From d15c0d1df49480b8f7d7c6182880e353574c871d Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Thu, 21 May 2026 19:59:10 +0200 Subject: net: mdio: realtek-rtl9300: enhance documentation & naming The Realtek ethernet MDIO driver currently only serves SOCs from the Realtek RTL930x series. This is only one lineup of the Realtek Otto switch series that also knows RTL838x, RTL839x, RTL931x devices. All of these share similar hardware with comparable MMIO access logic but have individual variations. Important to note - Controller works on switch ports instead of buses and addresses. - Devices incorporate additional MDIO hardware. E.g. - an auxiliary MDIO controller for GPIO expanders [1] - a MDIO style SerDes controller [2] To avoid future confusion enhance the driver documentation and function naming. Make clear what this driver is about and what parts are generic and what parts are device specific. For this rename the function and structure prefix as follows: - for generic functions use otto_emdio_ - for device specific helpers use e.g. otto_emdio_9300_ This prefix naming tries to align with the watchdog timer [3]. It paves the way so that drivers for the other Realtek Otto MDIO controllers can be added in future commits using the same naming convention. Remark 1: The read/write functions are kept device specific for now because they will only fit the RTL930x SOCs. Renaming will take place as soon as the I/O handling will be generalized. Remark 2: The driver name "mdio-rtl9300" is kept for now. [1] https://git.openwrt.org/openwrt/openwrt/tree/target/linux/realtek/patches-6.18/723-net-mdio-Add-Realtek-Otto-auxiliary-controller.patch [2] https://git.openwrt.org/openwrt/openwrt/tree/target/linux/realtek/files-6.18/drivers/net/mdio/mdio-realtek-otto-serdes.c [3] https://elixir.bootlin.com/linux/v7.0/source/drivers/watchdog/realtek_otto_wdt.c Signed-off-by: Markus Stockhausen Link: https://patch.msgid.link/20260521175918.1494797-2-markus.stockhausen@gmx.de Signed-off-by: Paolo Abeni --- drivers/net/mdio/mdio-realtek-rtl9300.c | 139 +++++++++++++++++++------------- 1 file changed, 84 insertions(+), 55 deletions(-) diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index 8d5fb014ca06..98484c689126 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -1,11 +1,40 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * MDIO controller for RTL9300 switches with integrated SoC. + * Realtek switches of the Otto series (RTL838x, RTL839x, RTL930x and RTL931x SoCs) have multiple + * integrated MDIO controllers. This driver targets the ethernet MDIO controller. It serves only + * 1G/2.5G/10G ethernet PHYs attached to up to 4 individual buses. * - * The MDIO communication is abstracted by the switch. At the software level - * communication uses the switch port to address the PHY. We work out the - * mapping based on the MDIO bus described in device tree and phandles on the - * ethernet-ports property. + * The controller is programmed through MMIO. The MDIO communication is abstracted by the hardware + * and uses the switch port number for its addressing. For this to work, mapping registers need to + * be setup in advance. With that the controller translates each port based I/O operation into the + * physical bus and address. This gives the following end-to-end communication + * + * +----------+ +----------+ +----------+ +----------+ + * | phydev | ... | phydev | | phydev | ... | phydev | + * +----------+ +----------+ +----------+ +----------+ + * | | | | + * mii_bus 0 +------------------+ +------------------+ mii_bus 1 + * | | + * +-----------------------------------------------------+ + * | MDIO driver | + * | translate bus/address -> port | + * +-----------------------------------------------------+ + * | Software + * - - - - - - - - - - - - - - - - - - - - - - - - - + * | Hardware + * +-----------------------------------------------------+ + * | MDIO controller | + * | translate port -> bus/address | + * +-----------------------------------------------------+ + * | | + * bus 0 +------------------+ +------------------+ bus 1 + * | | | | + * +----------+ +----------+ +----------+ +----------+ + * | PHY 0/1 | ... | PHY 0/31 | | PHY 1/1 | ... | PHY 1/31 | + * +----------+ +----------+ +----------+ +----------+ + * + * The driver works out the mapping based on the MDIO bus described in device tree and phandles on + * the ethernet-ports property. */ #include @@ -48,7 +77,7 @@ #define MAX_SMI_BUSSES 4 #define MAX_SMI_ADDR 0x1f -struct rtl9300_mdio_priv { +struct otto_emdio_priv { struct regmap *regmap; struct mutex lock; /* protect HW access */ DECLARE_BITMAP(valid_ports, MAX_PORTS); @@ -58,15 +87,15 @@ struct rtl9300_mdio_priv { struct mii_bus *bus[MAX_SMI_BUSSES]; }; -struct rtl9300_mdio_chan { - struct rtl9300_mdio_priv *priv; +struct otto_emdio_chan { + struct otto_emdio_priv *priv; u8 mdio_bus; }; -static int rtl9300_mdio_phy_to_port(struct mii_bus *bus, int phy_id) +static int otto_emdio_phy_to_port(struct mii_bus *bus, int phy_id) { - struct rtl9300_mdio_chan *chan = bus->priv; - struct rtl9300_mdio_priv *priv; + struct otto_emdio_chan *chan = bus->priv; + struct otto_emdio_priv *priv; int i; priv = chan->priv; @@ -79,7 +108,7 @@ static int rtl9300_mdio_phy_to_port(struct mii_bus *bus, int phy_id) return -ENOENT; } -static int rtl9300_mdio_wait_ready(struct rtl9300_mdio_priv *priv) +static int otto_emdio_wait_ready(struct otto_emdio_priv *priv) { struct regmap *regmap = priv->regmap; u32 val; @@ -90,10 +119,10 @@ static int rtl9300_mdio_wait_ready(struct rtl9300_mdio_priv *priv) val, !(val & PHY_CTRL_CMD), 10, 1000); } -static int rtl9300_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum) +static int otto_emdio_9300_read_c22(struct mii_bus *bus, int phy_id, int regnum) { - struct rtl9300_mdio_chan *chan = bus->priv; - struct rtl9300_mdio_priv *priv; + struct otto_emdio_chan *chan = bus->priv; + struct otto_emdio_priv *priv; struct regmap *regmap; int port; u32 val; @@ -102,12 +131,12 @@ static int rtl9300_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum) priv = chan->priv; regmap = priv->regmap; - port = rtl9300_mdio_phy_to_port(bus, phy_id); + port = otto_emdio_phy_to_port(bus, phy_id); if (port < 0) return port; mutex_lock(&priv->lock); - err = rtl9300_mdio_wait_ready(priv); + err = otto_emdio_wait_ready(priv); if (err) goto out_err; @@ -123,7 +152,7 @@ static int rtl9300_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum) if (err) goto out_err; - err = rtl9300_mdio_wait_ready(priv); + err = otto_emdio_wait_ready(priv); if (err) goto out_err; @@ -139,10 +168,10 @@ out_err: return err; } -static int rtl9300_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum, u16 value) +static int otto_emdio_9300_write_c22(struct mii_bus *bus, int phy_id, int regnum, u16 value) { - struct rtl9300_mdio_chan *chan = bus->priv; - struct rtl9300_mdio_priv *priv; + struct otto_emdio_chan *chan = bus->priv; + struct otto_emdio_priv *priv; struct regmap *regmap; int port; u32 val; @@ -151,12 +180,12 @@ static int rtl9300_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum, u priv = chan->priv; regmap = priv->regmap; - port = rtl9300_mdio_phy_to_port(bus, phy_id); + port = otto_emdio_phy_to_port(bus, phy_id); if (port < 0) return port; mutex_lock(&priv->lock); - err = rtl9300_mdio_wait_ready(priv); + err = otto_emdio_wait_ready(priv); if (err) goto out_err; @@ -194,10 +223,10 @@ out_err: return err; } -static int rtl9300_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr, int regnum) +static int otto_emdio_9300_read_c45(struct mii_bus *bus, int phy_id, int dev_addr, int regnum) { - struct rtl9300_mdio_chan *chan = bus->priv; - struct rtl9300_mdio_priv *priv; + struct otto_emdio_chan *chan = bus->priv; + struct otto_emdio_priv *priv; struct regmap *regmap; int port; u32 val; @@ -206,12 +235,12 @@ static int rtl9300_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr, priv = chan->priv; regmap = priv->regmap; - port = rtl9300_mdio_phy_to_port(bus, phy_id); + port = otto_emdio_phy_to_port(bus, phy_id); if (port < 0) return port; mutex_lock(&priv->lock); - err = rtl9300_mdio_wait_ready(priv); + err = otto_emdio_wait_ready(priv); if (err) goto out_err; @@ -231,7 +260,7 @@ static int rtl9300_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr, if (err) goto out_err; - err = rtl9300_mdio_wait_ready(priv); + err = otto_emdio_wait_ready(priv); if (err) goto out_err; @@ -247,11 +276,11 @@ out_err: return err; } -static int rtl9300_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr, +static int otto_emdio_9300_write_c45(struct mii_bus *bus, int phy_id, int dev_addr, int regnum, u16 value) { - struct rtl9300_mdio_chan *chan = bus->priv; - struct rtl9300_mdio_priv *priv; + struct otto_emdio_chan *chan = bus->priv; + struct otto_emdio_priv *priv; struct regmap *regmap; int port; u32 val; @@ -260,12 +289,12 @@ static int rtl9300_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr, priv = chan->priv; regmap = priv->regmap; - port = rtl9300_mdio_phy_to_port(bus, phy_id); + port = otto_emdio_phy_to_port(bus, phy_id); if (port < 0) return port; mutex_lock(&priv->lock); - err = rtl9300_mdio_wait_ready(priv); + err = otto_emdio_wait_ready(priv); if (err) goto out_err; @@ -307,7 +336,7 @@ out_err: return err; } -static int rtl9300_mdiobus_init(struct rtl9300_mdio_priv *priv) +static int otto_emdio_9300_mdiobus_init(struct otto_emdio_priv *priv) { u32 glb_ctrl_mask = 0, glb_ctrl_val = 0; struct regmap *regmap = priv->regmap; @@ -350,10 +379,10 @@ static int rtl9300_mdiobus_init(struct rtl9300_mdio_priv *priv) return 0; } -static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_priv *priv, - struct fwnode_handle *node) +static int otto_emdio_probe_one(struct device *dev, struct otto_emdio_priv *priv, + struct fwnode_handle *node) { - struct rtl9300_mdio_chan *chan; + struct otto_emdio_chan *chan; struct mii_bus *bus; u32 mdio_bus; int err; @@ -380,11 +409,11 @@ static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_pri bus->name = "Realtek Switch MDIO Bus"; if (priv->smi_bus_is_c45[mdio_bus]) { - bus->read_c45 = rtl9300_mdio_read_c45; - bus->write_c45 = rtl9300_mdio_write_c45; + bus->read_c45 = otto_emdio_9300_read_c45; + bus->write_c45 = otto_emdio_9300_write_c45; } else { - bus->read = rtl9300_mdio_read_c22; - bus->write = rtl9300_mdio_write_c22; + bus->read = otto_emdio_9300_read_c22; + bus->write = otto_emdio_9300_write_c22; } bus->parent = dev; chan = bus->priv; @@ -404,9 +433,9 @@ static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_pri * ethernet-ports node and build a mapping of the switch port to MDIO bus/addr * based on the phy-handle. */ -static int rtl9300_mdiobus_map_ports(struct device *dev) +static int otto_emdio_map_ports(struct device *dev) { - struct rtl9300_mdio_priv *priv = dev_get_drvdata(dev); + struct otto_emdio_priv *priv = dev_get_drvdata(dev); struct device *parent = dev->parent; int err; @@ -462,10 +491,10 @@ static int rtl9300_mdiobus_map_ports(struct device *dev) return 0; } -static int rtl9300_mdiobus_probe(struct platform_device *pdev) +static int otto_emdio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct rtl9300_mdio_priv *priv; + struct otto_emdio_priv *priv; int err; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -482,38 +511,38 @@ static int rtl9300_mdiobus_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); - err = rtl9300_mdiobus_map_ports(dev); + err = otto_emdio_map_ports(dev); if (err) return err; device_for_each_child_node_scoped(dev, child) { - err = rtl9300_mdiobus_probe_one(dev, priv, child); + err = otto_emdio_probe_one(dev, priv, child); if (err) return err; } - err = rtl9300_mdiobus_init(priv); + err = otto_emdio_9300_mdiobus_init(priv); if (err) return dev_err_probe(dev, err, "failed to initialise MDIO bus controller\n"); return 0; } -static const struct of_device_id rtl9300_mdio_ids[] = { +static const struct of_device_id otto_emdio_ids[] = { { .compatible = "realtek,rtl9301-mdio" }, {} }; -MODULE_DEVICE_TABLE(of, rtl9300_mdio_ids); +MODULE_DEVICE_TABLE(of, otto_emdio_ids); -static struct platform_driver rtl9300_mdio_driver = { - .probe = rtl9300_mdiobus_probe, +static struct platform_driver otto_emdio_driver = { + .probe = otto_emdio_probe, .driver = { .name = "mdio-rtl9300", - .of_match_table = rtl9300_mdio_ids, + .of_match_table = otto_emdio_ids, }, }; -module_platform_driver(rtl9300_mdio_driver); +module_platform_driver(otto_emdio_driver); MODULE_DESCRIPTION("RTL9300 MDIO driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 315a02b39e8c4d1e8aebc8c3cc1e14e193f116ae Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Thu, 21 May 2026 19:59:11 +0200 Subject: net: mdio: realtek-rtl9300: Add device specific info structure Device properties of the RTL930x SOCs are hardcoded into the MDIO driver. This must be relaxed to support additional devices like the RTL838x or RTL839x. These do not have 4 SMI buses but 1 or 2 instead. To support multiple devices establish an info structure that contains individual variations of each series. As a first use case add the number of buses into this structure and use it where needed. Signed-off-by: Markus Stockhausen Link: https://patch.msgid.link/20260521175918.1494797-3-markus.stockhausen@gmx.de Signed-off-by: Paolo Abeni --- drivers/net/mdio/mdio-realtek-rtl9300.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index 98484c689126..931c6684b2f3 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -51,6 +51,7 @@ #include #include +#define RTL9300_NUM_BUSES 4 #define SMI_GLB_CTRL 0xca00 #define GLB_CTRL_INTF_SEL(intf) BIT(16 + (intf)) #define SMI_PORT0_15_POLLING_SEL 0xca08 @@ -77,7 +78,12 @@ #define MAX_SMI_BUSSES 4 #define MAX_SMI_ADDR 0x1f +struct otto_emdio_info { + u8 num_buses; +}; + struct otto_emdio_priv { + const struct otto_emdio_info *info; struct regmap *regmap; struct mutex lock; /* protect HW access */ DECLARE_BITMAP(valid_ports, MAX_PORTS); @@ -357,7 +363,7 @@ static int otto_emdio_9300_mdiobus_init(struct otto_emdio_priv *priv) /* Put the interfaces into C45 mode if required */ glb_ctrl_mask = GENMASK(19, 16); - for (i = 0; i < MAX_SMI_BUSSES; i++) + for (i = 0; i < priv->info->num_buses; i++) if (priv->smi_bus_is_c45[i]) glb_ctrl_val |= GLB_CTRL_INTF_SEL(i); @@ -476,7 +482,7 @@ static int otto_emdio_map_ports(struct device *dev) if (err) return err; - if (bus >= MAX_SMI_BUSSES) + if (bus >= priv->info->num_buses) return dev_err_probe(dev, -EINVAL, "illegal smi bus number %d\n", bus); err = of_property_read_u32(phy_dn, "reg", &addr); @@ -505,6 +511,7 @@ static int otto_emdio_probe(struct platform_device *pdev) if (err) return err; + priv->info = device_get_match_data(dev); priv->regmap = syscon_node_to_regmap(dev->parent->of_node); if (IS_ERR(priv->regmap)) return PTR_ERR(priv->regmap); @@ -528,8 +535,12 @@ static int otto_emdio_probe(struct platform_device *pdev) return 0; } +static const struct otto_emdio_info otto_emdio_9300_info = { + .num_buses = RTL9300_NUM_BUSES, +}; + static const struct of_device_id otto_emdio_ids[] = { - { .compatible = "realtek,rtl9301-mdio" }, + { .compatible = "realtek,rtl9301-mdio", .data = &otto_emdio_9300_info }, {} }; MODULE_DEVICE_TABLE(of, otto_emdio_ids); -- cgit v1.2.3 From 215701873a7ed1214bba82c8fadcd2583d0246c3 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Thu, 21 May 2026 19:59:12 +0200 Subject: net: mdio: realtek-rtl9300: Add ports to info structure The ethernet MDIO controller in the Realtek Otto series has a very special command register style. Instead of working with bus/address it works on ethernet port numbers. For this the controller is initialized via mapping registers that tell which port is mapped to which bus/address. Every request to the driver is then converted as follows 1. Kernel calls driver with bus/address 2. Driver converts bus/address to port and issues command 3. Hardware maps port back to bus/address The number of ports is different for each device. Make this configurable by adding a property to the info structure. Switch the existing usage of MAX_PORTS to this new property where needed. Signed-off-by: Markus Stockhausen Link: https://patch.msgid.link/20260521175918.1494797-4-markus.stockhausen@gmx.de Signed-off-by: Paolo Abeni --- drivers/net/mdio/mdio-realtek-rtl9300.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index 931c6684b2f3..941e557bc0e2 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -52,6 +52,7 @@ #include #define RTL9300_NUM_BUSES 4 +#define RTL9300_NUM_PORTS 28 #define SMI_GLB_CTRL 0xca00 #define GLB_CTRL_INTF_SEL(intf) BIT(16 + (intf)) #define SMI_PORT0_15_POLLING_SEL 0xca08 @@ -80,6 +81,7 @@ struct otto_emdio_info { u8 num_buses; + u8 num_ports; }; struct otto_emdio_priv { @@ -106,7 +108,7 @@ static int otto_emdio_phy_to_port(struct mii_bus *bus, int phy_id) priv = chan->priv; - for_each_set_bit(i, priv->valid_ports, MAX_PORTS) + for_each_set_bit(i, priv->valid_ports, priv->info->num_ports) if (priv->smi_bus[i] == chan->mdio_bus && priv->smi_addr[i] == phy_id) return i; @@ -351,7 +353,7 @@ static int otto_emdio_9300_mdiobus_init(struct otto_emdio_priv *priv) int i, err; /* Associate the port with the SMI interface and PHY */ - for_each_set_bit(i, priv->valid_ports, MAX_PORTS) { + for_each_set_bit(i, priv->valid_ports, priv->info->num_ports) { int pos; pos = (i % 6) * 5; @@ -472,7 +474,7 @@ static int otto_emdio_map_ports(struct device *dev) if (err) return err; - if (pn >= MAX_PORTS) + if (pn >= priv->info->num_ports) return dev_err_probe(dev, -EINVAL, "illegal port number %d\n", pn); if (test_bit(pn, priv->valid_ports)) @@ -537,6 +539,7 @@ static int otto_emdio_probe(struct platform_device *pdev) static const struct otto_emdio_info otto_emdio_9300_info = { .num_buses = RTL9300_NUM_BUSES, + .num_ports = RTL9300_NUM_PORTS, }; static const struct of_device_id otto_emdio_ids[] = { -- cgit v1.2.3 From 38c9d5b644049e9e78fafa385d420b2ae8485b81 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Thu, 21 May 2026 19:59:13 +0200 Subject: net: mdio: realtek-rtl9300: Add pages to info structure The Realtek ethernet MDIO controller has a proprietary paging feature that is closely aligned with Realtek based PHYs. These PHY know "pages" for C22 access. Those can be switched via reads/writes to register 31. Usually the paged access must be programmed in four steps. 1. read/save page register 2. change "page" register 31 3. read/write data register (on the given page) 4. restore page register The controller can run all this in hardware with one single request from the driver. It is given the page, the register and the data and takes care of all the rest. This reduces CPU load. The number of supported pages depend on the model. This is either 4096 for low port count SOCs (up to 28 ports) or 8192 for high port count SOCs (up to 56 ports). There is however one special page that allows to pass through all C22 commands directly to the PHY - without any caching. This so called raw page is dependent of the hardware. It is the highest supported page number minus 1. Provide the number of supported pages as a device specific property. This new "num_pages" aligns with the existing properties and gives an better insight into the hardware layout than just defining the number of the raw page. The later directly derives from that and can be accessed with the new RAW_PAGE() macro. Make use of it where needed. Signed-off-by: Markus Stockhausen Link: https://patch.msgid.link/20260521175918.1494797-5-markus.stockhausen@gmx.de Signed-off-by: Paolo Abeni --- drivers/net/mdio/mdio-realtek-rtl9300.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index 941e557bc0e2..94f59a56bc46 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -52,6 +52,7 @@ #include #define RTL9300_NUM_BUSES 4 +#define RTL9300_NUM_PAGES 4096 #define RTL9300_NUM_PORTS 28 #define SMI_GLB_CTRL 0xca00 #define GLB_CTRL_INTF_SEL(intf) BIT(16 + (intf)) @@ -78,10 +79,12 @@ #define MAX_PORTS 28 #define MAX_SMI_BUSSES 4 #define MAX_SMI_ADDR 0x1f +#define RAW_PAGE(priv) ((priv)->info->num_pages - 1) struct otto_emdio_info { u8 num_buses; u8 num_ports; + u16 num_pages; }; struct otto_emdio_priv { @@ -154,7 +157,7 @@ static int otto_emdio_9300_read_c22(struct mii_bus *bus, int phy_id, int regnum) val = FIELD_PREP(PHY_CTRL_REG_ADDR, regnum) | FIELD_PREP(PHY_CTRL_PARK_PAGE, 0x1f) | - FIELD_PREP(PHY_CTRL_MAIN_PAGE, 0xfff) | + FIELD_PREP(PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)) | PHY_CTRL_READ | PHY_CTRL_TYPE_C22 | PHY_CTRL_CMD; err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, val); if (err) @@ -207,7 +210,7 @@ static int otto_emdio_9300_write_c22(struct mii_bus *bus, int phy_id, int regnum val = FIELD_PREP(PHY_CTRL_REG_ADDR, regnum) | FIELD_PREP(PHY_CTRL_PARK_PAGE, 0x1f) | - FIELD_PREP(PHY_CTRL_MAIN_PAGE, 0xfff) | + FIELD_PREP(PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)) | PHY_CTRL_WRITE | PHY_CTRL_TYPE_C22 | PHY_CTRL_CMD; err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, val); if (err) @@ -540,6 +543,7 @@ static int otto_emdio_probe(struct platform_device *pdev) static const struct otto_emdio_info otto_emdio_9300_info = { .num_buses = RTL9300_NUM_BUSES, .num_ports = RTL9300_NUM_PORTS, + .num_pages = RTL9300_NUM_PAGES, }; static const struct of_device_id otto_emdio_ids[] = { -- cgit v1.2.3 From 62baf5f1d80fe4f83099d52ac12e1337dd9fa9fc Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Thu, 21 May 2026 19:59:14 +0200 Subject: net: mdio: realtek-rtl9300: Add register structure The MDIO controller of the Realtek Otto switches has either 4 or 7 command registers. This depends on the number of supported ports. These registers are "scattered" around the MMIO block and their addresses depend on the specific model. Nevertheless all command registers share a common pattern: - A mask register with one bit per addressed port (remark: the driver internally works on ports instead of bus/address) - A I/O data register that transfers the to be read/written data - A C45 registers that takes devnum and regnum - A C22 register that also includes run and status bits (remark: this also takes the Realtek proprietary C22 PHY page) Provide an additional structure for these command registers so it can be reused in two places. 1. For defining the register addresses in the regmap. 2. For defining the to be read/written register data This will finally result in access patterns like static int otto_emdio_run_cmd(u32 cmd, struct rtl_mdio_cmd_regs *cmd_regs, ...) { regmap_write(regmap, priv->info->reg->cmd_regs.c45_data, cmd_regs->c45_data); ... } static int otto_emdio_9300_write_c45(...) { struct otto_emdio_cmd_regs cmd_regs = { .c45_data = ... .io_data = ..., .port_mask = ..., }; return otto_emdio_run_cmd(RTL9300_CMD_WRITE_C45, &cmd_regs, ...); } As a first step start with the C45 register. This one takes the devnum/regnum data that is stored in the high/low 16 bits. Signed-off-by: Markus Stockhausen Link: https://patch.msgid.link/20260521175918.1494797-6-markus.stockhausen@gmx.de Signed-off-by: Paolo Abeni --- drivers/net/mdio/mdio-realtek-rtl9300.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index 94f59a56bc46..c992f09835f9 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -71,7 +71,7 @@ #define SMI_ACCESS_PHY_CTRL_2 0xcb78 #define PHY_CTRL_INDATA GENMASK(31, 16) #define PHY_CTRL_DATA GENMASK(15, 0) -#define SMI_ACCESS_PHY_CTRL_3 0xcb7c +#define RTL9300_SMI_ACCESS_PHY_CTRL_3 0xcb7c #define PHY_CTRL_MMD_DEVAD GENMASK(20, 16) #define PHY_CTRL_MMD_REG GENMASK(15, 0) #define SMI_PORT0_5_ADDR_CTRL 0xcb80 @@ -81,7 +81,13 @@ #define MAX_SMI_ADDR 0x1f #define RAW_PAGE(priv) ((priv)->info->num_pages - 1) + +struct otto_emdio_cmd_regs { + u32 c45_data; +}; + struct otto_emdio_info { + struct otto_emdio_cmd_regs cmd_regs; u8 num_buses; u8 num_ports; u16 num_pages; @@ -262,7 +268,7 @@ static int otto_emdio_9300_read_c45(struct mii_bus *bus, int phy_id, int dev_add val = FIELD_PREP(PHY_CTRL_MMD_DEVAD, dev_addr) | FIELD_PREP(PHY_CTRL_MMD_REG, regnum); - err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_3, val); + err = regmap_write(regmap, priv->info->cmd_regs.c45_data, val); if (err) goto out_err; @@ -320,7 +326,7 @@ static int otto_emdio_9300_write_c45(struct mii_bus *bus, int phy_id, int dev_ad val = FIELD_PREP(PHY_CTRL_MMD_DEVAD, dev_addr) | FIELD_PREP(PHY_CTRL_MMD_REG, regnum); - err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_3, val); + err = regmap_write(regmap, priv->info->cmd_regs.c45_data, val); if (err) goto out_err; @@ -541,6 +547,9 @@ static int otto_emdio_probe(struct platform_device *pdev) } static const struct otto_emdio_info otto_emdio_9300_info = { + .cmd_regs = { + .c45_data = RTL9300_SMI_ACCESS_PHY_CTRL_3, + }, .num_buses = RTL9300_NUM_BUSES, .num_ports = RTL9300_NUM_PORTS, .num_pages = RTL9300_NUM_PAGES, -- cgit v1.2.3 From 8bf7e2b133db0ec690268a0afb0ee9471f4fbb52 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Thu, 21 May 2026 19:59:15 +0200 Subject: net: mdio: realtek-rtl9300: Add command/C22 register Command issuing/status bits and C22 data share the same register. In the future the number of places where this register is used will be: - One generic command helper/runner for all devices that will access the command bits of the register - 8 device specific C22 read/write functions that will access the C22 data fields. Thus name the register c22_data to align with the existing c45_data register. This way all device specific helpers will have a common view on the to-be-fed data. Add the register to the existing structure and make use of it where needed. Signed-off-by: Markus Stockhausen Link: https://patch.msgid.link/20260521175918.1494797-7-markus.stockhausen@gmx.de Signed-off-by: Paolo Abeni --- drivers/net/mdio/mdio-realtek-rtl9300.c | 38 +++++++++++++++++---------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index c992f09835f9..d294bfaed887 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -58,7 +58,7 @@ #define GLB_CTRL_INTF_SEL(intf) BIT(16 + (intf)) #define SMI_PORT0_15_POLLING_SEL 0xca08 #define SMI_ACCESS_PHY_CTRL_0 0xcb70 -#define SMI_ACCESS_PHY_CTRL_1 0xcb74 +#define RTL9300_SMI_ACCESS_PHY_CTRL_1 0xcb74 #define PHY_CTRL_REG_ADDR GENMASK(24, 20) #define PHY_CTRL_PARK_PAGE GENMASK(19, 15) #define PHY_CTRL_MAIN_PAGE GENMASK(14, 3) @@ -83,6 +83,7 @@ struct otto_emdio_cmd_regs { + u32 c22_data; u32 c45_data; }; @@ -128,12 +129,12 @@ static int otto_emdio_phy_to_port(struct mii_bus *bus, int phy_id) static int otto_emdio_wait_ready(struct otto_emdio_priv *priv) { struct regmap *regmap = priv->regmap; - u32 val; + u32 cmd_reg, val; lockdep_assert_held(&priv->lock); + cmd_reg = priv->info->cmd_regs.c22_data; /* shared command/C22 register */ - return regmap_read_poll_timeout(regmap, SMI_ACCESS_PHY_CTRL_1, - val, !(val & PHY_CTRL_CMD), 10, 1000); + return regmap_read_poll_timeout(regmap, cmd_reg, val, !(val & PHY_CTRL_CMD), 10, 1000); } static int otto_emdio_9300_read_c22(struct mii_bus *bus, int phy_id, int regnum) @@ -141,12 +142,13 @@ static int otto_emdio_9300_read_c22(struct mii_bus *bus, int phy_id, int regnum) struct otto_emdio_chan *chan = bus->priv; struct otto_emdio_priv *priv; struct regmap *regmap; + u32 cmd_reg, val; int port; - u32 val; int err; priv = chan->priv; regmap = priv->regmap; + cmd_reg = priv->info->cmd_regs.c22_data; /* shared command/C22 register */ port = otto_emdio_phy_to_port(bus, phy_id); if (port < 0) @@ -165,7 +167,7 @@ static int otto_emdio_9300_read_c22(struct mii_bus *bus, int phy_id, int regnum) FIELD_PREP(PHY_CTRL_PARK_PAGE, 0x1f) | FIELD_PREP(PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)) | PHY_CTRL_READ | PHY_CTRL_TYPE_C22 | PHY_CTRL_CMD; - err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, val); + err = regmap_write(regmap, cmd_reg, val); if (err) goto out_err; @@ -190,12 +192,13 @@ static int otto_emdio_9300_write_c22(struct mii_bus *bus, int phy_id, int regnum struct otto_emdio_chan *chan = bus->priv; struct otto_emdio_priv *priv; struct regmap *regmap; + u32 cmd_reg, val; int port; - u32 val; int err; priv = chan->priv; regmap = priv->regmap; + cmd_reg = priv->info->cmd_regs.c22_data; /* shared command/C22 register */ port = otto_emdio_phy_to_port(bus, phy_id); if (port < 0) @@ -218,12 +221,11 @@ static int otto_emdio_9300_write_c22(struct mii_bus *bus, int phy_id, int regnum FIELD_PREP(PHY_CTRL_PARK_PAGE, 0x1f) | FIELD_PREP(PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)) | PHY_CTRL_WRITE | PHY_CTRL_TYPE_C22 | PHY_CTRL_CMD; - err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, val); + err = regmap_write(regmap, cmd_reg, val); if (err) goto out_err; - err = regmap_read_poll_timeout(regmap, SMI_ACCESS_PHY_CTRL_1, - val, !(val & PHY_CTRL_CMD), 10, 100); + err = regmap_read_poll_timeout(regmap, cmd_reg, val, !(val & PHY_CTRL_CMD), 10, 100); if (err) goto out_err; @@ -245,12 +247,13 @@ static int otto_emdio_9300_read_c45(struct mii_bus *bus, int phy_id, int dev_add struct otto_emdio_chan *chan = bus->priv; struct otto_emdio_priv *priv; struct regmap *regmap; + u32 cmd_reg, val; int port; - u32 val; int err; priv = chan->priv; regmap = priv->regmap; + cmd_reg = priv->info->cmd_regs.c22_data; /* shared command/C22 register */ port = otto_emdio_phy_to_port(bus, phy_id); if (port < 0) @@ -272,8 +275,7 @@ static int otto_emdio_9300_read_c45(struct mii_bus *bus, int phy_id, int dev_add if (err) goto out_err; - err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, - PHY_CTRL_READ | PHY_CTRL_TYPE_C45 | PHY_CTRL_CMD); + err = regmap_write(regmap, cmd_reg, PHY_CTRL_READ | PHY_CTRL_TYPE_C45 | PHY_CTRL_CMD); if (err) goto out_err; @@ -299,12 +301,13 @@ static int otto_emdio_9300_write_c45(struct mii_bus *bus, int phy_id, int dev_ad struct otto_emdio_chan *chan = bus->priv; struct otto_emdio_priv *priv; struct regmap *regmap; + u32 cmd_reg, val; int port; - u32 val; int err; priv = chan->priv; regmap = priv->regmap; + cmd_reg = priv->info->cmd_regs.c22_data; /* shared command/C22 register */ port = otto_emdio_phy_to_port(bus, phy_id); if (port < 0) @@ -330,13 +333,11 @@ static int otto_emdio_9300_write_c45(struct mii_bus *bus, int phy_id, int dev_ad if (err) goto out_err; - err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_1, - PHY_CTRL_TYPE_C45 | PHY_CTRL_WRITE | PHY_CTRL_CMD); + err = regmap_write(regmap, cmd_reg, PHY_CTRL_TYPE_C45 | PHY_CTRL_WRITE | PHY_CTRL_CMD); if (err) goto out_err; - err = regmap_read_poll_timeout(regmap, SMI_ACCESS_PHY_CTRL_1, - val, !(val & PHY_CTRL_CMD), 10, 100); + err = regmap_read_poll_timeout(regmap, cmd_reg, val, !(val & PHY_CTRL_CMD), 10, 100); if (err) goto out_err; @@ -548,6 +549,7 @@ static int otto_emdio_probe(struct platform_device *pdev) static const struct otto_emdio_info otto_emdio_9300_info = { .cmd_regs = { + .c22_data = RTL9300_SMI_ACCESS_PHY_CTRL_1, .c45_data = RTL9300_SMI_ACCESS_PHY_CTRL_3, }, .num_buses = RTL9300_NUM_BUSES, -- cgit v1.2.3 From ffc92cd009145eb5f85d913fbbc67fd24b601080 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Thu, 21 May 2026 19:59:16 +0200 Subject: net: mdio: realtek-rtl9300: Add I/O register The MDIO data that needs to be written or read to registers of the controller is handled by an I/O register. Add that to the register structure and make use of it where needed. Signed-off-by: Markus Stockhausen Link: https://patch.msgid.link/20260521175918.1494797-8-markus.stockhausen@gmx.de Signed-off-by: Paolo Abeni --- drivers/net/mdio/mdio-realtek-rtl9300.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index d294bfaed887..d379b6171e30 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -68,7 +68,7 @@ #define PHY_CTRL_TYPE_C22 0 #define PHY_CTRL_CMD BIT(0) #define PHY_CTRL_FAIL BIT(25) -#define SMI_ACCESS_PHY_CTRL_2 0xcb78 +#define RTL9300_SMI_ACCESS_PHY_CTRL_2 0xcb78 #define PHY_CTRL_INDATA GENMASK(31, 16) #define PHY_CTRL_DATA GENMASK(15, 0) #define RTL9300_SMI_ACCESS_PHY_CTRL_3 0xcb7c @@ -85,6 +85,7 @@ struct otto_emdio_cmd_regs { u32 c22_data; u32 c45_data; + u32 io_data; }; struct otto_emdio_info { @@ -141,13 +142,14 @@ static int otto_emdio_9300_read_c22(struct mii_bus *bus, int phy_id, int regnum) { struct otto_emdio_chan *chan = bus->priv; struct otto_emdio_priv *priv; + u32 io_reg, cmd_reg, val; struct regmap *regmap; - u32 cmd_reg, val; int port; int err; priv = chan->priv; regmap = priv->regmap; + io_reg = priv->info->cmd_regs.io_data; cmd_reg = priv->info->cmd_regs.c22_data; /* shared command/C22 register */ port = otto_emdio_phy_to_port(bus, phy_id); @@ -159,7 +161,7 @@ static int otto_emdio_9300_read_c22(struct mii_bus *bus, int phy_id, int regnum) if (err) goto out_err; - err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, FIELD_PREP(PHY_CTRL_INDATA, port)); + err = regmap_write(regmap, io_reg, FIELD_PREP(PHY_CTRL_INDATA, port)); if (err) goto out_err; @@ -175,7 +177,7 @@ static int otto_emdio_9300_read_c22(struct mii_bus *bus, int phy_id, int regnum) if (err) goto out_err; - err = regmap_read(regmap, SMI_ACCESS_PHY_CTRL_2, &val); + err = regmap_read(regmap, io_reg, &val); if (err) goto out_err; @@ -191,13 +193,14 @@ static int otto_emdio_9300_write_c22(struct mii_bus *bus, int phy_id, int regnum { struct otto_emdio_chan *chan = bus->priv; struct otto_emdio_priv *priv; + u32 io_reg, cmd_reg, val; struct regmap *regmap; - u32 cmd_reg, val; int port; int err; priv = chan->priv; regmap = priv->regmap; + io_reg = priv->info->cmd_regs.io_data; cmd_reg = priv->info->cmd_regs.c22_data; /* shared command/C22 register */ port = otto_emdio_phy_to_port(bus, phy_id); @@ -213,7 +216,7 @@ static int otto_emdio_9300_write_c22(struct mii_bus *bus, int phy_id, int regnum if (err) goto out_err; - err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, FIELD_PREP(PHY_CTRL_INDATA, value)); + err = regmap_write(regmap, io_reg, FIELD_PREP(PHY_CTRL_INDATA, value)); if (err) goto out_err; @@ -246,13 +249,14 @@ static int otto_emdio_9300_read_c45(struct mii_bus *bus, int phy_id, int dev_add { struct otto_emdio_chan *chan = bus->priv; struct otto_emdio_priv *priv; + u32 io_reg, cmd_reg, val; struct regmap *regmap; - u32 cmd_reg, val; int port; int err; priv = chan->priv; regmap = priv->regmap; + io_reg = priv->info->cmd_regs.io_data; cmd_reg = priv->info->cmd_regs.c22_data; /* shared command/C22 register */ port = otto_emdio_phy_to_port(bus, phy_id); @@ -265,7 +269,7 @@ static int otto_emdio_9300_read_c45(struct mii_bus *bus, int phy_id, int dev_add goto out_err; val = FIELD_PREP(PHY_CTRL_INDATA, port); - err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, val); + err = regmap_write(regmap, io_reg, val); if (err) goto out_err; @@ -283,7 +287,7 @@ static int otto_emdio_9300_read_c45(struct mii_bus *bus, int phy_id, int dev_add if (err) goto out_err; - err = regmap_read(regmap, SMI_ACCESS_PHY_CTRL_2, &val); + err = regmap_read(regmap, io_reg, &val); if (err) goto out_err; @@ -300,13 +304,14 @@ static int otto_emdio_9300_write_c45(struct mii_bus *bus, int phy_id, int dev_ad { struct otto_emdio_chan *chan = bus->priv; struct otto_emdio_priv *priv; + u32 io_reg, cmd_reg, val; struct regmap *regmap; - u32 cmd_reg, val; int port; int err; priv = chan->priv; regmap = priv->regmap; + io_reg = priv->info->cmd_regs.io_data; cmd_reg = priv->info->cmd_regs.c22_data; /* shared command/C22 register */ port = otto_emdio_phy_to_port(bus, phy_id); @@ -323,7 +328,7 @@ static int otto_emdio_9300_write_c45(struct mii_bus *bus, int phy_id, int dev_ad goto out_err; val = FIELD_PREP(PHY_CTRL_INDATA, value); - err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_2, val); + err = regmap_write(regmap, io_reg, val); if (err) goto out_err; @@ -551,6 +556,7 @@ static const struct otto_emdio_info otto_emdio_9300_info = { .cmd_regs = { .c22_data = RTL9300_SMI_ACCESS_PHY_CTRL_1, .c45_data = RTL9300_SMI_ACCESS_PHY_CTRL_3, + .io_data = RTL9300_SMI_ACCESS_PHY_CTRL_2, }, .num_buses = RTL9300_NUM_BUSES, .num_ports = RTL9300_NUM_PORTS, -- cgit v1.2.3 From cad6a373f7f69254cb57e76e06f7734777575555 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Thu, 21 May 2026 19:59:17 +0200 Subject: net: mdio: realtek-rtl9300: Add port mask register MDIO controller commands work on ports. These are converted by the driver and hardware forth and back to bus/address. For write commands a port mask register needs to be filled. Each bit tells the controller to which PHY the write will be issued. Setting multiple bits allows to program multiple PHYs in one step. The driver will not make use of this parallel write feature. But it must at least fill the bit of the target port that it wants to write to. Depending on the SOC type and the number of supported PHYs this is either one or two 32 bit port mask registers. The driver currently only supports the 28 port RTL930x SOCs. So provide only the mask register for the lower 32 ports. Add it to the register structure and make use of it where needed. Signed-off-by: Markus Stockhausen Link: https://patch.msgid.link/20260521175918.1494797-9-markus.stockhausen@gmx.de Signed-off-by: Paolo Abeni --- drivers/net/mdio/mdio-realtek-rtl9300.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index d379b6171e30..8130e376b59b 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -57,7 +57,7 @@ #define SMI_GLB_CTRL 0xca00 #define GLB_CTRL_INTF_SEL(intf) BIT(16 + (intf)) #define SMI_PORT0_15_POLLING_SEL 0xca08 -#define SMI_ACCESS_PHY_CTRL_0 0xcb70 +#define RTL9300_SMI_ACCESS_PHY_CTRL_0 0xcb70 #define RTL9300_SMI_ACCESS_PHY_CTRL_1 0xcb74 #define PHY_CTRL_REG_ADDR GENMASK(24, 20) #define PHY_CTRL_PARK_PAGE GENMASK(19, 15) @@ -86,6 +86,7 @@ struct otto_emdio_cmd_regs { u32 c22_data; u32 c45_data; u32 io_data; + u32 port_mask_low; }; struct otto_emdio_info { @@ -212,7 +213,7 @@ static int otto_emdio_9300_write_c22(struct mii_bus *bus, int phy_id, int regnum if (err) goto out_err; - err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_0, BIT(port)); + err = regmap_write(regmap, priv->info->cmd_regs.port_mask_low, BIT(port)); if (err) goto out_err; @@ -323,7 +324,7 @@ static int otto_emdio_9300_write_c45(struct mii_bus *bus, int phy_id, int dev_ad if (err) goto out_err; - err = regmap_write(regmap, SMI_ACCESS_PHY_CTRL_0, BIT(port)); + err = regmap_write(regmap, priv->info->cmd_regs.port_mask_low, BIT(port)); if (err) goto out_err; @@ -557,6 +558,7 @@ static const struct otto_emdio_info otto_emdio_9300_info = { .c22_data = RTL9300_SMI_ACCESS_PHY_CTRL_1, .c45_data = RTL9300_SMI_ACCESS_PHY_CTRL_3, .io_data = RTL9300_SMI_ACCESS_PHY_CTRL_2, + .port_mask_low = RTL9300_SMI_ACCESS_PHY_CTRL_0, }, .num_buses = RTL9300_NUM_BUSES, .num_ports = RTL9300_NUM_PORTS, -- cgit v1.2.3 From 826a1926f084037b91415a53a29ce93264f08ada Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Thu, 21 May 2026 19:59:18 +0200 Subject: net: mdio: realtek-rtl9300: Link I/O functions in info structure The MDIO controller registers of the different devices of the Realtek Otto switch series are very similar. Nevertheless each device will need to feed the whole command data distributed over the controller registers slightly different. E.g. the combined C22/command register has different field layouts. On RTL930x bits 24-20 define the to-be-accessed C22 register number while on RTL839x this is stored in bits 9-5. Thus there need to be device specific read/write functions that are called dynamically. Add them into the info structure and make use of them where needed. Signed-off-by: Markus Stockhausen Link: https://patch.msgid.link/20260521175918.1494797-10-markus.stockhausen@gmx.de Signed-off-by: Paolo Abeni --- drivers/net/mdio/mdio-realtek-rtl9300.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index 8130e376b59b..65c59b8457d4 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -94,6 +94,10 @@ struct otto_emdio_info { u8 num_buses; u8 num_ports; u16 num_pages; + int (*read_c22)(struct mii_bus *bus, int phy_id, int regnum); + int (*read_c45)(struct mii_bus *bus, int phy_id, int dev_addr, int regnum); + int (*write_c22)(struct mii_bus *bus, int phy_id, int regnum, u16 value); + int (*write_c45)(struct mii_bus *bus, int phy_id, int dev_addr, int regnum, u16 value); }; struct otto_emdio_priv { @@ -433,11 +437,11 @@ static int otto_emdio_probe_one(struct device *dev, struct otto_emdio_priv *priv bus->name = "Realtek Switch MDIO Bus"; if (priv->smi_bus_is_c45[mdio_bus]) { - bus->read_c45 = otto_emdio_9300_read_c45; - bus->write_c45 = otto_emdio_9300_write_c45; + bus->read_c45 = priv->info->read_c45; + bus->write_c45 = priv->info->write_c45; } else { - bus->read = otto_emdio_9300_read_c22; - bus->write = otto_emdio_9300_write_c22; + bus->read = priv->info->read_c22; + bus->write = priv->info->write_c22; } bus->parent = dev; chan = bus->priv; @@ -563,6 +567,10 @@ static const struct otto_emdio_info otto_emdio_9300_info = { .num_buses = RTL9300_NUM_BUSES, .num_ports = RTL9300_NUM_PORTS, .num_pages = RTL9300_NUM_PAGES, + .read_c22 = otto_emdio_9300_read_c22, + .read_c45 = otto_emdio_9300_read_c45, + .write_c22 = otto_emdio_9300_write_c22, + .write_c45 = otto_emdio_9300_write_c45, }; static const struct of_device_id otto_emdio_ids[] = { -- cgit v1.2.3