646 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/* Copyright (c) 2021-2022 NXP. */3 4#include <linux/module.h>5#include <linux/of.h>6#include <linux/phy.h>7#include <linux/phy/phy.h>8#include <linux/platform_device.h>9#include <linux/workqueue.h>10 11#define LYNX_28G_NUM_LANE 812#define LYNX_28G_NUM_PLL 213 14/* General registers per SerDes block */15#define LYNX_28G_PCC8 0x10a016#define LYNX_28G_PCC8_SGMII 0x117#define LYNX_28G_PCC8_SGMII_DIS 0x018 19#define LYNX_28G_PCCC 0x10b020#define LYNX_28G_PCCC_10GBASER 0x921#define LYNX_28G_PCCC_USXGMII 0x122#define LYNX_28G_PCCC_SXGMII_DIS 0x023 24#define LYNX_28G_LNa_PCC_OFFSET(lane) (4 * (LYNX_28G_NUM_LANE - (lane->id) - 1))25 26/* Per PLL registers */27#define LYNX_28G_PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0)28#define LYNX_28G_PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24)29#define LYNX_28G_PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23)30 31#define LYNX_28G_PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4)32#define LYNX_28G_PLLnCR0_REFCLK_SEL(cr0) (((cr0) & GENMASK(20, 16)))33#define LYNX_28G_PLLnCR0_REFCLK_SEL_100MHZ 0x034#define LYNX_28G_PLLnCR0_REFCLK_SEL_125MHZ 0x1000035#define LYNX_28G_PLLnCR0_REFCLK_SEL_156MHZ 0x2000036#define LYNX_28G_PLLnCR0_REFCLK_SEL_150MHZ 0x3000037#define LYNX_28G_PLLnCR0_REFCLK_SEL_161MHZ 0x4000038 39#define LYNX_28G_PLLnCR1(pll) (0x400 + (pll) * 0x100 + 0x8)40#define LYNX_28G_PLLnCR1_FRATE_SEL(cr1) (((cr1) & GENMASK(28, 24)))41#define LYNX_28G_PLLnCR1_FRATE_5G_10GVCO 0x042#define LYNX_28G_PLLnCR1_FRATE_5G_25GVCO 0x1000000043#define LYNX_28G_PLLnCR1_FRATE_10G_20GVCO 0x600000044 45/* Per SerDes lane registers */46/* Lane a General Control Register */47#define LYNX_28G_LNaGCR0(lane) (0x800 + (lane) * 0x100 + 0x0)48#define LYNX_28G_LNaGCR0_PROTO_SEL_MSK GENMASK(7, 3)49#define LYNX_28G_LNaGCR0_PROTO_SEL_SGMII 0x850#define LYNX_28G_LNaGCR0_PROTO_SEL_XFI 0x5051#define LYNX_28G_LNaGCR0_IF_WIDTH_MSK GENMASK(2, 0)52#define LYNX_28G_LNaGCR0_IF_WIDTH_10_BIT 0x053#define LYNX_28G_LNaGCR0_IF_WIDTH_20_BIT 0x254 55/* Lane a Tx Reset Control Register */56#define LYNX_28G_LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20)57#define LYNX_28G_LNaTRSTCTL_HLT_REQ BIT(27)58#define LYNX_28G_LNaTRSTCTL_RST_DONE BIT(30)59#define LYNX_28G_LNaTRSTCTL_RST_REQ BIT(31)60 61/* Lane a Tx General Control Register */62#define LYNX_28G_LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24)63#define LYNX_28G_LNaTGCR0_USE_PLLF 0x064#define LYNX_28G_LNaTGCR0_USE_PLLS BIT(28)65#define LYNX_28G_LNaTGCR0_USE_PLL_MSK BIT(28)66#define LYNX_28G_LNaTGCR0_N_RATE_FULL 0x067#define LYNX_28G_LNaTGCR0_N_RATE_HALF 0x100000068#define LYNX_28G_LNaTGCR0_N_RATE_QUARTER 0x200000069#define LYNX_28G_LNaTGCR0_N_RATE_MSK GENMASK(26, 24)70 71#define LYNX_28G_LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30)72 73/* Lane a Rx Reset Control Register */74#define LYNX_28G_LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40)75#define LYNX_28G_LNaRRSTCTL_HLT_REQ BIT(27)76#define LYNX_28G_LNaRRSTCTL_RST_DONE BIT(30)77#define LYNX_28G_LNaRRSTCTL_RST_REQ BIT(31)78#define LYNX_28G_LNaRRSTCTL_CDR_LOCK BIT(12)79 80/* Lane a Rx General Control Register */81#define LYNX_28G_LNaRGCR0(lane) (0x800 + (lane) * 0x100 + 0x44)82#define LYNX_28G_LNaRGCR0_USE_PLLF 0x083#define LYNX_28G_LNaRGCR0_USE_PLLS BIT(28)84#define LYNX_28G_LNaRGCR0_USE_PLL_MSK BIT(28)85#define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24)86#define LYNX_28G_LNaRGCR0_N_RATE_FULL 0x087#define LYNX_28G_LNaRGCR0_N_RATE_HALF 0x100000088#define LYNX_28G_LNaRGCR0_N_RATE_QUARTER 0x200000089#define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24)90 91#define LYNX_28G_LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48)92 93#define LYNX_28G_LNaRECR0(lane) (0x800 + (lane) * 0x100 + 0x50)94#define LYNX_28G_LNaRECR1(lane) (0x800 + (lane) * 0x100 + 0x54)95#define LYNX_28G_LNaRECR2(lane) (0x800 + (lane) * 0x100 + 0x58)96 97#define LYNX_28G_LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74)98 99#define LYNX_28G_LNaPSS(lane) (0x1000 + (lane) * 0x4)100#define LYNX_28G_LNaPSS_TYPE(pss) (((pss) & GENMASK(30, 24)) >> 24)101#define LYNX_28G_LNaPSS_TYPE_SGMII 0x4102#define LYNX_28G_LNaPSS_TYPE_XFI 0x28103 104#define LYNX_28G_SGMIIaCR1(lane) (0x1804 + (lane) * 0x10)105#define LYNX_28G_SGMIIaCR1_SGPCS_EN BIT(11)106#define LYNX_28G_SGMIIaCR1_SGPCS_DIS 0x0107#define LYNX_28G_SGMIIaCR1_SGPCS_MSK BIT(11)108 109struct lynx_28g_priv;110 111struct lynx_28g_pll {112 struct lynx_28g_priv *priv;113 u32 rstctl, cr0, cr1;114 int id;115 DECLARE_PHY_INTERFACE_MASK(supported);116};117 118struct lynx_28g_lane {119 struct lynx_28g_priv *priv;120 struct phy *phy;121 bool powered_up;122 bool init;123 unsigned int id;124 phy_interface_t interface;125};126 127struct lynx_28g_priv {128 void __iomem *base;129 struct device *dev;130 /* Serialize concurrent access to registers shared between lanes,131 * like PCCn132 */133 spinlock_t pcc_lock;134 struct lynx_28g_pll pll[LYNX_28G_NUM_PLL];135 struct lynx_28g_lane lane[LYNX_28G_NUM_LANE];136 137 struct delayed_work cdr_check;138};139 140static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,141 u32 val, u32 mask)142{143 void __iomem *reg = priv->base + off;144 u32 orig, tmp;145 146 orig = ioread32(reg);147 tmp = orig & ~mask;148 tmp |= val;149 iowrite32(tmp, reg);150}151 152#define lynx_28g_lane_rmw(lane, reg, val, mask) \153 lynx_28g_rmw((lane)->priv, LYNX_28G_##reg(lane->id), \154 LYNX_28G_##reg##_##val, LYNX_28G_##reg##_##mask)155#define lynx_28g_lane_read(lane, reg) \156 ioread32((lane)->priv->base + LYNX_28G_##reg((lane)->id))157#define lynx_28g_pll_read(pll, reg) \158 ioread32((pll)->priv->base + LYNX_28G_##reg((pll)->id))159 160static bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf)161{162 int i;163 164 for (i = 0; i < LYNX_28G_NUM_PLL; i++) {165 if (LYNX_28G_PLLnRSTCTL_DIS(priv->pll[i].rstctl))166 continue;167 168 if (test_bit(intf, priv->pll[i].supported))169 return true;170 }171 172 return false;173}174 175static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,176 phy_interface_t intf)177{178 struct lynx_28g_pll *pll;179 int i;180 181 for (i = 0; i < LYNX_28G_NUM_PLL; i++) {182 pll = &priv->pll[i];183 184 if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))185 continue;186 187 if (test_bit(intf, pll->supported))188 return pll;189 }190 191 return NULL;192}193 194static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,195 struct lynx_28g_pll *pll,196 phy_interface_t intf)197{198 switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {199 case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:200 case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:201 switch (intf) {202 case PHY_INTERFACE_MODE_SGMII:203 case PHY_INTERFACE_MODE_1000BASEX:204 lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_QUARTER, N_RATE_MSK);205 lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_QUARTER, N_RATE_MSK);206 break;207 default:208 break;209 }210 break;211 case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:212 switch (intf) {213 case PHY_INTERFACE_MODE_10GBASER:214 case PHY_INTERFACE_MODE_USXGMII:215 lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_FULL, N_RATE_MSK);216 lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_FULL, N_RATE_MSK);217 break;218 default:219 break;220 }221 break;222 default:223 break;224 }225}226 227static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,228 struct lynx_28g_pll *pll)229{230 if (pll->id == 0) {231 lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLF, USE_PLL_MSK);232 lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLF, USE_PLL_MSK);233 } else {234 lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLS, USE_PLL_MSK);235 lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLS, USE_PLL_MSK);236 }237}238 239static void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane)240{241 u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);242 struct lynx_28g_priv *priv = lane->priv;243 244 /* Cleanup the protocol configuration registers of the current protocol */245 switch (lane->interface) {246 case PHY_INTERFACE_MODE_10GBASER:247 lynx_28g_rmw(priv, LYNX_28G_PCCC,248 LYNX_28G_PCCC_SXGMII_DIS << lane_offset,249 GENMASK(3, 0) << lane_offset);250 break;251 case PHY_INTERFACE_MODE_SGMII:252 case PHY_INTERFACE_MODE_1000BASEX:253 lynx_28g_rmw(priv, LYNX_28G_PCC8,254 LYNX_28G_PCC8_SGMII_DIS << lane_offset,255 GENMASK(3, 0) << lane_offset);256 break;257 default:258 break;259 }260}261 262static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)263{264 u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);265 struct lynx_28g_priv *priv = lane->priv;266 struct lynx_28g_pll *pll;267 268 lynx_28g_cleanup_lane(lane);269 270 /* Setup the lane to run in SGMII */271 lynx_28g_rmw(priv, LYNX_28G_PCC8,272 LYNX_28G_PCC8_SGMII << lane_offset,273 GENMASK(3, 0) << lane_offset);274 275 /* Setup the protocol select and SerDes parallel interface width */276 lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_SGMII, PROTO_SEL_MSK);277 lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_10_BIT, IF_WIDTH_MSK);278 279 /* Switch to the PLL that works with this interface type */280 pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII);281 lynx_28g_lane_set_pll(lane, pll);282 283 /* Choose the portion of clock net to be used on this lane */284 lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_SGMII);285 286 /* Enable the SGMII PCS */287 lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_EN, SGPCS_MSK);288 289 /* Configure the appropriate equalization parameters for the protocol */290 iowrite32(0x00808006, priv->base + LYNX_28G_LNaTECR0(lane->id));291 iowrite32(0x04310000, priv->base + LYNX_28G_LNaRGCR1(lane->id));292 iowrite32(0x9f800000, priv->base + LYNX_28G_LNaRECR0(lane->id));293 iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));294 iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR2(lane->id));295 iowrite32(0x00000000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));296}297 298static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)299{300 u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);301 struct lynx_28g_priv *priv = lane->priv;302 struct lynx_28g_pll *pll;303 304 lynx_28g_cleanup_lane(lane);305 306 /* Enable the SXGMII lane */307 lynx_28g_rmw(priv, LYNX_28G_PCCC,308 LYNX_28G_PCCC_10GBASER << lane_offset,309 GENMASK(3, 0) << lane_offset);310 311 /* Setup the protocol select and SerDes parallel interface width */312 lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_XFI, PROTO_SEL_MSK);313 lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_20_BIT, IF_WIDTH_MSK);314 315 /* Switch to the PLL that works with this interface type */316 pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER);317 lynx_28g_lane_set_pll(lane, pll);318 319 /* Choose the portion of clock net to be used on this lane */320 lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_10GBASER);321 322 /* Disable the SGMII PCS */323 lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_DIS, SGPCS_MSK);324 325 /* Configure the appropriate equalization parameters for the protocol */326 iowrite32(0x10808307, priv->base + LYNX_28G_LNaTECR0(lane->id));327 iowrite32(0x10000000, priv->base + LYNX_28G_LNaRGCR1(lane->id));328 iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR0(lane->id));329 iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));330 iowrite32(0x81000020, priv->base + LYNX_28G_LNaRECR2(lane->id));331 iowrite32(0x00002000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));332}333 334static int lynx_28g_power_off(struct phy *phy)335{336 struct lynx_28g_lane *lane = phy_get_drvdata(phy);337 u32 trstctl, rrstctl;338 339 if (!lane->powered_up)340 return 0;341 342 /* Issue a halt request */343 lynx_28g_lane_rmw(lane, LNaTRSTCTL, HLT_REQ, HLT_REQ);344 lynx_28g_lane_rmw(lane, LNaRRSTCTL, HLT_REQ, HLT_REQ);345 346 /* Wait until the halting process is complete */347 do {348 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);349 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);350 } while ((trstctl & LYNX_28G_LNaTRSTCTL_HLT_REQ) ||351 (rrstctl & LYNX_28G_LNaRRSTCTL_HLT_REQ));352 353 lane->powered_up = false;354 355 return 0;356}357 358static int lynx_28g_power_on(struct phy *phy)359{360 struct lynx_28g_lane *lane = phy_get_drvdata(phy);361 u32 trstctl, rrstctl;362 363 if (lane->powered_up)364 return 0;365 366 /* Issue a reset request on the lane */367 lynx_28g_lane_rmw(lane, LNaTRSTCTL, RST_REQ, RST_REQ);368 lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);369 370 /* Wait until the reset sequence is completed */371 do {372 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);373 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);374 } while (!(trstctl & LYNX_28G_LNaTRSTCTL_RST_DONE) ||375 !(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));376 377 lane->powered_up = true;378 379 return 0;380}381 382static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)383{384 struct lynx_28g_lane *lane = phy_get_drvdata(phy);385 struct lynx_28g_priv *priv = lane->priv;386 int powered_up = lane->powered_up;387 int err = 0;388 389 if (mode != PHY_MODE_ETHERNET)390 return -EOPNOTSUPP;391 392 if (lane->interface == PHY_INTERFACE_MODE_NA)393 return -EOPNOTSUPP;394 395 if (!lynx_28g_supports_interface(priv, submode))396 return -EOPNOTSUPP;397 398 /* If the lane is powered up, put the lane into the halt state while399 * the reconfiguration is being done.400 */401 if (powered_up)402 lynx_28g_power_off(phy);403 404 spin_lock(&priv->pcc_lock);405 406 switch (submode) {407 case PHY_INTERFACE_MODE_SGMII:408 case PHY_INTERFACE_MODE_1000BASEX:409 lynx_28g_lane_set_sgmii(lane);410 break;411 case PHY_INTERFACE_MODE_10GBASER:412 lynx_28g_lane_set_10gbaser(lane);413 break;414 default:415 err = -EOPNOTSUPP;416 goto out;417 }418 419 lane->interface = submode;420 421out:422 spin_unlock(&priv->pcc_lock);423 424 /* Power up the lane if necessary */425 if (powered_up)426 lynx_28g_power_on(phy);427 428 return err;429}430 431static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode,432 union phy_configure_opts *opts __always_unused)433{434 struct lynx_28g_lane *lane = phy_get_drvdata(phy);435 struct lynx_28g_priv *priv = lane->priv;436 437 if (mode != PHY_MODE_ETHERNET)438 return -EOPNOTSUPP;439 440 if (!lynx_28g_supports_interface(priv, submode))441 return -EOPNOTSUPP;442 443 return 0;444}445 446static int lynx_28g_init(struct phy *phy)447{448 struct lynx_28g_lane *lane = phy_get_drvdata(phy);449 450 /* Mark the fact that the lane was init */451 lane->init = true;452 453 /* SerDes lanes are powered on at boot time. Any lane that is managed454 * by this driver will get powered down at init time aka at dpaa2-eth455 * probe time.456 */457 lane->powered_up = true;458 lynx_28g_power_off(phy);459 460 return 0;461}462 463static const struct phy_ops lynx_28g_ops = {464 .init = lynx_28g_init,465 .power_on = lynx_28g_power_on,466 .power_off = lynx_28g_power_off,467 .set_mode = lynx_28g_set_mode,468 .validate = lynx_28g_validate,469 .owner = THIS_MODULE,470};471 472static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)473{474 struct lynx_28g_pll *pll;475 int i;476 477 for (i = 0; i < LYNX_28G_NUM_PLL; i++) {478 pll = &priv->pll[i];479 pll->priv = priv;480 pll->id = i;481 482 pll->rstctl = lynx_28g_pll_read(pll, PLLnRSTCTL);483 pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0);484 pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1);485 486 if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))487 continue;488 489 switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {490 case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:491 case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:492 /* 5GHz clock net */493 __set_bit(PHY_INTERFACE_MODE_1000BASEX, pll->supported);494 __set_bit(PHY_INTERFACE_MODE_SGMII, pll->supported);495 break;496 case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:497 /* 10.3125GHz clock net */498 __set_bit(PHY_INTERFACE_MODE_10GBASER, pll->supported);499 break;500 default:501 /* 6GHz, 12.890625GHz, 8GHz */502 break;503 }504 }505}506 507#define work_to_lynx(w) container_of((w), struct lynx_28g_priv, cdr_check.work)508 509static void lynx_28g_cdr_lock_check(struct work_struct *work)510{511 struct lynx_28g_priv *priv = work_to_lynx(work);512 struct lynx_28g_lane *lane;513 u32 rrstctl;514 int i;515 516 for (i = 0; i < LYNX_28G_NUM_LANE; i++) {517 lane = &priv->lane[i];518 519 mutex_lock(&lane->phy->mutex);520 521 if (!lane->init || !lane->powered_up) {522 mutex_unlock(&lane->phy->mutex);523 continue;524 }525 526 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);527 if (!(rrstctl & LYNX_28G_LNaRRSTCTL_CDR_LOCK)) {528 lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);529 do {530 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);531 } while (!(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));532 }533 534 mutex_unlock(&lane->phy->mutex);535 }536 queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,537 msecs_to_jiffies(1000));538}539 540static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)541{542 u32 pss, protocol;543 544 pss = lynx_28g_lane_read(lane, LNaPSS);545 protocol = LYNX_28G_LNaPSS_TYPE(pss);546 switch (protocol) {547 case LYNX_28G_LNaPSS_TYPE_SGMII:548 lane->interface = PHY_INTERFACE_MODE_SGMII;549 break;550 case LYNX_28G_LNaPSS_TYPE_XFI:551 lane->interface = PHY_INTERFACE_MODE_10GBASER;552 break;553 default:554 lane->interface = PHY_INTERFACE_MODE_NA;555 }556}557 558static struct phy *lynx_28g_xlate(struct device *dev,559 const struct of_phandle_args *args)560{561 struct lynx_28g_priv *priv = dev_get_drvdata(dev);562 int idx = args->args[0];563 564 if (WARN_ON(idx >= LYNX_28G_NUM_LANE))565 return ERR_PTR(-EINVAL);566 567 return priv->lane[idx].phy;568}569 570static int lynx_28g_probe(struct platform_device *pdev)571{572 struct device *dev = &pdev->dev;573 struct phy_provider *provider;574 struct lynx_28g_priv *priv;575 int i;576 577 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);578 if (!priv)579 return -ENOMEM;580 priv->dev = &pdev->dev;581 582 priv->base = devm_platform_ioremap_resource(pdev, 0);583 if (IS_ERR(priv->base))584 return PTR_ERR(priv->base);585 586 lynx_28g_pll_read_configuration(priv);587 588 for (i = 0; i < LYNX_28G_NUM_LANE; i++) {589 struct lynx_28g_lane *lane = &priv->lane[i];590 struct phy *phy;591 592 memset(lane, 0, sizeof(*lane));593 594 phy = devm_phy_create(&pdev->dev, NULL, &lynx_28g_ops);595 if (IS_ERR(phy))596 return PTR_ERR(phy);597 598 lane->priv = priv;599 lane->phy = phy;600 lane->id = i;601 phy_set_drvdata(phy, lane);602 lynx_28g_lane_read_configuration(lane);603 }604 605 dev_set_drvdata(dev, priv);606 607 spin_lock_init(&priv->pcc_lock);608 INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);609 610 queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,611 msecs_to_jiffies(1000));612 613 dev_set_drvdata(&pdev->dev, priv);614 provider = devm_of_phy_provider_register(&pdev->dev, lynx_28g_xlate);615 616 return PTR_ERR_OR_ZERO(provider);617}618 619static void lynx_28g_remove(struct platform_device *pdev)620{621 struct device *dev = &pdev->dev;622 struct lynx_28g_priv *priv = dev_get_drvdata(dev);623 624 cancel_delayed_work_sync(&priv->cdr_check);625}626 627static const struct of_device_id lynx_28g_of_match_table[] = {628 { .compatible = "fsl,lynx-28g" },629 { },630};631MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table);632 633static struct platform_driver lynx_28g_driver = {634 .probe = lynx_28g_probe,635 .remove_new = lynx_28g_remove,636 .driver = {637 .name = "lynx-28g",638 .of_match_table = lynx_28g_of_match_table,639 },640};641module_platform_driver(lynx_28g_driver);642 643MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");644MODULE_DESCRIPTION("Lynx 28G SerDes PHY driver for Layerscape SoCs");645MODULE_LICENSE("GPL v2");646