]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
powerpc/serdes: Add the workaround for erratum A-007186
authorShaveta Leekha <shaveta@freescale.com>
Wed, 28 May 2014 08:48:55 +0000 (14:18 +0530)
committerYork Sun <yorksun@freescale.com>
Thu, 5 Jun 2014 20:45:07 +0000 (13:45 -0700)
SerDes PLL is calibrated at reset. When the junction temperature
delta from the time the PLL is calibrated exceeds +56C/-66C,
jitter may increase and can cause PLL to unlock.

This workaround overwrite the SerDes registers with new values,
to calibrate SerDes registers.
These values are known to work fine for all temperature ranges.

This workaround is valid for B4, T4 and T2 platforms, so
added in their config.

Signed-off-by: Shaveta Leekha <shaveta@freescale.com>
Signed-off-by: Poonam Aggrwal <Poonam.Aggrwal@freescale.com>
[York Sun: replaced typedef ccsr_sfp_regs_t with struct ccsr_sfp_regs]
Reviewed-by: York Sun <yorksun@freescale.com>
arch/powerpc/cpu/mpc85xx/cmd_errata.c
arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c
arch/powerpc/include/asm/config_mpc85xx.h
arch/powerpc/include/asm/immap_85xx.h

index f69c83489735b8197bf7871f6f49c3b29a8ea540..3a04a893012d2d46ad8160eddea6320d93302402 100644 (file)
@@ -269,6 +269,9 @@ static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 #ifdef CONFIG_SYS_FSL_ERRATUM_USB14
        puts("Work-around for Erratum USB14 enabled\n");
 #endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A007186
+       puts("Work-around for Erratum A007186 enabled\n");
+#endif
 #ifdef CONFIG_SYS_FSL_ERRATUM_A006593
        puts("Work-around for Erratum A006593 enabled\n");
 #endif
index 70e09eaed5994a9a8516bc7c597efa9ed575fbe4..d1fc76a13ed25c99e7272b916288cd04fe1c1a41 100644 (file)
@@ -147,12 +147,43 @@ int serdes_get_first_lane(u32 sd, enum srds_prtcl device)
        return -ENODEV;
 }
 
+#define BC3_SHIFT      9
+#define DC3_SHIFT      6
+#define FC3_SHIFT      0
+#define BC2_SHIFT      19
+#define DC2_SHIFT      16
+#define FC2_SHIFT      10
+#define BC1_SHIFT      29
+#define DC1_SHIFT      26
+#define FC1_SHIFT      20
+#define BC_MASK                0x1
+#define DC_MASK                0x7
+#define FC_MASK                0x3F
+
+#define FUSE_VAL_MASK          0x00000003
+#define FUSE_VAL_SHIFT         30
+#define CR0_DCBIAS_SHIFT       5
+#define CR1_FCAP_SHIFT         15
+#define CR1_BCAP_SHIFT         29
+#define FCAP_MASK              0x001F8000
+#define BCAP_MASK              0x20000000
+#define BCAP_OVD_MASK          0x10000000
+#define BYP_CAL_MASK           0x02000000
+
 u64 serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift)
 {
        ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
        u64 serdes_prtcl_map = 0;
        u32 cfg;
        int lane;
+#ifdef CONFIG_SYS_FSL_ERRATUM_A007186
+       struct ccsr_sfp_regs  __iomem *sfp_regs =
+                       (struct ccsr_sfp_regs __iomem *)(CONFIG_SYS_SFP_ADDR);
+       u32 pll_num, pll_status, bc, dc, fc, pll_cr_upd, pll_cr0, pll_cr1;
+       u32 bc_status, fc_status, dc_status, pll_sr2;
+       serdes_corenet_t  __iomem *srds_regs = (void *)sd_addr;
+       u32 sfp_spfr0, sel;
+#endif
 
        cfg = in_be32(&gur->rcwsr[4]) & sd_prctl_mask;
        /* Is serdes enabled at all? */
@@ -161,6 +192,123 @@ u64 serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift)
                return 0;
        }
 
+/* Erratum A-007186
+ * Freescale Scratch Pad Fuse Register n (SFP_FSPFR0)
+ * The workaround requires factory pre-set SerDes calibration values to be
+ * read from a fuse block(Freescale Scratch Pad Fuse Register SFP_FSPFR0)
+ * These values have been shown to work across the
+ * entire temperature range for all SerDes. These values are then written into
+ * the SerDes registers to calibrate the SerDes PLL.
+ *
+ * This workaround for the protocols and rates that only have the Ring VCO.
+ */
+#ifdef CONFIG_SYS_FSL_ERRATUM_A007186
+       sfp_spfr0 = in_be32(&sfp_regs->fsl_spfr0);
+       debug("A007186: sfp_spfr0= %x\n", sfp_spfr0);
+
+       sel = (sfp_spfr0 >> FUSE_VAL_SHIFT) & FUSE_VAL_MASK;
+
+       if (sel == 0x01 || sel == 0x02) {
+               for (pll_num = 0; pll_num < SRDS_MAX_BANK; pll_num++) {
+                       pll_status = in_be32(&srds_regs->bank[pll_num].pllcr0);
+                       debug("A007186: pll_num=%x pllcr0=%x\n",
+                             pll_num, pll_status);
+                       /* STEP 1 */
+                       /* Read factory pre-set SerDes calibration values
+                        * from fuse block(SFP scratch register-sfp_spfr0)
+                        */
+                       switch (pll_status & SRDS_PLLCR0_FRATE_SEL_MASK) {
+                       case SRDS_PLLCR0_FRATE_SEL_3_0:
+                       case SRDS_PLLCR0_FRATE_SEL_3_072:
+                               debug("A007186: 3.0/3.072 protocol rate\n");
+                               bc = (sfp_spfr0 >> BC1_SHIFT) & BC_MASK;
+                               dc = (sfp_spfr0 >> DC1_SHIFT) & DC_MASK;
+                               fc = (sfp_spfr0 >> FC1_SHIFT) & FC_MASK;
+                               break;
+                       case SRDS_PLLCR0_FRATE_SEL_3_125:
+                               debug("A007186: 3.125 protocol rate\n");
+                               bc = (sfp_spfr0 >> BC2_SHIFT) & BC_MASK;
+                               dc = (sfp_spfr0 >> DC2_SHIFT) & DC_MASK;
+                               fc = (sfp_spfr0 >> FC2_SHIFT) & FC_MASK;
+                               break;
+                       case SRDS_PLLCR0_FRATE_SEL_3_75:
+                               debug("A007186: 3.75 protocol rate\n");
+                               bc = (sfp_spfr0 >> BC1_SHIFT) & BC_MASK;
+                               dc = (sfp_spfr0 >> DC1_SHIFT) & DC_MASK;
+                               fc = (sfp_spfr0 >> FC1_SHIFT) & FC_MASK;
+                               break;
+                       default:
+                               continue;
+                       }
+
+                       /* STEP 2 */
+                       /* Write SRDSxPLLnCR1[11:16] = FC
+                        * Write SRDSxPLLnCR1[2] = BC
+                        */
+                       pll_cr1 = in_be32(&srds_regs->bank[pll_num].pllcr1);
+                       pll_cr_upd = (((bc << CR1_BCAP_SHIFT) & BCAP_MASK) |
+                                     ((fc << CR1_FCAP_SHIFT) & FCAP_MASK));
+                       out_be32(&srds_regs->bank[pll_num].pllcr1,
+                                (pll_cr_upd | pll_cr1));
+                       debug("A007186: pll_num=%x Updated PLLCR1=%x\n",
+                             pll_num, (pll_cr_upd | pll_cr1));
+                       /* Write SRDSxPLLnCR0[24:26] = DC
+                        */
+                       pll_cr0 = in_be32(&srds_regs->bank[pll_num].pllcr0);
+                       out_be32(&srds_regs->bank[pll_num].pllcr0,
+                                pll_cr0 | (dc << CR0_DCBIAS_SHIFT));
+                       debug("A007186: pll_num=%x, Updated PLLCR0=%x\n",
+                             pll_num, (pll_cr0 | (dc << CR0_DCBIAS_SHIFT)));
+                       /* Write SRDSxPLLnCR1[3] = 1
+                        * Write SRDSxPLLnCR1[6] = 1
+                        */
+                       pll_cr1 = in_be32(&srds_regs->bank[pll_num].pllcr1);
+                       pll_cr_upd = (BCAP_OVD_MASK | BYP_CAL_MASK);
+                       out_be32(&srds_regs->bank[pll_num].pllcr1,
+                                (pll_cr_upd | pll_cr1));
+                       debug("A007186: pll_num=%x Updated PLLCR1=%x\n",
+                             pll_num, (pll_cr_upd | pll_cr1));
+
+                       /* STEP 3 */
+                       /* Read the status Registers */
+                       /* Verify SRDSxPLLnSR2[8] = BC */
+                       pll_sr2 = in_be32(&srds_regs->bank[pll_num].pllsr2);
+                       debug("A007186: pll_num=%x pllsr2=%x\n",
+                             pll_num, pll_sr2);
+                       bc_status = (pll_sr2 >> 23) & BC_MASK;
+                       if (bc_status != bc)
+                               debug("BC mismatch\n");
+                       fc_status = (pll_sr2 >> 16) & FC_MASK;
+                       if (fc_status != fc)
+                               debug("FC mismatch\n");
+                       pll_cr0 = in_be32(&srds_regs->bank[pll_num].pllcr0);
+                       out_be32(&srds_regs->bank[pll_num].pllcr0, pll_cr0 |
+                                                               0x02000000);
+                       pll_sr2 = in_be32(&srds_regs->bank[pll_num].pllsr2);
+                       dc_status = (pll_sr2 >> 17) & DC_MASK;
+                       if (dc_status != dc)
+                               debug("DC mismatch\n");
+                       pll_cr0 = in_be32(&srds_regs->bank[pll_num].pllcr0);
+                       out_be32(&srds_regs->bank[pll_num].pllcr0, pll_cr0 &
+                                                               0xfdffffff);
+
+                       /* STEP 4 */
+                       /* Wait 750us to verify the PLL is locked
+                        * by checking SRDSxPLLnCR0[8] = 1.
+                        */
+                       udelay(750);
+                       pll_status = in_be32(&srds_regs->bank[pll_num].pllcr0);
+                       debug("A007186: pll_num=%x pllcr0=%x\n",
+                             pll_num, pll_status);
+
+                       if ((pll_status & SRDS_PLLCR0_PLL_LCK) == 0)
+                               printf("A007186 Serdes PLL not locked\n");
+                       else
+                               debug("A007186 Serdes PLL locked\n");
+               }
+       }
+#endif
+
        cfg >>= sd_prctl_shift;
        printf("Using SERDES%d Protocol: %d (0x%x)\n", sd + 1, cfg, cfg);
        if (!is_serdes_prtcl_valid(sd, cfg))
index c9fd2a554aa0e1c9a69f22350e2f8d42aedb6e58..712f2ef4b3020aab86eefd459b0d9e324e068924 100644 (file)
 #define CONFIG_SYS_FSL_ERRATUM_A005871
 #define CONFIG_SYS_FSL_ERRATUM_A006261
 #define CONFIG_SYS_FSL_ERRATUM_A006379
+#define CONFIG_SYS_FSL_ERRATUM_A007186
 #define CONFIG_SYS_FSL_ERRATUM_A006593
 #define CONFIG_SYS_CCSRBAR_DEFAULT     0xfe000000
+#define CONFIG_SYS_FSL_SFP_VER_3_0
 #define CONFIG_SYS_FSL_PCI_VER_3_X
 
 #elif defined(CONFIG_PPC_B4860) || defined(CONFIG_PPC_B4420)
 #define CONFIG_SYS_FSL_ERRATUM_A_004934
 #define CONFIG_SYS_FSL_ERRATUM_A005871
 #define CONFIG_SYS_FSL_ERRATUM_A006379
+#define CONFIG_SYS_FSL_ERRATUM_A007186
 #define CONFIG_SYS_FSL_ERRATUM_A006593
 #define CONFIG_SYS_FSL_ERRATUM_A007075
 #define CONFIG_SYS_FSL_ERRATUM_A006475
 #define CONFIG_SYS_FSL_ERRATUM_A006384
 #define CONFIG_SYS_FSL_ERRATUM_A007212
 #define CONFIG_SYS_CCSRBAR_DEFAULT     0xfe000000
+#define CONFIG_SYS_FSL_SFP_VER_3_0
 
 #ifdef CONFIG_PPC_B4860
 #define CONFIG_SYS_FSL_CORES_PER_CLUSTER 4
@@ -827,8 +831,10 @@ defined(CONFIG_PPC_T1020) || defined(CONFIG_PPC_T1022)
 #define CONFIG_SYS_FSL_ERRATUM_ESDHC111
 #define CONFIG_SYS_FSL_ERRATUM_A006261
 #define CONFIG_SYS_FSL_ERRATUM_A006593
+#define CONFIG_SYS_FSL_ERRATUM_A007186
 #define CONFIG_SYS_FSL_ERRATUM_A006379
 #define ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE
+#define CONFIG_SYS_FSL_SFP_VER_3_0
 
 
 #elif defined(CONFIG_PPC_C29X)
index eff573b5aded3c83b75dc83083aa46bc60897b98..fe1dcc27d6d078d9885a89408c0b9afcce7a3e20 100644 (file)
@@ -2521,14 +2521,17 @@ typedef struct serdes_corenet {
 #define SRDS_PLLCR0_RFCK_SEL_150       0x30000000
 #define SRDS_PLLCR0_RFCK_SEL_161_13    0x40000000
 #define SRDS_PLLCR0_RFCK_SEL_122_88    0x50000000
+#define SRDS_PLLCR0_PLL_LCK            0x00800000
 #define SRDS_PLLCR0_DCBIAS_OUT_EN      0x02000000
 #define SRDS_PLLCR0_FRATE_SEL_MASK     0x000f0000
 #define SRDS_PLLCR0_FRATE_SEL_5                0x00000000
+#define SRDS_PLLCR0_FRATE_SEL_4_9152   0x00030000
 #define SRDS_PLLCR0_FRATE_SEL_3_75     0x00050000
 #define SRDS_PLLCR0_FRATE_SEL_5_15     0x00060000
 #define SRDS_PLLCR0_FRATE_SEL_4                0x00070000
-#define SRDS_PLLCR0_FRATE_SEL_3_12     0x00090000
-#define SRDS_PLLCR0_FRATE_SEL_3                0x000a0000
+#define SRDS_PLLCR0_FRATE_SEL_3_125    0x00090000
+#define SRDS_PLLCR0_FRATE_SEL_3_0      0x000a0000
+#define SRDS_PLLCR0_FRATE_SEL_3_072    0x000c0000
 #define SRDS_PLLCR0_DCBIAS_OVRD                0x000000F0
 #define SRDS_PLLCR0_DCBIAS_OVRD_SHIFT  4
                u32     pllcr1; /* PLL Control Register 1 */
@@ -2863,6 +2866,21 @@ struct ccsr_pman {
        u8      res_f4[0xf0c];
 };
 #endif
+#ifdef CONFIG_SYS_FSL_SFP_VER_3_0
+struct ccsr_sfp_regs {
+       u32 ospr;               /* 0x200 */
+       u32 reserved0[14];
+       u32 srk_hash[8];        /* 0x23c Super Root Key Hash */
+       u32 oem_uid;            /* 0x9c OEM Unique ID */
+       u8 reserved2[0x04];
+       u32 ovpr;                       /* 0xA4  Intent To Secure */
+       u8 reserved4[0x08];
+       u32 fsl_uid;            /* 0xB0  FSL Unique ID */
+       u8 reserved5[0x04];
+       u32 fsl_spfr0;          /* Scratch Pad Fuse Register 0 */
+       u32 fsl_spfr1;          /* Scratch Pad Fuse Register 1 */
+};
+#endif
 
 #ifdef CONFIG_FSL_CORENET
 #define CONFIG_SYS_FSL_CORENET_CCM_OFFSET      0x0000
@@ -2876,6 +2894,14 @@ struct ccsr_pman {
 #define CONFIG_SYS_MPC8xxx_DDR3_OFFSET         0xA000
 #define CONFIG_SYS_FSL_CORENET_CLK_OFFSET      0xE1000
 #define CONFIG_SYS_FSL_CORENET_RCPM_OFFSET     0xE2000
+#ifdef CONFIG_SYS_FSL_SFP_VER_3_0
+/* In SFPv3, OSPR register is now at offset 0x200.
+ *  * So directly mapping sfp register map to this address */
+#define CONFIG_SYS_OSPR_OFFSET                  0x200
+#define CONFIG_SYS_SFP_OFFSET            (0xE8000 + CONFIG_SYS_OSPR_OFFSET)
+#else
+#define CONFIG_SYS_SFP_OFFSET                   0xE8000
+#endif
 #define CONFIG_SYS_FSL_CORENET_SERDES_OFFSET   0xEA000
 #define CONFIG_SYS_FSL_CORENET_SERDES2_OFFSET  0xEB000
 #define CONFIG_SYS_FSL_CPC_OFFSET              0x10000
@@ -3094,6 +3120,9 @@ struct ccsr_pman {
 #define CONFIG_SYS_PCIE4_ADDR \
        (CONFIG_SYS_IMMR + CONFIG_SYS_MPC85xx_PCIE4_OFFSET)
 
+#define CONFIG_SYS_SFP_ADDR  \
+       (CONFIG_SYS_IMMR + CONFIG_SYS_SFP_OFFSET)
+
 #define TSEC_BASE_ADDR         (CONFIG_SYS_IMMR + CONFIG_SYS_TSEC1_OFFSET)
 #define MDIO_BASE_ADDR         (CONFIG_SYS_IMMR + CONFIG_SYS_MDIO1_OFFSET)