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