summaryrefslogtreecommitdiff
path: root/arch/powerpc/cpu/mpc85xx
diff options
context:
space:
mode:
authorYork Sun <yorksun@freescale.com>2014-03-28 15:07:27 -0700
committerYork Sun <yorksun@freescale.com>2014-04-22 17:58:48 -0700
commitc3678b0937a0543280067fd8e08e6e2d278d90e2 (patch)
tree166623230c6ec5a618c800b4cbc52d56e101984b /arch/powerpc/cpu/mpc85xx
parent22cbf964345e502afa29087c343db309831ab111 (diff)
downloadu-boot-imx-c3678b0937a0543280067fd8e08e6e2d278d90e2.zip
u-boot-imx-c3678b0937a0543280067fd8e08e6e2d278d90e2.tar.gz
u-boot-imx-c3678b0937a0543280067fd8e08e6e2d278d90e2.tar.bz2
powerpc/mpc85xx: Add workaround for erratum A007212
Erratum A007212 for DDR is about a runaway condition for DDR PLL oscilliator. Please refer to erratum document for detail. For this workaround to work, DDR PLL needs to be disabled in RCW. However, u-boot needs to know the expected PLL ratio. We put the ratio in a reserved field RCW[18:23]. U-boot will skip this workaround if DDR PLL ratio is set, or the reserved field is not set. Workaround for erratum A007212 applies to selected versions of B4/T4 SoCs. It is safe to apply the workaround to all versions. It is helpful for upgrading SoC without changing u-boot. In case DDR PLL is disabled by RCW (part of the erratum workaround), we need this u-boot workround to bring up DDR clock. Signed-off-by: York Sun <yorksun@freescale.com>
Diffstat (limited to 'arch/powerpc/cpu/mpc85xx')
-rw-r--r--arch/powerpc/cpu/mpc85xx/cmd_errata.c19
-rw-r--r--arch/powerpc/cpu/mpc85xx/cpu_init.c69
-rw-r--r--arch/powerpc/cpu/mpc85xx/speed.c7
3 files changed, 95 insertions, 0 deletions
diff --git a/arch/powerpc/cpu/mpc85xx/cmd_errata.c b/arch/powerpc/cpu/mpc85xx/cmd_errata.c
index ee063fd..9d8acd0 100644
--- a/arch/powerpc/cpu/mpc85xx/cmd_errata.c
+++ b/arch/powerpc/cpu/mpc85xx/cmd_errata.c
@@ -113,6 +113,21 @@ static void check_erratum_a4580(uint32_t svr)
}
#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A007212
+/*
+ * This workaround can be implemented in PBI, or by u-boot.
+ */
+static void check_erratum_a007212(void)
+{
+ u32 __iomem *plldgdcr = (void *)(CONFIG_SYS_DCSRBAR + 0x21c20);
+
+ if (in_be32(plldgdcr) & 0x1fe) {
+ /* check if PLL ratio is set by workaround */
+ puts("Work-around for Erratum A007212 enabled\n");
+ }
+}
+#endif
+
static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_CPU_A011
@@ -281,6 +296,10 @@ static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (has_erratum_a006261())
puts("Work-around for Erratum A006261 enabled\n");
#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A007212
+ check_erratum_a007212();
+#endif
+
return 0;
}
diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init.c b/arch/powerpc/cpu/mpc85xx/cpu_init.c
index 0a33e8d..941c20e 100644
--- a/arch/powerpc/cpu/mpc85xx/cpu_init.c
+++ b/arch/powerpc/cpu/mpc85xx/cpu_init.c
@@ -280,6 +280,71 @@ static void corenet_tb_init(void)
}
#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A007212
+void fsl_erratum_a007212_workaround(void)
+{
+ ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 ddr_pll_ratio;
+ u32 __iomem *plldgdcr1 = (void *)(CONFIG_SYS_DCSRBAR + 0x21c20);
+ u32 __iomem *plldadcr1 = (void *)(CONFIG_SYS_DCSRBAR + 0x21c28);
+ u32 __iomem *dpdovrcr4 = (void *)(CONFIG_SYS_DCSRBAR + 0x21e80);
+#if (CONFIG_NUM_DDR_CONTROLLERS >= 2)
+ u32 __iomem *plldgdcr2 = (void *)(CONFIG_SYS_DCSRBAR + 0x21c40);
+ u32 __iomem *plldadcr2 = (void *)(CONFIG_SYS_DCSRBAR + 0x21c48);
+#if (CONFIG_NUM_DDR_CONTROLLERS >= 3)
+ u32 __iomem *plldgdcr3 = (void *)(CONFIG_SYS_DCSRBAR + 0x21c60);
+ u32 __iomem *plldadcr3 = (void *)(CONFIG_SYS_DCSRBAR + 0x21c68);
+#endif
+#endif
+ /*
+ * Even this workaround applies to selected version of SoCs, it is
+ * safe to apply to all versions, with the limitation of odd ratios.
+ * If RCW has disabled DDR PLL, we have to apply this workaround,
+ * otherwise DDR will not work.
+ */
+ ddr_pll_ratio = (in_be32(&gur->rcwsr[0]) >>
+ FSL_CORENET_RCWSR0_MEM_PLL_RAT_SHIFT) &
+ FSL_CORENET_RCWSR0_MEM_PLL_RAT_MASK;
+ /* check if RCW sets ratio to 0, required by this workaround */
+ if (ddr_pll_ratio != 0)
+ return;
+ ddr_pll_ratio = (in_be32(&gur->rcwsr[0]) >>
+ FSL_CORENET_RCWSR0_MEM_PLL_RAT_RESV_SHIFT) &
+ FSL_CORENET_RCWSR0_MEM_PLL_RAT_MASK;
+ /* check if reserved bits have the desired ratio */
+ if (ddr_pll_ratio == 0) {
+ printf("Error: Unknown DDR PLL ratio!\n");
+ return;
+ }
+ ddr_pll_ratio >>= 1;
+
+ setbits_be32(plldadcr1, 0x02000001);
+#if (CONFIG_NUM_DDR_CONTROLLERS >= 2)
+ setbits_be32(plldadcr2, 0x02000001);
+#if (CONFIG_NUM_DDR_CONTROLLERS >= 3)
+ setbits_be32(plldadcr3, 0x02000001);
+#endif
+#endif
+ setbits_be32(dpdovrcr4, 0xe0000000);
+ out_be32(plldgdcr1, 0x08000001 | (ddr_pll_ratio << 1));
+#if (CONFIG_NUM_DDR_CONTROLLERS >= 2)
+ out_be32(plldgdcr2, 0x08000001 | (ddr_pll_ratio << 1));
+#if (CONFIG_NUM_DDR_CONTROLLERS >= 3)
+ out_be32(plldgdcr3, 0x08000001 | (ddr_pll_ratio << 1));
+#endif
+#endif
+ udelay(100);
+ clrbits_be32(plldadcr1, 0x02000001);
+#if (CONFIG_NUM_DDR_CONTROLLERS >= 2)
+ clrbits_be32(plldadcr2, 0x02000001);
+#if (CONFIG_NUM_DDR_CONTROLLERS >= 3)
+ clrbits_be32(plldadcr3, 0x02000001);
+#endif
+#endif
+ clrbits_be32(dpdovrcr4, 0xe0000000);
+}
+#endif
+
void cpu_init_f (void)
{
extern void m8560_cpm_reset (void);
@@ -349,6 +414,10 @@ void cpu_init_f (void)
in_be32(&gur->dcsrcr);
#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A007212
+ fsl_erratum_a007212_workaround();
+#endif
+
}
/* Implement a dummy function for those platforms w/o SERDES */
diff --git a/arch/powerpc/cpu/mpc85xx/speed.c b/arch/powerpc/cpu/mpc85xx/speed.c
index 488fd5e..35dfb0a 100644
--- a/arch/powerpc/cpu/mpc85xx/speed.c
+++ b/arch/powerpc/cpu/mpc85xx/speed.c
@@ -107,6 +107,13 @@ void get_sys_info(sys_info_t *sys_info)
mem_pll_rat = (in_be32(&gur->rcwsr[0]) >>
FSL_CORENET_RCWSR0_MEM_PLL_RAT_SHIFT)
& FSL_CORENET_RCWSR0_MEM_PLL_RAT_MASK;
+#ifdef CONFIG_SYS_FSL_ERRATUM_A007212
+ if (mem_pll_rat == 0) {
+ mem_pll_rat = (in_be32(&gur->rcwsr[0]) >>
+ FSL_CORENET_RCWSR0_MEM_PLL_RAT_RESV_SHIFT) &
+ FSL_CORENET_RCWSR0_MEM_PLL_RAT_MASK;
+ }
+#endif
/* T4240/T4160 Rev2.0 MEM_PLL_RAT uses a value which is half of
* T4240/T4160 Rev1.0. eg. It's 12 in Rev1.0, however, for Rev2.0
* it uses 6.