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:
committed by
Jerome Forissier
parent
c832cd3b49
commit
dfc39f9caf
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
Reference in New Issue
Block a user