summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimur Tabi <timur@freescale.com>2011-04-18 17:16:00 -0500
committerKumar Gala <galak@kernel.crashing.org>2011-04-28 22:09:23 -0500
commitd90fdba6ca0b08c77cced6e914609e3696dd5909 (patch)
tree6065ad540c9aeb234869d430e9b2d0ba7a4d9a1e
parentf68d3063491442ca5d871d3019a9d3f195873ed7 (diff)
powerpc/85xx: Implement work-around for P4080 erratum SERDES-A001
Bank powerdown through RCW[SRDS_LPD_Bn] for XAUI on FM2 and SGMII on FM1 are swapped. Erratum SERDES-A001 says that if bank two is kept disabled and after bank three is enabled, then the PLL for bank three won't lock properly. The work-around is to enable and then disable bank two after bank three is enabled. Signed-off-by: Timur Tabi <timur@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
-rw-r--r--arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c80
-rw-r--r--arch/powerpc/include/asm/config_mpc85xx.h1
2 files changed, 65 insertions, 16 deletions
diff --git a/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c b/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c
index b44a81edea8..741a0f84aac 100644
--- a/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c
+++ b/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c
@@ -432,6 +432,28 @@ static void p4080_erratum_serdes_a005(serdes_corenet_t *regs, unsigned int cfg)
}
#endif
+/*
+ * Wait for the RSTDONE bit to get set, or a one-second timeout.
+ */
+static void wait_for_rstdone(unsigned int bank)
+{
+ serdes_corenet_t *srds_regs =
+ (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR;
+ unsigned long long end_tick;
+ u32 rstctl;
+
+ /* wait for reset complete or 1-second timeout */
+ end_tick = usec2ticks(1000000) + get_ticks();
+ do {
+ rstctl = in_be32(&srds_regs->bank[bank].rstctl);
+ if (rstctl & SRDS_RSTCTL_RSTDONE)
+ break;
+ } while (end_tick > get_ticks());
+
+ if (!(rstctl & SRDS_RSTCTL_RSTDONE))
+ printf("SERDES: timeout resetting bank %u\n", bank);
+}
+
void fsl_serdes_init(void)
{
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
@@ -439,7 +461,6 @@ void fsl_serdes_init(void)
serdes_corenet_t *srds_regs;
int lane, bank, idx;
enum srds_prtcl lane_prtcl;
- long long end_tick;
int have_bank[SRDS_MAX_BANK] = {};
#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
u32 serdes8_devdisr = 0;
@@ -451,6 +472,9 @@ void fsl_serdes_init(void)
#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES9
enum srds_prtcl device;
#endif
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES_A001
+ int need_serdes_a001; /* TRUE == need work-around for SERDES A001 */
+#endif
char buffer[HWCONFIG_BUFFER_SIZE];
char *buf = NULL;
@@ -519,11 +543,32 @@ void fsl_serdes_init(void)
have_bank[FSL_SRDS_BANK_3] = 1;
#endif
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES_A001
+ /*
+ * The work-aroud for erratum SERDES-A001 is needed only if bank two
+ * is disabled and bank three is enabled.
+ */
+ need_serdes_a001 =
+ !have_bank[FSL_SRDS_BANK_2] && have_bank[FSL_SRDS_BANK_3];
+#endif
+
+ /* Power down the banks we're not interested in */
for (bank = 0; bank < SRDS_MAX_BANK; bank++) {
if (!have_bank[bank]) {
printf("SERDES: bank %d disabled\n", bank + 1);
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES_A001
+ /*
+ * Erratum SERDES-A001 says bank two needs to be powered
+ * down after bank three is powered up, so don't power
+ * down bank two here.
+ */
+ if (!need_serdes_a001 || (bank != FSL_SRDS_BANK_2))
+ setbits_be32(&srds_regs->bank[bank].rstctl,
+ SRDS_RSTCTL_SDPD);
+#else
setbits_be32(&srds_regs->bank[bank].rstctl,
SRDS_RSTCTL_SDPD);
+#endif
}
}
@@ -649,8 +694,6 @@ void fsl_serdes_init(void)
#endif
for (idx = 0; idx < SRDS_MAX_BANK; idx++) {
- u32 rstctl;
-
bank = idx;
#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
@@ -689,20 +732,25 @@ void fsl_serdes_init(void)
/* reset banks for errata */
setbits_be32(&srds_regs->bank[bank].rstctl, SRDS_RSTCTL_RST);
- /* wait for reset complete or 1-second timeout */
- end_tick = usec2ticks(1000000) + get_ticks();
- do {
- rstctl = in_be32(&srds_regs->bank[bank].rstctl);
- if (rstctl & SRDS_RSTCTL_RSTDONE)
- break;
- } while (end_tick > get_ticks());
-
- if (!(rstctl & SRDS_RSTCTL_RSTDONE)) {
- printf("SERDES: timeout resetting bank %d\n",
- bank + 1);
- continue;
- }
+ wait_for_rstdone(bank);
+ }
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES_A001
+ if (need_serdes_a001) {
+ /*
+ * Bank three has been enabled, so enable bank two and then
+ * disable it.
+ */
+ srds_lpd_b[FSL_SRDS_BANK_2] = 0;
+ enable_bank(gur, FSL_SRDS_BANK_2);
+
+ wait_for_rstdone(FSL_SRDS_BANK_2);
+
+ /* Disable bank 2 */
+ setbits_be32(&srds_regs->bank[FSL_SRDS_BANK_2].rstctl,
+ SRDS_RSTCTL_SDPD);
}
+#endif
#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES9
for (device = XAUI_FM1; device <= XAUI_FM2; device++) {
diff --git a/arch/powerpc/include/asm/config_mpc85xx.h b/arch/powerpc/include/asm/config_mpc85xx.h
index b8b8914c442..ccf703b2430 100644
--- a/arch/powerpc/include/asm/config_mpc85xx.h
+++ b/arch/powerpc/include/asm/config_mpc85xx.h
@@ -311,6 +311,7 @@
#define CONFIG_SYS_P4080_ERRATUM_CPU22
#define CONFIG_SYS_P4080_ERRATUM_SERDES8
#define CONFIG_SYS_P4080_ERRATUM_SERDES9
+#define CONFIG_SYS_P4080_ERRATUM_SERDES_A001
#define CONFIG_SYS_P4080_ERRATUM_SERDES_A005
/* P5010 is single core version of P5020 */