diff options
-rw-r--r-- | arch/powerpc/cpu/mpc85xx/cmd_errata.c | 8 | ||||
-rw-r--r-- | arch/powerpc/include/asm/config_mpc85xx.h | 2 | ||||
-rw-r--r-- | arch/powerpc/include/asm/immap_85xx.h | 19 | ||||
-rw-r--r-- | 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"); |