1*6dc92ba4SVladimir Oltean // SPDX-License-Identifier: GPL-2.0+ 2*6dc92ba4SVladimir Oltean /* Copyright 2021-2026 NXP */ 3*6dc92ba4SVladimir Oltean 4*6dc92ba4SVladimir Oltean #include <linux/delay.h> 5*6dc92ba4SVladimir Oltean #include <linux/module.h> 6*6dc92ba4SVladimir Oltean #include <linux/of.h> 7*6dc92ba4SVladimir Oltean #include <linux/phy.h> 8*6dc92ba4SVladimir Oltean #include <linux/phy/phy.h> 9*6dc92ba4SVladimir Oltean #include <linux/platform_device.h> 10*6dc92ba4SVladimir Oltean #include <linux/workqueue.h> 11*6dc92ba4SVladimir Oltean 12*6dc92ba4SVladimir Oltean #include "phy-fsl-lynx-core.h" 13*6dc92ba4SVladimir Oltean 14*6dc92ba4SVladimir Oltean /* SoC IP wrapper for protocol converters */ 15*6dc92ba4SVladimir Oltean #define PCCR8 0x220 16*6dc92ba4SVladimir Oltean #define PCCR8_SGMIIa_KX BIT(3) 17*6dc92ba4SVladimir Oltean #define PCCR8_SGMIIa_CFG GENMASK(2, 0) 18*6dc92ba4SVladimir Oltean 19*6dc92ba4SVladimir Oltean #define PCCR9 0x224 20*6dc92ba4SVladimir Oltean #define PCCR9_QSGMIIa_CFG GENMASK(2, 0) 21*6dc92ba4SVladimir Oltean #define PCCR9_QXGMIIa_CFG GENMASK(2, 0) 22*6dc92ba4SVladimir Oltean 23*6dc92ba4SVladimir Oltean #define PCCRB 0x22c 24*6dc92ba4SVladimir Oltean #define PCCRB_XFIa_CFG GENMASK(2, 0) 25*6dc92ba4SVladimir Oltean #define PCCRB_SXGMIIa_CFG GENMASK(2, 0) 26*6dc92ba4SVladimir Oltean 27*6dc92ba4SVladimir Oltean #define SGMII_CFG(id) (28 - (id) * 4) 28*6dc92ba4SVladimir Oltean #define QSGMII_CFG(id) (28 - (id) * 4) 29*6dc92ba4SVladimir Oltean #define SXGMII_CFG(id) (28 - (id) * 4) 30*6dc92ba4SVladimir Oltean #define QXGMII_CFG(id) (12 - (id) * 4) 31*6dc92ba4SVladimir Oltean #define XFI_CFG(id) (28 - (id) * 4) 32*6dc92ba4SVladimir Oltean 33*6dc92ba4SVladimir Oltean #define CR(x) ((x) * 4) 34*6dc92ba4SVladimir Oltean 35*6dc92ba4SVladimir Oltean #define A 0 36*6dc92ba4SVladimir Oltean #define B 1 37*6dc92ba4SVladimir Oltean #define C 2 38*6dc92ba4SVladimir Oltean #define D 3 39*6dc92ba4SVladimir Oltean #define E 4 40*6dc92ba4SVladimir Oltean #define F 5 41*6dc92ba4SVladimir Oltean #define G 6 42*6dc92ba4SVladimir Oltean #define H 7 43*6dc92ba4SVladimir Oltean 44*6dc92ba4SVladimir Oltean #define SGMIIaCR0(id) (0x1800 + (id) * 0x10) 45*6dc92ba4SVladimir Oltean #define QSGMIIaCR0(id) (0x1880 + (id) * 0x10) 46*6dc92ba4SVladimir Oltean #define XAUIaCR0(id) (0x1900 + (id) * 0x10) 47*6dc92ba4SVladimir Oltean #define XFIaCR0(id) (0x1980 + (id) * 0x10) 48*6dc92ba4SVladimir Oltean #define SXGMIIaCR0(id) (0x1a80 + (id) * 0x10) 49*6dc92ba4SVladimir Oltean #define QXGMIIaCR0(id) (0x1b00 + (id) * 0x20) 50*6dc92ba4SVladimir Oltean 51*6dc92ba4SVladimir Oltean #define SGMIIaCR0_RST_SGM BIT(31) 52*6dc92ba4SVladimir Oltean #define SGMIIaCR0_RST_SGM_OFF SGMIIaCR0_RST_SGM 53*6dc92ba4SVladimir Oltean #define SGMIIaCR0_RST_SGM_ON 0 54*6dc92ba4SVladimir Oltean #define SGMIIaCR0_PD_SGM BIT(30) 55*6dc92ba4SVladimir Oltean #define SGMIIaCR1_SGPCS_EN BIT(11) 56*6dc92ba4SVladimir Oltean #define SGMIIaCR1_SGPCS_DIS 0x0 57*6dc92ba4SVladimir Oltean 58*6dc92ba4SVladimir Oltean #define QSGMIIaCR0_RST_QSGM BIT(31) 59*6dc92ba4SVladimir Oltean #define QSGMIIaCR0_RST_QSGM_OFF QSGMIIaCR0_RST_QSGM 60*6dc92ba4SVladimir Oltean #define QSGMIIaCR0_RST_QSGM_ON 0 61*6dc92ba4SVladimir Oltean #define QSGMIIaCR0_PD_QSGM BIT(30) 62*6dc92ba4SVladimir Oltean 63*6dc92ba4SVladimir Oltean /* Per PLL registers */ 64*6dc92ba4SVladimir Oltean #define PLLnCR0(pll) ((pll) * 0x20 + 0x4) 65*6dc92ba4SVladimir Oltean 66*6dc92ba4SVladimir Oltean #define PLLnCR0_POFF BIT(31) 67*6dc92ba4SVladimir Oltean 68*6dc92ba4SVladimir Oltean #define PLLnCR0_REFCLK_SEL GENMASK(30, 28) 69*6dc92ba4SVladimir Oltean #define PLLnCR0_REFCLK_SEL_100MHZ 0x0 70*6dc92ba4SVladimir Oltean #define PLLnCR0_REFCLK_SEL_125MHZ 0x1 71*6dc92ba4SVladimir Oltean #define PLLnCR0_REFCLK_SEL_156MHZ 0x2 72*6dc92ba4SVladimir Oltean #define PLLnCR0_REFCLK_SEL_150MHZ 0x3 73*6dc92ba4SVladimir Oltean #define PLLnCR0_REFCLK_SEL_161MHZ 0x4 74*6dc92ba4SVladimir Oltean #define PLLnCR0_PLL_LCK BIT(23) 75*6dc92ba4SVladimir Oltean #define PLLnCR0_FRATE_SEL GENMASK(19, 16) 76*6dc92ba4SVladimir Oltean #define PLLnCR0_FRATE_5G 0x0 77*6dc92ba4SVladimir Oltean #define PLLnCR0_FRATE_5_15625G 0x6 78*6dc92ba4SVladimir Oltean #define PLLnCR0_FRATE_4G 0x7 79*6dc92ba4SVladimir Oltean #define PLLnCR0_FRATE_3_125G 0x9 80*6dc92ba4SVladimir Oltean #define PLLnCR0_FRATE_3G 0xa 81*6dc92ba4SVladimir Oltean 82*6dc92ba4SVladimir Oltean /* Per SerDes lane registers */ 83*6dc92ba4SVladimir Oltean 84*6dc92ba4SVladimir Oltean /* Lane a Protocol Select status register */ 85*6dc92ba4SVladimir Oltean #define LNaPSSR0(lane) (0x100 + (lane) * 0x20) 86*6dc92ba4SVladimir Oltean #define LNaPSSR0_TYPE GENMASK(30, 26) 87*6dc92ba4SVladimir Oltean #define LNaPSSR0_IS_QUAD GENMASK(25, 24) 88*6dc92ba4SVladimir Oltean #define LNaPSSR0_MAC GENMASK(19, 16) 89*6dc92ba4SVladimir Oltean #define LNaPSSR0_PCS GENMASK(10, 8) 90*6dc92ba4SVladimir Oltean #define LNaPSSR0_LANE GENMASK(2, 0) 91*6dc92ba4SVladimir Oltean 92*6dc92ba4SVladimir Oltean /* Lane a General Control Register */ 93*6dc92ba4SVladimir Oltean #define LNaGCR0(lane) (0x800 + (lane) * 0x40 + 0x0) 94*6dc92ba4SVladimir Oltean #define LNaGCR0_RPLL_PLLF BIT(31) 95*6dc92ba4SVladimir Oltean #define LNaGCR0_RPLL_PLLS 0x0 96*6dc92ba4SVladimir Oltean #define LNaGCR0_RPLL_MSK BIT(31) 97*6dc92ba4SVladimir Oltean #define LNaGCR0_RRAT_SEL GENMASK(29, 28) 98*6dc92ba4SVladimir Oltean #define LNaGCR0_TRAT_SEL GENMASK(25, 24) 99*6dc92ba4SVladimir Oltean #define LNaGCR0_TPLL_PLLF BIT(27) 100*6dc92ba4SVladimir Oltean #define LNaGCR0_TPLL_PLLS 0x0 101*6dc92ba4SVladimir Oltean #define LNaGCR0_TPLL_MSK BIT(27) 102*6dc92ba4SVladimir Oltean #define LNaGCR0_RRST_OFF LNaGCR0_RRST 103*6dc92ba4SVladimir Oltean #define LNaGCR0_TRST_OFF LNaGCR0_TRST 104*6dc92ba4SVladimir Oltean #define LNaGCR0_RRST_ON 0x0 105*6dc92ba4SVladimir Oltean #define LNaGCR0_TRST_ON 0x0 106*6dc92ba4SVladimir Oltean #define LNaGCR0_RRST BIT(22) 107*6dc92ba4SVladimir Oltean #define LNaGCR0_TRST BIT(21) 108*6dc92ba4SVladimir Oltean #define LNaGCR0_RX_PD BIT(20) 109*6dc92ba4SVladimir Oltean #define LNaGCR0_TX_PD BIT(19) 110*6dc92ba4SVladimir Oltean #define LNaGCR0_IF20BIT_EN BIT(18) 111*6dc92ba4SVladimir Oltean #define LNaGCR0_PROTS GENMASK(11, 7) 112*6dc92ba4SVladimir Oltean 113*6dc92ba4SVladimir Oltean #define LNaGCR1(lane) (0x800 + (lane) * 0x40 + 0x4) 114*6dc92ba4SVladimir Oltean #define LNaGCR1_RDAT_INV BIT(31) 115*6dc92ba4SVladimir Oltean #define LNaGCR1_TDAT_INV BIT(30) 116*6dc92ba4SVladimir Oltean #define LNaGCR1_OPAD_CTL BIT(26) 117*6dc92ba4SVladimir Oltean #define LNaGCR1_REIDL_TH GENMASK(22, 20) 118*6dc92ba4SVladimir Oltean #define LNaGCR1_REIDL_EX_SEL GENMASK(19, 18) 119*6dc92ba4SVladimir Oltean #define LNaGCR1_REIDL_ET_SEL GENMASK(17, 16) 120*6dc92ba4SVladimir Oltean #define LNaGCR1_REIDL_EX_MSB BIT(15) 121*6dc92ba4SVladimir Oltean #define LNaGCR1_REIDL_ET_MSB BIT(14) 122*6dc92ba4SVladimir Oltean #define LNaGCR1_REQ_CTL_SNP BIT(13) 123*6dc92ba4SVladimir Oltean #define LNaGCR1_REQ_CDR_SNP BIT(12) 124*6dc92ba4SVladimir Oltean #define LNaGCR1_TRSTDIR BIT(7) 125*6dc92ba4SVladimir Oltean #define LNaGCR1_REQ_BIN_SNP BIT(6) 126*6dc92ba4SVladimir Oltean #define LNaGCR1_ISLEW_RCTL GENMASK(5, 4) 127*6dc92ba4SVladimir Oltean #define LNaGCR1_OSLEW_RCTL GENMASK(1, 0) 128*6dc92ba4SVladimir Oltean 129*6dc92ba4SVladimir Oltean #define LNaRECR0(lane) (0x800 + (lane) * 0x40 + 0x10) 130*6dc92ba4SVladimir Oltean #define LNaRECR0_RXEQ_BST BIT(28) 131*6dc92ba4SVladimir Oltean #define LNaRECR0_GK2OVD GENMASK(27, 24) 132*6dc92ba4SVladimir Oltean #define LNaRECR0_GK3OVD GENMASK(19, 16) 133*6dc92ba4SVladimir Oltean #define LNaRECR0_GK2OVD_EN BIT(15) 134*6dc92ba4SVladimir Oltean #define LNaRECR0_GK3OVD_EN BIT(14) 135*6dc92ba4SVladimir Oltean #define LNaRECR0_OSETOVD_EN BIT(13) 136*6dc92ba4SVladimir Oltean #define LNaRECR0_BASE_WAND GENMASK(11, 10) 137*6dc92ba4SVladimir Oltean #define LNaRECR0_OSETOVD GENMASK(6, 0) 138*6dc92ba4SVladimir Oltean 139*6dc92ba4SVladimir Oltean #define LNaTECR0(lane) (0x800 + (lane) * 0x40 + 0x18) 140*6dc92ba4SVladimir Oltean #define LNaTECR0_TEQ_TYPE GENMASK(29, 28) 141*6dc92ba4SVladimir Oltean #define LNaTECR0_SGN_PREQ BIT(26) 142*6dc92ba4SVladimir Oltean #define LNaTECR0_RATIO_PREQ GENMASK(25, 22) 143*6dc92ba4SVladimir Oltean #define LNaTECR0_SGN_POST1Q BIT(21) 144*6dc92ba4SVladimir Oltean #define LNaTECR0_RATIO_PST1Q GENMASK(20, 16) 145*6dc92ba4SVladimir Oltean #define LNaTECR0_ADPT_EQ GENMASK(13, 8) 146*6dc92ba4SVladimir Oltean #define LNaTECR0_AMP_RED GENMASK(5, 0) 147*6dc92ba4SVladimir Oltean 148*6dc92ba4SVladimir Oltean #define LNaTTLCR0(lane) (0x800 + (lane) * 0x40 + 0x20) 149*6dc92ba4SVladimir Oltean #define LNaTTLCR1(lane) (0x800 + (lane) * 0x40 + 0x24) 150*6dc92ba4SVladimir Oltean #define LNaTTLCR2(lane) (0x800 + (lane) * 0x40 + 0x28) 151*6dc92ba4SVladimir Oltean 152*6dc92ba4SVladimir Oltean #define LNaTCSR3(lane) (0x800 + (lane) * 0x40 + 0x3C) 153*6dc92ba4SVladimir Oltean #define LNaTCSR3_CDR_LCK BIT(27) 154*6dc92ba4SVladimir Oltean 155*6dc92ba4SVladimir Oltean enum lynx_10g_rat_sel { 156*6dc92ba4SVladimir Oltean RAT_SEL_FULL = 0x0, 157*6dc92ba4SVladimir Oltean RAT_SEL_HALF = 0x1, 158*6dc92ba4SVladimir Oltean RAT_SEL_QUARTER = 0x2, 159*6dc92ba4SVladimir Oltean RAT_SEL_DOUBLE = 0x3, 160*6dc92ba4SVladimir Oltean }; 161*6dc92ba4SVladimir Oltean 162*6dc92ba4SVladimir Oltean enum lynx_10g_eq_type { 163*6dc92ba4SVladimir Oltean EQ_TYPE_NO_EQ = 0, 164*6dc92ba4SVladimir Oltean EQ_TYPE_2TAP = 1, 165*6dc92ba4SVladimir Oltean EQ_TYPE_3TAP = 2, 166*6dc92ba4SVladimir Oltean }; 167*6dc92ba4SVladimir Oltean 168*6dc92ba4SVladimir Oltean enum lynx_10g_proto_sel { 169*6dc92ba4SVladimir Oltean PROTO_SEL_PCIE = 0, 170*6dc92ba4SVladimir Oltean PROTO_SEL_SGMII_BASEX_KX_QSGMII = 1, 171*6dc92ba4SVladimir Oltean PROTO_SEL_SATA = 2, 172*6dc92ba4SVladimir Oltean PROTO_SEL_XAUI = 4, 173*6dc92ba4SVladimir Oltean PROTO_SEL_XFI_10GBASER_KR_SXGMII = 0xa, 174*6dc92ba4SVladimir Oltean }; 175*6dc92ba4SVladimir Oltean 176*6dc92ba4SVladimir Oltean struct lynx_10g_proto_conf { 177*6dc92ba4SVladimir Oltean int proto_sel; 178*6dc92ba4SVladimir Oltean int if20bit_en; 179*6dc92ba4SVladimir Oltean int reidl_th; 180*6dc92ba4SVladimir Oltean int reidl_et_msb; 181*6dc92ba4SVladimir Oltean int reidl_et_sel; 182*6dc92ba4SVladimir Oltean int reidl_ex_msb; 183*6dc92ba4SVladimir Oltean int reidl_ex_sel; 184*6dc92ba4SVladimir Oltean int islew_rctl; 185*6dc92ba4SVladimir Oltean int oslew_rctl; 186*6dc92ba4SVladimir Oltean int rxeq_bst; 187*6dc92ba4SVladimir Oltean int gk2ovd; 188*6dc92ba4SVladimir Oltean int gk3ovd; 189*6dc92ba4SVladimir Oltean int gk2ovd_en; 190*6dc92ba4SVladimir Oltean int gk3ovd_en; 191*6dc92ba4SVladimir Oltean int base_wand; 192*6dc92ba4SVladimir Oltean int teq_type; 193*6dc92ba4SVladimir Oltean int sgn_preq; 194*6dc92ba4SVladimir Oltean int ratio_preq; 195*6dc92ba4SVladimir Oltean int sgn_post1q; 196*6dc92ba4SVladimir Oltean int ratio_post1q; 197*6dc92ba4SVladimir Oltean int adpt_eq; 198*6dc92ba4SVladimir Oltean int amp_red; 199*6dc92ba4SVladimir Oltean int ttlcr0; 200*6dc92ba4SVladimir Oltean }; 201*6dc92ba4SVladimir Oltean 202*6dc92ba4SVladimir Oltean static const struct lynx_10g_proto_conf lynx_10g_proto_conf[LANE_MODE_MAX] = { 203*6dc92ba4SVladimir Oltean [LANE_MODE_1000BASEX_SGMII] = { 204*6dc92ba4SVladimir Oltean .proto_sel = PROTO_SEL_SGMII_BASEX_KX_QSGMII, 205*6dc92ba4SVladimir Oltean .reidl_th = 1, 206*6dc92ba4SVladimir Oltean .reidl_ex_sel = 3, 207*6dc92ba4SVladimir Oltean .reidl_et_msb = 1, 208*6dc92ba4SVladimir Oltean .islew_rctl = 1, 209*6dc92ba4SVladimir Oltean .oslew_rctl = 1, 210*6dc92ba4SVladimir Oltean .gk2ovd = 15, 211*6dc92ba4SVladimir Oltean .gk3ovd = 15, 212*6dc92ba4SVladimir Oltean .gk2ovd_en = 1, 213*6dc92ba4SVladimir Oltean .gk3ovd_en = 1, 214*6dc92ba4SVladimir Oltean .teq_type = EQ_TYPE_NO_EQ, 215*6dc92ba4SVladimir Oltean .adpt_eq = 48, 216*6dc92ba4SVladimir Oltean .amp_red = 6, 217*6dc92ba4SVladimir Oltean .ttlcr0 = 0x39000400, 218*6dc92ba4SVladimir Oltean }, 219*6dc92ba4SVladimir Oltean [LANE_MODE_2500BASEX] = { 220*6dc92ba4SVladimir Oltean .proto_sel = PROTO_SEL_SGMII_BASEX_KX_QSGMII, 221*6dc92ba4SVladimir Oltean .islew_rctl = 2, 222*6dc92ba4SVladimir Oltean .oslew_rctl = 2, 223*6dc92ba4SVladimir Oltean .teq_type = EQ_TYPE_2TAP, 224*6dc92ba4SVladimir Oltean .sgn_post1q = 1, 225*6dc92ba4SVladimir Oltean .ratio_post1q = 6, 226*6dc92ba4SVladimir Oltean .adpt_eq = 48, 227*6dc92ba4SVladimir Oltean .ttlcr0 = 0x00000400, 228*6dc92ba4SVladimir Oltean }, 229*6dc92ba4SVladimir Oltean [LANE_MODE_QSGMII] = { 230*6dc92ba4SVladimir Oltean .proto_sel = PROTO_SEL_SGMII_BASEX_KX_QSGMII, 231*6dc92ba4SVladimir Oltean .islew_rctl = 1, 232*6dc92ba4SVladimir Oltean .oslew_rctl = 1, 233*6dc92ba4SVladimir Oltean .teq_type = EQ_TYPE_2TAP, 234*6dc92ba4SVladimir Oltean .sgn_post1q = 1, 235*6dc92ba4SVladimir Oltean .ratio_post1q = 6, 236*6dc92ba4SVladimir Oltean .adpt_eq = 48, 237*6dc92ba4SVladimir Oltean .amp_red = 2, 238*6dc92ba4SVladimir Oltean .ttlcr0 = 0x00000400, 239*6dc92ba4SVladimir Oltean }, 240*6dc92ba4SVladimir Oltean [LANE_MODE_10G_QXGMII] = { 241*6dc92ba4SVladimir Oltean .proto_sel = PROTO_SEL_XFI_10GBASER_KR_SXGMII, 242*6dc92ba4SVladimir Oltean .if20bit_en = 1, 243*6dc92ba4SVladimir Oltean .islew_rctl = 1, 244*6dc92ba4SVladimir Oltean .oslew_rctl = 1, 245*6dc92ba4SVladimir Oltean .base_wand = 1, 246*6dc92ba4SVladimir Oltean .teq_type = EQ_TYPE_NO_EQ, 247*6dc92ba4SVladimir Oltean .adpt_eq = 48, 248*6dc92ba4SVladimir Oltean .ttlcr0 = 0x00000400, 249*6dc92ba4SVladimir Oltean }, 250*6dc92ba4SVladimir Oltean [LANE_MODE_USXGMII] = { 251*6dc92ba4SVladimir Oltean .proto_sel = PROTO_SEL_XFI_10GBASER_KR_SXGMII, 252*6dc92ba4SVladimir Oltean .if20bit_en = 1, 253*6dc92ba4SVladimir Oltean .islew_rctl = 1, 254*6dc92ba4SVladimir Oltean .oslew_rctl = 1, 255*6dc92ba4SVladimir Oltean .base_wand = 1, 256*6dc92ba4SVladimir Oltean .teq_type = EQ_TYPE_NO_EQ, 257*6dc92ba4SVladimir Oltean .sgn_post1q = 1, 258*6dc92ba4SVladimir Oltean .adpt_eq = 48, 259*6dc92ba4SVladimir Oltean .ttlcr0 = 0x00000400, 260*6dc92ba4SVladimir Oltean }, 261*6dc92ba4SVladimir Oltean [LANE_MODE_10GBASER] = { 262*6dc92ba4SVladimir Oltean .proto_sel = PROTO_SEL_XFI_10GBASER_KR_SXGMII, 263*6dc92ba4SVladimir Oltean .if20bit_en = 1, 264*6dc92ba4SVladimir Oltean .islew_rctl = 2, 265*6dc92ba4SVladimir Oltean .oslew_rctl = 2, 266*6dc92ba4SVladimir Oltean .rxeq_bst = 1, 267*6dc92ba4SVladimir Oltean .base_wand = 1, 268*6dc92ba4SVladimir Oltean .teq_type = EQ_TYPE_2TAP, 269*6dc92ba4SVladimir Oltean .sgn_post1q = 1, 270*6dc92ba4SVladimir Oltean .ratio_post1q = 3, 271*6dc92ba4SVladimir Oltean .adpt_eq = 48, 272*6dc92ba4SVladimir Oltean .amp_red = 7, 273*6dc92ba4SVladimir Oltean .ttlcr0 = 0x00000400, 274*6dc92ba4SVladimir Oltean }, 275*6dc92ba4SVladimir Oltean }; 276*6dc92ba4SVladimir Oltean 277*6dc92ba4SVladimir Oltean static void lynx_10g_cdr_lock_check(struct lynx_lane *lane) 278*6dc92ba4SVladimir Oltean { 279*6dc92ba4SVladimir Oltean u32 tcsr3 = lynx_lane_read(lane, LNaTCSR3); 280*6dc92ba4SVladimir Oltean 281*6dc92ba4SVladimir Oltean if (tcsr3 & LNaTCSR3_CDR_LCK) 282*6dc92ba4SVladimir Oltean return; 283*6dc92ba4SVladimir Oltean 284*6dc92ba4SVladimir Oltean dev_dbg(&lane->phy->dev, 285*6dc92ba4SVladimir Oltean "Lane %c CDR unlocked, resetting receiver...\n", 286*6dc92ba4SVladimir Oltean 'A' + lane->id); 287*6dc92ba4SVladimir Oltean 288*6dc92ba4SVladimir Oltean lynx_lane_rmw(lane, LNaGCR0, LNaGCR0_RRST_ON, LNaGCR0_RRST); 289*6dc92ba4SVladimir Oltean usleep_range(1, 2); 290*6dc92ba4SVladimir Oltean lynx_lane_rmw(lane, LNaGCR0, LNaGCR0_RRST_OFF, LNaGCR0_RRST); 291*6dc92ba4SVladimir Oltean 292*6dc92ba4SVladimir Oltean usleep_range(1, 2); 293*6dc92ba4SVladimir Oltean } 294*6dc92ba4SVladimir Oltean 295*6dc92ba4SVladimir Oltean static void lynx_10g_pll_read_configuration(struct lynx_pll *pll) 296*6dc92ba4SVladimir Oltean { 297*6dc92ba4SVladimir Oltean u32 val; 298*6dc92ba4SVladimir Oltean 299*6dc92ba4SVladimir Oltean val = lynx_pll_read(pll, PLLnCR0); 300*6dc92ba4SVladimir Oltean pll->frate_sel = FIELD_GET(PLLnCR0_FRATE_SEL, val); 301*6dc92ba4SVladimir Oltean pll->refclk_sel = FIELD_GET(PLLnCR0_REFCLK_SEL, val); 302*6dc92ba4SVladimir Oltean pll->enabled = !(val & PLLnCR0_POFF); 303*6dc92ba4SVladimir Oltean pll->locked = !!(val & PLLnCR0_PLL_LCK); 304*6dc92ba4SVladimir Oltean 305*6dc92ba4SVladimir Oltean if (!pll->enabled) 306*6dc92ba4SVladimir Oltean return; 307*6dc92ba4SVladimir Oltean 308*6dc92ba4SVladimir Oltean switch (pll->frate_sel) { 309*6dc92ba4SVladimir Oltean case PLLnCR0_FRATE_5G: 310*6dc92ba4SVladimir Oltean /* 5GHz clock net */ 311*6dc92ba4SVladimir Oltean __set_bit(LANE_MODE_1000BASEX_SGMII, pll->supported); 312*6dc92ba4SVladimir Oltean __set_bit(LANE_MODE_QSGMII, pll->supported); 313*6dc92ba4SVladimir Oltean break; 314*6dc92ba4SVladimir Oltean case PLLnCR0_FRATE_3_125G: 315*6dc92ba4SVladimir Oltean __set_bit(LANE_MODE_2500BASEX, pll->supported); 316*6dc92ba4SVladimir Oltean break; 317*6dc92ba4SVladimir Oltean case PLLnCR0_FRATE_5_15625G: 318*6dc92ba4SVladimir Oltean /* 10.3125GHz clock net */ 319*6dc92ba4SVladimir Oltean __set_bit(LANE_MODE_10GBASER, pll->supported); 320*6dc92ba4SVladimir Oltean __set_bit(LANE_MODE_USXGMII, pll->supported); 321*6dc92ba4SVladimir Oltean __set_bit(LANE_MODE_10G_QXGMII, pll->supported); 322*6dc92ba4SVladimir Oltean break; 323*6dc92ba4SVladimir Oltean default: 324*6dc92ba4SVladimir Oltean break; 325*6dc92ba4SVladimir Oltean } 326*6dc92ba4SVladimir Oltean } 327*6dc92ba4SVladimir Oltean 328*6dc92ba4SVladimir Oltean /* On LS1028A, SGMIIA_CFG, SGMIIB_CFG, and SGMIIC_CFG from PCCR8 have the 329*6dc92ba4SVladimir Oltean * ability to map either an ENETC PCS (PCCR8_SGMIIa_CFG=2) or a Felix switch 330*6dc92ba4SVladimir Oltean * PCS (PCCR8_SGMIIa_CFG=1) to the same lane. 331*6dc92ba4SVladimir Oltean * 332*6dc92ba4SVladimir Oltean * On LS1088A, the same QSGMII PCS B can be connected to SerDes lane 1 333*6dc92ba4SVladimir Oltean * (PCCR9_QSGMIIa_CFG=1) or to lane 3 (PCCR9_QSGMIIa_CFG=2). 334*6dc92ba4SVladimir Oltean * 335*6dc92ba4SVladimir Oltean * The PHY API lacks the capability to distinguish anything about the consumer, 336*6dc92ba4SVladimir Oltean * so we don't support changing the initial muxing done by the RCW. 337*6dc92ba4SVladimir Oltean * 338*6dc92ba4SVladimir Oltean * However, after disabling a PCS through PCCR8, we need to properly restore 339*6dc92ba4SVladimir Oltean * the original value to keep the same muxing, and for that we need to back 340*6dc92ba4SVladimir Oltean * it up (here). 341*6dc92ba4SVladimir Oltean */ 342*6dc92ba4SVladimir Oltean static void lynx_10g_backup_pccr_val(struct lynx_lane *lane) 343*6dc92ba4SVladimir Oltean { 344*6dc92ba4SVladimir Oltean u32 val; 345*6dc92ba4SVladimir Oltean int err; 346*6dc92ba4SVladimir Oltean 347*6dc92ba4SVladimir Oltean if (lane->mode == LANE_MODE_UNKNOWN) 348*6dc92ba4SVladimir Oltean return; 349*6dc92ba4SVladimir Oltean 350*6dc92ba4SVladimir Oltean err = lynx_pccr_read(lane, lane->mode, &val); 351*6dc92ba4SVladimir Oltean if (err) { 352*6dc92ba4SVladimir Oltean dev_warn(&lane->phy->dev, 353*6dc92ba4SVladimir Oltean "The driver doesn't know how to access the PCCR for lane mode %s\n", 354*6dc92ba4SVladimir Oltean lynx_lane_mode_str(lane->mode)); 355*6dc92ba4SVladimir Oltean lane->mode = LANE_MODE_UNKNOWN; 356*6dc92ba4SVladimir Oltean return; 357*6dc92ba4SVladimir Oltean } 358*6dc92ba4SVladimir Oltean 359*6dc92ba4SVladimir Oltean lane->default_pccr[lane->mode] = val; 360*6dc92ba4SVladimir Oltean 361*6dc92ba4SVladimir Oltean /* 1000Base-X, 1000Base-KX, 2500Base-KX and SGMII use the same PCCR8. 362*6dc92ba4SVladimir Oltean * Only the KX bit differs (set for 1000Base-KX). Since we back up PCCR 363*6dc92ba4SVladimir Oltean * values per lane mode, make sure to not back up the PCCR8 value with 364*6dc92ba4SVladimir Oltean * the KX bit set for the non-KX modes, if the lane was in KX mode at 365*6dc92ba4SVladimir Oltean * boot time. Just preserve bits 2:0, which tell whether the (and 366*6dc92ba4SVladimir Oltean * which) 1G PCS was enabled. 367*6dc92ba4SVladimir Oltean */ 368*6dc92ba4SVladimir Oltean switch (lane->mode) { 369*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 370*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 371*6dc92ba4SVladimir Oltean lane->default_pccr[LANE_MODE_1000BASEX_SGMII] = val & ~PCCR8_SGMIIa_KX; 372*6dc92ba4SVladimir Oltean lane->default_pccr[LANE_MODE_2500BASEX] = val & ~PCCR8_SGMIIa_KX; 373*6dc92ba4SVladimir Oltean break; 374*6dc92ba4SVladimir Oltean default: 375*6dc92ba4SVladimir Oltean break; 376*6dc92ba4SVladimir Oltean } 377*6dc92ba4SVladimir Oltean } 378*6dc92ba4SVladimir Oltean 379*6dc92ba4SVladimir Oltean /* Is the PCS enabled, according to the value backed up from the PCCR register 380*6dc92ba4SVladimir Oltean * for this lane mode? 381*6dc92ba4SVladimir Oltean * 382*6dc92ba4SVladimir Oltean * Normally we'd need to ask "what lane mode are we talking about?", but the 383*6dc92ba4SVladimir Oltean * answer is invariably the same regardless - PCCR8_SGMIIa_CFG has the same 384*6dc92ba4SVladimir Oltean * layout as PCCR9_QSGMIIa_CFG, PCCRB_XFIa_CFG etc etc, and the value 0 385*6dc92ba4SVladimir Oltean * universally means "PCS disabled". So this is just a shorthand answer. 386*6dc92ba4SVladimir Oltean */ 387*6dc92ba4SVladimir Oltean static bool lynx_10g_pccr_val_enabled(u32 pccr) 388*6dc92ba4SVladimir Oltean { 389*6dc92ba4SVladimir Oltean return FIELD_PREP(PCCR8_SGMIIa_CFG, pccr) != 0; 390*6dc92ba4SVladimir Oltean } 391*6dc92ba4SVladimir Oltean 392*6dc92ba4SVladimir Oltean static bool lynx_10g_lane_is_3_125g(struct lynx_lane *lane) 393*6dc92ba4SVladimir Oltean { 394*6dc92ba4SVladimir Oltean struct lynx_priv *priv = lane->priv; 395*6dc92ba4SVladimir Oltean struct lynx_pll *pll; 396*6dc92ba4SVladimir Oltean u32 gcr0; 397*6dc92ba4SVladimir Oltean 398*6dc92ba4SVladimir Oltean gcr0 = lynx_lane_read(lane, LNaGCR0); 399*6dc92ba4SVladimir Oltean 400*6dc92ba4SVladimir Oltean if (gcr0 & LNaGCR0_TPLL_PLLF) 401*6dc92ba4SVladimir Oltean pll = &priv->pll[0]; 402*6dc92ba4SVladimir Oltean else 403*6dc92ba4SVladimir Oltean pll = &priv->pll[1]; 404*6dc92ba4SVladimir Oltean 405*6dc92ba4SVladimir Oltean if (pll->frate_sel != PLLnCR0_FRATE_3_125G) 406*6dc92ba4SVladimir Oltean return false; 407*6dc92ba4SVladimir Oltean 408*6dc92ba4SVladimir Oltean if (FIELD_GET(LNaGCR0_TRAT_SEL, gcr0) != RAT_SEL_FULL || 409*6dc92ba4SVladimir Oltean FIELD_GET(LNaGCR0_RRAT_SEL, gcr0) != RAT_SEL_FULL) 410*6dc92ba4SVladimir Oltean return false; 411*6dc92ba4SVladimir Oltean 412*6dc92ba4SVladimir Oltean return true; 413*6dc92ba4SVladimir Oltean } 414*6dc92ba4SVladimir Oltean 415*6dc92ba4SVladimir Oltean static void lynx_10g_lane_read_configuration(struct lynx_lane *lane) 416*6dc92ba4SVladimir Oltean { 417*6dc92ba4SVladimir Oltean u32 pssr0 = lynx_lane_read(lane, LNaPSSR0); 418*6dc92ba4SVladimir Oltean struct lynx_priv *priv = lane->priv; 419*6dc92ba4SVladimir Oltean int proto; 420*6dc92ba4SVladimir Oltean 421*6dc92ba4SVladimir Oltean proto = FIELD_GET(LNaPSSR0_TYPE, pssr0); 422*6dc92ba4SVladimir Oltean switch (proto) { 423*6dc92ba4SVladimir Oltean case PROTO_SEL_SGMII_BASEX_KX_QSGMII: 424*6dc92ba4SVladimir Oltean if (lynx_10g_lane_is_3_125g(lane)) 425*6dc92ba4SVladimir Oltean lane->mode = LANE_MODE_2500BASEX; 426*6dc92ba4SVladimir Oltean else if (FIELD_GET(LNaPSSR0_IS_QUAD, pssr0)) 427*6dc92ba4SVladimir Oltean lane->mode = LANE_MODE_QSGMII; 428*6dc92ba4SVladimir Oltean else 429*6dc92ba4SVladimir Oltean lane->mode = LANE_MODE_1000BASEX_SGMII; 430*6dc92ba4SVladimir Oltean break; 431*6dc92ba4SVladimir Oltean case PROTO_SEL_XFI_10GBASER_KR_SXGMII: 432*6dc92ba4SVladimir Oltean if (FIELD_GET(LNaPSSR0_IS_QUAD, pssr0)) 433*6dc92ba4SVladimir Oltean lane->mode = LANE_MODE_10G_QXGMII; 434*6dc92ba4SVladimir Oltean else if (priv->info->quirks & LYNX_QUIRK_HAS_HARDCODED_USXGMII) 435*6dc92ba4SVladimir Oltean lane->mode = LANE_MODE_USXGMII; 436*6dc92ba4SVladimir Oltean else 437*6dc92ba4SVladimir Oltean lane->mode = LANE_MODE_10GBASER; 438*6dc92ba4SVladimir Oltean break; 439*6dc92ba4SVladimir Oltean case PROTO_SEL_PCIE: 440*6dc92ba4SVladimir Oltean case PROTO_SEL_SATA: 441*6dc92ba4SVladimir Oltean case PROTO_SEL_XAUI: 442*6dc92ba4SVladimir Oltean break; 443*6dc92ba4SVladimir Oltean default: 444*6dc92ba4SVladimir Oltean dev_warn(&lane->phy->dev, "Unknown lane protocol 0x%x\n", 445*6dc92ba4SVladimir Oltean proto); 446*6dc92ba4SVladimir Oltean } 447*6dc92ba4SVladimir Oltean 448*6dc92ba4SVladimir Oltean lynx_10g_backup_pccr_val(lane); 449*6dc92ba4SVladimir Oltean } 450*6dc92ba4SVladimir Oltean 451*6dc92ba4SVladimir Oltean static int ls1028a_get_pccr(enum lynx_lane_mode lane_mode, int lane, 452*6dc92ba4SVladimir Oltean struct lynx_pccr *pccr) 453*6dc92ba4SVladimir Oltean { 454*6dc92ba4SVladimir Oltean switch (lane_mode) { 455*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 456*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 457*6dc92ba4SVladimir Oltean pccr->offset = PCCR8; 458*6dc92ba4SVladimir Oltean pccr->width = 4; 459*6dc92ba4SVladimir Oltean pccr->shift = SGMII_CFG(lane); 460*6dc92ba4SVladimir Oltean break; 461*6dc92ba4SVladimir Oltean case LANE_MODE_QSGMII: 462*6dc92ba4SVladimir Oltean if (lane != 1) 463*6dc92ba4SVladimir Oltean return -EINVAL; 464*6dc92ba4SVladimir Oltean 465*6dc92ba4SVladimir Oltean pccr->offset = PCCR9; 466*6dc92ba4SVladimir Oltean pccr->width = 3; 467*6dc92ba4SVladimir Oltean pccr->shift = QSGMII_CFG(A); 468*6dc92ba4SVladimir Oltean break; 469*6dc92ba4SVladimir Oltean case LANE_MODE_10G_QXGMII: 470*6dc92ba4SVladimir Oltean if (lane != 1) 471*6dc92ba4SVladimir Oltean return -EINVAL; 472*6dc92ba4SVladimir Oltean 473*6dc92ba4SVladimir Oltean pccr->offset = PCCR9; 474*6dc92ba4SVladimir Oltean pccr->width = 3; 475*6dc92ba4SVladimir Oltean pccr->shift = QXGMII_CFG(A); 476*6dc92ba4SVladimir Oltean break; 477*6dc92ba4SVladimir Oltean case LANE_MODE_USXGMII: 478*6dc92ba4SVladimir Oltean if (lane != 0) 479*6dc92ba4SVladimir Oltean return -EINVAL; 480*6dc92ba4SVladimir Oltean 481*6dc92ba4SVladimir Oltean pccr->offset = PCCRB; 482*6dc92ba4SVladimir Oltean pccr->width = 3; 483*6dc92ba4SVladimir Oltean pccr->shift = SXGMII_CFG(A); 484*6dc92ba4SVladimir Oltean break; 485*6dc92ba4SVladimir Oltean default: 486*6dc92ba4SVladimir Oltean return -EINVAL; 487*6dc92ba4SVladimir Oltean } 488*6dc92ba4SVladimir Oltean 489*6dc92ba4SVladimir Oltean return 0; 490*6dc92ba4SVladimir Oltean } 491*6dc92ba4SVladimir Oltean 492*6dc92ba4SVladimir Oltean static int ls1028a_get_pcvt_offset(int lane, enum lynx_lane_mode mode) 493*6dc92ba4SVladimir Oltean { 494*6dc92ba4SVladimir Oltean switch (mode) { 495*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 496*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 497*6dc92ba4SVladimir Oltean return SGMIIaCR0(lane); 498*6dc92ba4SVladimir Oltean case LANE_MODE_QSGMII: 499*6dc92ba4SVladimir Oltean return lane == 1 ? QSGMIIaCR0(A) : -EINVAL; 500*6dc92ba4SVladimir Oltean case LANE_MODE_USXGMII: 501*6dc92ba4SVladimir Oltean return lane == 0 ? SXGMIIaCR0(A) : -EINVAL; 502*6dc92ba4SVladimir Oltean case LANE_MODE_10G_QXGMII: 503*6dc92ba4SVladimir Oltean return lane == 1 ? QXGMIIaCR0(A) : -EINVAL; 504*6dc92ba4SVladimir Oltean default: 505*6dc92ba4SVladimir Oltean return -EINVAL; 506*6dc92ba4SVladimir Oltean } 507*6dc92ba4SVladimir Oltean } 508*6dc92ba4SVladimir Oltean 509*6dc92ba4SVladimir Oltean static const struct lynx_info lynx_info_ls1028a = { 510*6dc92ba4SVladimir Oltean .get_pccr = ls1028a_get_pccr, 511*6dc92ba4SVladimir Oltean .get_pcvt_offset = ls1028a_get_pcvt_offset, 512*6dc92ba4SVladimir Oltean .pll_read_configuration = lynx_10g_pll_read_configuration, 513*6dc92ba4SVladimir Oltean .lane_read_configuration = lynx_10g_lane_read_configuration, 514*6dc92ba4SVladimir Oltean .cdr_lock_check = lynx_10g_cdr_lock_check, 515*6dc92ba4SVladimir Oltean .num_lanes = 4, 516*6dc92ba4SVladimir Oltean .index = 1, 517*6dc92ba4SVladimir Oltean .quirks = LYNX_QUIRK_HAS_HARDCODED_USXGMII, 518*6dc92ba4SVladimir Oltean }; 519*6dc92ba4SVladimir Oltean 520*6dc92ba4SVladimir Oltean static int ls1046a_serdes1_get_pccr(enum lynx_lane_mode lane_mode, int lane, 521*6dc92ba4SVladimir Oltean struct lynx_pccr *pccr) 522*6dc92ba4SVladimir Oltean { 523*6dc92ba4SVladimir Oltean switch (lane_mode) { 524*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 525*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 526*6dc92ba4SVladimir Oltean pccr->offset = PCCR8; 527*6dc92ba4SVladimir Oltean pccr->width = 4; 528*6dc92ba4SVladimir Oltean pccr->shift = SGMII_CFG(lane); 529*6dc92ba4SVladimir Oltean break; 530*6dc92ba4SVladimir Oltean case LANE_MODE_QSGMII: 531*6dc92ba4SVladimir Oltean if (lane != 1) 532*6dc92ba4SVladimir Oltean return -EINVAL; 533*6dc92ba4SVladimir Oltean 534*6dc92ba4SVladimir Oltean pccr->offset = PCCR9; 535*6dc92ba4SVladimir Oltean pccr->width = 3; 536*6dc92ba4SVladimir Oltean pccr->shift = QSGMII_CFG(B); 537*6dc92ba4SVladimir Oltean break; 538*6dc92ba4SVladimir Oltean case LANE_MODE_10GBASER: 539*6dc92ba4SVladimir Oltean switch (lane) { 540*6dc92ba4SVladimir Oltean case 2: 541*6dc92ba4SVladimir Oltean pccr->shift = XFI_CFG(A); 542*6dc92ba4SVladimir Oltean break; 543*6dc92ba4SVladimir Oltean case 3: 544*6dc92ba4SVladimir Oltean pccr->shift = XFI_CFG(B); 545*6dc92ba4SVladimir Oltean break; 546*6dc92ba4SVladimir Oltean default: 547*6dc92ba4SVladimir Oltean return -EINVAL; 548*6dc92ba4SVladimir Oltean } 549*6dc92ba4SVladimir Oltean 550*6dc92ba4SVladimir Oltean pccr->offset = PCCRB; 551*6dc92ba4SVladimir Oltean pccr->width = 3; 552*6dc92ba4SVladimir Oltean break; 553*6dc92ba4SVladimir Oltean default: 554*6dc92ba4SVladimir Oltean return -EINVAL; 555*6dc92ba4SVladimir Oltean } 556*6dc92ba4SVladimir Oltean 557*6dc92ba4SVladimir Oltean return 0; 558*6dc92ba4SVladimir Oltean } 559*6dc92ba4SVladimir Oltean 560*6dc92ba4SVladimir Oltean static int ls1046a_serdes1_get_pcvt_offset(int lane, enum lynx_lane_mode mode) 561*6dc92ba4SVladimir Oltean { 562*6dc92ba4SVladimir Oltean switch (mode) { 563*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 564*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 565*6dc92ba4SVladimir Oltean return SGMIIaCR0(lane); 566*6dc92ba4SVladimir Oltean case LANE_MODE_QSGMII: 567*6dc92ba4SVladimir Oltean if (lane != 1) 568*6dc92ba4SVladimir Oltean return -EINVAL; 569*6dc92ba4SVladimir Oltean 570*6dc92ba4SVladimir Oltean return QSGMIIaCR0(B); 571*6dc92ba4SVladimir Oltean case LANE_MODE_10GBASER: 572*6dc92ba4SVladimir Oltean switch (lane) { 573*6dc92ba4SVladimir Oltean case 2: 574*6dc92ba4SVladimir Oltean return XFIaCR0(A); 575*6dc92ba4SVladimir Oltean case 3: 576*6dc92ba4SVladimir Oltean return XFIaCR0(B); 577*6dc92ba4SVladimir Oltean default: 578*6dc92ba4SVladimir Oltean return -EINVAL; 579*6dc92ba4SVladimir Oltean } 580*6dc92ba4SVladimir Oltean default: 581*6dc92ba4SVladimir Oltean return -EINVAL; 582*6dc92ba4SVladimir Oltean } 583*6dc92ba4SVladimir Oltean } 584*6dc92ba4SVladimir Oltean 585*6dc92ba4SVladimir Oltean static const struct lynx_info lynx_info_ls1046a_serdes1 = { 586*6dc92ba4SVladimir Oltean .get_pccr = ls1046a_serdes1_get_pccr, 587*6dc92ba4SVladimir Oltean .get_pcvt_offset = ls1046a_serdes1_get_pcvt_offset, 588*6dc92ba4SVladimir Oltean .pll_read_configuration = lynx_10g_pll_read_configuration, 589*6dc92ba4SVladimir Oltean .lane_read_configuration = lynx_10g_lane_read_configuration, 590*6dc92ba4SVladimir Oltean .cdr_lock_check = lynx_10g_cdr_lock_check, 591*6dc92ba4SVladimir Oltean .num_lanes = 4, 592*6dc92ba4SVladimir Oltean .index = 1, 593*6dc92ba4SVladimir Oltean }; 594*6dc92ba4SVladimir Oltean 595*6dc92ba4SVladimir Oltean static int ls1046a_serdes2_get_pccr(enum lynx_lane_mode lane_mode, int lane, 596*6dc92ba4SVladimir Oltean struct lynx_pccr *pccr) 597*6dc92ba4SVladimir Oltean { 598*6dc92ba4SVladimir Oltean switch (lane_mode) { 599*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 600*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 601*6dc92ba4SVladimir Oltean if (lane != 1) 602*6dc92ba4SVladimir Oltean return -EINVAL; 603*6dc92ba4SVladimir Oltean 604*6dc92ba4SVladimir Oltean pccr->offset = PCCR8; 605*6dc92ba4SVladimir Oltean pccr->width = 4; 606*6dc92ba4SVladimir Oltean pccr->shift = SGMII_CFG(B); 607*6dc92ba4SVladimir Oltean break; 608*6dc92ba4SVladimir Oltean default: 609*6dc92ba4SVladimir Oltean return -EINVAL; 610*6dc92ba4SVladimir Oltean } 611*6dc92ba4SVladimir Oltean 612*6dc92ba4SVladimir Oltean return 0; 613*6dc92ba4SVladimir Oltean } 614*6dc92ba4SVladimir Oltean 615*6dc92ba4SVladimir Oltean static int ls1046a_serdes2_get_pcvt_offset(int lane, enum lynx_lane_mode mode) 616*6dc92ba4SVladimir Oltean { 617*6dc92ba4SVladimir Oltean switch (mode) { 618*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 619*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 620*6dc92ba4SVladimir Oltean if (lane != 1) 621*6dc92ba4SVladimir Oltean return -EINVAL; 622*6dc92ba4SVladimir Oltean 623*6dc92ba4SVladimir Oltean return SGMIIaCR0(B); 624*6dc92ba4SVladimir Oltean default: 625*6dc92ba4SVladimir Oltean return -EINVAL; 626*6dc92ba4SVladimir Oltean } 627*6dc92ba4SVladimir Oltean } 628*6dc92ba4SVladimir Oltean 629*6dc92ba4SVladimir Oltean static const struct lynx_info lynx_info_ls1046a_serdes2 = { 630*6dc92ba4SVladimir Oltean .get_pccr = ls1046a_serdes2_get_pccr, 631*6dc92ba4SVladimir Oltean .get_pcvt_offset = ls1046a_serdes2_get_pcvt_offset, 632*6dc92ba4SVladimir Oltean .pll_read_configuration = lynx_10g_pll_read_configuration, 633*6dc92ba4SVladimir Oltean .lane_read_configuration = lynx_10g_lane_read_configuration, 634*6dc92ba4SVladimir Oltean .cdr_lock_check = lynx_10g_cdr_lock_check, 635*6dc92ba4SVladimir Oltean .num_lanes = 4, 636*6dc92ba4SVladimir Oltean .index = 2, 637*6dc92ba4SVladimir Oltean }; 638*6dc92ba4SVladimir Oltean 639*6dc92ba4SVladimir Oltean static int ls1088a_serdes1_get_pccr(enum lynx_lane_mode lane_mode, int lane, 640*6dc92ba4SVladimir Oltean struct lynx_pccr *pccr) 641*6dc92ba4SVladimir Oltean { 642*6dc92ba4SVladimir Oltean switch (lane_mode) { 643*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 644*6dc92ba4SVladimir Oltean pccr->offset = PCCR8; 645*6dc92ba4SVladimir Oltean pccr->width = 4; 646*6dc92ba4SVladimir Oltean pccr->shift = SGMII_CFG(lane); 647*6dc92ba4SVladimir Oltean break; 648*6dc92ba4SVladimir Oltean case LANE_MODE_QSGMII: 649*6dc92ba4SVladimir Oltean switch (lane) { 650*6dc92ba4SVladimir Oltean case 0: 651*6dc92ba4SVladimir Oltean pccr->shift = QSGMII_CFG(A); 652*6dc92ba4SVladimir Oltean break; 653*6dc92ba4SVladimir Oltean case 1: 654*6dc92ba4SVladimir Oltean case 3: 655*6dc92ba4SVladimir Oltean pccr->shift = QSGMII_CFG(B); 656*6dc92ba4SVladimir Oltean break; 657*6dc92ba4SVladimir Oltean default: 658*6dc92ba4SVladimir Oltean return -EINVAL; 659*6dc92ba4SVladimir Oltean } 660*6dc92ba4SVladimir Oltean 661*6dc92ba4SVladimir Oltean pccr->offset = PCCR9; 662*6dc92ba4SVladimir Oltean pccr->width = 3; 663*6dc92ba4SVladimir Oltean break; 664*6dc92ba4SVladimir Oltean case LANE_MODE_10GBASER: 665*6dc92ba4SVladimir Oltean switch (lane) { 666*6dc92ba4SVladimir Oltean case 2: 667*6dc92ba4SVladimir Oltean pccr->shift = XFI_CFG(A); 668*6dc92ba4SVladimir Oltean break; 669*6dc92ba4SVladimir Oltean case 3: 670*6dc92ba4SVladimir Oltean pccr->shift = XFI_CFG(B); 671*6dc92ba4SVladimir Oltean break; 672*6dc92ba4SVladimir Oltean default: 673*6dc92ba4SVladimir Oltean return -EINVAL; 674*6dc92ba4SVladimir Oltean } 675*6dc92ba4SVladimir Oltean 676*6dc92ba4SVladimir Oltean pccr->offset = PCCRB; 677*6dc92ba4SVladimir Oltean pccr->width = 3; 678*6dc92ba4SVladimir Oltean break; 679*6dc92ba4SVladimir Oltean default: 680*6dc92ba4SVladimir Oltean return -EINVAL; 681*6dc92ba4SVladimir Oltean } 682*6dc92ba4SVladimir Oltean 683*6dc92ba4SVladimir Oltean return 0; 684*6dc92ba4SVladimir Oltean } 685*6dc92ba4SVladimir Oltean 686*6dc92ba4SVladimir Oltean static int ls1088a_serdes1_get_pcvt_offset(int lane, enum lynx_lane_mode mode) 687*6dc92ba4SVladimir Oltean { 688*6dc92ba4SVladimir Oltean switch (mode) { 689*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 690*6dc92ba4SVladimir Oltean return SGMIIaCR0(lane); 691*6dc92ba4SVladimir Oltean case LANE_MODE_QSGMII: 692*6dc92ba4SVladimir Oltean switch (lane) { 693*6dc92ba4SVladimir Oltean case 0: 694*6dc92ba4SVladimir Oltean return QSGMIIaCR0(A); 695*6dc92ba4SVladimir Oltean case 1: 696*6dc92ba4SVladimir Oltean case 3: 697*6dc92ba4SVladimir Oltean return QSGMIIaCR0(B); 698*6dc92ba4SVladimir Oltean default: 699*6dc92ba4SVladimir Oltean return -EINVAL; 700*6dc92ba4SVladimir Oltean } 701*6dc92ba4SVladimir Oltean case LANE_MODE_10GBASER: 702*6dc92ba4SVladimir Oltean switch (lane) { 703*6dc92ba4SVladimir Oltean case 2: 704*6dc92ba4SVladimir Oltean return XFIaCR0(A); 705*6dc92ba4SVladimir Oltean case 3: 706*6dc92ba4SVladimir Oltean return XFIaCR0(B); 707*6dc92ba4SVladimir Oltean default: 708*6dc92ba4SVladimir Oltean return -EINVAL; 709*6dc92ba4SVladimir Oltean } 710*6dc92ba4SVladimir Oltean default: 711*6dc92ba4SVladimir Oltean return -EINVAL; 712*6dc92ba4SVladimir Oltean } 713*6dc92ba4SVladimir Oltean } 714*6dc92ba4SVladimir Oltean 715*6dc92ba4SVladimir Oltean static const struct lynx_info lynx_info_ls1088a_serdes1 = { 716*6dc92ba4SVladimir Oltean .get_pccr = ls1088a_serdes1_get_pccr, 717*6dc92ba4SVladimir Oltean .get_pcvt_offset = ls1088a_serdes1_get_pcvt_offset, 718*6dc92ba4SVladimir Oltean .pll_read_configuration = lynx_10g_pll_read_configuration, 719*6dc92ba4SVladimir Oltean .lane_read_configuration = lynx_10g_lane_read_configuration, 720*6dc92ba4SVladimir Oltean .cdr_lock_check = lynx_10g_cdr_lock_check, 721*6dc92ba4SVladimir Oltean .num_lanes = 4, 722*6dc92ba4SVladimir Oltean .index = 1, 723*6dc92ba4SVladimir Oltean }; 724*6dc92ba4SVladimir Oltean 725*6dc92ba4SVladimir Oltean static int ls2088a_serdes1_get_pccr(enum lynx_lane_mode lane_mode, int lane, 726*6dc92ba4SVladimir Oltean struct lynx_pccr *pccr) 727*6dc92ba4SVladimir Oltean { 728*6dc92ba4SVladimir Oltean switch (lane_mode) { 729*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 730*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 731*6dc92ba4SVladimir Oltean pccr->offset = PCCR8; 732*6dc92ba4SVladimir Oltean pccr->width = 4; 733*6dc92ba4SVladimir Oltean pccr->shift = SGMII_CFG(lane); 734*6dc92ba4SVladimir Oltean break; 735*6dc92ba4SVladimir Oltean case LANE_MODE_QSGMII: 736*6dc92ba4SVladimir Oltean switch (lane) { 737*6dc92ba4SVladimir Oltean case 2: 738*6dc92ba4SVladimir Oltean case 6: 739*6dc92ba4SVladimir Oltean pccr->shift = QSGMII_CFG(A); 740*6dc92ba4SVladimir Oltean break; 741*6dc92ba4SVladimir Oltean case 7: 742*6dc92ba4SVladimir Oltean pccr->shift = QSGMII_CFG(B); 743*6dc92ba4SVladimir Oltean break; 744*6dc92ba4SVladimir Oltean case 0: 745*6dc92ba4SVladimir Oltean case 4: 746*6dc92ba4SVladimir Oltean pccr->shift = QSGMII_CFG(C); 747*6dc92ba4SVladimir Oltean break; 748*6dc92ba4SVladimir Oltean case 1: 749*6dc92ba4SVladimir Oltean case 5: 750*6dc92ba4SVladimir Oltean pccr->shift = QSGMII_CFG(D); 751*6dc92ba4SVladimir Oltean break; 752*6dc92ba4SVladimir Oltean default: 753*6dc92ba4SVladimir Oltean return -EINVAL; 754*6dc92ba4SVladimir Oltean } 755*6dc92ba4SVladimir Oltean 756*6dc92ba4SVladimir Oltean pccr->offset = PCCR9; 757*6dc92ba4SVladimir Oltean pccr->width = 3; 758*6dc92ba4SVladimir Oltean break; 759*6dc92ba4SVladimir Oltean case LANE_MODE_10GBASER: 760*6dc92ba4SVladimir Oltean pccr->offset = PCCRB; 761*6dc92ba4SVladimir Oltean pccr->width = 3; 762*6dc92ba4SVladimir Oltean pccr->shift = XFI_CFG(lane); 763*6dc92ba4SVladimir Oltean break; 764*6dc92ba4SVladimir Oltean default: 765*6dc92ba4SVladimir Oltean return -EINVAL; 766*6dc92ba4SVladimir Oltean } 767*6dc92ba4SVladimir Oltean 768*6dc92ba4SVladimir Oltean return 0; 769*6dc92ba4SVladimir Oltean } 770*6dc92ba4SVladimir Oltean 771*6dc92ba4SVladimir Oltean static int ls2088a_serdes1_get_pcvt_offset(int lane, enum lynx_lane_mode mode) 772*6dc92ba4SVladimir Oltean { 773*6dc92ba4SVladimir Oltean switch (mode) { 774*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 775*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 776*6dc92ba4SVladimir Oltean return SGMIIaCR0(lane); 777*6dc92ba4SVladimir Oltean case LANE_MODE_QSGMII: 778*6dc92ba4SVladimir Oltean switch (lane) { 779*6dc92ba4SVladimir Oltean case 2: 780*6dc92ba4SVladimir Oltean case 6: 781*6dc92ba4SVladimir Oltean return QSGMIIaCR0(A); 782*6dc92ba4SVladimir Oltean case 7: 783*6dc92ba4SVladimir Oltean return QSGMIIaCR0(B); 784*6dc92ba4SVladimir Oltean case 0: 785*6dc92ba4SVladimir Oltean case 4: 786*6dc92ba4SVladimir Oltean return QSGMIIaCR0(C); 787*6dc92ba4SVladimir Oltean case 1: 788*6dc92ba4SVladimir Oltean case 5: 789*6dc92ba4SVladimir Oltean return QSGMIIaCR0(D); 790*6dc92ba4SVladimir Oltean default: 791*6dc92ba4SVladimir Oltean return -EINVAL; 792*6dc92ba4SVladimir Oltean } 793*6dc92ba4SVladimir Oltean case LANE_MODE_10GBASER: 794*6dc92ba4SVladimir Oltean return XFIaCR0(lane); 795*6dc92ba4SVladimir Oltean default: 796*6dc92ba4SVladimir Oltean return -EINVAL; 797*6dc92ba4SVladimir Oltean } 798*6dc92ba4SVladimir Oltean } 799*6dc92ba4SVladimir Oltean 800*6dc92ba4SVladimir Oltean static const struct lynx_info lynx_info_ls2088a_serdes1 = { 801*6dc92ba4SVladimir Oltean .get_pccr = ls2088a_serdes1_get_pccr, 802*6dc92ba4SVladimir Oltean .get_pcvt_offset = ls2088a_serdes1_get_pcvt_offset, 803*6dc92ba4SVladimir Oltean .pll_read_configuration = lynx_10g_pll_read_configuration, 804*6dc92ba4SVladimir Oltean .lane_read_configuration = lynx_10g_lane_read_configuration, 805*6dc92ba4SVladimir Oltean .cdr_lock_check = lynx_10g_cdr_lock_check, 806*6dc92ba4SVladimir Oltean .num_lanes = 8, 807*6dc92ba4SVladimir Oltean .index = 1, 808*6dc92ba4SVladimir Oltean }; 809*6dc92ba4SVladimir Oltean 810*6dc92ba4SVladimir Oltean static int ls2088a_serdes2_get_pccr(enum lynx_lane_mode lane_mode, int lane, 811*6dc92ba4SVladimir Oltean struct lynx_pccr *pccr) 812*6dc92ba4SVladimir Oltean { 813*6dc92ba4SVladimir Oltean switch (lane_mode) { 814*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 815*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 816*6dc92ba4SVladimir Oltean pccr->offset = PCCR8; 817*6dc92ba4SVladimir Oltean pccr->width = 4; 818*6dc92ba4SVladimir Oltean pccr->shift = SGMII_CFG(lane); 819*6dc92ba4SVladimir Oltean break; 820*6dc92ba4SVladimir Oltean default: 821*6dc92ba4SVladimir Oltean return -EINVAL; 822*6dc92ba4SVladimir Oltean } 823*6dc92ba4SVladimir Oltean 824*6dc92ba4SVladimir Oltean return 0; 825*6dc92ba4SVladimir Oltean } 826*6dc92ba4SVladimir Oltean 827*6dc92ba4SVladimir Oltean static int ls2088a_serdes2_get_pcvt_offset(int lane, enum lynx_lane_mode mode) 828*6dc92ba4SVladimir Oltean { 829*6dc92ba4SVladimir Oltean switch (mode) { 830*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 831*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 832*6dc92ba4SVladimir Oltean return SGMIIaCR0(lane); 833*6dc92ba4SVladimir Oltean default: 834*6dc92ba4SVladimir Oltean return -EINVAL; 835*6dc92ba4SVladimir Oltean } 836*6dc92ba4SVladimir Oltean } 837*6dc92ba4SVladimir Oltean 838*6dc92ba4SVladimir Oltean static const struct lynx_info lynx_info_ls2088a_serdes2 = { 839*6dc92ba4SVladimir Oltean .get_pccr = ls2088a_serdes2_get_pccr, 840*6dc92ba4SVladimir Oltean .get_pcvt_offset = ls2088a_serdes2_get_pcvt_offset, 841*6dc92ba4SVladimir Oltean .pll_read_configuration = lynx_10g_pll_read_configuration, 842*6dc92ba4SVladimir Oltean .lane_read_configuration = lynx_10g_lane_read_configuration, 843*6dc92ba4SVladimir Oltean .cdr_lock_check = lynx_10g_cdr_lock_check, 844*6dc92ba4SVladimir Oltean .num_lanes = 8, 845*6dc92ba4SVladimir Oltean .index = 2, 846*6dc92ba4SVladimir Oltean }; 847*6dc92ba4SVladimir Oltean 848*6dc92ba4SVladimir Oltean /* Halting puts the lane in a mode in which it can be reconfigured */ 849*6dc92ba4SVladimir Oltean static void lynx_10g_lane_halt(struct phy *phy) 850*6dc92ba4SVladimir Oltean { 851*6dc92ba4SVladimir Oltean struct lynx_lane *lane = phy_get_drvdata(phy); 852*6dc92ba4SVladimir Oltean 853*6dc92ba4SVladimir Oltean /* Issue a reset request */ 854*6dc92ba4SVladimir Oltean lynx_lane_rmw(lane, LNaGCR0, 855*6dc92ba4SVladimir Oltean LNaGCR0_RRST_ON | LNaGCR0_TRST_ON, 856*6dc92ba4SVladimir Oltean LNaGCR0_RRST | LNaGCR0_TRST); 857*6dc92ba4SVladimir Oltean 858*6dc92ba4SVladimir Oltean /* The RM says to wait for at least 50ns */ 859*6dc92ba4SVladimir Oltean usleep_range(1, 2); 860*6dc92ba4SVladimir Oltean } 861*6dc92ba4SVladimir Oltean 862*6dc92ba4SVladimir Oltean static void lynx_10g_lane_reset(struct phy *phy) 863*6dc92ba4SVladimir Oltean { 864*6dc92ba4SVladimir Oltean struct lynx_lane *lane = phy_get_drvdata(phy); 865*6dc92ba4SVladimir Oltean 866*6dc92ba4SVladimir Oltean /* Finalize the reset request */ 867*6dc92ba4SVladimir Oltean lynx_lane_rmw(lane, LNaGCR0, 868*6dc92ba4SVladimir Oltean LNaGCR0_RRST_OFF | LNaGCR0_TRST_OFF, 869*6dc92ba4SVladimir Oltean LNaGCR0_RRST | LNaGCR0_TRST); 870*6dc92ba4SVladimir Oltean } 871*6dc92ba4SVladimir Oltean 872*6dc92ba4SVladimir Oltean static int lynx_10g_power_off(struct phy *phy) 873*6dc92ba4SVladimir Oltean { 874*6dc92ba4SVladimir Oltean struct lynx_lane *lane = phy_get_drvdata(phy); 875*6dc92ba4SVladimir Oltean 876*6dc92ba4SVladimir Oltean if (!lane->powered_up) 877*6dc92ba4SVladimir Oltean return 0; 878*6dc92ba4SVladimir Oltean 879*6dc92ba4SVladimir Oltean /* Issue a reset request with the power down bits set */ 880*6dc92ba4SVladimir Oltean lynx_lane_rmw(lane, LNaGCR0, 881*6dc92ba4SVladimir Oltean LNaGCR0_RRST_ON | LNaGCR0_TRST_ON | 882*6dc92ba4SVladimir Oltean LNaGCR0_RX_PD | LNaGCR0_TX_PD, 883*6dc92ba4SVladimir Oltean LNaGCR0_RRST | LNaGCR0_TRST | 884*6dc92ba4SVladimir Oltean LNaGCR0_RX_PD | LNaGCR0_TX_PD); 885*6dc92ba4SVladimir Oltean 886*6dc92ba4SVladimir Oltean /* The RM says to wait for at least 50ns */ 887*6dc92ba4SVladimir Oltean usleep_range(1, 2); 888*6dc92ba4SVladimir Oltean 889*6dc92ba4SVladimir Oltean lane->powered_up = false; 890*6dc92ba4SVladimir Oltean 891*6dc92ba4SVladimir Oltean return 0; 892*6dc92ba4SVladimir Oltean } 893*6dc92ba4SVladimir Oltean 894*6dc92ba4SVladimir Oltean static int lynx_10g_power_on(struct phy *phy) 895*6dc92ba4SVladimir Oltean { 896*6dc92ba4SVladimir Oltean struct lynx_lane *lane = phy_get_drvdata(phy); 897*6dc92ba4SVladimir Oltean 898*6dc92ba4SVladimir Oltean if (lane->powered_up) 899*6dc92ba4SVladimir Oltean return 0; 900*6dc92ba4SVladimir Oltean 901*6dc92ba4SVladimir Oltean /* RM says that to enable a previously powered down lane, set 902*6dc92ba4SVladimir Oltean * LNmGCR0[{R,T}X_PD]=0, wait 15 us, then set LNmGCR0[{R,T}RST]=1. 903*6dc92ba4SVladimir Oltean */ 904*6dc92ba4SVladimir Oltean lynx_lane_rmw(lane, LNaGCR0, 0, LNaGCR0_RX_PD | LNaGCR0_TX_PD); 905*6dc92ba4SVladimir Oltean usleep_range(150, 300); 906*6dc92ba4SVladimir Oltean lynx_10g_lane_reset(phy); 907*6dc92ba4SVladimir Oltean 908*6dc92ba4SVladimir Oltean lane->powered_up = true; 909*6dc92ba4SVladimir Oltean 910*6dc92ba4SVladimir Oltean return 0; 911*6dc92ba4SVladimir Oltean } 912*6dc92ba4SVladimir Oltean 913*6dc92ba4SVladimir Oltean static void lynx_10g_lane_set_nrate(struct lynx_lane *lane, 914*6dc92ba4SVladimir Oltean struct lynx_pll *pll, 915*6dc92ba4SVladimir Oltean enum lynx_lane_mode mode) 916*6dc92ba4SVladimir Oltean { 917*6dc92ba4SVladimir Oltean enum lynx_10g_rat_sel nrate; 918*6dc92ba4SVladimir Oltean 919*6dc92ba4SVladimir Oltean switch (pll->frate_sel) { 920*6dc92ba4SVladimir Oltean case PLLnCR0_FRATE_5G: 921*6dc92ba4SVladimir Oltean switch (mode) { 922*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 923*6dc92ba4SVladimir Oltean nrate = RAT_SEL_QUARTER; 924*6dc92ba4SVladimir Oltean break; 925*6dc92ba4SVladimir Oltean case LANE_MODE_QSGMII: 926*6dc92ba4SVladimir Oltean nrate = RAT_SEL_FULL; 927*6dc92ba4SVladimir Oltean break; 928*6dc92ba4SVladimir Oltean default: 929*6dc92ba4SVladimir Oltean return; 930*6dc92ba4SVladimir Oltean } 931*6dc92ba4SVladimir Oltean break; 932*6dc92ba4SVladimir Oltean case PLLnCR0_FRATE_3_125G: 933*6dc92ba4SVladimir Oltean switch (mode) { 934*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 935*6dc92ba4SVladimir Oltean nrate = RAT_SEL_FULL; 936*6dc92ba4SVladimir Oltean break; 937*6dc92ba4SVladimir Oltean default: 938*6dc92ba4SVladimir Oltean return; 939*6dc92ba4SVladimir Oltean } 940*6dc92ba4SVladimir Oltean break; 941*6dc92ba4SVladimir Oltean case PLLnCR0_FRATE_5_15625G: 942*6dc92ba4SVladimir Oltean switch (mode) { 943*6dc92ba4SVladimir Oltean case LANE_MODE_10GBASER: 944*6dc92ba4SVladimir Oltean case LANE_MODE_USXGMII: 945*6dc92ba4SVladimir Oltean case LANE_MODE_10G_QXGMII: 946*6dc92ba4SVladimir Oltean nrate = RAT_SEL_DOUBLE; 947*6dc92ba4SVladimir Oltean break; 948*6dc92ba4SVladimir Oltean default: 949*6dc92ba4SVladimir Oltean return; 950*6dc92ba4SVladimir Oltean } 951*6dc92ba4SVladimir Oltean break; 952*6dc92ba4SVladimir Oltean default: 953*6dc92ba4SVladimir Oltean return; 954*6dc92ba4SVladimir Oltean } 955*6dc92ba4SVladimir Oltean 956*6dc92ba4SVladimir Oltean lynx_lane_rmw(lane, LNaGCR0, 957*6dc92ba4SVladimir Oltean FIELD_PREP(LNaGCR0_TRAT_SEL, nrate) | 958*6dc92ba4SVladimir Oltean FIELD_PREP(LNaGCR0_RRAT_SEL, nrate), 959*6dc92ba4SVladimir Oltean LNaGCR0_RRAT_SEL | LNaGCR0_TRAT_SEL); 960*6dc92ba4SVladimir Oltean } 961*6dc92ba4SVladimir Oltean 962*6dc92ba4SVladimir Oltean static void lynx_10g_lane_set_pll(struct lynx_lane *lane, 963*6dc92ba4SVladimir Oltean struct lynx_pll *pll) 964*6dc92ba4SVladimir Oltean { 965*6dc92ba4SVladimir Oltean if (pll->id == 0) { 966*6dc92ba4SVladimir Oltean lynx_lane_rmw(lane, LNaGCR0, 967*6dc92ba4SVladimir Oltean LNaGCR0_RPLL_PLLF | LNaGCR0_TPLL_PLLF, 968*6dc92ba4SVladimir Oltean LNaGCR0_RPLL_MSK | LNaGCR0_TPLL_MSK); 969*6dc92ba4SVladimir Oltean } else { 970*6dc92ba4SVladimir Oltean lynx_lane_rmw(lane, LNaGCR0, 971*6dc92ba4SVladimir Oltean LNaGCR0_RPLL_PLLS | LNaGCR0_TPLL_PLLS, 972*6dc92ba4SVladimir Oltean LNaGCR0_RPLL_MSK | LNaGCR0_TPLL_MSK); 973*6dc92ba4SVladimir Oltean } 974*6dc92ba4SVladimir Oltean } 975*6dc92ba4SVladimir Oltean 976*6dc92ba4SVladimir Oltean static void lynx_10g_lane_remap_pll(struct lynx_lane *lane, 977*6dc92ba4SVladimir Oltean enum lynx_lane_mode lane_mode) 978*6dc92ba4SVladimir Oltean { 979*6dc92ba4SVladimir Oltean struct lynx_priv *priv = lane->priv; 980*6dc92ba4SVladimir Oltean struct lynx_pll *pll; 981*6dc92ba4SVladimir Oltean 982*6dc92ba4SVladimir Oltean /* Switch to the PLL that works with this interface type */ 983*6dc92ba4SVladimir Oltean pll = lynx_pll_get(priv, lane_mode); 984*6dc92ba4SVladimir Oltean if (unlikely(!pll)) 985*6dc92ba4SVladimir Oltean return; 986*6dc92ba4SVladimir Oltean 987*6dc92ba4SVladimir Oltean lynx_10g_lane_set_pll(lane, pll); 988*6dc92ba4SVladimir Oltean 989*6dc92ba4SVladimir Oltean /* Choose the portion of clock net to be used on this lane */ 990*6dc92ba4SVladimir Oltean lynx_10g_lane_set_nrate(lane, pll, lane_mode); 991*6dc92ba4SVladimir Oltean } 992*6dc92ba4SVladimir Oltean 993*6dc92ba4SVladimir Oltean static void lynx_10g_lane_change_proto_conf(struct lynx_lane *lane, 994*6dc92ba4SVladimir Oltean enum lynx_lane_mode mode) 995*6dc92ba4SVladimir Oltean { 996*6dc92ba4SVladimir Oltean const struct lynx_10g_proto_conf *conf = &lynx_10g_proto_conf[mode]; 997*6dc92ba4SVladimir Oltean 998*6dc92ba4SVladimir Oltean lynx_lane_rmw(lane, LNaGCR0, 999*6dc92ba4SVladimir Oltean FIELD_PREP(LNaGCR0_PROTS, conf->proto_sel) | 1000*6dc92ba4SVladimir Oltean FIELD_PREP(LNaGCR0_IF20BIT_EN, conf->if20bit_en), 1001*6dc92ba4SVladimir Oltean LNaGCR0_PROTS | LNaGCR0_IF20BIT_EN); 1002*6dc92ba4SVladimir Oltean lynx_lane_rmw(lane, LNaGCR1, 1003*6dc92ba4SVladimir Oltean FIELD_PREP(LNaGCR1_REIDL_TH, conf->reidl_th) | 1004*6dc92ba4SVladimir Oltean FIELD_PREP(LNaGCR1_REIDL_ET_MSB, conf->reidl_et_msb) | 1005*6dc92ba4SVladimir Oltean FIELD_PREP(LNaGCR1_REIDL_ET_SEL, conf->reidl_et_sel) | 1006*6dc92ba4SVladimir Oltean FIELD_PREP(LNaGCR1_REIDL_EX_MSB, conf->reidl_ex_msb) | 1007*6dc92ba4SVladimir Oltean FIELD_PREP(LNaGCR1_REIDL_EX_SEL, conf->reidl_ex_sel) | 1008*6dc92ba4SVladimir Oltean FIELD_PREP(LNaGCR1_ISLEW_RCTL, conf->islew_rctl) | 1009*6dc92ba4SVladimir Oltean FIELD_PREP(LNaGCR1_OSLEW_RCTL, conf->oslew_rctl), 1010*6dc92ba4SVladimir Oltean LNaGCR1_REIDL_TH | 1011*6dc92ba4SVladimir Oltean LNaGCR1_REIDL_ET_MSB | LNaGCR1_REIDL_ET_SEL | 1012*6dc92ba4SVladimir Oltean LNaGCR1_REIDL_EX_MSB | LNaGCR1_REIDL_EX_SEL | 1013*6dc92ba4SVladimir Oltean LNaGCR1_ISLEW_RCTL | LNaGCR1_OSLEW_RCTL); 1014*6dc92ba4SVladimir Oltean lynx_lane_rmw(lane, LNaRECR0, 1015*6dc92ba4SVladimir Oltean FIELD_PREP(LNaRECR0_RXEQ_BST, conf->rxeq_bst) | 1016*6dc92ba4SVladimir Oltean FIELD_PREP(LNaRECR0_GK2OVD, conf->gk2ovd) | 1017*6dc92ba4SVladimir Oltean FIELD_PREP(LNaRECR0_GK3OVD, conf->gk3ovd) | 1018*6dc92ba4SVladimir Oltean FIELD_PREP(LNaRECR0_GK2OVD_EN, conf->gk2ovd_en) | 1019*6dc92ba4SVladimir Oltean FIELD_PREP(LNaRECR0_GK3OVD_EN, conf->gk3ovd_en) | 1020*6dc92ba4SVladimir Oltean FIELD_PREP(LNaRECR0_BASE_WAND, conf->base_wand), 1021*6dc92ba4SVladimir Oltean LNaRECR0_RXEQ_BST | LNaRECR0_GK2OVD | LNaRECR0_GK3OVD | 1022*6dc92ba4SVladimir Oltean LNaRECR0_GK2OVD_EN | LNaRECR0_GK3OVD_EN | 1023*6dc92ba4SVladimir Oltean LNaRECR0_BASE_WAND); 1024*6dc92ba4SVladimir Oltean lynx_lane_rmw(lane, LNaTECR0, 1025*6dc92ba4SVladimir Oltean FIELD_PREP(LNaTECR0_TEQ_TYPE, conf->teq_type) | 1026*6dc92ba4SVladimir Oltean FIELD_PREP(LNaTECR0_SGN_PREQ, conf->sgn_preq) | 1027*6dc92ba4SVladimir Oltean FIELD_PREP(LNaTECR0_RATIO_PREQ, conf->ratio_preq) | 1028*6dc92ba4SVladimir Oltean FIELD_PREP(LNaTECR0_SGN_POST1Q, conf->sgn_post1q) | 1029*6dc92ba4SVladimir Oltean FIELD_PREP(LNaTECR0_RATIO_PST1Q, conf->ratio_post1q) | 1030*6dc92ba4SVladimir Oltean FIELD_PREP(LNaTECR0_ADPT_EQ, conf->adpt_eq) | 1031*6dc92ba4SVladimir Oltean FIELD_PREP(LNaTECR0_AMP_RED, conf->amp_red), 1032*6dc92ba4SVladimir Oltean LNaTECR0_TEQ_TYPE | LNaTECR0_SGN_PREQ | 1033*6dc92ba4SVladimir Oltean LNaTECR0_RATIO_PREQ | LNaTECR0_SGN_POST1Q | 1034*6dc92ba4SVladimir Oltean LNaTECR0_RATIO_PST1Q | LNaTECR0_ADPT_EQ | 1035*6dc92ba4SVladimir Oltean LNaTECR0_AMP_RED); 1036*6dc92ba4SVladimir Oltean lynx_lane_write(lane, LNaTTLCR0, conf->ttlcr0); 1037*6dc92ba4SVladimir Oltean } 1038*6dc92ba4SVladimir Oltean 1039*6dc92ba4SVladimir Oltean static int lynx_10g_lane_disable_pcvt(struct lynx_lane *lane, 1040*6dc92ba4SVladimir Oltean enum lynx_lane_mode mode) 1041*6dc92ba4SVladimir Oltean { 1042*6dc92ba4SVladimir Oltean struct lynx_priv *priv = lane->priv; 1043*6dc92ba4SVladimir Oltean int err; 1044*6dc92ba4SVladimir Oltean 1045*6dc92ba4SVladimir Oltean spin_lock(&priv->pcc_lock); 1046*6dc92ba4SVladimir Oltean 1047*6dc92ba4SVladimir Oltean err = lynx_pccr_write(lane, mode, 0); 1048*6dc92ba4SVladimir Oltean if (err) 1049*6dc92ba4SVladimir Oltean goto out; 1050*6dc92ba4SVladimir Oltean 1051*6dc92ba4SVladimir Oltean switch (mode) { 1052*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 1053*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 1054*6dc92ba4SVladimir Oltean err = lynx_pcvt_rmw(lane, mode, CR(1), SGMIIaCR1_SGPCS_DIS, 1055*6dc92ba4SVladimir Oltean SGMIIaCR1_SGPCS_EN); 1056*6dc92ba4SVladimir Oltean if (err) 1057*6dc92ba4SVladimir Oltean goto out; 1058*6dc92ba4SVladimir Oltean 1059*6dc92ba4SVladimir Oltean lynx_pcvt_rmw(lane, mode, CR(0), 1060*6dc92ba4SVladimir Oltean SGMIIaCR0_RST_SGM_ON | SGMIIaCR0_PD_SGM, 1061*6dc92ba4SVladimir Oltean SGMIIaCR0_RST_SGM | SGMIIaCR0_PD_SGM); 1062*6dc92ba4SVladimir Oltean break; 1063*6dc92ba4SVladimir Oltean case LANE_MODE_QSGMII: 1064*6dc92ba4SVladimir Oltean err = lynx_pcvt_rmw(lane, mode, CR(0), 1065*6dc92ba4SVladimir Oltean QSGMIIaCR0_RST_QSGM_ON | QSGMIIaCR0_PD_QSGM, 1066*6dc92ba4SVladimir Oltean QSGMIIaCR0_RST_QSGM | QSGMIIaCR0_PD_QSGM); 1067*6dc92ba4SVladimir Oltean if (err) 1068*6dc92ba4SVladimir Oltean goto out; 1069*6dc92ba4SVladimir Oltean break; 1070*6dc92ba4SVladimir Oltean default: 1071*6dc92ba4SVladimir Oltean err = 0; 1072*6dc92ba4SVladimir Oltean } 1073*6dc92ba4SVladimir Oltean 1074*6dc92ba4SVladimir Oltean out: 1075*6dc92ba4SVladimir Oltean spin_unlock(&priv->pcc_lock); 1076*6dc92ba4SVladimir Oltean 1077*6dc92ba4SVladimir Oltean return err; 1078*6dc92ba4SVladimir Oltean } 1079*6dc92ba4SVladimir Oltean 1080*6dc92ba4SVladimir Oltean static int lynx_10g_lane_enable_pcvt(struct lynx_lane *lane, 1081*6dc92ba4SVladimir Oltean enum lynx_lane_mode mode) 1082*6dc92ba4SVladimir Oltean { 1083*6dc92ba4SVladimir Oltean struct lynx_priv *priv = lane->priv; 1084*6dc92ba4SVladimir Oltean u32 val; 1085*6dc92ba4SVladimir Oltean int err; 1086*6dc92ba4SVladimir Oltean 1087*6dc92ba4SVladimir Oltean spin_lock(&priv->pcc_lock); 1088*6dc92ba4SVladimir Oltean 1089*6dc92ba4SVladimir Oltean switch (mode) { 1090*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 1091*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 1092*6dc92ba4SVladimir Oltean err = lynx_pcvt_rmw(lane, mode, CR(1), SGMIIaCR1_SGPCS_EN, 1093*6dc92ba4SVladimir Oltean SGMIIaCR1_SGPCS_EN); 1094*6dc92ba4SVladimir Oltean if (err) 1095*6dc92ba4SVladimir Oltean goto out; 1096*6dc92ba4SVladimir Oltean 1097*6dc92ba4SVladimir Oltean lynx_pcvt_rmw(lane, mode, CR(0), SGMIIaCR0_RST_SGM_OFF, 1098*6dc92ba4SVladimir Oltean SGMIIaCR0_RST_SGM | SGMIIaCR0_PD_SGM); 1099*6dc92ba4SVladimir Oltean break; 1100*6dc92ba4SVladimir Oltean case LANE_MODE_QSGMII: 1101*6dc92ba4SVladimir Oltean err = lynx_pcvt_rmw(lane, mode, CR(0), QSGMIIaCR0_RST_QSGM_OFF, 1102*6dc92ba4SVladimir Oltean QSGMIIaCR0_RST_QSGM | QSGMIIaCR0_PD_QSGM); 1103*6dc92ba4SVladimir Oltean if (err) 1104*6dc92ba4SVladimir Oltean goto out; 1105*6dc92ba4SVladimir Oltean break; 1106*6dc92ba4SVladimir Oltean default: 1107*6dc92ba4SVladimir Oltean err = 0; 1108*6dc92ba4SVladimir Oltean } 1109*6dc92ba4SVladimir Oltean 1110*6dc92ba4SVladimir Oltean /* If the PCS was enabled at boot time, use the backed up PCCR value to 1111*6dc92ba4SVladimir Oltean * re-enable it here, to preserve the muxing. 1112*6dc92ba4SVladimir Oltean */ 1113*6dc92ba4SVladimir Oltean if (lynx_10g_pccr_val_enabled(lane->default_pccr[mode])) { 1114*6dc92ba4SVladimir Oltean err = lynx_pccr_write(lane, mode, lane->default_pccr[mode]); 1115*6dc92ba4SVladimir Oltean goto out; 1116*6dc92ba4SVladimir Oltean } 1117*6dc92ba4SVladimir Oltean 1118*6dc92ba4SVladimir Oltean /* If the PCS was not enabled, set the PCCR to a default value which 1119*6dc92ba4SVladimir Oltean * enables it (1). The assumption is that this is the only PCS <-> 1120*6dc92ba4SVladimir Oltean * SerDes lane muxing value possible. 1121*6dc92ba4SVladimir Oltean * 1122*6dc92ba4SVladimir Oltean * This is mostly useful for SGMII <-> 10GBase-R major protocol 1123*6dc92ba4SVladimir Oltean * reconfiguration, where at boot time, either the SGMII or the 1124*6dc92ba4SVladimir Oltean * 10GBase-R PCS is enabled for the lane, but not both. 1125*6dc92ba4SVladimir Oltean * 1126*6dc92ba4SVladimir Oltean * In fact, if there are multiple lane muxing options, this function 1127*6dc92ba4SVladimir Oltean * will most likely not choose the right one. For correct functionality 1128*6dc92ba4SVladimir Oltean * there, we assume that the PCS we are enabling here was found enabled 1129*6dc92ba4SVladimir Oltean * at boot time (reset default, or through PBL, or...), and we preserve 1130*6dc92ba4SVladimir Oltean * its muxing through the default_pccr branch above. 1131*6dc92ba4SVladimir Oltean */ 1132*6dc92ba4SVladimir Oltean val = 0; 1133*6dc92ba4SVladimir Oltean 1134*6dc92ba4SVladimir Oltean switch (mode) { 1135*6dc92ba4SVladimir Oltean case LANE_MODE_1000BASEX_SGMII: 1136*6dc92ba4SVladimir Oltean case LANE_MODE_2500BASEX: 1137*6dc92ba4SVladimir Oltean val |= FIELD_PREP(PCCR8_SGMIIa_CFG, 1); 1138*6dc92ba4SVladimir Oltean break; 1139*6dc92ba4SVladimir Oltean case LANE_MODE_QSGMII: 1140*6dc92ba4SVladimir Oltean val |= FIELD_PREP(PCCR9_QSGMIIa_CFG, 1); 1141*6dc92ba4SVladimir Oltean break; 1142*6dc92ba4SVladimir Oltean case LANE_MODE_10G_QXGMII: 1143*6dc92ba4SVladimir Oltean val |= FIELD_PREP(PCCR9_QXGMIIa_CFG, 1); 1144*6dc92ba4SVladimir Oltean break; 1145*6dc92ba4SVladimir Oltean case LANE_MODE_10GBASER: 1146*6dc92ba4SVladimir Oltean val |= FIELD_PREP(PCCRB_XFIa_CFG, 1); 1147*6dc92ba4SVladimir Oltean break; 1148*6dc92ba4SVladimir Oltean case LANE_MODE_USXGMII: 1149*6dc92ba4SVladimir Oltean val |= FIELD_PREP(PCCRB_SXGMIIa_CFG, 1); 1150*6dc92ba4SVladimir Oltean break; 1151*6dc92ba4SVladimir Oltean default: 1152*6dc92ba4SVladimir Oltean err = 0; 1153*6dc92ba4SVladimir Oltean goto out; 1154*6dc92ba4SVladimir Oltean } 1155*6dc92ba4SVladimir Oltean 1156*6dc92ba4SVladimir Oltean err = lynx_pccr_write(lane, mode, val); 1157*6dc92ba4SVladimir Oltean out: 1158*6dc92ba4SVladimir Oltean spin_unlock(&priv->pcc_lock); 1159*6dc92ba4SVladimir Oltean 1160*6dc92ba4SVladimir Oltean return err; 1161*6dc92ba4SVladimir Oltean } 1162*6dc92ba4SVladimir Oltean 1163*6dc92ba4SVladimir Oltean static bool lynx_10g_lane_mode_needs_rcw_override(struct lynx_lane *lane, 1164*6dc92ba4SVladimir Oltean enum lynx_lane_mode new) 1165*6dc92ba4SVladimir Oltean { 1166*6dc92ba4SVladimir Oltean enum lynx_lane_mode curr = lane->mode; 1167*6dc92ba4SVladimir Oltean 1168*6dc92ba4SVladimir Oltean /* Major protocol changes, which involve changing the PCS connection to 1169*6dc92ba4SVladimir Oltean * the GMII MAC with the one to the XGMII MAC, require an RCW override 1170*6dc92ba4SVladimir Oltean * procedure to reconfigure an internal mux, as documented here: 1171*6dc92ba4SVladimir Oltean * https://lore.kernel.org/linux-phy/20230810102631.bvozjer3t67r67iy@skbuf/ 1172*6dc92ba4SVladimir Oltean * This is SoC-specific, and not yet implemented in drivers/soc/fsl/guts.c. 1173*6dc92ba4SVladimir Oltean * 1174*6dc92ba4SVladimir Oltean * So the supported set of protocols depends on the initial lane mode. 1175*6dc92ba4SVladimir Oltean * 1176*6dc92ba4SVladimir Oltean * Minor protocol changes (SGMII <-> 1000Base-X <-> 2500Base-X or 1177*6dc92ba4SVladimir Oltean * 10GBase-R <-> USXGMII) are supported. 1178*6dc92ba4SVladimir Oltean */ 1179*6dc92ba4SVladimir Oltean if ((lynx_lane_mode_uses_gmii_mac(curr) && 1180*6dc92ba4SVladimir Oltean lynx_lane_mode_uses_xgmii_mac(new)) || 1181*6dc92ba4SVladimir Oltean (lynx_lane_mode_uses_xgmii_mac(curr) && 1182*6dc92ba4SVladimir Oltean lynx_lane_mode_uses_gmii_mac(new))) 1183*6dc92ba4SVladimir Oltean return true; 1184*6dc92ba4SVladimir Oltean 1185*6dc92ba4SVladimir Oltean return false; 1186*6dc92ba4SVladimir Oltean } 1187*6dc92ba4SVladimir Oltean 1188*6dc92ba4SVladimir Oltean static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode, 1189*6dc92ba4SVladimir Oltean union phy_configure_opts *opts) 1190*6dc92ba4SVladimir Oltean { 1191*6dc92ba4SVladimir Oltean struct lynx_lane *lane = phy_get_drvdata(phy); 1192*6dc92ba4SVladimir Oltean enum lynx_lane_mode lane_mode; 1193*6dc92ba4SVladimir Oltean int err; 1194*6dc92ba4SVladimir Oltean 1195*6dc92ba4SVladimir Oltean err = lynx_phy_mode_to_lane_mode(phy, mode, submode, &lane_mode); 1196*6dc92ba4SVladimir Oltean if (err) 1197*6dc92ba4SVladimir Oltean return err; 1198*6dc92ba4SVladimir Oltean 1199*6dc92ba4SVladimir Oltean if (lynx_10g_lane_mode_needs_rcw_override(lane, lane_mode)) 1200*6dc92ba4SVladimir Oltean return -EINVAL; 1201*6dc92ba4SVladimir Oltean 1202*6dc92ba4SVladimir Oltean return 0; 1203*6dc92ba4SVladimir Oltean } 1204*6dc92ba4SVladimir Oltean 1205*6dc92ba4SVladimir Oltean static int lynx_10g_set_mode(struct phy *phy, enum phy_mode mode, int submode) 1206*6dc92ba4SVladimir Oltean { 1207*6dc92ba4SVladimir Oltean struct lynx_lane *lane = phy_get_drvdata(phy); 1208*6dc92ba4SVladimir Oltean bool powered_up = lane->powered_up; 1209*6dc92ba4SVladimir Oltean enum lynx_lane_mode lane_mode; 1210*6dc92ba4SVladimir Oltean int err; 1211*6dc92ba4SVladimir Oltean 1212*6dc92ba4SVladimir Oltean err = lynx_10g_validate(phy, mode, submode, NULL); 1213*6dc92ba4SVladimir Oltean if (err) 1214*6dc92ba4SVladimir Oltean return err; 1215*6dc92ba4SVladimir Oltean 1216*6dc92ba4SVladimir Oltean lane_mode = phy_interface_to_lane_mode(submode); 1217*6dc92ba4SVladimir Oltean /* lynx_10g_validate() already made sure the lane_mode is supported */ 1218*6dc92ba4SVladimir Oltean 1219*6dc92ba4SVladimir Oltean if (lane_mode == lane->mode) 1220*6dc92ba4SVladimir Oltean return 0; 1221*6dc92ba4SVladimir Oltean 1222*6dc92ba4SVladimir Oltean /* If the lane is powered up, put the lane into the halt state while 1223*6dc92ba4SVladimir Oltean * the reconfiguration is being done. 1224*6dc92ba4SVladimir Oltean */ 1225*6dc92ba4SVladimir Oltean if (powered_up) 1226*6dc92ba4SVladimir Oltean lynx_10g_lane_halt(phy); 1227*6dc92ba4SVladimir Oltean 1228*6dc92ba4SVladimir Oltean err = lynx_10g_lane_disable_pcvt(lane, lane->mode); 1229*6dc92ba4SVladimir Oltean if (err) 1230*6dc92ba4SVladimir Oltean goto out; 1231*6dc92ba4SVladimir Oltean 1232*6dc92ba4SVladimir Oltean lynx_10g_lane_change_proto_conf(lane, lane_mode); 1233*6dc92ba4SVladimir Oltean lynx_10g_lane_remap_pll(lane, lane_mode); 1234*6dc92ba4SVladimir Oltean WARN_ON(lynx_10g_lane_enable_pcvt(lane, lane_mode)); 1235*6dc92ba4SVladimir Oltean 1236*6dc92ba4SVladimir Oltean lane->mode = lane_mode; 1237*6dc92ba4SVladimir Oltean 1238*6dc92ba4SVladimir Oltean out: 1239*6dc92ba4SVladimir Oltean if (powered_up) { 1240*6dc92ba4SVladimir Oltean /* The RM says to wait for at least 120 ns */ 1241*6dc92ba4SVladimir Oltean usleep_range(1, 2); 1242*6dc92ba4SVladimir Oltean lynx_10g_lane_reset(phy); 1243*6dc92ba4SVladimir Oltean } 1244*6dc92ba4SVladimir Oltean 1245*6dc92ba4SVladimir Oltean return err; 1246*6dc92ba4SVladimir Oltean } 1247*6dc92ba4SVladimir Oltean 1248*6dc92ba4SVladimir Oltean static int lynx_10g_init(struct phy *phy) 1249*6dc92ba4SVladimir Oltean { 1250*6dc92ba4SVladimir Oltean struct lynx_lane *lane = phy_get_drvdata(phy); 1251*6dc92ba4SVladimir Oltean 1252*6dc92ba4SVladimir Oltean /* Mark the fact that the lane was init */ 1253*6dc92ba4SVladimir Oltean lane->init = true; 1254*6dc92ba4SVladimir Oltean 1255*6dc92ba4SVladimir Oltean /* SerDes lanes are powered on at boot time. Any lane that is 1256*6dc92ba4SVladimir Oltean * managed by this driver will get powered off when its consumer 1257*6dc92ba4SVladimir Oltean * calls phy_init(). 1258*6dc92ba4SVladimir Oltean */ 1259*6dc92ba4SVladimir Oltean lane->powered_up = true; 1260*6dc92ba4SVladimir Oltean lynx_10g_power_off(phy); 1261*6dc92ba4SVladimir Oltean 1262*6dc92ba4SVladimir Oltean return 0; 1263*6dc92ba4SVladimir Oltean } 1264*6dc92ba4SVladimir Oltean 1265*6dc92ba4SVladimir Oltean static int lynx_10g_exit(struct phy *phy) 1266*6dc92ba4SVladimir Oltean { 1267*6dc92ba4SVladimir Oltean struct lynx_lane *lane = phy_get_drvdata(phy); 1268*6dc92ba4SVladimir Oltean 1269*6dc92ba4SVladimir Oltean /* The lane returns to the state where it isn't managed by the 1270*6dc92ba4SVladimir Oltean * consumer, so we must treat is as if it isn't initialized, and always 1271*6dc92ba4SVladimir Oltean * powered on. 1272*6dc92ba4SVladimir Oltean */ 1273*6dc92ba4SVladimir Oltean lane->init = false; 1274*6dc92ba4SVladimir Oltean lane->powered_up = false; 1275*6dc92ba4SVladimir Oltean lynx_10g_power_on(phy); 1276*6dc92ba4SVladimir Oltean 1277*6dc92ba4SVladimir Oltean return 0; 1278*6dc92ba4SVladimir Oltean } 1279*6dc92ba4SVladimir Oltean 1280*6dc92ba4SVladimir Oltean static const struct phy_ops lynx_10g_ops = { 1281*6dc92ba4SVladimir Oltean .init = lynx_10g_init, 1282*6dc92ba4SVladimir Oltean .exit = lynx_10g_exit, 1283*6dc92ba4SVladimir Oltean .power_on = lynx_10g_power_on, 1284*6dc92ba4SVladimir Oltean .power_off = lynx_10g_power_off, 1285*6dc92ba4SVladimir Oltean .set_mode = lynx_10g_set_mode, 1286*6dc92ba4SVladimir Oltean .validate = lynx_10g_validate, 1287*6dc92ba4SVladimir Oltean .owner = THIS_MODULE, 1288*6dc92ba4SVladimir Oltean }; 1289*6dc92ba4SVladimir Oltean 1290*6dc92ba4SVladimir Oltean static int lynx_10g_probe(struct platform_device *pdev) 1291*6dc92ba4SVladimir Oltean { 1292*6dc92ba4SVladimir Oltean return lynx_probe(pdev, of_device_get_match_data(&pdev->dev), 1293*6dc92ba4SVladimir Oltean &lynx_10g_ops); 1294*6dc92ba4SVladimir Oltean } 1295*6dc92ba4SVladimir Oltean 1296*6dc92ba4SVladimir Oltean static const struct of_device_id lynx_10g_of_match_table[] = { 1297*6dc92ba4SVladimir Oltean { .compatible = "fsl,ls1028a-serdes", .data = &lynx_info_ls1028a }, 1298*6dc92ba4SVladimir Oltean { .compatible = "fsl,ls1046a-serdes1", .data = &lynx_info_ls1046a_serdes1 }, 1299*6dc92ba4SVladimir Oltean { .compatible = "fsl,ls1046a-serdes2", .data = &lynx_info_ls1046a_serdes2 }, 1300*6dc92ba4SVladimir Oltean { .compatible = "fsl,ls1088a-serdes1", .data = &lynx_info_ls1088a_serdes1 }, 1301*6dc92ba4SVladimir Oltean { .compatible = "fsl,ls2088a-serdes1", .data = &lynx_info_ls2088a_serdes1 }, 1302*6dc92ba4SVladimir Oltean { .compatible = "fsl,ls2088a-serdes2", .data = &lynx_info_ls2088a_serdes2 }, 1303*6dc92ba4SVladimir Oltean {} 1304*6dc92ba4SVladimir Oltean }; 1305*6dc92ba4SVladimir Oltean MODULE_DEVICE_TABLE(of, lynx_10g_of_match_table); 1306*6dc92ba4SVladimir Oltean 1307*6dc92ba4SVladimir Oltean static struct platform_driver lynx_10g_driver = { 1308*6dc92ba4SVladimir Oltean .probe = lynx_10g_probe, 1309*6dc92ba4SVladimir Oltean .remove = lynx_remove, 1310*6dc92ba4SVladimir Oltean .driver = { 1311*6dc92ba4SVladimir Oltean .name = "lynx-10g", 1312*6dc92ba4SVladimir Oltean .of_match_table = lynx_10g_of_match_table, 1313*6dc92ba4SVladimir Oltean }, 1314*6dc92ba4SVladimir Oltean }; 1315*6dc92ba4SVladimir Oltean module_platform_driver(lynx_10g_driver); 1316*6dc92ba4SVladimir Oltean 1317*6dc92ba4SVladimir Oltean MODULE_IMPORT_NS("PHY_FSL_LYNX"); 1318*6dc92ba4SVladimir Oltean MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>"); 1319*6dc92ba4SVladimir Oltean MODULE_AUTHOR("Vladimir Oltean <vladimir.oltean@nxp.com>"); 1320*6dc92ba4SVladimir Oltean MODULE_DESCRIPTION("Lynx 10G SerDes PHY driver for Layerscape SoCs"); 1321*6dc92ba4SVladimir Oltean MODULE_LICENSE("GPL"); 1322