[U-Boot] [PATCH 4/4] powerpc/85xx: Implement work-around for P4080 erratum SERDES-A001

Kumar Gala galak at kernel.crashing.org
Fri Apr 22 15:34:34 CEST 2011


From: Timur Tabi <timur at freescale.com>

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
disabled.

Signed-off-by: Timur Tabi <timur at freescale.com>
Signed-off-by: Kumar Gala <galak at kernel.crashing.org>
---
 arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c |   80 ++++++++++++++++++++-----
 arch/powerpc/include/asm/config_mpc85xx.h     |    1 +
 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 b44a81e..741a0f8 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 207f717..41c2d20 100644
--- a/arch/powerpc/include/asm/config_mpc85xx.h
+++ b/arch/powerpc/include/asm/config_mpc85xx.h
@@ -315,6 +315,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 */
-- 
1.7.3.4



More information about the U-Boot mailing list