From: Ioana Ciornei Add support for 25GBASE-R in the Lynx 28G SerDes PHY driver. 25GbE is sourced from a clock net frequency of 12.890625 GHz, as produced by PLLF or PLLS, further multiplied by the lane by 2. The change consists of: - determining at probe time if any PLL was preconfigured for the required clock net frequency for 25GbE - adding the default lane parameters for reconfiguring a lane to 25GbE irrespective of the original protocol - allowing this operating mode only on supported lanes, i.e. all lanes of LX2162A SerDes #1, and LX2160A SerDes lanes 0-1, 4-7. Signed-off-by: Ioana Ciornei Signed-off-by: Vladimir Oltean --- part 1 -> part 2: - rewrite commit message. Patch made its last appearance in v3 from part 1: https://lore.kernel.org/linux-phy/20250926180505.760089-15-vladimir.oltean@nxp.com/ (old) part 1 change log: v2->v3: none v1->v2: implement missing lane_supports_mode() restrictions for 25GbE drivers/phy/freescale/phy-fsl-lynx-28g.c | 90 +++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 9e154313c99b..7ada581bbe4c 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -57,6 +57,7 @@ #define PLLnCR1_FRATE_5G_10GVCO 0x0 #define PLLnCR1_FRATE_5G_25GVCO 0x10 #define PLLnCR1_FRATE_10G_20GVCO 0x6 +#define PLLnCR1_FRATE_12G_25GVCO 0x16 /* Per SerDes lane registers */ /* Lane a General Control Register */ @@ -64,9 +65,11 @@ #define LNaGCR0_PROTO_SEL GENMASK(7, 3) #define LNaGCR0_PROTO_SEL_SGMII 0x1 #define LNaGCR0_PROTO_SEL_XFI 0xa +#define LNaGCR0_PROTO_SEL_25G 0x1a #define LNaGCR0_IF_WIDTH GENMASK(2, 0) #define LNaGCR0_IF_WIDTH_10_BIT 0x0 #define LNaGCR0_IF_WIDTH_20_BIT 0x2 +#define LNaGCR0_IF_WIDTH_40_BIT 0x4 /* Lane a Tx Reset Control Register */ #define LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20) @@ -83,6 +86,7 @@ #define LNaTGCR0_N_RATE_FULL 0x0 #define LNaTGCR0_N_RATE_HALF 0x1 #define LNaTGCR0_N_RATE_QUARTER 0x2 +#define LNaTGCR0_N_RATE_DOUBLE 0x3 #define LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30) #define LNaTECR0_EQ_TYPE GENMASK(30, 28) @@ -112,6 +116,7 @@ #define LNaRGCR0_N_RATE_FULL 0x0 #define LNaRGCR0_N_RATE_HALF 0x1 #define LNaRGCR0_N_RATE_QUARTER 0x2 +#define LNaRGCR0_N_RATE_DOUBLE 0x3 #define LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48) #define LNaRGCR1_RX_ORD_ELECIDLE BIT(31) @@ -269,6 +274,7 @@ enum lynx_lane_mode { LANE_MODE_1000BASEX_SGMII, LANE_MODE_10GBASER, LANE_MODE_USXGMII, + LANE_MODE_25GBASER, LANE_MODE_MAX, }; @@ -407,6 +413,41 @@ static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = { .ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP | LNaTTLCR0_DATA_IN_SSC, }, + [LANE_MODE_25GBASER] = { + .proto_sel = LNaGCR0_PROTO_SEL_25G, + .if_width = LNaGCR0_IF_WIDTH_40_BIT, + .teq_type = EQ_TYPE_3TAP, + .sgn_preq = 1, + .ratio_preq = 2, + .sgn_post1q = 1, + .ratio_post1q = 7, + .amp_red = 0, + .adpt_eq = 48, + .enter_idle_flt_sel = 0, + .exit_idle_flt_sel = 0, + .data_lost_th_sel = 0, + .gk2ovd = 0, + .gk3ovd = 0, + .gk4ovd = 5, + .gk2ovd_en = 0, + .gk3ovd_en = 0, + .gk4ovd_en = 1, + .eq_offset_ovd = 0x1f, + .eq_offset_ovd_en = 0, + .eq_offset_rng_dbl = 1, + .eq_blw_sel = 1, + .eq_boost = 2, + .spare_in = 3, + .smp_autoz_d1r = 2, + .smp_autoz_eg1r = 2, + .rccr0 = LNaRCCR0_CAL_EN | + LNaRCCR0_CAL_DC3_DIS | + LNaRCCR0_CAL_DC2_DIS | + LNaRCCR0_CAL_DC1_DIS | + LNaRCCR0_CAL_DC0_DIS, + .ttlcr0 = LNaTTLCR0_DATA_IN_SSC | + FIELD_PREP_CONST(LNaTTLCR0_CDR_MIN_SMP_ON, 1), + }, }; struct lynx_pccr { @@ -486,6 +527,8 @@ static const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode) return "10GBase-R"; case LANE_MODE_USXGMII: return "USXGMII"; + case LANE_MODE_25GBASER: + return "25GBase-R"; default: return "unknown"; } @@ -501,6 +544,8 @@ static enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf) return LANE_MODE_10GBASER; case PHY_INTERFACE_MODE_USXGMII: return LANE_MODE_USXGMII; + case PHY_INTERFACE_MODE_25GBASER: + return LANE_MODE_25GBASER; default: return LANE_MODE_UNKNOWN; } @@ -588,6 +633,20 @@ static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane, break; } break; + case PLLnCR1_FRATE_12G_25GVCO: + switch (lane_mode) { + case LANE_MODE_25GBASER: + lynx_28g_lane_rmw(lane, LNaTGCR0, + FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_DOUBLE), + LNaTGCR0_N_RATE); + lynx_28g_lane_rmw(lane, LNaRGCR0, + FIELD_PREP(LNaRGCR0_N_RATE, LNaRGCR0_N_RATE_DOUBLE), + LNaRGCR0_N_RATE); + break; + default: + break; + } + break; default: break; } @@ -665,6 +724,11 @@ static int lynx_28g_power_on(struct phy *phy) return 0; } +static int lynx_28g_e25g_pcvt(int lane) +{ + return 7 - lane; +} + static int lynx_28g_get_pccr(enum lynx_lane_mode lane_mode, int lane, struct lynx_pccr *pccr) { @@ -680,6 +744,11 @@ static int lynx_28g_get_pccr(enum lynx_lane_mode lane_mode, int lane, pccr->width = 4; pccr->shift = SXGMII_CFG(lane); break; + case LANE_MODE_25GBASER: + pccr->offset = PCCD; + pccr->width = 4; + pccr->shift = E25G_CFG(lynx_28g_e25g_pcvt(lane)); + break; default: return -EOPNOTSUPP; } @@ -695,6 +764,8 @@ static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode) case LANE_MODE_USXGMII: case LANE_MODE_10GBASER: return SXGMIIaCR0(lane); + case LANE_MODE_25GBASER: + return E25GaCR0(lynx_28g_e25g_pcvt(lane)); default: return -EOPNOTSUPP; } @@ -703,7 +774,12 @@ static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode) static bool lx2160a_serdes1_lane_supports_mode(int lane, enum lynx_lane_mode mode) { - return true; + switch (mode) { + case LANE_MODE_25GBASER: + return lane != 2 && lane != 3; + default: + return true; + } } static bool lx2160a_serdes2_lane_supports_mode(int lane, @@ -1019,6 +1095,9 @@ static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane, case LANE_MODE_USXGMII: val |= PCCC_SXGMIIn_CFG; break; + case LANE_MODE_25GBASER: + val |= PCCD_E25Gn_CFG; + break; default: break; } @@ -1143,8 +1222,12 @@ static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv) __set_bit(LANE_MODE_10GBASER, pll->supported); __set_bit(LANE_MODE_USXGMII, pll->supported); break; + case PLLnCR1_FRATE_12G_25GVCO: + /* 12.890625GHz clock net */ + __set_bit(LANE_MODE_25GBASER, pll->supported); + break; default: - /* 6GHz, 12.890625GHz, 8GHz */ + /* 6GHz, 8GHz */ break; } } @@ -1203,6 +1286,9 @@ static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane) else lane->mode = LANE_MODE_USXGMII; break; + case LNaPSS_TYPE_25G: + lane->mode = LANE_MODE_25GBASER; + break; default: lane->mode = LANE_MODE_UNKNOWN; } -- 2.34.1