|
@@ -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))
|