X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=arch%2Fpowerpc%2Fcpu%2Fmpc85xx%2Ffsl_corenet2_serdes.c;h=8edf5bb20ef79dc834c5ec5467f03f9cce21c155;hb=7cad2e38d61e27ea59fb7944f7e647e97ef292d3;hp=39d9409d64bab1442908e3ec8de64fb054aa3b52;hpb=a4c955bc3b23a38dc2c5c60b655a4d01eff93cec;p=u-boot diff --git a/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c b/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c index 39d9409d64..8edf5bb20e 100644 --- a/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c @@ -75,6 +75,8 @@ static const char *serdes_prtcl_str[] = { [XFI_FM2_MAC9] = "XFI_FM2_MAC9", [XFI_FM2_MAC10] = "XFI_FM2_MAC10", [INTERLAKEN] = "INTERLAKEN", + [QSGMII_SW1_A] = "QSGMII_SW1_A", + [QSGMII_SW1_B] = "QSGMII_SW1_B", }; #endif @@ -145,19 +147,162 @@ 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? */ - if (!cfg) { - printf("SERDES%d is not enabled\n", sd + 1); - 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); @@ -201,3 +346,24 @@ void fsl_serdes_init(void) #endif } + +const char *serdes_clock_to_string(u32 clock) +{ + switch (clock) { + case SRDS_PLLCR0_RFCK_SEL_100: + return "100"; + case SRDS_PLLCR0_RFCK_SEL_125: + return "125"; + case SRDS_PLLCR0_RFCK_SEL_156_25: + return "156.25"; + case SRDS_PLLCR0_RFCK_SEL_161_13: + return "161.1328123"; + default: +#if defined(CONFIG_T4240QDS) + return "???"; +#else + return "122.88"; +#endif + } +} +