From 7af9a07403e80415d097b4175616c7a7686b7deb Mon Sep 17 00:00:00 2001 From: Shaveta Leekha Date: Wed, 26 Feb 2014 16:08:22 +0530 Subject: [PATCH] powerpc/b4860: Add workaround for errata A006384 and A006475 SerDes PLLs may not lock reliably at 5 G VCO configuration(A006384) and at cold temperatures(A006475), workaround recalibrate the PLLs with some SerDes configuration Both these errata are only applicable for b4 rev1. So, make workaround for these errata conditional, depending upon soc version. Signed-off-by: Shaveta Leekha Reviewed-by: York Sun --- arch/powerpc/cpu/mpc85xx/cmd_errata.c | 8 + arch/powerpc/include/asm/config_mpc85xx.h | 2 + arch/powerpc/include/asm/immap_85xx.h | 19 ++- board/freescale/b4860qds/b4860qds.c | 193 ++++++++++++++++++++++ 4 files changed, 220 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/cpu/mpc85xx/cmd_errata.c b/arch/powerpc/cpu/mpc85xx/cmd_errata.c index 7693899058..d0a1c518bb 100644 --- a/arch/powerpc/cpu/mpc85xx/cmd_errata.c +++ b/arch/powerpc/cpu/mpc85xx/cmd_errata.c @@ -229,6 +229,14 @@ static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (IS_SVR_REV(svr, 1, 0)) puts("Work-around for Erratum A005871 enabled\n"); #endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A006475 + if (SVR_MAJ(get_svr()) == 1) + puts("Work-around for Erratum A006475 enabled\n"); +#endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A006384 + if (SVR_MAJ(get_svr()) == 1) + puts("Work-around for Erratum A006384 enabled\n"); +#endif #ifdef CONFIG_SYS_FSL_ERRATUM_A004849 /* This work-around is implemented in PBI, so just check for it */ check_erratum_a4849(svr); diff --git a/arch/powerpc/include/asm/config_mpc85xx.h b/arch/powerpc/include/asm/config_mpc85xx.h index 0ec1417a47..2f47b3fbd0 100644 --- a/arch/powerpc/include/asm/config_mpc85xx.h +++ b/arch/powerpc/include/asm/config_mpc85xx.h @@ -662,6 +662,8 @@ #define CONFIG_SYS_FSL_ERRATUM_A005871 #define CONFIG_SYS_FSL_ERRATUM_A006379 #define CONFIG_SYS_FSL_ERRATUM_A006593 +#define CONFIG_SYS_FSL_ERRATUM_A006475 +#define CONFIG_SYS_FSL_ERRATUM_A006384 #define CONFIG_SYS_CCSRBAR_DEFAULT 0xfe000000 #ifdef CONFIG_PPC_B4860 diff --git a/arch/powerpc/include/asm/immap_85xx.h b/arch/powerpc/include/asm/immap_85xx.h index e0efc7eba7..edd7888c4c 100644 --- a/arch/powerpc/include/asm/immap_85xx.h +++ b/arch/powerpc/include/asm/immap_85xx.h @@ -2495,6 +2495,7 @@ typedef struct serdes_corenet { #define SRDS_RSTCTL_SDEN 0x00000020 #define SRDS_RSTCTL_SDRST_B 0x00000040 #define SRDS_RSTCTL_PLLRST_B 0x00000080 +#define SRDS_RSTCTL_RSTERR_SHIFT 29 u32 pllcr0; /* PLL Control Register 0 */ #define SRDS_PLLCR0_POFF 0x80000000 #define SRDS_PLLCR0_RFCK_SEL_MASK 0x70000000 @@ -2504,6 +2505,7 @@ 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_DCBIAS_OUT_EN 0x02000000 #define SRDS_PLLCR0_FRATE_SEL_MASK 0x000f0000 #define SRDS_PLLCR0_FRATE_SEL_5 0x00000000 #define SRDS_PLLCR0_FRATE_SEL_3_75 0x00050000 @@ -2511,9 +2513,22 @@ typedef struct serdes_corenet { #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_DCBIAS_OVRD 0x000000F0 +#define SRDS_PLLCR0_DCBIAS_OVRD_SHIFT 4 u32 pllcr1; /* PLL Control Register 1 */ -#define SRDS_PLLCR1_PLL_BWSEL 0x08000000 - u32 res_0c; /* 0x00c */ +#define SRDS_PLLCR1_BCAP_EN 0x20000000 +#define SRDS_PLLCR1_BCAP_OVD 0x10000000 +#define SRDS_PLLCR1_PLL_FCAP 0x001F8000 +#define SRDS_PLLCR1_PLL_FCAP_SHIFT 15 +#define SRDS_PLLCR1_PLL_BWSEL 0x08000000 +#define SRDS_PLLCR1_BYP_CAL 0x02000000 + u32 pllsr2; /* At 0x00c, PLL Status Register 2 */ +#define SRDS_PLLSR2_BCAP_EN 0x00800000 +#define SRDS_PLLSR2_BCAP_EN_SHIFT 23 +#define SRDS_PLLSR2_FCAP 0x003F0000 +#define SRDS_PLLSR2_FCAP_SHIFT 16 +#define SRDS_PLLSR2_DCBIAS 0x000F0000 +#define SRDS_PLLSR2_DCBIAS_SHIFT 16 u32 pllcr3; u32 pllcr4; u8 res_18[0x20-0x18]; diff --git a/board/freescale/b4860qds/b4860qds.c b/board/freescale/b4860qds/b4860qds.c index 24a709e257..d9c88a074f 100644 --- a/board/freescale/b4860qds/b4860qds.c +++ b/board/freescale/b4860qds/b4860qds.c @@ -288,6 +288,182 @@ int configure_vsc3316_3308(void) return 0; } +static int calibrate_pll(serdes_corenet_t *srds_regs, int pll_num) +{ + u32 rst_err; + + /* Steps For SerDes PLLs reset and reconfiguration + * or PLL power-up procedure + */ + debug("CALIBRATE PLL:%d\n", pll_num); + clrbits_be32(&srds_regs->bank[pll_num].rstctl, + SRDS_RSTCTL_SDRST_B); + udelay(10); + clrbits_be32(&srds_regs->bank[pll_num].rstctl, + (SRDS_RSTCTL_SDEN | SRDS_RSTCTL_PLLRST_B)); + udelay(10); + setbits_be32(&srds_regs->bank[pll_num].rstctl, + SRDS_RSTCTL_RST); + setbits_be32(&srds_regs->bank[pll_num].rstctl, + (SRDS_RSTCTL_SDEN | SRDS_RSTCTL_PLLRST_B + | SRDS_RSTCTL_SDRST_B)); + + udelay(20); + + /* Check whether PLL has been locked or not */ + rst_err = in_be32(&srds_regs->bank[pll_num].rstctl) & + SRDS_RSTCTL_RSTERR; + rst_err >>= SRDS_RSTCTL_RSTERR_SHIFT; + debug("RST_ERR value for PLL %d is: 0x%x:\n", pll_num, rst_err); + if (rst_err) + return rst_err; + + return rst_err; +} + +static int check_pll_locks(serdes_corenet_t *srds_regs, int pll_num) +{ + int ret = 0; + u32 fcap, dcbias, bcap, pllcr1, pllcr0; + + if (calibrate_pll(srds_regs, pll_num)) { + /* STEP 1 */ + /* Read fcap, dcbias and bcap value */ + clrbits_be32(&srds_regs->bank[pll_num].pllcr0, + SRDS_PLLCR0_DCBIAS_OUT_EN); + fcap = in_be32(&srds_regs->bank[pll_num].pllsr2) & + SRDS_PLLSR2_FCAP; + fcap >>= SRDS_PLLSR2_FCAP_SHIFT; + bcap = in_be32(&srds_regs->bank[pll_num].pllsr2) & + SRDS_PLLSR2_BCAP_EN; + bcap >>= SRDS_PLLSR2_BCAP_EN_SHIFT; + setbits_be32(&srds_regs->bank[pll_num].pllcr0, + SRDS_PLLCR0_DCBIAS_OUT_EN); + dcbias = in_be32(&srds_regs->bank[pll_num].pllsr2) & + SRDS_PLLSR2_DCBIAS; + dcbias >>= SRDS_PLLSR2_DCBIAS_SHIFT; + debug("values of bcap:%x, fcap:%x and dcbias:%x\n", + bcap, fcap, dcbias); + if (fcap == 0 && bcap == 1) { + /* Step 3 */ + clrbits_be32(&srds_regs->bank[pll_num].rstctl, + (SRDS_RSTCTL_SDEN | SRDS_RSTCTL_PLLRST_B + | SRDS_RSTCTL_SDRST_B)); + clrbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BCAP_EN); + setbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BCAP_OVD); + if (calibrate_pll(srds_regs, pll_num)) { + /*save the fcap, dcbias and bcap values*/ + clrbits_be32(&srds_regs->bank[pll_num].pllcr0, + SRDS_PLLCR0_DCBIAS_OUT_EN); + fcap = in_be32(&srds_regs->bank[pll_num].pllsr2) + & SRDS_PLLSR2_FCAP; + fcap >>= SRDS_PLLSR2_FCAP_SHIFT; + bcap = in_be32(&srds_regs->bank[pll_num].pllsr2) + & SRDS_PLLSR2_BCAP_EN; + bcap >>= SRDS_PLLSR2_BCAP_EN_SHIFT; + setbits_be32(&srds_regs->bank[pll_num].pllcr0, + SRDS_PLLCR0_DCBIAS_OUT_EN); + dcbias = in_be32 + (&srds_regs->bank[pll_num].pllsr2) & + SRDS_PLLSR2_DCBIAS; + dcbias >>= SRDS_PLLSR2_DCBIAS_SHIFT; + + /* Step 4*/ + clrbits_be32(&srds_regs->bank[pll_num].rstctl, + (SRDS_RSTCTL_SDEN | SRDS_RSTCTL_PLLRST_B + | SRDS_RSTCTL_SDRST_B)); + setbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BYP_CAL); + clrbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BCAP_EN); + setbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BCAP_OVD); + /* change the fcap and dcbias to the saved + * values from Step 3 */ + clrbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_PLL_FCAP); + pllcr1 = (in_be32 + (&srds_regs->bank[pll_num].pllcr1)| + (fcap << SRDS_PLLCR1_PLL_FCAP_SHIFT)); + out_be32(&srds_regs->bank[pll_num].pllcr1, + pllcr1); + clrbits_be32(&srds_regs->bank[pll_num].pllcr0, + SRDS_PLLCR0_DCBIAS_OVRD); + pllcr0 = (in_be32 + (&srds_regs->bank[pll_num].pllcr0)| + (dcbias << SRDS_PLLCR0_DCBIAS_OVRD_SHIFT)); + out_be32(&srds_regs->bank[pll_num].pllcr0, + pllcr0); + ret = calibrate_pll(srds_regs, pll_num); + if (ret) + return ret; + } else { + goto out; + } + } else { /* Step 5 */ + clrbits_be32(&srds_regs->bank[pll_num].rstctl, + (SRDS_RSTCTL_SDEN | SRDS_RSTCTL_PLLRST_B + | SRDS_RSTCTL_SDRST_B)); + udelay(10); + /* Change the fcap, dcbias, and bcap to the + * values from Step 1 */ + setbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BYP_CAL); + clrbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_PLL_FCAP); + pllcr1 = (in_be32(&srds_regs->bank[pll_num].pllcr1)| + (fcap << SRDS_PLLCR1_PLL_FCAP_SHIFT)); + out_be32(&srds_regs->bank[pll_num].pllcr1, + pllcr1); + clrbits_be32(&srds_regs->bank[pll_num].pllcr0, + SRDS_PLLCR0_DCBIAS_OVRD); + pllcr0 = (in_be32(&srds_regs->bank[pll_num].pllcr0)| + (dcbias << SRDS_PLLCR0_DCBIAS_OVRD_SHIFT)); + out_be32(&srds_regs->bank[pll_num].pllcr0, + pllcr0); + clrbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BCAP_EN); + setbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BCAP_OVD); + ret = calibrate_pll(srds_regs, pll_num); + if (ret) + return ret; + } + } +out: + return 0; +} + +static int check_serdes_pll_locks(void) +{ + serdes_corenet_t *srds1_regs = + (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR; + serdes_corenet_t *srds2_regs = + (void *)CONFIG_SYS_FSL_CORENET_SERDES2_ADDR; + int i, ret1, ret2; + + debug("\nSerDes1 Lock check\n"); + for (i = 0; i < CONFIG_SYS_FSL_SRDS_NUM_PLLS; i++) { + ret1 = check_pll_locks(srds1_regs, i); + if (ret1) { + printf("SerDes1, PLL:%d didnt lock\n", i); + return ret1; + } + } + debug("\nSerDes2 Lock check\n"); + for (i = 0; i < CONFIG_SYS_FSL_SRDS_NUM_PLLS; i++) { + ret2 = check_pll_locks(srds2_regs, i); + if (ret2) { + printf("SerDes2, PLL:%d didnt lock\n", i); + return ret2; + } + } + + return 0; +} + int config_serdes1_refclks(void) { ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); @@ -478,6 +654,8 @@ int config_serdes2_refclks(void) setbits_be32(&srds2_regs->bank[i].rstctl, (SRDS_RSTCTL_SDEN | SRDS_RSTCTL_PLLRST_B | SRDS_RSTCTL_SDRST_B)); + + udelay(10); } break; default: @@ -544,6 +722,21 @@ int board_early_init_r(void) else printf("SerDes2 Refclk reconfiguring failed.\n"); +#if defined(CONFIG_SYS_FSL_ERRATUM_A006384) || \ + defined(CONFIG_SYS_FSL_ERRATUM_A006475) + /* Rechecking the SerDes locks after all SerDes configurations + * are done, As SerDes PLLs may not lock reliably at 5 G VCO + * and at cold temperatures. + * Following sequence ensure the proper locking of SerDes PLLs. + */ + if (SVR_MAJ(get_svr()) == 1) { + if (check_serdes_pll_locks()) + printf("SerDes plls still not locked properly.\n"); + else + printf("SerDes plls have been locked well.\n"); + } +#endif + /* Configure VSC3316 and VSC3308 crossbar switches */ if (configure_vsc3316_3308()) printf("VSC:failed to configure VSC3316/3308.\n"); -- 2.39.2