]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
net: mediatek: move MT7531 MMIO MDIO to dedicated driver
authorChristian Marangi <ansuelsmth@gmail.com>
Sat, 20 Sep 2025 16:09:44 +0000 (18:09 +0200)
committerJerome Forissier <jerome.forissier@linaro.org>
Wed, 22 Oct 2025 09:16:10 +0000 (11:16 +0200)
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 <ansuelsmth@gmail.com>
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/mdio-mt7531-mmio.c [new file with mode: 0644]
drivers/net/mdio-mt7531-mmio.h [new file with mode: 0644]
drivers/net/mtk_eth/Kconfig
drivers/net/mtk_eth/mt7988.c

index 8576b0c3798e2d6b2dccb5394bc5e5de8912d11e..c9b35b5a2ffc2fe6b78be034625a125f60a777db 100644 (file)
@@ -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
index f8f9a71f815385257ed2c80419c96026f60740b7..a3c3420898ce620dba4f52a0cfcfd7f73e48b699 100644 (file)
@@ -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 (file)
index 0000000..3e325ca
--- /dev/null
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <asm/io.h>
+#include <dm.h>
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+#include <miiphy.h>
+
+#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 (file)
index 0000000..f98102c
--- /dev/null
@@ -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);
index a2060b8bd01e715e2280f620e585013958ce29ce..5d4e54ab90e7207d173696fdd54111b40c1a6b59 100644 (file)
@@ -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
index b77660be55c2287d292c27e043607dd98ec872d0..29b6363cbd71662a761c2b92a5ff36360e76cde7 100644 (file)
@@ -6,6 +6,7 @@
  * Author: Mark Lee <mark-mc.lee@mediatek.com>
  */
 
+#include <malloc.h>
 #include <miiphy.h>
 #include <linux/delay.h>
 #include <linux/mdio.h>
@@ -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;