diff options
Diffstat (limited to 'arch/powerpc/sysdev/ppc4xx_pci.c')
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_pci.c | 133 |
1 files changed, 117 insertions, 16 deletions
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 5abfcd157483..1814adbd2236 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c | |||
@@ -527,6 +527,7 @@ static void __init ppc4xx_probe_pcix_bridge(struct device_node *np) | |||
527 | * | 527 | * |
528 | * ibm,plb-pciex-440spe | 528 | * ibm,plb-pciex-440spe |
529 | * ibm,plb-pciex-405ex | 529 | * ibm,plb-pciex-405ex |
530 | * ibm,plb-pciex-460ex | ||
530 | * | 531 | * |
531 | * Anything else will be rejected for now as they are all subtly | 532 | * Anything else will be rejected for now as they are all subtly |
532 | * different unfortunately. | 533 | * different unfortunately. |
@@ -645,7 +646,7 @@ static int __init ppc440spe_pciex_core_init(struct device_node *np) | |||
645 | int time_out = 20; | 646 | int time_out = 20; |
646 | 647 | ||
647 | /* Set PLL clock receiver to LVPECL */ | 648 | /* Set PLL clock receiver to LVPECL */ |
648 | mtdcri(SDR0, PESDR0_PLLLCT1, mfdcri(SDR0, PESDR0_PLLLCT1) | 1 << 28); | 649 | dcri_clrset(SDR0, PESDR0_PLLLCT1, 0, 1 << 28); |
649 | 650 | ||
650 | /* Shouldn't we do all the calibration stuff etc... here ? */ | 651 | /* Shouldn't we do all the calibration stuff etc... here ? */ |
651 | if (ppc440spe_pciex_check_reset(np)) | 652 | if (ppc440spe_pciex_check_reset(np)) |
@@ -659,8 +660,7 @@ static int __init ppc440spe_pciex_core_init(struct device_node *np) | |||
659 | } | 660 | } |
660 | 661 | ||
661 | /* De-assert reset of PCIe PLL, wait for lock */ | 662 | /* De-assert reset of PCIe PLL, wait for lock */ |
662 | mtdcri(SDR0, PESDR0_PLLLCT1, | 663 | dcri_clrset(SDR0, PESDR0_PLLLCT1, 1 << 24, 0); |
663 | mfdcri(SDR0, PESDR0_PLLLCT1) & ~(1 << 24)); | ||
664 | udelay(3); | 664 | udelay(3); |
665 | 665 | ||
666 | while (time_out) { | 666 | while (time_out) { |
@@ -712,9 +712,8 @@ static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | |||
712 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL7SET1, | 712 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL7SET1, |
713 | 0x35000000); | 713 | 0x35000000); |
714 | } | 714 | } |
715 | val = mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET); | 715 | dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, |
716 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, | 716 | (1 << 24) | (1 << 16), 1 << 12); |
717 | (val & ~(1 << 24 | 1 << 16)) | 1 << 12); | ||
718 | 717 | ||
719 | return 0; | 718 | return 0; |
720 | } | 719 | } |
@@ -775,6 +774,115 @@ static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = | |||
775 | .setup_utl = ppc440speB_pciex_init_utl, | 774 | .setup_utl = ppc440speB_pciex_init_utl, |
776 | }; | 775 | }; |
777 | 776 | ||
777 | static int __init ppc460ex_pciex_core_init(struct device_node *np) | ||
778 | { | ||
779 | /* Nothing to do, return 2 ports */ | ||
780 | return 2; | ||
781 | } | ||
782 | |||
783 | static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | ||
784 | { | ||
785 | u32 val; | ||
786 | u32 utlset1; | ||
787 | |||
788 | if (port->endpoint) | ||
789 | val = PTYPE_LEGACY_ENDPOINT << 20; | ||
790 | else | ||
791 | val = PTYPE_ROOT_PORT << 20; | ||
792 | |||
793 | if (port->index == 0) { | ||
794 | val |= LNKW_X1 << 12; | ||
795 | utlset1 = 0x20000000; | ||
796 | } else { | ||
797 | val |= LNKW_X4 << 12; | ||
798 | utlset1 = 0x20101101; | ||
799 | } | ||
800 | |||
801 | mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val); | ||
802 | mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, utlset1); | ||
803 | mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01210000); | ||
804 | |||
805 | switch (port->index) { | ||
806 | case 0: | ||
807 | mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230); | ||
808 | mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000136); | ||
809 | mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006); | ||
810 | |||
811 | mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST,0x10000000); | ||
812 | break; | ||
813 | |||
814 | case 1: | ||
815 | mtdcri(SDR0, PESDR1_460EX_L0CDRCTL, 0x00003230); | ||
816 | mtdcri(SDR0, PESDR1_460EX_L1CDRCTL, 0x00003230); | ||
817 | mtdcri(SDR0, PESDR1_460EX_L2CDRCTL, 0x00003230); | ||
818 | mtdcri(SDR0, PESDR1_460EX_L3CDRCTL, 0x00003230); | ||
819 | mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000136); | ||
820 | mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000136); | ||
821 | mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000136); | ||
822 | mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000136); | ||
823 | mtdcri(SDR0, PESDR1_460EX_L0CLK, 0x00000006); | ||
824 | mtdcri(SDR0, PESDR1_460EX_L1CLK, 0x00000006); | ||
825 | mtdcri(SDR0, PESDR1_460EX_L2CLK, 0x00000006); | ||
826 | mtdcri(SDR0, PESDR1_460EX_L3CLK, 0x00000006); | ||
827 | |||
828 | mtdcri(SDR0, PESDR1_460EX_PHY_CTL_RST,0x10000000); | ||
829 | break; | ||
830 | } | ||
831 | |||
832 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, | ||
833 | mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) | | ||
834 | (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN)); | ||
835 | |||
836 | /* Poll for PHY reset */ | ||
837 | /* XXX FIXME add timeout */ | ||
838 | switch (port->index) { | ||
839 | case 0: | ||
840 | while (!(mfdcri(SDR0, PESDR0_460EX_RSTSTA) & 0x1)) | ||
841 | udelay(10); | ||
842 | break; | ||
843 | case 1: | ||
844 | while (!(mfdcri(SDR0, PESDR1_460EX_RSTSTA) & 0x1)) | ||
845 | udelay(10); | ||
846 | break; | ||
847 | } | ||
848 | |||
849 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, | ||
850 | (mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) & | ||
851 | ~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) | | ||
852 | PESDRx_RCSSET_RSTPYN); | ||
853 | |||
854 | port->has_ibpre = 1; | ||
855 | |||
856 | return 0; | ||
857 | } | ||
858 | |||
859 | static int ppc460ex_pciex_init_utl(struct ppc4xx_pciex_port *port) | ||
860 | { | ||
861 | dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x0); | ||
862 | |||
863 | /* | ||
864 | * Set buffer allocations and then assert VRB and TXE. | ||
865 | */ | ||
866 | out_be32(port->utl_base + PEUTL_PBCTL, 0x0800000c); | ||
867 | out_be32(port->utl_base + PEUTL_OUTTR, 0x08000000); | ||
868 | out_be32(port->utl_base + PEUTL_INTR, 0x02000000); | ||
869 | out_be32(port->utl_base + PEUTL_OPDBSZ, 0x04000000); | ||
870 | out_be32(port->utl_base + PEUTL_PBBSZ, 0x00000000); | ||
871 | out_be32(port->utl_base + PEUTL_IPHBSZ, 0x02000000); | ||
872 | out_be32(port->utl_base + PEUTL_IPDBSZ, 0x04000000); | ||
873 | out_be32(port->utl_base + PEUTL_RCIRQEN,0x00f00000); | ||
874 | out_be32(port->utl_base + PEUTL_PCTL, 0x80800066); | ||
875 | |||
876 | return 0; | ||
877 | } | ||
878 | |||
879 | static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata = | ||
880 | { | ||
881 | .core_init = ppc460ex_pciex_core_init, | ||
882 | .port_init_hw = ppc460ex_pciex_init_port_hw, | ||
883 | .setup_utl = ppc460ex_pciex_init_utl, | ||
884 | }; | ||
885 | |||
778 | #endif /* CONFIG_44x */ | 886 | #endif /* CONFIG_44x */ |
779 | 887 | ||
780 | #ifdef CONFIG_40x | 888 | #ifdef CONFIG_40x |
@@ -830,17 +938,9 @@ static int ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | |||
830 | * PCIe boards don't show this problem. | 938 | * PCIe boards don't show this problem. |
831 | * This has to be re-tested and fixed in a later release! | 939 | * This has to be re-tested and fixed in a later release! |
832 | */ | 940 | */ |
833 | #if 0 /* XXX FIXME: Not resetting the PHY will leave all resources | ||
834 | * configured as done previously by U-Boot. Then Linux will currently | ||
835 | * not reassign them. So the PHY reset is now done always. This will | ||
836 | * lead to problems with the Atheros PCIe board again. | ||
837 | */ | ||
838 | val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP); | 941 | val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP); |
839 | if (!(val & 0x00001000)) | 942 | if (!(val & 0x00001000)) |
840 | ppc405ex_pcie_phy_reset(port); | 943 | ppc405ex_pcie_phy_reset(port); |
841 | #else | ||
842 | ppc405ex_pcie_phy_reset(port); | ||
843 | #endif | ||
844 | 944 | ||
845 | dcr_write(port->dcrs, DCRO_PEGPL_CFG, 0x10000000); /* guarded on */ | 945 | dcr_write(port->dcrs, DCRO_PEGPL_CFG, 0x10000000); /* guarded on */ |
846 | 946 | ||
@@ -896,6 +996,8 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np) | |||
896 | else | 996 | else |
897 | ppc4xx_pciex_hwops = &ppc440speB_pcie_hwops; | 997 | ppc4xx_pciex_hwops = &ppc440speB_pcie_hwops; |
898 | } | 998 | } |
999 | if (of_device_is_compatible(np, "ibm,plb-pciex-460ex")) | ||
1000 | ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops; | ||
899 | #endif /* CONFIG_44x */ | 1001 | #endif /* CONFIG_44x */ |
900 | #ifdef CONFIG_40x | 1002 | #ifdef CONFIG_40x |
901 | if (of_device_is_compatible(np, "ibm,plb-pciex-405ex")) | 1003 | if (of_device_is_compatible(np, "ibm,plb-pciex-405ex")) |
@@ -1042,8 +1144,7 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) | |||
1042 | port->link = 0; | 1144 | port->link = 0; |
1043 | } | 1145 | } |
1044 | 1146 | ||
1045 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, | 1147 | dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 0, 1 << 20); |
1046 | mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) | 1 << 20); | ||
1047 | msleep(100); | 1148 | msleep(100); |
1048 | 1149 | ||
1049 | return 0; | 1150 | return 0; |