From 8db554dcbb2374a2dea130af56d781732070beb7 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 30 Sep 2025 10:05:10 +0200 Subject: net: mdio-uclass: introduce dm_eth_phy_connect_interface() dm_eth_phy_connect_interface() is a variant of dm_eth_phy_connect() that allows to set the used PHY mode, in case the MAC driver needs to fix it up. The previously static dm_eth_connect_phy_handle() is renamed and extended for this purpose. Signed-off-by: Matthias Schiffer --- include/miiphy.h | 15 +++++++++++++++ net/mdio-uclass.c | 18 ++++++------------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/include/miiphy.h b/include/miiphy.h index 00d0b9b6a43..96afe5f4030 100644 --- a/include/miiphy.h +++ b/include/miiphy.h @@ -192,6 +192,21 @@ struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, struct udevice *ethdev, phy_interface_t interface); +/** + * dm_eth_phy_connect_interface - Connect an Eth device to a PHY based on device + * tree with custom PHY interface + * + * Picks up the DT phy-handle and from ethernet device node and connects the + * ethernet device to the linked PHY, while allowing the caller to specify + * the phy-mode to use. + * + * @ethdev: ethernet device + * @interface: MAC-PHY protocol + * + * Return: pointer to phy_device, or 0 on error + */ +struct phy_device *dm_eth_phy_connect_interface(struct udevice *ethdev, + phy_interface_t interface); /** * dm_eth_phy_connect - Connect an Eth device to a PHY based on device tree * diff --git a/net/mdio-uclass.c b/net/mdio-uclass.c index 4f052ae432c..64af689d2df 100644 --- a/net/mdio-uclass.c +++ b/net/mdio-uclass.c @@ -242,8 +242,8 @@ struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, return phy_connect(pdata->mii_bus, phyaddr, ethdev, interface); } -static struct phy_device *dm_eth_connect_phy_handle(struct udevice *ethdev, - phy_interface_t interface) +struct phy_device *dm_eth_phy_connect_interface(struct udevice *ethdev, + phy_interface_t interface) { u32 phy_addr; struct udevice *mdiodev; @@ -282,8 +282,10 @@ static struct phy_device *dm_eth_connect_phy_handle(struct udevice *ethdev, phy = dm_mdio_phy_connect(mdiodev, phy_addr, ethdev, interface); out: - if (phy) + if (phy) { phy->node = phynode; + phy->interface = interface; + } return phy; } @@ -292,7 +294,6 @@ out: struct phy_device *dm_eth_phy_connect(struct udevice *ethdev) { phy_interface_t interface; - struct phy_device *phy; if (!dev_has_ofnode(ethdev)) { debug("%s: supplied eth dev has no DT node!\n", ethdev->name); @@ -303,14 +304,7 @@ struct phy_device *dm_eth_phy_connect(struct udevice *ethdev) if (interface == PHY_INTERFACE_MODE_NA) dev_dbg(ethdev, "can't find interface mode, default to NA\n"); - phy = dm_eth_connect_phy_handle(ethdev, interface); - - if (!phy) - return NULL; - - phy->interface = interface; - - return phy; + return dm_eth_phy_connect_interface(ethdev, interface); } UCLASS_DRIVER(mdio) = { -- cgit v1.3.1 From 4b10bcfdef9cb544ca80988fe36d307a622bcd21 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 30 Sep 2025 10:05:11 +0200 Subject: net: ethernet: ti: am65-cpsw: fix up PHY mode for fixed RGMII TX delay The am65-cpsw driver currently sets the SEL_RGMII_IDMODE flag in a MAC's mode register to enable or disable the TX delay. While this was supported for earlier generations of the CPSW controller, the datasheets of all modern TI SoCs using the am65-cpsw MAC state that the TX delay is fixed, and the SEL_RGMII_IDMODE bit is documented as reserved in most of them. Furthermore, while it was found that this bit does in fact disable the TX delay, [1] states that this setting is truly unsupported by TI and not just undocumented. Following the clarification of the rgmii* phy-mode values in the Linux DT bindings in [2], the Linux am65-cpsw driver was changed in [3] to account for the fixed TX delay by fixing up the mode passed to the PHY driver; a similar fixup already existed in the TI icssg-prueth driver. [4] followed up on this by explicitly clearing the SEL_RGMII_IDMODE flag to handle the case where it is set by the bootloader or other firmware before Linux. With the above changes, Device Trees that set the recommended "rgmii-id" mode are now appearing in Linux 6.17+. Avoid setting the unsupported SEL_RGMII_IDMODE flag for such Device Trees, and instead fix up the PHY interface mode, thus aligning the U-Boot driver with the Linux kernel. [1] https://www.spinics.net/lists/netdev/msg1112647.html [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c360eb0c3ccb95306704fd221442283ee82f1f58 [3] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ca13b249f291f4920466638d1adbfb3f9c8db6e9 [4] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a22d3b0d49d411e64ed07e30c2095035ecb30ed2 Signed-off-by: Matthias Schiffer --- drivers/net/ti/am65-cpsw-nuss.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c index 2aa7e5e3a30..7a88f76fd09 100644 --- a/drivers/net/ti/am65-cpsw-nuss.c +++ b/drivers/net/ti/am65-cpsw-nuss.c @@ -234,14 +234,11 @@ out: #define AM65_GMII_SEL_MODE_RGMII 2 #define AM65_GMII_SEL_MODE_SGMII 3 -#define AM65_GMII_SEL_RGMII_IDMODE BIT(4) - static int am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv, phy_interface_t phy_mode) { struct udevice *dev = priv->dev; u32 offset, reg, phandle; - bool rgmii_id = false; fdt_addr_t gmii_sel; u32 mode = 0; ofnode node; @@ -278,12 +275,6 @@ static int am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv, mode = AM65_GMII_SEL_MODE_RGMII; break; - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_TXID: - mode = AM65_GMII_SEL_MODE_RGMII; - rgmii_id = true; - break; - case PHY_INTERFACE_MODE_SGMII: mode = AM65_GMII_SEL_MODE_SGMII; break; @@ -298,9 +289,6 @@ static int am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv, break; }; - if (rgmii_id) - mode |= AM65_GMII_SEL_RGMII_IDMODE; - reg = mode; dev_dbg(dev, "gmii_sel PHY mode: %u, new gmii_sel: %08x\n", phy_mode, reg); @@ -630,7 +618,7 @@ static int am65_cpsw_phy_init(struct udevice *dev) u32 supported = PHY_GBIT_FEATURES; int ret = 0; - phydev = dm_eth_phy_connect(dev); + phydev = dm_eth_phy_connect_interface(dev, pdata->phy_interface); if (!phydev) { dev_err(dev, "phy_connect() failed\n"); return -ENODEV; @@ -657,9 +645,28 @@ static int am65_cpsw_ofdata_parse_phy(struct udevice *dev) dev_read_u32(dev, "reg", &priv->port_id); pdata->phy_interface = dev_read_phy_mode(dev); - if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) { + + /* CPSW controllers supported by this driver have a fixed internal TX + * delay in RGMII mode. Fix up PHY mode to account for this and warn + * about Device Trees that claim to have a TX delay on the PCB. + */ + switch (pdata->phy_interface) { + case PHY_INTERFACE_MODE_RGMII_ID: + pdata->phy_interface = PHY_INTERFACE_MODE_RGMII_RXID; + break; + case PHY_INTERFACE_MODE_RGMII_TXID: + pdata->phy_interface = PHY_INTERFACE_MODE_RGMII; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_RXID: + dev_warn(dev, + "RGMII mode without internal TX delay unsupported; please fix your Device Tree\n"); + break; + case PHY_INTERFACE_MODE_NA: dev_err(dev, "Invalid PHY mode, port %u\n", priv->port_id); return -EINVAL; + default: + break; } dev_read_u32(dev, "max-speed", (u32 *)&pdata->max_speed); -- cgit v1.3.1