18f73b37cSIoana Ciornei // SPDX-License-Identifier: GPL-2.0+ 28f73b37cSIoana Ciornei /* Copyright (c) 2021-2022 NXP. */ 38f73b37cSIoana Ciornei 48f73b37cSIoana Ciornei #include <linux/module.h> 57559e757SRob Herring #include <linux/of.h> 68f73b37cSIoana Ciornei #include <linux/phy.h> 78f73b37cSIoana Ciornei #include <linux/phy/phy.h> 88f73b37cSIoana Ciornei #include <linux/platform_device.h> 98f73b37cSIoana Ciornei #include <linux/workqueue.h> 108f73b37cSIoana Ciornei 118f73b37cSIoana Ciornei #define LYNX_28G_NUM_LANE 8 128f73b37cSIoana Ciornei #define LYNX_28G_NUM_PLL 2 138f73b37cSIoana Ciornei 148f73b37cSIoana Ciornei /* General registers per SerDes block */ 158f73b37cSIoana Ciornei #define LYNX_28G_PCC8 0x10a0 168f73b37cSIoana Ciornei #define LYNX_28G_PCC8_SGMII 0x1 178f73b37cSIoana Ciornei #define LYNX_28G_PCC8_SGMII_DIS 0x0 188f73b37cSIoana Ciornei 198f73b37cSIoana Ciornei #define LYNX_28G_PCCC 0x10b0 208f73b37cSIoana Ciornei #define LYNX_28G_PCCC_10GBASER 0x9 218f73b37cSIoana Ciornei #define LYNX_28G_PCCC_USXGMII 0x1 228f73b37cSIoana Ciornei #define LYNX_28G_PCCC_SXGMII_DIS 0x0 238f73b37cSIoana Ciornei 248f73b37cSIoana Ciornei #define LYNX_28G_LNa_PCC_OFFSET(lane) (4 * (LYNX_28G_NUM_LANE - (lane->id) - 1)) 258f73b37cSIoana Ciornei 268f73b37cSIoana Ciornei /* Per PLL registers */ 278f73b37cSIoana Ciornei #define LYNX_28G_PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0) 288f73b37cSIoana Ciornei #define LYNX_28G_PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24) 298f73b37cSIoana Ciornei #define LYNX_28G_PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23) 308f73b37cSIoana Ciornei 318f73b37cSIoana Ciornei #define LYNX_28G_PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4) 328f73b37cSIoana Ciornei #define LYNX_28G_PLLnCR0_REFCLK_SEL(cr0) (((cr0) & GENMASK(20, 16))) 338f73b37cSIoana Ciornei #define LYNX_28G_PLLnCR0_REFCLK_SEL_100MHZ 0x0 348f73b37cSIoana Ciornei #define LYNX_28G_PLLnCR0_REFCLK_SEL_125MHZ 0x10000 358f73b37cSIoana Ciornei #define LYNX_28G_PLLnCR0_REFCLK_SEL_156MHZ 0x20000 368f73b37cSIoana Ciornei #define LYNX_28G_PLLnCR0_REFCLK_SEL_150MHZ 0x30000 378f73b37cSIoana Ciornei #define LYNX_28G_PLLnCR0_REFCLK_SEL_161MHZ 0x40000 388f73b37cSIoana Ciornei 398f73b37cSIoana Ciornei #define LYNX_28G_PLLnCR1(pll) (0x400 + (pll) * 0x100 + 0x8) 408f73b37cSIoana Ciornei #define LYNX_28G_PLLnCR1_FRATE_SEL(cr1) (((cr1) & GENMASK(28, 24))) 418f73b37cSIoana Ciornei #define LYNX_28G_PLLnCR1_FRATE_5G_10GVCO 0x0 428f73b37cSIoana Ciornei #define LYNX_28G_PLLnCR1_FRATE_5G_25GVCO 0x10000000 438f73b37cSIoana Ciornei #define LYNX_28G_PLLnCR1_FRATE_10G_20GVCO 0x6000000 448f73b37cSIoana Ciornei 458f73b37cSIoana Ciornei /* Per SerDes lane registers */ 468f73b37cSIoana Ciornei /* Lane a General Control Register */ 478f73b37cSIoana Ciornei #define LYNX_28G_LNaGCR0(lane) (0x800 + (lane) * 0x100 + 0x0) 488f73b37cSIoana Ciornei #define LYNX_28G_LNaGCR0_PROTO_SEL_MSK GENMASK(7, 3) 498f73b37cSIoana Ciornei #define LYNX_28G_LNaGCR0_PROTO_SEL_SGMII 0x8 508f73b37cSIoana Ciornei #define LYNX_28G_LNaGCR0_PROTO_SEL_XFI 0x50 518f73b37cSIoana Ciornei #define LYNX_28G_LNaGCR0_IF_WIDTH_MSK GENMASK(2, 0) 528f73b37cSIoana Ciornei #define LYNX_28G_LNaGCR0_IF_WIDTH_10_BIT 0x0 538f73b37cSIoana Ciornei #define LYNX_28G_LNaGCR0_IF_WIDTH_20_BIT 0x2 548f73b37cSIoana Ciornei 558f73b37cSIoana Ciornei /* Lane a Tx Reset Control Register */ 568f73b37cSIoana Ciornei #define LYNX_28G_LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20) 578f73b37cSIoana Ciornei #define LYNX_28G_LNaTRSTCTL_HLT_REQ BIT(27) 588f73b37cSIoana Ciornei #define LYNX_28G_LNaTRSTCTL_RST_DONE BIT(30) 598f73b37cSIoana Ciornei #define LYNX_28G_LNaTRSTCTL_RST_REQ BIT(31) 608f73b37cSIoana Ciornei 618f73b37cSIoana Ciornei /* Lane a Tx General Control Register */ 628f73b37cSIoana Ciornei #define LYNX_28G_LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24) 638f73b37cSIoana Ciornei #define LYNX_28G_LNaTGCR0_USE_PLLF 0x0 648f73b37cSIoana Ciornei #define LYNX_28G_LNaTGCR0_USE_PLLS BIT(28) 658f73b37cSIoana Ciornei #define LYNX_28G_LNaTGCR0_USE_PLL_MSK BIT(28) 668f73b37cSIoana Ciornei #define LYNX_28G_LNaTGCR0_N_RATE_FULL 0x0 678f73b37cSIoana Ciornei #define LYNX_28G_LNaTGCR0_N_RATE_HALF 0x1000000 688f73b37cSIoana Ciornei #define LYNX_28G_LNaTGCR0_N_RATE_QUARTER 0x2000000 698f73b37cSIoana Ciornei #define LYNX_28G_LNaTGCR0_N_RATE_MSK GENMASK(26, 24) 708f73b37cSIoana Ciornei 718f73b37cSIoana Ciornei #define LYNX_28G_LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30) 728f73b37cSIoana Ciornei 738f73b37cSIoana Ciornei /* Lane a Rx Reset Control Register */ 748f73b37cSIoana Ciornei #define LYNX_28G_LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40) 758f73b37cSIoana Ciornei #define LYNX_28G_LNaRRSTCTL_HLT_REQ BIT(27) 768f73b37cSIoana Ciornei #define LYNX_28G_LNaRRSTCTL_RST_DONE BIT(30) 778f73b37cSIoana Ciornei #define LYNX_28G_LNaRRSTCTL_RST_REQ BIT(31) 788f73b37cSIoana Ciornei #define LYNX_28G_LNaRRSTCTL_CDR_LOCK BIT(12) 798f73b37cSIoana Ciornei 808f73b37cSIoana Ciornei /* Lane a Rx General Control Register */ 818f73b37cSIoana Ciornei #define LYNX_28G_LNaRGCR0(lane) (0x800 + (lane) * 0x100 + 0x44) 828f73b37cSIoana Ciornei #define LYNX_28G_LNaRGCR0_USE_PLLF 0x0 838f73b37cSIoana Ciornei #define LYNX_28G_LNaRGCR0_USE_PLLS BIT(28) 848f73b37cSIoana Ciornei #define LYNX_28G_LNaRGCR0_USE_PLL_MSK BIT(28) 858f73b37cSIoana Ciornei #define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24) 868f73b37cSIoana Ciornei #define LYNX_28G_LNaRGCR0_N_RATE_FULL 0x0 878f73b37cSIoana Ciornei #define LYNX_28G_LNaRGCR0_N_RATE_HALF 0x1000000 888f73b37cSIoana Ciornei #define LYNX_28G_LNaRGCR0_N_RATE_QUARTER 0x2000000 898f73b37cSIoana Ciornei #define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24) 908f73b37cSIoana Ciornei 918f73b37cSIoana Ciornei #define LYNX_28G_LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48) 928f73b37cSIoana Ciornei 938f73b37cSIoana Ciornei #define LYNX_28G_LNaRECR0(lane) (0x800 + (lane) * 0x100 + 0x50) 948f73b37cSIoana Ciornei #define LYNX_28G_LNaRECR1(lane) (0x800 + (lane) * 0x100 + 0x54) 958f73b37cSIoana Ciornei #define LYNX_28G_LNaRECR2(lane) (0x800 + (lane) * 0x100 + 0x58) 968f73b37cSIoana Ciornei 978f73b37cSIoana Ciornei #define LYNX_28G_LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74) 988f73b37cSIoana Ciornei 998f73b37cSIoana Ciornei #define LYNX_28G_LNaPSS(lane) (0x1000 + (lane) * 0x4) 1008f73b37cSIoana Ciornei #define LYNX_28G_LNaPSS_TYPE(pss) (((pss) & GENMASK(30, 24)) >> 24) 1018f73b37cSIoana Ciornei #define LYNX_28G_LNaPSS_TYPE_SGMII 0x4 1028f73b37cSIoana Ciornei #define LYNX_28G_LNaPSS_TYPE_XFI 0x28 1038f73b37cSIoana Ciornei 1048f73b37cSIoana Ciornei #define LYNX_28G_SGMIIaCR1(lane) (0x1804 + (lane) * 0x10) 1058f73b37cSIoana Ciornei #define LYNX_28G_SGMIIaCR1_SGPCS_EN BIT(11) 1068f73b37cSIoana Ciornei #define LYNX_28G_SGMIIaCR1_SGPCS_DIS 0x0 1078f73b37cSIoana Ciornei #define LYNX_28G_SGMIIaCR1_SGPCS_MSK BIT(11) 1088f73b37cSIoana Ciornei 1098f73b37cSIoana Ciornei struct lynx_28g_priv; 1108f73b37cSIoana Ciornei 1118f73b37cSIoana Ciornei struct lynx_28g_pll { 1128f73b37cSIoana Ciornei struct lynx_28g_priv *priv; 1138f73b37cSIoana Ciornei u32 rstctl, cr0, cr1; 1148f73b37cSIoana Ciornei int id; 1158f73b37cSIoana Ciornei DECLARE_PHY_INTERFACE_MASK(supported); 1168f73b37cSIoana Ciornei }; 1178f73b37cSIoana Ciornei 1188f73b37cSIoana Ciornei struct lynx_28g_lane { 1198f73b37cSIoana Ciornei struct lynx_28g_priv *priv; 1208f73b37cSIoana Ciornei struct phy *phy; 1218f73b37cSIoana Ciornei bool powered_up; 1228f73b37cSIoana Ciornei bool init; 1238f73b37cSIoana Ciornei unsigned int id; 1248f73b37cSIoana Ciornei phy_interface_t interface; 1258f73b37cSIoana Ciornei }; 1268f73b37cSIoana Ciornei 1278f73b37cSIoana Ciornei struct lynx_28g_priv { 1288f73b37cSIoana Ciornei void __iomem *base; 1298f73b37cSIoana Ciornei struct device *dev; 1308f73b37cSIoana Ciornei struct lynx_28g_pll pll[LYNX_28G_NUM_PLL]; 1318f73b37cSIoana Ciornei struct lynx_28g_lane lane[LYNX_28G_NUM_LANE]; 1328f73b37cSIoana Ciornei 1338f73b37cSIoana Ciornei struct delayed_work cdr_check; 1348f73b37cSIoana Ciornei }; 1358f73b37cSIoana Ciornei 1368f73b37cSIoana Ciornei static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off, 1378f73b37cSIoana Ciornei u32 val, u32 mask) 1388f73b37cSIoana Ciornei { 1398f73b37cSIoana Ciornei void __iomem *reg = priv->base + off; 1408f73b37cSIoana Ciornei u32 orig, tmp; 1418f73b37cSIoana Ciornei 1428f73b37cSIoana Ciornei orig = ioread32(reg); 1438f73b37cSIoana Ciornei tmp = orig & ~mask; 1448f73b37cSIoana Ciornei tmp |= val; 1458f73b37cSIoana Ciornei iowrite32(tmp, reg); 1468f73b37cSIoana Ciornei } 1478f73b37cSIoana Ciornei 1488f73b37cSIoana Ciornei #define lynx_28g_lane_rmw(lane, reg, val, mask) \ 1498f73b37cSIoana Ciornei lynx_28g_rmw((lane)->priv, LYNX_28G_##reg(lane->id), \ 1508f73b37cSIoana Ciornei LYNX_28G_##reg##_##val, LYNX_28G_##reg##_##mask) 1518f73b37cSIoana Ciornei #define lynx_28g_lane_read(lane, reg) \ 1528f73b37cSIoana Ciornei ioread32((lane)->priv->base + LYNX_28G_##reg((lane)->id)) 1538f73b37cSIoana Ciornei #define lynx_28g_pll_read(pll, reg) \ 1548f73b37cSIoana Ciornei ioread32((pll)->priv->base + LYNX_28G_##reg((pll)->id)) 1558f73b37cSIoana Ciornei 1568f73b37cSIoana Ciornei static bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf) 1578f73b37cSIoana Ciornei { 1588f73b37cSIoana Ciornei int i; 1598f73b37cSIoana Ciornei 1608f73b37cSIoana Ciornei for (i = 0; i < LYNX_28G_NUM_PLL; i++) { 1618f73b37cSIoana Ciornei if (LYNX_28G_PLLnRSTCTL_DIS(priv->pll[i].rstctl)) 1628f73b37cSIoana Ciornei continue; 1638f73b37cSIoana Ciornei 1648f73b37cSIoana Ciornei if (test_bit(intf, priv->pll[i].supported)) 1658f73b37cSIoana Ciornei return true; 1668f73b37cSIoana Ciornei } 1678f73b37cSIoana Ciornei 1688f73b37cSIoana Ciornei return false; 1698f73b37cSIoana Ciornei } 1708f73b37cSIoana Ciornei 1718f73b37cSIoana Ciornei static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv, 1728f73b37cSIoana Ciornei phy_interface_t intf) 1738f73b37cSIoana Ciornei { 1748f73b37cSIoana Ciornei struct lynx_28g_pll *pll; 1758f73b37cSIoana Ciornei int i; 1768f73b37cSIoana Ciornei 1778f73b37cSIoana Ciornei for (i = 0; i < LYNX_28G_NUM_PLL; i++) { 1788f73b37cSIoana Ciornei pll = &priv->pll[i]; 1798f73b37cSIoana Ciornei 1808f73b37cSIoana Ciornei if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl)) 1818f73b37cSIoana Ciornei continue; 1828f73b37cSIoana Ciornei 1838f73b37cSIoana Ciornei if (test_bit(intf, pll->supported)) 1848f73b37cSIoana Ciornei return pll; 1858f73b37cSIoana Ciornei } 1868f73b37cSIoana Ciornei 1878f73b37cSIoana Ciornei return NULL; 1888f73b37cSIoana Ciornei } 1898f73b37cSIoana Ciornei 1908f73b37cSIoana Ciornei static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane, 1918f73b37cSIoana Ciornei struct lynx_28g_pll *pll, 1928f73b37cSIoana Ciornei phy_interface_t intf) 1938f73b37cSIoana Ciornei { 1948f73b37cSIoana Ciornei switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) { 1958f73b37cSIoana Ciornei case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO: 1968f73b37cSIoana Ciornei case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO: 1978f73b37cSIoana Ciornei switch (intf) { 1988f73b37cSIoana Ciornei case PHY_INTERFACE_MODE_SGMII: 1998f73b37cSIoana Ciornei case PHY_INTERFACE_MODE_1000BASEX: 2008f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_QUARTER, N_RATE_MSK); 2018f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_QUARTER, N_RATE_MSK); 2028f73b37cSIoana Ciornei break; 2038f73b37cSIoana Ciornei default: 2048f73b37cSIoana Ciornei break; 2058f73b37cSIoana Ciornei } 2068f73b37cSIoana Ciornei break; 2078f73b37cSIoana Ciornei case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO: 2088f73b37cSIoana Ciornei switch (intf) { 2098f73b37cSIoana Ciornei case PHY_INTERFACE_MODE_10GBASER: 2108f73b37cSIoana Ciornei case PHY_INTERFACE_MODE_USXGMII: 2118f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_FULL, N_RATE_MSK); 2128f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_FULL, N_RATE_MSK); 2138f73b37cSIoana Ciornei break; 2148f73b37cSIoana Ciornei default: 2158f73b37cSIoana Ciornei break; 2168f73b37cSIoana Ciornei } 2178f73b37cSIoana Ciornei break; 2188f73b37cSIoana Ciornei default: 2198f73b37cSIoana Ciornei break; 2208f73b37cSIoana Ciornei } 2218f73b37cSIoana Ciornei } 2228f73b37cSIoana Ciornei 2238f73b37cSIoana Ciornei static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane, 2248f73b37cSIoana Ciornei struct lynx_28g_pll *pll) 2258f73b37cSIoana Ciornei { 2268f73b37cSIoana Ciornei if (pll->id == 0) { 2278f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLF, USE_PLL_MSK); 2288f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLF, USE_PLL_MSK); 2298f73b37cSIoana Ciornei } else { 2308f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLS, USE_PLL_MSK); 2318f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLS, USE_PLL_MSK); 2328f73b37cSIoana Ciornei } 2338f73b37cSIoana Ciornei } 2348f73b37cSIoana Ciornei 2358f73b37cSIoana Ciornei static void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane) 2368f73b37cSIoana Ciornei { 2378f73b37cSIoana Ciornei u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane); 2388f73b37cSIoana Ciornei struct lynx_28g_priv *priv = lane->priv; 2398f73b37cSIoana Ciornei 2408f73b37cSIoana Ciornei /* Cleanup the protocol configuration registers of the current protocol */ 2418f73b37cSIoana Ciornei switch (lane->interface) { 2428f73b37cSIoana Ciornei case PHY_INTERFACE_MODE_10GBASER: 2438f73b37cSIoana Ciornei lynx_28g_rmw(priv, LYNX_28G_PCCC, 2448f73b37cSIoana Ciornei LYNX_28G_PCCC_SXGMII_DIS << lane_offset, 2458f73b37cSIoana Ciornei GENMASK(3, 0) << lane_offset); 2468f73b37cSIoana Ciornei break; 2478f73b37cSIoana Ciornei case PHY_INTERFACE_MODE_SGMII: 2488f73b37cSIoana Ciornei case PHY_INTERFACE_MODE_1000BASEX: 2498f73b37cSIoana Ciornei lynx_28g_rmw(priv, LYNX_28G_PCC8, 2508f73b37cSIoana Ciornei LYNX_28G_PCC8_SGMII_DIS << lane_offset, 2518f73b37cSIoana Ciornei GENMASK(3, 0) << lane_offset); 2528f73b37cSIoana Ciornei break; 2538f73b37cSIoana Ciornei default: 2548f73b37cSIoana Ciornei break; 2558f73b37cSIoana Ciornei } 2568f73b37cSIoana Ciornei } 2578f73b37cSIoana Ciornei 2588f73b37cSIoana Ciornei static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane) 2598f73b37cSIoana Ciornei { 2608f73b37cSIoana Ciornei u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane); 2618f73b37cSIoana Ciornei struct lynx_28g_priv *priv = lane->priv; 2628f73b37cSIoana Ciornei struct lynx_28g_pll *pll; 2638f73b37cSIoana Ciornei 2648f73b37cSIoana Ciornei lynx_28g_cleanup_lane(lane); 2658f73b37cSIoana Ciornei 2668f73b37cSIoana Ciornei /* Setup the lane to run in SGMII */ 2678f73b37cSIoana Ciornei lynx_28g_rmw(priv, LYNX_28G_PCC8, 2688f73b37cSIoana Ciornei LYNX_28G_PCC8_SGMII << lane_offset, 2698f73b37cSIoana Ciornei GENMASK(3, 0) << lane_offset); 2708f73b37cSIoana Ciornei 2718f73b37cSIoana Ciornei /* Setup the protocol select and SerDes parallel interface width */ 2728f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_SGMII, PROTO_SEL_MSK); 2738f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_10_BIT, IF_WIDTH_MSK); 2748f73b37cSIoana Ciornei 2758f73b37cSIoana Ciornei /* Switch to the PLL that works with this interface type */ 2768f73b37cSIoana Ciornei pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII); 2778f73b37cSIoana Ciornei lynx_28g_lane_set_pll(lane, pll); 2788f73b37cSIoana Ciornei 2798f73b37cSIoana Ciornei /* Choose the portion of clock net to be used on this lane */ 2808f73b37cSIoana Ciornei lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_SGMII); 2818f73b37cSIoana Ciornei 2828f73b37cSIoana Ciornei /* Enable the SGMII PCS */ 2838f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_EN, SGPCS_MSK); 2848f73b37cSIoana Ciornei 2858f73b37cSIoana Ciornei /* Configure the appropriate equalization parameters for the protocol */ 2868f73b37cSIoana Ciornei iowrite32(0x00808006, priv->base + LYNX_28G_LNaTECR0(lane->id)); 2878f73b37cSIoana Ciornei iowrite32(0x04310000, priv->base + LYNX_28G_LNaRGCR1(lane->id)); 2888f73b37cSIoana Ciornei iowrite32(0x9f800000, priv->base + LYNX_28G_LNaRECR0(lane->id)); 2898f73b37cSIoana Ciornei iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id)); 2908f73b37cSIoana Ciornei iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR2(lane->id)); 2918f73b37cSIoana Ciornei iowrite32(0x00000000, priv->base + LYNX_28G_LNaRSCCR0(lane->id)); 2928f73b37cSIoana Ciornei } 2938f73b37cSIoana Ciornei 2948f73b37cSIoana Ciornei static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane) 2958f73b37cSIoana Ciornei { 2968f73b37cSIoana Ciornei u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane); 2978f73b37cSIoana Ciornei struct lynx_28g_priv *priv = lane->priv; 2988f73b37cSIoana Ciornei struct lynx_28g_pll *pll; 2998f73b37cSIoana Ciornei 3008f73b37cSIoana Ciornei lynx_28g_cleanup_lane(lane); 3018f73b37cSIoana Ciornei 3028f73b37cSIoana Ciornei /* Enable the SXGMII lane */ 3038f73b37cSIoana Ciornei lynx_28g_rmw(priv, LYNX_28G_PCCC, 3048f73b37cSIoana Ciornei LYNX_28G_PCCC_10GBASER << lane_offset, 3058f73b37cSIoana Ciornei GENMASK(3, 0) << lane_offset); 3068f73b37cSIoana Ciornei 3078f73b37cSIoana Ciornei /* Setup the protocol select and SerDes parallel interface width */ 3088f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_XFI, PROTO_SEL_MSK); 3098f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_20_BIT, IF_WIDTH_MSK); 3108f73b37cSIoana Ciornei 3118f73b37cSIoana Ciornei /* Switch to the PLL that works with this interface type */ 3128f73b37cSIoana Ciornei pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER); 3138f73b37cSIoana Ciornei lynx_28g_lane_set_pll(lane, pll); 3148f73b37cSIoana Ciornei 3158f73b37cSIoana Ciornei /* Choose the portion of clock net to be used on this lane */ 3168f73b37cSIoana Ciornei lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_10GBASER); 3178f73b37cSIoana Ciornei 3188f73b37cSIoana Ciornei /* Disable the SGMII PCS */ 3198f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_DIS, SGPCS_MSK); 3208f73b37cSIoana Ciornei 3218f73b37cSIoana Ciornei /* Configure the appropriate equalization parameters for the protocol */ 3228f73b37cSIoana Ciornei iowrite32(0x10808307, priv->base + LYNX_28G_LNaTECR0(lane->id)); 3238f73b37cSIoana Ciornei iowrite32(0x10000000, priv->base + LYNX_28G_LNaRGCR1(lane->id)); 3248f73b37cSIoana Ciornei iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR0(lane->id)); 3258f73b37cSIoana Ciornei iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id)); 3268f73b37cSIoana Ciornei iowrite32(0x81000020, priv->base + LYNX_28G_LNaRECR2(lane->id)); 3278f73b37cSIoana Ciornei iowrite32(0x00002000, priv->base + LYNX_28G_LNaRSCCR0(lane->id)); 3288f73b37cSIoana Ciornei } 3298f73b37cSIoana Ciornei 3308f73b37cSIoana Ciornei static int lynx_28g_power_off(struct phy *phy) 3318f73b37cSIoana Ciornei { 3328f73b37cSIoana Ciornei struct lynx_28g_lane *lane = phy_get_drvdata(phy); 3338f73b37cSIoana Ciornei u32 trstctl, rrstctl; 3348f73b37cSIoana Ciornei 3358f73b37cSIoana Ciornei if (!lane->powered_up) 3368f73b37cSIoana Ciornei return 0; 3378f73b37cSIoana Ciornei 3388f73b37cSIoana Ciornei /* Issue a halt request */ 3398f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaTRSTCTL, HLT_REQ, HLT_REQ); 3408f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaRRSTCTL, HLT_REQ, HLT_REQ); 3418f73b37cSIoana Ciornei 3428f73b37cSIoana Ciornei /* Wait until the halting process is complete */ 3438f73b37cSIoana Ciornei do { 3448f73b37cSIoana Ciornei trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL); 3458f73b37cSIoana Ciornei rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); 3468f73b37cSIoana Ciornei } while ((trstctl & LYNX_28G_LNaTRSTCTL_HLT_REQ) || 3478f73b37cSIoana Ciornei (rrstctl & LYNX_28G_LNaRRSTCTL_HLT_REQ)); 3488f73b37cSIoana Ciornei 3498f73b37cSIoana Ciornei lane->powered_up = false; 3508f73b37cSIoana Ciornei 3518f73b37cSIoana Ciornei return 0; 3528f73b37cSIoana Ciornei } 3538f73b37cSIoana Ciornei 3548f73b37cSIoana Ciornei static int lynx_28g_power_on(struct phy *phy) 3558f73b37cSIoana Ciornei { 3568f73b37cSIoana Ciornei struct lynx_28g_lane *lane = phy_get_drvdata(phy); 3578f73b37cSIoana Ciornei u32 trstctl, rrstctl; 3588f73b37cSIoana Ciornei 3598f73b37cSIoana Ciornei if (lane->powered_up) 3608f73b37cSIoana Ciornei return 0; 3618f73b37cSIoana Ciornei 3628f73b37cSIoana Ciornei /* Issue a reset request on the lane */ 3638f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaTRSTCTL, RST_REQ, RST_REQ); 3648f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ); 3658f73b37cSIoana Ciornei 3668f73b37cSIoana Ciornei /* Wait until the reset sequence is completed */ 3678f73b37cSIoana Ciornei do { 3688f73b37cSIoana Ciornei trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL); 3698f73b37cSIoana Ciornei rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); 3708f73b37cSIoana Ciornei } while (!(trstctl & LYNX_28G_LNaTRSTCTL_RST_DONE) || 3718f73b37cSIoana Ciornei !(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE)); 3728f73b37cSIoana Ciornei 3738f73b37cSIoana Ciornei lane->powered_up = true; 3748f73b37cSIoana Ciornei 3758f73b37cSIoana Ciornei return 0; 3768f73b37cSIoana Ciornei } 3778f73b37cSIoana Ciornei 3788f73b37cSIoana Ciornei static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode) 3798f73b37cSIoana Ciornei { 3808f73b37cSIoana Ciornei struct lynx_28g_lane *lane = phy_get_drvdata(phy); 3818f73b37cSIoana Ciornei struct lynx_28g_priv *priv = lane->priv; 3828f73b37cSIoana Ciornei int powered_up = lane->powered_up; 3838f73b37cSIoana Ciornei int err = 0; 3848f73b37cSIoana Ciornei 3858f73b37cSIoana Ciornei if (mode != PHY_MODE_ETHERNET) 3868f73b37cSIoana Ciornei return -EOPNOTSUPP; 3878f73b37cSIoana Ciornei 3888f73b37cSIoana Ciornei if (lane->interface == PHY_INTERFACE_MODE_NA) 3898f73b37cSIoana Ciornei return -EOPNOTSUPP; 3908f73b37cSIoana Ciornei 3918f73b37cSIoana Ciornei if (!lynx_28g_supports_interface(priv, submode)) 3928f73b37cSIoana Ciornei return -EOPNOTSUPP; 3938f73b37cSIoana Ciornei 3948f73b37cSIoana Ciornei /* If the lane is powered up, put the lane into the halt state while 3958f73b37cSIoana Ciornei * the reconfiguration is being done. 3968f73b37cSIoana Ciornei */ 3978f73b37cSIoana Ciornei if (powered_up) 3988f73b37cSIoana Ciornei lynx_28g_power_off(phy); 3998f73b37cSIoana Ciornei 4008f73b37cSIoana Ciornei switch (submode) { 4018f73b37cSIoana Ciornei case PHY_INTERFACE_MODE_SGMII: 4028f73b37cSIoana Ciornei case PHY_INTERFACE_MODE_1000BASEX: 4038f73b37cSIoana Ciornei lynx_28g_lane_set_sgmii(lane); 4048f73b37cSIoana Ciornei break; 4058f73b37cSIoana Ciornei case PHY_INTERFACE_MODE_10GBASER: 4068f73b37cSIoana Ciornei lynx_28g_lane_set_10gbaser(lane); 4078f73b37cSIoana Ciornei break; 4088f73b37cSIoana Ciornei default: 4098f73b37cSIoana Ciornei err = -EOPNOTSUPP; 4108f73b37cSIoana Ciornei goto out; 4118f73b37cSIoana Ciornei } 4128f73b37cSIoana Ciornei 4138f73b37cSIoana Ciornei lane->interface = submode; 4148f73b37cSIoana Ciornei 4158f73b37cSIoana Ciornei out: 4168f73b37cSIoana Ciornei /* Power up the lane if necessary */ 4178f73b37cSIoana Ciornei if (powered_up) 4188f73b37cSIoana Ciornei lynx_28g_power_on(phy); 4198f73b37cSIoana Ciornei 4208f73b37cSIoana Ciornei return err; 4218f73b37cSIoana Ciornei } 4228f73b37cSIoana Ciornei 4238f73b37cSIoana Ciornei static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode, 4248f73b37cSIoana Ciornei union phy_configure_opts *opts __always_unused) 4258f73b37cSIoana Ciornei { 4268f73b37cSIoana Ciornei struct lynx_28g_lane *lane = phy_get_drvdata(phy); 4278f73b37cSIoana Ciornei struct lynx_28g_priv *priv = lane->priv; 4288f73b37cSIoana Ciornei 4298f73b37cSIoana Ciornei if (mode != PHY_MODE_ETHERNET) 4308f73b37cSIoana Ciornei return -EOPNOTSUPP; 4318f73b37cSIoana Ciornei 4328f73b37cSIoana Ciornei if (!lynx_28g_supports_interface(priv, submode)) 4338f73b37cSIoana Ciornei return -EOPNOTSUPP; 4348f73b37cSIoana Ciornei 4358f73b37cSIoana Ciornei return 0; 4368f73b37cSIoana Ciornei } 4378f73b37cSIoana Ciornei 4388f73b37cSIoana Ciornei static int lynx_28g_init(struct phy *phy) 4398f73b37cSIoana Ciornei { 4408f73b37cSIoana Ciornei struct lynx_28g_lane *lane = phy_get_drvdata(phy); 4418f73b37cSIoana Ciornei 4428f73b37cSIoana Ciornei /* Mark the fact that the lane was init */ 4438f73b37cSIoana Ciornei lane->init = true; 4448f73b37cSIoana Ciornei 4458f73b37cSIoana Ciornei /* SerDes lanes are powered on at boot time. Any lane that is managed 4468f73b37cSIoana Ciornei * by this driver will get powered down at init time aka at dpaa2-eth 4478f73b37cSIoana Ciornei * probe time. 4488f73b37cSIoana Ciornei */ 4498f73b37cSIoana Ciornei lane->powered_up = true; 4508f73b37cSIoana Ciornei lynx_28g_power_off(phy); 4518f73b37cSIoana Ciornei 4528f73b37cSIoana Ciornei return 0; 4538f73b37cSIoana Ciornei } 4548f73b37cSIoana Ciornei 4558f73b37cSIoana Ciornei static const struct phy_ops lynx_28g_ops = { 4568f73b37cSIoana Ciornei .init = lynx_28g_init, 4578f73b37cSIoana Ciornei .power_on = lynx_28g_power_on, 4588f73b37cSIoana Ciornei .power_off = lynx_28g_power_off, 4598f73b37cSIoana Ciornei .set_mode = lynx_28g_set_mode, 4608f73b37cSIoana Ciornei .validate = lynx_28g_validate, 4618f73b37cSIoana Ciornei .owner = THIS_MODULE, 4628f73b37cSIoana Ciornei }; 4638f73b37cSIoana Ciornei 4648f73b37cSIoana Ciornei static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv) 4658f73b37cSIoana Ciornei { 4668f73b37cSIoana Ciornei struct lynx_28g_pll *pll; 4678f73b37cSIoana Ciornei int i; 4688f73b37cSIoana Ciornei 4698f73b37cSIoana Ciornei for (i = 0; i < LYNX_28G_NUM_PLL; i++) { 4708f73b37cSIoana Ciornei pll = &priv->pll[i]; 4718f73b37cSIoana Ciornei pll->priv = priv; 4728f73b37cSIoana Ciornei pll->id = i; 4738f73b37cSIoana Ciornei 4748f73b37cSIoana Ciornei pll->rstctl = lynx_28g_pll_read(pll, PLLnRSTCTL); 4758f73b37cSIoana Ciornei pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0); 4768f73b37cSIoana Ciornei pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1); 4778f73b37cSIoana Ciornei 4788f73b37cSIoana Ciornei if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl)) 4798f73b37cSIoana Ciornei continue; 4808f73b37cSIoana Ciornei 4818f73b37cSIoana Ciornei switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) { 4828f73b37cSIoana Ciornei case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO: 4838f73b37cSIoana Ciornei case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO: 4848f73b37cSIoana Ciornei /* 5GHz clock net */ 4858f73b37cSIoana Ciornei __set_bit(PHY_INTERFACE_MODE_1000BASEX, pll->supported); 4868f73b37cSIoana Ciornei __set_bit(PHY_INTERFACE_MODE_SGMII, pll->supported); 4878f73b37cSIoana Ciornei break; 4888f73b37cSIoana Ciornei case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO: 4898f73b37cSIoana Ciornei /* 10.3125GHz clock net */ 4908f73b37cSIoana Ciornei __set_bit(PHY_INTERFACE_MODE_10GBASER, pll->supported); 4918f73b37cSIoana Ciornei break; 4928f73b37cSIoana Ciornei default: 4938f73b37cSIoana Ciornei /* 6GHz, 12.890625GHz, 8GHz */ 4948f73b37cSIoana Ciornei break; 4958f73b37cSIoana Ciornei } 4968f73b37cSIoana Ciornei } 4978f73b37cSIoana Ciornei } 4988f73b37cSIoana Ciornei 4998f73b37cSIoana Ciornei #define work_to_lynx(w) container_of((w), struct lynx_28g_priv, cdr_check.work) 5008f73b37cSIoana Ciornei 5018f73b37cSIoana Ciornei static void lynx_28g_cdr_lock_check(struct work_struct *work) 5028f73b37cSIoana Ciornei { 5038f73b37cSIoana Ciornei struct lynx_28g_priv *priv = work_to_lynx(work); 5048f73b37cSIoana Ciornei struct lynx_28g_lane *lane; 5058f73b37cSIoana Ciornei u32 rrstctl; 5068f73b37cSIoana Ciornei int i; 5078f73b37cSIoana Ciornei 5088f73b37cSIoana Ciornei for (i = 0; i < LYNX_28G_NUM_LANE; i++) { 5098f73b37cSIoana Ciornei lane = &priv->lane[i]; 5108f73b37cSIoana Ciornei 5118f73b37cSIoana Ciornei if (!lane->init) 5128f73b37cSIoana Ciornei continue; 5138f73b37cSIoana Ciornei 5148f73b37cSIoana Ciornei if (!lane->powered_up) 5158f73b37cSIoana Ciornei continue; 5168f73b37cSIoana Ciornei 5178f73b37cSIoana Ciornei rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); 5188f73b37cSIoana Ciornei if (!(rrstctl & LYNX_28G_LNaRRSTCTL_CDR_LOCK)) { 5198f73b37cSIoana Ciornei lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ); 5208f73b37cSIoana Ciornei do { 5218f73b37cSIoana Ciornei rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL); 5228f73b37cSIoana Ciornei } while (!(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE)); 5238f73b37cSIoana Ciornei } 5248f73b37cSIoana Ciornei } 5258f73b37cSIoana Ciornei queue_delayed_work(system_power_efficient_wq, &priv->cdr_check, 5268f73b37cSIoana Ciornei msecs_to_jiffies(1000)); 5278f73b37cSIoana Ciornei } 5288f73b37cSIoana Ciornei 5298f73b37cSIoana Ciornei static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane) 5308f73b37cSIoana Ciornei { 5318f73b37cSIoana Ciornei u32 pss, protocol; 5328f73b37cSIoana Ciornei 5338f73b37cSIoana Ciornei pss = lynx_28g_lane_read(lane, LNaPSS); 5348f73b37cSIoana Ciornei protocol = LYNX_28G_LNaPSS_TYPE(pss); 5358f73b37cSIoana Ciornei switch (protocol) { 5368f73b37cSIoana Ciornei case LYNX_28G_LNaPSS_TYPE_SGMII: 5378f73b37cSIoana Ciornei lane->interface = PHY_INTERFACE_MODE_SGMII; 5388f73b37cSIoana Ciornei break; 5398f73b37cSIoana Ciornei case LYNX_28G_LNaPSS_TYPE_XFI: 5408f73b37cSIoana Ciornei lane->interface = PHY_INTERFACE_MODE_10GBASER; 5418f73b37cSIoana Ciornei break; 5428f73b37cSIoana Ciornei default: 5438f73b37cSIoana Ciornei lane->interface = PHY_INTERFACE_MODE_NA; 5448f73b37cSIoana Ciornei } 5458f73b37cSIoana Ciornei } 5468f73b37cSIoana Ciornei 5478f73b37cSIoana Ciornei static struct phy *lynx_28g_xlate(struct device *dev, 5488f73b37cSIoana Ciornei struct of_phandle_args *args) 5498f73b37cSIoana Ciornei { 5508f73b37cSIoana Ciornei struct lynx_28g_priv *priv = dev_get_drvdata(dev); 5518f73b37cSIoana Ciornei int idx = args->args[0]; 5528f73b37cSIoana Ciornei 5538f73b37cSIoana Ciornei if (WARN_ON(idx >= LYNX_28G_NUM_LANE)) 5548f73b37cSIoana Ciornei return ERR_PTR(-EINVAL); 5558f73b37cSIoana Ciornei 5568f73b37cSIoana Ciornei return priv->lane[idx].phy; 5578f73b37cSIoana Ciornei } 5588f73b37cSIoana Ciornei 5598f73b37cSIoana Ciornei static int lynx_28g_probe(struct platform_device *pdev) 5608f73b37cSIoana Ciornei { 5618f73b37cSIoana Ciornei struct device *dev = &pdev->dev; 5628f73b37cSIoana Ciornei struct phy_provider *provider; 5638f73b37cSIoana Ciornei struct lynx_28g_priv *priv; 5648f73b37cSIoana Ciornei int i; 5658f73b37cSIoana Ciornei 5668f73b37cSIoana Ciornei priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 5678f73b37cSIoana Ciornei if (!priv) 5688f73b37cSIoana Ciornei return -ENOMEM; 5698f73b37cSIoana Ciornei priv->dev = &pdev->dev; 5708f73b37cSIoana Ciornei 5718f73b37cSIoana Ciornei priv->base = devm_platform_ioremap_resource(pdev, 0); 5728f73b37cSIoana Ciornei if (IS_ERR(priv->base)) 5738f73b37cSIoana Ciornei return PTR_ERR(priv->base); 5748f73b37cSIoana Ciornei 5758f73b37cSIoana Ciornei lynx_28g_pll_read_configuration(priv); 5768f73b37cSIoana Ciornei 5778f73b37cSIoana Ciornei for (i = 0; i < LYNX_28G_NUM_LANE; i++) { 5788f73b37cSIoana Ciornei struct lynx_28g_lane *lane = &priv->lane[i]; 5798f73b37cSIoana Ciornei struct phy *phy; 5808f73b37cSIoana Ciornei 5818f73b37cSIoana Ciornei memset(lane, 0, sizeof(*lane)); 5828f73b37cSIoana Ciornei 5838f73b37cSIoana Ciornei phy = devm_phy_create(&pdev->dev, NULL, &lynx_28g_ops); 5848f73b37cSIoana Ciornei if (IS_ERR(phy)) 5858f73b37cSIoana Ciornei return PTR_ERR(phy); 5868f73b37cSIoana Ciornei 5878f73b37cSIoana Ciornei lane->priv = priv; 5888f73b37cSIoana Ciornei lane->phy = phy; 5898f73b37cSIoana Ciornei lane->id = i; 5908f73b37cSIoana Ciornei phy_set_drvdata(phy, lane); 5918f73b37cSIoana Ciornei lynx_28g_lane_read_configuration(lane); 5928f73b37cSIoana Ciornei } 5938f73b37cSIoana Ciornei 5948f73b37cSIoana Ciornei dev_set_drvdata(dev, priv); 5958f73b37cSIoana Ciornei 5968f73b37cSIoana Ciornei INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check); 5978f73b37cSIoana Ciornei 5988f73b37cSIoana Ciornei queue_delayed_work(system_power_efficient_wq, &priv->cdr_check, 5998f73b37cSIoana Ciornei msecs_to_jiffies(1000)); 6008f73b37cSIoana Ciornei 6018f73b37cSIoana Ciornei dev_set_drvdata(&pdev->dev, priv); 6028f73b37cSIoana Ciornei provider = devm_of_phy_provider_register(&pdev->dev, lynx_28g_xlate); 6038f73b37cSIoana Ciornei 6048f73b37cSIoana Ciornei return PTR_ERR_OR_ZERO(provider); 6058f73b37cSIoana Ciornei } 6068f73b37cSIoana Ciornei 607*f200bab3SIoana Ciornei static void lynx_28g_remove(struct platform_device *pdev) 608*f200bab3SIoana Ciornei { 609*f200bab3SIoana Ciornei struct device *dev = &pdev->dev; 610*f200bab3SIoana Ciornei struct lynx_28g_priv *priv = dev_get_drvdata(dev); 611*f200bab3SIoana Ciornei 612*f200bab3SIoana Ciornei cancel_delayed_work_sync(&priv->cdr_check); 613*f200bab3SIoana Ciornei } 614*f200bab3SIoana Ciornei 6158f73b37cSIoana Ciornei static const struct of_device_id lynx_28g_of_match_table[] = { 6168f73b37cSIoana Ciornei { .compatible = "fsl,lynx-28g" }, 6178f73b37cSIoana Ciornei { }, 6188f73b37cSIoana Ciornei }; 6198f73b37cSIoana Ciornei MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table); 6208f73b37cSIoana Ciornei 6218f73b37cSIoana Ciornei static struct platform_driver lynx_28g_driver = { 6228f73b37cSIoana Ciornei .probe = lynx_28g_probe, 623*f200bab3SIoana Ciornei .remove_new = lynx_28g_remove, 6248f73b37cSIoana Ciornei .driver = { 6258f73b37cSIoana Ciornei .name = "lynx-28g", 6268f73b37cSIoana Ciornei .of_match_table = lynx_28g_of_match_table, 6278f73b37cSIoana Ciornei }, 6288f73b37cSIoana Ciornei }; 6298f73b37cSIoana Ciornei module_platform_driver(lynx_28g_driver); 6308f73b37cSIoana Ciornei 6318f73b37cSIoana Ciornei MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>"); 6328f73b37cSIoana Ciornei MODULE_DESCRIPTION("Lynx 28G SerDes PHY driver for Layerscape SoCs"); 6338f73b37cSIoana Ciornei MODULE_LICENSE("GPL v2"); 634