aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/pci
diff options
context:
space:
mode:
authorJayachandran C <jchandra@broadcom.com>2013-12-21 16:52:27 +0530
committerRalf Baechle <ralf@linux-mips.org>2014-01-24 22:39:49 +0100
commitb6ba1c5294c3f51fd4cf8b0d60de4ba82ef2a1c9 (patch)
treef7d2f610de3852e8ded2d485c24bb52327039dea /arch/mips/pci
parent98d4884ca55883e8b16180bd969a8bccaa885c80 (diff)
MIPS: PCI: Netlogic XLP9XX support
Add PCI support for Netlogic XLP9XX. The PCI registers and SoC bus numbers have changed in XLP9XX. Also skip a few (bus,dev,fn) combinations which have issues when read. Signed-off-by: Jayachandran C <jchandra@broadcom.com> Signed-off-by: John Crispin <blogic@openwrt.org> Patchwork: http://patchwork.linux-mips.org/patch/6284/
Diffstat (limited to 'arch/mips/pci')
-rw-r--r--arch/mips/pci/pci-xlp.c95
1 files changed, 74 insertions, 21 deletions
diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c
index f390aa9970e..7babf01600c 100644
--- a/arch/mips/pci/pci-xlp.c
+++ b/arch/mips/pci/pci-xlp.c
@@ -67,9 +67,22 @@ static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn,
u32 *cfgaddr;
where &= ~3;
- if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954)
+ if (cpu_is_xlp9xx()) {
+ /* be very careful on SoC buses */
+ if (bus->number == 0) {
+ /* Scan only existing nodes - uboot bug? */
+ if (PCI_SLOT(devfn) != 0 ||
+ !nlm_node_present(PCI_FUNC(devfn)))
+ return 0xffffffff;
+ } else if (bus->parent->number == 0) { /* SoC bus */
+ if (PCI_SLOT(devfn) == 0) /* b.0.0 hangs */
+ return 0xffffffff;
+ if (devfn == 44) /* b.5.4 hangs */
+ return 0xffffffff;
+ }
+ } else if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954) {
return 0xffffffff;
-
+ }
cfgaddr = (u32 *)(pci_config_base +
pci_cfg_addr(bus->number, devfn, where));
data = *cfgaddr;
@@ -167,18 +180,35 @@ struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev)
{
struct pci_bus *bus, *p;
- /* Find the bridge on bus 0 */
bus = dev->bus;
- for (p = bus->parent; p && p->number != 0; p = p->parent)
- bus = p;
- return p ? bus->self : NULL;
+ if (cpu_is_xlp9xx()) {
+ /* find bus with grand parent number == 0 */
+ for (p = bus->parent; p && p->parent && p->parent->number != 0;
+ p = p->parent)
+ bus = p;
+ return (p && p->parent) ? bus->self : NULL;
+ } else {
+ /* Find the bridge on bus 0 */
+ for (p = bus->parent; p && p->number != 0; p = p->parent)
+ bus = p;
+
+ return p ? bus->self : NULL;
+ }
+}
+
+int xlp_socdev_to_node(const struct pci_dev *lnkdev)
+{
+ if (cpu_is_xlp9xx())
+ return PCI_FUNC(lnkdev->bus->self->devfn);
+ else
+ return PCI_SLOT(lnkdev->devfn) / 8;
}
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
struct pci_dev *lnkdev;
- int lnkslot, lnkfunc;
+ int lnkfunc, node;
/*
* For XLP PCIe, there is an IRQ per Link, find out which
@@ -187,9 +217,11 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
lnkdev = xlp_get_pcie_link(dev);
if (lnkdev == NULL)
return 0;
+
lnkfunc = PCI_FUNC(lnkdev->devfn);
- lnkslot = PCI_SLOT(lnkdev->devfn);
- return nlm_irq_to_xirq(lnkslot / 8, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc));
+ node = xlp_socdev_to_node(lnkdev);
+
+ return nlm_irq_to_xirq(node, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc));
}
/* Do platform specific device initialization at pci_enable_device() time */
@@ -216,17 +248,38 @@ static void xlp_config_pci_bswap(int node, int link)
* Enable byte swap in hardware. Program each link's PCIe SWAP regions
* from the link's address ranges.
*/
- reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link);
- nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg);
-
- reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_LIMIT0 + link);
- nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff);
-
- reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link);
- nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg);
-
- reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link);
- nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff);
+ if (cpu_is_xlp9xx()) {
+ reg = nlm_read_bridge_reg(nbubase,
+ BRIDGE_9XX_PCIEMEM_BASE0 + link);
+ nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_MEM_BASE, reg);
+
+ reg = nlm_read_bridge_reg(nbubase,
+ BRIDGE_9XX_PCIEMEM_LIMIT0 + link);
+ nlm_write_pci_reg(lnkbase,
+ PCIE_9XX_BYTE_SWAP_MEM_LIM, reg | 0xfff);
+
+ reg = nlm_read_bridge_reg(nbubase,
+ BRIDGE_9XX_PCIEIO_BASE0 + link);
+ nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_IO_BASE, reg);
+
+ reg = nlm_read_bridge_reg(nbubase,
+ BRIDGE_9XX_PCIEIO_LIMIT0 + link);
+ nlm_write_pci_reg(lnkbase,
+ PCIE_9XX_BYTE_SWAP_IO_LIM, reg | 0xfff);
+ } else {
+ reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link);
+ nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg);
+
+ reg = nlm_read_bridge_reg(nbubase,
+ BRIDGE_PCIEMEM_LIMIT0 + link);
+ nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff);
+
+ reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link);
+ nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg);
+
+ reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link);
+ nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff);
+ }
}
#else
/* Swap configuration not needed in little-endian mode */
@@ -260,7 +313,7 @@ static int __init pcibios_init(void)
/* put in intpin and irq - u-boot does not */
reg = nlm_read_pci_reg(pciebase, 0xf);
- reg &= ~0x1fu;
+ reg &= ~0x1ffu;
reg |= (1 << 8) | PIC_PCIE_LINK_LEGACY_IRQ(link);
nlm_write_pci_reg(pciebase, 0xf, reg);
pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link);