net: mdio: Introduce a regmap-based mdio driver
authorMaxime Chevallier <maxime.chevallier@bootlin.com>
Thu, 1 Jun 2023 14:14:51 +0000 (16:14 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 5 Jun 2023 08:56:36 +0000 (09:56 +0100)
There exists several examples today of devices that embed an ethernet
PHY or PCS directly inside an SoC. In this situation, either the device
is controlled through a vendor-specific register set, or sometimes
exposes the standard 802.3 registers that are typically accessed over
MDIO.

As phylib and phylink are designed to use mdiodevices, this driver
allows creating a virtual MDIO bus, that translates mdiodev register
accesses to regmap accesses.

The reason we use regmap is because there are at least 3 such devices
known today, 2 of them are Altera TSE PCS's, memory-mapped, exposed
with a 4-byte stride in stmmac's dwmac-socfpga variant, and a 2-byte
stride in altera-tse. The other one (nxp,sja1110-base-tx-mdio) is
exposed over SPI.

Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
MAINTAINERS
drivers/net/mdio/Kconfig
drivers/net/mdio/Makefile
drivers/net/mdio/mdio-regmap.c [new file with mode: 0644]
include/linux/mdio/mdio-regmap.h [new file with mode: 0644]

index 288d9a5edb9dc06627c7e84a60234475c8bb2533..5a2ba8567be6843bcd703842c38cfca6e18c7d89 100644 (file)
@@ -12844,6 +12844,13 @@ F:     Documentation/devicetree/bindings/net/ieee802154/mcr20a.txt
 F:     drivers/net/ieee802154/mcr20a.c
 F:     drivers/net/ieee802154/mcr20a.h
 
+MDIO REGMAP DRIVER
+M:     Maxime Chevallier <maxime.chevallier@bootlin.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/mdio/mdio-regmap.c
+F:     include/linux/mdio/mdio-regmap.h
+
 MEASUREMENT COMPUTING CIO-DAC IIO DRIVER
 M:     William Breathitt Gray <william.gray@linaro.org>
 L:     linux-iio@vger.kernel.org
index 9ff2e6f22f3f6b335177e026e84fa36e774b5a4a..4a7a303be2f7444223554a64ae6006d293fea89d 100644 (file)
@@ -185,6 +185,17 @@ config MDIO_IPQ8064
          This driver supports the MDIO interface found in the network
          interface units of the IPQ8064 SoC
 
+config MDIO_REGMAP
+       tristate
+       help
+         This driver allows using MDIO devices that are not sitting on a
+         regular MDIO bus, but still exposes the standard 802.3 register
+         layout. It's regmap-based so that it can be used on integrated,
+         memory-mapped PHYs, SPI PHYs and so on. A new virtual MDIO bus is
+         created, and its read/write operations are mapped to the underlying
+         regmap. Users willing to use this driver must explicitly select
+         REGMAP.
+
 config MDIO_THUNDER
        tristate "ThunderX SOCs MDIO buses"
        depends on 64BIT
index 7d4cb4c11e4ec105ff3fb7553669aa4891ae5d00..1015f0db4531dba5c0da0bcabfc877aaaa67d78a 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_MDIO_MOXART)             += mdio-moxart.o
 obj-$(CONFIG_MDIO_MSCC_MIIM)           += mdio-mscc-miim.o
 obj-$(CONFIG_MDIO_MVUSB)               += mdio-mvusb.o
 obj-$(CONFIG_MDIO_OCTEON)              += mdio-octeon.o
+obj-$(CONFIG_MDIO_REGMAP)              += mdio-regmap.o
 obj-$(CONFIG_MDIO_SUN4I)               += mdio-sun4i.o
 obj-$(CONFIG_MDIO_THUNDER)             += mdio-thunder.o
 obj-$(CONFIG_MDIO_XGENE)               += mdio-xgene.o
diff --git a/drivers/net/mdio/mdio-regmap.c b/drivers/net/mdio/mdio-regmap.c
new file mode 100644 (file)
index 0000000..8a742a8
--- /dev/null
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Driver for MMIO-Mapped MDIO devices. Some IPs expose internal PHYs or PCS
+ * within the MMIO-mapped area
+ *
+ * Copyright (C) 2023 Maxime Chevallier <maxime.chevallier@bootlin.com>
+ */
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/mdio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mdio/mdio-regmap.h>
+
+#define DRV_NAME "mdio-regmap"
+
+struct mdio_regmap_priv {
+       struct regmap *regmap;
+       u8 valid_addr;
+};
+
+static int mdio_regmap_read_c22(struct mii_bus *bus, int addr, int regnum)
+{
+       struct mdio_regmap_priv *ctx = bus->priv;
+       unsigned int val;
+       int ret;
+
+       if (ctx->valid_addr != addr)
+               return -ENODEV;
+
+       ret = regmap_read(ctx->regmap, regnum, &val);
+       if (ret < 0)
+               return ret;
+
+       return val;
+}
+
+static int mdio_regmap_write_c22(struct mii_bus *bus, int addr, int regnum,
+                                u16 val)
+{
+       struct mdio_regmap_priv *ctx = bus->priv;
+
+       if (ctx->valid_addr != addr)
+               return -ENODEV;
+
+       return regmap_write(ctx->regmap, regnum, val);
+}
+
+struct mii_bus *devm_mdio_regmap_register(struct device *dev,
+                                         const struct mdio_regmap_config *config)
+{
+       struct mdio_regmap_priv *mr;
+       struct mii_bus *mii;
+       int rc;
+
+       if (!config->parent)
+               return ERR_PTR(-EINVAL);
+
+       mii = devm_mdiobus_alloc_size(config->parent, sizeof(*mr));
+       if (!mii)
+               return ERR_PTR(-ENOMEM);
+
+       mr = mii->priv;
+       mr->regmap = config->regmap;
+       mr->valid_addr = config->valid_addr;
+
+       mii->name = DRV_NAME;
+       strscpy(mii->id, config->name, MII_BUS_ID_SIZE);
+       mii->parent = config->parent;
+       mii->read = mdio_regmap_read_c22;
+       mii->write = mdio_regmap_write_c22;
+
+       if (config->autoscan)
+               mii->phy_mask = ~BIT(config->valid_addr);
+       else
+               mii->phy_mask = ~0;
+
+       rc = devm_mdiobus_register(dev, mii);
+       if (rc) {
+               dev_err(config->parent, "Cannot register MDIO bus![%s] (%d)\n", mii->id, rc);
+               return ERR_PTR(rc);
+       }
+
+       return mii;
+}
+EXPORT_SYMBOL_GPL(devm_mdio_regmap_register);
+
+MODULE_DESCRIPTION("MDIO API over regmap");
+MODULE_AUTHOR("Maxime Chevallier <maxime.chevallier@bootlin.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mdio/mdio-regmap.h b/include/linux/mdio/mdio-regmap.h
new file mode 100644 (file)
index 0000000..679d906
--- /dev/null
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Driver for MMIO-Mapped MDIO devices. Some IPs expose internal PHYs or PCS
+ * within the MMIO-mapped area
+ *
+ * Copyright (C) 2023 Maxime Chevallier <maxime.chevallier@bootlin.com>
+ */
+#ifndef MDIO_REGMAP_H
+#define MDIO_REGMAP_H
+
+#include <linux/phy.h>
+
+struct device;
+struct regmap;
+
+struct mdio_regmap_config {
+       struct device *parent;
+       struct regmap *regmap;
+       char name[MII_BUS_ID_SIZE];
+       u8 valid_addr;
+       bool autoscan;
+};
+
+struct mii_bus *devm_mdio_regmap_register(struct device *dev,
+                                         const struct mdio_regmap_config *config);
+
+#endif