net: add Microsemi/Microchip MDIO driver

Add Microsemi/Microchip MDIO driver for interfaces found in their network
switches.

Driver is based on the Linux version.

Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Acked-by: Jerome Forissier <jerome@forissier.org>
This commit is contained in:
Robert Marko
2026-01-15 11:09:28 +01:00
committed by Jerome Forissier
parent c832cd3b49
commit dfc39f9caf
3 changed files with 145 additions and 0 deletions
+8
View File
@@ -1069,6 +1069,14 @@ config ASPEED_MDIO
This driver supports the MDIO bus of Aspeed AST2600 SOC. The driver
currently supports Clause 22.
config MDIO_MSCC_MIIM
bool "Microsemi MIIM interface support"
depends on DM_MDIO
select REGMAP
help
This driver supports MDIO interface found in Microsemi and Microchip
network switches.
config MDIO_MUX_MMIOREG
bool "MDIO MUX accessed as a MMIO register access"
depends on DM_MDIO_MUX
+1
View File
@@ -62,6 +62,7 @@ obj-$(CONFIG_LITEETH) += liteeth.o
obj-$(CONFIG_MACB) += macb.o
obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
obj-$(CONFIG_MDIO_IPQ4019) += mdio-ipq4019.o
obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.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
+136
View File
@@ -0,0 +1,136 @@
// SPDX-License-Identifier: GPL-2.0+
#include <asm/io.h>
#include <dm.h>
#include <time.h>
#include <regmap.h>
#include <miiphy.h>
#include <linux/bitfield.h>
#define MSCC_MIIM_REG_STATUS 0x0
#define MSCC_MIIM_STATUS_STAT_PENDING BIT(2)
#define MSCC_MIIM_STATUS_STAT_BUSY BIT(3)
#define MSCC_MIIM_REG_CMD 0x8
#define MSCC_MIIM_CMD_OPR_WRITE BIT(1)
#define MSCC_MIIM_CMD_OPR_READ BIT(2)
#define MSCC_MIIM_CMD_WRDATA_SHIFT 4
#define MSCC_MIIM_CMD_REGAD_SHIFT 20
#define MSCC_MIIM_CMD_PHYAD_SHIFT 25
#define MSCC_MIIM_CMD_VLD BIT(31)
#define MSCC_MIIM_REG_DATA 0xC
#define MSCC_MIIM_DATA_ERROR (BIT(16) | BIT(17))
#define MSCC_MIIM_DATA_MASK GENMASK(15, 0)
#define MSCC_MIIM_REG_CFG 0x10
#define MSCC_MIIM_CFG_PRESCALE_MASK GENMASK(7, 0)
/* 01 = Clause 22, 00 = Clause 45 */
#define MSCC_MIIM_CFG_ST_CFG_MASK GENMASK(10, 9)
#define MSCC_MIIM_C22 1
#define MSCC_MIIM_C45 0
#define MSCC_MDIO_TIMEOUT 10000
#define MSCC_MDIO_SLEEP 50
struct mscc_mdio_priv {
struct regmap *map;
};
static int mscc_mdio_wait_busy(struct mscc_mdio_priv *priv)
{
u32 busy;
return regmap_read_poll_timeout(priv->map, MSCC_MIIM_REG_STATUS, busy,
(busy & MSCC_MIIM_STATUS_STAT_BUSY) == 0,
MSCC_MDIO_SLEEP,
MSCC_MDIO_TIMEOUT);
}
static int mscc_mdio_read(struct udevice *dev, int addr, int devad, int reg)
{
struct mscc_mdio_priv *priv = dev_get_priv(dev);
u32 val;
int ret;
if (mscc_mdio_wait_busy(priv))
return -ETIMEDOUT;
ret = regmap_write(priv->map, MSCC_MIIM_REG_CMD,
MSCC_MIIM_CMD_VLD |
(addr << MSCC_MIIM_CMD_PHYAD_SHIFT) |
(reg << MSCC_MIIM_CMD_REGAD_SHIFT) |
MSCC_MIIM_CMD_OPR_READ);
if (ret)
return ret;
if (mscc_mdio_wait_busy(priv))
return -ETIMEDOUT;
regmap_read(priv->map, MSCC_MIIM_REG_DATA, &val);
if (val & MSCC_MIIM_DATA_ERROR)
return -EIO;
return FIELD_GET(MSCC_MIIM_DATA_MASK, val);
}
int mscc_mdio_write(struct udevice *dev, int addr, int devad, int reg, u16 val)
{
struct mscc_mdio_priv *priv = dev_get_priv(dev);
int ret;
if (mscc_mdio_wait_busy(priv))
return -ETIMEDOUT;
ret = regmap_write(priv->map, MSCC_MIIM_REG_CMD,
MSCC_MIIM_CMD_VLD |
(addr << MSCC_MIIM_CMD_PHYAD_SHIFT) |
(reg << MSCC_MIIM_CMD_REGAD_SHIFT) |
(val << MSCC_MIIM_CMD_WRDATA_SHIFT) |
MSCC_MIIM_CMD_OPR_WRITE);
return ret;
}
static const struct mdio_ops mscc_mdio_ops = {
.read = mscc_mdio_read,
.write = mscc_mdio_write,
};
static int mscc_mdio_bind(struct udevice *dev)
{
if (ofnode_valid(dev_ofnode(dev)))
device_set_name(dev, ofnode_get_name(dev_ofnode(dev)));
return 0;
}
static int mscc_mdio_probe(struct udevice *dev)
{
struct mscc_mdio_priv *priv = dev_get_priv(dev);
int ret;
ret = regmap_init_mem(dev_ofnode(dev), &priv->map);
if (ret)
return -EINVAL;
/* Enter Clause 22 mode */
ret = regmap_update_bits(priv->map, MSCC_MIIM_REG_CFG,
MSCC_MIIM_CFG_ST_CFG_MASK,
FIELD_PREP(MSCC_MIIM_CFG_ST_CFG_MASK,
MSCC_MIIM_C22));
return ret;
}
static const struct udevice_id mscc_mdio_ids[] = {
{ .compatible = "mscc,ocelot-miim", },
{ }
};
U_BOOT_DRIVER(mscc_mdio) = {
.name = "mscc_mdio",
.id = UCLASS_MDIO,
.of_match = mscc_mdio_ids,
.bind = mscc_mdio_bind,
.probe = mscc_mdio_probe,
.ops = &mscc_mdio_ops,
.priv_auto = sizeof(struct mscc_mdio_priv),
};