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>
This commit is contained in:
Timur Tabi 2011-04-18 17:16:00 -05:00 committed by Kumar Gala
parent f68d306349
commit d90fdba6ca
2 changed files with 65 additions and 16 deletions

View file

@ -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;
@ -450,6 +471,9 @@ void fsl_serdes_init(void)
#endif
#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,21 +732,26 @@ 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++) {
if (is_serdes_configured(device))

View file

@ -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 */