X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=arch%2Fpowerpc%2Fcpu%2Fmpc85xx%2Ffsl_corenet2_serdes.c;h=d1fc76a13ed25c99e7272b916288cd04fe1c1a41;hb=64f41212d880f3d00c6994d973aadeec5bda1b65;hp=01dcdf6bc1ae2f737e050e711c288c49b5b55513;hpb=d1001e3f0ce0059a55a870c42bac8aba2e4befec;p=u-boot diff --git a/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c b/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c index 01dcdf6bc1..d1fc76a13e 100644 --- a/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c @@ -1,23 +1,7 @@ /* * Copyright 2012 Freescale Semiconductor, Inc. * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * SPDX-License-Identifier: GPL-2.0+ */ #include @@ -29,8 +13,12 @@ #include #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 @@ -87,6 +75,8 @@ static const char *serdes_prtcl_str[] = { [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 @@ -94,8 +84,12 @@ 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 @@ -113,14 +107,18 @@ int serdes_get_first_lane(u32 sd, enum srds_prtcl device) 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; @@ -149,12 +147,43 @@ int serdes_get_first_lane(u32 sd, enum srds_prtcl device) 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? */ @@ -163,8 +192,125 @@ u64 serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift) 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: 0x%x\n", sd + 1, cfg); + 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); @@ -179,14 +325,18 @@ u64 serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift) 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, @@ -201,3 +351,24 @@ void fsl_serdes_init(void) #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 + } +} +