mirror of
https://github.com/openwrt/openwrt.git
synced 2026-10-19 15:55:05 +04:00
realtek: mdio: backport upstream patches
This backports the upstream efforts for the mdio driver. No downstream functionality is affected as OpenWrt still uses the mdio-realtek-otto driver. Link: https://github.com/openwrt/openwrt/pull/23678 Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
This commit is contained in:
1 parent
1ba7b38cfc
commit
32bcc2986c
20 files changed
+2628
No files matched your search
+381
@@ -0,0 +1,381 @@
|
||||
From d15c0d1df49480b8f7d7c6182880e353574c871d Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Thu, 21 May 2026 19:59:10 +0200
|
||||
Subject: [PATCH 01/20] 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 <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260521175918.1494797-2-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 139 ++++++++++++++----------
|
||||
1 file changed, 84 insertions(+), 55 deletions(-)
|
||||
|
||||
--- 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 <linux/bitfield.h>
|
||||
@@ -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(stru
|
||||
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(struc
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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 r
|
||||
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(str
|
||||
|
||||
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(str
|
||||
* 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(str
|
||||
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_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");
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
From 315a02b39e8c4d1e8aebc8c3cc1e14e193f116ae Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Thu, 21 May 2026 19:59:11 +0200
|
||||
Subject: [PATCH 02/20] 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 <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260521175918.1494797-3-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 17 ++++++++++++++---
|
||||
1 file changed, 14 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -51,6 +51,7 @@
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
+#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(
|
||||
|
||||
/* 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 d
|
||||
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 platf
|
||||
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 platf
|
||||
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);
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
From 215701873a7ed1214bba82c8fadcd2583d0246c3 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Thu, 21 May 2026 19:59:12 +0200
|
||||
Subject: [PATCH 03/20] 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 <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260521175918.1494797-4-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -52,6 +52,7 @@
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#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
|
||||
|
||||
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(
|
||||
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 d
|
||||
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 platf
|
||||
|
||||
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[] = {
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
From 38c9d5b644049e9e78fafa385d420b2ae8485b81 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Thu, 21 May 2026 19:59:13 +0200
|
||||
Subject: [PATCH 04/20] 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 <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260521175918.1494797-5-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 8 ++++++--
|
||||
1 file changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -52,6 +52,7 @@
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#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(stru
|
||||
|
||||
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(str
|
||||
|
||||
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 platf
|
||||
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[] = {
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
From 62baf5f1d80fe4f83099d52ac12e1337dd9fa9fc Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Thu, 21 May 2026 19:59:14 +0200
|
||||
Subject: [PATCH 05/20] 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 <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260521175918.1494797-6-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 15 ++++++++++++---
|
||||
1 file changed, 12 insertions(+), 3 deletions(-)
|
||||
|
||||
--- 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(stru
|
||||
|
||||
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(str
|
||||
|
||||
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 platf
|
||||
}
|
||||
|
||||
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,
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
From 8bf7e2b133db0ec690268a0afb0ee9471f4fbb52 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Thu, 21 May 2026 19:59:15 +0200
|
||||
Subject: [PATCH 06/20] 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 <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260521175918.1494797-7-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 38 +++++++++++++------------
|
||||
1 file changed, 20 insertions(+), 18 deletions(-)
|
||||
|
||||
--- 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
|
||||
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(stru
|
||||
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(stru
|
||||
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(str
|
||||
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(str
|
||||
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(stru
|
||||
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(stru
|
||||
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(str
|
||||
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(str
|
||||
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 platf
|
||||
|
||||
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,
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
From ffc92cd009145eb5f85d913fbbc67fd24b601080 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Thu, 21 May 2026 19:59:16 +0200
|
||||
Subject: [PATCH 07/20] 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 <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260521175918.1494797-8-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 28 +++++++++++++++----------
|
||||
1 file changed, 17 insertions(+), 11 deletions(-)
|
||||
|
||||
--- 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(stru
|
||||
{
|
||||
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(stru
|
||||
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(stru
|
||||
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(str
|
||||
{
|
||||
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(str
|
||||
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(stru
|
||||
{
|
||||
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(stru
|
||||
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(stru
|
||||
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(str
|
||||
{
|
||||
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(str
|
||||
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
|
||||
.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,
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
From cad6a373f7f69254cb57e76e06f7734777575555 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Thu, 21 May 2026 19:59:17 +0200
|
||||
Subject: [PATCH 08/20] 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 <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260521175918.1494797-9-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 8 +++++---
|
||||
1 file changed, 5 insertions(+), 3 deletions(-)
|
||||
|
||||
--- 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(str
|
||||
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(str
|
||||
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
|
||||
.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,
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
From 826a1926f084037b91415a53a29ce93264f08ada Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Thu, 21 May 2026 19:59:18 +0200
|
||||
Subject: [PATCH 09/20] 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 <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260521175918.1494797-10-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 16 ++++++++++++----
|
||||
1 file changed, 12 insertions(+), 4 deletions(-)
|
||||
|
||||
--- 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 d
|
||||
|
||||
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
|
||||
.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[] = {
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
From 9ccb438210c4838962dfa1a10d4c198391dcc284 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Wed, 27 May 2026 18:34:46 +0200
|
||||
Subject: [PATCH 10/20] net: mdio: realtek-rtl9300: provide generic command
|
||||
runner
|
||||
|
||||
The current bus read/write commands for C22/C45 are RTL930x specific.
|
||||
Avoid to duplicate those 200 lines of code for the RTL838x, RTL839x and
|
||||
RTL931x targets. Instead provide a generic command runner that is SoC
|
||||
independent. The implementation works as follows:
|
||||
|
||||
The runner will take a prepared list of the four MDIO registers. It will
|
||||
feed the data into the registers. This generic write to all registers
|
||||
(or to say "a little bit too much") is no issue. The hardware looks at
|
||||
the to be executed command and will only take the pieces of data that
|
||||
are really required. No side effects have been observed on any of the
|
||||
four SoCs during the time this mechanism exists in downstream OpenWrt.
|
||||
|
||||
The last fed register is the C22/command register. This will be enriched
|
||||
with the proper command flags from the caller. The hardware issues the
|
||||
command and the runner will wait for its finalization.
|
||||
|
||||
Besides from feeding all registers the runner emulates the behaviour of
|
||||
the old code as best as possible
|
||||
|
||||
- check defensively for a running command in advance
|
||||
- Before this commit the driver had different MMIO timeout values.
|
||||
1000s for command preparation, 100us after writes and 1000us after
|
||||
reads. The new version uses a consistent 1000us timeout for all
|
||||
of these.
|
||||
- return -ENXIO in case of hardware failure (fail bit)
|
||||
|
||||
As a first consumer of this runner convert the write_c45() function.
|
||||
This is realized in a multi stage approach
|
||||
|
||||
- a generic otto_emdio_write_c45() will be called by the bus
|
||||
- this will forward the request to the device specific writer. In this
|
||||
case otto_emdio_9300_write_c45().
|
||||
- There the command data is filled in and the additional helper
|
||||
otto_emdio_write_cmd() will be called
|
||||
- That adds the write flag and issues the generic command runner.
|
||||
|
||||
With all the above mentioned in place, there is not much left to do in
|
||||
otto_emdio_9300_write_c45(). It just fills the register fields and
|
||||
calls the write helper with the right command bits.
|
||||
|
||||
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Link: https://patch.msgid.link/20260527163449.1294961-2-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 135 +++++++++++++++---------
|
||||
1 file changed, 83 insertions(+), 52 deletions(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -90,6 +90,8 @@ struct otto_emdio_cmd_regs {
|
||||
};
|
||||
|
||||
struct otto_emdio_info {
|
||||
+ u32 cmd_fail;
|
||||
+ u32 cmd_write;
|
||||
struct otto_emdio_cmd_regs cmd_regs;
|
||||
u8 num_buses;
|
||||
u8 num_ports;
|
||||
@@ -97,7 +99,7 @@ struct otto_emdio_info {
|
||||
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);
|
||||
+ int (*write_c45)(struct mii_bus *bus, int port, int dev_addr, int regnum, u16 value);
|
||||
};
|
||||
|
||||
struct otto_emdio_priv {
|
||||
@@ -132,6 +134,64 @@ static int otto_emdio_phy_to_port(struct
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
+static struct otto_emdio_priv *otto_emdio_bus_to_priv(struct mii_bus *bus)
|
||||
+{
|
||||
+ struct otto_emdio_chan *chan = bus->priv;
|
||||
+
|
||||
+ return chan->priv;
|
||||
+}
|
||||
+
|
||||
+static int otto_emdio_run_cmd(struct mii_bus *bus, u32 cmd,
|
||||
+ struct otto_emdio_cmd_regs *cmd_data)
|
||||
+{
|
||||
+ struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
|
||||
+ const struct otto_emdio_info *info = priv->info;
|
||||
+ u32 cmdstate;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Defensive pre check just in case something goes horrible wrong */
|
||||
+ ret = regmap_read_poll_timeout(priv->regmap, info->cmd_regs.c22_data,
|
||||
+ cmdstate, !(cmdstate & PHY_CTRL_CMD), 10, 1000);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Fill all registers. Hardware will read only the needed bits depending on command */
|
||||
+ ret = regmap_write(priv->regmap, info->cmd_regs.port_mask_low, cmd_data->port_mask_low);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = regmap_write(priv->regmap, info->cmd_regs.io_data, cmd_data->io_data);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = regmap_write(priv->regmap, info->cmd_regs.c45_data, cmd_data->c45_data);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* C22 data and command bits share the same register. */
|
||||
+ ret = regmap_write(priv->regmap, info->cmd_regs.c22_data,
|
||||
+ cmd_data->c22_data | cmd | PHY_CTRL_CMD);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = regmap_read_poll_timeout(priv->regmap, info->cmd_regs.c22_data,
|
||||
+ cmdstate, !(cmdstate & PHY_CTRL_CMD), 10, 1000);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return cmdstate & info->cmd_fail ? -ENXIO : 0;
|
||||
+}
|
||||
+
|
||||
+static int otto_emdio_write_cmd(struct mii_bus *bus, u32 cmd,
|
||||
+ struct otto_emdio_cmd_regs *cmd_data)
|
||||
+{
|
||||
+ struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
|
||||
+
|
||||
+ lockdep_assert_held(&priv->lock);
|
||||
+
|
||||
+ return otto_emdio_run_cmd(bus, cmd | priv->info->cmd_write, cmd_data);
|
||||
+}
|
||||
+
|
||||
static int otto_emdio_wait_ready(struct otto_emdio_priv *priv)
|
||||
{
|
||||
struct regmap *regmap = priv->regmap;
|
||||
@@ -304,64 +364,33 @@ out_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
-static int otto_emdio_9300_write_c45(struct mii_bus *bus, int phy_id, int dev_addr,
|
||||
- int regnum, u16 value)
|
||||
+static int otto_emdio_9300_write_c45(struct mii_bus *bus, int port,
|
||||
+ int dev_addr, int regnum, u16 value)
|
||||
{
|
||||
- struct otto_emdio_chan *chan = bus->priv;
|
||||
- struct otto_emdio_priv *priv;
|
||||
- u32 io_reg, cmd_reg, val;
|
||||
- struct regmap *regmap;
|
||||
- int port;
|
||||
- int err;
|
||||
+ struct otto_emdio_cmd_regs cmd_data = {
|
||||
+ .c45_data = FIELD_PREP(PHY_CTRL_MMD_DEVAD, dev_addr) |
|
||||
+ FIELD_PREP(PHY_CTRL_MMD_REG, regnum),
|
||||
+ .io_data = FIELD_PREP(PHY_CTRL_INDATA, value),
|
||||
+ .port_mask_low = BIT(port),
|
||||
+ };
|
||||
|
||||
- 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 */
|
||||
+ return otto_emdio_write_cmd(bus, PHY_CTRL_TYPE_C45, &cmd_data);
|
||||
+}
|
||||
+
|
||||
+static int otto_emdio_write_c45(struct mii_bus *bus, int phy_id,
|
||||
+ int dev_addr, int regnum, u16 value)
|
||||
+{
|
||||
+ struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
|
||||
+ int ret, port;
|
||||
|
||||
port = otto_emdio_phy_to_port(bus, phy_id);
|
||||
if (port < 0)
|
||||
return port;
|
||||
|
||||
- mutex_lock(&priv->lock);
|
||||
- err = otto_emdio_wait_ready(priv);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- err = regmap_write(regmap, priv->info->cmd_regs.port_mask_low, BIT(port));
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- val = FIELD_PREP(PHY_CTRL_INDATA, value);
|
||||
- err = regmap_write(regmap, io_reg, val);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- val = FIELD_PREP(PHY_CTRL_MMD_DEVAD, dev_addr) |
|
||||
- FIELD_PREP(PHY_CTRL_MMD_REG, regnum);
|
||||
- err = regmap_write(regmap, priv->info->cmd_regs.c45_data, val);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- 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, cmd_reg, val, !(val & PHY_CTRL_CMD), 10, 100);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- if (val & PHY_CTRL_FAIL) {
|
||||
- err = -ENXIO;
|
||||
- goto out_err;
|
||||
- }
|
||||
-
|
||||
- mutex_unlock(&priv->lock);
|
||||
- return 0;
|
||||
+ scoped_guard(mutex, &priv->lock)
|
||||
+ ret = priv->info->write_c45(bus, port, dev_addr, regnum, value);
|
||||
|
||||
-out_err:
|
||||
- mutex_unlock(&priv->lock);
|
||||
- return err;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static int otto_emdio_9300_mdiobus_init(struct otto_emdio_priv *priv)
|
||||
@@ -438,7 +467,7 @@ static int otto_emdio_probe_one(struct d
|
||||
bus->name = "Realtek Switch MDIO Bus";
|
||||
if (priv->smi_bus_is_c45[mdio_bus]) {
|
||||
bus->read_c45 = priv->info->read_c45;
|
||||
- bus->write_c45 = priv->info->write_c45;
|
||||
+ bus->write_c45 = otto_emdio_write_c45;
|
||||
} else {
|
||||
bus->read = priv->info->read_c22;
|
||||
bus->write = priv->info->write_c22;
|
||||
@@ -558,6 +587,8 @@ static int otto_emdio_probe(struct platf
|
||||
}
|
||||
|
||||
static const struct otto_emdio_info otto_emdio_9300_info = {
|
||||
+ .cmd_fail = PHY_CTRL_FAIL,
|
||||
+ .cmd_write = PHY_CTRL_WRITE,
|
||||
.cmd_regs = {
|
||||
.c22_data = RTL9300_SMI_ACCESS_PHY_CTRL_1,
|
||||
.c45_data = RTL9300_SMI_ACCESS_PHY_CTRL_3,
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
From 9cd59932f2d2a09ef239228671020dfd1ae7f4af Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Wed, 27 May 2026 18:34:47 +0200
|
||||
Subject: [PATCH 11/20] net: mdio: realtek-rtl9300: use command runner for
|
||||
write_c22()
|
||||
|
||||
Now that the driver has a generic command runner make use of it in the
|
||||
write_c22() path. For this.
|
||||
|
||||
- add generic otto_emdio_write_c22() helper that will be called by bus
|
||||
- convert otto_emdio_9300_write_c22() to new command runner logic
|
||||
|
||||
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Link: https://patch.msgid.link/20260527163449.1294961-3-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 81 +++++++++----------------
|
||||
1 file changed, 27 insertions(+), 54 deletions(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -98,7 +98,7 @@ struct otto_emdio_info {
|
||||
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_c22)(struct mii_bus *bus, int port, int regnum, u16 value);
|
||||
int (*write_c45)(struct mii_bus *bus, int port, int dev_addr, int regnum, u16 value);
|
||||
};
|
||||
|
||||
@@ -254,60 +254,18 @@ out_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
-static int otto_emdio_9300_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 port, int regnum, u16 value)
|
||||
{
|
||||
- struct otto_emdio_chan *chan = bus->priv;
|
||||
- struct otto_emdio_priv *priv;
|
||||
- u32 io_reg, cmd_reg, val;
|
||||
- struct regmap *regmap;
|
||||
- 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);
|
||||
- if (port < 0)
|
||||
- return port;
|
||||
-
|
||||
- mutex_lock(&priv->lock);
|
||||
- err = otto_emdio_wait_ready(priv);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- err = regmap_write(regmap, priv->info->cmd_regs.port_mask_low, BIT(port));
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- err = regmap_write(regmap, io_reg, FIELD_PREP(PHY_CTRL_INDATA, value));
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- val = FIELD_PREP(PHY_CTRL_REG_ADDR, 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, cmd_reg, val);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- err = regmap_read_poll_timeout(regmap, cmd_reg, val, !(val & PHY_CTRL_CMD), 10, 100);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- if (val & PHY_CTRL_FAIL) {
|
||||
- err = -ENXIO;
|
||||
- goto out_err;
|
||||
- }
|
||||
-
|
||||
- mutex_unlock(&priv->lock);
|
||||
- return 0;
|
||||
+ struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
|
||||
+ struct otto_emdio_cmd_regs cmd_data = {
|
||||
+ .c22_data = FIELD_PREP(PHY_CTRL_REG_ADDR, regnum) |
|
||||
+ FIELD_PREP(PHY_CTRL_PARK_PAGE, 0x1f) |
|
||||
+ FIELD_PREP(PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)),
|
||||
+ .io_data = FIELD_PREP(PHY_CTRL_INDATA, value),
|
||||
+ .port_mask_low = BIT(port),
|
||||
+ };
|
||||
|
||||
-out_err:
|
||||
- mutex_unlock(&priv->lock);
|
||||
- return err;
|
||||
+ return otto_emdio_write_cmd(bus, PHY_CTRL_TYPE_C22, &cmd_data);
|
||||
}
|
||||
|
||||
static int otto_emdio_9300_read_c45(struct mii_bus *bus, int phy_id, int dev_addr, int regnum)
|
||||
@@ -377,6 +335,21 @@ static int otto_emdio_9300_write_c45(str
|
||||
return otto_emdio_write_cmd(bus, PHY_CTRL_TYPE_C45, &cmd_data);
|
||||
}
|
||||
|
||||
+static int otto_emdio_write_c22(struct mii_bus *bus, int phy_id, int regnum, u16 value)
|
||||
+{
|
||||
+ struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
|
||||
+ int ret, port;
|
||||
+
|
||||
+ port = otto_emdio_phy_to_port(bus, phy_id);
|
||||
+ if (port < 0)
|
||||
+ return port;
|
||||
+
|
||||
+ scoped_guard(mutex, &priv->lock)
|
||||
+ ret = priv->info->write_c22(bus, port, regnum, value);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static int otto_emdio_write_c45(struct mii_bus *bus, int phy_id,
|
||||
int dev_addr, int regnum, u16 value)
|
||||
{
|
||||
@@ -470,7 +443,7 @@ static int otto_emdio_probe_one(struct d
|
||||
bus->write_c45 = otto_emdio_write_c45;
|
||||
} else {
|
||||
bus->read = priv->info->read_c22;
|
||||
- bus->write = priv->info->write_c22;
|
||||
+ bus->write = otto_emdio_write_c22;
|
||||
}
|
||||
bus->parent = dev;
|
||||
chan = bus->priv;
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
From fcce51bfd4edc5cd4059f835315d227657bcf62e Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Wed, 27 May 2026 18:34:48 +0200
|
||||
Subject: [PATCH 12/20] net: mdio: realtek-rtl9300: use command runner for
|
||||
read_c45()
|
||||
|
||||
Convert the read_c45() path to the new command runner. This needs the
|
||||
additional helper otto_emdio_read_cmd() that can issue the command runner
|
||||
and process a read operation. It is basically nothing more than
|
||||
|
||||
- run the command
|
||||
- read the command result thorugh the I/O register
|
||||
|
||||
With this in place convert the read_c45() like the alread existing write
|
||||
C22/C45 implementation.
|
||||
|
||||
- bus calls otto_emdio_read_c45()
|
||||
- this handed over to SoC specific otto_emdio_9300_read_c45()
|
||||
- the registers are filled
|
||||
- the otto_emdio_read_cmd() is issued
|
||||
- that calls the command runner
|
||||
|
||||
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Link: https://patch.msgid.link/20260527163449.1294961-4-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 100 ++++++++++++------------
|
||||
1 file changed, 48 insertions(+), 52 deletions(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -91,13 +91,14 @@ struct otto_emdio_cmd_regs {
|
||||
|
||||
struct otto_emdio_info {
|
||||
u32 cmd_fail;
|
||||
+ u32 cmd_read;
|
||||
u32 cmd_write;
|
||||
struct otto_emdio_cmd_regs cmd_regs;
|
||||
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 (*read_c45)(struct mii_bus *bus, int port, int dev_addr, int regnum, u32 *value);
|
||||
int (*write_c22)(struct mii_bus *bus, int port, int regnum, u16 value);
|
||||
int (*write_c45)(struct mii_bus *bus, int port, int dev_addr, int regnum, u16 value);
|
||||
};
|
||||
@@ -182,6 +183,26 @@ static int otto_emdio_run_cmd(struct mii
|
||||
return cmdstate & info->cmd_fail ? -ENXIO : 0;
|
||||
}
|
||||
|
||||
+static int otto_emdio_read_cmd(struct mii_bus *bus, u32 cmd,
|
||||
+ struct otto_emdio_cmd_regs *cmd_data, u32 *value)
|
||||
+{
|
||||
+ struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
|
||||
+ int ret;
|
||||
+
|
||||
+ lockdep_assert_held(&priv->lock);
|
||||
+ ret = otto_emdio_run_cmd(bus, cmd | priv->info->cmd_read, cmd_data);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = regmap_read(priv->regmap, priv->info->cmd_regs.io_data, value);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ *value = FIELD_GET(PHY_CTRL_DATA, *value);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int otto_emdio_write_cmd(struct mii_bus *bus, u32 cmd,
|
||||
struct otto_emdio_cmd_regs *cmd_data)
|
||||
{
|
||||
@@ -268,58 +289,16 @@ static int otto_emdio_9300_write_c22(str
|
||||
return otto_emdio_write_cmd(bus, PHY_CTRL_TYPE_C22, &cmd_data);
|
||||
}
|
||||
|
||||
-static int otto_emdio_9300_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 port,
|
||||
+ int dev_addr, int regnum, u32 *value)
|
||||
{
|
||||
- struct otto_emdio_chan *chan = bus->priv;
|
||||
- struct otto_emdio_priv *priv;
|
||||
- u32 io_reg, cmd_reg, val;
|
||||
- struct regmap *regmap;
|
||||
- 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);
|
||||
- if (port < 0)
|
||||
- return port;
|
||||
-
|
||||
- mutex_lock(&priv->lock);
|
||||
- err = otto_emdio_wait_ready(priv);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- val = FIELD_PREP(PHY_CTRL_INDATA, port);
|
||||
- err = regmap_write(regmap, io_reg, val);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- val = FIELD_PREP(PHY_CTRL_MMD_DEVAD, dev_addr) |
|
||||
- FIELD_PREP(PHY_CTRL_MMD_REG, regnum);
|
||||
- err = regmap_write(regmap, priv->info->cmd_regs.c45_data, val);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- err = regmap_write(regmap, cmd_reg, PHY_CTRL_READ | PHY_CTRL_TYPE_C45 | PHY_CTRL_CMD);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- err = otto_emdio_wait_ready(priv);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- err = regmap_read(regmap, io_reg, &val);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- mutex_unlock(&priv->lock);
|
||||
- return FIELD_GET(PHY_CTRL_DATA, val);
|
||||
+ struct otto_emdio_cmd_regs cmd_data = {
|
||||
+ .c45_data = FIELD_PREP(PHY_CTRL_MMD_DEVAD, dev_addr) |
|
||||
+ FIELD_PREP(PHY_CTRL_MMD_REG, regnum),
|
||||
+ .io_data = FIELD_PREP(PHY_CTRL_INDATA, port),
|
||||
+ };
|
||||
|
||||
-out_err:
|
||||
- mutex_unlock(&priv->lock);
|
||||
- return err;
|
||||
+ return otto_emdio_read_cmd(bus, PHY_CTRL_TYPE_C45, &cmd_data, value);
|
||||
}
|
||||
|
||||
static int otto_emdio_9300_write_c45(struct mii_bus *bus, int port,
|
||||
@@ -350,6 +329,22 @@ static int otto_emdio_write_c22(struct m
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int otto_emdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr, int regnum)
|
||||
+{
|
||||
+ struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
|
||||
+ int ret, port;
|
||||
+ u32 value;
|
||||
+
|
||||
+ port = otto_emdio_phy_to_port(bus, phy_id);
|
||||
+ if (port < 0)
|
||||
+ return port;
|
||||
+
|
||||
+ scoped_guard(mutex, &priv->lock)
|
||||
+ ret = priv->info->read_c45(bus, port, dev_addr, regnum, &value);
|
||||
+
|
||||
+ return ret ? ret : value;
|
||||
+}
|
||||
+
|
||||
static int otto_emdio_write_c45(struct mii_bus *bus, int phy_id,
|
||||
int dev_addr, int regnum, u16 value)
|
||||
{
|
||||
@@ -439,7 +434,7 @@ static int otto_emdio_probe_one(struct d
|
||||
|
||||
bus->name = "Realtek Switch MDIO Bus";
|
||||
if (priv->smi_bus_is_c45[mdio_bus]) {
|
||||
- bus->read_c45 = priv->info->read_c45;
|
||||
+ bus->read_c45 = otto_emdio_read_c45;
|
||||
bus->write_c45 = otto_emdio_write_c45;
|
||||
} else {
|
||||
bus->read = priv->info->read_c22;
|
||||
@@ -561,6 +556,7 @@ static int otto_emdio_probe(struct platf
|
||||
|
||||
static const struct otto_emdio_info otto_emdio_9300_info = {
|
||||
.cmd_fail = PHY_CTRL_FAIL,
|
||||
+ .cmd_read = PHY_CTRL_READ,
|
||||
.cmd_write = PHY_CTRL_WRITE,
|
||||
.cmd_regs = {
|
||||
.c22_data = RTL9300_SMI_ACCESS_PHY_CTRL_1,
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
From 2e3c28c715e913decf228dcd656bbb0dfc18133b Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Wed, 27 May 2026 18:34:49 +0200
|
||||
Subject: [PATCH 13/20] net: mdio: realtek-rtl9300: use command runner for
|
||||
read_c22()
|
||||
|
||||
Convert the final missing read_c22() path to the new read enabled command
|
||||
runner. Do it the same way as other implementations.
|
||||
|
||||
- bus calls otto_emdio_read_c22()
|
||||
- this hands over to SoC specific otto_emdio_9300_read_c22()
|
||||
- finally the registers are filled and the runner issued
|
||||
|
||||
With this cleanup remove the obsolete helper otto_emdio_wait_ready()
|
||||
|
||||
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Link: https://patch.msgid.link/20260527163449.1294961-5-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 87 ++++++++-----------------
|
||||
1 file changed, 27 insertions(+), 60 deletions(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -97,7 +97,7 @@ 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_c22)(struct mii_bus *bus, int port, int regnum, u32 *value);
|
||||
int (*read_c45)(struct mii_bus *bus, int port, int dev_addr, int regnum, u32 *value);
|
||||
int (*write_c22)(struct mii_bus *bus, int port, int regnum, u16 value);
|
||||
int (*write_c45)(struct mii_bus *bus, int port, int dev_addr, int regnum, u16 value);
|
||||
@@ -213,66 +213,17 @@ static int otto_emdio_write_cmd(struct m
|
||||
return otto_emdio_run_cmd(bus, cmd | priv->info->cmd_write, cmd_data);
|
||||
}
|
||||
|
||||
-static int otto_emdio_wait_ready(struct otto_emdio_priv *priv)
|
||||
+static int otto_emdio_9300_read_c22(struct mii_bus *bus, int port, int regnum, u32 *value)
|
||||
{
|
||||
- struct regmap *regmap = priv->regmap;
|
||||
- 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, 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)
|
||||
-{
|
||||
- struct otto_emdio_chan *chan = bus->priv;
|
||||
- struct otto_emdio_priv *priv;
|
||||
- u32 io_reg, cmd_reg, val;
|
||||
- struct regmap *regmap;
|
||||
- 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);
|
||||
- if (port < 0)
|
||||
- return port;
|
||||
-
|
||||
- mutex_lock(&priv->lock);
|
||||
- err = otto_emdio_wait_ready(priv);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- err = regmap_write(regmap, io_reg, FIELD_PREP(PHY_CTRL_INDATA, port));
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- val = FIELD_PREP(PHY_CTRL_REG_ADDR, 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, cmd_reg, val);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- err = otto_emdio_wait_ready(priv);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- err = regmap_read(regmap, io_reg, &val);
|
||||
- if (err)
|
||||
- goto out_err;
|
||||
-
|
||||
- mutex_unlock(&priv->lock);
|
||||
- return FIELD_GET(PHY_CTRL_DATA, val);
|
||||
+ struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
|
||||
+ struct otto_emdio_cmd_regs cmd_data = {
|
||||
+ .c22_data = FIELD_PREP(PHY_CTRL_REG_ADDR, regnum) |
|
||||
+ FIELD_PREP(PHY_CTRL_PARK_PAGE, 0x1f) |
|
||||
+ FIELD_PREP(PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)),
|
||||
+ .io_data = FIELD_PREP(PHY_CTRL_INDATA, port),
|
||||
+ };
|
||||
|
||||
-out_err:
|
||||
- mutex_unlock(&priv->lock);
|
||||
- return err;
|
||||
+ return otto_emdio_read_cmd(bus, PHY_CTRL_TYPE_C22, &cmd_data, value);
|
||||
}
|
||||
|
||||
static int otto_emdio_9300_write_c22(struct mii_bus *bus, int port, int regnum, u16 value)
|
||||
@@ -314,6 +265,22 @@ static int otto_emdio_9300_write_c45(str
|
||||
return otto_emdio_write_cmd(bus, PHY_CTRL_TYPE_C45, &cmd_data);
|
||||
}
|
||||
|
||||
+static int otto_emdio_read_c22(struct mii_bus *bus, int phy_id, int regnum)
|
||||
+{
|
||||
+ struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
|
||||
+ int ret, port;
|
||||
+ u32 value;
|
||||
+
|
||||
+ port = otto_emdio_phy_to_port(bus, phy_id);
|
||||
+ if (port < 0)
|
||||
+ return port;
|
||||
+
|
||||
+ scoped_guard(mutex, &priv->lock)
|
||||
+ ret = priv->info->read_c22(bus, port, regnum, &value);
|
||||
+
|
||||
+ return ret ? ret : value;
|
||||
+}
|
||||
+
|
||||
static int otto_emdio_write_c22(struct mii_bus *bus, int phy_id, int regnum, u16 value)
|
||||
{
|
||||
struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
|
||||
@@ -437,7 +404,7 @@ static int otto_emdio_probe_one(struct d
|
||||
bus->read_c45 = otto_emdio_read_c45;
|
||||
bus->write_c45 = otto_emdio_write_c45;
|
||||
} else {
|
||||
- bus->read = priv->info->read_c22;
|
||||
+ bus->read = otto_emdio_read_c22;
|
||||
bus->write = otto_emdio_write_c22;
|
||||
}
|
||||
bus->parent = dev;
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
From f369dd8ccf2dbce9166544e266e2b6ca974f98d9 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Wed, 3 Jun 2026 19:59:18 +0200
|
||||
Subject: [PATCH 14/20] net: mdio: realtek-rtl9300: Refactor
|
||||
otto_emdio_map_ports()
|
||||
|
||||
This function has multiple issues:
|
||||
- It uses __free low level cleanups
|
||||
- It mixes "fwnode" and "of" functions
|
||||
|
||||
Convert this to a uniform "of" usage and manual reference counting
|
||||
cleanup. With that also fix two subtle lookup bugs in the original
|
||||
code.
|
||||
|
||||
mdio_dn = phy_dn->parent;
|
||||
if (mdio_dn->parent != dev->of_node)
|
||||
continue;
|
||||
|
||||
This skips an API access and therefore misses reference counting.
|
||||
Additionally in the case of a very buggy device tree, phy_dn might
|
||||
be a root node. Looking up its grandparent leads to a NULL pointer
|
||||
access.
|
||||
|
||||
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260603175924.123019-2-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 69 +++++++++++++++----------
|
||||
1 file changed, 42 insertions(+), 27 deletions(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -427,60 +427,75 @@ static int otto_emdio_probe_one(struct d
|
||||
*/
|
||||
static int otto_emdio_map_ports(struct device *dev)
|
||||
{
|
||||
+ struct device_node *ports_dn, *phy_dn, *bus_dn, *ctrl_dn;
|
||||
struct otto_emdio_priv *priv = dev_get_drvdata(dev);
|
||||
struct device *parent = dev->parent;
|
||||
- int err;
|
||||
+ u32 addr, bus, pn;
|
||||
+ int err = 0;
|
||||
|
||||
- struct fwnode_handle *ports __free(fwnode_handle) =
|
||||
- device_get_named_child_node(parent, "ethernet-ports");
|
||||
- if (!ports)
|
||||
+ ports_dn = of_get_child_by_name(parent->of_node, "ethernet-ports");
|
||||
+ if (!ports_dn)
|
||||
return dev_err_probe(dev, -EINVAL, "%pfwP missing ethernet-ports\n",
|
||||
dev_fwnode(parent));
|
||||
|
||||
- fwnode_for_each_child_node_scoped(ports, port) {
|
||||
- struct device_node *mdio_dn;
|
||||
- u32 addr;
|
||||
- u32 bus;
|
||||
- u32 pn;
|
||||
-
|
||||
- struct device_node *phy_dn __free(device_node) =
|
||||
- of_parse_phandle(to_of_node(port), "phy-handle", 0);
|
||||
+ for_each_available_child_of_node_scoped(ports_dn, port_dn) {
|
||||
+ ctrl_dn = NULL;
|
||||
+ bus_dn = NULL;
|
||||
+ phy_dn = of_parse_phandle(port_dn, "phy-handle", 0);
|
||||
/* skip ports without phys */
|
||||
if (!phy_dn)
|
||||
continue;
|
||||
|
||||
- mdio_dn = phy_dn->parent;
|
||||
+ bus_dn = of_get_parent(phy_dn);
|
||||
+ if (!bus_dn)
|
||||
+ goto put_nodes;
|
||||
+
|
||||
+ ctrl_dn = of_get_parent(bus_dn);
|
||||
/* only map ports that are connected to this mdio-controller */
|
||||
- if (mdio_dn->parent != dev->of_node)
|
||||
- continue;
|
||||
+ if (ctrl_dn != dev->of_node)
|
||||
+ goto put_nodes;
|
||||
|
||||
- err = fwnode_property_read_u32(port, "reg", &pn);
|
||||
+ err = of_property_read_u32(port_dn, "reg", &pn);
|
||||
if (err)
|
||||
- return err;
|
||||
+ goto put_nodes;
|
||||
|
||||
- if (pn >= priv->info->num_ports)
|
||||
- return dev_err_probe(dev, -EINVAL, "illegal port number %d\n", pn);
|
||||
+ if (pn >= priv->info->num_ports) {
|
||||
+ err = dev_err_probe(dev, -EINVAL, "illegal port number %d\n", pn);
|
||||
+ goto put_nodes;
|
||||
+ }
|
||||
+
|
||||
+ if (test_bit(pn, priv->valid_ports)) {
|
||||
+ err = dev_err_probe(dev, -EINVAL, "duplicated port number %d\n", pn);
|
||||
+ goto put_nodes;
|
||||
+ }
|
||||
|
||||
- if (test_bit(pn, priv->valid_ports))
|
||||
- return dev_err_probe(dev, -EINVAL, "duplicated port number %d\n", pn);
|
||||
-
|
||||
- err = of_property_read_u32(mdio_dn, "reg", &bus);
|
||||
+ err = of_property_read_u32(bus_dn, "reg", &bus);
|
||||
if (err)
|
||||
- return err;
|
||||
+ goto put_nodes;
|
||||
|
||||
- if (bus >= priv->info->num_buses)
|
||||
- return dev_err_probe(dev, -EINVAL, "illegal smi bus number %d\n", bus);
|
||||
+ if (bus >= priv->info->num_buses) {
|
||||
+ err = dev_err_probe(dev, -EINVAL, "illegal smi bus number %d\n", bus);
|
||||
+ goto put_nodes;
|
||||
+ }
|
||||
|
||||
err = of_property_read_u32(phy_dn, "reg", &addr);
|
||||
if (err)
|
||||
- return err;
|
||||
+ goto put_nodes;
|
||||
|
||||
__set_bit(pn, priv->valid_ports);
|
||||
priv->smi_bus[pn] = bus;
|
||||
priv->smi_addr[pn] = addr;
|
||||
+put_nodes:
|
||||
+ of_node_put(bus_dn);
|
||||
+ of_node_put(phy_dn);
|
||||
+ of_node_put(ctrl_dn);
|
||||
+ if (err)
|
||||
+ break;
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ of_node_put(ports_dn);
|
||||
+
|
||||
+ return err;
|
||||
}
|
||||
|
||||
static int otto_emdio_probe(struct platform_device *pdev)
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
From 829ee0f8bc3920092b06d32d9e05328395ed5b77 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Wed, 3 Jun 2026 19:59:19 +0200
|
||||
Subject: [PATCH 15/20] net: mdio: realtek-rtl9300: harden
|
||||
otto_emdio_map_ports()
|
||||
|
||||
Due to its design the MDIO driver needs to set up a port to bus/address
|
||||
mapping during probing. The "ethernet-ports" subnodes are scanned and
|
||||
from the "phy-handle" property the MDIO nodes are looked up. In case of
|
||||
a malformed device tree the driver might produce out-of-bounds accesses.
|
||||
The PHY address is not checked against the maximum supported address.
|
||||
|
||||
Add a sanity check and drop the unneeded MAX_SMI_ADDR define.
|
||||
|
||||
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260603175924.123019-3-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 11 ++++++-----
|
||||
1 file changed, 6 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -78,7 +78,6 @@
|
||||
|
||||
#define MAX_PORTS 28
|
||||
#define MAX_SMI_BUSSES 4
|
||||
-#define MAX_SMI_ADDR 0x1f
|
||||
#define RAW_PAGE(priv) ((priv)->info->num_pages - 1)
|
||||
|
||||
|
||||
@@ -430,8 +429,8 @@ static int otto_emdio_map_ports(struct d
|
||||
struct device_node *ports_dn, *phy_dn, *bus_dn, *ctrl_dn;
|
||||
struct otto_emdio_priv *priv = dev_get_drvdata(dev);
|
||||
struct device *parent = dev->parent;
|
||||
- u32 addr, bus, pn;
|
||||
- int err = 0;
|
||||
+ int addr, err = 0;
|
||||
+ u32 bus, pn;
|
||||
|
||||
ports_dn = of_get_child_by_name(parent->of_node, "ethernet-ports");
|
||||
if (!ports_dn)
|
||||
@@ -478,9 +477,11 @@ static int otto_emdio_map_ports(struct d
|
||||
goto put_nodes;
|
||||
}
|
||||
|
||||
- err = of_property_read_u32(phy_dn, "reg", &addr);
|
||||
- if (err)
|
||||
+ addr = of_mdio_parse_addr(dev, phy_dn);
|
||||
+ if (addr < 0) {
|
||||
+ err = addr;
|
||||
goto put_nodes;
|
||||
+ }
|
||||
|
||||
__set_bit(pn, priv->valid_ports);
|
||||
priv->smi_bus[pn] = bus;
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
From 67885c0e3919be0f39d8f69e4eb446c9df8fa5fc Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Wed, 3 Jun 2026 19:59:20 +0200
|
||||
Subject: [PATCH 16/20] net: mdio: realtek-rtl9300: harden
|
||||
otto_emdio_probe_one()
|
||||
|
||||
The bus probing of the MDIO driver uses a two stage approach.
|
||||
|
||||
1. The device tree "ethernet-ports" node is scanned to build a mapping
|
||||
between ports and PHYs.
|
||||
|
||||
2. The children of the device tree "controller" are scanned to create
|
||||
the individual MDIO buses.
|
||||
|
||||
The first step already checks the consistency of the PHY and bus nodes
|
||||
that are linked via the ports. But it might miss a dangling bus child
|
||||
node that is not linked. Step two simply iterates over all bus child
|
||||
nodes and might read malformed data from nodes not checked in step one.
|
||||
|
||||
Harden this and return a meaningful error message.
|
||||
|
||||
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260603175924.123019-4-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -380,7 +380,11 @@ static int otto_emdio_probe_one(struct d
|
||||
|
||||
err = fwnode_property_read_u32(node, "reg", &mdio_bus);
|
||||
if (err)
|
||||
- return err;
|
||||
+ return dev_err_probe(dev, err, "undefined smi bus number\n");
|
||||
+
|
||||
+ if (mdio_bus >= priv->info->num_buses)
|
||||
+ return dev_err_probe(dev, -EINVAL,
|
||||
+ "illegal (dangling) smi bus number %d\n", mdio_bus);
|
||||
|
||||
/* The MDIO accesses from the kernel work with the PHY polling unit in
|
||||
* the switch. We need to tell the PPU to operate either in GPHY (i.e.
|
||||
+219
@@ -0,0 +1,219 @@
|
||||
From 94f05740ad16c5b2bf738af69b99cd0c48afd19e Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Wed, 3 Jun 2026 19:59:21 +0200
|
||||
Subject: [PATCH 17/20] net: mdio: realtek-rtl9300: relocate topology setup
|
||||
|
||||
Until now the driver sets up the port to bus/address topology of the
|
||||
controller after all buses are set up via otto_emdio_probe_one(). This
|
||||
does not work for devices where U-Boot skips this setup. It is not
|
||||
only needed for the hardware internal background PHY polling engine
|
||||
but it is essential for access to the PHYs during probing.
|
||||
|
||||
Depending on the SoC type there exist two different register arrays
|
||||
|
||||
- Bus mapping registers (RTL930x, RTL931x) define to which bus the port
|
||||
is attached. E.g. [1]
|
||||
- Address mapping registers (RTL838x, RTL930x, RTL931x) define to which
|
||||
address of the bus the port is attached. E.g. [2]
|
||||
|
||||
Relocate the topology setup and make it generic. For this
|
||||
|
||||
- Define device-specific bus_base/addr_base attributes that give the
|
||||
register base address where the mapping lives. In case one or both are
|
||||
not given the SoC does not support this specific type of mapping.
|
||||
- Create a helper otto_emdio_setup_topology() that writes the detected
|
||||
topology to the registers.
|
||||
- Call this helper prior to otto_emdio_probe_one().
|
||||
- Remove unneeded code from otto_emdio_9300_mdiobus_init().
|
||||
- Due to the added prefixes, increase define indentation
|
||||
|
||||
Subtle change: The old coding used regmap_bulk_write and silently wrote
|
||||
bus=0/address=0 to mapping registers for ports that are out of scope.
|
||||
The new coding leaves those untouched.
|
||||
|
||||
[1] https://svanheule.net/realtek/longan/register/smi_port0_15_polling_sel
|
||||
[2] https://svanheule.net/realtek/longan/register/smi_port0_5_addr_ctrl
|
||||
|
||||
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260603175924.123019-5-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 127 ++++++++++++++----------
|
||||
1 file changed, 76 insertions(+), 51 deletions(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -51,34 +51,38 @@
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
-#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))
|
||||
-#define SMI_PORT0_15_POLLING_SEL 0xca08
|
||||
-#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)
|
||||
-#define PHY_CTRL_MAIN_PAGE GENMASK(14, 3)
|
||||
-#define PHY_CTRL_WRITE BIT(2)
|
||||
-#define PHY_CTRL_READ 0
|
||||
-#define PHY_CTRL_TYPE_C45 BIT(1)
|
||||
-#define PHY_CTRL_TYPE_C22 0
|
||||
-#define PHY_CTRL_CMD BIT(0)
|
||||
-#define PHY_CTRL_FAIL BIT(25)
|
||||
-#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
|
||||
-#define PHY_CTRL_MMD_DEVAD GENMASK(20, 16)
|
||||
-#define PHY_CTRL_MMD_REG GENMASK(15, 0)
|
||||
-#define SMI_PORT0_5_ADDR_CTRL 0xcb80
|
||||
-
|
||||
-#define MAX_PORTS 28
|
||||
-#define MAX_SMI_BUSSES 4
|
||||
-#define RAW_PAGE(priv) ((priv)->info->num_pages - 1)
|
||||
+#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))
|
||||
+#define RTL9300_SMI_PORT0_15_POLLING_SEL 0xca08
|
||||
+#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)
|
||||
+#define PHY_CTRL_MAIN_PAGE GENMASK(14, 3)
|
||||
+#define PHY_CTRL_WRITE BIT(2)
|
||||
+#define PHY_CTRL_READ 0
|
||||
+#define PHY_CTRL_TYPE_C45 BIT(1)
|
||||
+#define PHY_CTRL_TYPE_C22 0
|
||||
+#define PHY_CTRL_CMD BIT(0)
|
||||
+#define PHY_CTRL_FAIL BIT(25)
|
||||
+#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
|
||||
+#define PHY_CTRL_MMD_DEVAD GENMASK(20, 16)
|
||||
+#define PHY_CTRL_MMD_REG GENMASK(15, 0)
|
||||
+#define RTL9300_SMI_PORT0_5_ADDR_CTRL 0xcb80
|
||||
+
|
||||
+#define MAP_ADDRS_PER_REG 6
|
||||
+#define MAP_BITS_PER_ADDR 5
|
||||
+#define MAP_BITS_PER_BUS 2
|
||||
+#define MAP_BUSES_PER_REG 16
|
||||
+#define MAX_PORTS 28
|
||||
+#define MAX_SMI_BUSSES 4
|
||||
+#define RAW_PAGE(priv) ((priv)->info->num_pages - 1)
|
||||
|
||||
|
||||
struct otto_emdio_cmd_regs {
|
||||
@@ -89,6 +93,8 @@ struct otto_emdio_cmd_regs {
|
||||
};
|
||||
|
||||
struct otto_emdio_info {
|
||||
+ u32 addr_map_base;
|
||||
+ u32 bus_map_base;
|
||||
u32 cmd_fail;
|
||||
u32 cmd_read;
|
||||
u32 cmd_write;
|
||||
@@ -327,41 +333,54 @@ static int otto_emdio_write_c45(struct m
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int otto_emdio_9300_mdiobus_init(struct otto_emdio_priv *priv)
|
||||
+static int otto_emdio_write_mapping(struct otto_emdio_priv *priv, u32 base, u32 port,
|
||||
+ u32 vals_per_reg, u32 bits_per_val, u32 value)
|
||||
{
|
||||
- u32 glb_ctrl_mask = 0, glb_ctrl_val = 0;
|
||||
- struct regmap *regmap = priv->regmap;
|
||||
- u32 port_addr[5] = { 0 };
|
||||
- u32 poll_sel[2] = { 0 };
|
||||
- int i, err;
|
||||
+ u32 shift = (port % vals_per_reg) * bits_per_val;
|
||||
+ u32 reg = base + (port / vals_per_reg) * 4;
|
||||
+ u32 mask = GENMASK(bits_per_val - 1, 0);
|
||||
|
||||
- /* Associate the port with the SMI interface and PHY */
|
||||
- for_each_set_bit(i, priv->valid_ports, priv->info->num_ports) {
|
||||
- int pos;
|
||||
+ return regmap_update_bits(priv->regmap, reg, mask << shift, value << shift);
|
||||
+}
|
||||
|
||||
- pos = (i % 6) * 5;
|
||||
- port_addr[i / 6] |= (priv->smi_addr[i] & 0x1f) << pos;
|
||||
+static int otto_emdio_setup_topology(struct otto_emdio_priv *priv)
|
||||
+{
|
||||
+ const struct otto_emdio_info *info = priv->info;
|
||||
+ u32 port;
|
||||
+ int ret;
|
||||
|
||||
- pos = (i % 16) * 2;
|
||||
- poll_sel[i / 16] |= (priv->smi_bus[i] & 0x3) << pos;
|
||||
+ for_each_set_bit(port, priv->valid_ports, info->num_ports) {
|
||||
+ if (info->bus_map_base) {
|
||||
+ ret = otto_emdio_write_mapping(priv, info->bus_map_base, port,
|
||||
+ MAP_BUSES_PER_REG, MAP_BITS_PER_BUS,
|
||||
+ priv->smi_bus[port]);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+ if (info->addr_map_base) {
|
||||
+ ret = otto_emdio_write_mapping(priv, info->addr_map_base, port,
|
||||
+ MAP_ADDRS_PER_REG, MAP_BITS_PER_ADDR,
|
||||
+ priv->smi_addr[port]);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
}
|
||||
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+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;
|
||||
+ int i, err;
|
||||
+
|
||||
/* Put the interfaces into C45 mode if required */
|
||||
glb_ctrl_mask = GENMASK(19, 16);
|
||||
for (i = 0; i < priv->info->num_buses; i++)
|
||||
if (priv->smi_bus_is_c45[i])
|
||||
glb_ctrl_val |= GLB_CTRL_INTF_SEL(i);
|
||||
|
||||
- err = regmap_bulk_write(regmap, SMI_PORT0_5_ADDR_CTRL,
|
||||
- port_addr, 5);
|
||||
- if (err)
|
||||
- return err;
|
||||
-
|
||||
- err = regmap_bulk_write(regmap, SMI_PORT0_15_POLLING_SEL,
|
||||
- poll_sel, 2);
|
||||
- if (err)
|
||||
- return err;
|
||||
-
|
||||
err = regmap_update_bits(regmap, SMI_GLB_CTRL,
|
||||
glb_ctrl_mask, glb_ctrl_val);
|
||||
if (err)
|
||||
@@ -528,6 +547,10 @@ static int otto_emdio_probe(struct platf
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
+ err = otto_emdio_setup_topology(priv);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
device_for_each_child_node_scoped(dev, child) {
|
||||
err = otto_emdio_probe_one(dev, priv, child);
|
||||
if (err)
|
||||
@@ -542,6 +565,8 @@ static int otto_emdio_probe(struct platf
|
||||
}
|
||||
|
||||
static const struct otto_emdio_info otto_emdio_9300_info = {
|
||||
+ .addr_map_base = RTL9300_SMI_PORT0_5_ADDR_CTRL,
|
||||
+ .bus_map_base = RTL9300_SMI_PORT0_15_POLLING_SEL,
|
||||
.cmd_fail = PHY_CTRL_FAIL,
|
||||
.cmd_read = PHY_CTRL_READ,
|
||||
.cmd_write = PHY_CTRL_WRITE,
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
From 439aba443a8012b5a61bf327f75bec69be56ddd3 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Wed, 3 Jun 2026 19:59:22 +0200
|
||||
Subject: [PATCH 18/20] net: mdio: realtek-rtl9300: relocate c22/c45 device
|
||||
tree readout
|
||||
|
||||
otto_emdio_map_ports() is the central place to lookup the topology and the
|
||||
properties of the Realtek ethernet MDIO controller from the device tree.
|
||||
Deviating from this the c22/c45 detection via "ethernet-phy-ieee802.3-c45"
|
||||
is running separately in otto_emdio_probe_one(). It loops over the same
|
||||
nodes, just at a later point in time.
|
||||
|
||||
There is no benefit to divide this setup and to have a time window where
|
||||
the data structure is only filled partially. Additionally it uses the
|
||||
"fwnode" API. Consolidate the setup and convert it to the "of" API.
|
||||
|
||||
Remark. This is a subtle change for dangling PHY nodes (not referenced
|
||||
by ethernet-ports). Before this commit all PHY nodes were evaluated for
|
||||
c45 setup, now only the referenced ones.
|
||||
|
||||
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260603175924.123019-6-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 21 +++++++++------------
|
||||
1 file changed, 9 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -405,18 +405,6 @@ static int otto_emdio_probe_one(struct d
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"illegal (dangling) smi bus number %d\n", mdio_bus);
|
||||
|
||||
- /* The MDIO accesses from the kernel work with the PHY polling unit in
|
||||
- * the switch. We need to tell the PPU to operate either in GPHY (i.e.
|
||||
- * clause 22) or 10GPHY mode (i.e. clause 45).
|
||||
- *
|
||||
- * We select 10GPHY mode if there is at least one PHY that declares
|
||||
- * compatible = "ethernet-phy-ieee802.3-c45". This does mean we can't
|
||||
- * support both c45 and c22 on the same MDIO bus.
|
||||
- */
|
||||
- fwnode_for_each_child_node_scoped(node, child)
|
||||
- if (fwnode_device_is_compatible(child, "ethernet-phy-ieee802.3-c45"))
|
||||
- priv->smi_bus_is_c45[mdio_bus] = true;
|
||||
-
|
||||
bus = devm_mdiobus_alloc_size(dev, sizeof(*chan));
|
||||
if (!bus)
|
||||
return -ENOMEM;
|
||||
@@ -506,6 +494,15 @@ static int otto_emdio_map_ports(struct d
|
||||
goto put_nodes;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * The MDIO accesses from the kernel work with the PHY polling unit in the
|
||||
+ * switch. The PPU either operates in GPHY (i.e. clause 22) or 10GPHY mode
|
||||
+ * (i.e. clause 45). Select 10GPHY mode if there is at least one PHY that
|
||||
+ * declares compatible = "ethernet-phy-ieee802.3-c45".
|
||||
+ */
|
||||
+ if (of_device_is_compatible(phy_dn, "ethernet-phy-ieee802.3-c45"))
|
||||
+ priv->smi_bus_is_c45[bus] = true;
|
||||
+
|
||||
__set_bit(pn, priv->valid_ports);
|
||||
priv->smi_bus[pn] = bus;
|
||||
priv->smi_addr[pn] = addr;
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
From 56b4864150970ba834367fe74b37ce250419347e Mon Sep 17 00:00:00 2001
|
||||
From: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Date: Wed, 3 Jun 2026 19:59:23 +0200
|
||||
Subject: [PATCH 19/20] net: mdio: realtek-rtl9300: reorder controller setup
|
||||
|
||||
After the former refactoring the existing otto_emdio_9300_mdiobus_init()
|
||||
contains only the c22/c45 bus mode setup. Like the topology setup this
|
||||
must run before bus registration. Otherwise the bus does not "speak" the
|
||||
right protocol for PHY setup.
|
||||
|
||||
This setup is device-specific and other SoCs will need to set up other
|
||||
register bits in the controller in the future. Therefore
|
||||
|
||||
- Relocate c22/c45 device tree readout to the very beginning of the probing
|
||||
- Add a new device-specific setup_controller() into the info structure.
|
||||
- Relocate otto_emdio_priv to satisfy the new info structure dependency.
|
||||
- Rename otto_emdio_9300_mdiobus_init accordingly and add it to the
|
||||
RTL9300 info structure. At the same time, adapt register naming
|
||||
for the function to make it clear that it only applies to this SoC.
|
||||
- Call setup_controller() prior to bus registration.
|
||||
|
||||
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260603175924.123019-7-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 44 ++++++++++++++-----------
|
||||
1 file changed, 24 insertions(+), 20 deletions(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -54,8 +54,8 @@
|
||||
#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))
|
||||
+#define RTL9300_SMI_GLB_CTRL 0xca00
|
||||
+#define RTL9300_GLB_CTRL_INTF_SEL(intf) BIT(16 + (intf))
|
||||
#define RTL9300_SMI_PORT0_15_POLLING_SEL 0xca08
|
||||
#define RTL9300_SMI_ACCESS_PHY_CTRL_0 0xcb70
|
||||
#define RTL9300_SMI_ACCESS_PHY_CTRL_1 0xcb74
|
||||
@@ -92,6 +92,17 @@ struct otto_emdio_cmd_regs {
|
||||
u32 port_mask_low;
|
||||
};
|
||||
|
||||
+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);
|
||||
+ u8 smi_bus[MAX_PORTS];
|
||||
+ u8 smi_addr[MAX_PORTS];
|
||||
+ bool smi_bus_is_c45[MAX_SMI_BUSSES];
|
||||
+ struct mii_bus *bus[MAX_SMI_BUSSES];
|
||||
+};
|
||||
+
|
||||
struct otto_emdio_info {
|
||||
u32 addr_map_base;
|
||||
u32 bus_map_base;
|
||||
@@ -102,23 +113,13 @@ struct otto_emdio_info {
|
||||
u8 num_buses;
|
||||
u8 num_ports;
|
||||
u16 num_pages;
|
||||
+ int (*setup_controller)(struct otto_emdio_priv *priv);
|
||||
int (*read_c22)(struct mii_bus *bus, int port, int regnum, u32 *value);
|
||||
int (*read_c45)(struct mii_bus *bus, int port, int dev_addr, int regnum, u32 *value);
|
||||
int (*write_c22)(struct mii_bus *bus, int port, int regnum, u16 value);
|
||||
int (*write_c45)(struct mii_bus *bus, int port, int dev_addr, int regnum, u16 value);
|
||||
};
|
||||
|
||||
-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);
|
||||
- u8 smi_bus[MAX_PORTS];
|
||||
- u8 smi_addr[MAX_PORTS];
|
||||
- bool smi_bus_is_c45[MAX_SMI_BUSSES];
|
||||
- struct mii_bus *bus[MAX_SMI_BUSSES];
|
||||
-};
|
||||
-
|
||||
struct otto_emdio_chan {
|
||||
struct otto_emdio_priv *priv;
|
||||
u8 mdio_bus;
|
||||
@@ -369,7 +370,7 @@ static int otto_emdio_setup_topology(str
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int otto_emdio_9300_mdiobus_init(struct otto_emdio_priv *priv)
|
||||
+static int otto_emdio_9300_setup_controller(struct otto_emdio_priv *priv)
|
||||
{
|
||||
u32 glb_ctrl_mask = 0, glb_ctrl_val = 0;
|
||||
struct regmap *regmap = priv->regmap;
|
||||
@@ -379,9 +380,9 @@ static int otto_emdio_9300_mdiobus_init(
|
||||
glb_ctrl_mask = GENMASK(19, 16);
|
||||
for (i = 0; i < priv->info->num_buses; i++)
|
||||
if (priv->smi_bus_is_c45[i])
|
||||
- glb_ctrl_val |= GLB_CTRL_INTF_SEL(i);
|
||||
+ glb_ctrl_val |= RTL9300_GLB_CTRL_INTF_SEL(i);
|
||||
|
||||
- err = regmap_update_bits(regmap, SMI_GLB_CTRL,
|
||||
+ err = regmap_update_bits(regmap, RTL9300_SMI_GLB_CTRL,
|
||||
glb_ctrl_mask, glb_ctrl_val);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -548,16 +549,18 @@ static int otto_emdio_probe(struct platf
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
+ if (priv->info->setup_controller) {
|
||||
+ err = priv->info->setup_controller(priv);
|
||||
+ if (err)
|
||||
+ return dev_err_probe(dev, err, "failed to setup MDIO bus controller\n");
|
||||
+ }
|
||||
+
|
||||
device_for_each_child_node_scoped(dev, child) {
|
||||
err = otto_emdio_probe_one(dev, priv, child);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
- err = otto_emdio_9300_mdiobus_init(priv);
|
||||
- if (err)
|
||||
- return dev_err_probe(dev, err, "failed to initialise MDIO bus controller\n");
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -576,6 +579,7 @@ static const struct otto_emdio_info otto
|
||||
.num_buses = RTL9300_NUM_BUSES,
|
||||
.num_ports = RTL9300_NUM_PORTS,
|
||||
.num_pages = RTL9300_NUM_PAGES,
|
||||
+ .setup_controller = otto_emdio_9300_setup_controller,
|
||||
.read_c22 = otto_emdio_9300_read_c22,
|
||||
.read_c45 = otto_emdio_9300_read_c45,
|
||||
.write_c22 = otto_emdio_9300_write_c22,
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
From 50b682a5aed70847e0746db7f723d22bef1801d1 Mon Sep 17 00:00:00 2001
|
||||
From: Manuel Stocker <mensi@mensi.ch>
|
||||
Date: Wed, 3 Jun 2026 19:59:24 +0200
|
||||
Subject: [PATCH 20/20] net: mdio: realtek-rtl9300: Correctly handle
|
||||
ethernet-phy-package
|
||||
|
||||
Realtek Otto switches usually make use of multiport PHYs (e.g. 8 port
|
||||
1G RTL8218D or 4 port 2.5G RTL8224). The device tree can describe this
|
||||
fact via an "ethernet-phy-package" node that resides between the bus
|
||||
and the PHY node.
|
||||
|
||||
When looking up the device tree bus node via the chain port->phy->parent
|
||||
the driver totally ignores the existence of a PHY package. Enhance the
|
||||
lookup to take care of this feature.
|
||||
|
||||
Link: https://github.com/openwrt/openwrt/pull/23591
|
||||
Signed-off-by: Manuel Stocker <mensi@mensi.ch>
|
||||
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
Link: https://patch.msgid.link/20260603175924.123019-8-markus.stockhausen@gmx.de
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/mdio/mdio-realtek-rtl9300.c | 17 ++++++++++++++++-
|
||||
1 file changed, 16 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
|
||||
@@ -432,6 +432,21 @@ static int otto_emdio_probe_one(struct d
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static struct device_node *otto_emdio_get_bus_node(struct device_node *dn)
|
||||
+{
|
||||
+ struct device_node *parent = of_get_parent(dn);
|
||||
+ struct device_node *grandparent;
|
||||
+
|
||||
+ if (parent && of_node_name_eq(parent, "ethernet-phy-package")) {
|
||||
+ grandparent = of_get_parent(parent);
|
||||
+ of_node_put(parent);
|
||||
+
|
||||
+ return grandparent;
|
||||
+ }
|
||||
+
|
||||
+ return parent;
|
||||
+}
|
||||
+
|
||||
/* The mdio-controller is part of a switch block so we parse the sibling
|
||||
* ethernet-ports node and build a mapping of the switch port to MDIO bus/addr
|
||||
* based on the phy-handle.
|
||||
@@ -457,7 +472,7 @@ static int otto_emdio_map_ports(struct d
|
||||
if (!phy_dn)
|
||||
continue;
|
||||
|
||||
- bus_dn = of_get_parent(phy_dn);
|
||||
+ bus_dn = otto_emdio_get_bus_node(phy_dn);
|
||||
if (!bus_dn)
|
||||
goto put_nodes;
|
||||
|
||||
Reference in new issue
Block a user