1 // SPDX-License-Identifier: GPL-2.0+ 2 /* Copyright 2025-2026 NXP */ 3 4 #include <linux/module.h> 5 #include <linux/platform_device.h> 6 7 #include "phy-fsl-lynx-core.h" 8 9 const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode) 10 { 11 switch (lane_mode) { 12 case LANE_MODE_1000BASEX_SGMII: 13 return "1000Base-X/SGMII"; 14 case LANE_MODE_2500BASEX: 15 return "2500Base-X"; 16 case LANE_MODE_QSGMII: 17 return "QSGMII"; 18 case LANE_MODE_10G_QXGMII: 19 return "10G-QXGMII"; 20 case LANE_MODE_10GBASER: 21 return "10GBase-R"; 22 case LANE_MODE_USXGMII: 23 return "USXGMII"; 24 case LANE_MODE_25GBASER: 25 return "25GBase-R"; 26 default: 27 return "unknown"; 28 } 29 } 30 EXPORT_SYMBOL_NS_GPL(lynx_lane_mode_str, "PHY_FSL_LYNX"); 31 32 enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf) 33 { 34 switch (intf) { 35 case PHY_INTERFACE_MODE_SGMII: 36 case PHY_INTERFACE_MODE_1000BASEX: 37 return LANE_MODE_1000BASEX_SGMII; 38 case PHY_INTERFACE_MODE_2500BASEX: 39 return LANE_MODE_2500BASEX; 40 case PHY_INTERFACE_MODE_QSGMII: 41 return LANE_MODE_QSGMII; 42 case PHY_INTERFACE_MODE_10G_QXGMII: 43 return LANE_MODE_10G_QXGMII; 44 case PHY_INTERFACE_MODE_10GBASER: 45 return LANE_MODE_10GBASER; 46 case PHY_INTERFACE_MODE_USXGMII: 47 return LANE_MODE_USXGMII; 48 case PHY_INTERFACE_MODE_25GBASER: 49 return LANE_MODE_25GBASER; 50 default: 51 return LANE_MODE_UNKNOWN; 52 } 53 } 54 EXPORT_SYMBOL_NS_GPL(phy_interface_to_lane_mode, "PHY_FSL_LYNX"); 55 56 /* By default, assume that if we know how to get the PCCR register and 57 * protocol converter for a lane, that protocol is supported. 58 */ 59 static bool lynx_lane_supports_mode_default(struct lynx_lane *lane, 60 enum lynx_lane_mode mode) 61 { 62 struct lynx_priv *priv = lane->priv; 63 struct lynx_pccr pccr; 64 65 if (!priv->info->get_pccr || !priv->info->get_pcvt_offset) 66 return false; 67 68 if (priv->info->get_pccr(mode, lane->id, &pccr) < 0) 69 return false; 70 71 if (priv->info->get_pcvt_offset(lane->id, mode) < 0) 72 return false; 73 74 return true; 75 } 76 77 /* A lane mode is supported if we have a PLL that can provide its required 78 * clock net, and if there is a protocol converter for that mode on that lane. 79 */ 80 bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode) 81 { 82 struct lynx_priv *priv = lane->priv; 83 int i; 84 85 if (priv->info->lane_supports_mode) { 86 if (!priv->info->lane_supports_mode(lane->id, mode)) 87 return false; 88 } else if (!lynx_lane_supports_mode_default(lane, mode)) { 89 return false; 90 } 91 92 for (i = 0; i < LYNX_NUM_PLL; i++) { 93 if (!priv->pll[i].enabled) 94 continue; 95 96 if (test_bit(mode, priv->pll[i].supported)) 97 return true; 98 } 99 100 return false; 101 } 102 EXPORT_SYMBOL_NS_GPL(lynx_lane_supports_mode, "PHY_FSL_LYNX"); 103 104 /* The quad protocols are fixed because the lane has multiple consumers, and 105 * one phy_set_mode_ext() affects the other consumers as well. We have no use 106 * case for dynamic protocol changing here, so disallow it. 107 */ 108 static enum lynx_lane_mode lynx_fixed_protocols[] = { 109 LANE_MODE_QSGMII, 110 LANE_MODE_10G_QXGMII, 111 }; 112 113 static bool lynx_lane_restrict_fixed_mode_change(struct lynx_lane *lane, 114 enum lynx_lane_mode new) 115 { 116 enum lynx_lane_mode curr = lane->mode; 117 118 for (int i = 0; i < ARRAY_SIZE(lynx_fixed_protocols); i++) 119 if ((curr == lynx_fixed_protocols[i] || 120 new == lynx_fixed_protocols[i]) && 121 curr != new) 122 return true; 123 124 return false; 125 } 126 127 /* Translate the mode/submode from phy_validate() and phy_set_mode_ext() to a 128 * lane_mode and return 0 if it is supported and we can transition to it from 129 * the current lane mode, or return negative error otherwise. 130 */ 131 int lynx_phy_mode_to_lane_mode(struct phy *phy, enum phy_mode mode, 132 int submode, enum lynx_lane_mode *lane_mode) 133 { 134 struct lynx_lane *lane = phy_get_drvdata(phy); 135 enum lynx_lane_mode tmp_lane_mode; 136 137 /* The protocol configuration tables are incomplete for full lane 138 * reconfiguration from an arbitrary protocol. 139 */ 140 if (lane->mode == LANE_MODE_UNKNOWN) 141 return -EINVAL; 142 143 if (mode != PHY_MODE_ETHERNET) 144 return -EINVAL; 145 146 tmp_lane_mode = phy_interface_to_lane_mode(submode); 147 if (!lynx_lane_supports_mode(lane, tmp_lane_mode)) 148 return -EINVAL; 149 150 if (lynx_lane_restrict_fixed_mode_change(lane, tmp_lane_mode)) 151 return -EINVAL; 152 153 if (lane_mode) 154 *lane_mode = tmp_lane_mode; 155 156 return 0; 157 } 158 EXPORT_SYMBOL_NS_GPL(lynx_phy_mode_to_lane_mode, "PHY_FSL_LYNX"); 159 160 struct lynx_pll *lynx_pll_get(struct lynx_priv *priv, enum lynx_lane_mode mode) 161 { 162 struct lynx_pll *pll; 163 int i; 164 165 for (i = 0; i < LYNX_NUM_PLL; i++) { 166 pll = &priv->pll[i]; 167 168 if (!pll->enabled) 169 continue; 170 171 if (test_bit(mode, pll->supported)) 172 return pll; 173 } 174 175 /* no pll supports requested mode, either caller forgot to check 176 * lynx_lane_supports_mode(), or this is a bug. 177 */ 178 dev_WARN_ONCE(priv->dev, 1, "no pll for lane mode %s\n", 179 lynx_lane_mode_str(mode)); 180 return NULL; 181 } 182 EXPORT_SYMBOL_NS_GPL(lynx_pll_get, "PHY_FSL_LYNX"); 183 184 int lynx_pccr_read(struct lynx_lane *lane, enum lynx_lane_mode mode, u32 *val) 185 { 186 struct lynx_priv *priv = lane->priv; 187 struct lynx_pccr pccr; 188 u32 tmp; 189 int err; 190 191 err = priv->info->get_pccr(mode, lane->id, &pccr); 192 if (err) 193 return err; 194 195 tmp = lynx_read(priv, pccr.offset); 196 *val = (tmp >> pccr.shift) & GENMASK(pccr.width - 1, 0); 197 198 return 0; 199 } 200 EXPORT_SYMBOL_NS_GPL(lynx_pccr_read, "PHY_FSL_LYNX"); 201 202 int lynx_pccr_write(struct lynx_lane *lane, enum lynx_lane_mode mode, u32 val) 203 { 204 struct lynx_priv *priv = lane->priv; 205 struct lynx_pccr pccr; 206 u32 old, tmp, mask; 207 int err; 208 209 err = priv->info->get_pccr(mode, lane->id, &pccr); 210 if (err) 211 return err; 212 213 old = lynx_read(priv, pccr.offset); 214 mask = GENMASK(pccr.width - 1, 0) << pccr.shift; 215 tmp = (old & ~mask) | (val << pccr.shift); 216 lynx_write(priv, pccr.offset, tmp); 217 218 dev_dbg(&lane->phy->dev, "PCCR@0x%x: 0x%x -> 0x%x\n", 219 pccr.offset, old, tmp); 220 221 return 0; 222 } 223 EXPORT_SYMBOL_NS_GPL(lynx_pccr_write, "PHY_FSL_LYNX"); 224 225 int lynx_pcvt_read(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr, 226 u32 *val) 227 { 228 struct lynx_priv *priv = lane->priv; 229 int offset; 230 231 offset = priv->info->get_pcvt_offset(lane->id, mode); 232 if (offset < 0) 233 return offset; 234 235 *val = lynx_read(priv, offset + cr); 236 237 return 0; 238 } 239 EXPORT_SYMBOL_NS_GPL(lynx_pcvt_read, "PHY_FSL_LYNX"); 240 241 int lynx_pcvt_write(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr, 242 u32 val) 243 { 244 struct lynx_priv *priv = lane->priv; 245 int offset; 246 247 offset = priv->info->get_pcvt_offset(lane->id, mode); 248 if (offset < 0) 249 return offset; 250 251 lynx_write(priv, offset + cr, val); 252 253 return 0; 254 } 255 EXPORT_SYMBOL_NS_GPL(lynx_pcvt_write, "PHY_FSL_LYNX"); 256 257 int lynx_pcvt_rmw(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr, 258 u32 val, u32 mask) 259 { 260 int err; 261 u32 tmp; 262 263 err = lynx_pcvt_read(lane, mode, cr, &tmp); 264 if (err) 265 return err; 266 267 tmp &= ~mask; 268 tmp |= val; 269 270 return lynx_pcvt_write(lane, mode, cr, tmp); 271 } 272 EXPORT_SYMBOL_NS_GPL(lynx_pcvt_rmw, "PHY_FSL_LYNX"); 273 274 #define work_to_lynx(w) container_of((w), struct lynx_priv, cdr_check.work) 275 276 static void lynx_cdr_lock_check(struct work_struct *work) 277 { 278 struct lynx_priv *priv = work_to_lynx(work); 279 struct lynx_lane *lane; 280 281 for (int i = priv->info->first_lane; i < priv->info->num_lanes; i++) { 282 lane = &priv->lane[i]; 283 if (!lane->phy) 284 continue; 285 286 mutex_lock(&lane->phy->mutex); 287 288 if (!lane->init || !lane->powered_up) { 289 mutex_unlock(&lane->phy->mutex); 290 continue; 291 } 292 293 priv->info->cdr_lock_check(lane); 294 295 mutex_unlock(&lane->phy->mutex); 296 } 297 298 queue_delayed_work(system_power_efficient_wq, &priv->cdr_check, 299 msecs_to_jiffies(1000)); 300 } 301 302 static struct phy *lynx_xlate(struct device *dev, 303 const struct of_phandle_args *args) 304 { 305 struct lynx_priv *priv = dev_get_drvdata(dev); 306 int idx; 307 308 if (args->args_count == 0) 309 return of_phy_simple_xlate(dev, args); 310 else if (args->args_count != 1) 311 return ERR_PTR(-ENODEV); 312 313 idx = args->args[0]; 314 315 if (WARN_ON(idx >= priv->info->num_lanes || 316 idx < priv->info->first_lane)) 317 return ERR_PTR(-EINVAL); 318 319 return priv->lane[idx].phy ?: ERR_PTR(-ENODEV); 320 } 321 322 static int lynx_probe_lane(struct lynx_priv *priv, int id, 323 struct device_node *dn, 324 const struct phy_ops *phy_ops) 325 { 326 struct lynx_lane *lane = &priv->lane[id]; 327 struct phy *phy; 328 329 phy = devm_phy_create(priv->dev, dn, phy_ops); 330 if (IS_ERR(phy)) 331 return PTR_ERR(phy); 332 333 lane->priv = priv; 334 lane->phy = phy; 335 lane->id = id; 336 phy_set_drvdata(phy, lane); 337 priv->info->lane_read_configuration(lane); 338 339 return 0; 340 } 341 342 int lynx_probe(struct platform_device *pdev, const struct lynx_info *info, 343 const struct phy_ops *phy_ops) 344 { 345 struct device *dev = &pdev->dev; 346 struct phy_provider *provider; 347 struct device_node *dn; 348 struct lynx_priv *priv; 349 int err; 350 351 dn = dev_of_node(dev); 352 if (!dn) { 353 dev_err(dev, "Device requires an OF node\n"); 354 return -EINVAL; 355 } 356 357 if (!info) 358 return -ENODEV; 359 360 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 361 if (!priv) 362 return -ENOMEM; 363 364 priv->dev = dev; 365 priv->info = info; 366 priv->big_endian = device_property_read_bool(dev, "big-endian"); 367 dev_set_drvdata(dev, priv); 368 spin_lock_init(&priv->pcc_lock); 369 INIT_DELAYED_WORK(&priv->cdr_check, lynx_cdr_lock_check); 370 371 priv->lane = devm_kcalloc(dev, priv->info->num_lanes, 372 sizeof(*priv->lane), GFP_KERNEL); 373 if (!priv->lane) 374 return -ENOMEM; 375 376 priv->base = devm_platform_ioremap_resource(pdev, 0); 377 if (IS_ERR(priv->base)) 378 return PTR_ERR(priv->base); 379 380 for (int i = 0; i < LYNX_NUM_PLL; i++) { 381 struct lynx_pll *pll = &priv->pll[i]; 382 383 pll->priv = priv; 384 pll->id = i; 385 priv->info->pll_read_configuration(pll); 386 } 387 388 if (of_get_child_count(dn)) { 389 struct device_node *child; 390 391 for_each_available_child_of_node(dn, child) { 392 u32 reg; 393 394 /* PHY subnode name must be 'phy'. */ 395 if (!(of_node_name_eq(child, "phy"))) 396 continue; 397 398 if (of_property_read_u32(child, "reg", ®)) { 399 dev_err(dev, "No \"reg\" property for %pOF\n", child); 400 of_node_put(child); 401 return -EINVAL; 402 } 403 404 if (reg < priv->info->first_lane || reg >= priv->info->num_lanes) { 405 dev_err(dev, "\"reg\" property out of range for %pOF\n", child); 406 of_node_put(child); 407 return -EINVAL; 408 } 409 410 err = lynx_probe_lane(priv, reg, child, phy_ops); 411 if (err) { 412 of_node_put(child); 413 return err; 414 } 415 } 416 } else { 417 for (int i = priv->info->first_lane; i < priv->info->num_lanes; i++) { 418 err = lynx_probe_lane(priv, i, NULL, phy_ops); 419 if (err) 420 return err; 421 } 422 } 423 424 provider = devm_of_phy_provider_register(dev, lynx_xlate); 425 if (IS_ERR(provider)) 426 return PTR_ERR(provider); 427 428 queue_delayed_work(system_power_efficient_wq, &priv->cdr_check, 429 msecs_to_jiffies(1000)); 430 431 return 0; 432 } 433 EXPORT_SYMBOL_NS_GPL(lynx_probe, "PHY_FSL_LYNX"); 434 435 void lynx_remove(struct platform_device *pdev) 436 { 437 struct device *dev = &pdev->dev; 438 struct lynx_priv *priv = dev_get_drvdata(dev); 439 440 cancel_delayed_work_sync(&priv->cdr_check); 441 } 442 EXPORT_SYMBOL_NS_GPL(lynx_remove, "PHY_FSL_LYNX"); 443 444 MODULE_LICENSE("GPL"); 445 MODULE_DESCRIPTION("Freescale Lynx SerDes core functionality"); 446