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 .num_ports = 4, 235 .num_qsgmii_main_ports = 1, 236 }; 237 238 static const 239 struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j721e = { 240 .use_of_data = true, 241 .regfields = phy_gmii_sel_fields_am654, 242 .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII), 243 .num_ports = 8, 244 .num_qsgmii_main_ports = 2, 245 }; 246 247 static const 248 struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j784s4 = { 249 .use_of_data = true, 250 .regfields = phy_gmii_sel_fields_am654, 251 .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | 252 BIT(PHY_INTERFACE_MODE_USXGMII), 253 .num_ports = 8, 254 .num_qsgmii_main_ports = 2, 255 }; 256 257 static const struct of_device_id phy_gmii_sel_id_table[] = { 258 { 259 .compatible = "ti,am3352-phy-gmii-sel", 260 .data = &phy_gmii_sel_soc_am33xx, 261 }, 262 { 263 .compatible = "ti,dra7xx-phy-gmii-sel", 264 .data = &phy_gmii_sel_soc_dra7, 265 }, 266 { 267 .compatible = "ti,am43xx-phy-gmii-sel", 268 .data = &phy_gmii_sel_soc_am33xx, 269 }, 270 { 271 .compatible = "ti,dm814-phy-gmii-sel", 272 .data = &phy_gmii_sel_soc_dm814, 273 }, 274 { 275 .compatible = "ti,am654-phy-gmii-sel", 276 .data = &phy_gmii_sel_soc_am654, 277 }, 278 { 279 .compatible = "ti,j7200-cpsw5g-phy-gmii-sel", 280 .data = &phy_gmii_sel_cpsw5g_soc_j7200, 281 }, 282 { 283 .compatible = "ti,j721e-cpsw9g-phy-gmii-sel", 284 .data = &phy_gmii_sel_cpsw9g_soc_j721e, 285 }, 286 { 287 .compatible = "ti,j784s4-cpsw9g-phy-gmii-sel", 288 .data = &phy_gmii_sel_cpsw9g_soc_j784s4, 289 }, 290 {} 291 }; 292 MODULE_DEVICE_TABLE(of, phy_gmii_sel_id_table); 293 294 static const struct phy_ops phy_gmii_sel_ops = { 295 .set_mode = phy_gmii_sel_mode, 296 .owner = THIS_MODULE, 297 }; 298 299 static struct phy *phy_gmii_sel_of_xlate(struct device *dev, 300 struct of_phandle_args *args) 301 { 302 struct phy_gmii_sel_priv *priv = dev_get_drvdata(dev); 303 int phy_id = args->args[0]; 304 305 if (args->args_count < 1) 306 return ERR_PTR(-EINVAL); 307 if (!priv || !priv->if_phys) 308 return ERR_PTR(-ENODEV); 309 if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) && 310 args->args_count < 2) 311 return ERR_PTR(-EINVAL); 312 if (phy_id > priv->num_ports) 313 return ERR_PTR(-EINVAL); 314 if (phy_id != priv->if_phys[phy_id - 1].id) 315 return ERR_PTR(-EINVAL); 316 317 phy_id--; 318 if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) 319 priv->if_phys[phy_id].rmii_clock_external = args->args[1]; 320 dev_dbg(dev, "%s id:%u ext:%d\n", __func__, 321 priv->if_phys[phy_id].id, args->args[1]); 322 323 return priv->if_phys[phy_id].if_phy; 324 } 325 326 static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port, 327 struct phy_gmii_sel_phy_priv *if_phy) 328 { 329 const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data; 330 struct device *dev = priv->dev; 331 const struct reg_field *fields; 332 struct regmap_field *regfield; 333 struct reg_field field; 334 int ret; 335 336 if_phy->id = port; 337 if_phy->priv = priv; 338 339 fields = soc_data->regfields[port - 1]; 340 field = *fields++; 341 field.reg += priv->reg_offset; 342 dev_dbg(dev, "%s field %x %d %d\n", __func__, 343 field.reg, field.msb, field.lsb); 344 345 regfield = devm_regmap_field_alloc(dev, priv->regmap, field); 346 if (IS_ERR(regfield)) 347 return PTR_ERR(regfield); 348 if_phy->fields[PHY_GMII_SEL_PORT_MODE] = regfield; 349 350 field = *fields++; 351 field.reg += priv->reg_offset; 352 if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE)) { 353 regfield = devm_regmap_field_alloc(dev, 354 priv->regmap, 355 field); 356 if (IS_ERR(regfield)) 357 return PTR_ERR(regfield); 358 if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE] = regfield; 359 dev_dbg(dev, "%s field %x %d %d\n", __func__, 360 field.reg, field.msb, field.lsb); 361 } 362 363 field = *fields; 364 field.reg += priv->reg_offset; 365 if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) { 366 regfield = devm_regmap_field_alloc(dev, 367 priv->regmap, 368 field); 369 if (IS_ERR(regfield)) 370 return PTR_ERR(regfield); 371 if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN] = regfield; 372 dev_dbg(dev, "%s field %x %d %d\n", __func__, 373 field.reg, field.msb, field.lsb); 374 } 375 376 if_phy->if_phy = devm_phy_create(dev, 377 priv->dev->of_node, 378 &phy_gmii_sel_ops); 379 if (IS_ERR(if_phy->if_phy)) { 380 ret = PTR_ERR(if_phy->if_phy); 381 dev_err(dev, "Failed to create phy%d %d\n", port, ret); 382 return ret; 383 } 384 phy_set_drvdata(if_phy->if_phy, if_phy); 385 386 return 0; 387 } 388 389 static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv) 390 { 391 const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data; 392 struct phy_gmii_sel_phy_priv *if_phys; 393 struct device *dev = priv->dev; 394 int i, ret; 395 396 if (soc_data->use_of_data) { 397 const __be32 *offset; 398 u64 size; 399 400 offset = of_get_address(dev->of_node, 0, &size, NULL); 401 if (!offset) 402 return -EINVAL; 403 priv->num_ports = size / sizeof(u32); 404 if (!priv->num_ports) 405 return -EINVAL; 406 if (!priv->no_offset) 407 priv->reg_offset = __be32_to_cpu(*offset); 408 } 409 410 if_phys = devm_kcalloc(dev, priv->num_ports, 411 sizeof(*if_phys), GFP_KERNEL); 412 if (!if_phys) 413 return -ENOMEM; 414 dev_dbg(dev, "%s %d\n", __func__, priv->num_ports); 415 416 for (i = 0; i < priv->num_ports; i++) { 417 ret = phy_gmii_init_phy(priv, i + 1, &if_phys[i]); 418 if (ret) 419 return ret; 420 } 421 422 priv->if_phys = if_phys; 423 return 0; 424 } 425 426 static int phy_gmii_sel_probe(struct platform_device *pdev) 427 { 428 struct device *dev = &pdev->dev; 429 const struct phy_gmii_sel_soc_data *soc_data; 430 struct device_node *node = dev->of_node; 431 const struct of_device_id *of_id; 432 struct phy_gmii_sel_priv *priv; 433 u32 main_ports = 1; 434 int ret; 435 u32 i; 436 437 of_id = of_match_node(phy_gmii_sel_id_table, pdev->dev.of_node); 438 if (!of_id) 439 return -EINVAL; 440 441 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 442 if (!priv) 443 return -ENOMEM; 444 445 priv->dev = &pdev->dev; 446 priv->soc_data = of_id->data; 447 soc_data = priv->soc_data; 448 priv->num_ports = priv->soc_data->num_ports; 449 priv->qsgmii_main_ports = 0; 450 451 /* 452 * Based on the compatible, try to read the appropriate number of 453 * QSGMII main ports from the "ti,qsgmii-main-ports" property from 454 * the device-tree node. 455 */ 456 for (i = 0; i < soc_data->num_qsgmii_main_ports; i++) { 457 of_property_read_u32_index(node, "ti,qsgmii-main-ports", i, &main_ports); 458 /* 459 * Ensure that main_ports is within bounds. 460 */ 461 if (main_ports < 1 || main_ports > soc_data->num_ports) { 462 dev_err(dev, "Invalid qsgmii main port provided\n"); 463 return -EINVAL; 464 } 465 priv->qsgmii_main_ports |= PHY_GMII_PORT(main_ports); 466 } 467 468 priv->regmap = syscon_node_to_regmap(node->parent); 469 if (IS_ERR(priv->regmap)) { 470 priv->regmap = device_node_to_regmap(node); 471 if (IS_ERR(priv->regmap)) { 472 ret = PTR_ERR(priv->regmap); 473 dev_err(dev, "Failed to get syscon %d\n", ret); 474 return ret; 475 } 476 priv->no_offset = true; 477 } 478 479 ret = phy_gmii_sel_init_ports(priv); 480 if (ret) 481 return ret; 482 483 dev_set_drvdata(&pdev->dev, priv); 484 485 priv->phy_provider = 486 devm_of_phy_provider_register(dev, 487 phy_gmii_sel_of_xlate); 488 if (IS_ERR(priv->phy_provider)) { 489 ret = PTR_ERR(priv->phy_provider); 490 dev_err(dev, "Failed to create phy provider %d\n", ret); 491 return ret; 492 } 493 494 return 0; 495 } 496 497 static struct platform_driver phy_gmii_sel_driver = { 498 .probe = phy_gmii_sel_probe, 499 .driver = { 500 .name = "phy-gmii-sel", 501 .of_match_table = phy_gmii_sel_id_table, 502 }, 503 }; 504 module_platform_driver(phy_gmii_sel_driver); 505 506 MODULE_LICENSE("GPL v2"); 507 MODULE_AUTHOR("Grygorii Strashko <grygorii.strashko@ti.com>"); 508 MODULE_DESCRIPTION("TI CPSW Port's PHY Interface Mode selection Driver"); 509