Commit cc93d69c authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] sh: PCI updates

From: Paul Mundt <lethal@Linux-SH.ORG>

This updates the pci-auto code, as well as adding ops and fixups for the
RTS7751R2D board.
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 125190ef
......@@ -12,4 +12,5 @@ obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o \
dma-dreamcast.o
obj-$(CONFIG_SH_SECUREEDGE5410) += ops-snapgear.o
obj-$(CONFIG_SH_BIGSUR) += ops-bigsur.o
obj-$(CONFIG_SH_RTS7751R2D) += ops-rts7751r2d.o fixups-rts7751r2d.o
/*
* arch/sh/drivers/pci/fixups-rts7751r2d.c
*
* RTS7751R2D PCI fixups
*
* Copyright (C) 2003 Lineo uSolutions, Inc.
* Copyright (C) 2004 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include "pci-sh7751.h"
#include <asm/io.h>
#define PCIMCR_MRSET_OFF 0xBFFFFFFF
#define PCIMCR_RFSH_OFF 0xFFFFFFFB
int pci_fixup_pcic(void)
{
unsigned long mcr;
outl(0xfb900047, SH7751_PCICONF1);
outl(0xab000001, SH7751_PCICONF4);
mcr = inl(SH7751_MCR);
mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
outl(mcr, SH7751_PCIMCR);
return 0;
}
/*
* linux/arch/sh/kernel/pci-rts7751r2d.c
*
* Author: Ian DaSilva (idasilva@mvista.com)
*
* Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* PCI initialization for the Renesas SH7751R RTS7751R2D board
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <asm/io.h>
#include "pci-sh7751.h"
#include <asm/rts7751r2d/rts7751r2d.h>
int __init pcibios_map_platform_irq(u8 slot, u8 pin)
{
switch (slot) {
case 0: return IRQ_PCISLOT1; /* PCI Extend slot #1 */
case 1: return IRQ_PCISLOT2; /* PCI Extend slot #2 */
case 2: return IRQ_PCMCIA; /* PCI Cardbus Bridge */
case 3: return IRQ_PCIETH; /* Realtek Ethernet controller */
default:
printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
return -1;
}
}
static struct resource sh7751_io_resource = {
.name = "SH7751_IO",
.start = 0x4000,
.end = 0x4000 + SH7751_PCI_IO_SIZE - 1,
.flags = IORESOURCE_IO
};
static struct resource sh7751_mem_resource = {
.name = "SH7751_mem",
.start = SH7751_PCI_MEMORY_BASE,
.end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
.flags = IORESOURCE_MEM
};
extern struct pci_ops sh7751_pci_ops;
struct pci_channel board_pci_channels[] = {
{ &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
{ NULL, NULL, NULL, 0, 0 },
};
EXPORT_SYMBOL(board_pci_channels);
static struct sh7751_pci_address_map sh7751_pci_map = {
.window0 = {
.base = SH7751_CS3_BASE_ADDR,
.size = 0x03f00000,
},
.flags = SH7751_PCIC_NO_RESET,
};
int __init pcibios_init_platform(void)
{
return sh7751_pcic_init(&sh7751_pci_map);
}
......@@ -61,6 +61,8 @@ static struct sh7751_pci_address_map sh7751_pci_map = {
.base = SH7751_CS2_BASE_ADDR,
.size = SNAPGEAR_LSR1_SIZE,
},
.flags = SH7751_PCIC_NO_RESET,
};
/*
......
......@@ -45,7 +45,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#define DEBUG
#undef DEBUG
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
......@@ -106,7 +106,8 @@ static void __init
pciauto_setup_bars(struct pci_channel *hose,
int top_bus,
int current_bus,
int pci_devfn)
int pci_devfn,
int bar_limit)
{
u32 bar_response, bar_size, bar_value;
u32 bar, addr_mask, bar_nr = 0;
......@@ -114,7 +115,8 @@ pciauto_setup_bars(struct pci_channel *hose,
u32 * lower_limit;
int found_mem64 = 0;
for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar+=4) {
for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) {
#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
u32 bar_addr;
/* Read the old BAR value */
......@@ -123,6 +125,7 @@ pciauto_setup_bars(struct pci_channel *hose,
pci_devfn,
bar,
&bar_addr);
#endif
/* Tickle the BAR and get the response */
early_write_config_dword(hose, top_bus,
......@@ -137,6 +140,7 @@ pciauto_setup_bars(struct pci_channel *hose,
bar,
&bar_response);
#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
/*
* Write the old BAR value back out, only update the BAR
* if we implicitly want resources to be updated, which
......@@ -147,6 +151,7 @@ pciauto_setup_bars(struct pci_channel *hose,
pci_devfn,
bar,
bar_addr);
#endif
/* If BAR is not implemented go to the next BAR */
if (!bar_response)
......@@ -287,6 +292,11 @@ pciauto_postscan_setup_bridge(struct pci_channel *hose,
{
u32 temp;
/*
* [jsun] we always bump up baselines a little, so that if there
* nothing behind P2P bridge, we don't wind up overlapping IO/MEM
* spaces.
*/
pciauto_lower_memspc += 1;
pciauto_lower_iospc += 1;
......@@ -318,93 +328,99 @@ pciauto_postscan_setup_bridge(struct pci_channel *hose,
static void __init
pciauto_prescan_setup_cardbus_bridge(struct pci_channel *hose,
int top_bus,
int current_bus,
int pci_devfn,
int sub_bus)
int top_bus,
int current_bus,
int pci_devfn,
int sub_bus)
{
/* Configure bus number registers */
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_PRIMARY_BUS, current_bus);
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_SECONDARY_BUS, sub_bus + 1);
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_SUBORDINATE_BUS, 0xff);
/* Align memory and I/O to 4KB and 4 byte boundaries. */
pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1))
& ~(0x1000 - 1);
pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1))
& ~(0x4 - 1);
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_CB_MEMORY_BASE_0, pciauto_lower_memspc);
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_CB_IO_BASE_0, pciauto_lower_iospc);
/* Configure bus number registers */
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_PRIMARY_BUS, current_bus);
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_SECONDARY_BUS, sub_bus + 1);
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_SUBORDINATE_BUS, 0xff);
/* Align memory and I/O to 4KB and 4 byte boundaries. */
pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1))
& ~(0x1000 - 1);
pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1))
& ~(0x4 - 1);
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_CB_MEMORY_BASE_0, pciauto_lower_memspc);
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_CB_IO_BASE_0, pciauto_lower_iospc);
}
static void __init
pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose,
int top_bus,
int current_bus,
int pci_devfn,
int sub_bus)
int top_bus,
int current_bus,
int pci_devfn,
int sub_bus)
{
u32 temp;
/*
* [jsun] we always bump up baselines a little, so that if there
* nothing behind P2P bridge, we don't wind up overlapping IO/MEM
* spaces.
*/
pciauto_lower_memspc += 1;
pciauto_lower_iospc += 1;
/*
* Configure subordinate bus number. The PCI subsystem
* bus scan will renumber buses (reserving three additional
* for this PCI<->CardBus bridge for the case where a CardBus
* adapter contains a P2P or CB2CB bridge.
*/
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_SUBORDINATE_BUS, sub_bus);
/*
* Reserve an additional 4MB for mem space and 16KB for
* I/O space. This should cover any additional space
* requirement of unusual CardBus devices with
* additional bridges that can consume more address space.
*
* Although pcmcia-cs currently will reprogram bridge
* windows, the goal is to add an option to leave them
* alone and use the bridge window ranges as the regions
* that are searched for free resources upon hot-insertion
* of a device. This will allow a PCI<->CardBus bridge
* configured by this routine to happily live behind a
* P2P bridge in a system.
*/
/* Align memory and I/O to 4KB and 4 byte boundaries. */
pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1))
& ~(0x1000 - 1);
pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1))
& ~(0x4 - 1);
/* Set up memory and I/O filter limits, assume 32-bit I/O space */
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_CB_MEMORY_LIMIT_0, pciauto_lower_memspc - 1);
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_CB_IO_LIMIT_0, pciauto_lower_iospc - 1);
/* Enable memory and I/O accesses, enable bus master */
early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_COMMAND, &temp);
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER);
u32 temp;
#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
/*
* [jsun] we always bump up baselines a little, so that if there
* nothing behind P2P bridge, we don't wind up overlapping IO/MEM
* spaces.
*/
pciauto_lower_memspc += 1;
pciauto_lower_iospc += 1;
#endif
/*
* Configure subordinate bus number. The PCI subsystem
* bus scan will renumber buses (reserving three additional
* for this PCI<->CardBus bridge for the case where a CardBus
* adapter contains a P2P or CB2CB bridge.
*/
early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
PCI_SUBORDINATE_BUS, sub_bus);
/*
* Reserve an additional 4MB for mem space and 16KB for
* I/O space. This should cover any additional space
* requirement of unusual CardBus devices with
* additional bridges that can consume more address space.
*
* Although pcmcia-cs currently will reprogram bridge
* windows, the goal is to add an option to leave them
* alone and use the bridge window ranges as the regions
* that are searched for free resources upon hot-insertion
* of a device. This will allow a PCI<->CardBus bridge
* configured by this routine to happily live behind a
* P2P bridge in a system.
*/
#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D)
pciauto_lower_memspc += 0x00400000;
pciauto_lower_iospc += 0x00004000;
#endif
/* Align memory and I/O to 4KB and 4 byte boundaries. */
pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1))
& ~(0x1000 - 1);
pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1))
& ~(0x4 - 1);
/* Set up memory and I/O filter limits, assume 32-bit I/O space */
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_CB_MEMORY_LIMIT_0, pciauto_lower_memspc - 1);
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_CB_IO_LIMIT_0, pciauto_lower_iospc - 1);
/* Enable memory and I/O accesses, enable bus master */
early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_COMMAND, &temp);
early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER);
}
#define PCIAUTO_IDE_MODE_MASK 0x05
#define PCIAUTO_IDE_MODE_MASK 0x05
static int __init
pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
......@@ -455,6 +471,9 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) {
DBG(" Bridge: primary=%.2x, secondary=%.2x\n",
current_bus, sub_bus + 1);
#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D)
pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_1);
#endif
pciauto_prescan_setup_bridge(hose, top_bus, current_bus,
pci_devfn, sub_bus);
DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n",
......@@ -463,26 +482,26 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1);
DBG("Back to bus %.2x\n", current_bus);
pciauto_postscan_setup_bridge(hose, top_bus, current_bus,
pci_devfn, sub_bus);
pci_devfn, sub_bus);
continue;
} else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) {
DBG(" CARDBUS Bridge: primary=%.2x, secondary=%.2x\n",
current_bus, sub_bus + 1);
DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn));
/* Place CardBus Socket/ExCA registers */
pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn);
} else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) {
DBG(" CARDBUS Bridge: primary=%.2x, secondary=%.2x\n",
current_bus, sub_bus + 1);
DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn));
/* Place CardBus Socket/ExCA registers */
pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_0);
pciauto_prescan_setup_cardbus_bridge(hose, top_bus,
current_bus, pci_devfn, sub_bus);
pciauto_prescan_setup_cardbus_bridge(hose, top_bus,
current_bus, pci_devfn, sub_bus);
DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n",
sub_bus + 1,
pciauto_lower_iospc, pciauto_lower_memspc);
sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1);
DBG("Back to bus %.2x, sub_bus is %x\n", current_bus, sub_bus);
pciauto_postscan_setup_cardbus_bridge(hose, top_bus,
current_bus, pci_devfn, sub_bus);
continue;
DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n",
sub_bus + 1,
pciauto_lower_iospc, pciauto_lower_memspc);
sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1);
DBG("Back to bus %.2x, sub_bus is %x\n", current_bus, sub_bus);
pciauto_postscan_setup_cardbus_bridge(hose, top_bus,
current_bus, pci_devfn, sub_bus);
continue;
} else if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) {
unsigned char prg_iface;
......@@ -495,7 +514,7 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
}
}
/*
/*
* Found a peripheral, enable some standard
* settings
*/
......@@ -509,7 +528,7 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
PCI_LATENCY_TIMER, 0x80);
/* Allocate PCI I/O and/or memory space */
pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn);
pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_5);
}
return sub_bus;
}
......
......@@ -31,6 +31,7 @@
#include "pci-sh7751.h"
static unsigned int pci_probe = PCI_PROBE_CONF1;
extern int pci_fixup_pcic(void);
/*
* Direct access to PCI hardware...
......@@ -74,7 +75,8 @@ static int sh7751_pci_read(struct pci_bus *bus, unsigned int devfn,
}
/*
* Since SH7751 only does 32bit access we'll have to do a read,mask,write operation.
* Since SH7751 only does 32bit access we'll have to do a read,
* mask,write operation.
* We'll allow an odd byte offset, though it should be illegal.
*/
static int sh7751_pci_write(struct pci_bus *bus, unsigned int devfn,
......@@ -156,6 +158,7 @@ static int __init pci_check_direct(void)
* Handle bus scanning and fixups ....
*/
#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
static void __init pci_fixup_ide_bases(struct pci_dev *d)
{
int i;
......@@ -174,11 +177,13 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d)
}
}
}
#endif
/* Add future fixups here... */
struct pci_fixup pcibios_fixups[] = {
#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases },
#endif
{ 0 }
};
......@@ -261,19 +266,19 @@ int __init sh7751_pcic_init(struct sh7751_pci_address_map *map)
outl(word, PCI_REG(SH7751_PCICLKR));
/*
* XXX: This code is unused for the SnapGear boards as it is done in
* the bootloader and doing it here means the MAC addresses loaded by
* the bootloader get lost.
* This code is unused for some boards as it is done in the
* bootloader and doing it here means the MAC addresses loaded
* by the bootloader get lost.
*/
#ifndef CONFIG_SH_SECUREEDGE5410
/* toggle PCI reset pin */
word = SH7751_PCICR_PREFIX | SH7751_PCICR_PRST;
outl(word,PCI_REG(SH7751_PCICR));
/* Wait for a long time... not 1 sec. but long enough */
mdelay(100);
word = SH7751_PCICR_PREFIX;
outl(word,PCI_REG(SH7751_PCICR));
#endif
if (!(map->flags & SH7751_PCIC_NO_RESET)) {
/* toggle PCI reset pin */
word = SH7751_PCICR_PREFIX | SH7751_PCICR_PRST;
outl(word,PCI_REG(SH7751_PCICR));
/* Wait for a long time... not 1 sec. but long enough */
mdelay(100);
word = SH7751_PCICR_PREFIX;
outl(word,PCI_REG(SH7751_PCICR));
}
/* set the command/status bits to:
* Wait Cycle Control + Parity Enable + Bus Master +
......@@ -364,6 +369,10 @@ int __init sh7751_pcic_init(struct sh7751_pci_address_map *map)
* DMA interrupts...
*/
#ifdef CONFIG_SH_RTS7751R2D
pci_fixup_pcic();
#endif
/* SH7751 init done, set central function init complete */
/* use round robin mode to stop a device starving/overruning */
word = SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN | SH7751_PCICR_ARBM;
......
......@@ -234,6 +234,7 @@
#define SH7751_PCIWCR2 0x1EC /* Wait Control 2 Register */
#define SH7751_PCIWCR3 0x1F0 /* Wait Control 3 Register */
#define SH7751_PCIMCR 0x1F4 /* Memory Control Register */
#define SH7751_PCIBCR3 0x1f8 /* Memory BCR3 Register */
#define SH7751_PCIPCTR 0x200 /* Port Control Register */
#define SH7751_PCIPCTR_P2EN 0x000400000 /* Port 2 Enable */
#define SH7751_PCIPCTR_P1EN 0x000200000 /* Port 1 Enable */
......@@ -256,6 +257,8 @@
/* Memory Control Registers */
#define SH7751_BCR1 0xFF800000 /* Memory BCR1 Register */
#define SH7751_BCR2 0xFF800004 /* Memory BCR2 Register */
#define SH7751_BCR3 0xFF800050 /* Memory BCR3 Register */
#define SH7751_BCR4 0xFE0A00F0 /* Memory BCR4 Register */
#define SH7751_WCR1 0xFF800008 /* Wait Control 1 Register */
#define SH7751_WCR2 0xFF80000C /* Wait Control 2 Register */
#define SH7751_WCR3 0xFF800010 /* Wait Control 3 Register */
......@@ -274,6 +277,9 @@
/* General PCI values */
#define SH7751_PCI_HOST_BRIDGE 0x6
/* Flags */
#define SH7751_PCIC_NO_RESET 0x0001
/* External functions defined per platform i.e. Big Sur, SE... (these could be routed
* through the machine vectors... */
extern int pcibios_init_platform(void);
......@@ -287,6 +293,7 @@ struct sh7751_pci_address_space {
struct sh7751_pci_address_map {
struct sh7751_pci_address_space window0;
struct sh7751_pci_address_space window1;
unsigned long flags;
};
/* arch/sh/drivers/pci/pci-sh7751.c */
......
......@@ -25,7 +25,7 @@ static int __init pcibios_init(void)
#ifdef CONFIG_PCI_AUTO
/* assign resources */
busno=0;
busno = 0;
for (p = board_pci_channels; p->pci_ops != NULL; p++) {
busno = pciauto_assign_resources(busno, p) + 1;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment