diff options
author | Jayachandran C <jchandra@broadcom.com> | 2013-12-21 06:22:27 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-01-24 16:39:49 -0500 |
commit | b6ba1c5294c3f51fd4cf8b0d60de4ba82ef2a1c9 (patch) | |
tree | f7d2f610de3852e8ded2d485c24bb52327039dea | |
parent | 98d4884ca55883e8b16180bd969a8bccaa885c80 (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/
-rw-r--r-- | arch/mips/include/asm/netlogic/xlp-hal/pcibus.h | 10 | ||||
-rw-r--r-- | arch/mips/include/asm/netlogic/xlp-hal/xlp.h | 3 | ||||
-rw-r--r-- | arch/mips/netlogic/xlp/nlm_hal.c | 5 | ||||
-rw-r--r-- | arch/mips/pci/pci-xlp.c | 95 |
4 files changed, 90 insertions, 23 deletions
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h b/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h index 0fac32b1d8ba..d4deb87ad069 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h | |||
@@ -63,6 +63,12 @@ | |||
63 | #define PCIE_INT_EN0 0x261 | 63 | #define PCIE_INT_EN0 0x261 |
64 | #define PCIE_INT_EN1 0x262 | 64 | #define PCIE_INT_EN1 0x262 |
65 | 65 | ||
66 | /* XLP9XX has basic changes */ | ||
67 | #define PCIE_9XX_BYTE_SWAP_MEM_BASE 0x25c | ||
68 | #define PCIE_9XX_BYTE_SWAP_MEM_LIM 0x25d | ||
69 | #define PCIE_9XX_BYTE_SWAP_IO_BASE 0x25e | ||
70 | #define PCIE_9XX_BYTE_SWAP_IO_LIM 0x25f | ||
71 | |||
66 | /* other */ | 72 | /* other */ |
67 | #define PCIE_NLINKS 4 | 73 | #define PCIE_NLINKS 4 |
68 | 74 | ||
@@ -78,8 +84,8 @@ | |||
78 | 84 | ||
79 | #define nlm_read_pcie_reg(b, r) nlm_read_reg(b, r) | 85 | #define nlm_read_pcie_reg(b, r) nlm_read_reg(b, r) |
80 | #define nlm_write_pcie_reg(b, r, v) nlm_write_reg(b, r, v) | 86 | #define nlm_write_pcie_reg(b, r, v) nlm_write_reg(b, r, v) |
81 | #define nlm_get_pcie_base(node, inst) \ | 87 | #define nlm_get_pcie_base(node, inst) nlm_pcicfg_base(cpu_is_xlp9xx() ? \ |
82 | nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, inst)) | 88 | XLP9XX_IO_PCIE_OFFSET(node, inst) : XLP_IO_PCIE_OFFSET(node, inst)) |
83 | 89 | ||
84 | #ifdef CONFIG_PCI_MSI | 90 | #ifdef CONFIG_PCI_MSI |
85 | void xlp_init_node_msi_irqs(int node, int link); | 91 | void xlp_init_node_msi_irqs(int node, int link); |
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h index 9ccdb7d0f073..120c003c124d 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h | |||
@@ -84,6 +84,9 @@ void xlp_mmu_init(void); | |||
84 | void nlm_hal_init(void); | 84 | void nlm_hal_init(void); |
85 | int xlp_get_dram_map(int n, uint64_t *dram_map); | 85 | int xlp_get_dram_map(int n, uint64_t *dram_map); |
86 | 86 | ||
87 | struct pci_dev; | ||
88 | int xlp_socdev_to_node(const struct pci_dev *dev); | ||
89 | |||
87 | /* Device tree related */ | 90 | /* Device tree related */ |
88 | void xlp_early_init_devtree(void); | 91 | void xlp_early_init_devtree(void); |
89 | void *xlp_dt_init(void *fdtp); | 92 | void *xlp_dt_init(void *fdtp); |
diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c index efd64ac1f407..e7ff2d37a464 100644 --- a/arch/mips/netlogic/xlp/nlm_hal.c +++ b/arch/mips/netlogic/xlp/nlm_hal.c | |||
@@ -76,6 +76,11 @@ int nlm_irq_to_irt(int irq) | |||
76 | return 133; | 76 | return 133; |
77 | case PIC_UART_1_IRQ: | 77 | case PIC_UART_1_IRQ: |
78 | return 134; | 78 | return 134; |
79 | case PIC_PCIE_LINK_LEGACY_IRQ(0): | ||
80 | case PIC_PCIE_LINK_LEGACY_IRQ(1): | ||
81 | case PIC_PCIE_LINK_LEGACY_IRQ(2): | ||
82 | case PIC_PCIE_LINK_LEGACY_IRQ(3): | ||
83 | return 191 + irq - PIC_PCIE_LINK_LEGACY_IRQ_BASE; | ||
79 | } | 84 | } |
80 | return -1; | 85 | return -1; |
81 | } | 86 | } |
diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c index f390aa9970e6..7babf01600cb 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, | |||
67 | u32 *cfgaddr; | 67 | u32 *cfgaddr; |
68 | 68 | ||
69 | where &= ~3; | 69 | where &= ~3; |
70 | if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954) | 70 | if (cpu_is_xlp9xx()) { |
71 | /* be very careful on SoC buses */ | ||
72 | if (bus->number == 0) { | ||
73 | /* Scan only existing nodes - uboot bug? */ | ||
74 | if (PCI_SLOT(devfn) != 0 || | ||
75 | !nlm_node_present(PCI_FUNC(devfn))) | ||
76 | return 0xffffffff; | ||
77 | } else if (bus->parent->number == 0) { /* SoC bus */ | ||
78 | if (PCI_SLOT(devfn) == 0) /* b.0.0 hangs */ | ||
79 | return 0xffffffff; | ||
80 | if (devfn == 44) /* b.5.4 hangs */ | ||
81 | return 0xffffffff; | ||
82 | } | ||
83 | } else if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954) { | ||
71 | return 0xffffffff; | 84 | return 0xffffffff; |
72 | 85 | } | |
73 | cfgaddr = (u32 *)(pci_config_base + | 86 | cfgaddr = (u32 *)(pci_config_base + |
74 | pci_cfg_addr(bus->number, devfn, where)); | 87 | pci_cfg_addr(bus->number, devfn, where)); |
75 | data = *cfgaddr; | 88 | data = *cfgaddr; |
@@ -167,18 +180,35 @@ struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev) | |||
167 | { | 180 | { |
168 | struct pci_bus *bus, *p; | 181 | struct pci_bus *bus, *p; |
169 | 182 | ||
170 | /* Find the bridge on bus 0 */ | ||
171 | bus = dev->bus; | 183 | bus = dev->bus; |
172 | for (p = bus->parent; p && p->number != 0; p = p->parent) | ||
173 | bus = p; | ||
174 | 184 | ||
175 | return p ? bus->self : NULL; | 185 | if (cpu_is_xlp9xx()) { |
186 | /* find bus with grand parent number == 0 */ | ||
187 | for (p = bus->parent; p && p->parent && p->parent->number != 0; | ||
188 | p = p->parent) | ||
189 | bus = p; | ||
190 | return (p && p->parent) ? bus->self : NULL; | ||
191 | } else { | ||
192 | /* Find the bridge on bus 0 */ | ||
193 | for (p = bus->parent; p && p->number != 0; p = p->parent) | ||
194 | bus = p; | ||
195 | |||
196 | return p ? bus->self : NULL; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | int xlp_socdev_to_node(const struct pci_dev *lnkdev) | ||
201 | { | ||
202 | if (cpu_is_xlp9xx()) | ||
203 | return PCI_FUNC(lnkdev->bus->self->devfn); | ||
204 | else | ||
205 | return PCI_SLOT(lnkdev->devfn) / 8; | ||
176 | } | 206 | } |
177 | 207 | ||
178 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | 208 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) |
179 | { | 209 | { |
180 | struct pci_dev *lnkdev; | 210 | struct pci_dev *lnkdev; |
181 | int lnkslot, lnkfunc; | 211 | int lnkfunc, node; |
182 | 212 | ||
183 | /* | 213 | /* |
184 | * For XLP PCIe, there is an IRQ per Link, find out which | 214 | * 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) | |||
187 | lnkdev = xlp_get_pcie_link(dev); | 217 | lnkdev = xlp_get_pcie_link(dev); |
188 | if (lnkdev == NULL) | 218 | if (lnkdev == NULL) |
189 | return 0; | 219 | return 0; |
220 | |||
190 | lnkfunc = PCI_FUNC(lnkdev->devfn); | 221 | lnkfunc = PCI_FUNC(lnkdev->devfn); |
191 | lnkslot = PCI_SLOT(lnkdev->devfn); | 222 | node = xlp_socdev_to_node(lnkdev); |
192 | return nlm_irq_to_xirq(lnkslot / 8, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc)); | 223 | |
224 | return nlm_irq_to_xirq(node, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc)); | ||
193 | } | 225 | } |
194 | 226 | ||
195 | /* Do platform specific device initialization at pci_enable_device() time */ | 227 | /* Do platform specific device initialization at pci_enable_device() time */ |
@@ -216,17 +248,38 @@ static void xlp_config_pci_bswap(int node, int link) | |||
216 | * Enable byte swap in hardware. Program each link's PCIe SWAP regions | 248 | * Enable byte swap in hardware. Program each link's PCIe SWAP regions |
217 | * from the link's address ranges. | 249 | * from the link's address ranges. |
218 | */ | 250 | */ |
219 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link); | 251 | if (cpu_is_xlp9xx()) { |
220 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg); | 252 | reg = nlm_read_bridge_reg(nbubase, |
221 | 253 | BRIDGE_9XX_PCIEMEM_BASE0 + link); | |
222 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_LIMIT0 + link); | 254 | nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_MEM_BASE, reg); |
223 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff); | 255 | |
224 | 256 | reg = nlm_read_bridge_reg(nbubase, | |
225 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link); | 257 | BRIDGE_9XX_PCIEMEM_LIMIT0 + link); |
226 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg); | 258 | nlm_write_pci_reg(lnkbase, |
227 | 259 | PCIE_9XX_BYTE_SWAP_MEM_LIM, reg | 0xfff); | |
228 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link); | 260 | |
229 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff); | 261 | reg = nlm_read_bridge_reg(nbubase, |
262 | BRIDGE_9XX_PCIEIO_BASE0 + link); | ||
263 | nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_IO_BASE, reg); | ||
264 | |||
265 | reg = nlm_read_bridge_reg(nbubase, | ||
266 | BRIDGE_9XX_PCIEIO_LIMIT0 + link); | ||
267 | nlm_write_pci_reg(lnkbase, | ||
268 | PCIE_9XX_BYTE_SWAP_IO_LIM, reg | 0xfff); | ||
269 | } else { | ||
270 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link); | ||
271 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg); | ||
272 | |||
273 | reg = nlm_read_bridge_reg(nbubase, | ||
274 | BRIDGE_PCIEMEM_LIMIT0 + link); | ||
275 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff); | ||
276 | |||
277 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link); | ||
278 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg); | ||
279 | |||
280 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link); | ||
281 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff); | ||
282 | } | ||
230 | } | 283 | } |
231 | #else | 284 | #else |
232 | /* Swap configuration not needed in little-endian mode */ | 285 | /* Swap configuration not needed in little-endian mode */ |
@@ -260,7 +313,7 @@ static int __init pcibios_init(void) | |||
260 | 313 | ||
261 | /* put in intpin and irq - u-boot does not */ | 314 | /* put in intpin and irq - u-boot does not */ |
262 | reg = nlm_read_pci_reg(pciebase, 0xf); | 315 | reg = nlm_read_pci_reg(pciebase, 0xf); |
263 | reg &= ~0x1fu; | 316 | reg &= ~0x1ffu; |
264 | reg |= (1 << 8) | PIC_PCIE_LINK_LEGACY_IRQ(link); | 317 | reg |= (1 << 8) | PIC_PCIE_LINK_LEGACY_IRQ(link); |
265 | nlm_write_pci_reg(pciebase, 0xf, reg); | 318 | nlm_write_pci_reg(pciebase, 0xf, reg); |
266 | pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link); | 319 | pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link); |