From d90fdba6ca0b08c77cced6e914609e3696dd5909 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Mon, 18 Apr 2011 17:16:00 -0500 Subject: 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 Signed-off-by: Kumar Gala --- 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 b8b8914..ccf703b 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 */ -- cgit v1.1