In preparation for support of MDIO on AN7581, move the MT7531 logic to a dedicated driver and permit usage of the mdio read/write function to the mtk_eth driver.
Minor changes are required to mtk_eth for this change as the dedicated MDIO driver only needs info of the GSW register and nothing else. 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 <ansuels...@gmail.com> --- drivers/net/Kconfig | 3 + drivers/net/Makefile | 4 + drivers/net/mdio-mt7531.c | 140 +++++++++++++++++++++++++++++++++++ drivers/net/mdio-mt7531.h | 9 +++ drivers/net/mtk_eth/Kconfig | 1 + drivers/net/mtk_eth/mt753x.c | 29 +++----- drivers/net/mtk_eth/mt753x.h | 3 + 7 files changed, 169 insertions(+), 20 deletions(-) create mode 100644 drivers/net/mdio-mt7531.c create mode 100644 drivers/net/mdio-mt7531.h diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index d1cb69f85ad..9ac9bee46c9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -966,6 +966,9 @@ config TSEC_ENET This driver implements support for the (Enhanced) Three-Speed Ethernet Controller found on Freescale SoCs. +config MDIO_MT7531 + bool + source "drivers/net/mtk_eth/Kconfig" config HIFEMAC_ETH diff --git a/drivers/net/Makefile b/drivers/net/Makefile index f8f9a71f815..beb7864adc2 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -62,7 +62,11 @@ obj-$(CONFIG_LITEETH) += liteeth.o obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o obj-$(CONFIG_MDIO_IPQ4019) += mdio-ipq4019.o +<<<<<<< HEAD obj-$(CONFIG_MDIO_GPIO_BITBANG) += mdio_gpio.o +======= +obj-$(CONFIG_MDIO_MT7531) += mdio-mt7531.o +>>>>>>> net: mediatek: move MT7531 mdio to dedicated driver 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.c b/drivers/net/mdio-mt7531.c new file mode 100644 index 00000000000..4772c9b5407 --- /dev/null +++ b/drivers/net/mdio-mt7531.c @@ -0,0 +1,140 @@ +// 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); +} + +int mt7531_mdio_read(struct udevice *dev, int addr, int devad, int reg) +{ + struct mt7531_mdio_priv *priv = dev_get_priv(dev); + 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; +} + +int mt7531_mdio_write(struct udevice *dev, int addr, int devad, + int reg, u16 value) +{ + struct mt7531_mdio_priv *priv = dev_get_priv(dev); + 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; +} + +static const struct mdio_ops mt7531_mdio_ops = { + .read = mt7531_mdio_read, + .write = 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", + .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.h b/drivers/net/mdio-mt7531.h new file mode 100644 index 00000000000..ee096112f92 --- /dev/null +++ b/drivers/net/mdio-mt7531.h @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ + +struct mt7531_mdio_priv { + phys_addr_t switch_regs; +}; + +int mt7531_mdio_read(struct udevice *dev, int addr, int devad, int reg); +int mt7531_mdio_write(struct udevice *dev, int addr, int devad, + int reg, u16 value); diff --git a/drivers/net/mtk_eth/Kconfig b/drivers/net/mtk_eth/Kconfig index e8cdf408237..67b2b612b1a 100644 --- a/drivers/net/mtk_eth/Kconfig +++ b/drivers/net/mtk_eth/Kconfig @@ -4,6 +4,7 @@ config MEDIATEK_ETH select PHYLIB select DM_GPIO select DM_RESET + select MDIO_MT7531 help This Driver support MediaTek Ethernet GMAC Say Y to enable support for the MediaTek Ethernet GMAC. diff --git a/drivers/net/mtk_eth/mt753x.c b/drivers/net/mtk_eth/mt753x.c index cdd52f3ff1b..cf643f336d6 100644 --- a/drivers/net/mtk_eth/mt753x.c +++ b/drivers/net/mtk_eth/mt753x.c @@ -138,8 +138,8 @@ int mt7531_mii_read(struct mt753x_switch_priv *priv, u8 phy, u8 reg) phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy); - return mt7531_mii_rw(priv, phy_addr, reg, 0, MDIO_CMD_READ, - MDIO_ST_C22); + return mt7531_mdio_read(&priv->mdio_priv, phy_addr, MDIO_DEVAD_NONE, + reg); } int mt7531_mii_write(struct mt753x_switch_priv *priv, u8 phy, u8 reg, u16 val) @@ -151,48 +151,36 @@ int mt7531_mii_write(struct mt753x_switch_priv *priv, u8 phy, u8 reg, u16 val) phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy); - return mt7531_mii_rw(priv, phy_addr, reg, val, MDIO_CMD_WRITE, - MDIO_ST_C22); + return mt7531_mdio_write(&priv->mdio_priv, phy_addr, MDIO_DEVAD_NONE, + reg, val); } int mt7531_mmd_read(struct mt753x_switch_priv *priv, u8 addr, u8 devad, u16 reg) { u8 phy_addr; - int ret; if (addr >= MT753X_NUM_PHYS) return -EINVAL; phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr); - ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR, - MDIO_ST_C45); - if (ret) - return ret; - - return mt7531_mii_rw(priv, phy_addr, devad, 0, MDIO_CMD_READ_C45, - MDIO_ST_C45); + return mt7531_mdio_read(&priv->mdio_priv, phy_addr, devad, + reg); } int mt7531_mmd_write(struct mt753x_switch_priv *priv, u8 addr, u8 devad, u16 reg, u16 val) { u8 phy_addr; - int ret; if (addr >= MT753X_NUM_PHYS) return 0; phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr); - ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR, - MDIO_ST_C45); - if (ret) - return ret; - - return mt7531_mii_rw(priv, phy_addr, devad, val, MDIO_CMD_WRITE, - MDIO_ST_C45); + return mt7531_mdio_write(&priv->mdio_priv, phy_addr, devad, + reg, val); } static int mt7531_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) @@ -224,6 +212,7 @@ int mt7531_mdio_register(struct mt753x_switch_priv *priv) if (!mdio_bus) return -ENOMEM; + priv->mdio_priv.switch_regs = priv->epriv.ethsys_base + GSW_BASE; mdio_bus->read = mt7531_mdio_read; mdio_bus->write = mt7531_mdio_write; snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name); diff --git a/drivers/net/mtk_eth/mt753x.h b/drivers/net/mtk_eth/mt753x.h index 65046a1421c..cd128ad39fe 100644 --- a/drivers/net/mtk_eth/mt753x.h +++ b/drivers/net/mtk_eth/mt753x.h @@ -14,6 +14,8 @@ #include <linux/bitops.h> #include <linux/bitfield.h> +#include "../mdio-mt7531.h" + struct mtk_eth_priv; #define MT753X_NUM_PHYS 5 @@ -254,6 +256,7 @@ struct mtk_eth_priv; struct mt753x_switch_priv { struct mtk_eth_switch_priv epriv; + struct mt7531_mdio_priv mdio_priv; struct mii_dev *mdio_bus; u32 smi_addr; u32 phy_base; -- 2.50.0