The Ethernet MDIO controllers in Realtek Otto switches use an MDC clock frequency of 2.5 MHz by default. Hardware configuration fields allow the following frequencies to be selected: - RTL838x: 2.5 MHz or 10 MHz - RTL839x, RTL930x and RTL931x: 1.25 MHz, 2.5 MHz or 5 MHz Add support for configuring the MDC frequency through the clock-frequency property of each MDIO bus node. Lower frequencies can simplify protocol analysis with a logic analyzer, while higher frequencies reduce MDIO transaction times during normal operation. Program the frequency selector during every probe. If clock-frequency is absent, select the defined default of 2.5 MHz. This matches the configuration observed with a protocol analyzer under the stock firmware or after issuing "rtk network on" in the bootloader. RTL839x is an exception because both MDIO buses share a single frequency field. Use an explicitly specified frequency as the shared frequency and let buses without the property inherit it. Use the 2.5 MHz default if neither bus specifies a frequency. Reject conflicting explicit frequencies because the hardware cannot configure them independently. Signed-off-by: Markus Stockhausen Reviewed-by: Andrew Lunn --- drivers/net/mdio/mdio-realtek-rtl9300.c | 100 +++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index 63ffb7f82b98..eb7a6238dbd1 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -129,6 +129,7 @@ #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 @@ -168,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 @@ -195,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 @@ -270,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); @@ -745,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) { /* @@ -754,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; @@ -774,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; @@ -840,7 +927,7 @@ static int otto_emdio_probe_one(struct device *dev, struct otto_emdio_priv *priv { struct otto_emdio_chan *chan; struct mii_bus *bus; - u32 mdio_bus; + u32 mdio_bus, freq; int err; err = of_property_read_u32(node, "reg", &mdio_bus); @@ -873,6 +960,13 @@ 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); + 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"); @@ -1061,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, @@ -1085,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, @@ -1107,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, @@ -1133,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, -- 2.55.0