diff options
Diffstat (limited to 'recipes-kernel/linux/linux-3.0.6/acp3448v2/0009-add-acp3448-PCIe-controller-driver.patch')
-rw-r--r-- | recipes-kernel/linux/linux-3.0.6/acp3448v2/0009-add-acp3448-PCIe-controller-driver.patch | 1081 |
1 files changed, 1081 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-3.0.6/acp3448v2/0009-add-acp3448-PCIe-controller-driver.patch b/recipes-kernel/linux/linux-3.0.6/acp3448v2/0009-add-acp3448-PCIe-controller-driver.patch new file mode 100644 index 0000000..f97cbc5 --- /dev/null +++ b/recipes-kernel/linux/linux-3.0.6/acp3448v2/0009-add-acp3448-PCIe-controller-driver.patch | |||
@@ -0,0 +1,1081 @@ | |||
1 | commit b49648c2950a227edb4832924649485537d5c049 | ||
2 | Author: Jerry Pei <jerry.pei@enea.com> | ||
3 | Date: Thu Sep 20 15:14:33 2012 +0800 | ||
4 | |||
5 | add support for the PCIe controller on ACP34xx | ||
6 | |||
7 | Extracted from lsi.patch in lsi_acp_linux_3.8.1.28 tarball. | ||
8 | |||
9 | Signed-off-by: Jerry Pei <jerry.pei@enea.com> | ||
10 | |||
11 | diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c | ||
12 | index 56e8b3c..a4e1c46 100644 | ||
13 | --- a/arch/powerpc/sysdev/ppc4xx_pci.c | ||
14 | +++ b/arch/powerpc/sysdev/ppc4xx_pci.c | ||
15 | @@ -34,8 +34,16 @@ | ||
16 | #include <mm/mmu_decl.h> | ||
17 | |||
18 | #include "ppc4xx_pci.h" | ||
19 | +#ifdef CONFIG_ACP | ||
20 | +#include <linux/interrupt.h> | ||
21 | +#include "../../../drivers/lsi/acp/ncr.h" | ||
22 | +static int acp_plx; | ||
23 | +#endif | ||
24 | |||
25 | static int dma_offset_set; | ||
26 | +#ifdef CONFIG_ACP | ||
27 | +static u32 last_mpage = 0; | ||
28 | +#endif | ||
29 | |||
30 | #define U64_TO_U32_LOW(val) ((u32)((val) & 0x00000000ffffffffULL)) | ||
31 | #define U64_TO_U32_HIGH(val) ((u32)((val) >> 32)) | ||
32 | @@ -45,6 +53,9 @@ static int dma_offset_set; | ||
33 | #define RES_TO_U32_HIGH(val) \ | ||
34 | ((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_HIGH(val) : (0)) | ||
35 | |||
36 | +#define ACPX1_PCIE_MPAGE_UPPER(n) (0x1010 + (n * 8)) | ||
37 | +#define ACPX1_PCIE_MPAGE_LOWER(n) (0x1014 + (n * 8)) | ||
38 | + | ||
39 | static inline int ppc440spe_revA(void) | ||
40 | { | ||
41 | /* Catch both 440SPe variants, with and without RAID6 support */ | ||
42 | @@ -87,7 +98,33 @@ static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev) | ||
43 | printk(KERN_INFO "PCI: Hiding 4xx host bridge resources %s\n", | ||
44 | pci_name(dev)); | ||
45 | } | ||
46 | + | ||
47 | +static void __init | ||
48 | +fixup_acp_pci_bridge(struct pci_dev *dev) | ||
49 | +{ | ||
50 | + /* if we aren't a PCIe don't bother */ | ||
51 | + if (!pci_find_capability(dev, PCI_CAP_ID_EXP)) | ||
52 | + return ; | ||
53 | + | ||
54 | + /* | ||
55 | + * Set the class appropriately for a bridge device | ||
56 | + */ | ||
57 | + printk(KERN_INFO "PCI: Setting PCI Class to PCI_CLASS_BRIDGE_HOST for %04x:%04x\n", dev->vendor, dev->device); | ||
58 | + | ||
59 | + | ||
60 | + dev->class = PCI_CLASS_BRIDGE_HOST << 8; | ||
61 | + | ||
62 | + /* | ||
63 | + * Make the bridge transparent | ||
64 | + */ | ||
65 | + dev->transparent = 1; | ||
66 | + | ||
67 | + return ; | ||
68 | +} | ||
69 | + | ||
70 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_ppc4xx_pci_bridge); | ||
71 | +DECLARE_PCI_FIXUP_HEADER(0x1000, 0x5101, fixup_acp_pci_bridge); | ||
72 | +DECLARE_PCI_FIXUP_HEADER(0x1000, 0x5108, fixup_acp_pci_bridge); | ||
73 | |||
74 | static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, | ||
75 | void __iomem *reg, | ||
76 | @@ -646,6 +683,9 @@ struct ppc4xx_pciex_port | ||
77 | struct resource cfg_space; | ||
78 | struct resource utl_regs; | ||
79 | void __iomem *utl_base; | ||
80 | +#ifdef CONFIG_ACP | ||
81 | + int acpChipType; | ||
82 | +#endif | ||
83 | }; | ||
84 | |||
85 | static struct ppc4xx_pciex_port *ppc4xx_pciex_ports; | ||
86 | @@ -939,6 +979,35 @@ static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = | ||
87 | .check_link = ppc4xx_pciex_check_link_sdr, | ||
88 | }; | ||
89 | |||
90 | +#if defined(CONFIG_ACP) | ||
91 | + | ||
92 | +static int __init | ||
93 | +acp_pciex_core_init(struct device_node *np) | ||
94 | +{ | ||
95 | + return 3; | ||
96 | +} | ||
97 | + | ||
98 | +static int | ||
99 | +acp_pciex_port_init_hw(struct ppc4xx_pciex_port *port) | ||
100 | +{ | ||
101 | + return 0; | ||
102 | +} | ||
103 | + | ||
104 | +static int | ||
105 | +acp_pciex_setup_utl(struct ppc4xx_pciex_port *port) | ||
106 | +{ | ||
107 | + return 0; | ||
108 | +} | ||
109 | + | ||
110 | +static struct ppc4xx_pciex_hwops acp_pcie_hwops __initdata = | ||
111 | +{ | ||
112 | + .core_init = acp_pciex_core_init, | ||
113 | + .port_init_hw = acp_pciex_port_init_hw, | ||
114 | + .setup_utl = acp_pciex_setup_utl | ||
115 | +}; | ||
116 | + | ||
117 | +#endif | ||
118 | + | ||
119 | static int __init ppc460ex_pciex_core_init(struct device_node *np) | ||
120 | { | ||
121 | /* Nothing to do, return 2 ports */ | ||
122 | @@ -1419,6 +1488,11 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np) | ||
123 | if (core_init++) | ||
124 | return 0; | ||
125 | |||
126 | +#if defined(CONFIG_ACP) | ||
127 | + if (of_device_is_compatible(np, "lsi,plb-pciex")) | ||
128 | + ppc4xx_pciex_hwops = &acp_pcie_hwops; | ||
129 | +#endif | ||
130 | + | ||
131 | #ifdef CONFIG_44x | ||
132 | if (of_device_is_compatible(np, "ibm,plb-pciex-440spe")) { | ||
133 | if (ppc440spe_revA()) | ||
134 | @@ -1578,9 +1652,11 @@ static int ppc4xx_pciex_validate_bdf(struct ppc4xx_pciex_port *port, | ||
135 | PCI_SLOT(devfn) != 0) | ||
136 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
137 | |||
138 | +#ifndef CONFIG_ACP | ||
139 | /* Check if we have a link */ | ||
140 | if ((bus->number != port->hose->first_busno) && !port->link) | ||
141 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
142 | +#endif | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | @@ -1598,10 +1674,80 @@ static void __iomem *ppc4xx_pciex_get_config_base(struct ppc4xx_pciex_port *port | ||
147 | return (void __iomem *)port->hose->cfg_addr; | ||
148 | |||
149 | relbus = bus->number - (port->hose->first_busno + 1); | ||
150 | + | ||
151 | +#ifndef CONFIG_ACP | ||
152 | return (void __iomem *)port->hose->cfg_data + | ||
153 | ((relbus << 20) | (devfn << 12)); | ||
154 | +#else | ||
155 | + | ||
156 | + { | ||
157 | + unsigned mpage; | ||
158 | + u32 addr; | ||
159 | + int dev, fn; | ||
160 | + int cfg_type; | ||
161 | + | ||
162 | + /* | ||
163 | + * Set MPAGE0 to map config access for this BDF | ||
164 | + */ | ||
165 | + | ||
166 | + dev = ( (devfn & 0xf8) >> 3); | ||
167 | + fn = devfn & 0x7; | ||
168 | + | ||
169 | + if (dev > 31) { | ||
170 | + return NULL; | ||
171 | + } | ||
172 | + | ||
173 | +#ifdef CONFIG_ACP_X1V1 | ||
174 | + /* v1 only supports fn=0 */ | ||
175 | + if (fn) { | ||
176 | + return NULL; | ||
177 | + } | ||
178 | +#else | ||
179 | + /* v2 only supports fn0-3 and bus0-63 */ | ||
180 | + if (port->acpChipType == 1) { | ||
181 | + if ((fn > 3) || (bus->number > 63)) { | ||
182 | + return NULL; | ||
183 | + } | ||
184 | + } | ||
185 | +#endif | ||
186 | + | ||
187 | + if (relbus && (bus->number != bus->primary)) { | ||
188 | + cfg_type = 1; | ||
189 | + } else { | ||
190 | + cfg_type = 0; | ||
191 | + } | ||
192 | + | ||
193 | + /* build the mpage register */ | ||
194 | + mpage = (bus->number << 11) | | ||
195 | + (dev << 6) | | ||
196 | + (cfg_type << 5 ); | ||
197 | + | ||
198 | + mpage |= 0x10; /* enable MPAGE for configuration access */ | ||
199 | + | ||
200 | + if (5 > port->acpChipType) | ||
201 | + mpage |= 1; | ||
202 | + | ||
203 | + /* the function number moved for X2 */ | ||
204 | + if (port->acpChipType < 2) { | ||
205 | + mpage |= (fn << 17); | ||
206 | + } else { | ||
207 | + mpage |= (fn << 19); | ||
208 | + } | ||
209 | + | ||
210 | + | ||
211 | + if (mpage != last_mpage) { | ||
212 | + /* printk("%02x:%02x:%02x setting mpage = 0x%08x\n", bus->number, dev, fn, mpage); */ | ||
213 | + addr = ((u32) port->hose->cfg_addr) + ACPX1_PCIE_MPAGE_LOWER(7); | ||
214 | + out_le32((u32 *) addr, mpage); | ||
215 | + last_mpage = mpage; | ||
216 | + } | ||
217 | + | ||
218 | + return (void __iomem *)port->hose->cfg_data; | ||
219 | + } | ||
220 | +#endif | ||
221 | } | ||
222 | |||
223 | +#ifndef CONFIG_ACP | ||
224 | static int ppc4xx_pciex_read_config(struct pci_bus *bus, unsigned int devfn, | ||
225 | int offset, int len, u32 *val) | ||
226 | { | ||
227 | @@ -1703,10 +1849,225 @@ static int ppc4xx_pciex_write_config(struct pci_bus *bus, unsigned int devfn, | ||
228 | return PCIBIOS_SUCCESSFUL; | ||
229 | } | ||
230 | |||
231 | +#else | ||
232 | +static int | ||
233 | +ppc4xx_pciex_acp_read_config(struct pci_bus *bus, unsigned int devfn, | ||
234 | + int offset, int len, u32 *val) | ||
235 | +{ | ||
236 | + struct pci_controller *hose = (struct pci_controller *) bus->sysdata; | ||
237 | + struct ppc4xx_pciex_port *port = | ||
238 | + &ppc4xx_pciex_ports[hose->indirect_type]; | ||
239 | + void __iomem *addr; | ||
240 | + u32 bus_addr; | ||
241 | + u32 val32; | ||
242 | + u32 mcsr; | ||
243 | + int bo = offset & 0x3; | ||
244 | + int rc = PCIBIOS_SUCCESSFUL; | ||
245 | + | ||
246 | + BUG_ON(hose != port->hose); | ||
247 | + | ||
248 | + if (ppc4xx_pciex_validate_bdf(port, bus, devfn) != 0) | ||
249 | + return PCIBIOS_DEVICE_NOT_FOUND; | ||
250 | + | ||
251 | + addr = ppc4xx_pciex_get_config_base(port, bus, devfn); | ||
252 | + | ||
253 | + if (!addr) { | ||
254 | + *val = 0; | ||
255 | + return PCIBIOS_DEVICE_NOT_FOUND; | ||
256 | + } | ||
257 | + | ||
258 | + /* | ||
259 | + * Reading from configuration space of non-existing device can | ||
260 | + * generate transaction errors. For the read duration we suppress | ||
261 | + * assertion of machine check exceptions to avoid those. | ||
262 | + */ | ||
263 | + mtmsr( mfmsr() & ~(MSR_ME)); | ||
264 | + __asm__ __volatile__("msync"); | ||
265 | + | ||
266 | + /* | ||
267 | + * addressing is different for local config access vs. | ||
268 | + * access through the mapped config space. | ||
269 | + */ | ||
270 | + if (bus->number == port->hose->first_busno) { | ||
271 | + int wo = offset & 0xfffffffc; | ||
272 | + bus_addr = (u32) addr + wo; | ||
273 | + | ||
274 | + } else { | ||
275 | + | ||
276 | + /* | ||
277 | + * mapped config space only supports 32-bit access | ||
278 | + * | ||
279 | + * AXI address [3:0] is not used at all. | ||
280 | + * AXI address[9:4] becomes register number. | ||
281 | + * AXI address[13:10] becomes Ext. register number | ||
282 | + * AXI address[17:14] becomes 1st DWBE for configuration read only. | ||
283 | + * AXI address[29:27] is used to select one of 8 Mpage registers. | ||
284 | + */ | ||
285 | + | ||
286 | + bus_addr = (u32) addr + (offset << 2); | ||
287 | + | ||
288 | + switch (len) { | ||
289 | + case 1: | ||
290 | + bus_addr |= ((1 << bo) ) << 14; | ||
291 | + break; | ||
292 | + case 2: | ||
293 | + bus_addr |= ((3 << bo) ) << 14; | ||
294 | + break; | ||
295 | + default: | ||
296 | + bus_addr |= ( 0xf ) << 14; | ||
297 | + break; | ||
298 | + } | ||
299 | + | ||
300 | + } | ||
301 | + | ||
302 | + /* | ||
303 | + * do the read | ||
304 | + */ | ||
305 | + | ||
306 | + val32 = in_le32((u32 *)bus_addr); | ||
307 | + | ||
308 | + switch (len) { | ||
309 | + case 1: | ||
310 | + *val = (val32 >> (bo * 8)) & 0xff; | ||
311 | + break; | ||
312 | + case 2: | ||
313 | + *val = (val32 >> (bo * 8)) & 0xffff; | ||
314 | + break; | ||
315 | + default: | ||
316 | + *val = val32; | ||
317 | + break; | ||
318 | + } | ||
319 | + | ||
320 | + __asm__ __volatile__("msync"); | ||
321 | + | ||
322 | + mcsr = mfspr(SPRN_MCSR); | ||
323 | + if ( mcsr != 0) { | ||
324 | + mtspr(SPRN_MCSR, 0); | ||
325 | + __asm__ __volatile__("msync"); | ||
326 | + | ||
327 | +#ifdef PRINT_CONFIG_ACCESSES | ||
328 | + printk("acp_read_config : %3d [%3d..%3d] fn=0x%04x" | ||
329 | + " o=0x%04x l=%d a=0x%08x machine check!! 0x%08x\n", | ||
330 | + bus->number, hose->first_busno, hose->last_busno, | ||
331 | + devfn, offset, len, bus_addr, mcsr); | ||
332 | +#endif | ||
333 | + pr_debug("acp_read_config : bus=%3d [%3d..%3d] devfn=0x%04x" | ||
334 | + " offset=0x%04x len=%d, addr=0x%08x machine check!! " | ||
335 | + "0x%08x\n", | ||
336 | + bus->number, hose->first_busno, hose->last_busno, | ||
337 | + devfn, offset, len, bus_addr, mcsr); | ||
338 | + *val = 0; | ||
339 | + rc = PCIBIOS_DEVICE_NOT_FOUND; | ||
340 | + } else { | ||
341 | +#ifdef PRINT_CONFIG_ACCESSES | ||
342 | + printk("acp_read_config : %3d [%3d..%3d] fn=0x%04x" | ||
343 | + " o=0x%04x l=%d a=0x%08x v=0x%08x\n", | ||
344 | + bus->number, hose->first_busno, hose->last_busno, | ||
345 | + devfn, offset, len, bus_addr, *val); | ||
346 | +#endif | ||
347 | + pr_debug("acp_read_config : bus=%3d [%3d..%3d] devfn=0x%04x" | ||
348 | + " offset=0x%04x len=%d, addr=0x%08x val=0x%08x\n", | ||
349 | + bus->number, hose->first_busno, hose->last_busno, | ||
350 | + devfn, offset, len, bus_addr, *val); | ||
351 | + } | ||
352 | + | ||
353 | + /* re-enable machine checks */ | ||
354 | + mtmsr(mfmsr() | (MSR_ME) ); | ||
355 | + __asm__ __volatile__("msync"); | ||
356 | + | ||
357 | + return rc; | ||
358 | +} | ||
359 | + | ||
360 | +static int ppc4xx_pciex_acp_write_config(struct pci_bus *bus, unsigned int devfn, | ||
361 | + int offset, int len, u32 val) | ||
362 | +{ | ||
363 | + struct pci_controller *hose = (struct pci_controller *) bus->sysdata; | ||
364 | + struct ppc4xx_pciex_port *port = | ||
365 | + &ppc4xx_pciex_ports[hose->indirect_type]; | ||
366 | + void __iomem *addr; | ||
367 | + u32 bus_addr; | ||
368 | + u32 val32; | ||
369 | + | ||
370 | + if (ppc4xx_pciex_validate_bdf(port, bus, devfn) != 0) | ||
371 | + return PCIBIOS_DEVICE_NOT_FOUND; | ||
372 | + | ||
373 | + addr = ppc4xx_pciex_get_config_base(port, bus, devfn); | ||
374 | + | ||
375 | + if (!addr) { | ||
376 | + return PCIBIOS_DEVICE_NOT_FOUND; | ||
377 | + } | ||
378 | + | ||
379 | + /* | ||
380 | + * addressing is different for local config access vs. | ||
381 | + * access through the mapped config space. We need to | ||
382 | + * translate the offset for mapped config access | ||
383 | + */ | ||
384 | + if (bus->number == port->hose->first_busno) { | ||
385 | + /* the local ACP RC only supports 32-bit dword config access, | ||
386 | + * so if this is a byte or 16-bit word access we need to | ||
387 | + * perform a read-modify write | ||
388 | + */ | ||
389 | + if (len == 4) { | ||
390 | + bus_addr = (u32) addr + offset; | ||
391 | + } else { | ||
392 | + int bs = ((offset & 0x3) * 8); | ||
393 | + | ||
394 | + bus_addr = (u32) addr + (offset & 0xfffffffc); | ||
395 | + val32 = in_le32((u32 *)bus_addr); | ||
396 | + | ||
397 | + | ||
398 | + if (len == 2) { | ||
399 | + val32 = (val32 & ~(0xffff << bs) ) | ((val & 0xffff) << bs); | ||
400 | + } else { | ||
401 | + val32 = (val32 & ~(0xff << bs) ) | ((val & 0xff) << bs); | ||
402 | + } | ||
403 | + | ||
404 | + val = val32; | ||
405 | + len = 4; | ||
406 | + } | ||
407 | + | ||
408 | + } else { | ||
409 | + bus_addr = (u32) addr + (offset << 2) + (offset & 0x3); | ||
410 | + } | ||
411 | + | ||
412 | +#ifdef PRINT_CONFIG_ACCESSES | ||
413 | + printk("acp_write_config: %3d [%3d..%3d] fn=0x%04x" | ||
414 | + " o=0x%04x l=%d a=0x%08x v=0x%08x\n", | ||
415 | + bus->number, hose->first_busno, hose->last_busno, | ||
416 | + devfn, offset, len, bus_addr, val); | ||
417 | +#endif | ||
418 | + pr_debug("acp_write_config: bus=%3d [%3d..%3d] devfn=0x%04x" | ||
419 | + " offset=0x%04x len=%d, addr=0x%08x val=0x%08x\n", | ||
420 | + bus->number, hose->first_busno, hose->last_busno, | ||
421 | + devfn, offset, len, bus_addr, val); | ||
422 | + | ||
423 | + | ||
424 | + switch (len) { | ||
425 | + case 1: | ||
426 | + out_8((u8 *)(bus_addr), val); | ||
427 | + break; | ||
428 | + case 2: | ||
429 | + out_le16((u16 *)(bus_addr), val); | ||
430 | + break; | ||
431 | + default: | ||
432 | + out_le32((u32 *)(bus_addr), val); | ||
433 | + break; | ||
434 | + } | ||
435 | + | ||
436 | + return PCIBIOS_SUCCESSFUL; | ||
437 | +} | ||
438 | + | ||
439 | +#endif | ||
440 | + | ||
441 | static struct pci_ops ppc4xx_pciex_pci_ops = | ||
442 | { | ||
443 | +#ifndef CONFIG_ACP | ||
444 | .read = ppc4xx_pciex_read_config, | ||
445 | .write = ppc4xx_pciex_write_config, | ||
446 | +#else | ||
447 | + .read = ppc4xx_pciex_acp_read_config, | ||
448 | + .write = ppc4xx_pciex_acp_write_config, | ||
449 | +#endif | ||
450 | }; | ||
451 | |||
452 | static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, | ||
453 | @@ -1718,7 +2079,10 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, | ||
454 | unsigned int flags, | ||
455 | int index) | ||
456 | { | ||
457 | - u32 lah, lal, pciah, pcial, sa; | ||
458 | + u32 pciah, pcial; | ||
459 | +#ifndef CONFIG_ACP | ||
460 | + u32 lah, lal, sa; | ||
461 | +#endif | ||
462 | |||
463 | if (!is_power_of_2(size) || | ||
464 | (index < 2 && size < 0x100000) || | ||
465 | @@ -1730,10 +2094,11 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, | ||
466 | } | ||
467 | |||
468 | /* Calculate register values */ | ||
469 | - lah = RES_TO_U32_HIGH(plb_addr); | ||
470 | - lal = RES_TO_U32_LOW(plb_addr); | ||
471 | pciah = RES_TO_U32_HIGH(pci_addr); | ||
472 | pcial = RES_TO_U32_LOW(pci_addr); | ||
473 | +#ifndef CONFIG_ACP | ||
474 | + lah = RES_TO_U32_HIGH(plb_addr); | ||
475 | + lal = RES_TO_U32_LOW(plb_addr); | ||
476 | sa = (0xffffffffu << ilog2(size)) | 0x1; | ||
477 | |||
478 | /* Program register values */ | ||
479 | @@ -1779,6 +2144,41 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, | ||
480 | | DCRO_PEGPL_OMRxMSKL_VAL); | ||
481 | break; | ||
482 | } | ||
483 | +#else | ||
484 | + { | ||
485 | + /* ACP X1 setup MPAGE registers */ | ||
486 | + | ||
487 | + int i, num_pages; | ||
488 | + u32 mpage_lower; | ||
489 | + | ||
490 | + printk(KERN_INFO "setting outbound window %d with " | ||
491 | + "plb_add=0x%012llx, pci_addr=0x%012llx, size=0x%012llx\n", | ||
492 | + index, plb_addr, pci_addr, size); | ||
493 | + | ||
494 | + /* | ||
495 | + * MPAGE7 is dedicated to config access, so we only | ||
496 | + * have 7 128MB pages available for memory i/o. | ||
497 | + * Calculate how many pages we need | ||
498 | + */ | ||
499 | + if (size > (7 * 0x08000000)) { | ||
500 | + printk(KERN_WARNING "%s: Resource size 0x%012llx out of range\n", | ||
501 | + hose->dn->full_name, size); | ||
502 | + return -1; | ||
503 | + } | ||
504 | + | ||
505 | + num_pages = ( (size - 1) >> 27) + 1; | ||
506 | + for (i = 0; i < num_pages; i++) { | ||
507 | + mpage_lower = (pcial & 0xf8000000); | ||
508 | + | ||
509 | + if (5 > port->acpChipType) | ||
510 | + mpage_lower |= 1; | ||
511 | + | ||
512 | + out_le32( mbase + ACPX1_PCIE_MPAGE_UPPER(i), pciah); | ||
513 | + out_le32( mbase + ACPX1_PCIE_MPAGE_LOWER(i), mpage_lower); | ||
514 | + pcial += 0x08000000; | ||
515 | + } | ||
516 | + } | ||
517 | +#endif | ||
518 | |||
519 | return 0; | ||
520 | } | ||
521 | @@ -1907,6 +2307,108 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, | ||
522 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); | ||
523 | } | ||
524 | |||
525 | +#if defined(CONFIG_ACP) | ||
526 | + | ||
527 | +static void __init | ||
528 | +ppc4xx_configure_acp_pciex_PIMs(struct ppc4xx_pciex_port *port, | ||
529 | + struct pci_controller *hose, | ||
530 | + void __iomem *mbase, | ||
531 | + struct resource *res) | ||
532 | +{ | ||
533 | + resource_size_t size = res->end - res->start + 1; | ||
534 | + u64 sa; | ||
535 | + u32 value = 0; | ||
536 | + void __iomem *tpage_base = mbase + 0x1050; | ||
537 | + | ||
538 | + if (port->endpoint) { | ||
539 | + resource_size_t ep_addr = 0; | ||
540 | + resource_size_t ep_size = 32 << 20; | ||
541 | + | ||
542 | + /* Currently we map a fixed 64MByte window to PLB address | ||
543 | + * 0 (SDRAM). This should probably be configurable via a dts | ||
544 | + * property. | ||
545 | + */ | ||
546 | + | ||
547 | + /* Calculate window size */ | ||
548 | + sa = (0xffffffffffffffffull << ilog2(ep_size));; | ||
549 | + | ||
550 | + /* TODO: */ | ||
551 | + | ||
552 | + out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(ep_addr)); | ||
553 | + out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(ep_addr)); | ||
554 | + } else { | ||
555 | + /* Calculate window size */ | ||
556 | + sa = (0xffffffffffffffffull << ilog2(size));; | ||
557 | + | ||
558 | + if (res->flags & IORESOURCE_PREFETCH) | ||
559 | + sa |= 0x8; | ||
560 | + | ||
561 | + printk(KERN_INFO | ||
562 | + "configure inbound mapping from 0x%012llx-0x%012llx " | ||
563 | + "(0x%08llx bytes)\n", res->start, res->end, size); | ||
564 | + | ||
565 | + if (0 != ncr_read(NCP_REGION_ID(0xa, 0x10), 0x2c, 4, &value)) | ||
566 | + printk(KERN_WARNING "** Unable to get ACP type!\n"); | ||
567 | + | ||
568 | + /* | ||
569 | + * For ACP we need to set the dema_offset to the size of | ||
570 | + * inbound window. | ||
571 | + */ | ||
572 | + | ||
573 | + pci_dram_offset = size; | ||
574 | + hose->dma_window_base_cur = size; | ||
575 | + | ||
576 | + out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(size)); | ||
577 | + out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(size)); | ||
578 | + | ||
579 | + if (5 == port->acpChipType) { | ||
580 | + printk(KERN_WARNING "Setting SIZE for 2500\n"); | ||
581 | + out_le32(mbase + 0x11f4, 0xf0000000UL); | ||
582 | + } | ||
583 | + | ||
584 | + /* | ||
585 | + * set up the TPAGE registers | ||
586 | + * | ||
587 | + * We set the MSB of each TPAGE to select 128-bit AXI access. | ||
588 | + * For the address field we simply program an incrementing value | ||
589 | + * to map consecutive pages | ||
590 | + */ | ||
591 | + if (0 == acp_plx) { | ||
592 | + int i; | ||
593 | + | ||
594 | + for (i = 0; i < 8; i++) { | ||
595 | + out_le32(tpage_base, (0x80000000 + i)); | ||
596 | + tpage_base += 4; | ||
597 | + } | ||
598 | + } else { | ||
599 | + out_le32(tpage_base, 0x0); /* tpage 0 point to 0x0, not used */ | ||
600 | + tpage_base +=4; | ||
601 | + out_le32(tpage_base, 0x0); /* tpage 1 point to 0x0, not used */ | ||
602 | + tpage_base +=4; | ||
603 | + out_le32(tpage_base, 0x0); /* tpage 2 point to 0x0, not used */ | ||
604 | + tpage_base +=4; | ||
605 | + out_le32(tpage_base, 0x0); /* tpage 3 point to 0x0, not used */ | ||
606 | + tpage_base +=4; | ||
607 | + out_le32(tpage_base, 0x0); /* tpage 4 point to 0x0, not used */ | ||
608 | + tpage_base +=4; | ||
609 | + out_le32(tpage_base, 0x0); /* tpage 5 point to 0x0, not used */ | ||
610 | + tpage_base +=4; | ||
611 | + out_le32(tpage_base, 0x0); /* tpage 6 point to 0x0 for dynamic mapping */ | ||
612 | + tpage_base +=4; | ||
613 | + out_le32(tpage_base, 0x80001000); /* tpage 7 point to 0x20,0000,0000 tpage size = 256MB */ | ||
614 | + } | ||
615 | + } | ||
616 | + | ||
617 | + /* Enable I/O, Mem, and Busmaster cycles */ | ||
618 | +#if 0 | ||
619 | + out_le16(mbase + PCI_COMMAND, | ||
620 | + in_le16(mbase + PCI_COMMAND) | | ||
621 | + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); | ||
622 | +#endif | ||
623 | +} | ||
624 | + | ||
625 | +#endif | ||
626 | + | ||
627 | static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) | ||
628 | { | ||
629 | struct resource dma_window; | ||
630 | @@ -2070,6 +2572,439 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) | ||
631 | iounmap(mbase); | ||
632 | } | ||
633 | |||
634 | +#if defined(CONFIG_ACP) | ||
635 | + | ||
636 | +static irqreturn_t | ||
637 | +acp_pcie_isr(int irq, void *arg) | ||
638 | +{ | ||
639 | + struct pci_controller *hose = (struct pci_controller *) arg; | ||
640 | + void __iomem *mbase = (void __iomem *)hose->cfg_addr; | ||
641 | + | ||
642 | + u32 intr_status; | ||
643 | + u32 msg_fifo_stat; | ||
644 | + u32 msg_fifo_info; | ||
645 | + u8 externalPciIntr = 0; | ||
646 | + | ||
647 | + | ||
648 | + /* read the PEI interrupt status register */ | ||
649 | + intr_status = in_le32(mbase + 0x10c0); | ||
650 | +#if 0 | ||
651 | + { | ||
652 | + u32 intr_enb; | ||
653 | + intr_enb = in_le32(mbase + 0x10c4); | ||
654 | + printk("PCIE%d mbase %p intr_status/enb = 0x%08x 0x%08x\n", | ||
655 | + hose->indirect_type, mbase, intr_status, intr_enb); | ||
656 | + } | ||
657 | +#else | ||
658 | + in_le32(mbase + 0x10c4); | ||
659 | +#endif | ||
660 | + | ||
661 | + /* check if this is a PCIe message from an external device */ | ||
662 | + if (intr_status & 0x00000010) { | ||
663 | + externalPciIntr = 1; | ||
664 | + | ||
665 | + msg_fifo_stat = in_le32(mbase + 0x10b4); | ||
666 | + | ||
667 | + /* loop until the message fifo is empty */ | ||
668 | + while ( (msg_fifo_stat & 0x01) == 0) { | ||
669 | + u8 bus, dev, fn; | ||
670 | + u8 msg_type; | ||
671 | + msg_fifo_info = in_le32(mbase + 0x10b0); | ||
672 | + | ||
673 | + bus = (msg_fifo_info >> 16 ) & 0xff; | ||
674 | + dev = (msg_fifo_info >> 11 ) & 0x1f; | ||
675 | + fn = (msg_fifo_info >> 8 ) & 0x07; | ||
676 | + msg_type = msg_fifo_info & 0xff; | ||
677 | + | ||
678 | + /* print out the BDF and message type. | ||
679 | + * We ignore the common message types. | ||
680 | + */ | ||
681 | + switch (msg_type) { | ||
682 | + case 0x20: /* assert_INTa */ | ||
683 | + case 0x21: /* assert_INTb */ | ||
684 | + case 0x22: /* assert_INTc */ | ||
685 | + case 0x23: /* assert_INTd */ | ||
686 | + case 0x24: /* de-assert_INTa */ | ||
687 | + case 0x25: /* de-assert_INTb */ | ||
688 | + case 0x26: /* de-assert_INTc */ | ||
689 | + case 0x27: /* de-assert_INTd */ | ||
690 | + /* do nothing */ | ||
691 | + break; | ||
692 | + default: | ||
693 | + printk("BDF %02x:%02x.%x sent msgtype 0x%02x\n", | ||
694 | + bus, dev, fn, msg_type); | ||
695 | + break; | ||
696 | + } | ||
697 | + | ||
698 | + /* re-read fifo status */ | ||
699 | + msg_fifo_stat = in_le32(mbase + 0x10b4); | ||
700 | + | ||
701 | + } | ||
702 | + } else { | ||
703 | + /* | ||
704 | + Ignore the common interrupts, still need to figure out what | ||
705 | + they all mean. | ||
706 | + */ | ||
707 | + if (intr_status & 0xf3ffffab) { | ||
708 | + u32 t2a_err_stat; | ||
709 | + u32 t2a_other_err_stat; | ||
710 | + u32 int_enb; | ||
711 | + u32 linkStatus; | ||
712 | + u32 offset; | ||
713 | + | ||
714 | + printk(KERN_ERR "ACP_PCIE_ISR: got PEI error interrupt 0x%08x\n", | ||
715 | + intr_status); | ||
716 | + | ||
717 | + linkStatus = in_le32(mbase + 0x117c); | ||
718 | + printk(KERN_ERR "link_status (0x117c) = 0x%08x\n", linkStatus); | ||
719 | + | ||
720 | + if (intr_status & 0x00020000) { | ||
721 | + t2a_err_stat = in_le32(mbase + 0x1170); | ||
722 | + printk(KERN_ERR "t2a_fn_indp_err_stat = 0x%08x\n", t2a_err_stat); | ||
723 | + int_enb = in_le32(mbase + 0x10c4); | ||
724 | + int_enb &= 0xfffdffff; | ||
725 | + out_le32(mbase + 0x10c4, int_enb); | ||
726 | + } | ||
727 | + | ||
728 | + if (intr_status & 0x00040000) { | ||
729 | + t2a_other_err_stat = in_le32(mbase + 0x1174); | ||
730 | + printk(KERN_ERR "t2a_fn_indp_other_err_stat = 0x%08x\n", | ||
731 | + t2a_other_err_stat); | ||
732 | + int_enb = in_le32(mbase + 0x10c4); | ||
733 | + int_enb &= 0xfffbffff; | ||
734 | + out_le32(mbase + 0x10c4, int_enb); | ||
735 | + } | ||
736 | + | ||
737 | + if (intr_status & 0x00000800) { | ||
738 | + printk("pci_config = 0x%08x\n", in_le32(mbase + 0x1000)); | ||
739 | + printk("pci_status = 0x%08x\n", in_le32(mbase + 0x1004)); | ||
740 | + | ||
741 | + int_enb = in_le32(mbase + 0x10c4); | ||
742 | + int_enb &= 0xfffff7ff; | ||
743 | + out_le32(mbase + 0x10c4, int_enb); | ||
744 | + } | ||
745 | + | ||
746 | + /* | ||
747 | + * dump all the potentially interesting PEI registers | ||
748 | + */ | ||
749 | + for (offset = 0x114c; offset <= 0x1180; offset += 4) { | ||
750 | + printk(" 0x%04x : 0x%08x\n", offset, in_le32(mbase + offset)); | ||
751 | + } | ||
752 | + } | ||
753 | + } | ||
754 | + | ||
755 | + /* | ||
756 | + * We clear all the interrupts in the PEI status, even though | ||
757 | + * interrupts from external devices have not yet been handled. | ||
758 | + * That should be okay, since the PCI IRQ in the MPIC won't be | ||
759 | + * re-enabled until all external handlers have been called. | ||
760 | + */ | ||
761 | + out_le32(mbase + 0x10c0, intr_status); | ||
762 | + | ||
763 | + return (externalPciIntr ? IRQ_NONE : IRQ_HANDLED); | ||
764 | +} | ||
765 | + | ||
766 | +static void __init ppc4xx_acp_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) | ||
767 | +{ | ||
768 | + struct resource dma_window; | ||
769 | + struct pci_controller *hose = NULL; | ||
770 | + const int *bus_range; | ||
771 | + int primary = 0, busses; | ||
772 | + void __iomem *mbase = NULL, *cfg_data = NULL; | ||
773 | + int mappedIrq; | ||
774 | + int err; | ||
775 | + u32 pci_status; | ||
776 | + u32 link_state; | ||
777 | + u32 pci_config; | ||
778 | + u32 version; | ||
779 | + | ||
780 | + /* Check if primary bridge */ | ||
781 | + if (of_get_property(port->node, "primary", NULL)) | ||
782 | + primary = 1; | ||
783 | + | ||
784 | + /* Get bus range if any */ | ||
785 | + bus_range = of_get_property(port->node, "bus-range", NULL); | ||
786 | + | ||
787 | + /* Allocate the host controller data structure */ | ||
788 | + hose = pcibios_alloc_controller(port->node); | ||
789 | + if (!hose) | ||
790 | + goto fail; | ||
791 | + | ||
792 | + /* We stick the port number in "indirect_type" so the config space | ||
793 | + * ops can retrieve the port data structure easily | ||
794 | + */ | ||
795 | + hose->indirect_type = port->index; | ||
796 | + | ||
797 | + /* Get bus range */ | ||
798 | + hose->first_busno = bus_range ? bus_range[0] : 0x0; | ||
799 | + hose->last_busno = bus_range ? bus_range[1] : 0xff; | ||
800 | + | ||
801 | + /* Because of how big mapping the config space is (1M per bus), we | ||
802 | + * limit how many busses we support. In the long run, we could replace | ||
803 | + * that with something akin to kmap_atomic instead. We set aside 1 bus | ||
804 | + * for the host itself too. | ||
805 | + */ | ||
806 | + busses = hose->last_busno - hose->first_busno; /* This is off by 1 */ | ||
807 | + if (busses > MAX_PCIE_BUS_MAPPED) { | ||
808 | + busses = MAX_PCIE_BUS_MAPPED; | ||
809 | + hose->last_busno = hose->first_busno + busses; | ||
810 | + } | ||
811 | + | ||
812 | + if (!port->endpoint) { | ||
813 | + /* | ||
814 | + * map the bottom page of PCIe memory for config space access | ||
815 | + */ | ||
816 | + cfg_data = ioremap(port->cfg_space.start, 0x100000); | ||
817 | + if (cfg_data == NULL) { | ||
818 | + printk(KERN_ERR "%s: Can't map external config space !", | ||
819 | + port->node->full_name); | ||
820 | + goto fail; | ||
821 | + } | ||
822 | + hose->cfg_data = cfg_data; | ||
823 | + } | ||
824 | + | ||
825 | + /* | ||
826 | + * The internal config space has already been mapped, so | ||
827 | + * just re-use that virtual address. | ||
828 | + */ | ||
829 | + hose->cfg_addr = port->utl_base; | ||
830 | + | ||
831 | + pr_debug("PCIE %s, bus %d..%d\n", port->node->full_name, | ||
832 | + hose->first_busno, hose->last_busno); | ||
833 | + pr_debug(" config space mapped at: root @0x%p, other @0x%p\n", | ||
834 | + hose->cfg_addr, hose->cfg_data); | ||
835 | + | ||
836 | + /* Setup config space */ | ||
837 | + hose->ops = &ppc4xx_pciex_pci_ops; | ||
838 | + port->hose = hose; | ||
839 | + mbase = (void __iomem *)hose->cfg_addr; | ||
840 | + | ||
841 | + if (port->endpoint) { | ||
842 | + /* if we're an endpoint don't do anything else */ | ||
843 | + printk(KERN_INFO "PCIE%d: successfully set as endpoint\n", | ||
844 | + port->index); | ||
845 | + return; | ||
846 | + } | ||
847 | + | ||
848 | + /* setting up as root complex */ | ||
849 | + pci_config = in_le32(mbase + 0x1000); | ||
850 | + | ||
851 | + pci_status = in_le32(mbase + 0x1004); | ||
852 | + link_state = (pci_status & 0x3f00) >> 8; | ||
853 | + printk("PCIE%d status = 0x%08x : PCI link state = 0x%x\n", | ||
854 | + port->index, pci_status, link_state); | ||
855 | + | ||
856 | + /* make sure the ACP device is configured as PCI Root Complex */ | ||
857 | + if ((pci_status & 0x18) != 0x18) { | ||
858 | + printk("ACP device is not PCI Root Complex! status = 0x%08x\n", | ||
859 | + pci_status); | ||
860 | + goto fail; | ||
861 | + } | ||
862 | + | ||
863 | + /* make sure the link is up */ | ||
864 | + if (link_state != 0xb) { | ||
865 | + /* reset */ | ||
866 | + printk("PCI link in bad state - resetting\n"); | ||
867 | + pci_config |= 1; | ||
868 | + out_le32(mbase + 0x1000, pci_config); | ||
869 | + msleep(1000); | ||
870 | + | ||
871 | + pci_status = in_le32(mbase + 0x1004); | ||
872 | + link_state = (pci_status & 0x3f00) >> 8; | ||
873 | + | ||
874 | + printk("PCI link state now = 0x%x\n", link_state); | ||
875 | + | ||
876 | + if (link_state != 0xb) { | ||
877 | + printk("PCI link still in bad state - giving up!\n"); | ||
878 | + goto fail; | ||
879 | + } | ||
880 | + } | ||
881 | + | ||
882 | + /* get the device version */ | ||
883 | + if (0 != ncr_read(NCP_REGION_ID(0xa, 0x10), 0x2c, 4, &version)) { | ||
884 | + printk(KERN_ERR "Unable to detect ACP revision!\n"); | ||
885 | + goto fail; | ||
886 | + } | ||
887 | + port->acpChipType = (version & 0x1f); | ||
888 | + printk(KERN_INFO "Using PEI register set for ACP chipType %d\n", | ||
889 | + port->acpChipType); | ||
890 | + | ||
891 | + /* | ||
892 | + * Set bus numbers on our root port | ||
893 | + */ | ||
894 | + out_8(mbase + PCI_PRIMARY_BUS, hose->first_busno); | ||
895 | + out_8(mbase + PCI_SECONDARY_BUS, hose->first_busno + 1); | ||
896 | + out_8(mbase + PCI_SUBORDINATE_BUS, hose->last_busno); | ||
897 | + | ||
898 | + | ||
899 | + /* Parse outbound mapping resources */ | ||
900 | + pci_process_bridge_OF_ranges(hose, port->node, primary); | ||
901 | + | ||
902 | + /* Parse inbound mapping resources */ | ||
903 | + if (ppc4xx_parse_dma_ranges(hose, mbase, &dma_window) != 0) | ||
904 | + goto fail; | ||
905 | + | ||
906 | + /* Configure outbound ranges POMs */ | ||
907 | + ppc4xx_configure_pciex_POMs(port, hose, mbase); | ||
908 | + | ||
909 | + /* Configure inbound ranges PIMs */ | ||
910 | + ppc4xx_configure_acp_pciex_PIMs(port, hose, mbase, &dma_window); | ||
911 | + | ||
912 | + /* | ||
913 | + * hook up an interrupt handler | ||
914 | + */ | ||
915 | +#if 0 | ||
916 | + mappedIrq = irq_create_mapping(NULL, 29); | ||
917 | + if (mappedIrq == NO_IRQ) { | ||
918 | + printk(KERN_ERR "irq_create_mapping failed!!!\n"); | ||
919 | + goto fail; | ||
920 | + } | ||
921 | + | ||
922 | + err = set_irq_type(mappedIrq, IRQ_TYPE_LEVEL_HIGH); | ||
923 | + if (err) { | ||
924 | + printk(KERN_ERR "set_irq_type failed!!!!\n"); | ||
925 | + goto fail; | ||
926 | + } | ||
927 | +#endif | ||
928 | + printk("PCIE%d mapping interrupt\n", port->index); | ||
929 | + mappedIrq = irq_of_parse_and_map(port->node, 0); | ||
930 | + | ||
931 | + err = request_irq(mappedIrq, acp_pcie_isr, IRQF_SHARED, "acp_pcie", hose); | ||
932 | + if (err) { | ||
933 | + printk(KERN_ERR "request_irq failed!!!!\n"); | ||
934 | + goto fail; | ||
935 | + } | ||
936 | + | ||
937 | + /* unmask PEI interrupts */ | ||
938 | +#if 0 | ||
939 | + out_le32(mbase + 0x10c4, 0xffffffff); | ||
940 | +#else | ||
941 | + /* for now ignore retry requests, and INT assert/deassert */ | ||
942 | + out_le32(mbase + 0x10c4, 0xf3fffffd); | ||
943 | +#endif | ||
944 | + | ||
945 | + if (port->acpChipType == 1) { | ||
946 | + /* | ||
947 | + * for v2 we need to set the 'axi_interface_rdy' bit | ||
948 | + * this bit didn't exist in X1V1, and means something | ||
949 | + * else for X2... | ||
950 | + */ | ||
951 | + pci_config = in_le32(mbase + 0x1000); | ||
952 | + pci_config |= 0x00040000; | ||
953 | + out_le32(mbase + 0x1000, pci_config); | ||
954 | + } | ||
955 | + | ||
956 | + if (!port->endpoint) { | ||
957 | + printk(KERN_INFO "PCIE%d: successfully set as root-complex\n", | ||
958 | + port->index); | ||
959 | + } else { | ||
960 | + } | ||
961 | + | ||
962 | + return; | ||
963 | + fail: | ||
964 | + if (hose) | ||
965 | + pcibios_free_controller(hose); | ||
966 | + if (cfg_data) | ||
967 | + iounmap(cfg_data); | ||
968 | +} | ||
969 | + | ||
970 | +static void __init ppc4xx_probe_acp_pciex_bridge(struct device_node *np) | ||
971 | +{ | ||
972 | + struct ppc4xx_pciex_port *port; | ||
973 | + const u32 *pval; | ||
974 | + int portno; | ||
975 | + const char *val; | ||
976 | + const u32 *field; | ||
977 | + | ||
978 | + /* First, proceed to core initialization as we assume there's | ||
979 | + * only one PCIe core in the system | ||
980 | + */ | ||
981 | + if (ppc4xx_pciex_check_core_init(np)) | ||
982 | + return; | ||
983 | + | ||
984 | + /* Get the port number from the device-tree */ | ||
985 | + pval = of_get_property(np, "port", NULL); | ||
986 | + if (pval == NULL) { | ||
987 | + printk(KERN_ERR "PCIE: Can't find port number for %s\n", | ||
988 | + np->full_name); | ||
989 | + return; | ||
990 | + } | ||
991 | + portno = *pval; | ||
992 | + if (portno >= ppc4xx_pciex_port_count) { | ||
993 | + printk(KERN_ERR "PCIE: port number out of range for %s\n", | ||
994 | + np->full_name); | ||
995 | + return; | ||
996 | + } | ||
997 | + port = &ppc4xx_pciex_ports[portno]; | ||
998 | + port->index = portno; | ||
999 | + | ||
1000 | + /* | ||
1001 | + * Check if device is enabled | ||
1002 | + */ | ||
1003 | + if (!of_device_is_available(np)) { | ||
1004 | + printk(KERN_INFO "PCIE%d: Port disabled via device-tree\n", | ||
1005 | + port->index); | ||
1006 | + return; | ||
1007 | + } | ||
1008 | + | ||
1009 | + /* Make sure PCIe is enabled in the device tree. */ | ||
1010 | + field = of_get_property(np, "enabled", NULL); | ||
1011 | + | ||
1012 | + if (!field || (field && (0 == *field))) { | ||
1013 | + printk(KERN_INFO "%s: Port disabled via device-tree\n", | ||
1014 | + np->full_name); | ||
1015 | + return; | ||
1016 | + } | ||
1017 | + | ||
1018 | + /* Check for the PLX work-around. */ | ||
1019 | + field = of_get_property(np, "plx", NULL); | ||
1020 | + | ||
1021 | + if (field && (0 != *field)) | ||
1022 | + acp_plx = 1; | ||
1023 | + else | ||
1024 | + acp_plx = 0; | ||
1025 | + | ||
1026 | + port->node = of_node_get(np); | ||
1027 | + | ||
1028 | + /* Check if device_type property is set to "pci" or "pci-endpoint". | ||
1029 | + * Resulting from this setup this PCIe port will be configured | ||
1030 | + * as root-complex or as endpoint. | ||
1031 | + */ | ||
1032 | + val = of_get_property(port->node, "device_type", NULL); | ||
1033 | + if (!strcmp(val, "pci-endpoint")) { | ||
1034 | + port->endpoint = 1; | ||
1035 | + } else if (!strcmp(val, "pci")) { | ||
1036 | + port->endpoint = 0; | ||
1037 | + } else { | ||
1038 | + printk(KERN_ERR "PCIE%d: missing or incorrect device_type for %s\n", | ||
1039 | + portno, np->full_name); | ||
1040 | + return; | ||
1041 | + } | ||
1042 | + | ||
1043 | + /* Fetch config space registers address */ | ||
1044 | + if (of_address_to_resource(np, 0, &port->cfg_space)) { | ||
1045 | + printk(KERN_ERR "%s: Can't get PCI-E config space !", | ||
1046 | + np->full_name); | ||
1047 | + return; | ||
1048 | + } | ||
1049 | + | ||
1050 | + /* Fetch host bridge internal registers address */ | ||
1051 | + if (of_address_to_resource(np, 1, &port->utl_regs)) { | ||
1052 | + printk(KERN_ERR "%s: Can't get UTL register base !", | ||
1053 | + np->full_name); | ||
1054 | + return; | ||
1055 | + } | ||
1056 | + | ||
1057 | + port->utl_base = ioremap(port->utl_regs.start, resource_size(&port->utl_regs)); | ||
1058 | + | ||
1059 | + printk("%s PCIE%d config base = 0x%012llx (0x%08x virtual)\n", np->full_name, port->index, port->utl_regs.start, (u32) port->utl_base); | ||
1060 | + | ||
1061 | + /* Setup the linux hose data structure */ | ||
1062 | + ppc4xx_acp_pciex_port_setup_hose(port); | ||
1063 | +} | ||
1064 | + | ||
1065 | +#endif /* CONFIG_ACP */ | ||
1066 | + | ||
1067 | static void __init ppc4xx_probe_pciex_bridge(struct device_node *np) | ||
1068 | { | ||
1069 | struct ppc4xx_pciex_port *port; | ||
1070 | @@ -2174,6 +3109,11 @@ static int __init ppc4xx_pci_find_bridges(void) | ||
1071 | |||
1072 | pci_add_flags(PCI_ENABLE_PROC_DOMAINS | PCI_COMPAT_DOMAIN_0); | ||
1073 | |||
1074 | +#if defined(CONFIG_ACP) | ||
1075 | + for_each_compatible_node(np, NULL, "lsi,plb-pciex") | ||
1076 | + ppc4xx_probe_acp_pciex_bridge(np); | ||
1077 | +#endif | ||
1078 | + | ||
1079 | #ifdef CONFIG_PPC4xx_PCI_EXPRESS | ||
1080 | for_each_compatible_node(np, NULL, "ibm,plb-pciex") | ||
1081 | ppc4xx_probe_pciex_bridge(np); | ||