162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* Copyright (c) 2021-2022 NXP. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/module.h> 562306a36Sopenharmony_ci#include <linux/of.h> 662306a36Sopenharmony_ci#include <linux/phy.h> 762306a36Sopenharmony_ci#include <linux/phy/phy.h> 862306a36Sopenharmony_ci#include <linux/platform_device.h> 962306a36Sopenharmony_ci#include <linux/workqueue.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#define LYNX_28G_NUM_LANE 8 1262306a36Sopenharmony_ci#define LYNX_28G_NUM_PLL 2 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* General registers per SerDes block */ 1562306a36Sopenharmony_ci#define LYNX_28G_PCC8 0x10a0 1662306a36Sopenharmony_ci#define LYNX_28G_PCC8_SGMII 0x1 1762306a36Sopenharmony_ci#define LYNX_28G_PCC8_SGMII_DIS 0x0 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define LYNX_28G_PCCC 0x10b0 2062306a36Sopenharmony_ci#define LYNX_28G_PCCC_10GBASER 0x9 2162306a36Sopenharmony_ci#define LYNX_28G_PCCC_USXGMII 0x1 2262306a36Sopenharmony_ci#define LYNX_28G_PCCC_SXGMII_DIS 0x0 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define LYNX_28G_LNa_PCC_OFFSET(lane) (4 * (LYNX_28G_NUM_LANE - (lane->id) - 1)) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Per PLL registers */ 2762306a36Sopenharmony_ci#define LYNX_28G_PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0) 2862306a36Sopenharmony_ci#define LYNX_28G_PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24) 2962306a36Sopenharmony_ci#define LYNX_28G_PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4) 3262306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0_REFCLK_SEL(cr0) (((cr0) & GENMASK(20, 16))) 3362306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0_REFCLK_SEL_100MHZ 0x0 3462306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0_REFCLK_SEL_125MHZ 0x10000 3562306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0_REFCLK_SEL_156MHZ 0x20000 3662306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0_REFCLK_SEL_150MHZ 0x30000 3762306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0_REFCLK_SEL_161MHZ 0x40000 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define LYNX_28G_PLLnCR1(pll) (0x400 + (pll) * 0x100 + 0x8) 4062306a36Sopenharmony_ci#define LYNX_28G_PLLnCR1_FRATE_SEL(cr1) (((cr1) & GENMASK(28, 24))) 4162306a36Sopenharmony_ci#define LYNX_28G_PLLnCR1_FRATE_5G_10GVCO 0x0 4262306a36Sopenharmony_ci#define LYNX_28G_PLLnCR1_FRATE_5G_25GVCO 0x10000000 4362306a36Sopenharmony_ci#define LYNX_28G_PLLnCR1_FRATE_10G_20GVCO 0x6000000 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* Per SerDes lane registers */ 4662306a36Sopenharmony_ci/* Lane a General Control Register */ 4762306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0(lane) (0x800 + (lane) * 0x100 + 0x0) 4862306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0_PROTO_SEL_MSK GENMASK(7, 3) 4962306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0_PROTO_SEL_SGMII 0x8 5062306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0_PROTO_SEL_XFI 0x50 5162306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0_IF_WIDTH_MSK GENMASK(2, 0) 5262306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0_IF_WIDTH_10_BIT 0x0 5362306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0_IF_WIDTH_20_BIT 0x2 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* Lane a Tx Reset Control Register */ 5662306a36Sopenharmony_ci#define LYNX_28G_LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20) 5762306a36Sopenharmony_ci#define LYNX_28G_LNaTRSTCTL_HLT_REQ BIT(27) 5862306a36Sopenharmony_ci#define LYNX_28G_LNaTRSTCTL_RST_DONE BIT(30) 5962306a36Sopenharmony_ci#define LYNX_28G_LNaTRSTCTL_RST_REQ BIT(31) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* Lane a Tx General Control Register */ 6262306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24) 6362306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_USE_PLLF 0x0 6462306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_USE_PLLS BIT(28) 6562306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_USE_PLL_MSK BIT(28) 6662306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_N_RATE_FULL 0x0 6762306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_N_RATE_HALF 0x1000000 6862306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_N_RATE_QUARTER 0x2000000 6962306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_N_RATE_MSK GENMASK(26, 24) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define LYNX_28G_LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* Lane a Rx Reset Control Register */ 7462306a36Sopenharmony_ci#define LYNX_28G_LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40) 7562306a36Sopenharmony_ci#define LYNX_28G_LNaRRSTCTL_HLT_REQ BIT(27) 7662306a36Sopenharmony_ci#define LYNX_28G_LNaRRSTCTL_RST_DONE BIT(30) 7762306a36Sopenharmony_ci#define LYNX_28G_LNaRRSTCTL_RST_REQ BIT(31) 7862306a36Sopenharmony_ci#define LYNX_28G_LNaRRSTCTL_CDR_LOCK BIT(12) 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* Lane a Rx General Control Register */ 8162306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0(lane) (0x800 + (lane) * 0x100 + 0x44) 8262306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_USE_PLLF 0x0 8362306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_USE_PLLS BIT(28) 8462306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_USE_PLL_MSK BIT(28) 8562306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24) 8662306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_N_RATE_FULL 0x0 8762306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_N_RATE_HALF 0x1000000 8862306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_N_RATE_QUARTER 0x2000000 8962306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24) 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48) 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define LYNX_28G_LNaRECR0(lane) (0x800 + (lane) * 0x100 + 0x50) 9462306a36Sopenharmony_ci#define LYNX_28G_LNaRECR1(lane) (0x800 + (lane) * 0x100 + 0x54) 9562306a36Sopenharmony_ci#define LYNX_28G_LNaRECR2(lane) (0x800 + (lane) * 0x100 + 0x58) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define LYNX_28G_LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#define LYNX_28G_LNaPSS(lane) (0x1000 + (lane) * 0x4) 10062306a36Sopenharmony_ci#define LYNX_28G_LNaPSS_TYPE(pss) (((pss) & GENMASK(30, 24)) >> 24) 10162306a36Sopenharmony_ci#define LYNX_28G_LNaPSS_TYPE_SGMII 0x4 10262306a36Sopenharmony_ci#define LYNX_28G_LNaPSS_TYPE_XFI 0x28 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#define LYNX_28G_SGMIIaCR1(lane) (0x1804 + (lane) * 0x10) 10562306a36Sopenharmony_ci#define LYNX_28G_SGMIIaCR1_SGPCS_EN BIT(11) 10662306a36Sopenharmony_ci#define LYNX_28G_SGMIIaCR1_SGPCS_DIS 0x0 10762306a36Sopenharmony_ci#define LYNX_28G_SGMIIaCR1_SGPCS_MSK BIT(11) 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistruct lynx_28g_priv; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistruct lynx_28g_pll { 11262306a36Sopenharmony_ci struct lynx_28g_priv *priv; 11362306a36Sopenharmony_ci u32 rstctl, cr0, cr1; 11462306a36Sopenharmony_ci int id; 11562306a36Sopenharmony_ci DECLARE_PHY_INTERFACE_MASK(supported); 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistruct lynx_28g_lane { 11962306a36Sopenharmony_ci struct lynx_28g_priv *priv; 12062306a36Sopenharmony_ci struct phy *phy; 12162306a36Sopenharmony_ci bool powered_up; 12262306a36Sopenharmony_ci bool init; 12362306a36Sopenharmony_ci unsigned int id; 12462306a36Sopenharmony_ci phy_interface_t interface; 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistruct lynx_28g_priv { 12862306a36Sopenharmony_ci void __iomem *base; 12962306a36Sopenharmony_ci struct device *dev; 13062306a36Sopenharmony_ci /* Serialize concurrent access to registers shared between lanes, 13162306a36Sopenharmony_ci * like PCCn 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci spinlock_t pcc_lock; 13462306a36Sopenharmony_ci struct lynx_28g_pll pll[LYNX_28G_NUM_PLL]; 13562306a36Sopenharmony_ci struct lynx_28g_lane lane[LYNX_28G_NUM_LANE]; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci struct delayed_work cdr_check; 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off, 14162306a36Sopenharmony_ci u32 val, u32 mask) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci void __iomem *reg = priv->base + off; 14462306a36Sopenharmony_ci u32 orig, tmp; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci orig = ioread32(reg); 14762306a36Sopenharmony_ci tmp = orig & ~mask; 14862306a36Sopenharmony_ci tmp |= val; 14962306a36Sopenharmony_ci iowrite32(tmp, reg); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci#define lynx_28g_lane_rmw(lane, reg, val, mask) \ 15362306a36Sopenharmony_ci lynx_28g_rmw((lane)->priv, LYNX_28G_##reg(lane->id), \ 15462306a36Sopenharmony_ci LYNX_28G_##reg##_##val, LYNX_28G_##reg##_##mask) 15562306a36Sopenharmony_ci#define lynx_28g_lane_read(lane, reg) \ 15662306a36Sopenharmony_ci ioread32((lane)->priv->base + LYNX_28G_##reg((lane)->id)) 15762306a36Sopenharmony_ci#define lynx_28g_pll_read(pll, reg) \ 15862306a36Sopenharmony_ci ioread32((pll)->priv->base + LYNX_28G_##reg((pll)->id)) 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci int i; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci for (i = 0; i < LYNX_28G_NUM_PLL; i++) { 16562306a36Sopenharmony_ci if (LYNX_28G_PLLnRSTCTL_DIS(priv->pll[i].rstctl)) 16662306a36Sopenharmony_ci continue; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (test_bit(intf, priv->pll[i].supported)) 16962306a36Sopenharmony_ci return true; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return false; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv, 17662306a36Sopenharmony_ci phy_interface_t intf) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct lynx_28g_pll *pll; 17962306a36Sopenharmony_ci int i; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci for (i = 0; i < LYNX_28G_NUM_PLL; i++) { 18262306a36Sopenharmony_ci pll = &priv->pll[i]; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl)) 18562306a36Sopenharmony_ci continue; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (test_bit(intf, pll->supported)) 18862306a36Sopenharmony_ci return pll; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return NULL; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane, 19562306a36Sopenharmony_ci struct lynx_28g_pll *pll, 19662306a36Sopenharmony_ci phy_interface_t intf) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) { 19962306a36Sopenharmony_ci case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO: 20062306a36Sopenharmony_ci case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO: 20162306a36Sopenharmony_ci switch (intf) { 20262306a36Sopenharmony_ci case PHY_INTERFACE_MODE_SGMII: 20362306a36Sopenharmony_ci case PHY_INTERFACE_MODE_1000BASEX: 20462306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_QUARTER, N_RATE_MSK); 20562306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_QUARTER, N_RATE_MSK); 20662306a36Sopenharmony_ci break; 20762306a36Sopenharmony_ci default: 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci break; 21162306a36Sopenharmony_ci case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO: 21262306a36Sopenharmony_ci switch (intf) { 21362306a36Sopenharmony_ci case PHY_INTERFACE_MODE_10GBASER: 21462306a36Sopenharmony_ci case PHY_INTERFACE_MODE_USXGMII: 21562306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_FULL, N_RATE_MSK); 21662306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_FULL, N_RATE_MSK); 21762306a36Sopenharmony_ci break; 21862306a36Sopenharmony_ci default: 21962306a36Sopenharmony_ci break; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci default: 22362306a36Sopenharmony_ci break; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane, 22862306a36Sopenharmony_ci struct lynx_28g_pll *pll) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci if (pll->id == 0) { 23162306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLF, USE_PLL_MSK); 23262306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLF, USE_PLL_MSK); 23362306a36Sopenharmony_ci } else { 23462306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLS, USE_PLL_MSK); 23562306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLS, USE_PLL_MSK); 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane); 24262306a36Sopenharmony_ci struct lynx_28g_priv *priv = lane->priv; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* Cleanup the protocol configuration registers of the current protocol */ 24562306a36Sopenharmony_ci switch (lane->interface) { 24662306a36Sopenharmony_ci case PHY_INTERFACE_MODE_10GBASER: 24762306a36Sopenharmony_ci lynx_28g_rmw(priv, LYNX_28G_PCCC, 24862306a36Sopenharmony_ci LYNX_28G_PCCC_SXGMII_DIS << lane_offset, 24962306a36Sopenharmony_ci GENMASK(3, 0) << lane_offset); 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci case PHY_INTERFACE_MODE_SGMII: 25262306a36Sopenharmony_ci case PHY_INTERFACE_MODE_1000BASEX: 25362306a36Sopenharmony_ci lynx_28g_rmw(priv, LYNX_28G_PCC8, 25462306a36Sopenharmony_ci LYNX_28G_PCC8_SGMII_DIS << lane_offset, 25562306a36Sopenharmony_ci GENMASK(3, 0) << lane_offset); 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci default: 25862306a36Sopenharmony_ci break; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane); 26562306a36Sopenharmony_ci struct lynx_28g_priv *priv = lane->priv; 26662306a36Sopenharmony_ci struct lynx_28g_pll *pll; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci lynx_28g_cleanup_lane(lane); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* Setup the lane to run in SGMII */ 27162306a36Sopenharmony_ci lynx_28g_rmw(priv, LYNX_28G_PCC8, 27262306a36Sopenharmony_ci LYNX_28G_PCC8_SGMII << lane_offset, 27362306a36Sopenharmony_ci GENMASK(3, 0) << lane_offset); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* Setup the protocol select and SerDes parallel interface width */ 27662306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_SGMII, PROTO_SEL_MSK); 27762306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_10_BIT, IF_WIDTH_MSK); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* Switch to the PLL that works with this interface type */ 28062306a36Sopenharmony_ci pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII); 28162306a36Sopenharmony_ci lynx_28g_lane_set_pll(lane, pll); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* Choose the portion of clock net to be used on this lane */ 28462306a36Sopenharmony_ci lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_SGMII); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* Enable the SGMII PCS */ 28762306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_EN, SGPCS_MSK); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* Configure the appropriate equalization parameters for the protocol */ 29062306a36Sopenharmony_ci iowrite32(0x00808006, priv->base + LYNX_28G_LNaTECR0(lane->id)); 29162306a36Sopenharmony_ci iowrite32(0x04310000, priv->base + LYNX_28G_LNaRGCR1(lane->id)); 29262306a36Sopenharmony_ci iowrite32(0x9f800000, priv->base + LYNX_28G_LNaRECR0(lane->id)); 29362306a36Sopenharmony_ci iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id)); 29462306a36Sopenharmony_ci iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR2(lane->id)); 29562306a36Sopenharmony_ci iowrite32(0x00000000, priv->base + LYNX_28G_LNaRSCCR0(lane->id)); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane); 30162306a36Sopenharmony_ci struct lynx_28g_priv *priv = lane->priv; 30262306a36Sopenharmony_ci struct lynx_28g_pll *pll; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci lynx_28g_cleanup_lane(lane); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* Enable the SXGMII lane */ 30762306a36Sopenharmony_ci lynx_28g_rmw(priv, LYNX_28G_PCCC, 30862306a36Sopenharmony_ci LYNX_28G_PCCC_10GBASER << lane_offset, 30962306a36Sopenharmony_ci GENMASK(3, 0) << lane_offset); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* Setup the protocol select and SerDes parallel interface width */ 31262306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_XFI, PROTO_SEL_MSK); 31362306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_20_BIT, IF_WIDTH_MSK); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* Switch to the PLL that works with this interface type */ 31662306a36Sopenharmony_ci pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER); 31762306a36Sopenharmony_ci lynx_28g_lane_set_pll(lane, pll); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* Choose the portion of clock net to be used on this lane */ 32062306a36Sopenharmony_ci lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_10GBASER); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* Disable the SGMII PCS */ 32362306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_DIS, SGPCS_MSK); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* Configure the appropriate equalization parameters for the protocol */ 32662306a36Sopenharmony_ci iowrite32(0x10808307, priv->base + LYNX_28G_LNaTECR0(lane->id)); 32762306a36Sopenharmony_ci iowrite32(0x10000000, priv->base + LYNX_28G_LNaRGCR1(lane->id)); 32862306a36Sopenharmony_ci iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR0(lane->id)); 32962306a36Sopenharmony_ci iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id)); 33062306a36Sopenharmony_ci iowrite32(0x81000020, priv->base + LYNX_28G_LNaRECR2(lane->id)); 33162306a36Sopenharmony_ci iowrite32(0x00002000, priv->base + LYNX_28G_LNaRSCCR0(lane->id)); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic int lynx_28g_power_off(struct phy *phy) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct lynx_28g_lane *lane = phy_get_drvdata(phy); 33762306a36Sopenharmony_ci u32 trstctl, rrstctl; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (!lane->powered_up) 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* Issue a halt request */ 34362306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaTRSTCTL, HLT_REQ, HLT_REQ); 34462306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaRRSTCTL, HLT_REQ, HLT_REQ); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* Wait until the halting process is complete */ 34762306a36Sopenharmony_ci do { 34862306a36Sopenharmony_ci trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL); 34962306a36Sopenharmony_ci rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); 35062306a36Sopenharmony_ci } while ((trstctl & LYNX_28G_LNaTRSTCTL_HLT_REQ) || 35162306a36Sopenharmony_ci (rrstctl & LYNX_28G_LNaRRSTCTL_HLT_REQ)); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci lane->powered_up = false; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int lynx_28g_power_on(struct phy *phy) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct lynx_28g_lane *lane = phy_get_drvdata(phy); 36162306a36Sopenharmony_ci u32 trstctl, rrstctl; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (lane->powered_up) 36462306a36Sopenharmony_ci return 0; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* Issue a reset request on the lane */ 36762306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaTRSTCTL, RST_REQ, RST_REQ); 36862306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* Wait until the reset sequence is completed */ 37162306a36Sopenharmony_ci do { 37262306a36Sopenharmony_ci trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL); 37362306a36Sopenharmony_ci rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); 37462306a36Sopenharmony_ci } while (!(trstctl & LYNX_28G_LNaTRSTCTL_RST_DONE) || 37562306a36Sopenharmony_ci !(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE)); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci lane->powered_up = true; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct lynx_28g_lane *lane = phy_get_drvdata(phy); 38562306a36Sopenharmony_ci struct lynx_28g_priv *priv = lane->priv; 38662306a36Sopenharmony_ci int powered_up = lane->powered_up; 38762306a36Sopenharmony_ci int err = 0; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (mode != PHY_MODE_ETHERNET) 39062306a36Sopenharmony_ci return -EOPNOTSUPP; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (lane->interface == PHY_INTERFACE_MODE_NA) 39362306a36Sopenharmony_ci return -EOPNOTSUPP; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (!lynx_28g_supports_interface(priv, submode)) 39662306a36Sopenharmony_ci return -EOPNOTSUPP; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* If the lane is powered up, put the lane into the halt state while 39962306a36Sopenharmony_ci * the reconfiguration is being done. 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_ci if (powered_up) 40262306a36Sopenharmony_ci lynx_28g_power_off(phy); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci spin_lock(&priv->pcc_lock); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci switch (submode) { 40762306a36Sopenharmony_ci case PHY_INTERFACE_MODE_SGMII: 40862306a36Sopenharmony_ci case PHY_INTERFACE_MODE_1000BASEX: 40962306a36Sopenharmony_ci lynx_28g_lane_set_sgmii(lane); 41062306a36Sopenharmony_ci break; 41162306a36Sopenharmony_ci case PHY_INTERFACE_MODE_10GBASER: 41262306a36Sopenharmony_ci lynx_28g_lane_set_10gbaser(lane); 41362306a36Sopenharmony_ci break; 41462306a36Sopenharmony_ci default: 41562306a36Sopenharmony_ci err = -EOPNOTSUPP; 41662306a36Sopenharmony_ci goto out; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci lane->interface = submode; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ciout: 42262306a36Sopenharmony_ci spin_unlock(&priv->pcc_lock); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* Power up the lane if necessary */ 42562306a36Sopenharmony_ci if (powered_up) 42662306a36Sopenharmony_ci lynx_28g_power_on(phy); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return err; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode, 43262306a36Sopenharmony_ci union phy_configure_opts *opts __always_unused) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct lynx_28g_lane *lane = phy_get_drvdata(phy); 43562306a36Sopenharmony_ci struct lynx_28g_priv *priv = lane->priv; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (mode != PHY_MODE_ETHERNET) 43862306a36Sopenharmony_ci return -EOPNOTSUPP; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (!lynx_28g_supports_interface(priv, submode)) 44162306a36Sopenharmony_ci return -EOPNOTSUPP; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic int lynx_28g_init(struct phy *phy) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct lynx_28g_lane *lane = phy_get_drvdata(phy); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* Mark the fact that the lane was init */ 45162306a36Sopenharmony_ci lane->init = true; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* SerDes lanes are powered on at boot time. Any lane that is managed 45462306a36Sopenharmony_ci * by this driver will get powered down at init time aka at dpaa2-eth 45562306a36Sopenharmony_ci * probe time. 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_ci lane->powered_up = true; 45862306a36Sopenharmony_ci lynx_28g_power_off(phy); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return 0; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic const struct phy_ops lynx_28g_ops = { 46462306a36Sopenharmony_ci .init = lynx_28g_init, 46562306a36Sopenharmony_ci .power_on = lynx_28g_power_on, 46662306a36Sopenharmony_ci .power_off = lynx_28g_power_off, 46762306a36Sopenharmony_ci .set_mode = lynx_28g_set_mode, 46862306a36Sopenharmony_ci .validate = lynx_28g_validate, 46962306a36Sopenharmony_ci .owner = THIS_MODULE, 47062306a36Sopenharmony_ci}; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci struct lynx_28g_pll *pll; 47562306a36Sopenharmony_ci int i; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci for (i = 0; i < LYNX_28G_NUM_PLL; i++) { 47862306a36Sopenharmony_ci pll = &priv->pll[i]; 47962306a36Sopenharmony_ci pll->priv = priv; 48062306a36Sopenharmony_ci pll->id = i; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci pll->rstctl = lynx_28g_pll_read(pll, PLLnRSTCTL); 48362306a36Sopenharmony_ci pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0); 48462306a36Sopenharmony_ci pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl)) 48762306a36Sopenharmony_ci continue; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) { 49062306a36Sopenharmony_ci case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO: 49162306a36Sopenharmony_ci case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO: 49262306a36Sopenharmony_ci /* 5GHz clock net */ 49362306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_1000BASEX, pll->supported); 49462306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_SGMII, pll->supported); 49562306a36Sopenharmony_ci break; 49662306a36Sopenharmony_ci case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO: 49762306a36Sopenharmony_ci /* 10.3125GHz clock net */ 49862306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_10GBASER, pll->supported); 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci default: 50162306a36Sopenharmony_ci /* 6GHz, 12.890625GHz, 8GHz */ 50262306a36Sopenharmony_ci break; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci#define work_to_lynx(w) container_of((w), struct lynx_28g_priv, cdr_check.work) 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic void lynx_28g_cdr_lock_check(struct work_struct *work) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct lynx_28g_priv *priv = work_to_lynx(work); 51262306a36Sopenharmony_ci struct lynx_28g_lane *lane; 51362306a36Sopenharmony_ci u32 rrstctl; 51462306a36Sopenharmony_ci int i; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci for (i = 0; i < LYNX_28G_NUM_LANE; i++) { 51762306a36Sopenharmony_ci lane = &priv->lane[i]; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci mutex_lock(&lane->phy->mutex); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (!lane->init || !lane->powered_up) { 52262306a36Sopenharmony_ci mutex_unlock(&lane->phy->mutex); 52362306a36Sopenharmony_ci continue; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); 52762306a36Sopenharmony_ci if (!(rrstctl & LYNX_28G_LNaRRSTCTL_CDR_LOCK)) { 52862306a36Sopenharmony_ci lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ); 52962306a36Sopenharmony_ci do { 53062306a36Sopenharmony_ci rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); 53162306a36Sopenharmony_ci } while (!(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE)); 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci mutex_unlock(&lane->phy->mutex); 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci queue_delayed_work(system_power_efficient_wq, &priv->cdr_check, 53762306a36Sopenharmony_ci msecs_to_jiffies(1000)); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci u32 pss, protocol; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci pss = lynx_28g_lane_read(lane, LNaPSS); 54562306a36Sopenharmony_ci protocol = LYNX_28G_LNaPSS_TYPE(pss); 54662306a36Sopenharmony_ci switch (protocol) { 54762306a36Sopenharmony_ci case LYNX_28G_LNaPSS_TYPE_SGMII: 54862306a36Sopenharmony_ci lane->interface = PHY_INTERFACE_MODE_SGMII; 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci case LYNX_28G_LNaPSS_TYPE_XFI: 55162306a36Sopenharmony_ci lane->interface = PHY_INTERFACE_MODE_10GBASER; 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci default: 55462306a36Sopenharmony_ci lane->interface = PHY_INTERFACE_MODE_NA; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic struct phy *lynx_28g_xlate(struct device *dev, 55962306a36Sopenharmony_ci struct of_phandle_args *args) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci struct lynx_28g_priv *priv = dev_get_drvdata(dev); 56262306a36Sopenharmony_ci int idx = args->args[0]; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (WARN_ON(idx >= LYNX_28G_NUM_LANE)) 56562306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return priv->lane[idx].phy; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic int lynx_28g_probe(struct platform_device *pdev) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct device *dev = &pdev->dev; 57362306a36Sopenharmony_ci struct phy_provider *provider; 57462306a36Sopenharmony_ci struct lynx_28g_priv *priv; 57562306a36Sopenharmony_ci int i; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 57862306a36Sopenharmony_ci if (!priv) 57962306a36Sopenharmony_ci return -ENOMEM; 58062306a36Sopenharmony_ci priv->dev = &pdev->dev; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci priv->base = devm_platform_ioremap_resource(pdev, 0); 58362306a36Sopenharmony_ci if (IS_ERR(priv->base)) 58462306a36Sopenharmony_ci return PTR_ERR(priv->base); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci lynx_28g_pll_read_configuration(priv); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci for (i = 0; i < LYNX_28G_NUM_LANE; i++) { 58962306a36Sopenharmony_ci struct lynx_28g_lane *lane = &priv->lane[i]; 59062306a36Sopenharmony_ci struct phy *phy; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci memset(lane, 0, sizeof(*lane)); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci phy = devm_phy_create(&pdev->dev, NULL, &lynx_28g_ops); 59562306a36Sopenharmony_ci if (IS_ERR(phy)) 59662306a36Sopenharmony_ci return PTR_ERR(phy); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci lane->priv = priv; 59962306a36Sopenharmony_ci lane->phy = phy; 60062306a36Sopenharmony_ci lane->id = i; 60162306a36Sopenharmony_ci phy_set_drvdata(phy, lane); 60262306a36Sopenharmony_ci lynx_28g_lane_read_configuration(lane); 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci dev_set_drvdata(dev, priv); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci spin_lock_init(&priv->pcc_lock); 60862306a36Sopenharmony_ci INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci queue_delayed_work(system_power_efficient_wq, &priv->cdr_check, 61162306a36Sopenharmony_ci msecs_to_jiffies(1000)); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci dev_set_drvdata(&pdev->dev, priv); 61462306a36Sopenharmony_ci provider = devm_of_phy_provider_register(&pdev->dev, lynx_28g_xlate); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(provider); 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic void lynx_28g_remove(struct platform_device *pdev) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci struct device *dev = &pdev->dev; 62262306a36Sopenharmony_ci struct lynx_28g_priv *priv = dev_get_drvdata(dev); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci cancel_delayed_work_sync(&priv->cdr_check); 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic const struct of_device_id lynx_28g_of_match_table[] = { 62862306a36Sopenharmony_ci { .compatible = "fsl,lynx-28g" }, 62962306a36Sopenharmony_ci { }, 63062306a36Sopenharmony_ci}; 63162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, lynx_28g_of_match_table); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic struct platform_driver lynx_28g_driver = { 63462306a36Sopenharmony_ci .probe = lynx_28g_probe, 63562306a36Sopenharmony_ci .remove_new = lynx_28g_remove, 63662306a36Sopenharmony_ci .driver = { 63762306a36Sopenharmony_ci .name = "lynx-28g", 63862306a36Sopenharmony_ci .of_match_table = lynx_28g_of_match_table, 63962306a36Sopenharmony_ci }, 64062306a36Sopenharmony_ci}; 64162306a36Sopenharmony_cimodule_platform_driver(lynx_28g_driver); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ciMODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>"); 64462306a36Sopenharmony_ciMODULE_DESCRIPTION("Lynx 28G SerDes PHY driver for Layerscape SoCs"); 64562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 646