mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-09-19 19:23:21 +09:00
b6808cd82d
SerDes PLL is calibrated at reset. When the junction temperature delta from the time the PLL is calibrated exceeds +56C/-66C, jitter may increase and can cause PLL to unlock. This workaround overwrite the SerDes registers with new values, to calibrate SerDes registers. These values are known to work fine for all temperature ranges. This workaround is valid for B4, T4 and T2 platforms, so added in their config. Signed-off-by: Shaveta Leekha <shaveta@freescale.com> Signed-off-by: Poonam Aggrwal <Poonam.Aggrwal@freescale.com> [York Sun: replaced typedef ccsr_sfp_regs_t with struct ccsr_sfp_regs] Reviewed-by: York Sun <yorksun@freescale.com>
375 lines
10 KiB
C
375 lines
10 KiB
C
/*
|
|
* Copyright 2012 Freescale Semiconductor, Inc.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <asm/fsl_serdes.h>
|
|
#include <asm/immap_85xx.h>
|
|
#include <asm/io.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/fsl_law.h>
|
|
#include <asm/errno.h>
|
|
#include "fsl_corenet2_serdes.h"
|
|
|
|
#ifdef CONFIG_SYS_FSL_SRDS_1
|
|
static u64 serdes1_prtcl_map;
|
|
#endif
|
|
#ifdef CONFIG_SYS_FSL_SRDS_2
|
|
static u64 serdes2_prtcl_map;
|
|
#endif
|
|
#ifdef CONFIG_SYS_FSL_SRDS_3
|
|
static u64 serdes3_prtcl_map;
|
|
#endif
|
|
#ifdef CONFIG_SYS_FSL_SRDS_4
|
|
static u64 serdes4_prtcl_map;
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
static const char *serdes_prtcl_str[] = {
|
|
[NONE] = "NA",
|
|
[PCIE1] = "PCIE1",
|
|
[PCIE2] = "PCIE2",
|
|
[PCIE3] = "PCIE3",
|
|
[PCIE4] = "PCIE4",
|
|
[SATA1] = "SATA1",
|
|
[SATA2] = "SATA2",
|
|
[SRIO1] = "SRIO1",
|
|
[SRIO2] = "SRIO2",
|
|
[SGMII_FM1_DTSEC1] = "SGMII_FM1_DTSEC1",
|
|
[SGMII_FM1_DTSEC2] = "SGMII_FM1_DTSEC2",
|
|
[SGMII_FM1_DTSEC3] = "SGMII_FM1_DTSEC3",
|
|
[SGMII_FM1_DTSEC4] = "SGMII_FM1_DTSEC4",
|
|
[SGMII_FM1_DTSEC5] = "SGMII_FM1_DTSEC5",
|
|
[SGMII_FM1_DTSEC6] = "SGMII_FM1_DTSEC6",
|
|
[SGMII_FM2_DTSEC1] = "SGMII_FM2_DTSEC1",
|
|
[SGMII_FM2_DTSEC2] = "SGMII_FM2_DTSEC2",
|
|
[SGMII_FM2_DTSEC3] = "SGMII_FM2_DTSEC3",
|
|
[SGMII_FM2_DTSEC4] = "SGMII_FM2_DTSEC4",
|
|
[XAUI_FM1] = "XAUI_FM1",
|
|
[XAUI_FM2] = "XAUI_FM2",
|
|
[AURORA] = "DEBUG",
|
|
[CPRI1] = "CPRI1",
|
|
[CPRI2] = "CPRI2",
|
|
[CPRI3] = "CPRI3",
|
|
[CPRI4] = "CPRI4",
|
|
[CPRI5] = "CPRI5",
|
|
[CPRI6] = "CPRI6",
|
|
[CPRI7] = "CPRI7",
|
|
[CPRI8] = "CPRI8",
|
|
[XAUI_FM1_MAC9] = "XAUI_FM1_MAC9",
|
|
[XAUI_FM1_MAC10] = "XAUI_FM1_MAC10",
|
|
[XAUI_FM2_MAC9] = "XAUI_FM2_MAC9",
|
|
[XAUI_FM2_MAC10] = "XAUI_FM2_MAC10",
|
|
[HIGIG_FM1_MAC9] = "HiGig_FM1_MAC9",
|
|
[HIGIG_FM1_MAC10] = "HiGig_FM1_MAC10",
|
|
[HIGIG_FM2_MAC9] = "HiGig_FM2_MAC9",
|
|
[HIGIG_FM2_MAC10] = "HiGig_FM2_MAC10",
|
|
[QSGMII_FM1_A] = "QSGMII_FM1_A",
|
|
[QSGMII_FM1_B] = "QSGMII_FM1_B",
|
|
[QSGMII_FM2_A] = "QSGMII_FM2_A",
|
|
[QSGMII_FM2_B] = "QSGMII_FM2_B",
|
|
[XFI_FM1_MAC9] = "XFI_FM1_MAC9",
|
|
[XFI_FM1_MAC10] = "XFI_FM1_MAC10",
|
|
[XFI_FM2_MAC9] = "XFI_FM2_MAC9",
|
|
[XFI_FM2_MAC10] = "XFI_FM2_MAC10",
|
|
[INTERLAKEN] = "INTERLAKEN",
|
|
[QSGMII_SW1_A] = "QSGMII_SW1_A",
|
|
[QSGMII_SW1_B] = "QSGMII_SW1_B",
|
|
};
|
|
#endif
|
|
|
|
int is_serdes_configured(enum srds_prtcl device)
|
|
{
|
|
u64 ret = 0;
|
|
|
|
#ifdef CONFIG_SYS_FSL_SRDS_1
|
|
ret |= (1ULL << device) & serdes1_prtcl_map;
|
|
#endif
|
|
#ifdef CONFIG_SYS_FSL_SRDS_2
|
|
ret |= (1ULL << device) & serdes2_prtcl_map;
|
|
#endif
|
|
#ifdef CONFIG_SYS_FSL_SRDS_3
|
|
ret |= (1ULL << device) & serdes3_prtcl_map;
|
|
#endif
|
|
#ifdef CONFIG_SYS_FSL_SRDS_4
|
|
ret |= (1ULL << device) & serdes4_prtcl_map;
|
|
#endif
|
|
|
|
return !!ret;
|
|
}
|
|
|
|
int serdes_get_first_lane(u32 sd, enum srds_prtcl device)
|
|
{
|
|
const ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
|
u32 cfg = in_be32(&gur->rcwsr[4]);
|
|
int i;
|
|
|
|
switch (sd) {
|
|
#ifdef CONFIG_SYS_FSL_SRDS_1
|
|
case FSL_SRDS_1:
|
|
cfg &= FSL_CORENET2_RCWSR4_SRDS1_PRTCL;
|
|
cfg >>= FSL_CORENET2_RCWSR4_SRDS1_PRTCL_SHIFT;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_SYS_FSL_SRDS_2
|
|
case FSL_SRDS_2:
|
|
cfg &= FSL_CORENET2_RCWSR4_SRDS2_PRTCL;
|
|
cfg >>= FSL_CORENET2_RCWSR4_SRDS2_PRTCL_SHIFT;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_SYS_FSL_SRDS_3
|
|
case FSL_SRDS_3:
|
|
cfg &= FSL_CORENET2_RCWSR4_SRDS3_PRTCL;
|
|
cfg >>= FSL_CORENET2_RCWSR4_SRDS3_PRTCL_SHIFT;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_SYS_FSL_SRDS_4
|
|
case FSL_SRDS_4:
|
|
cfg &= FSL_CORENET2_RCWSR4_SRDS4_PRTCL;
|
|
cfg >>= FSL_CORENET2_RCWSR4_SRDS4_PRTCL_SHIFT;
|
|
break;
|
|
#endif
|
|
default:
|
|
printf("invalid SerDes%d\n", sd);
|
|
break;
|
|
}
|
|
/* Is serdes enabled at all? */
|
|
if (unlikely(cfg == 0))
|
|
return -ENODEV;
|
|
|
|
for (i = 0; i < SRDS_MAX_LANES; i++) {
|
|
if (serdes_get_prtcl(sd, cfg, i) == device)
|
|
return i;
|
|
}
|
|
|
|
return -ENODEV;
|
|
}
|
|
|
|
#define BC3_SHIFT 9
|
|
#define DC3_SHIFT 6
|
|
#define FC3_SHIFT 0
|
|
#define BC2_SHIFT 19
|
|
#define DC2_SHIFT 16
|
|
#define FC2_SHIFT 10
|
|
#define BC1_SHIFT 29
|
|
#define DC1_SHIFT 26
|
|
#define FC1_SHIFT 20
|
|
#define BC_MASK 0x1
|
|
#define DC_MASK 0x7
|
|
#define FC_MASK 0x3F
|
|
|
|
#define FUSE_VAL_MASK 0x00000003
|
|
#define FUSE_VAL_SHIFT 30
|
|
#define CR0_DCBIAS_SHIFT 5
|
|
#define CR1_FCAP_SHIFT 15
|
|
#define CR1_BCAP_SHIFT 29
|
|
#define FCAP_MASK 0x001F8000
|
|
#define BCAP_MASK 0x20000000
|
|
#define BCAP_OVD_MASK 0x10000000
|
|
#define BYP_CAL_MASK 0x02000000
|
|
|
|
u64 serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift)
|
|
{
|
|
ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
|
u64 serdes_prtcl_map = 0;
|
|
u32 cfg;
|
|
int lane;
|
|
#ifdef CONFIG_SYS_FSL_ERRATUM_A007186
|
|
struct ccsr_sfp_regs __iomem *sfp_regs =
|
|
(struct ccsr_sfp_regs __iomem *)(CONFIG_SYS_SFP_ADDR);
|
|
u32 pll_num, pll_status, bc, dc, fc, pll_cr_upd, pll_cr0, pll_cr1;
|
|
u32 bc_status, fc_status, dc_status, pll_sr2;
|
|
serdes_corenet_t __iomem *srds_regs = (void *)sd_addr;
|
|
u32 sfp_spfr0, sel;
|
|
#endif
|
|
|
|
cfg = in_be32(&gur->rcwsr[4]) & sd_prctl_mask;
|
|
/* Is serdes enabled at all? */
|
|
if (!cfg) {
|
|
printf("SERDES%d is not enabled\n", sd + 1);
|
|
return 0;
|
|
}
|
|
|
|
/* Erratum A-007186
|
|
* Freescale Scratch Pad Fuse Register n (SFP_FSPFR0)
|
|
* The workaround requires factory pre-set SerDes calibration values to be
|
|
* read from a fuse block(Freescale Scratch Pad Fuse Register SFP_FSPFR0)
|
|
* These values have been shown to work across the
|
|
* entire temperature range for all SerDes. These values are then written into
|
|
* the SerDes registers to calibrate the SerDes PLL.
|
|
*
|
|
* This workaround for the protocols and rates that only have the Ring VCO.
|
|
*/
|
|
#ifdef CONFIG_SYS_FSL_ERRATUM_A007186
|
|
sfp_spfr0 = in_be32(&sfp_regs->fsl_spfr0);
|
|
debug("A007186: sfp_spfr0= %x\n", sfp_spfr0);
|
|
|
|
sel = (sfp_spfr0 >> FUSE_VAL_SHIFT) & FUSE_VAL_MASK;
|
|
|
|
if (sel == 0x01 || sel == 0x02) {
|
|
for (pll_num = 0; pll_num < SRDS_MAX_BANK; pll_num++) {
|
|
pll_status = in_be32(&srds_regs->bank[pll_num].pllcr0);
|
|
debug("A007186: pll_num=%x pllcr0=%x\n",
|
|
pll_num, pll_status);
|
|
/* STEP 1 */
|
|
/* Read factory pre-set SerDes calibration values
|
|
* from fuse block(SFP scratch register-sfp_spfr0)
|
|
*/
|
|
switch (pll_status & SRDS_PLLCR0_FRATE_SEL_MASK) {
|
|
case SRDS_PLLCR0_FRATE_SEL_3_0:
|
|
case SRDS_PLLCR0_FRATE_SEL_3_072:
|
|
debug("A007186: 3.0/3.072 protocol rate\n");
|
|
bc = (sfp_spfr0 >> BC1_SHIFT) & BC_MASK;
|
|
dc = (sfp_spfr0 >> DC1_SHIFT) & DC_MASK;
|
|
fc = (sfp_spfr0 >> FC1_SHIFT) & FC_MASK;
|
|
break;
|
|
case SRDS_PLLCR0_FRATE_SEL_3_125:
|
|
debug("A007186: 3.125 protocol rate\n");
|
|
bc = (sfp_spfr0 >> BC2_SHIFT) & BC_MASK;
|
|
dc = (sfp_spfr0 >> DC2_SHIFT) & DC_MASK;
|
|
fc = (sfp_spfr0 >> FC2_SHIFT) & FC_MASK;
|
|
break;
|
|
case SRDS_PLLCR0_FRATE_SEL_3_75:
|
|
debug("A007186: 3.75 protocol rate\n");
|
|
bc = (sfp_spfr0 >> BC1_SHIFT) & BC_MASK;
|
|
dc = (sfp_spfr0 >> DC1_SHIFT) & DC_MASK;
|
|
fc = (sfp_spfr0 >> FC1_SHIFT) & FC_MASK;
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
/* STEP 2 */
|
|
/* Write SRDSxPLLnCR1[11:16] = FC
|
|
* Write SRDSxPLLnCR1[2] = BC
|
|
*/
|
|
pll_cr1 = in_be32(&srds_regs->bank[pll_num].pllcr1);
|
|
pll_cr_upd = (((bc << CR1_BCAP_SHIFT) & BCAP_MASK) |
|
|
((fc << CR1_FCAP_SHIFT) & FCAP_MASK));
|
|
out_be32(&srds_regs->bank[pll_num].pllcr1,
|
|
(pll_cr_upd | pll_cr1));
|
|
debug("A007186: pll_num=%x Updated PLLCR1=%x\n",
|
|
pll_num, (pll_cr_upd | pll_cr1));
|
|
/* Write SRDSxPLLnCR0[24:26] = DC
|
|
*/
|
|
pll_cr0 = in_be32(&srds_regs->bank[pll_num].pllcr0);
|
|
out_be32(&srds_regs->bank[pll_num].pllcr0,
|
|
pll_cr0 | (dc << CR0_DCBIAS_SHIFT));
|
|
debug("A007186: pll_num=%x, Updated PLLCR0=%x\n",
|
|
pll_num, (pll_cr0 | (dc << CR0_DCBIAS_SHIFT)));
|
|
/* Write SRDSxPLLnCR1[3] = 1
|
|
* Write SRDSxPLLnCR1[6] = 1
|
|
*/
|
|
pll_cr1 = in_be32(&srds_regs->bank[pll_num].pllcr1);
|
|
pll_cr_upd = (BCAP_OVD_MASK | BYP_CAL_MASK);
|
|
out_be32(&srds_regs->bank[pll_num].pllcr1,
|
|
(pll_cr_upd | pll_cr1));
|
|
debug("A007186: pll_num=%x Updated PLLCR1=%x\n",
|
|
pll_num, (pll_cr_upd | pll_cr1));
|
|
|
|
/* STEP 3 */
|
|
/* Read the status Registers */
|
|
/* Verify SRDSxPLLnSR2[8] = BC */
|
|
pll_sr2 = in_be32(&srds_regs->bank[pll_num].pllsr2);
|
|
debug("A007186: pll_num=%x pllsr2=%x\n",
|
|
pll_num, pll_sr2);
|
|
bc_status = (pll_sr2 >> 23) & BC_MASK;
|
|
if (bc_status != bc)
|
|
debug("BC mismatch\n");
|
|
fc_status = (pll_sr2 >> 16) & FC_MASK;
|
|
if (fc_status != fc)
|
|
debug("FC mismatch\n");
|
|
pll_cr0 = in_be32(&srds_regs->bank[pll_num].pllcr0);
|
|
out_be32(&srds_regs->bank[pll_num].pllcr0, pll_cr0 |
|
|
0x02000000);
|
|
pll_sr2 = in_be32(&srds_regs->bank[pll_num].pllsr2);
|
|
dc_status = (pll_sr2 >> 17) & DC_MASK;
|
|
if (dc_status != dc)
|
|
debug("DC mismatch\n");
|
|
pll_cr0 = in_be32(&srds_regs->bank[pll_num].pllcr0);
|
|
out_be32(&srds_regs->bank[pll_num].pllcr0, pll_cr0 &
|
|
0xfdffffff);
|
|
|
|
/* STEP 4 */
|
|
/* Wait 750us to verify the PLL is locked
|
|
* by checking SRDSxPLLnCR0[8] = 1.
|
|
*/
|
|
udelay(750);
|
|
pll_status = in_be32(&srds_regs->bank[pll_num].pllcr0);
|
|
debug("A007186: pll_num=%x pllcr0=%x\n",
|
|
pll_num, pll_status);
|
|
|
|
if ((pll_status & SRDS_PLLCR0_PLL_LCK) == 0)
|
|
printf("A007186 Serdes PLL not locked\n");
|
|
else
|
|
debug("A007186 Serdes PLL locked\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
cfg >>= sd_prctl_shift;
|
|
printf("Using SERDES%d Protocol: %d (0x%x)\n", sd + 1, cfg, cfg);
|
|
if (!is_serdes_prtcl_valid(sd, cfg))
|
|
printf("SERDES%d[PRTCL] = 0x%x is not valid\n", sd + 1, cfg);
|
|
|
|
for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
|
|
enum srds_prtcl lane_prtcl = serdes_get_prtcl(sd, cfg, lane);
|
|
serdes_prtcl_map |= (1ULL << lane_prtcl);
|
|
}
|
|
|
|
return serdes_prtcl_map;
|
|
}
|
|
|
|
void fsl_serdes_init(void)
|
|
{
|
|
|
|
#ifdef CONFIG_SYS_FSL_SRDS_1
|
|
serdes1_prtcl_map = serdes_init(FSL_SRDS_1,
|
|
CONFIG_SYS_FSL_CORENET_SERDES_ADDR,
|
|
FSL_CORENET2_RCWSR4_SRDS1_PRTCL,
|
|
FSL_CORENET2_RCWSR4_SRDS1_PRTCL_SHIFT);
|
|
#endif
|
|
#ifdef CONFIG_SYS_FSL_SRDS_2
|
|
serdes2_prtcl_map = serdes_init(FSL_SRDS_2,
|
|
CONFIG_SYS_FSL_CORENET_SERDES_ADDR + FSL_SRDS_2 * 0x1000,
|
|
FSL_CORENET2_RCWSR4_SRDS2_PRTCL,
|
|
FSL_CORENET2_RCWSR4_SRDS2_PRTCL_SHIFT);
|
|
#endif
|
|
#ifdef CONFIG_SYS_FSL_SRDS_3
|
|
serdes3_prtcl_map = serdes_init(FSL_SRDS_3,
|
|
CONFIG_SYS_FSL_CORENET_SERDES_ADDR + FSL_SRDS_3 * 0x1000,
|
|
FSL_CORENET2_RCWSR4_SRDS3_PRTCL,
|
|
FSL_CORENET2_RCWSR4_SRDS3_PRTCL_SHIFT);
|
|
#endif
|
|
#ifdef CONFIG_SYS_FSL_SRDS_4
|
|
serdes4_prtcl_map = serdes_init(FSL_SRDS_4,
|
|
CONFIG_SYS_FSL_CORENET_SERDES_ADDR + FSL_SRDS_4 * 0x1000,
|
|
FSL_CORENET2_RCWSR4_SRDS4_PRTCL,
|
|
FSL_CORENET2_RCWSR4_SRDS4_PRTCL_SHIFT);
|
|
#endif
|
|
|
|
}
|
|
|
|
const char *serdes_clock_to_string(u32 clock)
|
|
{
|
|
switch (clock) {
|
|
case SRDS_PLLCR0_RFCK_SEL_100:
|
|
return "100";
|
|
case SRDS_PLLCR0_RFCK_SEL_125:
|
|
return "125";
|
|
case SRDS_PLLCR0_RFCK_SEL_156_25:
|
|
return "156.25";
|
|
case SRDS_PLLCR0_RFCK_SEL_161_13:
|
|
return "161.1328123";
|
|
default:
|
|
#if defined(CONFIG_T4240QDS)
|
|
return "???";
|
|
#else
|
|
return "122.88";
|
|
#endif
|
|
}
|
|
}
|
|
|