| Author | Tokens | Token Proportion | Commits | Commit Proportion |
|---|---|---|---|---|
| Vladimir Oltean | 3336 | 69.38% | 25 | 75.76% |
| Ioana Ciornei | 1455 | 30.26% | 4 | 12.12% |
| Josua Mayer | 12 | 0.25% | 1 | 3.03% |
| Thierry Reding | 3 | 0.06% | 1 | 3.03% |
| Krzysztof Kozlowski | 1 | 0.02% | 1 | 3.03% |
| Uwe Kleine-König | 1 | 0.02% | 1 | 3.03% |
| Total | 4808 | 33 |
// SPDX-License-Identifier: GPL-2.0+ /* Copyright (c) 2021-2022 NXP. */ #include <linux/bitfield.h> #include <linux/module.h> #include <linux/of.h> #include <linux/phy.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/workqueue.h> #include "phy-fsl-lynx-core.h" #define LYNX_28G_NUM_LANE 8 /* SoC IP wrapper for protocol converters */ #define PCC8 0x10a0 #define PCC8_SGMIIa_KX BIT(3) #define PCC8_SGMIIa_CFG BIT(0) #define PCCC 0x10b0 #define PCCC_SXGMIIn_XFI BIT(3) #define PCCC_SXGMIIn_CFG BIT(0) #define PCCD 0x10b4 #define PCCD_E25Gn_CFG BIT(0) #define PCCE 0x10b8 #define PCCE_E40Gn_LRV BIT(3) #define PCCE_E40Gn_CFG BIT(0) #define PCCE_E50Gn_LRV BIT(3) #define PCCE_E50GnCFG BIT(0) #define PCCE_E100Gn_LRV BIT(3) #define PCCE_E100Gn_CFG BIT(0) #define SGMII_CFG(id) (28 - (id) * 4) /* Offset into PCC8 */ #define SXGMII_CFG(id) (28 - (id) * 4) /* Offset into PCCC */ #define E25G_CFG(id) (28 - (id) * 4) /* Offset into PCCD */ #define E40G_CFG(id) (28 - (id) * 4) /* Offset into PCCE */ #define E50G_CFG(id) (20 - (id) * 4) /* Offset into PCCE */ #define E100G_CFG(id) (12 - (id) * 4) /* Offset into PCCE */ /* Per PLL registers */ #define PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0) #define PLLnRSTCTL_DIS BIT(24) #define PLLnRSTCTL_LOCK BIT(23) #define PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4) #define PLLnCR0_REFCLK_SEL GENMASK(20, 16) #define PLLnCR0_REFCLK_SEL_100MHZ 0x0 #define PLLnCR0_REFCLK_SEL_125MHZ 0x1 #define PLLnCR0_REFCLK_SEL_156MHZ 0x2 #define PLLnCR0_REFCLK_SEL_150MHZ 0x3 #define PLLnCR0_REFCLK_SEL_161MHZ 0x4 #define PLLnCR1(pll) (0x400 + (pll) * 0x100 + 0x8) #define PLLnCR1_FRATE_SEL GENMASK(28, 24) #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 */ #define LNaGCR0(lane) (0x800 + (lane) * 0x100 + 0x0) #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) #define LNaTRSTCTL_RST_REQ BIT(31) #define LNaTRSTCTL_RST_DONE BIT(30) #define LNaTRSTCTL_HLT_REQ BIT(27) #define LNaTRSTCTL_STP_REQ BIT(26) #define LNaTRSTCTL_DIS BIT(24) /* Lane a Tx General Control Register */ #define LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24) #define LNaTGCR0_USE_PLL BIT(28) #define LNaTGCR0_USE_PLLF 0x0 #define LNaTGCR0_USE_PLLS 0x1 #define LNaTGCR0_N_RATE GENMASK(26, 24) #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) #define LNaTECR0_EQ_SGN_PREQ BIT(23) #define LNaTECR0_EQ_PREQ GENMASK(19, 16) #define LNaTECR0_EQ_SGN_POST1Q BIT(15) #define LNaTECR0_EQ_POST1Q GENMASK(12, 8) #define LNaTECR0_EQ_AMP_RED GENMASK(5, 0) #define LNaTECR1(lane) (0x800 + (lane) * 0x100 + 0x34) #define LNaTECR1_EQ_ADPT_EQ_DRVR_DIS BIT(31) #define LNaTECR1_EQ_ADPT_EQ GENMASK(29, 24) /* Lane a Rx Reset Control Register */ #define LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40) #define LNaRRSTCTL_RST_REQ BIT(31) #define LNaRRSTCTL_RST_DONE BIT(30) #define LNaRRSTCTL_HLT_REQ BIT(27) #define LNaRRSTCTL_STP_REQ BIT(26) #define LNaRRSTCTL_DIS BIT(24) #define LNaRRSTCTL_CDR_LOCK BIT(12) /* Lane a Rx General Control Register */ #define LNaRGCR0(lane) (0x800 + (lane) * 0x100 + 0x44) #define LNaRGCR0_USE_PLL BIT(28) #define LNaRGCR0_USE_PLLF 0x0 #define LNaRGCR0_USE_PLLS 0x1 #define LNaRGCR0_N_RATE GENMASK(26, 24) #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) #define LNaRGCR1_DATA_LOST_FLT BIT(30) #define LNaRGCR1_DATA_LOST BIT(29) #define LNaRGCR1_IDLE_CONFIG BIT(28) #define LNaRGCR1_ENTER_IDLE_FLT_SEL GENMASK(26, 24) #define LNaRGCR1_EXIT_IDLE_FLT_SEL GENMASK(22, 20) #define LNaRGCR1_DATA_LOST_TH_SEL GENMASK(18, 16) #define LNaRGCR1_EXT_REC_CLK_SEL GENMASK(10, 8) #define LNaRGCR1_WAKE_TX_DIS BIT(5) #define LNaRGCR1_PHY_RDY BIT(4) #define LNaRGCR1_CHANGE_RX_CLK BIT(3) #define LNaRGCR1_PWR_MGT GENMASK(2, 0) #define LNaRECR0(lane) (0x800 + (lane) * 0x100 + 0x50) #define LNaRECR0_EQ_GAINK2_HF_OV_EN BIT(31) #define LNaRECR0_EQ_GAINK2_HF_OV GENMASK(28, 24) #define LNaRECR0_EQ_GAINK3_MF_OV_EN BIT(23) #define LNaRECR0_EQ_GAINK3_MF_OV GENMASK(20, 16) #define LNaRECR0_EQ_GAINK4_LF_OV_EN BIT(7) #define LNaRECR0_EQ_GAINK4_LF_DIS BIT(6) #define LNaRECR0_EQ_GAINK4_LF_OV GENMASK(4, 0) #define LNaRECR1(lane) (0x800 + (lane) * 0x100 + 0x54) #define LNaRECR1_EQ_BLW_OV_EN BIT(31) #define LNaRECR1_EQ_BLW_OV GENMASK(28, 24) #define LNaRECR1_EQ_OFFSET_OV_EN BIT(23) #define LNaRECR1_EQ_OFFSET_OV GENMASK(21, 16) #define LNaRECR2(lane) (0x800 + (lane) * 0x100 + 0x58) #define LNaRECR2_EQ_OFFSET_RNG_DBL BIT(31) #define LNaRECR2_EQ_BOOST GENMASK(29, 28) #define LNaRECR2_EQ_BLW_SEL GENMASK(25, 24) #define LNaRECR2_EQ_ZERO GENMASK(17, 16) #define LNaRECR2_EQ_IND GENMASK(13, 12) #define LNaRECR2_EQ_BIN_DATA_AVG_TC GENMASK(5, 4) #define LNaRECR2_SPARE_IN GENMASK(1, 0) #define LNaRECR3(lane) (0x800 + (lane) * 0x100 + 0x5c) #define LNaRECR3_EQ_SNAP_START BIT(31) #define LNaRECR3_EQ_SNAP_DONE BIT(30) #define LNaRECR3_EQ_GAINK2_HF_STAT GENMASK(28, 24) #define LNaRECR3_EQ_GAINK3_MF_STAT GENMASK(20, 16) #define LNaRECR3_SPARE_OUT GENMASK(13, 12) #define LNaRECR3_EQ_GAINK4_LF_STAT GENMASK(4, 0) #define LNaRECR4(lane) (0x800 + (lane) * 0x100 + 0x60) #define LNaRECR4_BLW_STAT GENMASK(28, 24) #define LNaRECR4_EQ_OFFSET_STAT GENMASK(21, 16) #define LNaRECR4_EQ_BIN_DATA_SEL GENMASK(15, 12) #define LNaRECR4_EQ_BIN_DATA GENMASK(8, 0) /* bit 9 is reserved */ #define LNaRECR4_EQ_BIN_DATA_SGN BIT(8) #define LNaRCCR0(lane) (0x800 + (lane) * 0x100 + 0x68) #define LNaRCCR0_CAL_EN BIT(31) #define LNaRCCR0_MEAS_EN BIT(30) #define LNaRCCR0_CAL_BIN_SEL BIT(28) #define LNaRCCR0_CAL_DC3_DIS BIT(27) #define LNaRCCR0_CAL_DC2_DIS BIT(26) #define LNaRCCR0_CAL_DC1_DIS BIT(25) #define LNaRCCR0_CAL_DC0_DIS BIT(24) #define LNaRCCR0_CAL_AC3_OV_EN BIT(15) #define LNaRCCR0_CAL_AC3_OV GENMASK(11, 8) #define LNaRCCR0_CAL_AC2_OV_EN BIT(7) #define LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74) #define LNaRSCCR0_SMP_OFF_EN BIT(31) #define LNaRSCCR0_SMP_OFF_OV_EN BIT(30) #define LNaRSCCR0_SMP_MAN_OFF_EN BIT(29) #define LNaRSCCR0_SMP_OFF_RNG_OV_EN BIT(27) #define LNaRSCCR0_SMP_OFF_RNG_4X_OV BIT(25) #define LNaRSCCR0_SMP_OFF_RNG_2X_OV BIT(24) #define LNaRSCCR0_SMP_AUTOZ_PD BIT(23) #define LNaRSCCR0_SMP_AUTOZ_CTRL GENMASK(19, 16) #define LNaRSCCR0_SMP_AUTOZ_D1R GENMASK(13, 12) #define LNaRSCCR0_SMP_AUTOZ_D1F GENMASK(9, 8) #define LNaRSCCR0_SMP_AUTOZ_EG1R GENMASK(5, 4) #define LNaRSCCR0_SMP_AUTOZ_EG1F GENMASK(1, 0) #define LNaTTLCR0(lane) (0x800 + (lane) * 0x100 + 0x80) #define LNaTTLCR0_TTL_FLT_SEL GENMASK(29, 24) #define LNaTTLCR0_TTL_SLO_PM_BYP BIT(22) #define LNaTTLCR0_STALL_DET_DIS BIT(21) #define LNaTTLCR0_INACT_MON_DIS BIT(20) #define LNaTTLCR0_CDR_OV GENMASK(18, 16) #define LNaTTLCR0_DATA_IN_SSC BIT(15) #define LNaTTLCR0_CDR_MIN_SMP_ON GENMASK(1, 0) #define LNaTCSR0(lane) (0x800 + (lane) * 0x100 + 0xa0) #define LNaTCSR0_SD_STAT_OBS_EN BIT(31) #define LNaTCSR0_SD_LPBK_SEL GENMASK(29, 28) #define LNaPSS(lane) (0x1000 + (lane) * 0x4) #define LNaPSS_TYPE GENMASK(30, 24) #define LNaPSS_TYPE_SGMII (PROTO_SEL_SGMII_BASEX_KX << 2) #define LNaPSS_TYPE_XFI (PROTO_SEL_XFI_10GBASER_KR_SXGMII << 2) #define LNaPSS_TYPE_40G ((PROTO_SEL_XFI_10GBASER_KR_SXGMII << 2) | 3) #define LNaPSS_TYPE_25G (PROTO_SEL_25G_50G_100G << 2) #define LNaPSS_TYPE_100G ((PROTO_SEL_25G_50G_100G << 2) | 2) /* MDEV_PORT is at the same bitfield address for all protocol converters */ #define MDEV_PORT GENMASK(31, 27) #define SGMIIaCR0(lane) (0x1800 + (lane) * 0x10) #define SGMIIaCR1(lane) (0x1804 + (lane) * 0x10) #define SGMIIaCR1_SGPCS_EN BIT(11) #define ANLTaCR0(lane) (0x1a00 + (lane) * 0x10) #define ANLTaCR1(lane) (0x1a04 + (lane) * 0x10) #define SXGMIIaCR0(lane) (0x1a80 + (lane) * 0x10) #define SXGMIIaCR0_RST BIT(31) #define SXGMIIaCR0_PD BIT(30) #define SXGMIIaCR1(lane) (0x1a84 + (lane) * 0x10) #define E25GaCR0(lane) (0x1b00 + (lane) * 0x10) #define E25GaCR0_RST BIT(31) #define E25GaCR0_PD BIT(30) #define E25GaCR1(lane) (0x1b04 + (lane) * 0x10) #define E25GaCR2(lane) (0x1b08 + (lane) * 0x10) #define E25GaCR2_FEC_ENA BIT(23) #define E25GaCR2_FEC_ERR_ENA BIT(22) #define E25GaCR2_FEC91_ENA BIT(20) #define E40GaCR0(pcvt) (0x1b40 + (pcvt) * 0x20) #define E40GaCR1(pcvt) (0x1b44 + (pcvt) * 0x20) #define E50GaCR1(pcvt) (0x1b84 + (pcvt) * 0x10) #define E100GaCR1(pcvt) (0x1c04 + (pcvt) * 0x20) #define CR(x) ((x) * 4) #define LYNX_28G_LANE_HALT_SLEEP_US 100 #define LYNX_28G_LANE_HALT_TIMEOUT_US 1000000 #define LYNX_28G_LANE_RESET_SLEEP_US 100 #define LYNX_28G_LANE_RESET_TIMEOUT_US 1000000 #define LYNX_28G_LANE_STOP_SLEEP_US 100 #define LYNX_28G_LANE_STOP_TIMEOUT_US 1000000 #define lynx_28g_lane_rmw lynx_lane_rmw #define lynx_28g_lane_read lynx_lane_read #define lynx_28g_lane_write lynx_lane_write #define lynx_28g_priv lynx_priv #define lynx_28g_lane lynx_lane #define lynx_28g_pll lynx_pll enum lynx_28g_eq_type { EQ_TYPE_NO_EQ = 0, EQ_TYPE_2TAP = 1, EQ_TYPE_3TAP = 2, }; enum lynx_28g_proto_sel { PROTO_SEL_PCIE = 0, PROTO_SEL_SGMII_BASEX_KX = 1, PROTO_SEL_SATA = 2, PROTO_SEL_XAUI = 4, PROTO_SEL_XFI_10GBASER_KR_SXGMII = 0xa, PROTO_SEL_25G_50G_100G = 0x1a, }; struct lynx_28g_proto_conf { /* LNaGCR0 */ int proto_sel; int if_width; /* LNaTECR0 */ int teq_type; int sgn_preq; int ratio_preq; int sgn_post1q; int ratio_post1q; int amp_red; /* LNaTECR1 */ int adpt_eq; /* LNaRGCR1 */ int enter_idle_flt_sel; int exit_idle_flt_sel; int data_lost_th_sel; /* LNaRECR0 */ int gk2ovd; int gk3ovd; int gk4ovd; int gk2ovd_en; int gk3ovd_en; int gk4ovd_en; /* LNaRECR1 ? */ int eq_offset_ovd; int eq_offset_ovd_en; /* LNaRECR2 */ int eq_offset_rng_dbl; int eq_blw_sel; int eq_boost; int spare_in; /* LNaRSCCR0 */ int smp_autoz_d1r; int smp_autoz_eg1r; /* LNaRCCR0 */ int rccr0; /* LNaTTLCR0 */ int ttlcr0; }; static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = { [LANE_MODE_1000BASEX_SGMII] = { .proto_sel = LNaGCR0_PROTO_SEL_SGMII, .if_width = LNaGCR0_IF_WIDTH_10_BIT, .teq_type = EQ_TYPE_NO_EQ, .sgn_preq = 1, .ratio_preq = 0, .sgn_post1q = 1, .ratio_post1q = 0, .amp_red = 6, .adpt_eq = 48, .enter_idle_flt_sel = 4, .exit_idle_flt_sel = 3, .data_lost_th_sel = 1, .gk2ovd = 0x1f, .gk3ovd = 0, .gk4ovd = 0, .gk2ovd_en = 1, .gk3ovd_en = 1, .gk4ovd_en = 0, .eq_offset_ovd = 0x1f, .eq_offset_ovd_en = 0, .eq_offset_rng_dbl = 0, .eq_blw_sel = 0, .eq_boost = 0, .spare_in = 0, .smp_autoz_d1r = 0, .smp_autoz_eg1r = 0, .rccr0 = LNaRCCR0_CAL_EN, .ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP | LNaTTLCR0_DATA_IN_SSC, }, [LANE_MODE_USXGMII] = { .proto_sel = LNaGCR0_PROTO_SEL_XFI, .if_width = LNaGCR0_IF_WIDTH_20_BIT, .teq_type = EQ_TYPE_2TAP, .sgn_preq = 1, .ratio_preq = 0, .sgn_post1q = 1, .ratio_post1q = 3, .amp_red = 7, .adpt_eq = 48, .enter_idle_flt_sel = 0, .exit_idle_flt_sel = 0, .data_lost_th_sel = 0, .gk2ovd = 0, .gk3ovd = 0, .gk4ovd = 0, .gk2ovd_en = 0, .gk3ovd_en = 0, .gk4ovd_en = 0, .eq_offset_ovd = 0x1f, .eq_offset_ovd_en = 0, .eq_offset_rng_dbl = 1, .eq_blw_sel = 1, .eq_boost = 0, .spare_in = 0, .smp_autoz_d1r = 2, .smp_autoz_eg1r = 0, .rccr0 = LNaRCCR0_CAL_EN, .ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP | LNaTTLCR0_DATA_IN_SSC, }, [LANE_MODE_10GBASER] = { .proto_sel = LNaGCR0_PROTO_SEL_XFI, .if_width = LNaGCR0_IF_WIDTH_20_BIT, .teq_type = EQ_TYPE_2TAP, .sgn_preq = 1, .ratio_preq = 0, .sgn_post1q = 1, .ratio_post1q = 3, .amp_red = 7, .adpt_eq = 48, .enter_idle_flt_sel = 0, .exit_idle_flt_sel = 0, .data_lost_th_sel = 0, .gk2ovd = 0, .gk3ovd = 0, .gk4ovd = 0, .gk2ovd_en = 0, .gk3ovd_en = 0, .gk4ovd_en = 0, .eq_offset_ovd = 0x1f, .eq_offset_ovd_en = 0, .eq_offset_rng_dbl = 1, .eq_blw_sel = 1, .eq_boost = 0, .spare_in = 0, .smp_autoz_d1r = 2, .smp_autoz_eg1r = 0, .rccr0 = LNaRCCR0_CAL_EN, .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), }, }; static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane, struct lynx_28g_pll *pll, enum lynx_lane_mode lane_mode) { switch (pll->frate_sel) { case PLLnCR1_FRATE_5G_10GVCO: case PLLnCR1_FRATE_5G_25GVCO: switch (lane_mode) { case LANE_MODE_1000BASEX_SGMII: lynx_28g_lane_rmw(lane, LNaTGCR0, FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_QUARTER), LNaTGCR0_N_RATE); lynx_28g_lane_rmw(lane, LNaRGCR0, FIELD_PREP(LNaRGCR0_N_RATE, LNaRGCR0_N_RATE_QUARTER), LNaRGCR0_N_RATE); break; default: break; } break; case PLLnCR1_FRATE_10G_20GVCO: switch (lane_mode) { case LANE_MODE_10GBASER: case LANE_MODE_USXGMII: lynx_28g_lane_rmw(lane, LNaTGCR0, FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_FULL), LNaTGCR0_N_RATE); lynx_28g_lane_rmw(lane, LNaRGCR0, FIELD_PREP(LNaRGCR0_N_RATE, LNaRGCR0_N_RATE_FULL), LNaRGCR0_N_RATE); break; default: 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; } } static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane, struct lynx_28g_pll *pll) { if (pll->id == 0) { lynx_28g_lane_rmw(lane, LNaTGCR0, FIELD_PREP(LNaTGCR0_USE_PLL, LNaTGCR0_USE_PLLF), LNaTGCR0_USE_PLL); lynx_28g_lane_rmw(lane, LNaRGCR0, FIELD_PREP(LNaRGCR0_USE_PLL, LNaRGCR0_USE_PLLF), LNaRGCR0_USE_PLL); } else { lynx_28g_lane_rmw(lane, LNaTGCR0, FIELD_PREP(LNaTGCR0_USE_PLL, LNaTGCR0_USE_PLLS), LNaTGCR0_USE_PLL); lynx_28g_lane_rmw(lane, LNaRGCR0, FIELD_PREP(LNaRGCR0_USE_PLL, LNaRGCR0_USE_PLLS), LNaRGCR0_USE_PLL); } } static bool lynx_28g_lane_halt_done(struct lynx_28g_lane *lane) { u32 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL); u32 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); return !(trstctl & LNaTRSTCTL_HLT_REQ) && !(rrstctl & LNaRRSTCTL_HLT_REQ); } static bool lynx_28g_lane_stop_done(struct lynx_28g_lane *lane) { u32 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL); u32 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); return !(trstctl & LNaTRSTCTL_STP_REQ) && !(rrstctl & LNaRRSTCTL_STP_REQ); } static bool lynx_28g_lane_reset_done(struct lynx_28g_lane *lane) { u32 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL); u32 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); return (trstctl & LNaTRSTCTL_RST_DONE) && (rrstctl & LNaRRSTCTL_RST_DONE); } /* Halting puts the lane in a mode in which it can be reconfigured */ static int lynx_28g_lane_halt(struct phy *phy) { struct lynx_28g_lane *lane = phy_get_drvdata(phy); bool done; int err; /* Issue a halt request */ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_HLT_REQ, LNaTRSTCTL_HLT_REQ); lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_HLT_REQ, LNaRRSTCTL_HLT_REQ); /* Wait until the halting process is complete */ err = read_poll_timeout(lynx_28g_lane_halt_done, done, done, LYNX_28G_LANE_HALT_SLEEP_US, LYNX_28G_LANE_HALT_TIMEOUT_US, false, lane); if (err) { dev_err(&phy->dev, "Lane %c halt failed: %pe\n", 'A' + lane->id, ERR_PTR(err)); } return err; } static int lynx_28g_lane_reset(struct phy *phy) { struct lynx_28g_lane *lane = phy_get_drvdata(phy); bool done; int err; /* Issue a reset request on the lane */ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_RST_REQ, LNaTRSTCTL_RST_REQ); lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_RST_REQ, LNaRRSTCTL_RST_REQ); /* Wait until the reset sequence is completed */ err = read_poll_timeout(lynx_28g_lane_reset_done, done, done, LYNX_28G_LANE_RESET_SLEEP_US, LYNX_28G_LANE_RESET_TIMEOUT_US, false, lane); if (err) { dev_err(&phy->dev, "Lane %c reset failed: %pe\n", 'A' + lane->id, ERR_PTR(err)); } return err; } static int lynx_28g_power_off(struct phy *phy) { struct lynx_28g_lane *lane = phy_get_drvdata(phy); bool done; int err; if (!lane->powered_up) return 0; /* Issue a stop request */ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_STP_REQ, LNaTRSTCTL_STP_REQ); lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_STP_REQ, LNaRRSTCTL_STP_REQ); /* Wait until the stop process is complete */ err = read_poll_timeout(lynx_28g_lane_stop_done, done, done, LYNX_28G_LANE_STOP_SLEEP_US, LYNX_28G_LANE_STOP_TIMEOUT_US, false, lane); if (err) { dev_err(&phy->dev, "Lane %c stop failed: %pe\n", 'A' + lane->id, ERR_PTR(err)); } /* Power down the RX and TX portions of the lane */ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_DIS, LNaRRSTCTL_DIS); lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_DIS, LNaTRSTCTL_DIS); lane->powered_up = false; return 0; } static int lynx_28g_power_on(struct phy *phy) { struct lynx_28g_lane *lane = phy_get_drvdata(phy); int err; if (lane->powered_up) return 0; /* Power up the RX and TX portions of the lane */ lynx_28g_lane_rmw(lane, LNaRRSTCTL, 0, LNaRRSTCTL_DIS); lynx_28g_lane_rmw(lane, LNaTRSTCTL, 0, LNaTRSTCTL_DIS); err = lynx_28g_lane_reset(phy); if (err) return err; lane->powered_up = true; 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) { switch (lane_mode) { case LANE_MODE_1000BASEX_SGMII: pccr->offset = PCC8; pccr->width = 4; pccr->shift = SGMII_CFG(lane); break; case LANE_MODE_USXGMII: case LANE_MODE_10GBASER: pccr->offset = PCCC; 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; } return 0; } static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode) { switch (lane_mode) { case LANE_MODE_1000BASEX_SGMII: return SGMIIaCR0(lane); 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; } } static bool lx2160a_serdes1_lane_supports_mode(int lane, enum lynx_lane_mode mode) { switch (mode) { case LANE_MODE_25GBASER: return lane != 2 && lane != 3; default: return true; } } static bool lx2160a_serdes2_lane_supports_mode(int lane, enum lynx_lane_mode mode) { switch (mode) { case LANE_MODE_1000BASEX_SGMII: return true; case LANE_MODE_USXGMII: case LANE_MODE_10GBASER: return lane == 6 || lane == 7; default: return false; } } static bool lx2160a_serdes3_lane_supports_mode(int lane, enum lynx_lane_mode mode) { /* * Non-networking SerDes, and this driver supports only * networking protocols */ return false; } static bool lx2162a_serdes1_lane_supports_mode(int lane, enum lynx_lane_mode mode) { return true; } static bool lx2162a_serdes2_lane_supports_mode(int lane, enum lynx_lane_mode mode) { return lx2160a_serdes2_lane_supports_mode(lane, mode); } /* Feature set is not expected to grow for the deprecated compatible string */ static bool lynx_28g_compat_lane_supports_mode(int lane, enum lynx_lane_mode mode) { switch (mode) { case LANE_MODE_1000BASEX_SGMII: case LANE_MODE_USXGMII: case LANE_MODE_10GBASER: return true; default: return false; } } static void lynx_28g_cdr_lock_check(struct lynx_lane *lane) { u32 rrstctl; int err; rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); if (!!(rrstctl & LNaRRSTCTL_CDR_LOCK)) return; lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_RST_REQ, LNaRRSTCTL_RST_REQ); err = read_poll_timeout(lynx_28g_lane_read, rrstctl, !!(rrstctl & LNaRRSTCTL_RST_DONE), LYNX_28G_LANE_RESET_SLEEP_US, LYNX_28G_LANE_RESET_TIMEOUT_US, false, lane, LNaRRSTCTL); if (err) { dev_warn_once(&lane->phy->dev, "Lane %c receiver reset failed: %pe\n", 'A' + lane->id, ERR_PTR(err)); } } static void lynx_28g_lane_remap_pll(struct lynx_lane *lane, enum lynx_lane_mode lane_mode) { struct lynx_priv *priv = lane->priv; struct lynx_pll *pll; /* Switch to the PLL that works with this interface type */ pll = lynx_pll_get(priv, lane_mode); if (unlikely(!pll)) return; lynx_28g_lane_set_pll(lane, pll); /* Choose the portion of clock net to be used on this lane */ lynx_28g_lane_set_nrate(lane, pll, lane_mode); } static void lynx_28g_lane_change_proto_conf(struct lynx_28g_lane *lane, enum lynx_lane_mode lane_mode) { const struct lynx_28g_proto_conf *conf = &lynx_28g_proto_conf[lane_mode]; lynx_28g_lane_rmw(lane, LNaGCR0, FIELD_PREP(LNaGCR0_PROTO_SEL, conf->proto_sel) | FIELD_PREP(LNaGCR0_IF_WIDTH, conf->if_width), LNaGCR0_PROTO_SEL | LNaGCR0_IF_WIDTH); lynx_28g_lane_rmw(lane, LNaTECR0, FIELD_PREP(LNaTECR0_EQ_TYPE, conf->teq_type) | FIELD_PREP(LNaTECR0_EQ_SGN_PREQ, conf->sgn_preq) | FIELD_PREP(LNaTECR0_EQ_PREQ, conf->ratio_preq) | FIELD_PREP(LNaTECR0_EQ_SGN_POST1Q, conf->sgn_post1q) | FIELD_PREP(LNaTECR0_EQ_POST1Q, conf->ratio_post1q) | FIELD_PREP(LNaTECR0_EQ_AMP_RED, conf->amp_red), LNaTECR0_EQ_TYPE | LNaTECR0_EQ_SGN_PREQ | LNaTECR0_EQ_PREQ | LNaTECR0_EQ_SGN_POST1Q | LNaTECR0_EQ_POST1Q | LNaTECR0_EQ_AMP_RED); lynx_28g_lane_rmw(lane, LNaTECR1, FIELD_PREP(LNaTECR1_EQ_ADPT_EQ, conf->adpt_eq), LNaTECR1_EQ_ADPT_EQ); lynx_28g_lane_rmw(lane, LNaRGCR1, FIELD_PREP(LNaRGCR1_ENTER_IDLE_FLT_SEL, conf->enter_idle_flt_sel) | FIELD_PREP(LNaRGCR1_EXIT_IDLE_FLT_SEL, conf->exit_idle_flt_sel) | FIELD_PREP(LNaRGCR1_DATA_LOST_TH_SEL, conf->data_lost_th_sel), LNaRGCR1_ENTER_IDLE_FLT_SEL | LNaRGCR1_EXIT_IDLE_FLT_SEL | LNaRGCR1_DATA_LOST_TH_SEL); lynx_28g_lane_rmw(lane, LNaRECR0, FIELD_PREP(LNaRECR0_EQ_GAINK2_HF_OV_EN, conf->gk2ovd_en) | FIELD_PREP(LNaRECR0_EQ_GAINK3_MF_OV_EN, conf->gk3ovd_en) | FIELD_PREP(LNaRECR0_EQ_GAINK4_LF_OV_EN, conf->gk4ovd_en) | FIELD_PREP(LNaRECR0_EQ_GAINK2_HF_OV, conf->gk2ovd) | FIELD_PREP(LNaRECR0_EQ_GAINK3_MF_OV, conf->gk3ovd) | FIELD_PREP(LNaRECR0_EQ_GAINK4_LF_OV, conf->gk4ovd), LNaRECR0_EQ_GAINK2_HF_OV | LNaRECR0_EQ_GAINK3_MF_OV | LNaRECR0_EQ_GAINK4_LF_OV | LNaRECR0_EQ_GAINK2_HF_OV_EN | LNaRECR0_EQ_GAINK3_MF_OV_EN | LNaRECR0_EQ_GAINK4_LF_OV_EN); lynx_28g_lane_rmw(lane, LNaRECR1, FIELD_PREP(LNaRECR1_EQ_OFFSET_OV, conf->eq_offset_ovd) | FIELD_PREP(LNaRECR1_EQ_OFFSET_OV_EN, conf->eq_offset_ovd_en), LNaRECR1_EQ_OFFSET_OV | LNaRECR1_EQ_OFFSET_OV_EN); lynx_28g_lane_rmw(lane, LNaRECR2, FIELD_PREP(LNaRECR2_EQ_OFFSET_RNG_DBL, conf->eq_offset_rng_dbl) | FIELD_PREP(LNaRECR2_EQ_BLW_SEL, conf->eq_blw_sel) | FIELD_PREP(LNaRECR2_EQ_BOOST, conf->eq_boost) | FIELD_PREP(LNaRECR2_SPARE_IN, conf->spare_in), LNaRECR2_EQ_OFFSET_RNG_DBL | LNaRECR2_EQ_BLW_SEL | LNaRECR2_EQ_BOOST | LNaRECR2_SPARE_IN); lynx_28g_lane_rmw(lane, LNaRSCCR0, FIELD_PREP(LNaRSCCR0_SMP_AUTOZ_D1R, conf->smp_autoz_d1r) | FIELD_PREP(LNaRSCCR0_SMP_AUTOZ_EG1R, conf->smp_autoz_eg1r), LNaRSCCR0_SMP_AUTOZ_D1R | LNaRSCCR0_SMP_AUTOZ_EG1R); lynx_28g_lane_write(lane, LNaRCCR0, conf->rccr0); lynx_28g_lane_write(lane, LNaTTLCR0, conf->ttlcr0); } static int lynx_28g_lane_disable_pcvt(struct lynx_28g_lane *lane, enum lynx_lane_mode lane_mode) { struct lynx_28g_priv *priv = lane->priv; int err; spin_lock(&priv->pcc_lock); err = lynx_pccr_write(lane, lane_mode, 0); if (err) goto out; switch (lane_mode) { case LANE_MODE_1000BASEX_SGMII: err = lynx_pcvt_rmw(lane, lane_mode, CR(1), 0, SGMIIaCR1_SGPCS_EN); break; default: err = 0; } out: spin_unlock(&priv->pcc_lock); return err; } static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane, enum lynx_lane_mode lane_mode) { struct lynx_28g_priv *priv = lane->priv; u32 val; int err; spin_lock(&priv->pcc_lock); switch (lane_mode) { case LANE_MODE_1000BASEX_SGMII: err = lynx_pcvt_rmw(lane, lane_mode, CR(1), SGMIIaCR1_SGPCS_EN, SGMIIaCR1_SGPCS_EN); break; default: err = 0; } val = 0; switch (lane_mode) { case LANE_MODE_1000BASEX_SGMII: val |= PCC8_SGMIIa_CFG; break; case LANE_MODE_10GBASER: val |= PCCC_SXGMIIn_XFI; fallthrough; case LANE_MODE_USXGMII: val |= PCCC_SXGMIIn_CFG; break; case LANE_MODE_25GBASER: val |= PCCD_E25Gn_CFG; break; default: break; } err = lynx_pccr_write(lane, lane_mode, val); spin_unlock(&priv->pcc_lock); return err; } static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode, union phy_configure_opts *opts) { return lynx_phy_mode_to_lane_mode(phy, mode, submode, NULL); } static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct lynx_lane *lane = phy_get_drvdata(phy); int powered_up = lane->powered_up; enum lynx_lane_mode lane_mode; int err; err = lynx_phy_mode_to_lane_mode(phy, mode, submode, &lane_mode); if (err) return err; if (lane_mode == lane->mode) return 0; /* If the lane is powered up, put the lane into the halt state while * the reconfiguration is being done. */ if (powered_up) { err = lynx_28g_lane_halt(phy); if (err) goto out; } err = lynx_28g_lane_disable_pcvt(lane, lane->mode); if (err) goto out; lynx_28g_lane_change_proto_conf(lane, lane_mode); lynx_28g_lane_remap_pll(lane, lane_mode); WARN_ON(lynx_28g_lane_enable_pcvt(lane, lane_mode)); lane->mode = lane_mode; out: if (powered_up) lynx_28g_lane_reset(phy); return err; } static int lynx_28g_init(struct phy *phy) { struct lynx_28g_lane *lane = phy_get_drvdata(phy); /* Mark the fact that the lane was init */ lane->init = true; /* SerDes lanes are powered on at boot time. Any lane that is managed * by this driver will get powered down at init time aka at dpaa2-eth * probe time. */ lane->powered_up = true; lynx_28g_power_off(phy); return 0; } static int lynx_28g_exit(struct phy *phy) { struct lynx_28g_lane *lane = phy_get_drvdata(phy); /* The lane returns to the state where it isn't managed by the * consumer, so we must treat is as if it isn't initialized, and * always powered on. */ lane->init = false; lane->powered_up = false; lynx_28g_power_on(phy); return 0; } static const struct phy_ops lynx_28g_ops = { .init = lynx_28g_init, .exit = lynx_28g_exit, .power_on = lynx_28g_power_on, .power_off = lynx_28g_power_off, .set_mode = lynx_28g_set_mode, .validate = lynx_28g_validate, .owner = THIS_MODULE, }; static void lynx_28g_pll_read_configuration(struct lynx_pll *pll) { u32 val; val = lynx_pll_read(pll, PLLnRSTCTL); pll->enabled = !(val & PLLnRSTCTL_DIS); pll->locked = !!(val & PLLnRSTCTL_LOCK); val = lynx_pll_read(pll, PLLnCR0); pll->refclk_sel = FIELD_GET(PLLnCR0_REFCLK_SEL, val); val = lynx_pll_read(pll, PLLnCR1); pll->frate_sel = FIELD_GET(PLLnCR1_FRATE_SEL, val); if (!pll->enabled) return; switch (pll->frate_sel) { case PLLnCR1_FRATE_5G_10GVCO: case PLLnCR1_FRATE_5G_25GVCO: /* 5GHz clock net */ __set_bit(LANE_MODE_1000BASEX_SGMII, pll->supported); break; case PLLnCR1_FRATE_10G_20GVCO: /* 10.3125GHz clock net */ __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, 8GHz */ break; } } static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane) { u32 pccr, pss, protocol; pss = lynx_28g_lane_read(lane, LNaPSS); protocol = FIELD_GET(LNaPSS_TYPE, pss); switch (protocol) { case LNaPSS_TYPE_SGMII: lane->mode = LANE_MODE_1000BASEX_SGMII; break; case LNaPSS_TYPE_XFI: lynx_pccr_read(lane, LANE_MODE_10GBASER, &pccr); if (pccr & PCCC_SXGMIIn_XFI) lane->mode = LANE_MODE_10GBASER; else lane->mode = LANE_MODE_USXGMII; break; case LNaPSS_TYPE_25G: lane->mode = LANE_MODE_25GBASER; break; default: lane->mode = LANE_MODE_UNKNOWN; } } static const struct lynx_info lynx_info_compat = { .get_pccr = lynx_28g_get_pccr, .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lynx_28g_compat_lane_supports_mode, .pll_read_configuration = lynx_28g_pll_read_configuration, .lane_read_configuration = lynx_28g_lane_read_configuration, .cdr_lock_check = lynx_28g_cdr_lock_check, .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2160a_serdes1 = { .get_pccr = lynx_28g_get_pccr, .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2160a_serdes1_lane_supports_mode, .pll_read_configuration = lynx_28g_pll_read_configuration, .lane_read_configuration = lynx_28g_lane_read_configuration, .cdr_lock_check = lynx_28g_cdr_lock_check, .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2160a_serdes2 = { .get_pccr = lynx_28g_get_pccr, .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2160a_serdes2_lane_supports_mode, .pll_read_configuration = lynx_28g_pll_read_configuration, .lane_read_configuration = lynx_28g_lane_read_configuration, .cdr_lock_check = lynx_28g_cdr_lock_check, .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2160a_serdes3 = { .get_pccr = lynx_28g_get_pccr, .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2160a_serdes3_lane_supports_mode, .pll_read_configuration = lynx_28g_pll_read_configuration, .lane_read_configuration = lynx_28g_lane_read_configuration, .cdr_lock_check = lynx_28g_cdr_lock_check, .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2162a_serdes1 = { .get_pccr = lynx_28g_get_pccr, .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2162a_serdes1_lane_supports_mode, .pll_read_configuration = lynx_28g_pll_read_configuration, .lane_read_configuration = lynx_28g_lane_read_configuration, .cdr_lock_check = lynx_28g_cdr_lock_check, .first_lane = 4, .num_lanes = LYNX_28G_NUM_LANE, }; static const struct lynx_info lynx_info_lx2162a_serdes2 = { .get_pccr = lynx_28g_get_pccr, .get_pcvt_offset = lynx_28g_get_pcvt_offset, .lane_supports_mode = lx2162a_serdes2_lane_supports_mode, .pll_read_configuration = lynx_28g_pll_read_configuration, .lane_read_configuration = lynx_28g_lane_read_configuration, .cdr_lock_check = lynx_28g_cdr_lock_check, .num_lanes = LYNX_28G_NUM_LANE, }; static int lynx_28g_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct lynx_info *info; /* * If we get here it means we probed on a device tree where * "fsl,lynx-28g" wasn't the fallback, but the sole compatible string. */ info = of_device_get_match_data(dev); if (info == &lynx_info_compat) dev_warn(dev, "Please update device tree to use per-device compatible strings\n"); return lynx_probe(pdev, info, &lynx_28g_ops); } static const struct of_device_id lynx_28g_of_match_table[] = { { .compatible = "fsl,lx2160a-serdes1", .data = &lynx_info_lx2160a_serdes1 }, { .compatible = "fsl,lx2160a-serdes2", .data = &lynx_info_lx2160a_serdes2 }, { .compatible = "fsl,lx2160a-serdes3", .data = &lynx_info_lx2160a_serdes3 }, { .compatible = "fsl,lx2162a-serdes1", .data = &lynx_info_lx2162a_serdes1 }, { .compatible = "fsl,lx2162a-serdes2", .data = &lynx_info_lx2162a_serdes2 }, { .compatible = "fsl,lynx-28g", .data = &lynx_info_compat }, /* fallback, keep last */ { }, }; MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table); static struct platform_driver lynx_28g_driver = { .probe = lynx_28g_probe, .remove = lynx_remove, .driver = { .name = "lynx-28g", .of_match_table = lynx_28g_of_match_table, }, }; module_platform_driver(lynx_28g_driver); MODULE_IMPORT_NS("PHY_FSL_LYNX"); MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>"); MODULE_DESCRIPTION("Lynx 28G SerDes PHY driver for Layerscape SoCs"); MODULE_LICENSE("GPL v2");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1