1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Texas Instruments CPSW Port's PHY Interface Mode selection Driver 4 * 5 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ 6 * 7 * Based on cpsw-phy-sel.c driver created by Mugunthan V N <mugunthanvnm@ti.com> 8 */ 9 10 #include <linux/platform_device.h> 11 #include <linux/module.h> 12 #include <linux/mfd/syscon.h> 13 #include <linux/of.h> 14 #include <linux/of_address.h> 15 #include <linux/of_net.h> 16 #include <linux/phy.h> 17 #include <linux/phy/phy.h> 18 #include <linux/regmap.h> 19 20 /* AM33xx SoC specific definitions for the CONTROL port */ 21 #define AM33XX_GMII_SEL_MODE_MII 0 22 #define AM33XX_GMII_SEL_MODE_RMII 1 23 #define AM33XX_GMII_SEL_MODE_RGMII 2 24 25 /* J72xx SoC specific definitions for the CONTROL port */ 26 #define J72XX_GMII_SEL_MODE_SGMII 3 27 #define J72XX_GMII_SEL_MODE_QSGMII 4 28 #define J72XX_GMII_SEL_MODE_USXGMII 5 29 #define J72XX_GMII_SEL_MODE_QSGMII_SUB 6 30 31 #define PHY_GMII_PORT(n) BIT((n) - 1) 32 33 enum { 34 PHY_GMII_SEL_PORT_MODE = 0, 35 PHY_GMII_SEL_RGMII_ID_MODE, 36 PHY_GMII_SEL_RMII_IO_CLK_EN, 37 PHY_GMII_SEL_LAST, 38 }; 39 40 struct phy_gmii_sel_phy_priv { 41 struct phy_gmii_sel_priv *priv; 42 u32 id; 43 struct phy *if_phy; 44 int rmii_clock_external; 45 int phy_if_mode; 46 struct regmap_field *fields[PHY_GMII_SEL_LAST]; 47 }; 48 49 struct phy_gmii_sel_soc_data { 50 u32 num_ports; 51 u32 features; 52 const struct reg_field (*regfields)[PHY_GMII_SEL_LAST]; 53 bool use_of_data; 54 u64 extra_modes; 55 u32 num_qsgmii_main_ports; 56 }; 57 58 struct phy_gmii_sel_priv { 59 struct device *dev; 60 const struct phy_gmii_sel_soc_data *soc_data; 61 struct regmap *regmap; 62 struct phy_provider *phy_provider; 63 struct phy_gmii_sel_phy_priv *if_phys; 64 u32 num_ports; 65 u32 reg_offset; 66 u32 qsgmii_main_ports; 67 bool no_offset; 68 }; 69 70 static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode) 71 { 72 struct phy_gmii_sel_phy_priv *if_phy = phy_get_drvdata(phy); 73 const struct phy_gmii_sel_soc_data *soc_data = if_phy->priv->soc_data; 74 struct device *dev = if_phy->priv->dev; 75 struct regmap_field *regfield; 76 int ret, rgmii_id = 0; 77 u32 gmii_sel_mode = 0; 78 79 if (mode != PHY_MODE_ETHERNET) 80 return -EINVAL; 81 82 switch (submode) { 83 case PHY_INTERFACE_MODE_RMII: 84 gmii_sel_mode = AM33XX_GMII_SEL_MODE_RMII; 85 break; 86 87 case PHY_INTERFACE_MODE_RGMII: 88 case PHY_INTERFACE_MODE_RGMII_RXID: 89 gmii_sel_mode = AM33XX_GMII_SEL_MODE_RGMII; 90 break; 91 92 case PHY_INTERFACE_MODE_RGMII_ID: 93 case PHY_INTERFACE_MODE_RGMII_TXID: 94 gmii_sel_mode = AM33XX_GMII_SEL_MODE_RGMII; 95 rgmii_id = 1; 96 break; 97 98 case PHY_INTERFACE_MODE_MII: 99 case PHY_INTERFACE_MODE_GMII: 100 gmii_sel_mode = AM33XX_GMII_SEL_MODE_MII; 101 break; 102 103 case PHY_INTERFACE_MODE_QSGMII: 104 if (!(soc_data->extra_modes & BIT(PHY_INTERFACE_MODE_QSGMII))) 105 goto unsupported; 106 if (if_phy->priv->qsgmii_main_ports & BIT(if_phy->id - 1)) 107 gmii_sel_mode = J72XX_GMII_SEL_MODE_QSGMII; 108 else 109 gmii_sel_mode = J72XX_GMII_SEL_MODE_QSGMII_SUB; 110 break; 111 112 case PHY_INTERFACE_MODE_SGMII: 113 if (!(soc_data->extra_modes & BIT(PHY_INTERFACE_MODE_SGMII))) 114 goto unsupported; 115 else 116 gmii_sel_mode = J72XX_GMII_SEL_MODE_SGMII; 117 break; 118 119 case PHY_INTERFACE_MODE_USXGMII: 120 if (!(soc_data->extra_modes & BIT(PHY_INTERFACE_MODE_USXGMII))) 121 goto unsupported; 122 else 123 gmii_sel_mode = J72XX_GMII_SEL_MODE_USXGMII; 124 break; 125 126 default: 127 goto unsupported; 128 } 129 130 if_phy->phy_if_mode = submode; 131 132 dev_dbg(dev, "%s id:%u mode:%u rgmii_id:%d rmii_clk_ext:%d\n", 133 __func__, if_phy->id, submode, rgmii_id, 134 if_phy->rmii_clock_external); 135 136 regfield = if_phy->fields[PHY_GMII_SEL_PORT_MODE]; 137 ret = regmap_field_write(regfield, gmii_sel_mode); 138 if (ret) { 139 dev_err(dev, "port%u: set mode fail %d", if_phy->id, ret); 140 return ret; 141 } 142 143 if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE) && 144 if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE]) { 145 regfield = if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE]; 146 ret = regmap_field_write(regfield, rgmii_id); 147 if (ret) 148 return ret; 149 } 150 151 if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) && 152 if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN]) { 153 regfield = if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN]; 154 ret = regmap_field_write(regfield, 155 if_phy->rmii_clock_external); 156 } 157 158 return 0; 159 160 unsupported: 161 dev_warn(dev, "port%u: unsupported mode: \"%s\"\n", 162 if_phy->id, phy_modes(submode)); 163 return -EINVAL; 164 } 165 166 static const 167 struct reg_field phy_gmii_sel_fields_am33xx[][PHY_GMII_SEL_LAST] = { 168 { 169 [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x650, 0, 1), 170 [PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x650, 4, 4), 171 [PHY_GMII_SEL_RMII_IO_CLK_EN] = REG_FIELD(0x650, 6, 6), 172 }, 173 { 174 [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x650, 2, 3), 175 [PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x650, 5, 5), 176 [PHY_GMII_SEL_RMII_IO_CLK_EN] = REG_FIELD(0x650, 7, 7), 177 }, 178 }; 179 180 static const 181 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am33xx = { 182 .num_ports = 2, 183 .features = BIT(PHY_GMII_SEL_RGMII_ID_MODE) | 184 BIT(PHY_GMII_SEL_RMII_IO_CLK_EN), 185 .regfields = phy_gmii_sel_fields_am33xx, 186 }; 187 188 static const 189 struct reg_field phy_gmii_sel_fields_dra7[][PHY_GMII_SEL_LAST] = { 190 { 191 [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x554, 0, 1), 192 }, 193 { 194 [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x554, 4, 5), 195 }, 196 }; 197 198 static const 199 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dra7 = { 200 .num_ports = 2, 201 .regfields = phy_gmii_sel_fields_dra7, 202 }; 203 204 static const 205 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dm814 = { 206 .num_ports = 2, 207 .features = BIT(PHY_GMII_SEL_RGMII_ID_MODE), 208 .regfields = phy_gmii_sel_fields_am33xx, 209 }; 210 211 static const 212 struct reg_field phy_gmii_sel_fields_am654[][PHY_GMII_SEL_LAST] = { 213 { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x0, 0, 2), }, 214 { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4, 0, 2), }, 215 { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x8, 0, 2), }, 216 { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0xC, 0, 2), }, 217 { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x10, 0, 2), }, 218 { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x14, 0, 2), }, 219 { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x18, 0, 2), }, 220 { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x1C, 0, 2), }, 221 }; 222 223 static const 224 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = { 225 .use_of_data = true, 226 .regfields = phy_gmii_sel_fields_am654, 227 }; 228 229 static const 230 struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = { 231 .use_of_data = true, 232 .regfields = phy_gmii_sel_fields_am654, 233 .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII) | 234 BIT(PHY_INTERFACE_MODE_USXGMII), 235 .num_ports = 4, 236 .num_qsgmii_main_ports = 1, 237 }; 238 239 static const 240 struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j721e = { 241 .use_of_data = true, 242 .regfields = phy_gmii_sel_fields_am654, 243 .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII), 244 .num_ports = 8, 245 .num_qsgmii_main_ports = 2, 246 }; 247 248 static const 249 struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j784s4 = { 250 .use_of_data = true, 251 .regfields = phy_gmii_sel_fields_am654, 252 .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII) | 253 BIT(PHY_INTERFACE_MODE_USXGMII), 254 .num_ports = 8, 255 .num_qsgmii_main_ports = 2, 256 }; 257 258 static const struct of_device_id phy_gmii_sel_id_table[] = { 259 { 260 .compatible = "ti,am3352-phy-gmii-sel", 261 .data = &phy_gmii_sel_soc_am33xx, 262 }, 263 { 264 .compatible = "ti,dra7xx-phy-gmii-sel", 265 .data = &phy_gmii_sel_soc_dra7, 266 }, 267 { 268 .compatible = "ti,am43xx-phy-gmii-sel", 269 .data = &phy_gmii_sel_soc_am33xx, 270 }, 271 { 272 .compatible = "ti,dm814-phy-gmii-sel", 273 .data = &phy_gmii_sel_soc_dm814, 274 }, 275 { 276 .compatible = "ti,am654-phy-gmii-sel", 277 .data = &phy_gmii_sel_soc_am654, 278 }, 279 { 280 .compatible = "ti,j7200-cpsw5g-phy-gmii-sel", 281 .data = &phy_gmii_sel_cpsw5g_soc_j7200, 282 }, 283 { 284 .compatible = "ti,j721e-cpsw9g-phy-gmii-sel", 285 .data = &phy_gmii_sel_cpsw9g_soc_j721e, 286 }, 287 { 288 .compatible = "ti,j784s4-cpsw9g-phy-gmii-sel", 289 .data = &phy_gmii_sel_cpsw9g_soc_j784s4, 290 }, 291 {} 292 }; 293 MODULE_DEVICE_TABLE(of, phy_gmii_sel_id_table); 294 295 static const struct phy_ops phy_gmii_sel_ops = { 296 .set_mode = phy_gmii_sel_mode, 297 .owner = THIS_MODULE, 298 }; 299 300 static struct phy *phy_gmii_sel_of_xlate(struct device *dev, 301 const struct of_phandle_args *args) 302 { 303 struct phy_gmii_sel_priv *priv = dev_get_drvdata(dev); 304 int phy_id = args->args[0]; 305 306 if (args->args_count < 1) 307 return ERR_PTR(-EINVAL); 308 if (!priv || !priv->if_phys) 309 return ERR_PTR(-ENODEV); 310 if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) && 311 args->args_count < 2) 312 return ERR_PTR(-EINVAL); 313 if (phy_id > priv->num_ports) 314 return ERR_PTR(-EINVAL); 315 if (phy_id != priv->if_phys[phy_id - 1].id) 316 return ERR_PTR(-EINVAL); 317 318 phy_id--; 319 if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) 320 priv->if_phys[phy_id].rmii_clock_external = args->args[1]; 321 dev_dbg(dev, "%s id:%u ext:%d\n", __func__, 322 priv->if_phys[phy_id].id, args->args[1]); 323 324 return priv->if_phys[phy_id].if_phy; 325 } 326 327 static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port, 328 struct phy_gmii_sel_phy_priv *if_phy) 329 { 330 const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data; 331 struct device *dev = priv->dev; 332 const struct reg_field *fields; 333 struct regmap_field *regfield; 334 struct reg_field field; 335 int ret; 336 337 if_phy->id = port; 338 if_phy->priv = priv; 339 340 fields = soc_data->regfields[port - 1]; 341 field = *fields++; 342 field.reg += priv->reg_offset; 343 dev_dbg(dev, "%s field %x %d %d\n", __func__, 344 field.reg, field.msb, field.lsb); 345 346 regfield = devm_regmap_field_alloc(dev, priv->regmap, field); 347 if (IS_ERR(regfield)) 348 return PTR_ERR(regfield); 349 if_phy->fields[PHY_GMII_SEL_PORT_MODE] = regfield; 350 351 field = *fields++; 352 field.reg += priv->reg_offset; 353 if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE)) { 354 regfield = devm_regmap_field_alloc(dev, 355 priv->regmap, 356 field); 357 if (IS_ERR(regfield)) 358 return PTR_ERR(regfield); 359 if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE] = regfield; 360 dev_dbg(dev, "%s field %x %d %d\n", __func__, 361 field.reg, field.msb, field.lsb); 362 } 363 364 field = *fields; 365 field.reg += priv->reg_offset; 366 if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) { 367 regfield = devm_regmap_field_alloc(dev, 368 priv->regmap, 369 field); 370 if (IS_ERR(regfield)) 371 return PTR_ERR(regfield); 372 if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN] = regfield; 373 dev_dbg(dev, "%s field %x %d %d\n", __func__, 374 field.reg, field.msb, field.lsb); 375 } 376 377 if_phy->if_phy = devm_phy_create(dev, 378 priv->dev->of_node, 379 &phy_gmii_sel_ops); 380 if (IS_ERR(if_phy->if_phy)) { 381 ret = PTR_ERR(if_phy->if_phy); 382 dev_err(dev, "Failed to create phy%d %d\n", port, ret); 383 return ret; 384 } 385 phy_set_drvdata(if_phy->if_phy, if_phy); 386 387 return 0; 388 } 389 390 static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv) 391 { 392 const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data; 393 struct phy_gmii_sel_phy_priv *if_phys; 394 struct device *dev = priv->dev; 395 int i, ret; 396 397 if (soc_data->use_of_data) { 398 const __be32 *offset; 399 u64 size; 400 401 offset = of_get_address(dev->of_node, 0, &size, NULL); 402 if (!offset) 403 return -EINVAL; 404 priv->num_ports = size / sizeof(u32); 405 if (!priv->num_ports) 406 return -EINVAL; 407 if (!priv->no_offset) 408 priv->reg_offset = __be32_to_cpu(*offset); 409 } 410 411 if_phys = devm_kcalloc(dev, priv->num_ports, 412 sizeof(*if_phys), GFP_KERNEL); 413 if (!if_phys) 414 return -ENOMEM; 415 dev_dbg(dev, "%s %d\n", __func__, priv->num_ports); 416 417 for (i = 0; i < priv->num_ports; i++) { 418 ret = phy_gmii_init_phy(priv, i + 1, &if_phys[i]); 419 if (ret) 420 return ret; 421 } 422 423 priv->if_phys = if_phys; 424 return 0; 425 } 426 427 static int phy_gmii_sel_probe(struct platform_device *pdev) 428 { 429 struct device *dev = &pdev->dev; 430 const struct phy_gmii_sel_soc_data *soc_data; 431 struct device_node *node = dev->of_node; 432 const struct of_device_id *of_id; 433 struct phy_gmii_sel_priv *priv; 434 u32 main_ports = 1; 435 int ret; 436 u32 i; 437 438 of_id = of_match_node(phy_gmii_sel_id_table, pdev->dev.of_node); 439 if (!of_id) 440 return -EINVAL; 441 442 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 443 if (!priv) 444 return -ENOMEM; 445 446 priv->dev = &pdev->dev; 447 priv->soc_data = of_id->data; 448 soc_data = priv->soc_data; 449 priv->num_ports = priv->soc_data->num_ports; 450 priv->qsgmii_main_ports = 0; 451 452 /* 453 * Based on the compatible, try to read the appropriate number of 454 * QSGMII main ports from the "ti,qsgmii-main-ports" property from 455 * the device-tree node. 456 */ 457 for (i = 0; i < soc_data->num_qsgmii_main_ports; i++) { 458 of_property_read_u32_index(node, "ti,qsgmii-main-ports", i, &main_ports); 459 /* 460 * Ensure that main_ports is within bounds. 461 */ 462 if (main_ports < 1 || main_ports > soc_data->num_ports) { 463 dev_err(dev, "Invalid qsgmii main port provided\n"); 464 return -EINVAL; 465 } 466 priv->qsgmii_main_ports |= PHY_GMII_PORT(main_ports); 467 } 468 469 priv->regmap = syscon_node_to_regmap(node->parent); 470 if (IS_ERR(priv->regmap)) { 471 priv->regmap = device_node_to_regmap(node); 472 if (IS_ERR(priv->regmap)) 473 return dev_err_probe(dev, PTR_ERR(priv->regmap), 474 "Failed to get syscon\n"); 475 priv->no_offset = true; 476 } 477 478 ret = phy_gmii_sel_init_ports(priv); 479 if (ret) 480 return ret; 481 482 dev_set_drvdata(&pdev->dev, priv); 483 484 priv->phy_provider = 485 devm_of_phy_provider_register(dev, 486 phy_gmii_sel_of_xlate); 487 if (IS_ERR(priv->phy_provider)) 488 return dev_err_probe(dev, PTR_ERR(priv->phy_provider), 489 "Failed to create phy provider\n"); 490 491 return 0; 492 } 493 494 static int phy_gmii_sel_resume_noirq(struct device *dev) 495 { 496 struct phy_gmii_sel_priv *priv = dev_get_drvdata(dev); 497 struct phy_gmii_sel_phy_priv *if_phys = priv->if_phys; 498 int ret, i; 499 500 for (i = 0; i < priv->num_ports; i++) { 501 if (if_phys[i].phy_if_mode) { 502 ret = phy_gmii_sel_mode(if_phys[i].if_phy, 503 PHY_MODE_ETHERNET, if_phys[i].phy_if_mode); 504 if (ret) { 505 dev_err(dev, "port%u: restore mode fail %d\n", 506 if_phys[i].if_phy->id, ret); 507 return ret; 508 } 509 } 510 } 511 512 return 0; 513 } 514 515 static DEFINE_NOIRQ_DEV_PM_OPS(phy_gmii_sel_pm_ops, NULL, phy_gmii_sel_resume_noirq); 516 517 static struct platform_driver phy_gmii_sel_driver = { 518 .probe = phy_gmii_sel_probe, 519 .driver = { 520 .name = "phy-gmii-sel", 521 .of_match_table = phy_gmii_sel_id_table, 522 .pm = pm_sleep_ptr(&phy_gmii_sel_pm_ops), 523 }, 524 }; 525 module_platform_driver(phy_gmii_sel_driver); 526 527 MODULE_LICENSE("GPL v2"); 528 MODULE_AUTHOR("Grygorii Strashko <grygorii.strashko@ti.com>"); 529 MODULE_DESCRIPTION("TI CPSW Port's PHY Interface Mode selection Driver"); 530