diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2006-10-08 23:25:15 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-10-09 21:54:26 -0400 |
commit | c10af8c38da7a0bc9010d6609237c1ab6d2da12c (patch) | |
tree | 49db04ebb078752d4593c7fc6c2f247fbd4cbcb3 /arch/powerpc/platforms/maple/pci.c | |
parent | 020533ef24309803789ab8b325b1a6463388decf (diff) |
[POWERPC] Make U4 PCIe work on maple
The Maple support code was missing code for U4/CPC945 PCIe. This adds
it, enabling it to work on tigerwood boards, and possibly also js21
using SLOF. Also disable an obsolete firmware workaround.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/maple/pci.c')
-rw-r--r-- | arch/powerpc/platforms/maple/pci.c | 176 |
1 files changed, 169 insertions, 7 deletions
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 1b827618e05f..8debae3aa3c9 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * 2 of the License, or (at your option) any later version. | 8 | * 2 of the License, or (at your option) any later version. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #define DEBUG | 11 | #undef DEBUG |
12 | 12 | ||
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/pci.h> | 14 | #include <linux/pci.h> |
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/bootmem.h> | 18 | #include <linux/bootmem.h> |
19 | #include <linux/irq.h> | ||
19 | 20 | ||
20 | #include <asm/sections.h> | 21 | #include <asm/sections.h> |
21 | #include <asm/io.h> | 22 | #include <asm/io.h> |
@@ -33,7 +34,7 @@ | |||
33 | #define DBG(x...) | 34 | #define DBG(x...) |
34 | #endif | 35 | #endif |
35 | 36 | ||
36 | static struct pci_controller *u3_agp, *u3_ht; | 37 | static struct pci_controller *u3_agp, *u3_ht, *u4_pcie; |
37 | 38 | ||
38 | static int __init fixup_one_level_bus_range(struct device_node *node, int higher) | 39 | static int __init fixup_one_level_bus_range(struct device_node *node, int higher) |
39 | { | 40 | { |
@@ -287,6 +288,114 @@ static struct pci_ops u3_ht_pci_ops = | |||
287 | u3_ht_write_config | 288 | u3_ht_write_config |
288 | }; | 289 | }; |
289 | 290 | ||
291 | static unsigned int u4_pcie_cfa0(unsigned int devfn, unsigned int off) | ||
292 | { | ||
293 | return (1 << PCI_SLOT(devfn)) | | ||
294 | (PCI_FUNC(devfn) << 8) | | ||
295 | ((off >> 8) << 28) | | ||
296 | (off & 0xfcu); | ||
297 | } | ||
298 | |||
299 | static unsigned int u4_pcie_cfa1(unsigned int bus, unsigned int devfn, | ||
300 | unsigned int off) | ||
301 | { | ||
302 | return (bus << 16) | | ||
303 | (devfn << 8) | | ||
304 | ((off >> 8) << 28) | | ||
305 | (off & 0xfcu) | 1u; | ||
306 | } | ||
307 | |||
308 | static volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose, | ||
309 | u8 bus, u8 dev_fn, int offset) | ||
310 | { | ||
311 | unsigned int caddr; | ||
312 | |||
313 | if (bus == hose->first_busno) | ||
314 | caddr = u4_pcie_cfa0(dev_fn, offset); | ||
315 | else | ||
316 | caddr = u4_pcie_cfa1(bus, dev_fn, offset); | ||
317 | |||
318 | /* Uninorth will return garbage if we don't read back the value ! */ | ||
319 | do { | ||
320 | out_le32(hose->cfg_addr, caddr); | ||
321 | } while (in_le32(hose->cfg_addr) != caddr); | ||
322 | |||
323 | offset &= 0x03; | ||
324 | return hose->cfg_data + offset; | ||
325 | } | ||
326 | |||
327 | static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn, | ||
328 | int offset, int len, u32 *val) | ||
329 | { | ||
330 | struct pci_controller *hose; | ||
331 | volatile void __iomem *addr; | ||
332 | |||
333 | hose = pci_bus_to_host(bus); | ||
334 | if (hose == NULL) | ||
335 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
336 | if (offset >= 0x1000) | ||
337 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
338 | addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); | ||
339 | if (!addr) | ||
340 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
341 | /* | ||
342 | * Note: the caller has already checked that offset is | ||
343 | * suitably aligned and that len is 1, 2 or 4. | ||
344 | */ | ||
345 | switch (len) { | ||
346 | case 1: | ||
347 | *val = in_8(addr); | ||
348 | break; | ||
349 | case 2: | ||
350 | *val = in_le16(addr); | ||
351 | break; | ||
352 | default: | ||
353 | *val = in_le32(addr); | ||
354 | break; | ||
355 | } | ||
356 | return PCIBIOS_SUCCESSFUL; | ||
357 | } | ||
358 | static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, | ||
359 | int offset, int len, u32 val) | ||
360 | { | ||
361 | struct pci_controller *hose; | ||
362 | volatile void __iomem *addr; | ||
363 | |||
364 | hose = pci_bus_to_host(bus); | ||
365 | if (hose == NULL) | ||
366 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
367 | if (offset >= 0x1000) | ||
368 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
369 | addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); | ||
370 | if (!addr) | ||
371 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
372 | /* | ||
373 | * Note: the caller has already checked that offset is | ||
374 | * suitably aligned and that len is 1, 2 or 4. | ||
375 | */ | ||
376 | switch (len) { | ||
377 | case 1: | ||
378 | out_8(addr, val); | ||
379 | (void) in_8(addr); | ||
380 | break; | ||
381 | case 2: | ||
382 | out_le16(addr, val); | ||
383 | (void) in_le16(addr); | ||
384 | break; | ||
385 | default: | ||
386 | out_le32(addr, val); | ||
387 | (void) in_le32(addr); | ||
388 | break; | ||
389 | } | ||
390 | return PCIBIOS_SUCCESSFUL; | ||
391 | } | ||
392 | |||
393 | static struct pci_ops u4_pcie_pci_ops = | ||
394 | { | ||
395 | u4_pcie_read_config, | ||
396 | u4_pcie_write_config | ||
397 | }; | ||
398 | |||
290 | static void __init setup_u3_agp(struct pci_controller* hose) | 399 | static void __init setup_u3_agp(struct pci_controller* hose) |
291 | { | 400 | { |
292 | /* On G5, we move AGP up to high bus number so we don't need | 401 | /* On G5, we move AGP up to high bus number so we don't need |
@@ -307,6 +416,26 @@ static void __init setup_u3_agp(struct pci_controller* hose) | |||
307 | u3_agp = hose; | 416 | u3_agp = hose; |
308 | } | 417 | } |
309 | 418 | ||
419 | static void __init setup_u4_pcie(struct pci_controller* hose) | ||
420 | { | ||
421 | /* We currently only implement the "non-atomic" config space, to | ||
422 | * be optimised later. | ||
423 | */ | ||
424 | hose->ops = &u4_pcie_pci_ops; | ||
425 | hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); | ||
426 | hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); | ||
427 | |||
428 | /* The bus contains a bridge from root -> device, we need to | ||
429 | * make it visible on bus 0 so that we pick the right type | ||
430 | * of config cycles. If we didn't, we would have to force all | ||
431 | * config cycles to be type 1. So we override the "bus-range" | ||
432 | * property here | ||
433 | */ | ||
434 | hose->first_busno = 0x00; | ||
435 | hose->last_busno = 0xff; | ||
436 | u4_pcie = hose; | ||
437 | } | ||
438 | |||
310 | static void __init setup_u3_ht(struct pci_controller* hose) | 439 | static void __init setup_u3_ht(struct pci_controller* hose) |
311 | { | 440 | { |
312 | hose->ops = &u3_ht_pci_ops; | 441 | hose->ops = &u3_ht_pci_ops; |
@@ -354,6 +483,10 @@ static int __init add_bridge(struct device_node *dev) | |||
354 | setup_u3_ht(hose); | 483 | setup_u3_ht(hose); |
355 | disp_name = "U3-HT"; | 484 | disp_name = "U3-HT"; |
356 | primary = 1; | 485 | primary = 1; |
486 | } else if (device_is_compatible(dev, "u4-pcie")) { | ||
487 | setup_u4_pcie(hose); | ||
488 | disp_name = "U4-PCIE"; | ||
489 | primary = 0; | ||
357 | } | 490 | } |
358 | printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", | 491 | printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", |
359 | disp_name, hose->first_busno, hose->last_busno); | 492 | disp_name, hose->first_busno, hose->last_busno); |
@@ -361,7 +494,6 @@ static int __init add_bridge(struct device_node *dev) | |||
361 | /* Interpret the "ranges" property */ | 494 | /* Interpret the "ranges" property */ |
362 | /* This also maps the I/O region and sets isa_io/mem_base */ | 495 | /* This also maps the I/O region and sets isa_io/mem_base */ |
363 | pci_process_bridge_OF_ranges(hose, dev, primary); | 496 | pci_process_bridge_OF_ranges(hose, dev, primary); |
364 | pci_setup_phb_io(hose, primary); | ||
365 | 497 | ||
366 | /* Fixup "bus-range" OF property */ | 498 | /* Fixup "bus-range" OF property */ |
367 | fixup_bus_range(dev); | 499 | fixup_bus_range(dev); |
@@ -376,8 +508,17 @@ void __init maple_pcibios_fixup(void) | |||
376 | 508 | ||
377 | DBG(" -> maple_pcibios_fixup\n"); | 509 | DBG(" -> maple_pcibios_fixup\n"); |
378 | 510 | ||
379 | for_each_pci_dev(dev) | 511 | for_each_pci_dev(dev) { |
380 | pci_read_irq_line(dev); | 512 | /* Fixup IRQ for PCIe host */ |
513 | if (u4_pcie != NULL && dev->bus->number == 0 && | ||
514 | pci_bus_to_host(dev->bus) == u4_pcie) { | ||
515 | printk(KERN_DEBUG "Fixup U4 PCIe IRQ\n"); | ||
516 | dev->irq = irq_create_mapping(NULL, 1); | ||
517 | if (dev->irq != NO_IRQ) | ||
518 | set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW); | ||
519 | } else | ||
520 | pci_read_irq_line(dev); | ||
521 | } | ||
381 | 522 | ||
382 | DBG(" <- maple_pcibios_fixup\n"); | 523 | DBG(" <- maple_pcibios_fixup\n"); |
383 | } | 524 | } |
@@ -388,8 +529,10 @@ static void __init maple_fixup_phb_resources(void) | |||
388 | 529 | ||
389 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { | 530 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { |
390 | unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; | 531 | unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; |
532 | |||
391 | hose->io_resource.start += offset; | 533 | hose->io_resource.start += offset; |
392 | hose->io_resource.end += offset; | 534 | hose->io_resource.end += offset; |
535 | |||
393 | printk(KERN_INFO "PCI Host %d, io start: %llx; io end: %llx\n", | 536 | printk(KERN_INFO "PCI Host %d, io start: %llx; io end: %llx\n", |
394 | hose->global_number, | 537 | hose->global_number, |
395 | (unsigned long long)hose->io_resource.start, | 538 | (unsigned long long)hose->io_resource.start, |
@@ -431,6 +574,19 @@ void __init maple_pci_init(void) | |||
431 | if (ht && add_bridge(ht) != 0) | 574 | if (ht && add_bridge(ht) != 0) |
432 | of_node_put(ht); | 575 | of_node_put(ht); |
433 | 576 | ||
577 | /* | ||
578 | * We need to call pci_setup_phb_io for the HT bridge first | ||
579 | * so it gets the I/O port numbers starting at 0, and we | ||
580 | * need to call it for the AGP bridge after that so it gets | ||
581 | * small positive I/O port numbers. | ||
582 | */ | ||
583 | if (u3_ht) | ||
584 | pci_setup_phb_io(u3_ht, 1); | ||
585 | if (u3_agp) | ||
586 | pci_setup_phb_io(u3_agp, 0); | ||
587 | if (u4_pcie) | ||
588 | pci_setup_phb_io(u4_pcie, 0); | ||
589 | |||
434 | /* Fixup the IO resources on our host bridges as the common code | 590 | /* Fixup the IO resources on our host bridges as the common code |
435 | * does it only for childs of the host bridges | 591 | * does it only for childs of the host bridges |
436 | */ | 592 | */ |
@@ -465,8 +621,11 @@ int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel) | |||
465 | return defirq; | 621 | return defirq; |
466 | 622 | ||
467 | np = pci_device_to_OF_node(pdev); | 623 | np = pci_device_to_OF_node(pdev); |
468 | if (np == NULL) | 624 | if (np == NULL) { |
625 | printk("Failed to locate OF node for IDE %s\n", | ||
626 | pci_name(pdev)); | ||
469 | return defirq; | 627 | return defirq; |
628 | } | ||
470 | irq = irq_of_parse_and_map(np, channel & 0x1); | 629 | irq = irq_of_parse_and_map(np, channel & 0x1); |
471 | if (irq == NO_IRQ) { | 630 | if (irq == NO_IRQ) { |
472 | printk("Failed to map onboard IDE interrupt for channel %d\n", | 631 | printk("Failed to map onboard IDE interrupt for channel %d\n", |
@@ -479,6 +638,9 @@ int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel) | |||
479 | /* XXX: To remove once all firmwares are ok */ | 638 | /* XXX: To remove once all firmwares are ok */ |
480 | static void fixup_maple_ide(struct pci_dev* dev) | 639 | static void fixup_maple_ide(struct pci_dev* dev) |
481 | { | 640 | { |
641 | if (!machine_is(maple)) | ||
642 | return; | ||
643 | |||
482 | #if 0 /* Enable this to enable IDE port 0 */ | 644 | #if 0 /* Enable this to enable IDE port 0 */ |
483 | { | 645 | { |
484 | u8 v; | 646 | u8 v; |
@@ -495,7 +657,7 @@ static void fixup_maple_ide(struct pci_dev* dev) | |||
495 | dev->resource[4].start = 0xcc00; | 657 | dev->resource[4].start = 0xcc00; |
496 | dev->resource[4].end = 0xcc10; | 658 | dev->resource[4].end = 0xcc10; |
497 | #endif | 659 | #endif |
498 | #if 1 /* Enable this to fixup IDE sense/polarity of irqs in IO-APICs */ | 660 | #if 0 /* Enable this to fixup IDE sense/polarity of irqs in IO-APICs */ |
499 | { | 661 | { |
500 | struct pci_dev *apicdev; | 662 | struct pci_dev *apicdev; |
501 | u32 v; | 663 | u32 v; |