diff options
Diffstat (limited to 'arch/mips/pci/pci-xlp.c')
-rw-r--r-- | arch/mips/pci/pci-xlp.c | 110 |
1 files changed, 79 insertions, 31 deletions
diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c index 653d2db9e0c5..7babf01600cb 100644 --- a/arch/mips/pci/pci-xlp.c +++ b/arch/mips/pci/pci-xlp.c | |||
@@ -47,10 +47,11 @@ | |||
47 | #include <asm/netlogic/interrupt.h> | 47 | #include <asm/netlogic/interrupt.h> |
48 | #include <asm/netlogic/haldefs.h> | 48 | #include <asm/netlogic/haldefs.h> |
49 | #include <asm/netlogic/common.h> | 49 | #include <asm/netlogic/common.h> |
50 | #include <asm/netlogic/mips-extns.h> | ||
50 | 51 | ||
51 | #include <asm/netlogic/xlp-hal/iomap.h> | 52 | #include <asm/netlogic/xlp-hal/iomap.h> |
52 | #include <asm/netlogic/xlp-hal/pic.h> | ||
53 | #include <asm/netlogic/xlp-hal/xlp.h> | 53 | #include <asm/netlogic/xlp-hal/xlp.h> |
54 | #include <asm/netlogic/xlp-hal/pic.h> | ||
54 | #include <asm/netlogic/xlp-hal/pcibus.h> | 55 | #include <asm/netlogic/xlp-hal/pcibus.h> |
55 | #include <asm/netlogic/xlp-hal/bridge.h> | 56 | #include <asm/netlogic/xlp-hal/bridge.h> |
56 | 57 | ||
@@ -66,9 +67,22 @@ static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn, | |||
66 | u32 *cfgaddr; | 67 | u32 *cfgaddr; |
67 | 68 | ||
68 | where &= ~3; | 69 | where &= ~3; |
69 | 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) { | ||
70 | return 0xffffffff; | 84 | return 0xffffffff; |
71 | 85 | } | |
72 | cfgaddr = (u32 *)(pci_config_base + | 86 | cfgaddr = (u32 *)(pci_config_base + |
73 | pci_cfg_addr(bus->number, devfn, where)); | 87 | pci_cfg_addr(bus->number, devfn, where)); |
74 | data = *cfgaddr; | 88 | data = *cfgaddr; |
@@ -162,27 +176,39 @@ struct pci_controller nlm_pci_controller = { | |||
162 | .io_offset = 0x00000000UL, | 176 | .io_offset = 0x00000000UL, |
163 | }; | 177 | }; |
164 | 178 | ||
165 | static struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev) | 179 | struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev) |
166 | { | 180 | { |
167 | struct pci_bus *bus, *p; | 181 | struct pci_bus *bus, *p; |
168 | 182 | ||
169 | /* Find the bridge on bus 0 */ | ||
170 | bus = dev->bus; | 183 | bus = dev->bus; |
171 | for (p = bus->parent; p && p->number != 0; p = p->parent) | ||
172 | bus = p; | ||
173 | 184 | ||
174 | 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 | } | ||
175 | } | 198 | } |
176 | 199 | ||
177 | static inline int nlm_pci_link_to_irq(int link) | 200 | int xlp_socdev_to_node(const struct pci_dev *lnkdev) |
178 | { | 201 | { |
179 | return PIC_PCIE_LINK_0_IRQ + link; | 202 | if (cpu_is_xlp9xx()) |
203 | return PCI_FUNC(lnkdev->bus->self->devfn); | ||
204 | else | ||
205 | return PCI_SLOT(lnkdev->devfn) / 8; | ||
180 | } | 206 | } |
181 | 207 | ||
182 | 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) |
183 | { | 209 | { |
184 | struct pci_dev *lnkdev; | 210 | struct pci_dev *lnkdev; |
185 | int lnkslot, lnkfunc; | 211 | int lnkfunc, node; |
186 | 212 | ||
187 | /* | 213 | /* |
188 | * 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 |
@@ -191,9 +217,11 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | |||
191 | lnkdev = xlp_get_pcie_link(dev); | 217 | lnkdev = xlp_get_pcie_link(dev); |
192 | if (lnkdev == NULL) | 218 | if (lnkdev == NULL) |
193 | return 0; | 219 | return 0; |
220 | |||
194 | lnkfunc = PCI_FUNC(lnkdev->devfn); | 221 | lnkfunc = PCI_FUNC(lnkdev->devfn); |
195 | lnkslot = PCI_SLOT(lnkdev->devfn); | 222 | node = xlp_socdev_to_node(lnkdev); |
196 | return nlm_irq_to_xirq(lnkslot / 8, nlm_pci_link_to_irq(lnkfunc)); | 223 | |
224 | return nlm_irq_to_xirq(node, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc)); | ||
197 | } | 225 | } |
198 | 226 | ||
199 | /* Do platform specific device initialization at pci_enable_device() time */ | 227 | /* Do platform specific device initialization at pci_enable_device() time */ |
@@ -220,17 +248,38 @@ static void xlp_config_pci_bswap(int node, int link) | |||
220 | * 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 |
221 | * from the link's address ranges. | 249 | * from the link's address ranges. |
222 | */ | 250 | */ |
223 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link); | 251 | if (cpu_is_xlp9xx()) { |
224 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg); | 252 | reg = nlm_read_bridge_reg(nbubase, |
225 | 253 | BRIDGE_9XX_PCIEMEM_BASE0 + link); | |
226 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_LIMIT0 + link); | 254 | nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_MEM_BASE, reg); |
227 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff); | 255 | |
228 | 256 | reg = nlm_read_bridge_reg(nbubase, | |
229 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link); | 257 | BRIDGE_9XX_PCIEMEM_LIMIT0 + link); |
230 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg); | 258 | nlm_write_pci_reg(lnkbase, |
231 | 259 | PCIE_9XX_BYTE_SWAP_MEM_LIM, reg | 0xfff); | |
232 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link); | 260 | |
233 | 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 | } | ||
234 | } | 283 | } |
235 | #else | 284 | #else |
236 | /* Swap configuration not needed in little-endian mode */ | 285 | /* Swap configuration not needed in little-endian mode */ |
@@ -239,7 +288,6 @@ static inline void xlp_config_pci_bswap(int node, int link) {} | |||
239 | 288 | ||
240 | static int __init pcibios_init(void) | 289 | static int __init pcibios_init(void) |
241 | { | 290 | { |
242 | struct nlm_soc_info *nodep; | ||
243 | uint64_t pciebase; | 291 | uint64_t pciebase; |
244 | int link, n; | 292 | int link, n; |
245 | u32 reg; | 293 | u32 reg; |
@@ -253,20 +301,20 @@ static int __init pcibios_init(void) | |||
253 | ioport_resource.end = ~0; | 301 | ioport_resource.end = ~0; |
254 | 302 | ||
255 | for (n = 0; n < NLM_NR_NODES; n++) { | 303 | for (n = 0; n < NLM_NR_NODES; n++) { |
256 | nodep = nlm_get_node(n); | 304 | if (!nlm_node_present(n)) |
257 | if (!nodep->coremask) | 305 | continue; |
258 | continue; /* node does not exist */ | ||
259 | 306 | ||
260 | for (link = 0; link < 4; link++) { | 307 | for (link = 0; link < PCIE_NLINKS; link++) { |
261 | pciebase = nlm_get_pcie_base(n, link); | 308 | pciebase = nlm_get_pcie_base(n, link); |
262 | if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff) | 309 | if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff) |
263 | continue; | 310 | continue; |
264 | xlp_config_pci_bswap(n, link); | 311 | xlp_config_pci_bswap(n, link); |
312 | xlp_init_node_msi_irqs(n, link); | ||
265 | 313 | ||
266 | /* put in intpin and irq - u-boot does not */ | 314 | /* put in intpin and irq - u-boot does not */ |
267 | reg = nlm_read_pci_reg(pciebase, 0xf); | 315 | reg = nlm_read_pci_reg(pciebase, 0xf); |
268 | reg &= ~0x1fu; | 316 | reg &= ~0x1ffu; |
269 | reg |= (1 << 8) | nlm_pci_link_to_irq(link); | 317 | reg |= (1 << 8) | PIC_PCIE_LINK_LEGACY_IRQ(link); |
270 | nlm_write_pci_reg(pciebase, 0xf, reg); | 318 | nlm_write_pci_reg(pciebase, 0xf, reg); |
271 | pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link); | 319 | pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link); |
272 | } | 320 | } |