Commit 642af0f9 authored by Maxime Chevallier's avatar Maxime Chevallier Committed by David S. Miller
Browse files

net: mdio: Introduce a regmap-based mdio driver



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: default avatarMaxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: default avatarSimon Horman <simon.horman@corigine.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f69de8aa
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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
+11 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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
+93 −0
Original line number Diff line number Diff line
// 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");
+26 −0
Original line number Diff line number Diff line
/* 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