summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/cpu/mpc85xx/cmd_errata.c8
-rw-r--r--arch/powerpc/include/asm/config_mpc85xx.h2
-rw-r--r--arch/powerpc/include/asm/immap_85xx.h19
-rw-r--r--board/freescale/b4860qds/b4860qds.c193
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");