MIPS: PCI: Netlogic XLP9XX support
authorJayachandran C <jchandra@broadcom.com>
Sat, 21 Dec 2013 11:22:27 +0000 (16:52 +0530)
committerRalf Baechle <ralf@linux-mips.org>
Fri, 24 Jan 2014 21:39:49 +0000 (22:39 +0100)
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/

arch/mips/include/asm/netlogic/xlp-hal/pcibus.h
arch/mips/include/asm/netlogic/xlp-hal/xlp.h
arch/mips/netlogic/xlp/nlm_hal.c
arch/mips/pci/pci-xlp.c

index 0fac32b1d8baed7cd24bdd4d6e9dad6dde88cd25..d4deb87ad06991bb0e374bad8baa2329c9dcf3a5 100644 (file)
 #define PCIE_INT_EN0                   0x261
 #define PCIE_INT_EN1                   0x262
 
+/* XLP9XX has basic changes */
+#define PCIE_9XX_BYTE_SWAP_MEM_BASE    0x25c
+#define PCIE_9XX_BYTE_SWAP_MEM_LIM     0x25d
+#define PCIE_9XX_BYTE_SWAP_IO_BASE     0x25e
+#define PCIE_9XX_BYTE_SWAP_IO_LIM      0x25f
+
 /* other */
 #define PCIE_NLINKS                    4
 
@@ -78,8 +84,8 @@
 
 #define nlm_read_pcie_reg(b, r)                nlm_read_reg(b, r)
 #define nlm_write_pcie_reg(b, r, v)    nlm_write_reg(b, r, v)
-#define nlm_get_pcie_base(node, inst)  \
-                       nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, inst))
+#define nlm_get_pcie_base(node, inst)  nlm_pcicfg_base(cpu_is_xlp9xx() ? \
+       XLP9XX_IO_PCIE_OFFSET(node, inst) : XLP_IO_PCIE_OFFSET(node, inst))
 
 #ifdef CONFIG_PCI_MSI
 void xlp_init_node_msi_irqs(int node, int link);
index 9ccdb7d0f073d47f4d0865f20e7692376719f463..120c003c124d4fd14789619862df8f3a67c59999 100644 (file)
@@ -84,6 +84,9 @@ void xlp_mmu_init(void);
 void nlm_hal_init(void);
 int xlp_get_dram_map(int n, uint64_t *dram_map);
 
+struct pci_dev;
+int xlp_socdev_to_node(const struct pci_dev *dev);
+
 /* Device tree related */
 void xlp_early_init_devtree(void);
 void *xlp_dt_init(void *fdtp);
index efd64ac1f407855cfbdf8c7e532cf1340af3095a..e7ff2d37a464e1b9be61eca1043219a9a12f02f6 100644 (file)
@@ -76,6 +76,11 @@ int nlm_irq_to_irt(int irq)
                        return 133;
                case PIC_UART_1_IRQ:
                        return 134;
+               case PIC_PCIE_LINK_LEGACY_IRQ(0):
+               case PIC_PCIE_LINK_LEGACY_IRQ(1):
+               case PIC_PCIE_LINK_LEGACY_IRQ(2):
+               case PIC_PCIE_LINK_LEGACY_IRQ(3):
+                       return 191 + irq - PIC_PCIE_LINK_LEGACY_IRQ_BASE;
                }
                return -1;
        }
index f390aa9970e67fae4608555595c5062baa0c2b83..7babf01600cb0fd9cbb97d4bb40f079693b2e8ed 100644 (file)
@@ -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);