diff options
-rw-r--r-- | arch/powerpc/Kconfig | 1 | ||||
-rw-r--r-- | arch/powerpc/sysdev/Kconfig | 8 | ||||
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_pci.c | 994 | ||||
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_pci.h | 242 |
4 files changed, 1227 insertions, 18 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index d40844f9b047..66a3d8cee5cf 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -166,6 +166,7 @@ config PPC_OF_PLATFORM_PCI | |||
166 | 166 | ||
167 | source "init/Kconfig" | 167 | source "init/Kconfig" |
168 | 168 | ||
169 | source "arch/powerpc/sysdev/Kconfig" | ||
169 | source "arch/powerpc/platforms/Kconfig" | 170 | source "arch/powerpc/platforms/Kconfig" |
170 | 171 | ||
171 | menu "Kernel options" | 172 | menu "Kernel options" |
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig new file mode 100644 index 000000000000..72fb35b9ebca --- /dev/null +++ b/arch/powerpc/sysdev/Kconfig | |||
@@ -0,0 +1,8 @@ | |||
1 | # For a description of the syntax of this configuration file, | ||
2 | # see Documentation/kbuild/kconfig-language.txt. | ||
3 | # | ||
4 | |||
5 | config PPC4xx_PCI_EXPRESS | ||
6 | bool | ||
7 | depends on PCI && 4xx | ||
8 | default n | ||
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index b7d79880c9b9..b986eff09f6b 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c | |||
@@ -3,16 +3,31 @@ | |||
3 | * | 3 | * |
4 | * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. | 4 | * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. |
5 | * | 5 | * |
6 | * Most PCI Express code is coming from Stefan Roese implementation for | ||
7 | * arch/ppc in the Denx tree, slightly reworked by me. | ||
8 | * | ||
9 | * Copyright 2007 DENX Software Engineering, Stefan Roese <sr@denx.de> | ||
10 | * | ||
11 | * Some of that comes itself from a previous implementation for 440SPE only | ||
12 | * by Roland Dreier: | ||
13 | * | ||
14 | * Copyright (c) 2005 Cisco Systems. All rights reserved. | ||
15 | * Roland Dreier <rolandd@cisco.com> | ||
16 | * | ||
6 | */ | 17 | */ |
7 | 18 | ||
8 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
9 | #include <linux/pci.h> | 20 | #include <linux/pci.h> |
10 | #include <linux/init.h> | 21 | #include <linux/init.h> |
11 | #include <linux/of.h> | 22 | #include <linux/of.h> |
23 | #include <linux/bootmem.h> | ||
24 | #include <linux/delay.h> | ||
12 | 25 | ||
13 | #include <asm/io.h> | 26 | #include <asm/io.h> |
14 | #include <asm/pci-bridge.h> | 27 | #include <asm/pci-bridge.h> |
15 | #include <asm/machdep.h> | 28 | #include <asm/machdep.h> |
29 | #include <asm/dcr.h> | ||
30 | #include <asm/dcr-regs.h> | ||
16 | 31 | ||
17 | #include "ppc4xx_pci.h" | 32 | #include "ppc4xx_pci.h" |
18 | 33 | ||
@@ -21,6 +36,17 @@ static int dma_offset_set; | |||
21 | /* Move that to a useable header */ | 36 | /* Move that to a useable header */ |
22 | extern unsigned long total_memory; | 37 | extern unsigned long total_memory; |
23 | 38 | ||
39 | #define U64_TO_U32_LOW(val) ((u32)((val) & 0x00000000ffffffffULL)) | ||
40 | #define U64_TO_U32_HIGH(val) ((u32)((val) >> 32)) | ||
41 | |||
42 | #ifdef CONFIG_RESOURCES_64BIT | ||
43 | #define RES_TO_U32_LOW(val) U64_TO_U32_LOW(val) | ||
44 | #define RES_TO_U32_HIGH(val) U64_TO_U32_HIGH(val) | ||
45 | #else | ||
46 | #define RES_TO_U32_LOW(val) (val) | ||
47 | #define RES_TO_U32_HIGH(val) (0) | ||
48 | #endif | ||
49 | |||
24 | static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev) | 50 | static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev) |
25 | { | 51 | { |
26 | struct pci_controller *hose; | 52 | struct pci_controller *hose; |
@@ -178,13 +204,8 @@ static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, | |||
178 | 204 | ||
179 | /* Calculate register values */ | 205 | /* Calculate register values */ |
180 | la = res->start; | 206 | la = res->start; |
181 | #ifdef CONFIG_RESOURCES_64BIT | 207 | pciha = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); |
182 | pciha = (res->start - hose->pci_mem_offset) >> 32; | 208 | pcila = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); |
183 | pcila = (res->start - hose->pci_mem_offset) & 0xffffffffu; | ||
184 | #else | ||
185 | pciha = 0; | ||
186 | pcila = res->start - hose->pci_mem_offset; | ||
187 | #endif | ||
188 | 209 | ||
189 | ma = res->end + 1 - res->start; | 210 | ma = res->end + 1 - res->start; |
190 | if (!is_power_of_2(ma) || ma < 0x1000 || ma > 0xffffffffu) { | 211 | if (!is_power_of_2(ma) || ma < 0x1000 || ma > 0xffffffffu) { |
@@ -333,16 +354,10 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, | |||
333 | } | 354 | } |
334 | 355 | ||
335 | /* Calculate register values */ | 356 | /* Calculate register values */ |
336 | #ifdef CONFIG_RESOURCES_64BIT | 357 | lah = RES_TO_U32_HIGH(res->start); |
337 | lah = res->start >> 32; | 358 | lal = RES_TO_U32_LOW(res->start); |
338 | lal = res->start & 0xffffffffu; | 359 | pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); |
339 | pciah = (res->start - hose->pci_mem_offset) >> 32; | 360 | pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); |
340 | pcial = (res->start - hose->pci_mem_offset) & 0xffffffffu; | ||
341 | #else | ||
342 | lah = pciah = 0; | ||
343 | lal = res->start; | ||
344 | pcial = res->start - hose->pci_mem_offset; | ||
345 | #endif | ||
346 | sa = res->end + 1 - res->start; | 361 | sa = res->end + 1 - res->start; |
347 | if (!is_power_of_2(sa) || sa < 0x100000 || | 362 | if (!is_power_of_2(sa) || sa < 0x100000 || |
348 | sa > 0xffffffffu) { | 363 | sa > 0xffffffffu) { |
@@ -492,20 +507,963 @@ static void __init ppc4xx_probe_pcix_bridge(struct device_node *np) | |||
492 | iounmap(reg); | 507 | iounmap(reg); |
493 | } | 508 | } |
494 | 509 | ||
510 | #ifdef CONFIG_PPC4xx_PCI_EXPRESS | ||
511 | |||
495 | /* | 512 | /* |
496 | * 4xx PCI-Express part | 513 | * 4xx PCI-Express part |
514 | * | ||
515 | * We support 3 parts currently based on the compatible property: | ||
516 | * | ||
517 | * ibm,plb-pciex-440speA | ||
518 | * ibm,plb-pciex-440speB | ||
519 | * ibm,plb-pciex-405ex | ||
520 | * | ||
521 | * Anything else will be rejected for now as they are all subtly | ||
522 | * different unfortunately. | ||
523 | * | ||
497 | */ | 524 | */ |
525 | |||
526 | #define MAX_PCIE_BUS_MAPPED 0x10 | ||
527 | |||
528 | struct ppc4xx_pciex_port | ||
529 | { | ||
530 | struct pci_controller *hose; | ||
531 | struct device_node *node; | ||
532 | unsigned int index; | ||
533 | int endpoint; | ||
534 | unsigned int sdr_base; | ||
535 | dcr_host_t dcrs; | ||
536 | struct resource cfg_space; | ||
537 | struct resource utl_regs; | ||
538 | }; | ||
539 | |||
540 | static struct ppc4xx_pciex_port *ppc4xx_pciex_ports; | ||
541 | static unsigned int ppc4xx_pciex_port_count; | ||
542 | |||
543 | struct ppc4xx_pciex_hwops | ||
544 | { | ||
545 | int (*core_init)(struct device_node *np); | ||
546 | int (*port_init_hw)(struct ppc4xx_pciex_port *port); | ||
547 | int (*setup_utl)(struct ppc4xx_pciex_port *port); | ||
548 | }; | ||
549 | |||
550 | static struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops; | ||
551 | |||
552 | #ifdef CONFIG_44x | ||
553 | |||
554 | /* Check various reset bits of the 440SPe PCIe core */ | ||
555 | static int __init ppc440spe_pciex_check_reset(struct device_node *np) | ||
556 | { | ||
557 | u32 valPE0, valPE1, valPE2; | ||
558 | int err = 0; | ||
559 | |||
560 | /* SDR0_PEGPLLLCT1 reset */ | ||
561 | if (!(mfdcri(SDR0, PESDR0_PLLLCT1) & 0x01000000)) { | ||
562 | /* | ||
563 | * the PCIe core was probably already initialised | ||
564 | * by firmware - let's re-reset RCSSET regs | ||
565 | * | ||
566 | * -- Shouldn't we also re-reset the whole thing ? -- BenH | ||
567 | */ | ||
568 | pr_debug("PCIE: SDR0_PLLLCT1 already reset.\n"); | ||
569 | mtdcri(SDR0, PESDR0_440SPE_RCSSET, 0x01010000); | ||
570 | mtdcri(SDR0, PESDR1_440SPE_RCSSET, 0x01010000); | ||
571 | mtdcri(SDR0, PESDR2_440SPE_RCSSET, 0x01010000); | ||
572 | } | ||
573 | |||
574 | valPE0 = mfdcri(SDR0, PESDR0_440SPE_RCSSET); | ||
575 | valPE1 = mfdcri(SDR0, PESDR1_440SPE_RCSSET); | ||
576 | valPE2 = mfdcri(SDR0, PESDR2_440SPE_RCSSET); | ||
577 | |||
578 | /* SDR0_PExRCSSET rstgu */ | ||
579 | if (!(valPE0 & 0x01000000) || | ||
580 | !(valPE1 & 0x01000000) || | ||
581 | !(valPE2 & 0x01000000)) { | ||
582 | printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstgu error\n"); | ||
583 | err = -1; | ||
584 | } | ||
585 | |||
586 | /* SDR0_PExRCSSET rstdl */ | ||
587 | if (!(valPE0 & 0x00010000) || | ||
588 | !(valPE1 & 0x00010000) || | ||
589 | !(valPE2 & 0x00010000)) { | ||
590 | printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstdl error\n"); | ||
591 | err = -1; | ||
592 | } | ||
593 | |||
594 | /* SDR0_PExRCSSET rstpyn */ | ||
595 | if ((valPE0 & 0x00001000) || | ||
596 | (valPE1 & 0x00001000) || | ||
597 | (valPE2 & 0x00001000)) { | ||
598 | printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstpyn error\n"); | ||
599 | err = -1; | ||
600 | } | ||
601 | |||
602 | /* SDR0_PExRCSSET hldplb */ | ||
603 | if ((valPE0 & 0x10000000) || | ||
604 | (valPE1 & 0x10000000) || | ||
605 | (valPE2 & 0x10000000)) { | ||
606 | printk(KERN_INFO "PCIE: SDR0_PExRCSSET hldplb error\n"); | ||
607 | err = -1; | ||
608 | } | ||
609 | |||
610 | /* SDR0_PExRCSSET rdy */ | ||
611 | if ((valPE0 & 0x00100000) || | ||
612 | (valPE1 & 0x00100000) || | ||
613 | (valPE2 & 0x00100000)) { | ||
614 | printk(KERN_INFO "PCIE: SDR0_PExRCSSET rdy error\n"); | ||
615 | err = -1; | ||
616 | } | ||
617 | |||
618 | /* SDR0_PExRCSSET shutdown */ | ||
619 | if ((valPE0 & 0x00000100) || | ||
620 | (valPE1 & 0x00000100) || | ||
621 | (valPE2 & 0x00000100)) { | ||
622 | printk(KERN_INFO "PCIE: SDR0_PExRCSSET shutdown error\n"); | ||
623 | err = -1; | ||
624 | } | ||
625 | |||
626 | return err; | ||
627 | } | ||
628 | |||
629 | /* Global PCIe core initializations for 440SPe core */ | ||
630 | static int __init ppc440spe_pciex_core_init(struct device_node *np) | ||
631 | { | ||
632 | int time_out = 20; | ||
633 | |||
634 | /* Set PLL clock receiver to LVPECL */ | ||
635 | mtdcri(SDR0, PESDR0_PLLLCT1, mfdcri(SDR0, PESDR0_PLLLCT1) | 1 << 28); | ||
636 | |||
637 | /* Shouldn't we do all the calibration stuff etc... here ? */ | ||
638 | if (ppc440spe_pciex_check_reset(np)) | ||
639 | return -ENXIO; | ||
640 | |||
641 | if (!(mfdcri(SDR0, PESDR0_PLLLCT2) & 0x10000)) { | ||
642 | printk(KERN_INFO "PCIE: PESDR_PLLCT2 resistance calibration " | ||
643 | "failed (0x%08x)\n", | ||
644 | mfdcri(SDR0, PESDR0_PLLLCT2)); | ||
645 | return -1; | ||
646 | } | ||
647 | |||
648 | /* De-assert reset of PCIe PLL, wait for lock */ | ||
649 | mtdcri(SDR0, PESDR0_PLLLCT1, | ||
650 | mfdcri(SDR0, PESDR0_PLLLCT1) & ~(1 << 24)); | ||
651 | udelay(3); | ||
652 | |||
653 | while (time_out) { | ||
654 | if (!(mfdcri(SDR0, PESDR0_PLLLCT3) & 0x10000000)) { | ||
655 | time_out--; | ||
656 | udelay(1); | ||
657 | } else | ||
658 | break; | ||
659 | } | ||
660 | if (!time_out) { | ||
661 | printk(KERN_INFO "PCIE: VCO output not locked\n"); | ||
662 | return -1; | ||
663 | } | ||
664 | |||
665 | pr_debug("PCIE initialization OK\n"); | ||
666 | |||
667 | return 3; | ||
668 | } | ||
669 | |||
670 | static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | ||
671 | { | ||
672 | u32 val = 1 << 24; | ||
673 | |||
674 | if (port->endpoint) | ||
675 | val = PTYPE_LEGACY_ENDPOINT << 20; | ||
676 | else | ||
677 | val = PTYPE_ROOT_PORT << 20; | ||
678 | |||
679 | if (port->index == 0) | ||
680 | val |= LNKW_X8 << 12; | ||
681 | else | ||
682 | val |= LNKW_X4 << 12; | ||
683 | |||
684 | mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val); | ||
685 | mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x20222222); | ||
686 | if (of_device_is_compatible(port->node, "ibm,plb-pciex-440speA")) | ||
687 | mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x11000000); | ||
688 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL0SET1, 0x35000000); | ||
689 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL1SET1, 0x35000000); | ||
690 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL2SET1, 0x35000000); | ||
691 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL3SET1, 0x35000000); | ||
692 | if (port->index == 0) { | ||
693 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL4SET1, | ||
694 | 0x35000000); | ||
695 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL5SET1, | ||
696 | 0x35000000); | ||
697 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL6SET1, | ||
698 | 0x35000000); | ||
699 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL7SET1, | ||
700 | 0x35000000); | ||
701 | } | ||
702 | val = mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET); | ||
703 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, | ||
704 | (val & ~(1 << 24 | 1 << 16)) | 1 << 12); | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static int ppc440speA_pciex_init_utl(struct ppc4xx_pciex_port *port) | ||
710 | { | ||
711 | void __iomem *utl_base; | ||
712 | |||
713 | /* XXX Check what that value means... I hate magic */ | ||
714 | dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x68782800); | ||
715 | |||
716 | utl_base = ioremap(port->utl_regs.start, 0x100); | ||
717 | BUG_ON(utl_base == NULL); | ||
718 | |||
719 | /* | ||
720 | * Set buffer allocations and then assert VRB and TXE. | ||
721 | */ | ||
722 | out_be32(utl_base + PEUTL_OUTTR, 0x08000000); | ||
723 | out_be32(utl_base + PEUTL_INTR, 0x02000000); | ||
724 | out_be32(utl_base + PEUTL_OPDBSZ, 0x10000000); | ||
725 | out_be32(utl_base + PEUTL_PBBSZ, 0x53000000); | ||
726 | out_be32(utl_base + PEUTL_IPHBSZ, 0x08000000); | ||
727 | out_be32(utl_base + PEUTL_IPDBSZ, 0x10000000); | ||
728 | out_be32(utl_base + PEUTL_RCIRQEN, 0x00f00000); | ||
729 | out_be32(utl_base + PEUTL_PCTL, 0x80800066); | ||
730 | |||
731 | iounmap(utl_base); | ||
732 | |||
733 | return 0; | ||
734 | } | ||
735 | |||
736 | static struct ppc4xx_pciex_hwops ppc440speA_pcie_hwops __initdata = | ||
737 | { | ||
738 | .core_init = ppc440spe_pciex_core_init, | ||
739 | .port_init_hw = ppc440spe_pciex_init_port_hw, | ||
740 | .setup_utl = ppc440speA_pciex_init_utl, | ||
741 | }; | ||
742 | |||
743 | static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = | ||
744 | { | ||
745 | .core_init = ppc440spe_pciex_core_init, | ||
746 | .port_init_hw = ppc440spe_pciex_init_port_hw, | ||
747 | }; | ||
748 | |||
749 | |||
750 | #endif /* CONFIG_44x */ | ||
751 | |||
752 | #ifdef CONFIG_40x | ||
753 | |||
754 | static int __init ppc405ex_pciex_core_init(struct device_node *np) | ||
755 | { | ||
756 | /* Nothing to do, return 2 ports */ | ||
757 | return 2; | ||
758 | } | ||
759 | |||
760 | static void ppc405ex_pcie_phy_reset(struct ppc4xx_pciex_port *port) | ||
761 | { | ||
762 | /* Assert the PE0_PHY reset */ | ||
763 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01010000); | ||
764 | msleep(1); | ||
765 | |||
766 | /* deassert the PE0_hotreset */ | ||
767 | if (port->endpoint) | ||
768 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01111000); | ||
769 | else | ||
770 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01101000); | ||
771 | |||
772 | /* poll for phy !reset */ | ||
773 | /* XXX FIXME add timeout */ | ||
774 | while (!(mfdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSTA) & 0x00001000)) | ||
775 | ; | ||
776 | |||
777 | /* deassert the PE0_gpl_utl_reset */ | ||
778 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x00101000); | ||
779 | } | ||
780 | |||
781 | static int ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | ||
782 | { | ||
783 | u32 val; | ||
784 | |||
785 | if (port->endpoint) | ||
786 | val = PTYPE_LEGACY_ENDPOINT; | ||
787 | else | ||
788 | val = PTYPE_ROOT_PORT; | ||
789 | |||
790 | mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, | ||
791 | 1 << 24 | val << 20 | LNKW_X1 << 12); | ||
792 | |||
793 | mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000); | ||
794 | mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000); | ||
795 | mtdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSET1, 0x720F0000); | ||
796 | mtdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSET2, 0x70600003); | ||
797 | |||
798 | /* | ||
799 | * Only reset the PHY when no link is currently established. | ||
800 | * This is for the Atheros PCIe board which has problems to establish | ||
801 | * the link (again) after this PHY reset. All other currently tested | ||
802 | * PCIe boards don't show this problem. | ||
803 | * This has to be re-tested and fixed in a later release! | ||
804 | */ | ||
805 | #if 0 /* XXX FIXME: Not resetting the PHY will leave all resources | ||
806 | * configured as done previously by U-Boot. Then Linux will currently | ||
807 | * not reassign them. So the PHY reset is now done always. This will | ||
808 | * lead to problems with the Atheros PCIe board again. | ||
809 | */ | ||
810 | val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP); | ||
811 | if (!(val & 0x00001000)) | ||
812 | ppc405ex_pcie_phy_reset(port); | ||
813 | #else | ||
814 | ppc405ex_pcie_phy_reset(port); | ||
815 | #endif | ||
816 | |||
817 | dcr_write(port->dcrs, DCRO_PEGPL_CFG, 0x10000000); /* guarded on */ | ||
818 | |||
819 | return 0; | ||
820 | } | ||
821 | |||
822 | static int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *port) | ||
823 | { | ||
824 | void __iomem *utl_base; | ||
825 | |||
826 | dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x0); | ||
827 | |||
828 | utl_base = ioremap(port->utl_regs.start, 0x100); | ||
829 | BUG_ON(utl_base == NULL); | ||
830 | |||
831 | /* | ||
832 | * Set buffer allocations and then assert VRB and TXE. | ||
833 | */ | ||
834 | out_be32(utl_base + PEUTL_OUTTR, 0x02000000); | ||
835 | out_be32(utl_base + PEUTL_INTR, 0x02000000); | ||
836 | out_be32(utl_base + PEUTL_OPDBSZ, 0x04000000); | ||
837 | out_be32(utl_base + PEUTL_PBBSZ, 0x21000000); | ||
838 | out_be32(utl_base + PEUTL_IPHBSZ, 0x02000000); | ||
839 | out_be32(utl_base + PEUTL_IPDBSZ, 0x04000000); | ||
840 | out_be32(utl_base + PEUTL_RCIRQEN, 0x00f00000); | ||
841 | out_be32(utl_base + PEUTL_PCTL, 0x80800066); | ||
842 | |||
843 | out_be32(utl_base + PEUTL_PBCTL, 0x0800000c); | ||
844 | out_be32(utl_base + PEUTL_RCSTA, | ||
845 | in_be32(utl_base + PEUTL_RCSTA) | 0x000040000); | ||
846 | |||
847 | iounmap(utl_base); | ||
848 | |||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | static struct ppc4xx_pciex_hwops ppc405ex_pcie_hwops __initdata = | ||
853 | { | ||
854 | .core_init = ppc405ex_pciex_core_init, | ||
855 | .port_init_hw = ppc405ex_pciex_init_port_hw, | ||
856 | .setup_utl = ppc405ex_pciex_init_utl, | ||
857 | }; | ||
858 | |||
859 | #endif /* CONFIG_40x */ | ||
860 | |||
861 | |||
862 | /* Check that the core has been initied and if not, do it */ | ||
863 | static int __init ppc4xx_pciex_check_core_init(struct device_node *np) | ||
864 | { | ||
865 | static int core_init; | ||
866 | int count = -ENODEV; | ||
867 | |||
868 | if (core_init++) | ||
869 | return 0; | ||
870 | |||
871 | #ifdef CONFIG_44x | ||
872 | if (of_device_is_compatible(np, "ibm,plb-pciex-440speA")) | ||
873 | ppc4xx_pciex_hwops = &ppc440speA_pcie_hwops; | ||
874 | else if (of_device_is_compatible(np, "ibm,plb-pciex-440speB")) | ||
875 | ppc4xx_pciex_hwops = &ppc440speB_pcie_hwops; | ||
876 | #endif /* CONFIG_44x */ | ||
877 | #ifdef CONFIG_40x | ||
878 | if (of_device_is_compatible(np, "ibm,plb-pciex-405ex")) | ||
879 | ppc4xx_pciex_hwops = &ppc405ex_pcie_hwops; | ||
880 | #endif | ||
881 | if (ppc4xx_pciex_hwops == NULL) { | ||
882 | printk(KERN_WARNING "PCIE: unknown host type %s\n", | ||
883 | np->full_name); | ||
884 | return -ENODEV; | ||
885 | } | ||
886 | |||
887 | count = ppc4xx_pciex_hwops->core_init(np); | ||
888 | if (count > 0) { | ||
889 | ppc4xx_pciex_ports = | ||
890 | kzalloc(count * sizeof(struct ppc4xx_pciex_port), | ||
891 | GFP_KERNEL); | ||
892 | if (ppc4xx_pciex_ports) { | ||
893 | ppc4xx_pciex_port_count = count; | ||
894 | return 0; | ||
895 | } | ||
896 | printk(KERN_WARNING "PCIE: failed to allocate ports array\n"); | ||
897 | return -ENOMEM; | ||
898 | } | ||
899 | return -ENODEV; | ||
900 | } | ||
901 | |||
902 | static void __init ppc4xx_pciex_port_init_mapping(struct ppc4xx_pciex_port *port) | ||
903 | { | ||
904 | /* We map PCI Express configuration based on the reg property */ | ||
905 | dcr_write(port->dcrs, DCRO_PEGPL_CFGBAH, | ||
906 | RES_TO_U32_HIGH(port->cfg_space.start)); | ||
907 | dcr_write(port->dcrs, DCRO_PEGPL_CFGBAL, | ||
908 | RES_TO_U32_LOW(port->cfg_space.start)); | ||
909 | |||
910 | /* XXX FIXME: Use size from reg property. For now, map 512M */ | ||
911 | dcr_write(port->dcrs, DCRO_PEGPL_CFGMSK, 0xe0000001); | ||
912 | |||
913 | /* We map UTL registers based on the reg property */ | ||
914 | dcr_write(port->dcrs, DCRO_PEGPL_REGBAH, | ||
915 | RES_TO_U32_HIGH(port->utl_regs.start)); | ||
916 | dcr_write(port->dcrs, DCRO_PEGPL_REGBAL, | ||
917 | RES_TO_U32_LOW(port->utl_regs.start)); | ||
918 | |||
919 | /* XXX FIXME: Use size from reg property */ | ||
920 | dcr_write(port->dcrs, DCRO_PEGPL_REGMSK, 0x00007001); | ||
921 | |||
922 | /* Disable all other outbound windows */ | ||
923 | dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, 0); | ||
924 | dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, 0); | ||
925 | dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0); | ||
926 | dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0); | ||
927 | } | ||
928 | |||
929 | static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) | ||
930 | { | ||
931 | int attempts, rc = 0; | ||
932 | u32 val; | ||
933 | |||
934 | /* Check if it's endpoint or root complex | ||
935 | * | ||
936 | * XXX Do we want to use the device-tree instead ? --BenH. | ||
937 | */ | ||
938 | val = mfdcri(SDR0, port->sdr_base + PESDRn_DLPSET); | ||
939 | port->endpoint = (((val >> 20) & 0xf) != PTYPE_ROOT_PORT); | ||
940 | |||
941 | /* Init HW */ | ||
942 | if (ppc4xx_pciex_hwops->port_init_hw) | ||
943 | rc = ppc4xx_pciex_hwops->port_init_hw(port); | ||
944 | if (rc != 0) | ||
945 | return rc; | ||
946 | |||
947 | /* | ||
948 | * Notice: the following delay has critical impact on device | ||
949 | * initialization - if too short (<50ms) the link doesn't get up. | ||
950 | * | ||
951 | * XXX FIXME: There are various issues with that link up thingy, | ||
952 | * we could just wait for the link with a timeout but Stefan says | ||
953 | * some cards need more time even after the link is up. I'll | ||
954 | * investigate. For now, we keep a fixed 1s delay. | ||
955 | * | ||
956 | * Ultimately, it should be made asynchronous so all ports are | ||
957 | * brought up simultaneously though. | ||
958 | */ | ||
959 | printk(KERN_INFO "PCIE%d: Waiting for link to go up...\n", | ||
960 | port->index); | ||
961 | msleep(1000); | ||
962 | |||
963 | /* | ||
964 | * Check that we exited the reset state properly | ||
965 | */ | ||
966 | val = mfdcri(SDR0, port->sdr_base + PESDRn_RCSSTS); | ||
967 | if (val & (1 << 20)) { | ||
968 | printk(KERN_WARNING "PCIE%d: PGRST failed %08x\n", | ||
969 | port->index, val); | ||
970 | return -1; | ||
971 | } | ||
972 | |||
973 | /* | ||
974 | * Verify link is up | ||
975 | */ | ||
976 | val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP); | ||
977 | if (!(val & 0x00001000)) { | ||
978 | printk(KERN_INFO "PCIE%d: link is not up !\n", | ||
979 | port->index); | ||
980 | return -1; | ||
981 | } | ||
982 | |||
983 | printk(KERN_INFO "PCIE%d: link is up !\n", | ||
984 | port->index); | ||
985 | |||
986 | /* | ||
987 | * Initialize mapping: disable all regions and configure | ||
988 | * CFG and REG regions based on resources in the device tree | ||
989 | */ | ||
990 | ppc4xx_pciex_port_init_mapping(port); | ||
991 | |||
992 | /* | ||
993 | * Setup UTL registers - but only on revA! | ||
994 | * We use default settings for revB chip. | ||
995 | * | ||
996 | * To be reworked. We may also be able to move that to | ||
997 | * before the link wait | ||
998 | * --BenH. | ||
999 | */ | ||
1000 | if (ppc4xx_pciex_hwops->setup_utl) | ||
1001 | ppc4xx_pciex_hwops->setup_utl(port); | ||
1002 | |||
1003 | /* | ||
1004 | * Check for VC0 active and assert RDY. | ||
1005 | */ | ||
1006 | attempts = 10; | ||
1007 | while (!(mfdcri(SDR0, port->sdr_base + PESDRn_RCSSTS) & (1 << 16))) { | ||
1008 | if (!(attempts--)) { | ||
1009 | printk(KERN_INFO "PCIE%d: VC0 not active\n", | ||
1010 | port->index); | ||
1011 | return -1; | ||
1012 | } | ||
1013 | msleep(1000); | ||
1014 | } | ||
1015 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, | ||
1016 | mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) | 1 << 20); | ||
1017 | msleep(100); | ||
1018 | |||
1019 | return 0; | ||
1020 | } | ||
1021 | |||
1022 | static int ppc4xx_pciex_validate_bdf(struct ppc4xx_pciex_port *port, | ||
1023 | struct pci_bus *bus, | ||
1024 | unsigned int devfn) | ||
1025 | { | ||
1026 | static int message; | ||
1027 | |||
1028 | /* Endpoint can not generate upstream(remote) config cycles */ | ||
1029 | if (port->endpoint && bus->number != port->hose->first_busno) | ||
1030 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1031 | |||
1032 | /* Check we are within the mapped range */ | ||
1033 | if (bus->number > port->hose->last_busno) { | ||
1034 | if (!message) { | ||
1035 | printk(KERN_WARNING "Warning! Probing bus %u" | ||
1036 | " out of range !\n", bus->number); | ||
1037 | message++; | ||
1038 | } | ||
1039 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1040 | } | ||
1041 | |||
1042 | /* The root complex has only one device / function */ | ||
1043 | if (bus->number == port->hose->first_busno && devfn != 0) | ||
1044 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1045 | |||
1046 | /* The other side of the RC has only one device as well */ | ||
1047 | if (bus->number == (port->hose->first_busno + 1) && | ||
1048 | PCI_SLOT(devfn) != 0) | ||
1049 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1050 | |||
1051 | return 0; | ||
1052 | } | ||
1053 | |||
1054 | static void __iomem *ppc4xx_pciex_get_config_base(struct ppc4xx_pciex_port *port, | ||
1055 | struct pci_bus *bus, | ||
1056 | unsigned int devfn) | ||
1057 | { | ||
1058 | int relbus; | ||
1059 | |||
1060 | /* Remove the casts when we finally remove the stupid volatile | ||
1061 | * in struct pci_controller | ||
1062 | */ | ||
1063 | if (bus->number == port->hose->first_busno) | ||
1064 | return (void __iomem *)port->hose->cfg_addr; | ||
1065 | |||
1066 | relbus = bus->number - (port->hose->first_busno + 1); | ||
1067 | return (void __iomem *)port->hose->cfg_data + | ||
1068 | ((relbus << 20) | (devfn << 12)); | ||
1069 | } | ||
1070 | |||
1071 | static int ppc4xx_pciex_read_config(struct pci_bus *bus, unsigned int devfn, | ||
1072 | int offset, int len, u32 *val) | ||
1073 | { | ||
1074 | struct pci_controller *hose = (struct pci_controller *) bus->sysdata; | ||
1075 | struct ppc4xx_pciex_port *port = | ||
1076 | &ppc4xx_pciex_ports[hose->indirect_type]; | ||
1077 | void __iomem *addr; | ||
1078 | u32 gpl_cfg; | ||
1079 | |||
1080 | BUG_ON(hose != port->hose); | ||
1081 | |||
1082 | if (ppc4xx_pciex_validate_bdf(port, bus, devfn) != 0) | ||
1083 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1084 | |||
1085 | addr = ppc4xx_pciex_get_config_base(port, bus, devfn); | ||
1086 | |||
1087 | /* | ||
1088 | * Reading from configuration space of non-existing device can | ||
1089 | * generate transaction errors. For the read duration we suppress | ||
1090 | * assertion of machine check exceptions to avoid those. | ||
1091 | */ | ||
1092 | gpl_cfg = dcr_read(port->dcrs, DCRO_PEGPL_CFG); | ||
1093 | dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg | GPL_DMER_MASK_DISA); | ||
1094 | |||
1095 | switch (len) { | ||
1096 | case 1: | ||
1097 | *val = in_8((u8 *)(addr + offset)); | ||
1098 | break; | ||
1099 | case 2: | ||
1100 | *val = in_le16((u16 *)(addr + offset)); | ||
1101 | break; | ||
1102 | default: | ||
1103 | *val = in_le32((u32 *)(addr + offset)); | ||
1104 | break; | ||
1105 | } | ||
1106 | |||
1107 | pr_debug("pcie-config-read: bus=%3d [%3d..%3d] devfn=0x%04x" | ||
1108 | " offset=0x%04x len=%d, addr=0x%p val=0x%08x\n", | ||
1109 | bus->number, hose->first_busno, hose->last_busno, | ||
1110 | devfn, offset, len, addr + offset, *val); | ||
1111 | |||
1112 | dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg); | ||
1113 | |||
1114 | return PCIBIOS_SUCCESSFUL; | ||
1115 | } | ||
1116 | |||
1117 | static int ppc4xx_pciex_write_config(struct pci_bus *bus, unsigned int devfn, | ||
1118 | int offset, int len, u32 val) | ||
1119 | { | ||
1120 | struct pci_controller *hose = (struct pci_controller *) bus->sysdata; | ||
1121 | struct ppc4xx_pciex_port *port = | ||
1122 | &ppc4xx_pciex_ports[hose->indirect_type]; | ||
1123 | void __iomem *addr; | ||
1124 | u32 gpl_cfg; | ||
1125 | |||
1126 | if (ppc4xx_pciex_validate_bdf(port, bus, devfn) != 0) | ||
1127 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1128 | |||
1129 | addr = ppc4xx_pciex_get_config_base(port, bus, devfn); | ||
1130 | |||
1131 | /* | ||
1132 | * Reading from configuration space of non-existing device can | ||
1133 | * generate transaction errors. For the read duration we suppress | ||
1134 | * assertion of machine check exceptions to avoid those. | ||
1135 | */ | ||
1136 | gpl_cfg = dcr_read(port->dcrs, DCRO_PEGPL_CFG); | ||
1137 | dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg | GPL_DMER_MASK_DISA); | ||
1138 | |||
1139 | pr_debug("pcie-config-write: bus=%3d [%3d..%3d] devfn=0x%04x" | ||
1140 | " offset=0x%04x len=%d, addr=0x%p val=0x%08x\n", | ||
1141 | bus->number, hose->first_busno, hose->last_busno, | ||
1142 | devfn, offset, len, addr + offset, val); | ||
1143 | |||
1144 | switch (len) { | ||
1145 | case 1: | ||
1146 | out_8((u8 *)(addr + offset), val); | ||
1147 | break; | ||
1148 | case 2: | ||
1149 | out_le16((u16 *)(addr + offset), val); | ||
1150 | break; | ||
1151 | default: | ||
1152 | out_le32((u32 *)(addr + offset), val); | ||
1153 | break; | ||
1154 | } | ||
1155 | |||
1156 | dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg); | ||
1157 | |||
1158 | return PCIBIOS_SUCCESSFUL; | ||
1159 | } | ||
1160 | |||
1161 | static struct pci_ops ppc4xx_pciex_pci_ops = | ||
1162 | { | ||
1163 | .read = ppc4xx_pciex_read_config, | ||
1164 | .write = ppc4xx_pciex_write_config, | ||
1165 | }; | ||
1166 | |||
1167 | static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, | ||
1168 | struct pci_controller *hose, | ||
1169 | void __iomem *mbase) | ||
1170 | { | ||
1171 | u32 lah, lal, pciah, pcial, sa; | ||
1172 | int i, j; | ||
1173 | |||
1174 | /* Setup outbound memory windows */ | ||
1175 | for (i = j = 0; i < 3; i++) { | ||
1176 | struct resource *res = &hose->mem_resources[i]; | ||
1177 | |||
1178 | /* we only care about memory windows */ | ||
1179 | if (!(res->flags & IORESOURCE_MEM)) | ||
1180 | continue; | ||
1181 | if (j > 1) { | ||
1182 | printk(KERN_WARNING "%s: Too many ranges\n", | ||
1183 | port->node->full_name); | ||
1184 | break; | ||
1185 | } | ||
1186 | |||
1187 | /* Calculate register values */ | ||
1188 | lah = RES_TO_U32_HIGH(res->start); | ||
1189 | lal = RES_TO_U32_LOW(res->start); | ||
1190 | pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); | ||
1191 | pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); | ||
1192 | sa = res->end + 1 - res->start; | ||
1193 | if (!is_power_of_2(sa) || sa < 0x100000 || | ||
1194 | sa > 0xffffffffu) { | ||
1195 | printk(KERN_WARNING "%s: Resource out of range\n", | ||
1196 | port->node->full_name); | ||
1197 | continue; | ||
1198 | } | ||
1199 | sa = (0xffffffffu << ilog2(sa)) | 0x1; | ||
1200 | |||
1201 | /* Program register values */ | ||
1202 | switch (j) { | ||
1203 | case 0: | ||
1204 | out_le32(mbase + PECFG_POM0LAH, pciah); | ||
1205 | out_le32(mbase + PECFG_POM0LAL, pcial); | ||
1206 | dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); | ||
1207 | dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); | ||
1208 | dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); | ||
1209 | dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); | ||
1210 | break; | ||
1211 | case 1: | ||
1212 | out_le32(mbase + PECFG_POM1LAH, pciah); | ||
1213 | out_le32(mbase + PECFG_POM1LAL, pcial); | ||
1214 | dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); | ||
1215 | dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); | ||
1216 | dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); | ||
1217 | dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); | ||
1218 | break; | ||
1219 | } | ||
1220 | j++; | ||
1221 | } | ||
1222 | |||
1223 | /* Configure IO, always 64K starting at 0 */ | ||
1224 | if (hose->io_resource.flags & IORESOURCE_IO) { | ||
1225 | lah = RES_TO_U32_HIGH(hose->io_base_phys); | ||
1226 | lal = RES_TO_U32_LOW(hose->io_base_phys); | ||
1227 | out_le32(mbase + PECFG_POM2LAH, 0); | ||
1228 | out_le32(mbase + PECFG_POM2LAL, 0); | ||
1229 | dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); | ||
1230 | dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); | ||
1231 | dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); | ||
1232 | dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0xffff0000 | 3); | ||
1233 | } | ||
1234 | } | ||
1235 | |||
1236 | static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, | ||
1237 | struct pci_controller *hose, | ||
1238 | void __iomem *mbase, | ||
1239 | struct resource *res) | ||
1240 | { | ||
1241 | resource_size_t size = res->end - res->start + 1; | ||
1242 | u64 sa; | ||
1243 | |||
1244 | /* Calculate window size */ | ||
1245 | sa = (0xffffffffffffffffull << ilog2(size));; | ||
1246 | if (res->flags & IORESOURCE_PREFETCH) | ||
1247 | sa |= 0x8; | ||
1248 | |||
1249 | out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); | ||
1250 | out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa)); | ||
1251 | |||
1252 | /* The setup of the split looks weird to me ... let's see if it works */ | ||
1253 | out_le32(mbase + PECFG_PIM0LAL, 0x00000000); | ||
1254 | out_le32(mbase + PECFG_PIM0LAH, 0x00000000); | ||
1255 | out_le32(mbase + PECFG_PIM1LAL, 0x00000000); | ||
1256 | out_le32(mbase + PECFG_PIM1LAH, 0x00000000); | ||
1257 | out_le32(mbase + PECFG_PIM01SAH, 0xffff0000); | ||
1258 | out_le32(mbase + PECFG_PIM01SAL, 0x00000000); | ||
1259 | |||
1260 | /* Enable inbound mapping */ | ||
1261 | out_le32(mbase + PECFG_PIMEN, 0x1); | ||
1262 | |||
1263 | out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(res->start)); | ||
1264 | out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(res->start)); | ||
1265 | |||
1266 | /* Enable I/O, Mem, and Busmaster cycles */ | ||
1267 | out_le16(mbase + PCI_COMMAND, | ||
1268 | in_le16(mbase + PCI_COMMAND) | | ||
1269 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); | ||
1270 | } | ||
1271 | |||
1272 | static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) | ||
1273 | { | ||
1274 | struct resource dma_window; | ||
1275 | struct pci_controller *hose = NULL; | ||
1276 | const int *bus_range; | ||
1277 | int primary = 0, busses; | ||
1278 | void __iomem *mbase = NULL, *cfg_data = NULL; | ||
1279 | |||
1280 | /* XXX FIXME: Handle endpoint mode properly */ | ||
1281 | if (port->endpoint) | ||
1282 | return; | ||
1283 | |||
1284 | /* Check if primary bridge */ | ||
1285 | if (of_get_property(port->node, "primary", NULL)) | ||
1286 | primary = 1; | ||
1287 | |||
1288 | /* Get bus range if any */ | ||
1289 | bus_range = of_get_property(port->node, "bus-range", NULL); | ||
1290 | |||
1291 | /* Allocate the host controller data structure */ | ||
1292 | hose = pcibios_alloc_controller(port->node); | ||
1293 | if (!hose) | ||
1294 | goto fail; | ||
1295 | |||
1296 | /* We stick the port number in "indirect_type" so the config space | ||
1297 | * ops can retrieve the port data structure easily | ||
1298 | */ | ||
1299 | hose->indirect_type = port->index; | ||
1300 | |||
1301 | /* Get bus range */ | ||
1302 | hose->first_busno = bus_range ? bus_range[0] : 0x0; | ||
1303 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | ||
1304 | |||
1305 | /* Because of how big mapping the config space is (1M per bus), we | ||
1306 | * limit how many busses we support. In the long run, we could replace | ||
1307 | * that with something akin to kmap_atomic instead. We set aside 1 bus | ||
1308 | * for the host itself too. | ||
1309 | */ | ||
1310 | busses = hose->last_busno - hose->first_busno; /* This is off by 1 */ | ||
1311 | if (busses > MAX_PCIE_BUS_MAPPED) { | ||
1312 | busses = MAX_PCIE_BUS_MAPPED; | ||
1313 | hose->last_busno = hose->first_busno + busses; | ||
1314 | } | ||
1315 | |||
1316 | /* We map the external config space in cfg_data and the host config | ||
1317 | * space in cfg_addr. External space is 1M per bus, internal space | ||
1318 | * is 4K | ||
1319 | */ | ||
1320 | cfg_data = ioremap(port->cfg_space.start + | ||
1321 | (hose->first_busno + 1) * 0x100000, | ||
1322 | busses * 0x100000); | ||
1323 | mbase = ioremap(port->cfg_space.start + 0x10000000, 0x1000); | ||
1324 | if (cfg_data == NULL || mbase == NULL) { | ||
1325 | printk(KERN_ERR "%s: Can't map config space !", | ||
1326 | port->node->full_name); | ||
1327 | goto fail; | ||
1328 | } | ||
1329 | |||
1330 | hose->cfg_data = cfg_data; | ||
1331 | hose->cfg_addr = mbase; | ||
1332 | |||
1333 | pr_debug("PCIE %s, bus %d..%d\n", port->node->full_name, | ||
1334 | hose->first_busno, hose->last_busno); | ||
1335 | pr_debug(" config space mapped at: root @0x%p, other @0x%p\n", | ||
1336 | hose->cfg_addr, hose->cfg_data); | ||
1337 | |||
1338 | /* Setup config space */ | ||
1339 | hose->ops = &ppc4xx_pciex_pci_ops; | ||
1340 | port->hose = hose; | ||
1341 | mbase = (void __iomem *)hose->cfg_addr; | ||
1342 | |||
1343 | /* | ||
1344 | * Set bus numbers on our root port | ||
1345 | */ | ||
1346 | out_8(mbase + PCI_PRIMARY_BUS, hose->first_busno); | ||
1347 | out_8(mbase + PCI_SECONDARY_BUS, hose->first_busno + 1); | ||
1348 | out_8(mbase + PCI_SUBORDINATE_BUS, hose->last_busno); | ||
1349 | |||
1350 | /* | ||
1351 | * OMRs are already reset, also disable PIMs | ||
1352 | */ | ||
1353 | out_le32(mbase + PECFG_PIMEN, 0); | ||
1354 | |||
1355 | /* Parse outbound mapping resources */ | ||
1356 | pci_process_bridge_OF_ranges(hose, port->node, primary); | ||
1357 | |||
1358 | /* Parse inbound mapping resources */ | ||
1359 | if (ppc4xx_parse_dma_ranges(hose, mbase, &dma_window) != 0) | ||
1360 | goto fail; | ||
1361 | |||
1362 | /* Configure outbound ranges POMs */ | ||
1363 | ppc4xx_configure_pciex_POMs(port, hose, mbase); | ||
1364 | |||
1365 | /* Configure inbound ranges PIMs */ | ||
1366 | ppc4xx_configure_pciex_PIMs(port, hose, mbase, &dma_window); | ||
1367 | |||
1368 | /* The root complex doesn't show up if we don't set some vendor | ||
1369 | * and device IDs into it. Those are the same bogus one that the | ||
1370 | * initial code in arch/ppc add. We might want to change that. | ||
1371 | */ | ||
1372 | out_le16(mbase + 0x200, 0xaaa0 + port->index); | ||
1373 | out_le16(mbase + 0x202, 0xbed0 + port->index); | ||
1374 | |||
1375 | /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ | ||
1376 | out_le32(mbase + 0x208, 0x06040001); | ||
1377 | |||
1378 | printk(KERN_INFO "PCIE%d: successfully set as root-complex\n", | ||
1379 | port->index); | ||
1380 | return; | ||
1381 | fail: | ||
1382 | if (hose) | ||
1383 | pcibios_free_controller(hose); | ||
1384 | if (cfg_data) | ||
1385 | iounmap(cfg_data); | ||
1386 | if (mbase) | ||
1387 | iounmap(mbase); | ||
1388 | } | ||
1389 | |||
498 | static void __init ppc4xx_probe_pciex_bridge(struct device_node *np) | 1390 | static void __init ppc4xx_probe_pciex_bridge(struct device_node *np) |
499 | { | 1391 | { |
500 | /* NYI */ | 1392 | struct ppc4xx_pciex_port *port; |
1393 | const u32 *pval; | ||
1394 | int portno; | ||
1395 | unsigned int dcrs; | ||
1396 | |||
1397 | /* First, proceed to core initialization as we assume there's | ||
1398 | * only one PCIe core in the system | ||
1399 | */ | ||
1400 | if (ppc4xx_pciex_check_core_init(np)) | ||
1401 | return; | ||
1402 | |||
1403 | /* Get the port number from the device-tree */ | ||
1404 | pval = of_get_property(np, "port", NULL); | ||
1405 | if (pval == NULL) { | ||
1406 | printk(KERN_ERR "PCIE: Can't find port number for %s\n", | ||
1407 | np->full_name); | ||
1408 | return; | ||
1409 | } | ||
1410 | portno = *pval; | ||
1411 | if (portno >= ppc4xx_pciex_port_count) { | ||
1412 | printk(KERN_ERR "PCIE: port number out of range for %s\n", | ||
1413 | np->full_name); | ||
1414 | return; | ||
1415 | } | ||
1416 | port = &ppc4xx_pciex_ports[portno]; | ||
1417 | port->index = portno; | ||
1418 | port->node = of_node_get(np); | ||
1419 | pval = of_get_property(np, "sdr-base", NULL); | ||
1420 | if (pval == NULL) { | ||
1421 | printk(KERN_ERR "PCIE: missing sdr-base for %s\n", | ||
1422 | np->full_name); | ||
1423 | return; | ||
1424 | } | ||
1425 | port->sdr_base = *pval; | ||
1426 | |||
1427 | /* Fetch config space registers address */ | ||
1428 | if (of_address_to_resource(np, 0, &port->cfg_space)) { | ||
1429 | printk(KERN_ERR "%s: Can't get PCI-E config space !", | ||
1430 | np->full_name); | ||
1431 | return; | ||
1432 | } | ||
1433 | /* Fetch host bridge internal registers address */ | ||
1434 | if (of_address_to_resource(np, 1, &port->utl_regs)) { | ||
1435 | printk(KERN_ERR "%s: Can't get UTL register base !", | ||
1436 | np->full_name); | ||
1437 | return; | ||
1438 | } | ||
1439 | |||
1440 | /* Map DCRs */ | ||
1441 | dcrs = dcr_resource_start(np, 0); | ||
1442 | if (dcrs == 0) { | ||
1443 | printk(KERN_ERR "%s: Can't get DCR register base !", | ||
1444 | np->full_name); | ||
1445 | return; | ||
1446 | } | ||
1447 | port->dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0)); | ||
1448 | |||
1449 | /* Initialize the port specific registers */ | ||
1450 | if (ppc4xx_pciex_port_init(port)) | ||
1451 | return; | ||
1452 | |||
1453 | /* Setup the linux hose data structure */ | ||
1454 | ppc4xx_pciex_port_setup_hose(port); | ||
501 | } | 1455 | } |
502 | 1456 | ||
1457 | #endif /* CONFIG_PPC4xx_PCI_EXPRESS */ | ||
1458 | |||
503 | static int __init ppc4xx_pci_find_bridges(void) | 1459 | static int __init ppc4xx_pci_find_bridges(void) |
504 | { | 1460 | { |
505 | struct device_node *np; | 1461 | struct device_node *np; |
506 | 1462 | ||
1463 | #ifdef CONFIG_PPC4xx_PCI_EXPRESS | ||
507 | for_each_compatible_node(np, NULL, "ibm,plb-pciex") | 1464 | for_each_compatible_node(np, NULL, "ibm,plb-pciex") |
508 | ppc4xx_probe_pciex_bridge(np); | 1465 | ppc4xx_probe_pciex_bridge(np); |
1466 | #endif | ||
509 | for_each_compatible_node(np, NULL, "ibm,plb-pcix") | 1467 | for_each_compatible_node(np, NULL, "ibm,plb-pcix") |
510 | ppc4xx_probe_pcix_bridge(np); | 1468 | ppc4xx_probe_pcix_bridge(np); |
511 | for_each_compatible_node(np, NULL, "ibm,plb-pci") | 1469 | for_each_compatible_node(np, NULL, "ibm,plb-pci") |
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.h b/arch/powerpc/sysdev/ppc4xx_pci.h index 8b787bfdc8a5..43e51ce5c477 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.h +++ b/arch/powerpc/sysdev/ppc4xx_pci.h | |||
@@ -121,5 +121,247 @@ | |||
121 | #define PCIL0_PTM2MS 0x38 | 121 | #define PCIL0_PTM2MS 0x38 |
122 | #define PCIL0_PTM2LA 0x3c | 122 | #define PCIL0_PTM2LA 0x3c |
123 | 123 | ||
124 | /* | ||
125 | * 4xx PCIe bridge register definitions | ||
126 | */ | ||
127 | |||
128 | /* DCR offsets */ | ||
129 | #define DCRO_PEGPL_CFGBAH 0x00 | ||
130 | #define DCRO_PEGPL_CFGBAL 0x01 | ||
131 | #define DCRO_PEGPL_CFGMSK 0x02 | ||
132 | #define DCRO_PEGPL_MSGBAH 0x03 | ||
133 | #define DCRO_PEGPL_MSGBAL 0x04 | ||
134 | #define DCRO_PEGPL_MSGMSK 0x05 | ||
135 | #define DCRO_PEGPL_OMR1BAH 0x06 | ||
136 | #define DCRO_PEGPL_OMR1BAL 0x07 | ||
137 | #define DCRO_PEGPL_OMR1MSKH 0x08 | ||
138 | #define DCRO_PEGPL_OMR1MSKL 0x09 | ||
139 | #define DCRO_PEGPL_OMR2BAH 0x0a | ||
140 | #define DCRO_PEGPL_OMR2BAL 0x0b | ||
141 | #define DCRO_PEGPL_OMR2MSKH 0x0c | ||
142 | #define DCRO_PEGPL_OMR2MSKL 0x0d | ||
143 | #define DCRO_PEGPL_OMR3BAH 0x0e | ||
144 | #define DCRO_PEGPL_OMR3BAL 0x0f | ||
145 | #define DCRO_PEGPL_OMR3MSKH 0x10 | ||
146 | #define DCRO_PEGPL_OMR3MSKL 0x11 | ||
147 | #define DCRO_PEGPL_REGBAH 0x12 | ||
148 | #define DCRO_PEGPL_REGBAL 0x13 | ||
149 | #define DCRO_PEGPL_REGMSK 0x14 | ||
150 | #define DCRO_PEGPL_SPECIAL 0x15 | ||
151 | #define DCRO_PEGPL_CFG 0x16 | ||
152 | #define DCRO_PEGPL_ESR 0x17 | ||
153 | #define DCRO_PEGPL_EARH 0x18 | ||
154 | #define DCRO_PEGPL_EARL 0x19 | ||
155 | #define DCRO_PEGPL_EATR 0x1a | ||
156 | |||
157 | /* DMER mask */ | ||
158 | #define GPL_DMER_MASK_DISA 0x02000000 | ||
159 | |||
160 | /* | ||
161 | * System DCRs (SDRs) | ||
162 | */ | ||
163 | #define PESDR0_PLLLCT1 0x03a0 | ||
164 | #define PESDR0_PLLLCT2 0x03a1 | ||
165 | #define PESDR0_PLLLCT3 0x03a2 | ||
166 | |||
167 | /* | ||
168 | * 440SPe additional DCRs | ||
169 | */ | ||
170 | #define PESDR0_440SPE_UTLSET1 0x0300 | ||
171 | #define PESDR0_440SPE_UTLSET2 0x0301 | ||
172 | #define PESDR0_440SPE_DLPSET 0x0302 | ||
173 | #define PESDR0_440SPE_LOOP 0x0303 | ||
174 | #define PESDR0_440SPE_RCSSET 0x0304 | ||
175 | #define PESDR0_440SPE_RCSSTS 0x0305 | ||
176 | #define PESDR0_440SPE_HSSL0SET1 0x0306 | ||
177 | #define PESDR0_440SPE_HSSL0SET2 0x0307 | ||
178 | #define PESDR0_440SPE_HSSL0STS 0x0308 | ||
179 | #define PESDR0_440SPE_HSSL1SET1 0x0309 | ||
180 | #define PESDR0_440SPE_HSSL1SET2 0x030a | ||
181 | #define PESDR0_440SPE_HSSL1STS 0x030b | ||
182 | #define PESDR0_440SPE_HSSL2SET1 0x030c | ||
183 | #define PESDR0_440SPE_HSSL2SET2 0x030d | ||
184 | #define PESDR0_440SPE_HSSL2STS 0x030e | ||
185 | #define PESDR0_440SPE_HSSL3SET1 0x030f | ||
186 | #define PESDR0_440SPE_HSSL3SET2 0x0310 | ||
187 | #define PESDR0_440SPE_HSSL3STS 0x0311 | ||
188 | #define PESDR0_440SPE_HSSL4SET1 0x0312 | ||
189 | #define PESDR0_440SPE_HSSL4SET2 0x0313 | ||
190 | #define PESDR0_440SPE_HSSL4STS 0x0314 | ||
191 | #define PESDR0_440SPE_HSSL5SET1 0x0315 | ||
192 | #define PESDR0_440SPE_HSSL5SET2 0x0316 | ||
193 | #define PESDR0_440SPE_HSSL5STS 0x0317 | ||
194 | #define PESDR0_440SPE_HSSL6SET1 0x0318 | ||
195 | #define PESDR0_440SPE_HSSL6SET2 0x0319 | ||
196 | #define PESDR0_440SPE_HSSL6STS 0x031a | ||
197 | #define PESDR0_440SPE_HSSL7SET1 0x031b | ||
198 | #define PESDR0_440SPE_HSSL7SET2 0x031c | ||
199 | #define PESDR0_440SPE_HSSL7STS 0x031d | ||
200 | #define PESDR0_440SPE_HSSCTLSET 0x031e | ||
201 | #define PESDR0_440SPE_LANE_ABCD 0x031f | ||
202 | #define PESDR0_440SPE_LANE_EFGH 0x0320 | ||
203 | |||
204 | #define PESDR1_440SPE_UTLSET1 0x0340 | ||
205 | #define PESDR1_440SPE_UTLSET2 0x0341 | ||
206 | #define PESDR1_440SPE_DLPSET 0x0342 | ||
207 | #define PESDR1_440SPE_LOOP 0x0343 | ||
208 | #define PESDR1_440SPE_RCSSET 0x0344 | ||
209 | #define PESDR1_440SPE_RCSSTS 0x0345 | ||
210 | #define PESDR1_440SPE_HSSL0SET1 0x0346 | ||
211 | #define PESDR1_440SPE_HSSL0SET2 0x0347 | ||
212 | #define PESDR1_440SPE_HSSL0STS 0x0348 | ||
213 | #define PESDR1_440SPE_HSSL1SET1 0x0349 | ||
214 | #define PESDR1_440SPE_HSSL1SET2 0x034a | ||
215 | #define PESDR1_440SPE_HSSL1STS 0x034b | ||
216 | #define PESDR1_440SPE_HSSL2SET1 0x034c | ||
217 | #define PESDR1_440SPE_HSSL2SET2 0x034d | ||
218 | #define PESDR1_440SPE_HSSL2STS 0x034e | ||
219 | #define PESDR1_440SPE_HSSL3SET1 0x034f | ||
220 | #define PESDR1_440SPE_HSSL3SET2 0x0350 | ||
221 | #define PESDR1_440SPE_HSSL3STS 0x0351 | ||
222 | #define PESDR1_440SPE_HSSCTLSET 0x0352 | ||
223 | #define PESDR1_440SPE_LANE_ABCD 0x0353 | ||
224 | |||
225 | #define PESDR2_440SPE_UTLSET1 0x0370 | ||
226 | #define PESDR2_440SPE_UTLSET2 0x0371 | ||
227 | #define PESDR2_440SPE_DLPSET 0x0372 | ||
228 | #define PESDR2_440SPE_LOOP 0x0373 | ||
229 | #define PESDR2_440SPE_RCSSET 0x0374 | ||
230 | #define PESDR2_440SPE_RCSSTS 0x0375 | ||
231 | #define PESDR2_440SPE_HSSL0SET1 0x0376 | ||
232 | #define PESDR2_440SPE_HSSL0SET2 0x0377 | ||
233 | #define PESDR2_440SPE_HSSL0STS 0x0378 | ||
234 | #define PESDR2_440SPE_HSSL1SET1 0x0379 | ||
235 | #define PESDR2_440SPE_HSSL1SET2 0x037a | ||
236 | #define PESDR2_440SPE_HSSL1STS 0x037b | ||
237 | #define PESDR2_440SPE_HSSL2SET1 0x037c | ||
238 | #define PESDR2_440SPE_HSSL2SET2 0x037d | ||
239 | #define PESDR2_440SPE_HSSL2STS 0x037e | ||
240 | #define PESDR2_440SPE_HSSL3SET1 0x037f | ||
241 | #define PESDR2_440SPE_HSSL3SET2 0x0380 | ||
242 | #define PESDR2_440SPE_HSSL3STS 0x0381 | ||
243 | #define PESDR2_440SPE_HSSCTLSET 0x0382 | ||
244 | #define PESDR2_440SPE_LANE_ABCD 0x0383 | ||
245 | |||
246 | /* | ||
247 | * 405EX additional DCRs | ||
248 | */ | ||
249 | #define PESDR0_405EX_UTLSET1 0x0400 | ||
250 | #define PESDR0_405EX_UTLSET2 0x0401 | ||
251 | #define PESDR0_405EX_DLPSET 0x0402 | ||
252 | #define PESDR0_405EX_LOOP 0x0403 | ||
253 | #define PESDR0_405EX_RCSSET 0x0404 | ||
254 | #define PESDR0_405EX_RCSSTS 0x0405 | ||
255 | #define PESDR0_405EX_PHYSET1 0x0406 | ||
256 | #define PESDR0_405EX_PHYSET2 0x0407 | ||
257 | #define PESDR0_405EX_BIST 0x0408 | ||
258 | #define PESDR0_405EX_LPB 0x040B | ||
259 | #define PESDR0_405EX_PHYSTA 0x040C | ||
260 | |||
261 | #define PESDR1_405EX_UTLSET1 0x0440 | ||
262 | #define PESDR1_405EX_UTLSET2 0x0441 | ||
263 | #define PESDR1_405EX_DLPSET 0x0442 | ||
264 | #define PESDR1_405EX_LOOP 0x0443 | ||
265 | #define PESDR1_405EX_RCSSET 0x0444 | ||
266 | #define PESDR1_405EX_RCSSTS 0x0445 | ||
267 | #define PESDR1_405EX_PHYSET1 0x0446 | ||
268 | #define PESDR1_405EX_PHYSET2 0x0447 | ||
269 | #define PESDR1_405EX_BIST 0x0448 | ||
270 | #define PESDR1_405EX_LPB 0x044B | ||
271 | #define PESDR1_405EX_PHYSTA 0x044C | ||
272 | |||
273 | /* | ||
274 | * Of the above, some are common offsets from the base | ||
275 | */ | ||
276 | #define PESDRn_UTLSET1 0x00 | ||
277 | #define PESDRn_UTLSET2 0x01 | ||
278 | #define PESDRn_DLPSET 0x02 | ||
279 | #define PESDRn_LOOP 0x03 | ||
280 | #define PESDRn_RCSSET 0x04 | ||
281 | #define PESDRn_RCSSTS 0x05 | ||
282 | |||
283 | /* 440spe only */ | ||
284 | #define PESDRn_440SPE_HSSL0SET1 0x06 | ||
285 | #define PESDRn_440SPE_HSSL0SET2 0x07 | ||
286 | #define PESDRn_440SPE_HSSL0STS 0x08 | ||
287 | #define PESDRn_440SPE_HSSL1SET1 0x09 | ||
288 | #define PESDRn_440SPE_HSSL1SET2 0x0a | ||
289 | #define PESDRn_440SPE_HSSL1STS 0x0b | ||
290 | #define PESDRn_440SPE_HSSL2SET1 0x0c | ||
291 | #define PESDRn_440SPE_HSSL2SET2 0x0d | ||
292 | #define PESDRn_440SPE_HSSL2STS 0x0e | ||
293 | #define PESDRn_440SPE_HSSL3SET1 0x0f | ||
294 | #define PESDRn_440SPE_HSSL3SET2 0x10 | ||
295 | #define PESDRn_440SPE_HSSL3STS 0x11 | ||
296 | |||
297 | /* 440spe port 0 only */ | ||
298 | #define PESDRn_440SPE_HSSL4SET1 0x12 | ||
299 | #define PESDRn_440SPE_HSSL4SET2 0x13 | ||
300 | #define PESDRn_440SPE_HSSL4STS 0x14 | ||
301 | #define PESDRn_440SPE_HSSL5SET1 0x15 | ||
302 | #define PESDRn_440SPE_HSSL5SET2 0x16 | ||
303 | #define PESDRn_440SPE_HSSL5STS 0x17 | ||
304 | #define PESDRn_440SPE_HSSL6SET1 0x18 | ||
305 | #define PESDRn_440SPE_HSSL6SET2 0x19 | ||
306 | #define PESDRn_440SPE_HSSL6STS 0x1a | ||
307 | #define PESDRn_440SPE_HSSL7SET1 0x1b | ||
308 | #define PESDRn_440SPE_HSSL7SET2 0x1c | ||
309 | #define PESDRn_440SPE_HSSL7STS 0x1d | ||
310 | |||
311 | /* 405ex only */ | ||
312 | #define PESDRn_405EX_PHYSET1 0x06 | ||
313 | #define PESDRn_405EX_PHYSET2 0x07 | ||
314 | #define PESDRn_405EX_PHYSTA 0x0c | ||
315 | |||
316 | /* | ||
317 | * UTL register offsets | ||
318 | */ | ||
319 | #define PEUTL_PBCTL 0x00 | ||
320 | #define PEUTL_PBBSZ 0x20 | ||
321 | #define PEUTL_OPDBSZ 0x68 | ||
322 | #define PEUTL_IPHBSZ 0x70 | ||
323 | #define PEUTL_IPDBSZ 0x78 | ||
324 | #define PEUTL_OUTTR 0x90 | ||
325 | #define PEUTL_INTR 0x98 | ||
326 | #define PEUTL_PCTL 0xa0 | ||
327 | #define PEUTL_RCSTA 0xB0 | ||
328 | #define PEUTL_RCIRQEN 0xb8 | ||
329 | |||
330 | /* | ||
331 | * Config space register offsets | ||
332 | */ | ||
333 | #define PECFG_BAR0LMPA 0x210 | ||
334 | #define PECFG_BAR0HMPA 0x214 | ||
335 | #define PECFG_BAR1MPA 0x218 | ||
336 | #define PECFG_BAR2LMPA 0x220 | ||
337 | #define PECFG_BAR2HMPA 0x224 | ||
338 | |||
339 | #define PECFG_PIMEN 0x33c | ||
340 | #define PECFG_PIM0LAL 0x340 | ||
341 | #define PECFG_PIM0LAH 0x344 | ||
342 | #define PECFG_PIM1LAL 0x348 | ||
343 | #define PECFG_PIM1LAH 0x34c | ||
344 | #define PECFG_PIM01SAL 0x350 | ||
345 | #define PECFG_PIM01SAH 0x354 | ||
346 | |||
347 | #define PECFG_POM0LAL 0x380 | ||
348 | #define PECFG_POM0LAH 0x384 | ||
349 | #define PECFG_POM1LAL 0x388 | ||
350 | #define PECFG_POM1LAH 0x38c | ||
351 | #define PECFG_POM2LAL 0x390 | ||
352 | #define PECFG_POM2LAH 0x394 | ||
353 | |||
354 | |||
355 | enum | ||
356 | { | ||
357 | PTYPE_ENDPOINT = 0x0, | ||
358 | PTYPE_LEGACY_ENDPOINT = 0x1, | ||
359 | PTYPE_ROOT_PORT = 0x4, | ||
360 | |||
361 | LNKW_X1 = 0x1, | ||
362 | LNKW_X4 = 0x4, | ||
363 | LNKW_X8 = 0x8 | ||
364 | }; | ||
365 | |||
124 | 366 | ||
125 | #endif /* __PPC4XX_PCI_H__ */ | 367 | #endif /* __PPC4XX_PCI_H__ */ |