[U-Boot] [PATCH 2/2] mdio: add marvell MDIO driver
Chris Packham
judge.packham at gmail.com
Wed Jun 6 08:52:03 UTC 2018
Hi Ken,
On Wed, Jun 6, 2018 at 8:06 PM <make at marvell.com> wrote:
>
> From: Ken Ma <make at marvell.com>
aside, awesome email address for someone in embedded development :)
Some minor comments below
Reviewed-by: Chris Packham <judge.packham at gmail.com>
> This patch adds a separate driver for the MDIO interface of the
> Marvell Ethernet controllers based on driver model. There are two
> reasons to have a separate driver rather than including it inside
> the MAC driver itself:
> *) The MDIO interface is shared by all Ethernet ports, so a driver
> must guarantee non-concurrent accesses to this MDIO interface. The
> most logical way is to have a separate driver that handles this
> single MDIO interface, used by all Ethernet ports.
> *) The MDIO interface is the same between the existing mv643xx_eth
> driver and the new mvneta/mvpp2 driver. Even though it is for now
> only used by the mvneta/mvpp2 driver, it will in the future be
> used by the mv643xx_eth driver as well.
Yay.
In u-boot mv643xx_eth is mvgbe.c. I've been looking at converting it
to DM but the first problem I hit was the MDIO interface so this is
very much welcome. Were you planning on adding an actual mv643xx_eth
driver or is that just a copy/paste from Linux?
>
> This driver supports SMI IEEE for 802.3 Clause 22 and XSMI for IEEE
> 802.3 Clause 45.
>
> This patch also adds device tree binding for marvell MDIO driver.
>
> Signed-off-by: Ken Ma <make at marvell.com>
> ---
>
> MAINTAINERS | 1 +
> arch/arm/Kconfig | 1 +
> doc/device-tree-bindings/mdio/marvell-mdio.txt | 18 ++
> drivers/mdio/Kconfig | 10 ++
> drivers/mdio/Makefile | 1 +
> drivers/mdio/mvmdio.c | 237 +++++++++++++++++++++++++
> 6 files changed, 268 insertions(+)
> create mode 100644 doc/device-tree-bindings/mdio/marvell-mdio.txt
> create mode 100644 drivers/mdio/mvmdio.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f66a904..fb58f17 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -137,6 +137,7 @@ T: git git://git.denx.de/u-boot-marvell.git
> F: arch/arm/mach-kirkwood/
> F: arch/arm/mach-mvebu/
> F: drivers/ata/ahci_mvebu.c
> +F: drivers/mdio/mvmdio.c
>
> ARM MARVELL PXA
> M: Marek Vasut <marex at denx.de>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index dde422b..aae4570 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -432,6 +432,7 @@ config ARCH_MVEBU
> select DM_SPI
> select DM_SPI_FLASH
> select SPI
> + select DM_MDIO
>
> config TARGET_DEVKIT3250
> bool "Support devkit3250"
> diff --git a/doc/device-tree-bindings/mdio/marvell-mdio.txt b/doc/device-tree-bindings/mdio/marvell-mdio.txt
> new file mode 100644
> index 0000000..55db435
> --- /dev/null
> +++ b/doc/device-tree-bindings/mdio/marvell-mdio.txt
> @@ -0,0 +1,18 @@
> +* Marvell MDIO Ethernet Controller interface
> +
> +The Ethernet controllers of the Marvel Armada 3700 and Armada 7k/8k
> +have an identical unit that provides an interface with the MDIO bus.
> +This driver handles this MDIO interface.
> +
> +Mandatory properties:
> +SoC specific:
> + - #address-cells: Must be <1>.
> + - #size-cells: Must be <0>.
> + - compatible: Should be "marvell,orion-mdio" (for SMI)
> + "marvell,xmdio" (for XSMI)
> + - reg: Base address and size SMI/XMSI bus.
> +
> +Optional properties:
> + - mdio-name - MDIO bus name
> +
> +For example, please refer to "mdio-bus.txt".
> diff --git a/drivers/mdio/Kconfig b/drivers/mdio/Kconfig
> index 76e3758..ce251c5 100644
> --- a/drivers/mdio/Kconfig
> +++ b/drivers/mdio/Kconfig
> @@ -15,4 +15,14 @@ config DM_MDIO
> udevice or mii bus from its child phy node or
> an ethernet udevice which the phy belongs to.
>
> +config MVMDIO
> + bool "Marvell MDIO interface support"
> + depends on DM_MDIO
> + select PHYLIB
> + help
> + This driver supports the MDIO interface found in the network
> + interface units of the Marvell EBU SoCs (Kirkwood, Orion5x,
> + Dove, Armada 370, Armada XP, Armada 37xx and Armada7K/8K/8KP).
> +
> + This driver is used by the MVPP2 and MVNETA drivers.
> endmenu
> diff --git a/drivers/mdio/Makefile b/drivers/mdio/Makefile
> index 9b290c0..9f571aa 100644
> --- a/drivers/mdio/Makefile
> +++ b/drivers/mdio/Makefile
> @@ -4,3 +4,4 @@
> # Author: Ken Ma<make at marvell.com>
>
> obj-$(CONFIG_DM_MDIO) += mdio-uclass.o
> +obj-$(CONFIG_MVMDIO) += mvmdio.o
> diff --git a/drivers/mdio/mvmdio.c b/drivers/mdio/mvmdio.c
> new file mode 100644
> index 0000000..b2c6636
> --- /dev/null
> +++ b/drivers/mdio/mvmdio.c
> @@ -0,0 +1,237 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2018 Marvell International Ltd.
> + * Author: Ken Ma<make at marvell.com>
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <dm/device-internal.h>
> +#include <dm/lists.h>
> +#include <miiphy.h>
> +#include <phy.h>
> +#include <asm/io.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +#define MVMDIO_SMI_DATA_SHIFT 0
> +#define MVMDIO_SMI_PHY_ADDR_SHIFT 16
> +#define MVMDIO_SMI_PHY_REG_SHIFT 21
> +#define MVMDIO_SMI_READ_OPERATION BIT(26)
> +#define MVMDIO_SMI_WRITE_OPERATION 0
> +#define MVMDIO_SMI_READ_VALID BIT(27)
> +#define MVMDIO_SMI_BUSY BIT(28)
> +
> +#define MVMDIO_XSMI_MGNT_REG 0x0
> +#define MVMDIO_XSMI_PHYADDR_SHIFT 16
> +#define MVMDIO_XSMI_DEVADDR_SHIFT 21
> +#define MVMDIO_XSMI_WRITE_OPERATION (0x5 << 26)
> +#define MVMDIO_XSMI_READ_OPERATION (0x7 << 26)
> +#define MVMDIO_XSMI_READ_VALID BIT(29)
> +#define MVMDIO_XSMI_BUSY BIT(30)
> +#define MVMDIO_XSMI_ADDR_REG 0x8
> +
> +#define MVMDIO_TIMEOUT 10000
> +
> +struct mvmdio_priv {
> + void *mdio_base;
> +};
> +
> +enum mvmdio_bus_type {
> + BUS_TYPE_SMI,
> + BUS_TYPE_XSMI
> +};
> +
> +/* Wait for the SMI unit to be ready for another operation */
> +static int mvmdio_smi_wait_ready(struct mii_dev *bus)
> +{
> + u32 timeout = MVMDIO_TIMEOUT;
> + struct mvmdio_priv *priv = bus->priv;
> + u32 smi_reg;
> +
> + /* Wait till the SMI is not busy */
> + do {
> + /* Read smi register */
> + smi_reg = readl(priv->mdio_base);
> + if (timeout-- == 0) {
> + debug("Error: SMI busy timeout\n");
Should this be dev_err(bus->parent, ...); ?
> + return -ETIME;
> + }
> + } while (smi_reg & MVMDIO_SMI_BUSY);
> +
> + return 0;
> +}
> +
> +static int mvmdio_smi_read(struct mii_dev *bus, int addr,
> + int devad, int reg)
> +{
> + struct mvmdio_priv *priv = bus->priv;
> + u32 val;
> + int ret;
> +
> + if (devad != MDIO_DEVAD_NONE)
> + return -EOPNOTSUPP;
mvgbe has a feature to read back the PHY address via the PHY Address
Register which I assume is configureable via hardware strapping. Looks
like the Armada-38x has the same feature although the mvneta driver
doesn't implement it. Should this new driver include this?
> +
> + ret = mvmdio_smi_wait_ready(bus);
> + if (ret < 0)
> + return ret;
> +
> + writel(((addr << MVMDIO_SMI_PHY_ADDR_SHIFT) |
> + (reg << MVMDIO_SMI_PHY_REG_SHIFT) |
> + MVMDIO_SMI_READ_OPERATION),
> + priv->mdio_base);
> +
> + ret = mvmdio_smi_wait_ready(bus);
> + if (ret < 0)
> + return ret;
> +
> + val = readl(priv->mdio_base);
> + if (!(val & MVMDIO_SMI_READ_VALID)) {
> + dev_err(bus->parent, "SMI bus read not valid\n");
> + return -ENODEV;
> + }
> +
> + return val & GENMASK(15, 0);
> +}
> +
> +static int mvmdio_smi_write(struct mii_dev *bus, int addr, int devad,
> + int reg, u16 value)
> +{
> + struct mvmdio_priv *priv = bus->priv;
> + int ret;
> +
> + if (devad != MDIO_DEVAD_NONE)
> + return -EOPNOTSUPP;
> +
> + ret = mvmdio_smi_wait_ready(bus);
> + if (ret < 0)
> + return ret;
> +
> + writel(((addr << MVMDIO_SMI_PHY_ADDR_SHIFT) |
> + (reg << MVMDIO_SMI_PHY_REG_SHIFT) |
> + MVMDIO_SMI_WRITE_OPERATION |
> + (value << MVMDIO_SMI_DATA_SHIFT)),
> + priv->mdio_base);
> +
> + return 0;
> +}
> +
> +static int mvmdio_xsmi_wait_ready(struct mii_dev *bus)
> +{
> + u32 timeout = MVMDIO_TIMEOUT;
> + struct mvmdio_priv *priv = bus->priv;
> + u32 xsmi_reg;
> +
> + /* Wait till the xSMI is not busy */
> + do {
> + /* Read xSMI register */
> + xsmi_reg = readl(priv->mdio_base);
> + if (timeout-- == 0) {
> + debug("xSMI busy time-out\n");
Should this be dev_err(bus->parent, ...); ?
> + return -ETIME;
> + }
> + } while (xsmi_reg & MVMDIO_XSMI_BUSY);
> +
> + return 0;
> +}
> +
> +static int mvmdio_xsmi_read(struct mii_dev *bus, int addr,
> + int devad, int reg)
> +{
> + struct mvmdio_priv *priv = bus->priv;
> + int ret;
> +
> + if (devad == MDIO_DEVAD_NONE)
> + return -EOPNOTSUPP;
> +
> + ret = mvmdio_xsmi_wait_ready(bus);
> + if (ret < 0)
> + return ret;
> +
> + writel(reg & GENMASK(15, 0), priv->mdio_base + MVMDIO_XSMI_ADDR_REG);
> + writel(((addr << MVMDIO_XSMI_PHYADDR_SHIFT) |
> + (devad << MVMDIO_XSMI_DEVADDR_SHIFT) |
> + MVMDIO_XSMI_READ_OPERATION),
> + priv->mdio_base + MVMDIO_XSMI_MGNT_REG);
> +
> + ret = mvmdio_xsmi_wait_ready(bus);
> + if (ret < 0)
> + return ret;
> +
> + if (!(readl(priv->mdio_base + MVMDIO_XSMI_MGNT_REG) &
> + MVMDIO_XSMI_READ_VALID)) {
> + dev_err(bus->parent, "XSMI bus read not valid\n");
> + return -ENODEV;
> + }
> +
> + return readl(priv->mdio_base + MVMDIO_XSMI_MGNT_REG) & GENMASK(15, 0);
> +}
> +
> +static int mvmdio_xsmi_write(struct mii_dev *bus, int addr, int devad,
> + int reg, u16 value)
> +{
> + struct mvmdio_priv *priv = bus->priv;
> + int ret;
> +
> + if (devad == MDIO_DEVAD_NONE)
> + return -EOPNOTSUPP;
> +
> + ret = mvmdio_xsmi_wait_ready(bus);
> + if (ret < 0)
> + return ret;
> +
> + writel(reg & GENMASK(15, 0), priv->mdio_base + MVMDIO_XSMI_ADDR_REG);
> + writel(((addr << MVMDIO_XSMI_PHYADDR_SHIFT) |
> + (devad << MVMDIO_XSMI_DEVADDR_SHIFT) |
> + MVMDIO_XSMI_WRITE_OPERATION | value),
> + priv->mdio_base + MVMDIO_XSMI_MGNT_REG);
> +
> + return 0;
> +}
> +
> +static int mvmdio_probe(struct udevice *dev)
> +{
> + struct mii_dev **pbus = dev_get_uclass_platdata(dev);
> + struct mii_dev *bus = *pbus;
> + struct mvmdio_priv *priv;
> + enum mvmdio_bus_type type;
> +
> + priv = dev_get_priv(dev);
> + priv->mdio_base = (void *)devfdt_get_addr(dev);
> + bus->priv = priv;
> +
> + type = (enum mvmdio_bus_type)dev_get_driver_data(dev);
> + switch (type) {
> + case BUS_TYPE_SMI:
> + bus->read = mvmdio_smi_read;
> + bus->write = mvmdio_smi_write;
> + if (!bus->name)
> + snprintf(bus->name, MDIO_NAME_LEN,
> + "orion-mdio.%p", priv->mdio_base);
> + break;
> + case BUS_TYPE_XSMI:
> + bus->read = mvmdio_xsmi_read;
> + bus->write = mvmdio_xsmi_write;
> + if (!bus->name)
> + snprintf(bus->name, MDIO_NAME_LEN,
> + "xmdio.%p", priv->mdio_base);
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static const struct udevice_id mvmdio_ids[] = {
> + { .compatible = "marvell,orion-mdio", .data = BUS_TYPE_SMI },
> + { .compatible = "marvell,xmdio", .data = BUS_TYPE_XSMI },
> + { }
> +};
> +
> +U_BOOT_DRIVER(mvmdio) = {
> + .name = "mvmdio",
> + .id = UCLASS_MDIO,
> + .of_match = mvmdio_ids,
> + .probe = mvmdio_probe,
> + .priv_auto_alloc_size = sizeof(struct mvmdio_priv),
> +};
> +
> --
> 1.9.1
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot
More information about the U-Boot
mailing list