Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net: mdio: Add RTL9300 MDIO driver

Add a driver for the MDIO controller on the RTL9300 family of Ethernet
switches with integrated SoC. There are 4 physical SMI interfaces on the
RTL9300 however access is done using the switch ports. The driver takes
the MDIO bus hierarchy from the DTS and uses this to configure the
switch ports so they are associated with the correct PHY. This mapping
is also used when dealing with software requests from phylib.

Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20250409231554.3943115-1-chris.packham@alliedtelesis.co.nz
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Chris Packham and committed by
Paolo Abeni
24e31e47 23f09f01

+530
+7
drivers/net/mdio/Kconfig
··· 185 185 This driver supports the MDIO interface found in the network 186 186 interface units of the IPQ8064 SoC 187 187 188 + config MDIO_REALTEK_RTL9300 189 + tristate "Realtek RTL9300 MDIO interface support" 190 + depends on MACH_REALTEK_RTL || COMPILE_TEST 191 + help 192 + This driver supports the MDIO interface found in the Realtek 193 + RTL9300 family of Ethernet switches with integrated SoC. 194 + 188 195 config MDIO_REGMAP 189 196 tristate 190 197 help
+1
drivers/net/mdio/Makefile
··· 19 19 obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o 20 20 obj-$(CONFIG_MDIO_MVUSB) += mdio-mvusb.o 21 21 obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o 22 + obj-$(CONFIG_MDIO_REALTEK_RTL9300) += mdio-realtek-rtl9300.o 22 23 obj-$(CONFIG_MDIO_REGMAP) += mdio-regmap.o 23 24 obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o 24 25 obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o
+522
drivers/net/mdio/mdio-realtek-rtl9300.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * MDIO controller for RTL9300 switches with integrated SoC. 4 + * 5 + * The MDIO communication is abstracted by the switch. At the software level 6 + * communication uses the switch port to address the PHY. We work out the 7 + * mapping based on the MDIO bus described in device tree and phandles on the 8 + * ethernet-ports property. 9 + */ 10 + 11 + #include <linux/bitfield.h> 12 + #include <linux/bitmap.h> 13 + #include <linux/bits.h> 14 + #include <linux/find.h> 15 + #include <linux/mdio.h> 16 + #include <linux/mfd/syscon.h> 17 + #include <linux/mod_devicetable.h> 18 + #include <linux/mutex.h> 19 + #include <linux/of_mdio.h> 20 + #include <linux/phy.h> 21 + #include <linux/platform_device.h> 22 + #include <linux/property.h> 23 + #include <linux/regmap.h> 24 + 25 + #define SMI_GLB_CTRL 0xca00 26 + #define GLB_CTRL_INTF_SEL(intf) BIT(16 + (intf)) 27 + #define SMI_PORT0_15_POLLING_SEL 0xca08 28 + #define SMI_ACCESS_PHY_CTRL_0 0xcb70 29 + #define SMI_ACCESS_PHY_CTRL_1 0xcb74 30 + #define PHY_CTRL_REG_ADDR GENMASK(24, 20) 31 + #define PHY_CTRL_PARK_PAGE GENMASK(19, 15) 32 + #define PHY_CTRL_MAIN_PAGE GENMASK(14, 3) 33 + #define PHY_CTRL_WRITE BIT(2) 34 + #define PHY_CTRL_READ 0 35 + #define PHY_CTRL_TYPE_C45 BIT(1) 36 + #define PHY_CTRL_TYPE_C22 0 37 + #define PHY_CTRL_CMD BIT(0) 38 + #define PHY_CTRL_FAIL BIT(25) 39 + #define SMI_ACCESS_PHY_CTRL_2 0xcb78 40 + #define PHY_CTRL_INDATA GENMASK(31, 16) 41 + #define PHY_CTRL_DATA GENMASK(15, 0) 42 + #define SMI_ACCESS_PHY_CTRL_3 0xcb7c 43 + #define PHY_CTRL_MMD_DEVAD GENMASK(20, 16) 44 + #define PHY_CTRL_MMD_REG GENMASK(15, 0) 45 + #define SMI_PORT0_5_ADDR_CTRL 0xcb80 46 + 47 + #define MAX_PORTS 28 48 + #define MAX_SMI_BUSSES 4 49 + #define MAX_SMI_ADDR 0x1f 50 + 51 + struct rtl9300_mdio_priv { 52 + struct regmap *regmap; 53 + struct mutex lock; /* protect HW access */ 54 + DECLARE_BITMAP(valid_ports, MAX_PORTS); 55 + u8 smi_bus[MAX_PORTS]; 56 + u8 smi_addr[MAX_PORTS]; 57 + bool smi_bus_is_c45[MAX_SMI_BUSSES]; 58 + struct mii_bus *bus[MAX_SMI_BUSSES]; 59 + }; 60 + 61 + struct rtl9300_mdio_chan { 62 + struct rtl9300_mdio_priv *priv; 63 + u8 mdio_bus; 64 + }; 65 + 66 + static int rtl9300_mdio_phy_to_port(struct mii_bus *bus, int phy_id) 67 + { 68 + struct rtl9300_mdio_chan *chan = bus->priv; 69 + struct rtl9300_mdio_priv *priv; 70 + int i; 71 + 72 + priv = chan->priv; 73 + 74 + for_each_set_bit(i, priv->valid_ports, MAX_PORTS) 75 + if (priv->smi_bus[i] == chan->mdio_bus && 76 + priv->smi_addr[i] == phy_id) 77 + return i; 78 + 79 + return -ENOENT; 80 + } 81 + 82 + static int rtl9300_mdio_wait_ready(struct rtl9300_mdio_priv *priv) 83 + { 84 + struct regmap *regmap = priv->regmap; 85 + u32 val; 86 + 87 + lockdep_assert_held(&priv->lock); 88 + 89 + return regmap_read_poll_timeout(regmap, SMI_ACCESS_PHY_CTRL_1, 90 + val, !(val & PHY_CTRL_CMD), 10, 1000); 91 + } 92 + 93 + static int rtl9300_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum) 94 + { 95 + struct rtl9300_mdio_chan *chan = bus->priv; 96 + struct rtl9300_mdio_priv *priv; 97 + struct regmap *regmap; 98 + int port; 99 + u32 val; 100 + int err; 101 + 102 + priv = chan->priv; 103 + regmap = priv->regmap; 104 + 105 + port = rtl9300_mdio_phy_to_port(bus, phy_id); 106 + if (port < 0) 107 + return port; 108 + 109 + mutex_lock(&priv->lock); 110 + err = rtl9300_mdio_wait_ready(priv); 111 + if (err) 112 + goto out_err; 113 + 114 + err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, FIELD_PREP(PHY_CTRL_INDATA, port)); 115 + if (err) 116 + goto out_err; 117 + 118 + val = FIELD_PREP(PHY_CTRL_REG_ADDR, regnum) | 119 + FIELD_PREP(PHY_CTRL_PARK_PAGE, 0x1f) | 120 + FIELD_PREP(PHY_CTRL_MAIN_PAGE, 0xfff) | 121 + PHY_CTRL_READ | PHY_CTRL_TYPE_C22 | PHY_CTRL_CMD; 122 + err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, val); 123 + if (err) 124 + goto out_err; 125 + 126 + err = rtl9300_mdio_wait_ready(priv); 127 + if (err) 128 + goto out_err; 129 + 130 + err = regmap_read(regmap, SMI_ACCESS_PHY_CTRL_2, &val); 131 + if (err) 132 + goto out_err; 133 + 134 + mutex_unlock(&priv->lock); 135 + return FIELD_GET(PHY_CTRL_DATA, val); 136 + 137 + out_err: 138 + mutex_unlock(&priv->lock); 139 + return err; 140 + } 141 + 142 + static int rtl9300_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum, u16 value) 143 + { 144 + struct rtl9300_mdio_chan *chan = bus->priv; 145 + struct rtl9300_mdio_priv *priv; 146 + struct regmap *regmap; 147 + int port; 148 + u32 val; 149 + int err; 150 + 151 + priv = chan->priv; 152 + regmap = priv->regmap; 153 + 154 + port = rtl9300_mdio_phy_to_port(bus, phy_id); 155 + if (port < 0) 156 + return port; 157 + 158 + mutex_lock(&priv->lock); 159 + err = rtl9300_mdio_wait_ready(priv); 160 + if (err) 161 + goto out_err; 162 + 163 + err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_0, BIT(port)); 164 + if (err) 165 + goto out_err; 166 + 167 + err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, FIELD_PREP(PHY_CTRL_INDATA, value)); 168 + if (err) 169 + goto out_err; 170 + 171 + val = FIELD_PREP(PHY_CTRL_REG_ADDR, regnum) | 172 + FIELD_PREP(PHY_CTRL_PARK_PAGE, 0x1f) | 173 + FIELD_PREP(PHY_CTRL_MAIN_PAGE, 0xfff) | 174 + PHY_CTRL_WRITE | PHY_CTRL_TYPE_C22 | PHY_CTRL_CMD; 175 + err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, val); 176 + if (err) 177 + goto out_err; 178 + 179 + err = regmap_read_poll_timeout(regmap, SMI_ACCESS_PHY_CTRL_1, 180 + val, !(val & PHY_CTRL_CMD), 10, 100); 181 + if (err) 182 + goto out_err; 183 + 184 + if (val & PHY_CTRL_FAIL) { 185 + err = -ENXIO; 186 + goto out_err; 187 + } 188 + 189 + mutex_unlock(&priv->lock); 190 + return 0; 191 + 192 + out_err: 193 + mutex_unlock(&priv->lock); 194 + return err; 195 + } 196 + 197 + static int rtl9300_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr, int regnum) 198 + { 199 + struct rtl9300_mdio_chan *chan = bus->priv; 200 + struct rtl9300_mdio_priv *priv; 201 + struct regmap *regmap; 202 + int port; 203 + u32 val; 204 + int err; 205 + 206 + priv = chan->priv; 207 + regmap = priv->regmap; 208 + 209 + port = rtl9300_mdio_phy_to_port(bus, phy_id); 210 + if (port < 0) 211 + return port; 212 + 213 + mutex_lock(&priv->lock); 214 + err = rtl9300_mdio_wait_ready(priv); 215 + if (err) 216 + goto out_err; 217 + 218 + val = FIELD_PREP(PHY_CTRL_INDATA, port); 219 + err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, val); 220 + if (err) 221 + goto out_err; 222 + 223 + val = FIELD_PREP(PHY_CTRL_MMD_DEVAD, dev_addr) | 224 + FIELD_PREP(PHY_CTRL_MMD_REG, regnum); 225 + err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_3, val); 226 + if (err) 227 + goto out_err; 228 + 229 + err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, 230 + PHY_CTRL_READ | PHY_CTRL_TYPE_C45 | PHY_CTRL_CMD); 231 + if (err) 232 + goto out_err; 233 + 234 + err = rtl9300_mdio_wait_ready(priv); 235 + if (err) 236 + goto out_err; 237 + 238 + err = regmap_read(regmap, SMI_ACCESS_PHY_CTRL_2, &val); 239 + if (err) 240 + goto out_err; 241 + 242 + mutex_unlock(&priv->lock); 243 + return FIELD_GET(PHY_CTRL_DATA, val); 244 + 245 + out_err: 246 + mutex_unlock(&priv->lock); 247 + return err; 248 + } 249 + 250 + static int rtl9300_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr, 251 + int regnum, u16 value) 252 + { 253 + struct rtl9300_mdio_chan *chan = bus->priv; 254 + struct rtl9300_mdio_priv *priv; 255 + struct regmap *regmap; 256 + int port; 257 + u32 val; 258 + int err; 259 + 260 + priv = chan->priv; 261 + regmap = priv->regmap; 262 + 263 + port = rtl9300_mdio_phy_to_port(bus, phy_id); 264 + if (port < 0) 265 + return port; 266 + 267 + mutex_lock(&priv->lock); 268 + err = rtl9300_mdio_wait_ready(priv); 269 + if (err) 270 + goto out_err; 271 + 272 + err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_0, BIT(port)); 273 + if (err) 274 + goto out_err; 275 + 276 + val = FIELD_PREP(PHY_CTRL_INDATA, value); 277 + err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, val); 278 + if (err) 279 + goto out_err; 280 + 281 + val = FIELD_PREP(PHY_CTRL_MMD_DEVAD, dev_addr) | 282 + FIELD_PREP(PHY_CTRL_MMD_REG, regnum); 283 + err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_3, val); 284 + if (err) 285 + goto out_err; 286 + 287 + err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, 288 + PHY_CTRL_TYPE_C45 | PHY_CTRL_WRITE | PHY_CTRL_CMD); 289 + if (err) 290 + goto out_err; 291 + 292 + err = regmap_read_poll_timeout(regmap, SMI_ACCESS_PHY_CTRL_1, 293 + val, !(val & PHY_CTRL_CMD), 10, 100); 294 + if (err) 295 + goto out_err; 296 + 297 + if (val & PHY_CTRL_FAIL) { 298 + err = -ENXIO; 299 + goto out_err; 300 + } 301 + 302 + mutex_unlock(&priv->lock); 303 + return 0; 304 + 305 + out_err: 306 + mutex_unlock(&priv->lock); 307 + return err; 308 + } 309 + 310 + static int rtl9300_mdiobus_init(struct rtl9300_mdio_priv *priv) 311 + { 312 + u32 glb_ctrl_mask = 0, glb_ctrl_val = 0; 313 + struct regmap *regmap = priv->regmap; 314 + u32 port_addr[5] = { 0 }; 315 + u32 poll_sel[2] = { 0 }; 316 + int i, err; 317 + 318 + /* Associate the port with the SMI interface and PHY */ 319 + for_each_set_bit(i, priv->valid_ports, MAX_PORTS) { 320 + int pos; 321 + 322 + pos = (i % 6) * 5; 323 + port_addr[i / 6] |= (priv->smi_addr[i] & 0x1f) << pos; 324 + 325 + pos = (i % 16) * 2; 326 + poll_sel[i / 16] |= (priv->smi_bus[i] & 0x3) << pos; 327 + } 328 + 329 + /* Put the interfaces into C45 mode if required */ 330 + glb_ctrl_mask = GENMASK(19, 16); 331 + for (i = 0; i < MAX_SMI_BUSSES; i++) 332 + if (priv->smi_bus_is_c45[i]) 333 + glb_ctrl_val |= GLB_CTRL_INTF_SEL(i); 334 + 335 + err = regmap_bulk_write(regmap, SMI_PORT0_5_ADDR_CTRL, 336 + port_addr, 5); 337 + if (err) 338 + return err; 339 + 340 + err = regmap_bulk_write(regmap, SMI_PORT0_15_POLLING_SEL, 341 + poll_sel, 2); 342 + if (err) 343 + return err; 344 + 345 + err = regmap_update_bits(regmap, SMI_GLB_CTRL, 346 + glb_ctrl_mask, glb_ctrl_val); 347 + if (err) 348 + return err; 349 + 350 + return 0; 351 + } 352 + 353 + static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_priv *priv, 354 + struct fwnode_handle *node) 355 + { 356 + struct rtl9300_mdio_chan *chan; 357 + struct fwnode_handle *child; 358 + struct mii_bus *bus; 359 + u32 mdio_bus; 360 + int err; 361 + 362 + err = fwnode_property_read_u32(node, "reg", &mdio_bus); 363 + if (err) 364 + return err; 365 + 366 + /* The MDIO accesses from the kernel work with the PHY polling unit in 367 + * the switch. We need to tell the PPU to operate either in GPHY (i.e. 368 + * clause 22) or 10GPHY mode (i.e. clause 45). 369 + * 370 + * We select 10GPHY mode if there is at least one PHY that declares 371 + * compatible = "ethernet-phy-ieee802.3-c45". This does mean we can't 372 + * support both c45 and c22 on the same MDIO bus. 373 + */ 374 + fwnode_for_each_child_node(node, child) 375 + if (fwnode_device_is_compatible(child, "ethernet-phy-ieee802.3-c45")) 376 + priv->smi_bus_is_c45[mdio_bus] = true; 377 + 378 + bus = devm_mdiobus_alloc_size(dev, sizeof(*chan)); 379 + if (!bus) 380 + return -ENOMEM; 381 + 382 + bus->name = "Realtek Switch MDIO Bus"; 383 + if (priv->smi_bus_is_c45[mdio_bus]) { 384 + bus->read_c45 = rtl9300_mdio_read_c45; 385 + bus->write_c45 = rtl9300_mdio_write_c45; 386 + } else { 387 + bus->read = rtl9300_mdio_read_c22; 388 + bus->write = rtl9300_mdio_write_c22; 389 + } 390 + bus->parent = dev; 391 + chan = bus->priv; 392 + chan->mdio_bus = mdio_bus; 393 + chan->priv = priv; 394 + 395 + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", dev_name(dev), mdio_bus); 396 + 397 + err = devm_of_mdiobus_register(dev, bus, to_of_node(node)); 398 + if (err) 399 + return dev_err_probe(dev, err, "cannot register MDIO bus\n"); 400 + 401 + return 0; 402 + } 403 + 404 + /* The mdio-controller is part of a switch block so we parse the sibling 405 + * ethernet-ports node and build a mapping of the switch port to MDIO bus/addr 406 + * based on the phy-handle. 407 + */ 408 + static int rtl9300_mdiobus_map_ports(struct device *dev) 409 + { 410 + struct rtl9300_mdio_priv *priv = dev_get_drvdata(dev); 411 + struct device *parent = dev->parent; 412 + struct fwnode_handle *port; 413 + int err; 414 + 415 + struct fwnode_handle *ports __free(fwnode_handle) = 416 + device_get_named_child_node(parent, "ethernet-ports"); 417 + if (!ports) 418 + return dev_err_probe(dev, -EINVAL, "%pfwP missing ethernet-ports\n", 419 + dev_fwnode(parent)); 420 + 421 + fwnode_for_each_child_node(ports, port) { 422 + struct device_node *mdio_dn; 423 + u32 addr; 424 + u32 bus; 425 + u32 pn; 426 + 427 + struct device_node *phy_dn __free(device_node) = 428 + of_parse_phandle(to_of_node(port), "phy-handle", 0); 429 + /* skip ports without phys */ 430 + if (!phy_dn) 431 + continue; 432 + 433 + mdio_dn = phy_dn->parent; 434 + /* only map ports that are connected to this mdio-controller */ 435 + if (mdio_dn->parent != dev->of_node) 436 + continue; 437 + 438 + err = fwnode_property_read_u32(port, "reg", &pn); 439 + if (err) 440 + return err; 441 + 442 + if (pn >= MAX_PORTS) 443 + return dev_err_probe(dev, -EINVAL, "illegal port number %d\n", pn); 444 + 445 + if (test_bit(pn, priv->valid_ports)) 446 + return dev_err_probe(dev, -EINVAL, "duplicated port number %d\n", pn); 447 + 448 + err = of_property_read_u32(mdio_dn, "reg", &bus); 449 + if (err) 450 + return err; 451 + 452 + if (bus >= MAX_SMI_BUSSES) 453 + return dev_err_probe(dev, -EINVAL, "illegal smi bus number %d\n", bus); 454 + 455 + err = of_property_read_u32(phy_dn, "reg", &addr); 456 + if (err) 457 + return err; 458 + 459 + __set_bit(pn, priv->valid_ports); 460 + priv->smi_bus[pn] = bus; 461 + priv->smi_addr[pn] = addr; 462 + } 463 + 464 + return 0; 465 + } 466 + 467 + static int rtl9300_mdiobus_probe(struct platform_device *pdev) 468 + { 469 + struct device *dev = &pdev->dev; 470 + struct rtl9300_mdio_priv *priv; 471 + struct fwnode_handle *child; 472 + int err; 473 + 474 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 475 + if (!priv) 476 + return -ENOMEM; 477 + 478 + err = devm_mutex_init(dev, &priv->lock); 479 + if (err) 480 + return err; 481 + 482 + priv->regmap = syscon_node_to_regmap(dev->parent->of_node); 483 + if (IS_ERR(priv->regmap)) 484 + return PTR_ERR(priv->regmap); 485 + 486 + platform_set_drvdata(pdev, priv); 487 + 488 + err = rtl9300_mdiobus_map_ports(dev); 489 + if (err) 490 + return err; 491 + 492 + device_for_each_child_node(dev, child) { 493 + err = rtl9300_mdiobus_probe_one(dev, priv, child); 494 + if (err) 495 + return err; 496 + } 497 + 498 + err = rtl9300_mdiobus_init(priv); 499 + if (err) 500 + return dev_err_probe(dev, err, "failed to initialise MDIO bus controller\n"); 501 + 502 + return 0; 503 + } 504 + 505 + static const struct of_device_id rtl9300_mdio_ids[] = { 506 + { .compatible = "realtek,rtl9301-mdio" }, 507 + {} 508 + }; 509 + MODULE_DEVICE_TABLE(of, rtl9300_mdio_ids); 510 + 511 + static struct platform_driver rtl9300_mdio_driver = { 512 + .probe = rtl9300_mdiobus_probe, 513 + .driver = { 514 + .name = "mdio-rtl9300", 515 + .of_match_table = rtl9300_mdio_ids, 516 + }, 517 + }; 518 + 519 + module_platform_driver(rtl9300_mdio_driver); 520 + 521 + MODULE_DESCRIPTION("RTL9300 MDIO driver"); 522 + MODULE_LICENSE("GPL");