From: Markus Stockhausen Date: Tue, 7 Apr 2026 16:22:07 +0000 (+0200) Subject: realtek: mdio: activate multiple busses X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=084da38a2e74499156fb806abef9dbfffd563aeb;p=thirdparty%2Fopenwrt.git realtek: mdio: activate multiple busses The mdio controller inside the Realtek switches drives multiple busses. Until now the driver exposed a flattened single bus (aka port view). Align to the upstream driver and expose up to 4 busses depending on the dts definition. For this: 1. Adapt rtmdio_probe() so it calls rtmdio_probe_one() for each child dts child node that represents a single bus. 2. Adapt rtmdio_probe_one() so it registers a single bus in "full-auto" mode. No more hacks via fwnode_mdiobus_register_phy() needed. 3. Adapt rtmdio_phy_to_port() so it uses a lookup based on the new topology. 4. Adapt rtmdio_get_phy_info() for multiple busses. 5. In the DSA driver adapt the mdio controller load check to wait until all busses have been registered. Signed-off-by: Markus Stockhausen Link: https://github.com/openwrt/openwrt/pull/22830 Signed-off-by: Robert Marko --- diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c index 11fc2decb72..56df39855fc 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/common.c @@ -214,17 +214,24 @@ u64 rtl839x_get_port_reg_le(int reg) static int rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv) { struct device_node *dn, *phy_node, *pcs_node, *led_node; - struct mii_bus *bus; u32 pn; - /* Check if mdio bus is defined with status "okay" and already registered */ + /* Check if all busses of Realtek mdio controller are registered */ dn = of_find_compatible_node(NULL, NULL, "realtek,otto-mdio"); - if (!dn || !of_device_is_available(dn)) + if (!of_device_is_available(dn)) { + of_node_put(dn); return -ENODEV; - bus = of_mdio_find_bus(dn); - if (!bus) - return -EPROBE_DEFER; - put_device(&bus->dev); + } + + for_each_child_of_node_scoped(dn, bn) { + struct mii_bus *bus = of_mdio_find_bus(bn); + if (!bus) { + of_node_put(dn); + return -EPROBE_DEFER; + } + put_device(&bus->dev); + } + of_node_put(dn); dn = of_find_compatible_node(NULL, NULL, "realtek,otto-switch"); if (!dn) { diff --git a/target/linux/realtek/files-6.18/drivers/net/mdio/mdio-realtek-otto.c b/target/linux/realtek/files-6.18/drivers/net/mdio/mdio-realtek-otto.c index 827df30a2db..3c6f2b16c31 100644 --- a/target/linux/realtek/files-6.18/drivers/net/mdio/mdio-realtek-otto.c +++ b/target/linux/realtek/files-6.18/drivers/net/mdio/mdio-realtek-otto.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -227,15 +228,15 @@ struct rtmdio_phy_info { static int rtmdio_phy_to_port(struct mii_bus *bus, int phy) { - struct rtmdio_ctrl *ctrl = rtmdio_ctrl_from_bus(bus); - - if (phy < 0 || phy >= ctrl->cfg->num_phys) - return -ENOENT; + struct rtmdio_chan *chan = bus->priv; + struct rtmdio_ctrl *ctrl = chan->ctrl; + int pn; - if (!test_bit(phy, ctrl->valid_ports)) - return -ENOENT; + for_each_port(ctrl, pn) + if (ctrl->port[pn].smi_bus == chan->smi_bus && ctrl->port[pn].smi_addr == phy) + return pn; - return phy; + return -ENOENT; } static int rtmdio_run_cmd(struct mii_bus *bus, int cmd, int mask, int regnum, int fail) @@ -642,9 +643,10 @@ static u32 rtmdio_get_phy_id(struct phy_device *phydev) static int rtmdio_get_phy_info(struct rtmdio_ctrl *ctrl, int pn, struct rtmdio_phy_info *phyinfo) { - struct phy_device *phydev = mdiobus_get_phy(ctrl->bus[0].mii_bus, pn); - u32 phyid = rtmdio_get_phy_id(phydev); + struct mii_bus *bus = ctrl->bus[ctrl->port[pn].smi_bus].mii_bus; + int addr = ctrl->port[pn].smi_addr; int ret = 0; + u32 phyid; /* * Depending on the attached PHY the polling mechanism must be fine tuned. Basically @@ -652,6 +654,7 @@ static int rtmdio_get_phy_info(struct rtmdio_ctrl *ctrl, int pn, struct rtmdio_p * features. */ memset(phyinfo, 0, sizeof(*phyinfo)); + phyid = rtmdio_get_phy_id(mdiobus_get_phy(bus, addr)); switch(phyid) { case RTMDIO_PHY_AQR113C_A: @@ -920,21 +923,26 @@ static int rtmdio_map_ports(struct device *dev) return 0; } -static int rtmdio_probe_one(struct device *dev, struct rtmdio_ctrl *ctrl) +static int rtmdio_probe_one(struct device *dev, struct rtmdio_ctrl *ctrl, + struct fwnode_handle *node) { struct rtmdio_chan *chan; struct mii_bus *bus; - int ret, pn; + int smi_bus, ret; + + ret = fwnode_property_read_u32(node, "reg", &smi_bus); + if (ret) + return ret; bus = devm_mdiobus_alloc_size(dev, sizeof(*chan)); if (!bus) return -ENOMEM; + ctrl->bus[smi_bus].mii_bus = bus; + chan = bus->priv; chan->ctrl = ctrl; - - chan->smi_bus = 0; - ctrl->bus[0].mii_bus = bus; + chan->smi_bus = smi_bus; bus->name = "Realtek MDIO bus"; bus->read = rtmdio_read; @@ -942,22 +950,11 @@ static int rtmdio_probe_one(struct device *dev, struct rtmdio_ctrl *ctrl) bus->read_c45 = rtmdio_read_c45; bus->write_c45 = rtmdio_write_c45; bus->parent = dev; - bus->phy_mask = ~0; - snprintf(bus->id, MII_BUS_ID_SIZE, "realtek-mdio"); - device_set_node(&bus->dev, of_fwnode_handle(dev->of_node)); + snprintf(bus->id, MII_BUS_ID_SIZE, "realtek-mdio-%d", smi_bus); - ret = devm_mdiobus_register(dev, bus); + ret = devm_of_mdiobus_register(dev, bus, to_of_node(node)); if (ret) - return dev_err_probe(dev, ret, "cannot register MDIO bus\n"); - - for_each_port(ctrl, pn) { - if (!ret) - ret = fwnode_mdiobus_register_phy(bus, - of_fwnode_handle(ctrl->port[pn].dn), pn); - of_node_put(ctrl->port[pn].dn); - } - if (ret) - return ret; + return dev_err_probe(dev, ret, "cannot register MDIO %d bus\n", smi_bus); return 0; } @@ -991,9 +988,11 @@ static int rtmdio_probe(struct platform_device *pdev) rtmdio_setup_smi_topology(ctrl); ctrl->cfg->setup_ctrl(ctrl); - ret = rtmdio_probe_one(dev, ctrl); - if (ret) - return ret; + device_for_each_child_node_scoped(dev, child) { + ret = rtmdio_probe_one(dev, ctrl, child); + if (ret) + return ret; + } if (ctrl->cfg->setup_polling) ctrl->cfg->setup_polling(ctrl);