Hello. This patch caused a build conflict with ARCH_AM33XX. Probably ARCH_OMAP3 should be replaced with ARCH_OMAP. PATH=$PATH:/usr/local/usr5/bin CROSS_COMPILE=arm-buildroot-linux-gnueabihf- make ARCH=arm mm_am335x_defconfig WARNING: unmet direct dependencies detected for DRIVER_NET_TI_DAVINCI_MDIO Depends on [n]: NET [=y] && (ARCH_OMAP3 [=n] || ARCH_K3 [=n] || COMPILE_TEST [ =n]) Selected by [y]: - DRIVER_NET_CPSW [=y] && NET [=y] && ARCH_OMAP [=y] WARNING: unmet direct dependencies detected for DRIVER_NET_TI_DAVINCI_MDIO Depends on [n]: NET [=y] && (ARCH_OMAP3 [=n] || ARCH_K3 [=n] || COMPILE_TEST [ =n]) Selected by [y]: - DRIVER_NET_CPSW [=y] && NET [=y] && ARCH_OMAP [=y] пт, 8 нояб. 2024 г. в 16:15, Sascha Hauer <s.hauer@xxxxxxxxxxxxxx>: > > The davinci MDIO driver can be reused for the CPSW found on TI K3 SoCs > which needs a new ethernet driver. Separate the MDIO driver from the > CPSW driver to make it usable with other ethernet drivers. > > Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> > --- > drivers/net/Kconfig | 5 ++ > drivers/net/Makefile | 1 + > drivers/net/cpsw.c | 178 ------------------------------------------ > drivers/net/davinci_mdio.c | 188 +++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 194 insertions(+), 178 deletions(-) > > diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig > index 13e9ff6924..7f0d277548 100644 > --- a/drivers/net/Kconfig > +++ b/drivers/net/Kconfig > @@ -53,8 +53,13 @@ config DRIVER_NET_CS8900 > config DRIVER_NET_CPSW > bool "CPSW ethernet driver" > depends on ARCH_OMAP > + select DRIVER_NET_TI_DAVINCI_MDIO > select PHYLIB > > +config DRIVER_NET_TI_DAVINCI_MDIO > + bool "TI Davinci MDIO driver" > + depends on ARCH_OMAP3 || COMPILE_TEST > + > config DRIVER_NET_DAVINCI_EMAC > bool "TI Davinci/OMAP EMAC ethernet driver" > depends on ARCH_OMAP3 > diff --git a/drivers/net/Makefile b/drivers/net/Makefile > index 207345cfa3..b451813f7c 100644 > --- a/drivers/net/Makefile > +++ b/drivers/net/Makefile > @@ -10,6 +10,7 @@ obj-$(CONFIG_DRIVER_NET_BCMGENET) += bcmgenet.o > obj-$(CONFIG_DRIVER_NET_CS8900) += cs8900.o > obj-$(CONFIG_DRIVER_NET_CPSW) += cpsw.o > obj-$(CONFIG_DRIVER_NET_DAVINCI_EMAC) += davinci_emac.o > +obj-$(CONFIG_DRIVER_NET_TI_DAVINCI_MDIO) += davinci_mdio.o > obj-$(CONFIG_DRIVER_NET_DESIGNWARE) += designware.o > obj-$(CONFIG_DRIVER_NET_DESIGNWARE_GENERIC) += designware_generic.o > obj-$(CONFIG_DRIVER_NET_DESIGNWARE_SOCFPGA) += designware_socfpga.o > diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c > index 3e4f6502f9..b11930fdd0 100644 > --- a/drivers/net/cpsw.c > +++ b/drivers/net/cpsw.c > @@ -28,8 +28,6 @@ > #define CPSW_VERSION_2 0x19010c > > #define BITMASK(bits) ((1 << (bits)) - 1) > -#define PHY_REG_MASK 0x1f > -#define PHY_ID_MASK 0x1f > #define NUM_DESCS (PKTBUFSRX * 2) > #define PKT_MIN 60 > #define PKT_MAX (1500 + 14 + 4 + 4) > @@ -60,34 +58,6 @@ > > #define SLIVER_SIZE 0x40 > > -struct cpsw_mdio_regs { > - u32 version; > - u32 control; > -#define CONTROL_IDLE (1 << 31) > -#define CONTROL_ENABLE (1 << 30) > - > - u32 alive; > - u32 link; > - u32 linkintraw; > - u32 linkintmasked; > - u32 __reserved_0[2]; > - u32 userintraw; > - u32 userintmasked; > - u32 userintmaskset; > - u32 userintmaskclr; > - u32 __reserved_1[20]; > - > - struct { > - u32 access; > - u32 physel; > -#define USERACCESS_GO (1 << 31) > -#define USERACCESS_WRITE (1 << 30) > -#define USERACCESS_ACK (1 << 29) > -#define USERACCESS_READ (0) > -#define USERACCESS_DATA (0xffff) > - } user[0]; > -}; > - > struct cpsw_regs { > u32 id_ver; > u32 control; > @@ -226,12 +196,6 @@ struct cpsw_priv { > struct cpsw_slave *slaves; > }; > > -struct cpsw_mdio_priv { > - struct device *dev; > - struct mii_bus miibus; > - struct cpsw_mdio_regs *mdio_regs; > -}; > - > static int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) > { > int idx; > @@ -524,148 +488,6 @@ static inline void cpsw_ale_port_state(struct cpsw_priv *priv, int port, > writel(tmp, priv->ale_regs + offset); > } > > -/* wait until hardware is ready for another user access */ > -static u32 wait_for_user_access(struct cpsw_mdio_priv *priv) > -{ > - struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs; > - u32 tmp; > - uint64_t start = get_time_ns(); > - > - do { > - tmp = readl(&mdio_regs->user[0].access); > - > - if (!(tmp & USERACCESS_GO)) > - break; > - > - if (is_timeout(start, 100 * MSECOND)) { > - dev_err(priv->dev, "timeout waiting for user access\n"); > - break; > - } > - } while (1); > - > - return tmp; > -} > - > -static int cpsw_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg) > -{ > - struct cpsw_mdio_priv *priv = bus->priv; > - struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs; > - > - u32 tmp; > - > - if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK) > - return -EINVAL; > - > - wait_for_user_access(priv); > - > - tmp = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) | > - (phy_id << 16)); > - writel(tmp, &mdio_regs->user[0].access); > - > - tmp = wait_for_user_access(priv); > - > - return (tmp & USERACCESS_ACK) ? (tmp & USERACCESS_DATA) : -1; > -} > - > -static int cpsw_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg, u16 value) > -{ > - struct cpsw_mdio_priv *priv = bus->priv; > - struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs; > - u32 tmp; > - > - if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK) > - return -EINVAL; > - > - wait_for_user_access(priv); > - tmp = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) | > - (phy_id << 16) | (value & USERACCESS_DATA)); > - writel(tmp, &mdio_regs->user[0].access); > - wait_for_user_access(priv); > - > - return 0; > -} > - > -static int cpsw_mdio_probe(struct device *dev) > -{ > - struct resource *iores; > - struct cpsw_mdio_priv *priv; > - uint64_t start; > - uint32_t phy_mask; > - int ret; > - > - priv = xzalloc(sizeof(*priv)); > - > - /* If we can't request I/O memory region, we'll assume parent did > - * it for us > - */ > - iores = dev_request_mem_resource(dev, 0); > - if (IS_ERR(iores) && PTR_ERR(iores) == -EBUSY) > - iores = dev_get_resource(dev, IORESOURCE_MEM, 0); > - if (IS_ERR(iores)) > - return PTR_ERR(iores); > - priv->mdio_regs = IOMEM(iores->start); > - priv->miibus.read = cpsw_mdio_read; > - priv->miibus.write = cpsw_mdio_write; > - priv->miibus.priv = priv; > - priv->miibus.parent = dev; > - > - /* > - * set enable and clock divider > - * > - * FIXME: Use a clock to calculate the divider > - */ > - writel(0xff | CONTROL_ENABLE, &priv->mdio_regs->control); > - > - /* > - * wait for scan logic to settle: > - * the scan time consists of (a) a large fixed component, and (b) a > - * small component that varies with the mii bus frequency. These > - * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x > - * silicon. Since the effect of (b) was found to be largely > - * negligible, we keep things simple here. > - */ > - udelay(2000); > - > - start = get_time_ns(); > - while (1) { > - phy_mask = readl(&priv->mdio_regs->alive); > - if (phy_mask) { > - dev_info(dev, "detected phy mask 0x%x\n", phy_mask); > - phy_mask = ~phy_mask; > - break; > - } > - if (is_timeout(start, 256 * MSECOND)) { > - dev_err(dev, "no live phy, scanning all\n"); > - phy_mask = 0; > - break; > - } > - } > - > - priv->miibus.phy_mask = phy_mask; > - > - ret = mdiobus_register(&priv->miibus); > - if (ret) > - return ret; > - > - return 0; > -} > - > -static __maybe_unused struct of_device_id cpsw_mdio_dt_ids[] = { > - { > - .compatible = "ti,cpsw-mdio", > - }, { > - /* sentinel */ > - } > -}; > -MODULE_DEVICE_TABLE(of, cpsw_mdio_dt_ids); > - > -static struct driver cpsw_mdio_driver = { > - .name = "cpsw-mdio", > - .probe = cpsw_mdio_probe, > - .of_compatible = DRV_OF_COMPAT(cpsw_mdio_dt_ids), > -}; > -coredevice_platform_driver(cpsw_mdio_driver); > - > static inline void soft_reset(struct cpsw_priv *priv, void *reg) > { > int ret; > diff --git a/drivers/net/davinci_mdio.c b/drivers/net/davinci_mdio.c > new file mode 100644 > index 0000000000..c5cd28fba4 > --- /dev/null > +++ b/drivers/net/davinci_mdio.c > @@ -0,0 +1,188 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * DaVinci MDIO Module driver > + */ > +#include <driver.h> > +#include <linux/phy.h> > +#include <clock.h> > +#include <xfuncs.h> > +#include <io.h> > + > +#define PHY_REG_MASK 0x1f > +#define PHY_ID_MASK 0x1f > + > +struct cpsw_mdio_regs { > + u32 version; > + u32 control; > +#define CONTROL_IDLE (1 << 31) > +#define CONTROL_ENABLE (1 << 30) > + > + u32 alive; > + u32 link; > + u32 linkintraw; > + u32 linkintmasked; > + u32 __reserved_0[2]; > + u32 userintraw; > + u32 userintmasked; > + u32 userintmaskset; > + u32 userintmaskclr; > + u32 __reserved_1[20]; > + > + struct { > + u32 access; > + u32 physel; > +#define USERACCESS_GO (1 << 31) > +#define USERACCESS_WRITE (1 << 30) > +#define USERACCESS_ACK (1 << 29) > +#define USERACCESS_READ (0) > +#define USERACCESS_DATA (0xffff) > + } user[0]; > +}; > + > +struct cpsw_mdio_priv { > + struct device *dev; > + struct mii_bus miibus; > + struct cpsw_mdio_regs *mdio_regs; > +}; > + > +/* wait until hardware is ready for another user access */ > +static u32 wait_for_user_access(struct cpsw_mdio_priv *priv) > +{ > + struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs; > + u32 tmp; > + uint64_t start = get_time_ns(); > + > + do { > + tmp = readl(&mdio_regs->user[0].access); > + > + if (!(tmp & USERACCESS_GO)) > + break; > + > + if (is_timeout(start, 100 * MSECOND)) { > + dev_err(priv->dev, "timeout waiting for user access\n"); > + break; > + } > + } while (1); > + > + return tmp; > +} > + > +static int cpsw_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg) > +{ > + struct cpsw_mdio_priv *priv = bus->priv; > + struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs; > + > + u32 tmp; > + > + if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK) > + return -EINVAL; > + > + wait_for_user_access(priv); > + > + tmp = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) | > + (phy_id << 16)); > + writel(tmp, &mdio_regs->user[0].access); > + > + tmp = wait_for_user_access(priv); > + > + return (tmp & USERACCESS_ACK) ? (tmp & USERACCESS_DATA) : -1; > +} > + > +static int cpsw_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg, u16 value) > +{ > + struct cpsw_mdio_priv *priv = bus->priv; > + struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs; > + u32 tmp; > + > + if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK) > + return -EINVAL; > + > + wait_for_user_access(priv); > + tmp = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) | > + (phy_id << 16) | (value & USERACCESS_DATA)); > + writel(tmp, &mdio_regs->user[0].access); > + wait_for_user_access(priv); > + > + return 0; > +} > + > +static int cpsw_mdio_probe(struct device *dev) > +{ > + struct resource *iores; > + struct cpsw_mdio_priv *priv; > + uint64_t start; > + uint32_t phy_mask; > + int ret; > + > + priv = xzalloc(sizeof(*priv)); > + > + /* If we can't request I/O memory region, we'll assume parent did > + * it for us > + */ > + iores = dev_request_mem_resource(dev, 0); > + if (IS_ERR(iores) && PTR_ERR(iores) == -EBUSY) > + iores = dev_get_resource(dev, IORESOURCE_MEM, 0); > + if (IS_ERR(iores)) > + return PTR_ERR(iores); > + priv->mdio_regs = IOMEM(iores->start); > + priv->miibus.read = cpsw_mdio_read; > + priv->miibus.write = cpsw_mdio_write; > + priv->miibus.priv = priv; > + priv->miibus.parent = dev; > + > + /* > + * set enable and clock divider > + * > + * FIXME: Use a clock to calculate the divider > + */ > + writel(0xff | CONTROL_ENABLE, &priv->mdio_regs->control); > + > + /* > + * wait for scan logic to settle: > + * the scan time consists of (a) a large fixed component, and (b) a > + * small component that varies with the mii bus frequency. These > + * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x > + * silicon. Since the effect of (b) was found to be largely > + * negligible, we keep things simple here. > + */ > + udelay(2000); > + > + start = get_time_ns(); > + while (1) { > + phy_mask = readl(&priv->mdio_regs->alive); > + if (phy_mask) { > + dev_info(dev, "detected phy mask 0x%x\n", phy_mask); > + phy_mask = ~phy_mask; > + break; > + } > + if (is_timeout(start, 256 * MSECOND)) { > + dev_err(dev, "no live phy, scanning all\n"); > + phy_mask = 0; > + break; > + } > + } > + > + priv->miibus.phy_mask = phy_mask; > + > + ret = mdiobus_register(&priv->miibus); > + if (ret) > + return ret; > + > + return 0; > +} > + > +static __maybe_unused struct of_device_id cpsw_mdio_dt_ids[] = { > + { > + .compatible = "ti,cpsw-mdio", > + }, { > + /* sentinel */ > + } > +}; > +MODULE_DEVICE_TABLE(of, cpsw_mdio_dt_ids); > + > +static struct driver cpsw_mdio_driver = { > + .name = "cpsw-mdio", > + .probe = cpsw_mdio_probe, > + .of_compatible = DRV_OF_COMPAT(cpsw_mdio_dt_ids), > +}; > +coredevice_platform_driver(cpsw_mdio_driver); > > -- > 2.39.5 > >