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 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(). 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 --- drivers/net/mdio/mdio-realtek-rtl9300.c | 70 ++++++++++++++++--------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index 74ea2550e652..9f67d8dd4185 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -56,7 +56,7 @@ #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_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) @@ -74,7 +74,7 @@ #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 RTL9300_SMI_PORT0_5_ADDR_CTRL 0xcb80 #define MAX_PORTS 28 #define MAX_SMI_BUSSES 4 @@ -89,6 +89,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,24 +329,46 @@ static int otto_emdio_write_c45(struct mii_bus *bus, int phy_id, 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 ports_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 % ports_per_reg) * bits_per_val; + u32 reg = base + (port / ports_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) { + /* 16 ports per register, 2 bits per port (bus index 0-3) */ + ret = otto_emdio_write_mapping(priv, info->bus_map_base, port, + 16, 2, priv->smi_bus[port]); + if (ret) + return ret; + } + if (info->addr_map_base) { + /* 6 ports per register, 5 bits per port (PHY address 0-31) */ + ret = otto_emdio_write_mapping(priv, info->addr_map_base, port, + 6, 5, 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); @@ -352,16 +376,6 @@ static int otto_emdio_9300_mdiobus_init(struct otto_emdio_priv *priv) 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) @@ -534,6 +548,10 @@ static int otto_emdio_probe(struct platform_device *pdev) 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) @@ -548,6 +566,8 @@ static int otto_emdio_probe(struct platform_device *pdev) } 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, -- 2.54.0