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