From 4cc1fe3f5617133e1d5a180f1d62cc987dc4e81d Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 25 Sep 2025 14:44:11 -0600 Subject: arm: socfpga: Tighten a few more driver dependencies Some drivers which depend on SoCFPGA specific headers had not had appropriate dependencies list in Kconfig. Add ARCH_SOCFPGA or TARGET_SOCFPGA_SOC64 where appropriate. Signed-off-by: Tom Rini --- drivers/net/Kconfig | 4 ++-- drivers/power/domain/Kconfig | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 7ae28c4e0d5..c2ef9fb52f7 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -190,7 +190,7 @@ config DWC_ETH_XGMAC_SOCFPGA bool "Synopsys DWC Ethernet XGMAC device support for SOCFPGA" select REGMAP select SYSCON - depends on DWC_ETH_XGMAC + depends on ARCH_SOCFPGA && DWC_ETH_XGMAC default y if TARGET_SOCFPGA_AGILEX5 help The Synopsys Designware Ethernet XGMAC IP block with specific @@ -376,7 +376,7 @@ config ETH_DESIGNWARE_SOCFPGA select SYSCON select DW_ALTDESCRIPTOR bool "Altera SoCFPGA extras for Synopsys Designware Ethernet MAC" - depends on ETH_DESIGNWARE + depends on ARCH_SOCFPGA && ETH_DESIGNWARE help The Altera SoCFPGA requires additional configuration of the Altera system manager to correctly interface with the PHY. diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index ebf5d828cb0..0ad885c9e8b 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -20,7 +20,7 @@ config APPLE_PMGR_POWER_DOMAIN config AGILEX5_PMGR_POWER_DOMAIN bool "Enable the Agilex5 PMGR power domain driver" - depends on SPL_POWER_DOMAIN + depends on SPL_POWER_DOMAIN && TARGET_SOCFPGA_SOC64 help Enable support for power gating peripherals' SRAM specified in the handoff data values obtained from the bitstream to reduce -- cgit v1.2.3 From 772703b77e51f8c1685e7daaa9935dc46b21a30e Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 25 Sep 2025 14:44:14 -0600 Subject: net: Tighten more driver dependencies In this case, the mediatek network drivers cannot build outside of ARCH_MEDIATEK or ARCH_MTMIPS, and so express this requirement in Kconfig as well. In the case of DWC_ETH_XGMAC / DWC_ETH_XGMAC_SOCFPGA, the file controlled by the DWC_ETH_XGMAC option references a socfpga-specific array defined in the file controlled by DWC_ETH_XGMAC_SOCFPGA. Rework these options in Kconfig to handle this dependency. Signed-off-by: Tom Rini --- drivers/net/Kconfig | 5 +++-- drivers/net/mtk_eth/Kconfig | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c2ef9fb52f7..8576b0c3798 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -179,7 +179,7 @@ config CALXEDA_XGMAC machines. config DWC_ETH_XGMAC - bool "Synopsys DWC Ethernet XGMAC device support" + bool select PHYLIB help This driver supports the Synopsys Designware Ethernet XGMAC (10G @@ -190,7 +190,8 @@ config DWC_ETH_XGMAC_SOCFPGA bool "Synopsys DWC Ethernet XGMAC device support for SOCFPGA" select REGMAP select SYSCON - depends on ARCH_SOCFPGA && DWC_ETH_XGMAC + select DWC_ETH_XGMAC + depends on ARCH_SOCFPGA default y if TARGET_SOCFPGA_AGILEX5 help The Synopsys Designware Ethernet XGMAC IP block with specific diff --git a/drivers/net/mtk_eth/Kconfig b/drivers/net/mtk_eth/Kconfig index e8cdf408237..a2060b8bd01 100644 --- a/drivers/net/mtk_eth/Kconfig +++ b/drivers/net/mtk_eth/Kconfig @@ -1,6 +1,7 @@ config MEDIATEK_ETH bool "MediaTek Ethernet GMAC Driver" + depends on ARCH_MEDIATEK || ARCH_MTMIPS select PHYLIB select DM_GPIO select DM_RESET -- cgit v1.2.3 From 83633e5774a107315f33ee7800a647b74854d48f Mon Sep 17 00:00:00 2001 From: Beiyan Yun Date: Tue, 23 Sep 2025 15:12:58 +0800 Subject: net: phy: aquantia: switch to use phy_get_ofnode() Use PHY API phy_get_ofnode() helper to get PHY DT node. Signed-off-by: Beiyan Yun --- drivers/net/phy/aquantia.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index f63a13824ca..903fcd667f6 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -338,7 +338,7 @@ static int aquantia_set_proto(struct phy_device *phydev, static int aquantia_dts_config(struct phy_device *phydev) { - ofnode node = phydev->node; + ofnode node = phy_get_ofnode(phydev); u32 prop; u16 reg; -- cgit v1.2.3 From 9b2e1079e7db35155710a401eb52007abe449ad7 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 20 Sep 2025 18:09:41 +0200 Subject: net: mediatek: mt7531/7988: fix broken PHY turn ON/OFF The PHY for MT7531/MT7988 are never actully turned ON/OFF for the affected PHY as we are read/writing to the wrong PHY address. This is caused by the fact that we use the MT753X_PHY_ADDR macro 2 times offsetting the address multiple times. One in the _setup() function and one in the mt7531_mii_read/write. Drop the additional usage of MT753X_PHY_ADDR in setup() to correctly set the PHY. Signed-off-by: Christian Marangi --- drivers/net/mtk_eth/mt7531.c | 20 +++++++------------- drivers/net/mtk_eth/mt7988.c | 12 +++++------- 2 files changed, 12 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mtk_eth/mt7531.c b/drivers/net/mtk_eth/mt7531.c index 32d6bebbbdb..965bc3cb7e9 100644 --- a/drivers/net/mtk_eth/mt7531.c +++ b/drivers/net/mtk_eth/mt7531.c @@ -22,17 +22,13 @@ static int mt7531_core_reg_read(struct mt753x_switch_priv *priv, u32 reg) { - u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0); - - return mt7531_mmd_read(priv, phy_addr, 0x1f, reg); + return mt7531_mmd_read(priv, 0, 0x1f, reg); } static void mt7531_core_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 val) { - u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0); - - mt7531_mmd_write(priv, phy_addr, 0x1f, reg, val); + mt7531_mmd_write(priv, 0, 0x1f, reg, val); } static void mt7531_core_pll_setup(struct mt753x_switch_priv *priv) @@ -171,7 +167,7 @@ static int mt7531_setup(struct mtk_eth_switch_priv *swpriv) { struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; u32 i, val, pmcr, port5_sgmii; - u16 phy_addr, phy_val; + u16 phy_val; priv->smi_addr = MT753X_DFL_SMI_ADDR; priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK; @@ -180,10 +176,9 @@ static int mt7531_setup(struct mtk_eth_switch_priv *swpriv) /* Turn off PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); - phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); + phy_val = mt7531_mii_read(priv, i, MII_BMCR); phy_val |= BMCR_PDOWN; - mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); + mt7531_mii_write(priv, i, MII_BMCR, phy_val); } /* Force MAC link down before reset */ @@ -239,10 +234,9 @@ static int mt7531_setup(struct mtk_eth_switch_priv *swpriv) /* Turn on PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); - phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); + phy_val = mt7531_mii_read(priv, i, MII_BMCR); phy_val &= ~BMCR_PDOWN; - mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); + mt7531_mii_write(priv, i, MII_BMCR, phy_val); } mt7531_phy_setting(priv); diff --git a/drivers/net/mtk_eth/mt7988.c b/drivers/net/mtk_eth/mt7988.c index a416d87840c..87b6ed30cd0 100644 --- a/drivers/net/mtk_eth/mt7988.c +++ b/drivers/net/mtk_eth/mt7988.c @@ -61,7 +61,7 @@ static void mt7988_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable) static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) { struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; - u16 phy_addr, phy_val; + u16 phy_val; u32 pmcr; int i; @@ -72,10 +72,9 @@ static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) /* Turn off PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); - phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); + phy_val = mt7531_mii_read(priv, i, MII_BMCR); phy_val |= BMCR_PDOWN; - mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); + mt7531_mii_write(priv, i, MII_BMCR, phy_val); } switch (priv->epriv.phy_interface) { @@ -128,10 +127,9 @@ static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) /* Turn on PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); - phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); + phy_val = mt7531_mii_read(priv, i, MII_BMCR); phy_val &= ~BMCR_PDOWN; - mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); + mt7531_mii_write(priv, i, MII_BMCR, phy_val); } mt7988_phy_setting(priv); -- cgit v1.2.3 From 85f3d070e27c3024c6d2c58ecbfd0ecb2343cc0c Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 20 Sep 2025 18:09:42 +0200 Subject: net: mediatek: mt7988: restore PHY page on PHY setting exit On exiting the phy_setting function for MT7988, the PHY page is never restored to Page 0. This can cause all kind of problem with reading the status of the PHY at runtime. Correctly restore PHY page on exiting the PHY setting function. Signed-off-by: Christian Marangi --- drivers/net/mtk_eth/mt7988.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mtk_eth/mt7988.c b/drivers/net/mtk_eth/mt7988.c index 87b6ed30cd0..06bbe049da3 100644 --- a/drivers/net/mtk_eth/mt7988.c +++ b/drivers/net/mtk_eth/mt7988.c @@ -34,8 +34,10 @@ static void mt7988_phy_setting(struct mt753x_switch_priv *priv) u32 i; for (i = 0; i < MT753X_NUM_PHYS; i++) { - /* Enable HW auto downshift */ + /* Set PHY to PHY page 1 */ mt7531_mii_write(priv, i, 0x1f, 0x1); + + /* Enable HW auto downshift */ val = mt7531_mii_read(priv, i, PHY_EXT_REG_14); val |= PHY_EN_DOWN_SHFIT; mt7531_mii_write(priv, i, PHY_EXT_REG_14, val); @@ -44,6 +46,9 @@ static void mt7988_phy_setting(struct mt753x_switch_priv *priv) val = mt7531_mii_read(priv, i, PHY_EXT_REG_17); val |= PHY_LINKDOWN_POWER_SAVING_EN; mt7531_mii_write(priv, i, PHY_EXT_REG_17, val); + + /* Restore PHY to PHY page 0 */ + mt7531_mii_write(priv, i, 0x1f, 0x0); } } -- cgit v1.2.3 From ca4264db44c1ece69d208f63c4bfe607c60751d9 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 20 Sep 2025 18:09:43 +0200 Subject: net: mediatek: mt7988: free allocated MDIO bus on cleanup Correctly free the MDIO Bus on calling cleanup function. While at it also fix a copy-paste error and rename the cleanup function name to the more specific name. Signed-off-by: Christian Marangi --- drivers/net/mtk_eth/mt7988.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mtk_eth/mt7988.c b/drivers/net/mtk_eth/mt7988.c index 06bbe049da3..b77660be55c 100644 --- a/drivers/net/mtk_eth/mt7988.c +++ b/drivers/net/mtk_eth/mt7988.c @@ -142,11 +142,13 @@ static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) return mt7531_mdio_register(priv); } -static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv) +static int mt7988_cleanup(struct mtk_eth_switch_priv *swpriv) { struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; + struct mii_dev *mdio_bus = priv->mdio_bus; - mdio_unregister(priv->mdio_bus); + mdio_unregister(mdio_bus); + mdio_free(mdio_bus); return 0; } @@ -158,6 +160,6 @@ MTK_ETH_SWITCH(mt7988) = { .reset_wait_time = 50, .setup = mt7988_setup, - .cleanup = mt7531_cleanup, + .cleanup = mt7988_cleanup, .mac_control = mt7988_mac_control, }; -- cgit v1.2.3 From b24268d151a0c28772785e14703491364becda5b Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 20 Sep 2025 18:09:44 +0200 Subject: net: mediatek: move MT7531 MMIO MDIO to dedicated driver In preparation for support of MDIO on AN7581, move the MT7531 MMIO logic to a dedicated driver and permit usage of the mdio read/write function to the mtk_eth driver. This only affect MT7988 that can use MMIO operation to access the Switch register. The MT7988 code is updated to make use of the external driver. This permits Airoha driver to make use of DM_MDIO to bind for the MT7531 driver that have the same exact register. Signed-off-by: Christian Marangi --- drivers/net/Kconfig | 3 + drivers/net/Makefile | 1 + drivers/net/mdio-mt7531-mmio.c | 168 +++++++++++++++++++++++++++++++++++++++++ drivers/net/mdio-mt7531-mmio.h | 9 +++ drivers/net/mtk_eth/Kconfig | 1 + drivers/net/mtk_eth/mt7988.c | 85 +++++++++++++++++---- 6 files changed, 254 insertions(+), 13 deletions(-) create mode 100644 drivers/net/mdio-mt7531-mmio.c create mode 100644 drivers/net/mdio-mt7531-mmio.h (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8576b0c3798..c9b35b5a2ff 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -967,6 +967,9 @@ config TSEC_ENET This driver implements support for the (Enhanced) Three-Speed Ethernet Controller found on Freescale SoCs. +config MDIO_MT7531_MMIO + bool + source "drivers/net/mtk_eth/Kconfig" config HIFEMAC_ETH diff --git a/drivers/net/Makefile b/drivers/net/Makefile index f8f9a71f815..a3c3420898c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o obj-$(CONFIG_MDIO_IPQ4019) += mdio-ipq4019.o obj-$(CONFIG_MDIO_GPIO_BITBANG) += mdio_gpio.o +obj-$(CONFIG_MDIO_MT7531_MMIO) += mdio-mt7531-mmio.o obj-$(CONFIG_MDIO_MUX_I2CREG) += mdio_mux_i2creg.o obj-$(CONFIG_MDIO_MUX_MESON_G12A) += mdio_mux_meson_g12a.o obj-$(CONFIG_MDIO_MUX_MESON_GXL) += mdio_mux_meson_gxl.o diff --git a/drivers/net/mdio-mt7531-mmio.c b/drivers/net/mdio-mt7531-mmio.c new file mode 100644 index 00000000000..3e325ca58da --- /dev/null +++ b/drivers/net/mdio-mt7531-mmio.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include +#include + +#define MT7531_PHY_IAC 0x701c +#define MT7531_PHY_ACS_ST BIT(31) +#define MT7531_MDIO_REG_ADDR_CL22 GENMASK(29, 25) +#define MT7531_MDIO_DEV_ADDR MT7531_MDIO_REG_ADDR_CL22 +#define MT7531_MDIO_PHY_ADDR GENMASK(24, 20) +#define MT7531_MDIO_CMD GENMASK(19, 18) +#define MT7531_MDIO_CMD_READ_CL45 FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x3) +#define MT7531_MDIO_CMD_READ_CL22 FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x2) +#define MT7531_MDIO_CMD_WRITE FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x1) +#define MT7531_MDIO_CMD_ADDR FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x0) +#define MT7531_MDIO_ST GENMASK(17, 16) +#define MT7531_MDIO_ST_CL22 FIELD_PREP_CONST(MT7531_MDIO_ST, 0x1) +#define MT7531_MDIO_ST_CL45 FIELD_PREP_CONST(MT7531_MDIO_ST, 0x0) +#define MT7531_MDIO_RW_DATA GENMASK(15, 0) +#define MT7531_MDIO_REG_ADDR_CL45 MT7531_MDIO_RW_DATA + +#define MT7531_MDIO_TIMEOUT 100000 +#define MT7531_MDIO_SLEEP 20 + +struct mt7531_mdio_priv { + phys_addr_t switch_regs; +}; + +static int mt7531_mdio_wait_busy(struct mt7531_mdio_priv *priv) +{ + unsigned int busy; + + return readl_poll_sleep_timeout(priv->switch_regs + MT7531_PHY_IAC, + busy, (busy & MT7531_PHY_ACS_ST) == 0, + MT7531_MDIO_SLEEP, MT7531_MDIO_TIMEOUT); +} + +static int mt7531_mdio_read(struct mt7531_mdio_priv *priv, int addr, int devad, int reg) +{ + u32 val; + + if (devad != MDIO_DEVAD_NONE) { + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = MT7531_PHY_ACS_ST | + MT7531_MDIO_ST_CL45 | MT7531_MDIO_CMD_ADDR | + FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr) | + FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad) | + FIELD_PREP(MT7531_MDIO_REG_ADDR_CL45, reg); + + writel(val, priv->switch_regs + MT7531_PHY_IAC); + } + + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = MT7531_PHY_ACS_ST | FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr); + if (devad != MDIO_DEVAD_NONE) + val |= MT7531_MDIO_ST_CL45 | MT7531_MDIO_CMD_READ_CL45 | + FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad); + else + val |= MT7531_MDIO_ST_CL22 | MT7531_MDIO_CMD_READ_CL22 | + FIELD_PREP(MT7531_MDIO_REG_ADDR_CL22, reg); + + writel(val, priv->switch_regs + MT7531_PHY_IAC); + + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = readl(priv->switch_regs + MT7531_PHY_IAC); + return val & MT7531_MDIO_RW_DATA; +} + +static int mt7531_mdio_write(struct mt7531_mdio_priv *priv, int addr, int devad, + int reg, u16 value) +{ + u32 val; + + if (devad != MDIO_DEVAD_NONE) { + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = MT7531_PHY_ACS_ST | + MT7531_MDIO_ST_CL45 | MT7531_MDIO_CMD_ADDR | + FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr) | + FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad) | + FIELD_PREP(MT7531_MDIO_REG_ADDR_CL45, reg); + + writel(val, priv->switch_regs + MT7531_PHY_IAC); + } + + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = MT7531_PHY_ACS_ST | FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr) | + MT7531_MDIO_CMD_WRITE | FIELD_PREP(MT7531_MDIO_RW_DATA, value); + if (devad != MDIO_DEVAD_NONE) + val |= MT7531_MDIO_ST_CL45 | + FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad); + else + val |= MT7531_MDIO_ST_CL22 | + FIELD_PREP(MT7531_MDIO_REG_ADDR_CL22, reg); + + writel(val, priv->switch_regs + MT7531_PHY_IAC); + + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + return 0; +} + +int mt7531_mdio_mmio_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + struct mt7531_mdio_priv *priv = bus->priv; + + return mt7531_mdio_read(priv, addr, devad, reg); +} + +int mt7531_mdio_mmio_write(struct mii_dev *bus, int addr, int devad, + int reg, u16 value) +{ + struct mt7531_mdio_priv *priv = bus->priv; + + return mt7531_mdio_write(priv, addr, devad, reg, value); +} + +static int dm_mt7531_mdio_read(struct udevice *dev, int addr, int devad, int reg) +{ + struct mt7531_mdio_priv *priv = dev_get_priv(dev); + + return mt7531_mdio_read(priv, addr, devad, reg); +} + +static int dm_mt7531_mdio_write(struct udevice *dev, int addr, int devad, + int reg, u16 value) +{ + struct mt7531_mdio_priv *priv = dev_get_priv(dev); + + return mt7531_mdio_write(priv, addr, devad, reg, value); +} + +static const struct mdio_ops mt7531_mdio_ops = { + .read = dm_mt7531_mdio_read, + .write = dm_mt7531_mdio_write, +}; + +static int mt7531_mdio_probe(struct udevice *dev) +{ + struct mt7531_mdio_priv *priv = dev_get_priv(dev); + + priv->switch_regs = dev_read_addr(dev); + if (priv->switch_regs == FDT_ADDR_T_NONE) + return -EINVAL; + + return 0; +} + +U_BOOT_DRIVER(mt7531_mdio) = { + .name = "mt7531-mdio-mmio", + .id = UCLASS_MDIO, + .probe = mt7531_mdio_probe, + .ops = &mt7531_mdio_ops, + .priv_auto = sizeof(struct mt7531_mdio_priv), +}; diff --git a/drivers/net/mdio-mt7531-mmio.h b/drivers/net/mdio-mt7531-mmio.h new file mode 100644 index 00000000000..f98102cb939 --- /dev/null +++ b/drivers/net/mdio-mt7531-mmio.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +struct mt7531_mdio_mmio_priv { + phys_addr_t switch_regs; +}; + +int mt7531_mdio_mmio_read(struct mii_dev *bus, int addr, int devad, int reg); +int mt7531_mdio_mmio_write(struct mii_dev *bus, int addr, int devad, + int reg, u16 value); diff --git a/drivers/net/mtk_eth/Kconfig b/drivers/net/mtk_eth/Kconfig index a2060b8bd01..5d4e54ab90e 100644 --- a/drivers/net/mtk_eth/Kconfig +++ b/drivers/net/mtk_eth/Kconfig @@ -31,6 +31,7 @@ config MTK_ETH_SWITCH_MT7531 config MTK_ETH_SWITCH_MT7988 bool "Support for MediaTek MT7988 built-in ethernet switch" depends on TARGET_MT7988 + select MDIO_MT7531_MMIO default y config MTK_ETH_SWITCH_AN8855 diff --git a/drivers/net/mtk_eth/mt7988.c b/drivers/net/mtk_eth/mt7988.c index b77660be55c..29b6363cbd7 100644 --- a/drivers/net/mtk_eth/mt7988.c +++ b/drivers/net/mtk_eth/mt7988.c @@ -6,6 +6,7 @@ * Author: Mark Lee */ +#include #include #include #include @@ -14,6 +15,8 @@ #include "mtk_eth.h" #include "mt753x.h" +#include "../mdio-mt7531-mmio.h" + static int mt7988_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data) { *data = readl(priv->epriv.ethsys_base + GSW_BASE + reg); @@ -30,25 +33,34 @@ static int mt7988_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data) static void mt7988_phy_setting(struct mt753x_switch_priv *priv) { + struct mii_dev *mdio_bus = priv->mdio_bus; u16 val; u32 i; for (i = 0; i < MT753X_NUM_PHYS; i++) { + u16 addr = MT753X_PHY_ADDR(priv->phy_base, i); + /* Set PHY to PHY page 1 */ - mt7531_mii_write(priv, i, 0x1f, 0x1); + mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE, + 0x1f, 0x1); /* Enable HW auto downshift */ - val = mt7531_mii_read(priv, i, PHY_EXT_REG_14); + val = mt7531_mdio_mmio_read(mdio_bus, addr, MDIO_DEVAD_NONE, + PHY_EXT_REG_14); val |= PHY_EN_DOWN_SHFIT; - mt7531_mii_write(priv, i, PHY_EXT_REG_14, val); + mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE, + PHY_EXT_REG_14, val); /* PHY link down power saving enable */ - val = mt7531_mii_read(priv, i, PHY_EXT_REG_17); + val = mt7531_mdio_mmio_read(mdio_bus, addr, MDIO_DEVAD_NONE, + PHY_EXT_REG_17); val |= PHY_LINKDOWN_POWER_SAVING_EN; - mt7531_mii_write(priv, i, PHY_EXT_REG_17, val); + mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE, + PHY_EXT_REG_17, val); /* Restore PHY to PHY page 0 */ - mt7531_mii_write(priv, i, 0x1f, 0x0); + mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE, + 0x1f, 0x0); } } @@ -63,23 +75,66 @@ static void mt7988_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable) mt7988_reg_write(priv, PMCR_REG(6), pmcr); } +static int mt7988_mdio_register(struct mt753x_switch_priv *priv) +{ + struct mt7531_mdio_mmio_priv *mdio_priv; + struct mii_dev *mdio_bus = mdio_alloc(); + int ret; + + if (!mdio_bus) + return -ENOMEM; + + mdio_priv = malloc(sizeof(*mdio_priv)); + if (!mdio_priv) + return -ENOMEM; + + mdio_priv->switch_regs = (phys_addr_t)priv->epriv.ethsys_base + GSW_BASE; + + mdio_bus->read = mt7531_mdio_mmio_read; + mdio_bus->write = mt7531_mdio_mmio_write; + snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name); + + mdio_bus->priv = mdio_priv; + + ret = mdio_register(mdio_bus); + if (ret) { + free(mdio_bus->priv); + mdio_free(mdio_bus); + return ret; + } + + priv->mdio_bus = mdio_bus; + + return 0; +} + static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) { struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; - u16 phy_val; + struct mii_dev *mdio_bus; + u16 phy_addr, phy_val; + int ret, i; u32 pmcr; - int i; priv->smi_addr = MT753X_DFL_SMI_ADDR; priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK; priv->reg_read = mt7988_reg_read; priv->reg_write = mt7988_reg_write; + ret = mt7988_mdio_register(priv); + if (ret) + return ret; + + mdio_bus = priv->mdio_bus; + /* Turn off PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_val = mt7531_mii_read(priv, i, MII_BMCR); + phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); + phy_val = mt7531_mdio_mmio_read(mdio_bus, phy_addr, + MDIO_DEVAD_NONE, MII_BMCR); phy_val |= BMCR_PDOWN; - mt7531_mii_write(priv, i, MII_BMCR, phy_val); + mt7531_mdio_mmio_write(mdio_bus, phy_addr, MDIO_DEVAD_NONE, + MII_BMCR, phy_val); } switch (priv->epriv.phy_interface) { @@ -132,14 +187,17 @@ static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) /* Turn on PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_val = mt7531_mii_read(priv, i, MII_BMCR); + phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); + phy_val = mt7531_mdio_mmio_read(mdio_bus, phy_addr, + MDIO_DEVAD_NONE, MII_BMCR); phy_val &= ~BMCR_PDOWN; - mt7531_mii_write(priv, i, MII_BMCR, phy_val); + mt7531_mdio_mmio_write(mdio_bus, phy_addr, MDIO_DEVAD_NONE, + MII_BMCR, phy_val); } mt7988_phy_setting(priv); - return mt7531_mdio_register(priv); + return 0; } static int mt7988_cleanup(struct mtk_eth_switch_priv *swpriv) @@ -148,6 +206,7 @@ static int mt7988_cleanup(struct mtk_eth_switch_priv *swpriv) struct mii_dev *mdio_bus = priv->mdio_bus; mdio_unregister(mdio_bus); + free(mdio_bus->priv); mdio_free(mdio_bus); return 0; -- cgit v1.2.3 From ec127937199d7ec7116f07bb1642565ab6671a36 Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Wed, 8 Oct 2025 10:31:38 +0300 Subject: net: airoha: simplify rx/free packet logic a bit The commit 997786bbf473 ("drivers/net/airoha_eth: fix stalling in package receiving") can be improved. Instead of returning previous descriptor it's possible: * do nothing in even descriptor case * return 2 descriptor to the queue (current and previous) in the odd descriptor case. This patch: * implements above approach * remove logic not required within new approach * adds note that PKTBUFSRX must be even and larger than 7 for reliable driver operations Signed-off-by: Mikhail Kshevetskiy --- drivers/net/airoha_eth.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/airoha_eth.c b/drivers/net/airoha_eth.c index 6588eb3a806..19c3d60044c 100644 --- a/drivers/net/airoha_eth.c +++ b/drivers/net/airoha_eth.c @@ -449,14 +449,10 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q, RX_RING_SIZE_MASK, FIELD_PREP(RX_RING_SIZE_MASK, ndesc)); - /* - * See arht_eth_free_pkt() for the reasons used to fill - * REG_RX_CPU_IDX(qid) register. - */ airoha_qdma_rmw(qdma, REG_RX_RING_SIZE(qid), RX_RING_THR_MASK, FIELD_PREP(RX_RING_THR_MASK, 0)); airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK, - FIELD_PREP(RX_RING_CPU_IDX_MASK, q->ndesc - 3)); + FIELD_PREP(RX_RING_CPU_IDX_MASK, q->ndesc - 1)); airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK, FIELD_PREP(RX_RING_DMA_IDX_MASK, q->head)); @@ -920,7 +916,6 @@ static int arht_eth_free_pkt(struct udevice *dev, uchar *packet, int length) struct airoha_qdma *qdma = ð->qdma[0]; struct airoha_queue *q; int qid; - u16 prev, pprev; if (!packet) return 0; @@ -930,22 +925,29 @@ static int arht_eth_free_pkt(struct udevice *dev, uchar *packet, int length) /* * Due to cpu cache issue the airoha_qdma_reset_rx_desc() function - * will always touch 2 descriptors: - * - if current descriptor is even, then the previous and the one - * before previous descriptors will be touched (previous cacheline) - * - if current descriptor is odd, then only current and previous - * descriptors will be touched (current cacheline) + * will always touch 2 descriptors placed on the same cacheline: + * - if current descriptor is even, then current and next + * descriptors will be touched + * - if current descriptor is odd, then current and previous + * descriptors will be touched * - * Thus, to prevent possible destroying of rx queue, only (q->ndesc - 2) - * descriptors might be used for packet receiving. + * Thus, to prevent possible destroying of rx queue, we should: + * - do nothing in the even descriptor case, + * - utilize 2 descriptors (current and previous one) in the + * odd descriptor case. + * + * WARNING: Observations shows that PKTBUFSRX must be even and + * larger than 7 for reliable driver operations. */ - prev = (q->head + q->ndesc - 1) % q->ndesc; - pprev = (q->head + q->ndesc - 2) % q->ndesc; - q->head = (q->head + 1) % q->ndesc; + if (q->head & 0x01) { + airoha_qdma_reset_rx_desc(q, q->head - 1); + airoha_qdma_reset_rx_desc(q, q->head); - airoha_qdma_reset_rx_desc(q, prev); - airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK, - FIELD_PREP(RX_RING_CPU_IDX_MASK, pprev)); + airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK, + FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head)); + } + + q->head = (q->head + 1) % q->ndesc; return 0; } -- cgit v1.2.3 From 34369d34e413ac32a131dd144b55ad04873e4854 Mon Sep 17 00:00:00 2001 From: "Lucien.Jheng" Date: Mon, 6 Oct 2025 20:49:15 +0800 Subject: net: phy: add paged PHY register accessors Synchronize paged PHY helpers with Linux v6.17. Add support for PHY devices that use paged register access by implementing the following functions: - phy_save_page(): Save current page number - phy_select_page(): Switch to a specific page and return previous page - phy_restore_page(): Restore previously saved page Also adds read_page and write_page callbacks to the phy_driver structure to enable driver-specific page handling. These helpers allow safe access to paged PHY registers by ensuring proper page selection and restoration, even in error conditions, which will be used by the Airoha PHY driver. Signed-off-by: Lucien.Jheng --- drivers/net/phy/phy.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 9702d042296..b58283fe3d5 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1250,3 +1250,116 @@ bool phy_interface_is_ncsi(void) return 0; #endif } + +/** + * __phy_read_page() - read the current page + * @phydev: a pointer to a &struct phy_device + * + * Returns page index or < 0 on error + */ +static int __phy_read_page(struct phy_device *phydev) +{ + struct phy_driver *drv = phydev->drv; + + if (!drv->read_page) { + debug("read_page callback not available, PHY driver not loaded?\n"); + return -EOPNOTSUPP; + } + + return drv->read_page(phydev); +} + +/** + * __phy_write_page() - Write a new page + * @phydev: a pointer to a &struct phy_device + * @page: page index to select + * + * Returns 0 or < 0 on error. + */ +static int __phy_write_page(struct phy_device *phydev, int page) +{ + struct phy_driver *drv = phydev->drv; + + if (!drv->write_page) { + debug("write_page callback not available, PHY driver not loaded?\n"); + return -EOPNOTSUPP; + } + + return drv->write_page(phydev, page); +} + +/** + * phy_save_page() - save the current page + * @phydev: a pointer to a &struct phy_device + * + * Return the current page number. On error, + * returns a negative errno. phy_restore_page() must always be called + * after this, irrespective of success or failure of this call. + */ +int phy_save_page(struct phy_device *phydev) +{ + return __phy_read_page(phydev); +} + +/** + * phy_select_page - Switch to a PHY page and return the previous page + * @phydev: a pointer to a &struct phy_device + * @page: desired page + * + * NOTE: Save the current PHY page, and set the current page. + * On error, returns a negative errno, otherwise returns the previous page number. + * phy_restore_page() must always be called after this, irrespective + * of success or failure of this call. + */ +int phy_select_page(struct phy_device *phydev, int page) +{ + int ret, oldpage; + + oldpage = ret = phy_save_page(phydev); + if (ret < 0) + return ret; + + if (oldpage != page) { + ret = __phy_write_page(phydev, page); + if (ret < 0) + return ret; + } + + return oldpage; +} + +/** + * phy_restore_page - Restore a previously saved page and propagate status + * @phydev: a pointer to a &struct phy_device + * @oldpage: the old page, return value from phy_save_page() or phy_select_page() + * @ret: operation's return code + * + * Restoring @oldpage if it is a valid page. + * This function propagates the earliest error code from the group of + * operations. + * + * Returns: + * @oldpage if it was a negative value, otherwise + * @ret if it was a negative errno value, otherwise + * phy_write_page()'s negative value if it were in error, otherwise + * @ret. + */ +int phy_restore_page(struct phy_device *phydev, int oldpage, int ret) +{ + int r; + + if (oldpage >= 0) { + r = __phy_write_page(phydev, oldpage); + + /* Propagate the operation return code if the page write + * was successful. + */ + if (ret >= 0 && r < 0) + ret = r; + } else { + /* Propagate the phy page selection error code */ + ret = oldpage; + } + + return ret; +} \ No newline at end of file -- cgit v1.2.3 From 85c2c2c517ac8a6bba406bfd84fa11b26bbcb9aa Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Fri, 10 Oct 2025 11:36:33 -0600 Subject: net: phy: Make driver overloading get_phy_id depend on !COMPILE_TEST With commit 597fe041a85f ("net/phy: enable get_phy_id redefinable") we made get_phy_id a public but weak function, so that PHY drivers that had required non-standard ways of getting the PHY ID could be supported. However, overloading a weak function multiple times is (rightly) a link error. At this point, we have two PHYs which make use of this feature, so make both of them only available when COMPILE_TEST is unset, as part of being able to support "allyesconfig" in the future. Signed-off-by: Tom Rini --- drivers/net/phy/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 185c6a3156e..018be98705a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -56,6 +56,7 @@ endif # B53_SWITCH config MV88E61XX_SWITCH bool "Marvell MV88E61xx Ethernet switch PHY support." + depends on !COMPILE_TEST if MV88E61XX_SWITCH @@ -119,6 +120,7 @@ config PHY_BROADCOM config PHY_CORTINA bool "Cortina Ethernet PHYs support" + depends on !COMPILE_TEST config SYS_CORTINA_NO_FW_UPLOAD bool "Cortina firmware loading support" -- cgit v1.2.3 From ed6ec8d1ca0658d811df1cc78d06fec4f7f69fc9 Mon Sep 17 00:00:00 2001 From: Jim Liu Date: Tue, 14 Oct 2025 13:20:05 +0800 Subject: net: designware: fix bitbang init error The Synchronous Abort and reset errors occurred due to incorrect parameter passing during initialization. Signed-off-by: Jim Liu [jf: add missing #if IS_ENABLED(CONFIG_BITBANGMII)] Signed-off-by: Jerome Forissier --- drivers/net/designware.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 2fd92cf16bb..6ed9c6d538a 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -125,6 +125,16 @@ static int dw_mdio_reset(struct mii_dev *bus) return __dw_mdio_reset(dev); } + +#if IS_ENABLED(CONFIG_BITBANGMII) +static int dw_bb_mdio_reset(struct mii_dev *bus) +{ + struct dw_eth_dev *priv = bus->priv; + + return __dw_mdio_reset(priv->dev); +} +#endif + #endif #if IS_ENABLED(CONFIG_DM_MDIO) @@ -348,7 +358,7 @@ static int dw_bb_mdio_init(const char *name, struct udevice *dev) bus->read = dw_bb_miiphy_read; bus->write = dw_bb_miiphy_write; #if CONFIG_IS_ENABLED(DM_GPIO) - bus->reset = dw_mdio_reset; + bus->reset = dw_bb_mdio_reset; #endif bus->priv = dwpriv; -- cgit v1.2.3