diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2008-06-26 11:12:50 -0400 |
---|---|---|
committer | Nicolas Pitre <nico@cam.org> | 2008-06-30 16:04:44 -0400 |
commit | da01bba3cb8814b17d809e09c301e1dad86fec87 (patch) | |
tree | 0605379dac7ae8b9de458b2d46230c839b319c34 /arch | |
parent | 1338760329c586e0141831099e15f5c336dd9c1d (diff) |
[ARM] Orion: make PCI handling code deal with Cardbus slots
The Cardbus connector does not have an IDSEL signal, and Cardbus
cards are always the intended target of configuration transactions
on their local PCI bus. This means that if the Orion's PCI bus
signals are hooked up to a Cardbus slot, the same set of PCI
functions will will appear 31 times, for each of the PCI device
IDs 1-31 (ID 0 is the host bridge).
This patch adds a function to the Orion PCI handling code that board
support code can call to enable Cardbus mode. When Cardbus mode is
enabled, configuration transactions on the PCI local bus are only
allowed to PCI IDs 0 (host bridge) and 1 (cardbus device).
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-orion5x/common.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/pci.c | 36 |
2 files changed, 30 insertions, 7 deletions
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h index 97db8d88f3db..f72cf0e77544 100644 --- a/arch/arm/mach-orion5x/common.h +++ b/arch/arm/mach-orion5x/common.h | |||
@@ -40,6 +40,7 @@ struct pci_bus; | |||
40 | struct pci_sys_data; | 40 | struct pci_sys_data; |
41 | 41 | ||
42 | void orion5x_pcie_id(u32 *dev, u32 *rev); | 42 | void orion5x_pcie_id(u32 *dev, u32 *rev); |
43 | void orion5x_pci_set_cardbus_mode(void); | ||
43 | int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys); | 44 | int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys); |
44 | struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys); | 45 | struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys); |
45 | int orion5x_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin); | 46 | int orion5x_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin); |
diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c index 025ef63b1ddb..256a4f680935 100644 --- a/arch/arm/mach-orion5x/pci.c +++ b/arch/arm/mach-orion5x/pci.c | |||
@@ -266,6 +266,8 @@ static int __init pcie_setup(struct pci_sys_data *sys) | |||
266 | */ | 266 | */ |
267 | static DEFINE_SPINLOCK(orion5x_pci_lock); | 267 | static DEFINE_SPINLOCK(orion5x_pci_lock); |
268 | 268 | ||
269 | static int orion5x_pci_cardbus_mode; | ||
270 | |||
269 | static int orion5x_pci_local_bus_nr(void) | 271 | static int orion5x_pci_local_bus_nr(void) |
270 | { | 272 | { |
271 | u32 conf = readl(PCI_P2P_CONF); | 273 | u32 conf = readl(PCI_P2P_CONF); |
@@ -321,14 +323,30 @@ static int orion5x_pci_hw_wr_conf(int bus, int dev, u32 func, | |||
321 | return ret; | 323 | return ret; |
322 | } | 324 | } |
323 | 325 | ||
326 | static int orion5x_pci_valid_config(int bus, u32 devfn) | ||
327 | { | ||
328 | if (bus == orion5x_pci_local_bus_nr()) { | ||
329 | /* | ||
330 | * Don't go out for local device | ||
331 | */ | ||
332 | if (PCI_SLOT(devfn) == 0 && PCI_FUNC(devfn) != 0) | ||
333 | return 0; | ||
334 | |||
335 | /* | ||
336 | * When the PCI signals are directly connected to a | ||
337 | * Cardbus slot, ignore all but device IDs 0 and 1. | ||
338 | */ | ||
339 | if (orion5x_pci_cardbus_mode && PCI_SLOT(devfn) > 1) | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | return 1; | ||
344 | } | ||
345 | |||
324 | static int orion5x_pci_rd_conf(struct pci_bus *bus, u32 devfn, | 346 | static int orion5x_pci_rd_conf(struct pci_bus *bus, u32 devfn, |
325 | int where, int size, u32 *val) | 347 | int where, int size, u32 *val) |
326 | { | 348 | { |
327 | /* | 349 | if (!orion5x_pci_valid_config(bus->number, devfn)) { |
328 | * Don't go out for local device | ||
329 | */ | ||
330 | if (bus->number == orion5x_pci_local_bus_nr() && | ||
331 | PCI_SLOT(devfn) == 0 && PCI_FUNC(devfn) != 0) { | ||
332 | *val = 0xffffffff; | 350 | *val = 0xffffffff; |
333 | return PCIBIOS_DEVICE_NOT_FOUND; | 351 | return PCIBIOS_DEVICE_NOT_FOUND; |
334 | } | 352 | } |
@@ -340,8 +358,7 @@ static int orion5x_pci_rd_conf(struct pci_bus *bus, u32 devfn, | |||
340 | static int orion5x_pci_wr_conf(struct pci_bus *bus, u32 devfn, | 358 | static int orion5x_pci_wr_conf(struct pci_bus *bus, u32 devfn, |
341 | int where, int size, u32 val) | 359 | int where, int size, u32 val) |
342 | { | 360 | { |
343 | if (bus->number == orion5x_pci_local_bus_nr() && | 361 | if (!orion5x_pci_valid_config(bus->number, devfn)) |
344 | PCI_SLOT(devfn) == 0 && PCI_FUNC(devfn) != 0) | ||
345 | return PCIBIOS_DEVICE_NOT_FOUND; | 362 | return PCIBIOS_DEVICE_NOT_FOUND; |
346 | 363 | ||
347 | return orion5x_pci_hw_wr_conf(bus->number, PCI_SLOT(devfn), | 364 | return orion5x_pci_hw_wr_conf(bus->number, PCI_SLOT(devfn), |
@@ -524,6 +541,11 @@ static void __devinit rc_pci_fixup(struct pci_dev *dev) | |||
524 | } | 541 | } |
525 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup); | 542 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup); |
526 | 543 | ||
544 | void __init orion5x_pci_set_cardbus_mode(void) | ||
545 | { | ||
546 | orion5x_pci_cardbus_mode = 1; | ||
547 | } | ||
548 | |||
527 | int __init orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys) | 549 | int __init orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys) |
528 | { | 550 | { |
529 | int ret = 0; | 551 | int ret = 0; |