u-boot-brain/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c
Tom Rini 83d290c56f SPDX: Convert all of our single license tags to Linux Kernel style
When U-Boot started using SPDX tags we were among the early adopters and
there weren't a lot of other examples to borrow from.  So we picked the
area of the file that usually had a full license text and replaced it
with an appropriate SPDX-License-Identifier: entry.  Since then, the
Linux Kernel has adopted SPDX tags and they place it as the very first
line in a file (except where shebangs are used, then it's second line)
and with slightly different comment styles than us.

In part due to community overlap, in part due to better tag visibility
and in part for other minor reasons, switch over to that style.

This commit changes all instances where we have a single declared
license in the tag as both the before and after are identical in tag
contents.  There's also a few places where I found we did not have a tag
and have introduced one.

Signed-off-by: Tom Rini <trini@konsulko.com>
2018-05-07 09:34:12 -04:00

401 lines
11 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2012 Freescale Semiconductor, Inc.
*/
#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 <linux/errno.h>
#include <fsl_errata.h>
#include "fsl_corenet2_serdes.h"
#ifdef CONFIG_SYS_FSL_SRDS_1
static u8 serdes1_prtcl_map[SERDES_PRCTL_COUNT];
#endif
#ifdef CONFIG_SYS_FSL_SRDS_2
static u8 serdes2_prtcl_map[SERDES_PRCTL_COUNT];
#endif
#ifdef CONFIG_SYS_FSL_SRDS_3
static u8 serdes3_prtcl_map[SERDES_PRCTL_COUNT];
#endif
#ifdef CONFIG_SYS_FSL_SRDS_4
static u8 serdes4_prtcl_map[SERDES_PRCTL_COUNT];
#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",
[SGMII_SW1_MAC1] = "SGMII_SW1_MAC1",
[SGMII_SW1_MAC2] = "SGMII_SW1_MAC2",
[SGMII_SW1_MAC3] = "SGMII_SW1_MAC3",
[SGMII_SW1_MAC4] = "SGMII_SW1_MAC4",
[SGMII_SW1_MAC5] = "SGMII_SW1_MAC5",
[SGMII_SW1_MAC6] = "SGMII_SW1_MAC6",
};
#endif
int is_serdes_configured(enum srds_prtcl device)
{
int ret = 0;
#ifdef CONFIG_SYS_FSL_SRDS_1
if (!serdes1_prtcl_map[NONE])
fsl_serdes_init();
ret |= serdes1_prtcl_map[device];
#endif
#ifdef CONFIG_SYS_FSL_SRDS_2
if (!serdes2_prtcl_map[NONE])
fsl_serdes_init();
ret |= serdes2_prtcl_map[device];
#endif
#ifdef CONFIG_SYS_FSL_SRDS_3
if (!serdes3_prtcl_map[NONE])
fsl_serdes_init();
ret |= serdes3_prtcl_map[device];
#endif
#ifdef CONFIG_SYS_FSL_SRDS_4
if (!serdes4_prtcl_map[NONE])
fsl_serdes_init();
ret |= serdes4_prtcl_map[device];
#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
void serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift,
u8 serdes_prtcl_map[SERDES_PRCTL_COUNT])
{
ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
u32 cfg;
int lane;
if (serdes_prtcl_map[NONE])
return;
memset(serdes_prtcl_map, 0, sizeof(u8) * SERDES_PRCTL_COUNT);
#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;
/* 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 (has_erratum_a007186() && (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);
if (unlikely(lane_prtcl >= SERDES_PRCTL_COUNT))
debug("Unknown SerDes lane protocol %d\n", lane_prtcl);
else
serdes_prtcl_map[lane_prtcl] = 1;
}
/* Set the first element to indicate serdes has been initialized */
serdes_prtcl_map[NONE] = 1;
}
void fsl_serdes_init(void)
{
#ifdef CONFIG_SYS_FSL_SRDS_1
serdes_init(FSL_SRDS_1,
CONFIG_SYS_FSL_CORENET_SERDES_ADDR,
FSL_CORENET2_RCWSR4_SRDS1_PRTCL,
FSL_CORENET2_RCWSR4_SRDS1_PRTCL_SHIFT,
serdes1_prtcl_map);
#endif
#ifdef CONFIG_SYS_FSL_SRDS_2
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,
serdes2_prtcl_map);
#endif
#ifdef CONFIG_SYS_FSL_SRDS_3
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,
serdes3_prtcl_map);
#endif
#ifdef CONFIG_SYS_FSL_SRDS_4
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,
serdes4_prtcl_map);
#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_TARGET_T4240QDS) || defined(CONFIG_TARGET_T4160QDS)
return "???";
#else
return "122.88";
#endif
}
}