Merge branch 'net-mdio-realtek-rtl9300-add-bus-frequency-handling'

Markus Stockhausen says:

====================
net: mdio: realtek-rtl9300: add bus frequency handling

The Realtek Otto switch platform consists of four different series

- RTL838x aka maple   : 28 port 1G Switches
- RTL839x aka cypress : 52 port 1G Switches
- RTL930x aka longan  : 28 port 1G/2.5G/10G Switches
- RTL931x aka mango   : 56 port 1G/2.5G/10G Switches

All of them support changing the bus frequency of their one to four
Ethernet MDIO buses, although the available settings differ between
the series. Extend the driver to support this feature.
====================

Link: https://patch.msgid.link/20261005074908.1273383-1-markus.stockhausen@gmx.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-10-08 16:32:44 -07:00
commit b22554323b
2 changed files with 173 additions and 9 deletions

View File

@ -71,6 +71,68 @@ required:
- compatible
- reg
allOf:
- if:
properties:
compatible:
contains:
enum:
- realtek,rtl8380-mdio
- realtek,rtl8381-mdio
- realtek,rtl8382-mdio
then:
properties:
mdio-bus@0:
properties:
clock-frequency:
enum: [2500000, 10000000]
default: 2500000
patternProperties:
'^mdio-bus@[1-3]$': false
- if:
properties:
compatible:
contains:
enum:
- realtek,rtl8391-mdio
- realtek,rtl8392-mdio
- realtek,rtl8393-mdio
then:
patternProperties:
'^mdio-bus@[01]$':
properties:
clock-frequency:
enum: [1250000, 2500000, 5000000]
description: |
RTL839x has one clock selector shared by both MDIO buses. All explicitly
specified clock-frequency values must be identical. A bus without this
property inherits the shared frequency selected by another available bus.
If neither available bus specifies a frequency, 2500000 Hz is used.
'^mdio-bus@[2-3]$': false
- if:
properties:
compatible:
contains:
enum:
- realtek,rtl9301-mdio
- realtek,rtl9302b-mdio
- realtek,rtl9302c-mdio
- realtek,rtl9303-mdio
- realtek,rtl9311-mdio
- realtek,rtl9312-mdio
- realtek,rtl9313-mdio
then:
patternProperties:
'^mdio-bus@[0-3]$':
properties:
clock-frequency:
enum: [1250000, 2500000, 5000000]
default: 2500000
unevaluatedProperties: false
examples:

View File

@ -123,13 +123,13 @@
#include <linux/of_mdio.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#define RTL8380_NUM_BUSES 1
#define RTL8380_NUM_PAGES 4096
#define RTL8380_NUM_PORTS 28
#define RTL8380_SMI_GLB_CTRL 0xa100
#define RTL8380_SMI_FREQ_SEL BIT(1)
#define RTL8380_SMI_PHY_PATCH_DONE BIT(15)
#define RTL8380_SMI_ACCESS_PHY_CTRL_0 0xa1b8
#define RTL8380_SMI_ACCESS_PHY_CTRL_1 0xa1bc
@ -169,12 +169,15 @@
#define RTL8390_PHYREG_PORT_CTRL_LOW 0x03e4
#define RTL8390_PHYREG_PORT_CTRL_HIGH 0x03e8
#define RTL8390_SMI_PORT_POLLING_CTRL 0x03fc
#define RTL8390_SMI_GLB_CTRL 0x03f8
#define RTL8390_SMI_FREQ_SEL GENMASK(6, 5)
#define RTL9300_NUM_BUSES 4
#define RTL9300_NUM_PAGES 4096
#define RTL9300_NUM_PORTS 28
#define RTL9300_SMI_GLB_CTRL 0xca00
#define RTL9300_GLB_CTRL_INTF_SEL(intf) BIT(16 + (intf))
#define RTL9300_SMI_FREQ_SEL(intf) GENMASK((intf) * 2 + 9, (intf) * 2 + 8)
#define RTL9300_SMI_PORT0_15_POLLING_SEL 0xca08
#define RTL9300_SMI_ACCESS_PHY_CTRL_0 0xcb70
#define RTL9300_SMI_ACCESS_PHY_CTRL_1 0xcb74
@ -196,6 +199,8 @@
#define RTL9310_NUM_BUSES 4
#define RTL9310_NUM_PAGES 8192
#define RTL9310_NUM_PORTS 56
#define RTL9310_SMI_GLB_CTRL0 0x0cc0
#define RTL9310_SMI_FREQ_SEL(intf) GENMASK((intf) * 2 + 5, (intf) * 2 + 4)
#define RTL9310_SMI_GLB_CTRL1 0x0cbc
#define RTL9310_SMI_GLB_FMT_SEL_C45(intf) BIT((intf) * 2 + 1)
#define RTL9310_SMI_INDRT_ACCESS_CTRL_0 0x0c00
@ -271,6 +276,7 @@ struct otto_emdio_info {
u8 num_ports;
u16 num_pages;
u32 poll_ctrl;
int (*set_bus_frequency)(struct mii_bus *bus, u32 freq);
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);
@ -746,6 +752,17 @@ static int otto_emdio_setup_topology(struct otto_emdio_priv *priv)
return 0;
}
static int otto_emdio_8380_set_bus_frequency(struct mii_bus *bus, u32 freq)
{
struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
if (freq != 2500000 && freq != 10000000)
return -EINVAL;
return regmap_assign_bits(priv->regmap, RTL8380_SMI_GLB_CTRL,
RTL8380_SMI_FREQ_SEL, freq == 10000000);
}
static int otto_emdio_8380_setup_controller(struct otto_emdio_priv *priv)
{
/*
@ -755,6 +772,60 @@ static int otto_emdio_8380_setup_controller(struct otto_emdio_priv *priv)
return regmap_set_bits(priv->regmap, RTL8380_SMI_GLB_CTRL, RTL8380_SMI_PHY_PATCH_DONE);
}
static int otto_emdio_8390_set_bus_frequency(struct mii_bus *bus, u32 freq)
{
struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
u32 mdio_bus, child_freq, val;
bool freq_set = false;
int err;
/*
* RTL839x uses one frequency shared by both MDIO buses. Use the frequency passed by the
* caller as fallback, but prefer an explicitly requested frequency from any valid,
* available bus. Reject conflicting explicit requests. Only the first call programs the
* shared frequency.
*/
if (priv->bus[0] || priv->bus[1])
return 0;
for_each_available_child_of_node_scoped(bus->parent->of_node, child) {
err = of_property_read_u32(child, "reg", &mdio_bus);
if (err || mdio_bus >= priv->info->num_buses)
continue;
if (of_property_read_u32(child, "clock-frequency", &child_freq))
continue;
if (freq_set && freq != child_freq)
return -EINVAL;
freq = child_freq;
freq_set = true;
}
if (freq != 1250000 && freq != 2500000 && freq != 5000000)
return -EINVAL;
val = FIELD_PREP(RTL8390_SMI_FREQ_SEL, freq / 2500000);
return regmap_update_bits(priv->regmap, RTL8390_SMI_GLB_CTRL, RTL8390_SMI_FREQ_SEL, val);
}
static int otto_emdio_9300_set_bus_frequency(struct mii_bus *bus, u32 freq)
{
struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
struct otto_emdio_chan *chan = bus->priv;
u32 mask, val;
if (freq != 1250000 && freq != 2500000 && freq != 5000000)
return -EINVAL;
mask = RTL9300_SMI_FREQ_SEL(chan->mdio_bus);
val = field_prep(mask, freq / 2500000);
return regmap_update_bits(priv->regmap, RTL9300_SMI_GLB_CTRL, mask, val);
}
static int otto_emdio_9300_setup_controller(struct otto_emdio_priv *priv)
{
u32 glb_ctrl_mask = 0, glb_ctrl_val = 0;
@ -775,6 +846,21 @@ static int otto_emdio_9300_setup_controller(struct otto_emdio_priv *priv)
return 0;
}
static int otto_emdio_9310_set_bus_frequency(struct mii_bus *bus, u32 freq)
{
struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus);
struct otto_emdio_chan *chan = bus->priv;
u32 mask, val;
if (freq != 1250000 && freq != 2500000 && freq != 5000000)
return -EINVAL;
mask = RTL9310_SMI_FREQ_SEL(chan->mdio_bus);
val = field_prep(mask, freq / 2500000);
return regmap_update_bits(priv->regmap, RTL9310_SMI_GLB_CTRL0, mask, val);
}
static int otto_emdio_9310_setup_controller(struct otto_emdio_priv *priv)
{
int i, err;
@ -837,14 +923,14 @@ static void otto_emdio_notify_phy_detach(struct phy_device *phydev)
}
static int otto_emdio_probe_one(struct device *dev, struct otto_emdio_priv *priv,
struct fwnode_handle *node)
struct device_node *node)
{
struct otto_emdio_chan *chan;
struct mii_bus *bus;
u32 mdio_bus;
u32 mdio_bus, freq;
int err;
err = fwnode_property_read_u32(node, "reg", &mdio_bus);
err = of_property_read_u32(node, "reg", &mdio_bus);
if (err)
return dev_err_probe(dev, err, "undefined smi bus number\n");
@ -852,6 +938,9 @@ static int otto_emdio_probe_one(struct device *dev, struct otto_emdio_priv *priv
return dev_err_probe(dev, -EINVAL,
"illegal (dangling) smi bus number %d\n", mdio_bus);
if (priv->bus[mdio_bus])
return dev_err_probe(dev, -EINVAL, "duplicated smi bus number %d\n", mdio_bus);
bus = devm_mdiobus_alloc_size(dev, sizeof(*chan));
if (!bus)
return -ENOMEM;
@ -871,10 +960,19 @@ static int otto_emdio_probe_one(struct device *dev, struct otto_emdio_priv *priv
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", dev_name(dev), mdio_bus);
err = devm_of_mdiobus_register(dev, bus, to_of_node(node));
if (of_property_read_u32(node, "clock-frequency", &freq))
freq = 2500000;
err = priv->info->set_bus_frequency(bus, freq);
if (err)
return dev_err_probe(dev, err, "cannot set frequency %u for MDIO bus %d\n",
freq, mdio_bus);
err = devm_of_mdiobus_register(dev, bus, node);
if (err)
return dev_err_probe(dev, err, "cannot register MDIO bus\n");
priv->bus[mdio_bus] = bus;
return 0;
}
@ -907,8 +1005,8 @@ static int otto_emdio_map_ports(struct device *dev)
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));
return dev_err_probe(dev, -EINVAL, "%pOFP missing ethernet-ports\n",
parent->of_node);
for_each_available_child_of_node_scoped(ports_dn, port_dn) {
ctrl_dn = NULL;
@ -1008,7 +1106,7 @@ static int otto_emdio_probe(struct platform_device *pdev)
if (err)
return err;
priv->info = device_get_match_data(dev);
priv->info = of_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);
@ -1033,7 +1131,7 @@ static int otto_emdio_probe(struct platform_device *pdev)
return dev_err_probe(dev, err, "failed to setup MDIO bus controller\n");
}
device_for_each_child_node_scoped(dev, child) {
for_each_available_child_of_node_scoped(dev->of_node, child) {
err = otto_emdio_probe_one(dev, priv, child);
if (err)
return err;
@ -1057,6 +1155,7 @@ static const struct otto_emdio_info otto_emdio_8380_info = {
.num_pages = RTL8380_NUM_PAGES,
.num_ports = RTL8380_NUM_PORTS,
.poll_ctrl = RTL8380_SMI_POLL_CTRL,
.set_bus_frequency = otto_emdio_8380_set_bus_frequency,
.setup_controller = otto_emdio_8380_setup_controller,
.read_c22 = otto_emdio_8380_read_c22,
.read_c45 = otto_emdio_8380_read_c45,
@ -1081,6 +1180,7 @@ static const struct otto_emdio_info otto_emdio_8390_info = {
.num_pages = RTL8390_NUM_PAGES,
.num_ports = RTL8390_NUM_PORTS,
.poll_ctrl = RTL8390_SMI_PORT_POLLING_CTRL,
.set_bus_frequency = otto_emdio_8390_set_bus_frequency,
.read_c22 = otto_emdio_8390_read_c22,
.read_c45 = otto_emdio_8390_read_c45,
.write_c22 = otto_emdio_8390_write_c22,
@ -1103,6 +1203,7 @@ static const struct otto_emdio_info otto_emdio_9300_info = {
.num_ports = RTL9300_NUM_PORTS,
.num_pages = RTL9300_NUM_PAGES,
.poll_ctrl = RTL9300_SMI_POLL_CTRL,
.set_bus_frequency = otto_emdio_9300_set_bus_frequency,
.setup_controller = otto_emdio_9300_setup_controller,
.read_c22 = otto_emdio_9300_read_c22,
.read_c45 = otto_emdio_9300_read_c45,
@ -1129,6 +1230,7 @@ static const struct otto_emdio_info otto_emdio_9310_info = {
.num_pages = RTL9310_NUM_PAGES,
.num_ports = RTL9310_NUM_PORTS,
.poll_ctrl = RTL9310_SMI_PORT_POLLING_CTRL,
.set_bus_frequency = otto_emdio_9310_set_bus_frequency,
.setup_controller = otto_emdio_9310_setup_controller,
.read_c22 = otto_emdio_9310_read_c22,
.read_c45 = otto_emdio_9310_read_c45,