From: Bastien Curutchet (Schneider Electric) Date: Mon, 8 Jun 2026 14:10:12 +0000 (+0200) Subject: net: dsa: microchip: implement lan937x-specific MDIO registration X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=03d10c776802ba627191a3ab622f59af5def08b5;p=thirdparty%2Flinux.git net: dsa: microchip: implement lan937x-specific MDIO registration All the switches use a common mdio_register() function that uses two ksz_dev_ops callbacks (.mdio_bus_preinit() and .create_phy_addr_map()) to handle the lan937x specific case. These two callbacks are used only at this place in the code. Implement a new lan937x-specific MDIO registration functions that uses these two lan937x-specific functions. The lan937x bindings don't have any 'interrupts' property so this lan937x_mdio_register() doesn't call ksz_irq_phy_setup(). Expose the common ksz_*_mdio_{read/write} functions so they can be used in lan937x.c Remove the callbacks from ksz_dev_ops. Signed-off-by: Bastien Curutchet (Schneider Electric) Link: https://patch.msgid.link/20260608-clean-ksz-3rd-v2-9-6e61b7be23c4@bootlin.com Signed-off-by: Jakub Kicinski --- diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 7dc8e4ffacdd..d08659ffa442 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2256,7 +2256,7 @@ static void ksz_update_port_member(struct ksz_device *dev, int port) dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port); } -static int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) +int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) { struct ksz_device *dev = bus->priv; struct dsa_switch *ds = dev->ds; @@ -2264,8 +2264,7 @@ static int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) return ds->ops->phy_read(ds, addr, regnum); } -static int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, - u16 val) +int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val) { struct ksz_device *dev = bus->priv; struct dsa_switch *ds = dev->ds; @@ -2286,7 +2285,7 @@ static int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, * * Return: Value of the PHY register, or a negative error code on failure. */ -static int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum) +int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum) { struct ksz_device *dev = bus->priv; @@ -2306,8 +2305,7 @@ static int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum) * * Return: 0 on success, or a negative error code on failure. */ -static int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum, - u16 val) +int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val) { struct ksz_device *dev = bus->priv; @@ -2415,8 +2413,8 @@ static void ksz_irq_phy_free(struct ksz_device *dev) * * Return: 0 on success, or a negative error code on failure. */ -static int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus, - struct device_node *mdio_np) +int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus, + struct device_node *mdio_np) { struct device_node *phy_node, *phy_parent_node; bool phys_are_valid = true; @@ -2519,20 +2517,8 @@ int ksz_mdio_register(struct ksz_device *dev) goto put_mdio_node; } - if (dev->dev_ops->mdio_bus_preinit) { - ret = dev->dev_ops->mdio_bus_preinit(dev, !!parent_bus); - if (ret) - goto put_mdio_node; - } - - if (dev->dev_ops->create_phy_addr_map) { - ret = dev->dev_ops->create_phy_addr_map(dev, !!parent_bus); - if (ret) - goto put_mdio_node; - } else { - for (i = 0; i < dev->info->port_cnt; i++) - dev->phy_addr_map[i] = i; - } + for (i = 0; i < dev->info->port_cnt; i++) + dev->phy_addr_map[i] = i; bus->priv = dev; if (parent_bus) { diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index bdc93f2855c7..0c10cd5775bc 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -366,42 +366,6 @@ struct ksz_dev_ops { u32 (*get_port_addr)(int port, int offset); void (*cfg_port_member)(struct ksz_device *dev, int port, u8 member); - /** - * @mdio_bus_preinit: Function pointer to pre-initialize the MDIO bus - * for accessing PHYs. - * @dev: Pointer to device structure. - * @side_mdio: Boolean indicating if the PHYs are accessed over a side - * MDIO bus. - * - * This function pointer is used to configure the MDIO bus for PHY - * access before initiating regular PHY operations. It enables either - * SPI/I2C or side MDIO access modes by unlocking necessary registers - * and setting up access permissions for the selected mode. - * - * Return: - * - 0 on success. - * - Negative error code on failure. - */ - int (*mdio_bus_preinit)(struct ksz_device *dev, bool side_mdio); - - /** - * @create_phy_addr_map: Function pointer to create a port-to-PHY - * address map. - * @dev: Pointer to device structure. - * @side_mdio: Boolean indicating if the PHYs are accessed over a side - * MDIO bus. - * - * This function pointer is responsible for mapping switch ports to PHY - * addresses according to the configured access mode (SPI or side MDIO) - * and the device’s strap configuration. The mapping setup may vary - * depending on the chip variant and configuration. Ensures the correct - * address mapping for PHY communication. - * - * Return: - * - 0 on success. - * - Negative error code on failure (e.g., invalid configuration). - */ - int (*create_phy_addr_map)(struct ksz_device *dev, bool side_mdio); void (*r_mib_cnt)(struct ksz_device *dev, int port, u16 addr, u64 *cnt); void (*r_mib_pkt)(struct ksz_device *dev, int port, u16 addr, @@ -498,6 +462,12 @@ int ksz_port_set_mac_address(struct dsa_switch *ds, int port, int ksz_suspend(struct dsa_switch *ds); int ksz_resume(struct dsa_switch *ds); +int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus, + struct device_node *mdio_np); +int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum); +int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val); +int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum); +int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val); int ksz_mdio_register(struct ksz_device *dev); int ksz_pirq_setup(struct ksz_device *dev, u8 p); int ksz_girq_setup(struct ksz_device *dev); diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index d45798de4ce9..48cd367455c3 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -669,6 +670,101 @@ static int lan937x_switch_init(struct ksz_device *dev) return 0; } +/** + * lan937x_mdio_register - Register and configure the MDIO bus for the LAN937x. + * @dev: Pointer to the KSZ device structure. + * + * This function sets up and registers an MDIO bus for a LAN937x switch, + * allowing access to its internal PHYs. If the device supports side MDIO, + * the function will configure the external MDIO controller specified by the + * "mdio-parent-bus" device tree property to directly manage internal PHYs. + * Otherwise, SPI or I2C access is set up for PHY access. + * + * Return: 0 on success, or a negative error code on failure. + */ +static int lan937x_mdio_register(struct ksz_device *dev) +{ + struct device_node *parent_bus_node; + struct mii_bus *parent_bus = NULL; + struct dsa_switch *ds = dev->ds; + struct device_node *mdio_np; + struct mii_bus *bus; + int ret; + + mdio_np = of_get_child_by_name(dev->dev->of_node, "mdio"); + if (!mdio_np) + return 0; + + parent_bus_node = of_parse_phandle(mdio_np, "mdio-parent-bus", 0); + if (parent_bus_node && !dev->info->phy_side_mdio_supported) { + dev_err(dev->dev, "Side MDIO bus is not supported for this HW, ignoring 'mdio-parent-bus' property.\n"); + ret = -EINVAL; + + goto put_mdio_node; + } else if (parent_bus_node) { + parent_bus = of_mdio_find_bus(parent_bus_node); + if (!parent_bus) { + ret = -EPROBE_DEFER; + + goto put_mdio_node; + } + + dev->parent_mdio_bus = parent_bus; + } + + bus = devm_mdiobus_alloc(ds->dev); + if (!bus) { + ret = -ENOMEM; + goto put_mdio_node; + } + + ret = lan937x_mdio_bus_preinit(dev, !!parent_bus); + if (ret) + goto put_mdio_node; + + ret = lan937x_create_phy_addr_map(dev, !!parent_bus); + if (ret) + goto put_mdio_node; + + bus->priv = dev; + if (parent_bus) { + bus->read = ksz_parent_mdio_read; + bus->write = ksz_parent_mdio_write; + bus->name = "KSZ side MDIO"; + snprintf(bus->id, MII_BUS_ID_SIZE, "ksz-side-mdio-%d", + ds->index); + } else { + bus->read = ksz_sw_mdio_read; + bus->write = ksz_sw_mdio_write; + bus->name = "ksz user smi"; + if (ds->dst->index != 0) + snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d-%d", + ds->dst->index, ds->index); + else + snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index); + } + + ret = ksz_parse_dt_phy_config(dev, bus, mdio_np); + if (ret) + goto put_mdio_node; + + ds->phys_mii_mask = bus->phy_mask; + bus->parent = ds->dev; + + ds->user_mii_bus = bus; + + ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np); + if (ret) + dev_err(ds->dev, "unable to register MDIO bus %s\n", + bus->id); + +put_mdio_node: + of_node_put(mdio_np); + of_node_put(parent_bus_node); + + return ret; +} + static int lan937x_setup(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; @@ -782,7 +878,7 @@ static int lan937x_setup(struct dsa_switch *ds) goto port_release; } - ret = ksz_mdio_register(dev); + ret = lan937x_mdio_register(dev); if (ret < 0) { dev_err(dev->dev, "failed to register the mdio"); goto out_ptp_clock_unregister; @@ -845,8 +941,6 @@ const struct phylink_mac_ops lan937x_phylink_mac_ops = { const struct ksz_dev_ops lan937x_dev_ops = { .get_port_addr = ksz9477_get_port_addr, .cfg_port_member = ksz9477_cfg_port_member, - .mdio_bus_preinit = lan937x_mdio_bus_preinit, - .create_phy_addr_map = lan937x_create_phy_addr_map, .r_mib_cnt = ksz9477_r_mib_cnt, .r_mib_pkt = ksz9477_r_mib_pkt, .r_mib_stat64 = ksz_r_mib_stats64,