[U-Boot] [PATCH v3 2/2] mdio: add marvell MDIO driver

Stefan Roese sr at denx.de
Wed Jun 13 13:46:48 UTC 2018


On 13.06.2018 06:37, make at marvell.com wrote:
> From: Ken Ma <make at marvell.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.
> 
> 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>
> Reviewed-by: Chris Packham <judge.packham at gmail.com>
> ---
> 
> Changes in v3:
> - Move marvell mdio driver to driver/net/mdio folder;
> - Update codes according to mdio uclass implementation updates.
> 
> Changes in v2:
> - Fix error printing:
>    - Change some debug to pr_err;
>    - mii bus has no parent member and it is not a udevice, so dev_err
>      is changed to pr_err for mii bus error printings.
> 
>   MAINTAINERS                                   |   1 +
>   arch/arm/Kconfig                              |   1 +
>   doc/device-tree-bindings/net/marvell-mdio.txt |  18 ++
>   drivers/net/mdio/Kconfig                      |  10 ++
>   drivers/net/mdio/Makefile                     |   1 +
>   drivers/net/mdio/mvmdio.c                     | 234 ++++++++++++++++++++++++++
>   6 files changed, 265 insertions(+)
>   create mode 100644 doc/device-tree-bindings/net/marvell-mdio.txt
>   create mode 100644 drivers/net/mdio/mvmdio.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 9e1fc83..d8584f9 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/net/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..e52b164 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 MDIO
>   
>   config TARGET_DEVKIT3250
>   	bool "Support devkit3250"
> diff --git a/doc/device-tree-bindings/net/marvell-mdio.txt b/doc/device-tree-bindings/net/marvell-mdio.txt
> new file mode 100644
> index 0000000..55db435
> --- /dev/null
> +++ b/doc/device-tree-bindings/net/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/net/mdio/Kconfig b/drivers/net/mdio/Kconfig
> index 533cc4a..d1a31e6 100644
> --- a/drivers/net/mdio/Kconfig
> +++ b/drivers/net/mdio/Kconfig
> @@ -15,4 +15,14 @@ config 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 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/net/mdio/Makefile b/drivers/net/mdio/Makefile
> index 45ae502..8b2e5a4 100644
> --- a/drivers/net/mdio/Makefile
> +++ b/drivers/net/mdio/Makefile
> @@ -4,3 +4,4 @@
>   # Author: Ken Ma<make at marvell.com>
>   
>   obj-$(CONFIG_MDIO) += mdio-uclass.o
> +obj-$(CONFIG_MVMDIO) += mvmdio.o
> diff --git a/drivers/net/mdio/mvmdio.c b/drivers/net/mdio/mvmdio.c
> new file mode 100644
> index 0000000..0fb45ce
> --- /dev/null
> +++ b/drivers/net/mdio/mvmdio.c
> @@ -0,0 +1,234 @@
> +// 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>
> +
> +#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) {
> +			pr_err("Error: SMI busy timeout\n");
> +			return -ETIME;
> +		}
> +	} while (smi_reg & MVMDIO_SMI_BUSY);
> +
> +	return 0;
> +}

You could use wait_for_bit_le32() here instead of implementing your
own custom busy wait polling function (include/wait_bit.h). This also
adds more accurate timeout handling (via timer).

Other than this:

Reviewed-by: Stefan Roese <sr at denx.de>

> +
> +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;
> +
> +	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)) {
> +		pr_err("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) {
> +			pr_err("xSMI busy time-out\n");
> +			return -ETIME;
> +		}
> +	} while (xsmi_reg & MVMDIO_XSMI_BUSY);
> +
> +	return 0;
> +}

Again, please use the already available wait bit functions.

Other than this:

Reviewed-by: Stefan Roese <sr at denx.de>

Thanks,
Stefan


More information about the U-Boot mailing list