Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), | |
3 | * IBM Corp. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU General Public License | |
7 | * as published by the Free Software Foundation; either version | |
8 | * 2 of the License, or (at your option) any later version. | |
9 | */ | |
10 | ||
c10af8c3 | 11 | #undef DEBUG |
1da177e4 LT |
12 | |
13 | #include <linux/kernel.h> | |
14 | #include <linux/pci.h> | |
15 | #include <linux/delay.h> | |
16 | #include <linux/string.h> | |
17 | #include <linux/init.h> | |
c10af8c3 | 18 | #include <linux/irq.h> |
1da177e4 LT |
19 | |
20 | #include <asm/sections.h> | |
21 | #include <asm/io.h> | |
22 | #include <asm/prom.h> | |
23 | #include <asm/pci-bridge.h> | |
24 | #include <asm/machdep.h> | |
25 | #include <asm/iommu.h> | |
d387899f | 26 | #include <asm/ppc-pci.h> |
1da177e4 | 27 | |
0cb7b2af PM |
28 | #include "maple.h" |
29 | ||
1da177e4 LT |
30 | #ifdef DEBUG |
31 | #define DBG(x...) printk(x) | |
32 | #else | |
33 | #define DBG(x...) | |
34 | #endif | |
35 | ||
c10af8c3 | 36 | static struct pci_controller *u3_agp, *u3_ht, *u4_pcie; |
1da177e4 LT |
37 | |
38 | static int __init fixup_one_level_bus_range(struct device_node *node, int higher) | |
39 | { | |
40 | for (; node != 0;node = node->sibling) { | |
eeb2b723 JK |
41 | const int *bus_range; |
42 | const unsigned int *class_code; | |
1da177e4 LT |
43 | int len; |
44 | ||
45 | /* For PCI<->PCI bridges or CardBus bridges, we go down */ | |
e2eb6392 | 46 | class_code = of_get_property(node, "class-code", NULL); |
1da177e4 LT |
47 | if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && |
48 | (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) | |
49 | continue; | |
e2eb6392 | 50 | bus_range = of_get_property(node, "bus-range", &len); |
1da177e4 LT |
51 | if (bus_range != NULL && len > 2 * sizeof(int)) { |
52 | if (bus_range[1] > higher) | |
53 | higher = bus_range[1]; | |
54 | } | |
55 | higher = fixup_one_level_bus_range(node->child, higher); | |
56 | } | |
57 | return higher; | |
58 | } | |
59 | ||
60 | /* This routine fixes the "bus-range" property of all bridges in the | |
61 | * system since they tend to have their "last" member wrong on macs | |
62 | * | |
63 | * Note that the bus numbers manipulated here are OF bus numbers, they | |
64 | * are not Linux bus numbers. | |
65 | */ | |
66 | static void __init fixup_bus_range(struct device_node *bridge) | |
67 | { | |
eeb2b723 JK |
68 | int *bus_range; |
69 | struct property *prop; | |
1da177e4 LT |
70 | int len; |
71 | ||
72 | /* Lookup the "bus-range" property for the hose */ | |
eeb2b723 JK |
73 | prop = of_find_property(bridge, "bus-range", &len); |
74 | if (prop == NULL || prop->value == NULL || len < 2 * sizeof(int)) { | |
1da177e4 LT |
75 | printk(KERN_WARNING "Can't get bus-range for %s\n", |
76 | bridge->full_name); | |
77 | return; | |
78 | } | |
1a38147e | 79 | bus_range = prop->value; |
1da177e4 LT |
80 | bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); |
81 | } | |
82 | ||
83 | ||
cc9881ce NL |
84 | static unsigned long u3_agp_cfa0(u8 devfn, u8 off) |
85 | { | |
86 | return (1 << (unsigned long)PCI_SLOT(devfn)) | | |
87 | ((unsigned long)PCI_FUNC(devfn) << 8) | | |
88 | ((unsigned long)off & 0xFCUL); | |
89 | } | |
1da177e4 | 90 | |
cc9881ce NL |
91 | static unsigned long u3_agp_cfa1(u8 bus, u8 devfn, u8 off) |
92 | { | |
93 | return ((unsigned long)bus << 16) | | |
94 | ((unsigned long)devfn << 8) | | |
95 | ((unsigned long)off & 0xFCUL) | | |
96 | 1UL; | |
97 | } | |
1da177e4 | 98 | |
8c42ec2c | 99 | static volatile void __iomem *u3_agp_cfg_access(struct pci_controller* hose, |
1da177e4 LT |
100 | u8 bus, u8 dev_fn, u8 offset) |
101 | { | |
102 | unsigned int caddr; | |
103 | ||
104 | if (bus == hose->first_busno) { | |
105 | if (dev_fn < (11 << 3)) | |
8c42ec2c | 106 | return NULL; |
cc9881ce | 107 | caddr = u3_agp_cfa0(dev_fn, offset); |
1da177e4 | 108 | } else |
cc9881ce | 109 | caddr = u3_agp_cfa1(bus, dev_fn, offset); |
1da177e4 LT |
110 | |
111 | /* Uninorth will return garbage if we don't read back the value ! */ | |
112 | do { | |
113 | out_le32(hose->cfg_addr, caddr); | |
114 | } while (in_le32(hose->cfg_addr) != caddr); | |
115 | ||
116 | offset &= 0x07; | |
8c42ec2c | 117 | return hose->cfg_data + offset; |
1da177e4 LT |
118 | } |
119 | ||
120 | static int u3_agp_read_config(struct pci_bus *bus, unsigned int devfn, | |
121 | int offset, int len, u32 *val) | |
122 | { | |
123 | struct pci_controller *hose; | |
8c42ec2c | 124 | volatile void __iomem *addr; |
1da177e4 LT |
125 | |
126 | hose = pci_bus_to_host(bus); | |
127 | if (hose == NULL) | |
128 | return PCIBIOS_DEVICE_NOT_FOUND; | |
129 | ||
130 | addr = u3_agp_cfg_access(hose, bus->number, devfn, offset); | |
131 | if (!addr) | |
132 | return PCIBIOS_DEVICE_NOT_FOUND; | |
133 | /* | |
134 | * Note: the caller has already checked that offset is | |
135 | * suitably aligned and that len is 1, 2 or 4. | |
136 | */ | |
137 | switch (len) { | |
138 | case 1: | |
8c42ec2c | 139 | *val = in_8(addr); |
1da177e4 LT |
140 | break; |
141 | case 2: | |
8c42ec2c | 142 | *val = in_le16(addr); |
1da177e4 LT |
143 | break; |
144 | default: | |
8c42ec2c | 145 | *val = in_le32(addr); |
1da177e4 LT |
146 | break; |
147 | } | |
148 | return PCIBIOS_SUCCESSFUL; | |
149 | } | |
150 | ||
151 | static int u3_agp_write_config(struct pci_bus *bus, unsigned int devfn, | |
152 | int offset, int len, u32 val) | |
153 | { | |
154 | struct pci_controller *hose; | |
8c42ec2c | 155 | volatile void __iomem *addr; |
1da177e4 LT |
156 | |
157 | hose = pci_bus_to_host(bus); | |
158 | if (hose == NULL) | |
159 | return PCIBIOS_DEVICE_NOT_FOUND; | |
160 | ||
161 | addr = u3_agp_cfg_access(hose, bus->number, devfn, offset); | |
162 | if (!addr) | |
163 | return PCIBIOS_DEVICE_NOT_FOUND; | |
164 | /* | |
165 | * Note: the caller has already checked that offset is | |
166 | * suitably aligned and that len is 1, 2 or 4. | |
167 | */ | |
168 | switch (len) { | |
169 | case 1: | |
8c42ec2c | 170 | out_8(addr, val); |
1da177e4 LT |
171 | break; |
172 | case 2: | |
8c42ec2c | 173 | out_le16(addr, val); |
1da177e4 LT |
174 | break; |
175 | default: | |
8c42ec2c | 176 | out_le32(addr, val); |
1da177e4 LT |
177 | break; |
178 | } | |
179 | return PCIBIOS_SUCCESSFUL; | |
180 | } | |
181 | ||
182 | static struct pci_ops u3_agp_pci_ops = | |
183 | { | |
2e67d407 NL |
184 | .read = u3_agp_read_config, |
185 | .write = u3_agp_write_config, | |
1da177e4 LT |
186 | }; |
187 | ||
cc9881ce NL |
188 | static unsigned long u3_ht_cfa0(u8 devfn, u8 off) |
189 | { | |
190 | return (devfn << 8) | off; | |
191 | } | |
1da177e4 | 192 | |
cc9881ce NL |
193 | static unsigned long u3_ht_cfa1(u8 bus, u8 devfn, u8 off) |
194 | { | |
195 | return u3_ht_cfa0(devfn, off) + (bus << 16) + 0x01000000UL; | |
196 | } | |
1da177e4 | 197 | |
8c42ec2c | 198 | static volatile void __iomem *u3_ht_cfg_access(struct pci_controller* hose, |
1da177e4 LT |
199 | u8 bus, u8 devfn, u8 offset) |
200 | { | |
201 | if (bus == hose->first_busno) { | |
202 | if (PCI_SLOT(devfn) == 0) | |
8c42ec2c AV |
203 | return NULL; |
204 | return hose->cfg_data + u3_ht_cfa0(devfn, offset); | |
1da177e4 | 205 | } else |
8c42ec2c | 206 | return hose->cfg_data + u3_ht_cfa1(bus, devfn, offset); |
1da177e4 LT |
207 | } |
208 | ||
f49a0c9c DES |
209 | static int u3_ht_root_read_config(struct pci_controller *hose, u8 offset, |
210 | int len, u32 *val) | |
211 | { | |
212 | volatile void __iomem *addr; | |
213 | ||
214 | addr = hose->cfg_addr; | |
215 | addr += ((offset & ~3) << 2) + (4 - len - (offset & 3)); | |
216 | ||
217 | switch (len) { | |
218 | case 1: | |
219 | *val = in_8(addr); | |
220 | break; | |
221 | case 2: | |
222 | *val = in_be16(addr); | |
223 | break; | |
224 | default: | |
225 | *val = in_be32(addr); | |
226 | break; | |
227 | } | |
228 | ||
229 | return PCIBIOS_SUCCESSFUL; | |
230 | } | |
231 | ||
232 | static int u3_ht_root_write_config(struct pci_controller *hose, u8 offset, | |
233 | int len, u32 val) | |
234 | { | |
235 | volatile void __iomem *addr; | |
236 | ||
237 | addr = hose->cfg_addr + ((offset & ~3) << 2) + (4 - len - (offset & 3)); | |
238 | ||
239 | if (offset >= PCI_BASE_ADDRESS_0 && offset < PCI_CAPABILITY_LIST) | |
240 | return PCIBIOS_SUCCESSFUL; | |
241 | ||
242 | switch (len) { | |
243 | case 1: | |
244 | out_8(addr, val); | |
245 | break; | |
246 | case 2: | |
247 | out_be16(addr, val); | |
248 | break; | |
249 | default: | |
250 | out_be32(addr, val); | |
251 | break; | |
252 | } | |
253 | ||
254 | return PCIBIOS_SUCCESSFUL; | |
255 | } | |
256 | ||
1da177e4 LT |
257 | static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, |
258 | int offset, int len, u32 *val) | |
259 | { | |
260 | struct pci_controller *hose; | |
8c42ec2c | 261 | volatile void __iomem *addr; |
1da177e4 LT |
262 | |
263 | hose = pci_bus_to_host(bus); | |
264 | if (hose == NULL) | |
265 | return PCIBIOS_DEVICE_NOT_FOUND; | |
266 | ||
f49a0c9c DES |
267 | if (bus->number == hose->first_busno && devfn == PCI_DEVFN(0, 0)) |
268 | return u3_ht_root_read_config(hose, offset, len, val); | |
269 | ||
d608df5c NL |
270 | if (offset > 0xff) |
271 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
272 | ||
1da177e4 LT |
273 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); |
274 | if (!addr) | |
275 | return PCIBIOS_DEVICE_NOT_FOUND; | |
276 | ||
277 | /* | |
278 | * Note: the caller has already checked that offset is | |
279 | * suitably aligned and that len is 1, 2 or 4. | |
280 | */ | |
281 | switch (len) { | |
282 | case 1: | |
8c42ec2c | 283 | *val = in_8(addr); |
1da177e4 LT |
284 | break; |
285 | case 2: | |
8c42ec2c | 286 | *val = in_le16(addr); |
1da177e4 LT |
287 | break; |
288 | default: | |
8c42ec2c | 289 | *val = in_le32(addr); |
1da177e4 LT |
290 | break; |
291 | } | |
292 | return PCIBIOS_SUCCESSFUL; | |
293 | } | |
294 | ||
295 | static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, | |
296 | int offset, int len, u32 val) | |
297 | { | |
298 | struct pci_controller *hose; | |
8c42ec2c | 299 | volatile void __iomem *addr; |
1da177e4 LT |
300 | |
301 | hose = pci_bus_to_host(bus); | |
302 | if (hose == NULL) | |
303 | return PCIBIOS_DEVICE_NOT_FOUND; | |
304 | ||
f49a0c9c DES |
305 | if (bus->number == hose->first_busno && devfn == PCI_DEVFN(0, 0)) |
306 | return u3_ht_root_write_config(hose, offset, len, val); | |
307 | ||
d608df5c NL |
308 | if (offset > 0xff) |
309 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
310 | ||
1da177e4 LT |
311 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); |
312 | if (!addr) | |
313 | return PCIBIOS_DEVICE_NOT_FOUND; | |
314 | /* | |
315 | * Note: the caller has already checked that offset is | |
316 | * suitably aligned and that len is 1, 2 or 4. | |
317 | */ | |
318 | switch (len) { | |
319 | case 1: | |
8c42ec2c | 320 | out_8(addr, val); |
1da177e4 LT |
321 | break; |
322 | case 2: | |
8c42ec2c | 323 | out_le16(addr, val); |
1da177e4 LT |
324 | break; |
325 | default: | |
8c42ec2c | 326 | out_le32(addr, val); |
1da177e4 LT |
327 | break; |
328 | } | |
329 | return PCIBIOS_SUCCESSFUL; | |
330 | } | |
331 | ||
332 | static struct pci_ops u3_ht_pci_ops = | |
333 | { | |
2e67d407 NL |
334 | .read = u3_ht_read_config, |
335 | .write = u3_ht_write_config, | |
1da177e4 LT |
336 | }; |
337 | ||
c10af8c3 BH |
338 | static unsigned int u4_pcie_cfa0(unsigned int devfn, unsigned int off) |
339 | { | |
340 | return (1 << PCI_SLOT(devfn)) | | |
341 | (PCI_FUNC(devfn) << 8) | | |
342 | ((off >> 8) << 28) | | |
343 | (off & 0xfcu); | |
344 | } | |
345 | ||
346 | static unsigned int u4_pcie_cfa1(unsigned int bus, unsigned int devfn, | |
347 | unsigned int off) | |
348 | { | |
349 | return (bus << 16) | | |
350 | (devfn << 8) | | |
351 | ((off >> 8) << 28) | | |
352 | (off & 0xfcu) | 1u; | |
353 | } | |
354 | ||
355 | static volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose, | |
356 | u8 bus, u8 dev_fn, int offset) | |
357 | { | |
358 | unsigned int caddr; | |
359 | ||
360 | if (bus == hose->first_busno) | |
361 | caddr = u4_pcie_cfa0(dev_fn, offset); | |
362 | else | |
363 | caddr = u4_pcie_cfa1(bus, dev_fn, offset); | |
364 | ||
365 | /* Uninorth will return garbage if we don't read back the value ! */ | |
366 | do { | |
367 | out_le32(hose->cfg_addr, caddr); | |
368 | } while (in_le32(hose->cfg_addr) != caddr); | |
369 | ||
370 | offset &= 0x03; | |
371 | return hose->cfg_data + offset; | |
372 | } | |
373 | ||
374 | static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn, | |
375 | int offset, int len, u32 *val) | |
376 | { | |
377 | struct pci_controller *hose; | |
378 | volatile void __iomem *addr; | |
379 | ||
380 | hose = pci_bus_to_host(bus); | |
381 | if (hose == NULL) | |
382 | return PCIBIOS_DEVICE_NOT_FOUND; | |
383 | if (offset >= 0x1000) | |
384 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
385 | addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); | |
386 | if (!addr) | |
387 | return PCIBIOS_DEVICE_NOT_FOUND; | |
388 | /* | |
389 | * Note: the caller has already checked that offset is | |
390 | * suitably aligned and that len is 1, 2 or 4. | |
391 | */ | |
392 | switch (len) { | |
393 | case 1: | |
394 | *val = in_8(addr); | |
395 | break; | |
396 | case 2: | |
397 | *val = in_le16(addr); | |
398 | break; | |
399 | default: | |
400 | *val = in_le32(addr); | |
401 | break; | |
402 | } | |
403 | return PCIBIOS_SUCCESSFUL; | |
404 | } | |
405 | static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, | |
406 | int offset, int len, u32 val) | |
407 | { | |
408 | struct pci_controller *hose; | |
409 | volatile void __iomem *addr; | |
410 | ||
411 | hose = pci_bus_to_host(bus); | |
412 | if (hose == NULL) | |
413 | return PCIBIOS_DEVICE_NOT_FOUND; | |
414 | if (offset >= 0x1000) | |
415 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
416 | addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); | |
417 | if (!addr) | |
418 | return PCIBIOS_DEVICE_NOT_FOUND; | |
419 | /* | |
420 | * Note: the caller has already checked that offset is | |
421 | * suitably aligned and that len is 1, 2 or 4. | |
422 | */ | |
423 | switch (len) { | |
424 | case 1: | |
425 | out_8(addr, val); | |
c10af8c3 BH |
426 | break; |
427 | case 2: | |
428 | out_le16(addr, val); | |
c10af8c3 BH |
429 | break; |
430 | default: | |
431 | out_le32(addr, val); | |
c10af8c3 BH |
432 | break; |
433 | } | |
434 | return PCIBIOS_SUCCESSFUL; | |
435 | } | |
436 | ||
437 | static struct pci_ops u4_pcie_pci_ops = | |
438 | { | |
2e67d407 NL |
439 | .read = u4_pcie_read_config, |
440 | .write = u4_pcie_write_config, | |
c10af8c3 BH |
441 | }; |
442 | ||
1da177e4 LT |
443 | static void __init setup_u3_agp(struct pci_controller* hose) |
444 | { | |
445 | /* On G5, we move AGP up to high bus number so we don't need | |
446 | * to reassign bus numbers for HT. If we ever have P2P bridges | |
399fe2bd | 447 | * on AGP, we'll have to move pci_assign_all_buses to the |
1da177e4 LT |
448 | * pci_controller structure so we enable it for AGP and not for |
449 | * HT childs. | |
450 | * We hard code the address because of the different size of | |
451 | * the reg address cell, we shall fix that by killing struct | |
452 | * reg_property and using some accessor functions instead | |
453 | */ | |
3238e9c9 | 454 | hose->first_busno = 0xf0; |
1da177e4 LT |
455 | hose->last_busno = 0xff; |
456 | hose->ops = &u3_agp_pci_ops; | |
457 | hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); | |
458 | hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); | |
459 | ||
460 | u3_agp = hose; | |
461 | } | |
462 | ||
c10af8c3 BH |
463 | static void __init setup_u4_pcie(struct pci_controller* hose) |
464 | { | |
465 | /* We currently only implement the "non-atomic" config space, to | |
466 | * be optimised later. | |
467 | */ | |
468 | hose->ops = &u4_pcie_pci_ops; | |
469 | hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); | |
470 | hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); | |
471 | ||
c10af8c3 BH |
472 | u4_pcie = hose; |
473 | } | |
474 | ||
1da177e4 LT |
475 | static void __init setup_u3_ht(struct pci_controller* hose) |
476 | { | |
477 | hose->ops = &u3_ht_pci_ops; | |
478 | ||
479 | /* We hard code the address because of the different size of | |
480 | * the reg address cell, we shall fix that by killing struct | |
481 | * reg_property and using some accessor functions instead | |
482 | */ | |
8c42ec2c | 483 | hose->cfg_data = ioremap(0xf2000000, 0x02000000); |
f49a0c9c | 484 | hose->cfg_addr = ioremap(0xf8070000, 0x1000); |
1da177e4 LT |
485 | |
486 | hose->first_busno = 0; | |
487 | hose->last_busno = 0xef; | |
488 | ||
489 | u3_ht = hose; | |
490 | } | |
491 | ||
09b55f76 | 492 | static int __init maple_add_bridge(struct device_node *dev) |
1da177e4 LT |
493 | { |
494 | int len; | |
495 | struct pci_controller *hose; | |
496 | char* disp_name; | |
eeb2b723 | 497 | const int *bus_range; |
1da177e4 | 498 | int primary = 1; |
1da177e4 LT |
499 | |
500 | DBG("Adding PCI host bridge %s\n", dev->full_name); | |
501 | ||
e2eb6392 | 502 | bus_range = of_get_property(dev, "bus-range", &len); |
3238e9c9 AB |
503 | if (bus_range == NULL || len < 2 * sizeof(int)) { |
504 | printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", | |
505 | dev->full_name); | |
506 | } | |
1da177e4 | 507 | |
b5166cc2 | 508 | hose = pcibios_alloc_controller(dev); |
1da177e4 LT |
509 | if (hose == NULL) |
510 | return -ENOMEM; | |
3238e9c9 AB |
511 | hose->first_busno = bus_range ? bus_range[0] : 0; |
512 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | |
19124d6d | 513 | hose->controller_ops = maple_pci_controller_ops; |
1da177e4 | 514 | |
1da177e4 | 515 | disp_name = NULL; |
55b61fec | 516 | if (of_device_is_compatible(dev, "u3-agp")) { |
3238e9c9 AB |
517 | setup_u3_agp(hose); |
518 | disp_name = "U3-AGP"; | |
519 | primary = 0; | |
55b61fec | 520 | } else if (of_device_is_compatible(dev, "u3-ht")) { |
3238e9c9 AB |
521 | setup_u3_ht(hose); |
522 | disp_name = "U3-HT"; | |
523 | primary = 1; | |
55b61fec | 524 | } else if (of_device_is_compatible(dev, "u4-pcie")) { |
c10af8c3 BH |
525 | setup_u4_pcie(hose); |
526 | disp_name = "U4-PCIE"; | |
527 | primary = 0; | |
3238e9c9 AB |
528 | } |
529 | printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", | |
530 | disp_name, hose->first_busno, hose->last_busno); | |
531 | ||
532 | /* Interpret the "ranges" property */ | |
533 | /* This also maps the I/O region and sets isa_io/mem_base */ | |
f7abbc19 | 534 | pci_process_bridge_OF_ranges(hose, dev, primary); |
1da177e4 | 535 | |
3238e9c9 AB |
536 | /* Fixup "bus-range" OF property */ |
537 | fixup_bus_range(dev); | |
1da177e4 | 538 | |
17cd87c2 BH |
539 | /* Check for legacy IOs */ |
540 | isa_bridge_find_early(hose); | |
541 | ||
1da177e4 LT |
542 | return 0; |
543 | } | |
544 | ||
545 | ||
cad5cef6 | 546 | void maple_pci_irq_fixup(struct pci_dev *dev) |
1da177e4 | 547 | { |
f90bb153 BH |
548 | DBG(" -> maple_pci_irq_fixup\n"); |
549 | ||
550 | /* Fixup IRQ for PCIe host */ | |
551 | if (u4_pcie != NULL && dev->bus->number == 0 && | |
552 | pci_bus_to_host(dev->bus) == u4_pcie) { | |
553 | printk(KERN_DEBUG "Fixup U4 PCIe IRQ\n"); | |
554 | dev->irq = irq_create_mapping(NULL, 1); | |
555 | if (dev->irq != NO_IRQ) | |
ec775d0e | 556 | irq_set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW); |
f90bb153 | 557 | } |
1e1b20a1 | 558 | |
f90bb153 BH |
559 | /* Hide AMD8111 IDE interrupt when in legacy mode so |
560 | * the driver calls pci_get_legacy_ide_irq() | |
561 | */ | |
562 | if (dev->vendor == PCI_VENDOR_ID_AMD && | |
563 | dev->device == PCI_DEVICE_ID_AMD_8111_IDE && | |
564 | (dev->class & 5) != 5) { | |
565 | dev->irq = NO_IRQ; | |
c10af8c3 | 566 | } |
1da177e4 | 567 | |
f90bb153 | 568 | DBG(" <- maple_pci_irq_fixup\n"); |
1da177e4 LT |
569 | } |
570 | ||
1da177e4 LT |
571 | void __init maple_pci_init(void) |
572 | { | |
573 | struct device_node *np, *root; | |
574 | struct device_node *ht = NULL; | |
575 | ||
576 | /* Probe root PCI hosts, that is on U3 the AGP host and the | |
577 | * HyperTransport host. That one is actually "kept" around | |
578 | * and actually added last as it's resource management relies | |
579 | * on the AGP resources to have been setup first | |
580 | */ | |
581 | root = of_find_node_by_path("/"); | |
582 | if (root == NULL) { | |
583 | printk(KERN_CRIT "maple_find_bridges: can't find root of device tree\n"); | |
584 | return; | |
585 | } | |
586 | for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { | |
f1f00333 | 587 | if (!np->type) |
1da177e4 | 588 | continue; |
f1f00333 NL |
589 | if (strcmp(np->type, "pci") && strcmp(np->type, "ht")) |
590 | continue; | |
55b61fec SR |
591 | if ((of_device_is_compatible(np, "u4-pcie") || |
592 | of_device_is_compatible(np, "u3-agp")) && | |
09b55f76 | 593 | maple_add_bridge(np) == 0) |
f1f00333 NL |
594 | of_node_get(np); |
595 | ||
55b61fec | 596 | if (of_device_is_compatible(np, "u3-ht")) { |
1da177e4 LT |
597 | of_node_get(np); |
598 | ht = np; | |
599 | } | |
600 | } | |
601 | of_node_put(root); | |
602 | ||
603 | /* Now setup the HyperTransport host if we found any | |
604 | */ | |
09b55f76 | 605 | if (ht && maple_add_bridge(ht) != 0) |
1da177e4 LT |
606 | of_node_put(ht); |
607 | ||
1da177e4 LT |
608 | /* Setup the linkage between OF nodes and PHBs */ |
609 | pci_devs_phb_init(); | |
610 | ||
611 | /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We | |
612 | * assume there is no P2P bridge on the AGP bus, which should be a | |
613 | * safe assumptions hopefully. | |
614 | */ | |
615 | if (u3_agp) { | |
44ef3390 | 616 | struct device_node *np = u3_agp->dn; |
1635317f | 617 | PCI_DN(np)->busno = 0xf0; |
1da177e4 | 618 | for (np = np->child; np; np = np->sibling) |
1635317f | 619 | PCI_DN(np)->busno = 0xf0; |
1da177e4 LT |
620 | } |
621 | ||
4558f417 | 622 | /* Tell pci.c to not change any resource allocations. */ |
673c9756 | 623 | pci_add_flags(PCI_PROBE_ONLY); |
1da177e4 LT |
624 | } |
625 | ||
626 | int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel) | |
627 | { | |
628 | struct device_node *np; | |
0ebfff14 BH |
629 | unsigned int defirq = channel ? 15 : 14; |
630 | unsigned int irq; | |
1da177e4 LT |
631 | |
632 | if (pdev->vendor != PCI_VENDOR_ID_AMD || | |
633 | pdev->device != PCI_DEVICE_ID_AMD_8111_IDE) | |
0ebfff14 | 634 | return defirq; |
1da177e4 LT |
635 | |
636 | np = pci_device_to_OF_node(pdev); | |
c10af8c3 BH |
637 | if (np == NULL) { |
638 | printk("Failed to locate OF node for IDE %s\n", | |
639 | pci_name(pdev)); | |
0ebfff14 | 640 | return defirq; |
c10af8c3 | 641 | } |
0ebfff14 BH |
642 | irq = irq_of_parse_and_map(np, channel & 0x1); |
643 | if (irq == NO_IRQ) { | |
644 | printk("Failed to map onboard IDE interrupt for channel %d\n", | |
645 | channel); | |
646 | return defirq; | |
647 | } | |
648 | return irq; | |
1da177e4 | 649 | } |
6eb0ac03 | 650 | |
cad5cef6 | 651 | static void quirk_ipr_msi(struct pci_dev *dev) |
6eb0ac03 ME |
652 | { |
653 | /* Something prevents MSIs from the IPR from working on Bimini, | |
654 | * and the driver has no smarts to recover. So disable MSI | |
655 | * on it for now. */ | |
656 | ||
657 | if (machine_is(maple)) { | |
658 | dev->no_msi = 1; | |
659 | dev_info(&dev->dev, "Quirk disabled MSI\n"); | |
660 | } | |
661 | } | |
662 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, | |
663 | quirk_ipr_msi); | |
19124d6d DA |
664 | |
665 | struct pci_controller_ops maple_pci_controller_ops = { | |
666 | }; |