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 <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/22830
Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
Markus Stockhausen 2026-04-07 18:22:07 +02:00 committed by Robert Marko
parent 87d5b3f7e6
commit 084da38a2e
2 changed files with 44 additions and 38 deletions

View File

@ -214,17 +214,24 @@ u64 rtl839x_get_port_reg_le(int reg)
static int rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv) static int rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
{ {
struct device_node *dn, *phy_node, *pcs_node, *led_node; struct device_node *dn, *phy_node, *pcs_node, *led_node;
struct mii_bus *bus;
u32 pn; 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"); 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; return -ENODEV;
bus = of_mdio_find_bus(dn); }
if (!bus)
return -EPROBE_DEFER; for_each_child_of_node_scoped(dn, bn) {
put_device(&bus->dev); 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"); dn = of_find_compatible_node(NULL, NULL, "realtek,otto-switch");
if (!dn) { if (!dn) {

View File

@ -4,6 +4,7 @@
#include <linux/fwnode_mdio.h> #include <linux/fwnode_mdio.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_mdio.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
@ -227,15 +228,15 @@ struct rtmdio_phy_info {
static int rtmdio_phy_to_port(struct mii_bus *bus, int phy) static int rtmdio_phy_to_port(struct mii_bus *bus, int phy)
{ {
struct rtmdio_ctrl *ctrl = rtmdio_ctrl_from_bus(bus); struct rtmdio_chan *chan = bus->priv;
struct rtmdio_ctrl *ctrl = chan->ctrl;
int pn;
if (phy < 0 || phy >= ctrl->cfg->num_phys) for_each_port(ctrl, pn)
return -ENOENT; if (ctrl->port[pn].smi_bus == chan->smi_bus && ctrl->port[pn].smi_addr == phy)
return pn;
if (!test_bit(phy, ctrl->valid_ports)) return -ENOENT;
return -ENOENT;
return phy;
} }
static int rtmdio_run_cmd(struct mii_bus *bus, int cmd, int mask, int regnum, int fail) 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) 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); struct mii_bus *bus = ctrl->bus[ctrl->port[pn].smi_bus].mii_bus;
u32 phyid = rtmdio_get_phy_id(phydev); int addr = ctrl->port[pn].smi_addr;
int ret = 0; int ret = 0;
u32 phyid;
/* /*
* Depending on the attached PHY the polling mechanism must be fine tuned. Basically * 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. * features.
*/ */
memset(phyinfo, 0, sizeof(*phyinfo)); memset(phyinfo, 0, sizeof(*phyinfo));
phyid = rtmdio_get_phy_id(mdiobus_get_phy(bus, addr));
switch(phyid) { switch(phyid) {
case RTMDIO_PHY_AQR113C_A: case RTMDIO_PHY_AQR113C_A:
@ -920,21 +923,26 @@ static int rtmdio_map_ports(struct device *dev)
return 0; 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 rtmdio_chan *chan;
struct mii_bus *bus; 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)); bus = devm_mdiobus_alloc_size(dev, sizeof(*chan));
if (!bus) if (!bus)
return -ENOMEM; return -ENOMEM;
ctrl->bus[smi_bus].mii_bus = bus;
chan = bus->priv; chan = bus->priv;
chan->ctrl = ctrl; chan->ctrl = ctrl;
chan->smi_bus = smi_bus;
chan->smi_bus = 0;
ctrl->bus[0].mii_bus = bus;
bus->name = "Realtek MDIO bus"; bus->name = "Realtek MDIO bus";
bus->read = rtmdio_read; 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->read_c45 = rtmdio_read_c45;
bus->write_c45 = rtmdio_write_c45; bus->write_c45 = rtmdio_write_c45;
bus->parent = dev; bus->parent = dev;
bus->phy_mask = ~0; snprintf(bus->id, MII_BUS_ID_SIZE, "realtek-mdio-%d", smi_bus);
snprintf(bus->id, MII_BUS_ID_SIZE, "realtek-mdio");
device_set_node(&bus->dev, of_fwnode_handle(dev->of_node));
ret = devm_mdiobus_register(dev, bus); ret = devm_of_mdiobus_register(dev, bus, to_of_node(node));
if (ret) if (ret)
return dev_err_probe(dev, ret, "cannot register MDIO bus\n"); return dev_err_probe(dev, ret, "cannot register MDIO %d bus\n", smi_bus);
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 0; return 0;
} }
@ -991,9 +988,11 @@ static int rtmdio_probe(struct platform_device *pdev)
rtmdio_setup_smi_topology(ctrl); rtmdio_setup_smi_topology(ctrl);
ctrl->cfg->setup_ctrl(ctrl); ctrl->cfg->setup_ctrl(ctrl);
ret = rtmdio_probe_one(dev, ctrl); device_for_each_child_node_scoped(dev, child) {
if (ret) ret = rtmdio_probe_one(dev, ctrl, child);
return ret; if (ret)
return ret;
}
if (ctrl->cfg->setup_polling) if (ctrl->cfg->setup_polling)
ctrl->cfg->setup_polling(ctrl); ctrl->cfg->setup_polling(ctrl);