From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 976B03D45EA for ; Mon, 8 Jun 2026 14:10:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780927836; cv=none; b=cskJr5tb4+Var7rFz0kj4de7EVfcdi9Gcp1HvigoaAnou8uaZocBKgXqOJe9aA3RunDC04Ct7CSWgB90AKn2upEr6DqkO6+TPUZ89PkkjILFe2dl/GpVz7aWA+j7JJkKbq6gVkTPdSdQzhRlB51hkkgphKj78/KYnS1e8nZR/dk= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780927836; c=relaxed/simple; bh=W6m8HZei4UV+niYNkVAEOJU75DypSdLg91CvhywA2DQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HOmhV6G7nRZ6dF/iSRO8buzmcPIrwRYWo8/9k8ESiTH77Zhq+Hnw12u4Qrrl8VVCnlnt6ycKsgiEFDBkKLkk+V53Gsafj8H0GyHQKHEst4fns/8+NKQkHCIoDX65D7Jhm0Qc5T+D7hWcijVD+FfuA5ITRSEuK6+ilx4ATDgWM20= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=wycQx5zy; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="wycQx5zy" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 4B012C5147F; Mon, 8 Jun 2026 14:10:34 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 41B295FFB7; Mon, 8 Jun 2026 14:10:33 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 20538106A2976; Mon, 8 Jun 2026 16:10:31 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1780927832; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=RzyrL2uKbcB+VzpygJToWwpY8lqohI8R5nq0G/jrPgE=; b=wycQx5zyfPmZlAAZjGbyccLA9TIJTwnmajHusCDVmsSUIqQOEkvR2bWbdSgYwTN8R//DKL k+U32hNuk66XzrAWidWZt0gceQctB0OYHH5wYODGayzLJGbAy0qciWGypuBdJgqbqPWE8/ Ph4F/QaCAHy/aTpQqa/qhXBMvQ2yt8+5nK4BPuAbYyDi7rC/oNKl+98hUxpBoMWbJIZBJD MQ9OR9FEUwFV5xuRRf17AX5UPSHzrMgeDhOPkFJVSb0JY0qtFE6/ki1RQWAyKkxZROeGTH PqSz6BNOOdAU2+Pw71bZzYdV8hntzhHjnt8f1kKORuERLaHtLezu2++6E2YGZQ== From: "Bastien Curutchet (Schneider Electric)" Date: Mon, 08 Jun 2026 16:10:12 +0200 Subject: [PATCH net-next v2 09/10] net: dsa: microchip: implement lan937x-specific MDIO registration Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit Message-Id: <20260608-clean-ksz-3rd-v2-9-6e61b7be23c4@bootlin.com> References: <20260608-clean-ksz-3rd-v2-0-6e61b7be23c4@bootlin.com> In-Reply-To: <20260608-clean-ksz-3rd-v2-0-6e61b7be23c4@bootlin.com> To: Woojung Huh , UNGLinuxDriver@microchip.com, Andrew Lunn , Vladimir Oltean , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Russell King Cc: Pascal Eberhard , =?utf-8?q?Miqu=C3=A8l_Raynal?= , Thomas Petazzoni , Tristram Ha , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, "Bastien Curutchet (Schneider Electric)" X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 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) --- drivers/net/dsa/microchip/ksz_common.c | 30 +++------- drivers/net/dsa/microchip/ksz_common.h | 42 ++----------- drivers/net/dsa/microchip/lan937x_main.c | 100 ++++++++++++++++++++++++++++++- 3 files changed, 111 insertions(+), 61 deletions(-) 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 2c118eaddd75..7b9a12648e85 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -362,42 +362,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, @@ -494,6 +458,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, -- 2.54.0