This is mostly updating the PCI Express code to work with the new core
in the Rev. B chip, which unfortunately has different undocumented
restrictions on the PLB addresses that can be used from the Rev. A core.

Also, when adding the cputable entry for 440SPe Rev. B, we need to
adjust the entry for 440SP Rev. A so that it looks at more bits of the
PVR.  The 440SPe Rev. B has PVR 53421891, which would have matched the
old 440SP pattern of 53xxx891.

Signed-off-by: Roland Dreier <[EMAIL PROTECTED]>
---
Matt, please queue for a 2.6.20 merge.

 arch/powerpc/kernel/cputable.c           |   21 ++-
 arch/ppc/platforms/4xx/davinci_sc.c      |    5 -
 arch/ppc/syslib/ppc440spe_pcie.c         |  258 ++++++++++++++++++++++--------
 drivers/infiniband/hw/mthca/mthca_main.c |    4 +-
 4 files changed, 206 insertions(+), 82 deletions(-)

diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index bfd499e..04559be 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -1073,8 +1073,8 @@ #ifdef CONFIG_44x
                .platform               = "ppc440",
        },
        { /* 440SP Rev. A */
-               .pvr_mask               = 0xff000fff,
-               .pvr_value              = 0x53000891,
+               .pvr_mask               = 0xfff00fff,
+               .pvr_value              = 0x53200891,
                .cpu_name               = "440SP Rev. A",
                .cpu_features           = CPU_FTRS_44X,
                .cpu_user_features      = COMMON_USER_BOOKE,
@@ -1083,9 +1083,20 @@ #ifdef CONFIG_44x
                .platform               = "ppc440",
        },
        { /* 440SPe Rev. A */
-               .pvr_mask               = 0xff000fff,
-               .pvr_value              = 0x53000890,
-               .cpu_name               = "440SPe Rev. A",
+               .pvr_mask               = 0xfff00fff,
+               .pvr_value              = 0x53400890,
+               .cpu_name               = "440SPe Rev. A",
+               .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
+                       CPU_FTR_USE_TB,
+               .cpu_user_features      = COMMON_USER_BOOKE,
+               .icache_bsize           = 32,
+               .dcache_bsize           = 32,
+               .platform               = "ppc440",
+       },
+       { /* 440SPe Rev. B */
+               .pvr_mask               = 0xfff00fff,
+               .pvr_value              = 0x53400891,
+               .cpu_name               = "440SPe Rev. B",
                .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
                        CPU_FTR_USE_TB,
                .cpu_user_features      = COMMON_USER_BOOKE,
diff --git a/arch/ppc/platforms/4xx/davinci_sc.c 
b/arch/ppc/platforms/4xx/davinci_sc.c
index 623988f..3dbedda 100644
--- a/arch/ppc/platforms/4xx/davinci_sc.c
+++ b/arch/ppc/platforms/4xx/davinci_sc.c
@@ -172,11 +172,6 @@ davinci_sc_setup_hoses(void)
        char name[20];
        int i;
 
-       if (0 && ppc440spe_init_pcie()) {
-               printk(KERN_WARNING "PPC440SPe PCI Express initialization 
failed\n");
-               return;
-       }
-
        for (i = 0; i <= 2; ++i) {
                if (!davinci_sc_pcie_card_present(i))
                        continue;
diff --git a/arch/ppc/syslib/ppc440spe_pcie.c b/arch/ppc/syslib/ppc440spe_pcie.c
index dd5d4b9..7ae14d2 100644
--- a/arch/ppc/syslib/ppc440spe_pcie.c
+++ b/arch/ppc/syslib/ppc440spe_pcie.c
@@ -19,16 +19,23 @@ #include <asm/ibm44x.h>
 
 #include "ppc440spe_pcie.h"
 
+static enum {
+       REV_A,
+       REV_B
+} core_rev;
+
 static int
 pcie_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
                     int len, u32 *val)
 {
        struct pci_controller *hose = bus->sysdata;
 
-       if (PCI_SLOT(devfn) != 1)
+       /* 440SPE implements only one function per port */
+       if (PCI_SLOT(devfn) != 1 || PCI_FUNC(devfn) != 0)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
-       offset += devfn << 12;
+       if (core_rev == REV_A)
+               offset += devfn << 12;
 
        /*
         * Note: the caller has already checked that offset is
@@ -57,10 +64,11 @@ pcie_write_config(struct pci_bus *bus, u
 {
        struct pci_controller *hose = bus->sysdata;
 
-       if (PCI_SLOT(devfn) != 1)
+       if (PCI_SLOT(devfn) != 1 || PCI_FUNC(devfn) != 0)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
-       offset += devfn << 12;
+       if (core_rev == REV_A)
+               offset += devfn << 12;
 
        switch (len) {
        case 1:
@@ -153,6 +161,20 @@ static void check_error(void)
  */
 int ppc440spe_init_pcie(void)
 {
+       int i;
+
+       switch (PVR_REV(mfspr(SPRN_PVR))) {
+       case 0x1890: core_rev = REV_A; break;
+       case 0x1891: core_rev = REV_B; break;
+       default:
+               printk(KERN_ERR "PCIE: Unknown PVR rev. %lx\n",
+                      PVR_REV(mfspr(SPRN_PVR)));
+               return -1;
+       }
+
+       printk(KERN_INFO "PCIE: core rev %c detected\n",
+              core_rev == REV_A ? 'A' : 'B');
+
        /* Set PLL clock receiver to LVPECL */
        SDR_WRITE(PESDR0_PLLLCT1, SDR_READ(PESDR0_PLLLCT1) | 1 << 28);
 
@@ -168,21 +190,78 @@ int ppc440spe_init_pcie(void)
        SDR_WRITE(PESDR0_PLLLCT1, SDR_READ(PESDR0_PLLLCT1) & ~(1 << 24));
        udelay(3);
 
+       for (i = 0; i < 100; ++i) {
+               if (SDR_READ(PESDR0_PLLLCT3) & 0x10000000)
+                       goto pll_ok;
+
+               udelay(1);
+       }
+
+       printk(KERN_INFO "PCIE: VCO output not locked: %x\n",
+              SDR_READ(PESDR0_PLLLCT3));
+       return -1;
+
+pll_ok:
        return 0;
 }
 
+static void ppc440spe_setup_utl(int port)
+{
+       void __iomem *utl_base;
+
+       /*
+        * Map UTL registers at 0xc_1000_0n00
+        */
+       switch (port) {
+       case 0:
+               mtdcr(DCRN_PEGPL_REGBAH(PCIE0), 0x0000000c);
+               mtdcr(DCRN_PEGPL_REGBAL(PCIE0), 0x10000000);
+               mtdcr(DCRN_PEGPL_REGMSK(PCIE0), 0x00007001);
+               mtdcr(DCRN_PEGPL_SPECIAL(PCIE0), 0x68782800);
+               break;
+
+       case 1:
+               mtdcr(DCRN_PEGPL_REGBAH(PCIE1), 0x0000000c);
+               mtdcr(DCRN_PEGPL_REGBAL(PCIE1), 0x10001000);
+               mtdcr(DCRN_PEGPL_REGMSK(PCIE1), 0x00007001);
+               mtdcr(DCRN_PEGPL_SPECIAL(PCIE1), 0x68782800);
+               break;
+
+       case 2:
+               mtdcr(DCRN_PEGPL_REGBAH(PCIE2), 0x0000000c);
+               mtdcr(DCRN_PEGPL_REGBAL(PCIE2), 0x10002000);
+               mtdcr(DCRN_PEGPL_REGMSK(PCIE2), 0x00007001);
+               mtdcr(DCRN_PEGPL_SPECIAL(PCIE2), 0x68782800);
+       }
+
+       utl_base = ioremap64(0xc10000000ull + 0x1000 * port, 0x100);
+
+       /*
+        * Set buffer allocations and then assert VRB and TXE.
+        */
+       out_be32(utl_base + PEUTL_OUTTR,   0x08000000);
+       out_be32(utl_base + PEUTL_INTR,    0x02000000);
+       out_be32(utl_base + PEUTL_OPDBSZ,  0x10000000);
+       out_be32(utl_base + PEUTL_PBBSZ,   0x53000000);
+       out_be32(utl_base + PEUTL_IPHBSZ,  0x08000000);
+       out_be32(utl_base + PEUTL_IPDBSZ,  0x10000000);
+       out_be32(utl_base + PEUTL_RCIRQEN, 0x00f00000);
+       out_be32(utl_base + PEUTL_PCTL,    0x80800066);
+
+       iounmap(utl_base);
+}
+
 int ppc440spe_init_pcie_rootport(int port)
 {
        static int core_init;
-       void __iomem *utl_base;
        u32 val = 0;
        int i;
 
        if (!core_init) {
-               ++core_init;
                i = ppc440spe_init_pcie();
                if (i)
                        return i;
+               ++core_init;
        }
 
        /*
@@ -193,13 +272,19 @@ int ppc440spe_init_pcie_rootport(int por
         * - Set up UTL configuration.
         * - Increase SERDES drive strength to levels suggested by AMCC.
         * - De-assert RSTPYN, RSTDL and RSTGU.
+        *
+        * For rev. B chips, we don't set PESDRn_UTLSET2, but just
+        * leave it with default setting 0x11310000. The register has
+        * new fields, PESDRn_UTLSET2[LKINE] in particular: clearing
+        * it leads to a PCIe core hang.
         */
        switch (port) {
        case 0:
                SDR_WRITE(PESDR0_DLPSET, PTYPE_ROOT_PORT << 20 | LNKW_X8 << 12);
 
                SDR_WRITE(PESDR0_UTLSET1, 0x21222222);
-               SDR_WRITE(PESDR0_UTLSET2, 0x11000000);
+               if (core_rev == REV_A)
+                       SDR_WRITE(PESDR0_UTLSET2, 0x11000000);
 
                SDR_WRITE(PESDR0_HSSL0SET1, 0x35000000);
                SDR_WRITE(PESDR0_HSSL1SET1, 0x35000000);
@@ -218,7 +303,8 @@ int ppc440spe_init_pcie_rootport(int por
                SDR_WRITE(PESDR1_DLPSET, PTYPE_ROOT_PORT << 20 | LNKW_X4 << 12);
 
                SDR_WRITE(PESDR1_UTLSET1, 0x21222222);
-               SDR_WRITE(PESDR1_UTLSET2, 0x11000000);
+               if (core_rev == REV_A)
+                       SDR_WRITE(PESDR1_UTLSET2, 0x11000000);
 
                SDR_WRITE(PESDR1_HSSL0SET1, 0x35000000);
                SDR_WRITE(PESDR1_HSSL1SET1, 0x35000000);
@@ -233,7 +319,8 @@ int ppc440spe_init_pcie_rootport(int por
                SDR_WRITE(PESDR2_DLPSET, PTYPE_ROOT_PORT << 20 | LNKW_X4 << 12);
 
                SDR_WRITE(PESDR2_UTLSET1, 0x21222222);
-               SDR_WRITE(PESDR2_UTLSET2, 0x11000000);
+               if (core_rev == REV_A)
+                       SDR_WRITE(PESDR2_UTLSET2, 0x11000000);
 
                SDR_WRITE(PESDR2_HSSL0SET1, 0x35000000);
                SDR_WRITE(PESDR2_HSSL1SET1, 0x35000000);
@@ -255,78 +342,81 @@ int ppc440spe_init_pcie_rootport(int por
 
        if (!(val & (1 << 20)))
                printk(KERN_INFO "PCIE%d: PGRST inactive\n", port);
-       else
-               printk(KERN_WARNING "PGRST for PCIE%d failed %08x\n", port, 
val);
-
-       switch (port) {
-       case 0: printk(KERN_INFO "PCIE0: LOOP %08x\n", SDR_READ(PESDR0_LOOP)); 
break;
-       case 1: printk(KERN_INFO "PCIE1: LOOP %08x\n", SDR_READ(PESDR1_LOOP)); 
break;
-       case 2: printk(KERN_INFO "PCIE2: LOOP %08x\n", SDR_READ(PESDR2_LOOP)); 
break;
+       else {
+               printk(KERN_WARNING "PCIE%d: PGRST failed %08x\n", port, val);
+               return -1;
        }
 
-       /*
-        * Map UTL registers at 0xc_1000_0n00
-        */
        switch (port) {
-       case 0:
-               mtdcr(DCRN_PEGPL_REGBAH(PCIE0), 0x0000000c);
-               mtdcr(DCRN_PEGPL_REGBAL(PCIE0), 0x10000000);
-               mtdcr(DCRN_PEGPL_REGMSK(PCIE0), 0x00007001);
-               mtdcr(DCRN_PEGPL_SPECIAL(PCIE0), 0x68782800);
-               break;
-
-       case 1:
-               mtdcr(DCRN_PEGPL_REGBAH(PCIE1), 0x0000000c);
-               mtdcr(DCRN_PEGPL_REGBAL(PCIE1), 0x10001000);
-               mtdcr(DCRN_PEGPL_REGMSK(PCIE1), 0x00007001);
-               mtdcr(DCRN_PEGPL_SPECIAL(PCIE1), 0x68782800);
-               break;
-
-       case 2:
-               mtdcr(DCRN_PEGPL_REGBAH(PCIE2), 0x0000000c);
-               mtdcr(DCRN_PEGPL_REGBAL(PCIE2), 0x10002000);
-               mtdcr(DCRN_PEGPL_REGMSK(PCIE2), 0x00007001);
-               mtdcr(DCRN_PEGPL_SPECIAL(PCIE2), 0x68782800);
+       case 0: val = SDR_READ(PESDR0_LOOP); break;
+       case 1: val = SDR_READ(PESDR1_LOOP); break;
+       case 2: val = SDR_READ(PESDR2_LOOP); break;
        }
 
-       utl_base = ioremap64(0xc10000000ull + 0x1000 * port, 0x100);
+       if (val & 0x1000)
+               printk(KERN_INFO "PCIE%d: link up\n", port);
+       else {
+               printk(KERN_WARNING "PCIE%d: link down %08x\n", port, val);
+               return -1;
+       }
 
        /*
-        * Set buffer allocations and then assert VRB and TXE.
+        * Setup UTL registers - but only on rev. A!
+        * Just leave rev. B with default settings.
         */
-       out_be32(utl_base + PEUTL_OUTTR,   0x08000000);
-       out_be32(utl_base + PEUTL_INTR,    0x02000000);
-       out_be32(utl_base + PEUTL_OPDBSZ,  0x10000000);
-       out_be32(utl_base + PEUTL_PBBSZ,   0x53000000);
-       out_be32(utl_base + PEUTL_IPHBSZ,  0x08000000);
-       out_be32(utl_base + PEUTL_IPDBSZ,  0x10000000);
-       out_be32(utl_base + PEUTL_RCIRQEN, 0x00f00000);
-       out_be32(utl_base + PEUTL_PCTL,    0x80800066);
-
-       iounmap(utl_base);
+       if (core_rev == REV_A)
+               ppc440spe_setup_utl(port);
 
        /*
         * We map PCI Express configuration access into the 512MB regions
+        *
+        * Rev. B is very strict about PLB real addressess and ranges
+        * to be mapped for config space; it seems to only work with
+        * 0xd_nnnn_nnnn range (the core hangs on config transaction
+        * attempts when set otherwise), while rev. A only works with
+        * 0xc_nnnn_nnnn.  So we use the following ranges:
+        *
+        * Rev. A:
         *     PCIE0: 0xc_4000_0000
         *     PCIE1: 0xc_8000_0000
         *     PCIE2: 0xc_c000_0000
+        *
+        * Rev. B:
+        *     PCIE0: 0xd_0000_0000
+        *     PCIE1: 0xd_2000_0000
+        *     PCIE2: 0xd_4000_0000
         */
        switch (port) {
        case 0:
-               mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000c);
-               mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x40000000);
+               if (core_rev == REV_A) {
+                       mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000c);
+                       mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x40000000);
+               } else {
+                       mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000d);
+                       mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x00000000);
+               }
                mtdcr(DCRN_PEGPL_CFGMSK(PCIE0), 0xe0000001); /* 512MB region, 
valid */
                break;
 
        case 1:
-               mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000c);
-               mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x80000000);
+               if (core_rev == REV_A) {
+                       mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000c);
+                       mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x80000000);
+               } else {
+                       mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000d);
+                       mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x20000000);
+               }
                mtdcr(DCRN_PEGPL_CFGMSK(PCIE1), 0xe0000001); /* 512MB region, 
valid */
                break;
 
        case 2:
-               mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000c);
-               mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0xc0000000);
+               if (core_rev == REV_A) {
+                       mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000c);
+                       mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0xc0000000);
+               } else {
+                       mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000d);
+                       mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0x40000000);
+               }
                mtdcr(DCRN_PEGPL_CFGMSK(PCIE2), 0xe0000001); /* 512MB region, 
valid */
                break;
        }
@@ -336,18 +426,24 @@ int ppc440spe_init_pcie_rootport(int por
         */
        switch (port) {
        case 0:
-               if (!(SDR_READ(PESDR0_RCSSTS) & (1 << 16)))
+               if (!(SDR_READ(PESDR0_RCSSTS) & (1 << 16))) {
                        printk(KERN_WARNING "PCIE0: VC0 not active\n");
+                       return -1;
+               }
                SDR_WRITE(PESDR0_RCSSET, SDR_READ(PESDR0_RCSSET) | 1 << 20);
                break;
        case 1:
-               if (!(SDR_READ(PESDR1_RCSSTS) & (1 << 16)))
-                       printk(KERN_WARNING "PCIE0: VC0 not active\n");
+               if (!(SDR_READ(PESDR1_RCSSTS) & (1 << 16))) {
+                       printk(KERN_WARNING "PCIE1: VC0 not active\n");
+                       return -1;
+               }
                SDR_WRITE(PESDR1_RCSSET, SDR_READ(PESDR1_RCSSET) | 1 << 20);
                break;
        case 2:
-               if (!(SDR_READ(PESDR2_RCSSTS) & (1 << 16)))
-                       printk(KERN_WARNING "PCIE0: VC0 not active\n");
+               if (!(SDR_READ(PESDR2_RCSSTS) & (1 << 16))) {
+                       printk(KERN_WARNING "PCIE2: VC0 not active\n");
+                       return -1;
+               }
                SDR_WRITE(PESDR2_RCSSET, SDR_READ(PESDR2_RCSSET) | 1 << 20);
                break;
        }
@@ -375,19 +471,42 @@ void ppc440spe_setup_pcie(struct pci_con
 {
        void __iomem *mbase;
 
-       /*
-        * Map 16MB, which is enough for 4 bits of bus #
-        */
-       hose->cfg_data = ioremap64(0xc40000000ull + port * 0x40000000,
-                                  1 << 24);
+       if (core_rev == REV_A) {
+               /*
+                * Map 16MB, which is enough for 4 bits of bus #
+                */
+               hose->cfg_data = ioremap64(0xc40000000ull + port * 0x40000000,
+                                          1 << 24);
+
+               mbase = ioremap64(0xc50000000ull + port * 0x40000000, 0x1000);
+       } else {
+               /*
+                * Rev. B is very strict about PLB real addressess and
+                * sizes to be mapped for config space; the core hangs
+                * on config transaction attempt if not set to
+                * 0xd_0010_0000, 0xd_2010_0000, 0xd_4010_0000
+                * respectively.
+                */
+               hose->cfg_data = ioremap64(0xd00100000ull + port * 0x20000000,
+                                          0x400);
+
+               /* for accessing Local Config space we need to set A[35] */
+               mbase = ioremap64(0xd10000000ull + port * 0x20000000, 0x400);
+       }
+
        hose->ops = &pcie_pci_ops;
 
        /*
         * Set bus numbers on our root port
         */
-       mbase = ioremap64(0xc50000000ull + port * 0x40000000, 4096);
-       out_8(mbase + PCI_PRIMARY_BUS, 0);
-       out_8(mbase + PCI_SECONDARY_BUS, 0);
+       if (core_rev == REV_A) {
+               out_8(mbase + PCI_PRIMARY_BUS, 0);
+               out_8(mbase + PCI_SECONDARY_BUS, 0);
+       } else {
+               out_8(mbase + PCI_PRIMARY_BUS, 0);
+               out_8(mbase + PCI_SECONDARY_BUS, 1);
+               out_8(mbase + PCI_SUBORDINATE_BUS, 1);
+       }
 
        /*
         * Set up outbound translation to hose->mem_space from PLB
@@ -412,7 +531,6 @@ void ppc440spe_setup_pcie(struct pci_con
                mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE1), 0x7fffffff);
                mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE1),
                      ~(hose->mem_space.end - hose->mem_space.start) | 3);
-
                break;
        case 2:
                mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2),  0x0000000d);
-- 
1.4.3.2
_______________________________________________
Linuxppc-embedded mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

Reply via email to