[openwrt/openwrt] ipq40xx: backport upstream MDIO driver

LEDE Commits lede-commits at lists.infradead.org
Wed Dec 23 10:36:28 EST 2020


ynezz pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/4cdc8d20fa6f0acdac532ad972cd664a5927e9f3

commit 4cdc8d20fa6f0acdac532ad972cd664a5927e9f3
Author: Robert Marko <robert.marko at sartura.hr>
AuthorDate: Fri Nov 13 14:24:59 2020 +0100

    ipq40xx: backport upstream MDIO driver
    
    IPQ40xx MDIO driver was upstreamed in kernel version 5.8.
    So lets backport the upstream version and drop our local one.
    
    This also refreshed the kernel config since the symbol name has changed.
    
    Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
 target/linux/ipq40xx/config-5.4                    |   2 +-
 ...v5.8-net-phy-mdio-add-IPQ4019-MDIO-driver.patch | 210 +++++++++++++++++++
 ....8-02-ARM-dts-qcom-ipq4019-add-MDIO-node.patch} |   0
 .../patches-5.4/700-net-add-qualcomm-mdio.patch    | 225 ---------------------
 4 files changed, 211 insertions(+), 226 deletions(-)

diff --git a/target/linux/ipq40xx/config-5.4 b/target/linux/ipq40xx/config-5.4
index d8945aa293..5c42be48bd 100644
--- a/target/linux/ipq40xx/config-5.4
+++ b/target/linux/ipq40xx/config-5.4
@@ -233,7 +233,7 @@ CONFIG_MDIO_BITBANG=y
 CONFIG_MDIO_BUS=y
 CONFIG_MDIO_DEVICE=y
 CONFIG_MDIO_GPIO=y
-CONFIG_MDIO_IPQ40XX=y
+CONFIG_MDIO_IPQ4019=y
 # CONFIG_MDM_GCC_9615 is not set
 # CONFIG_MDM_LCC_9615 is not set
 CONFIG_MEMFD_CREATE=y
diff --git a/target/linux/ipq40xx/patches-5.4/0005-01-v5.8-net-phy-mdio-add-IPQ4019-MDIO-driver.patch b/target/linux/ipq40xx/patches-5.4/0005-01-v5.8-net-phy-mdio-add-IPQ4019-MDIO-driver.patch
new file mode 100644
index 0000000000..d678f761f5
--- /dev/null
+++ b/target/linux/ipq40xx/patches-5.4/0005-01-v5.8-net-phy-mdio-add-IPQ4019-MDIO-driver.patch
@@ -0,0 +1,210 @@
+From 466ed24fb22342f3ae1c10758a6a0c6a8c081b2d Mon Sep 17 00:00:00 2001
+From: Robert Marko <robert.marko at sartura.hr>
+Date: Thu, 30 Apr 2020 11:07:05 +0200
+Subject: [PATCH] net: phy: mdio: add IPQ4019 MDIO driver
+
+This patch adds the driver for the MDIO interface
+inside of Qualcomm IPQ40xx series SoC-s.
+
+Signed-off-by: Christian Lamparter <chunkeey at gmail.com>
+Signed-off-by: Robert Marko <robert.marko at sartura.hr>
+Reviewed-by: Andrew Lunn <andrew at lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli at gmail.com>
+Cc: Luka Perkov <luka.perkov at sartura.hr>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/phy/Kconfig        |   7 ++
+ drivers/net/phy/Makefile       |   1 +
+ drivers/net/phy/mdio-ipq4019.c | 160 +++++++++++++++++++++++++++++++++
+ 3 files changed, 168 insertions(+)
+ create mode 100644 drivers/net/phy/mdio-ipq4019.c
+
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -156,6 +156,13 @@ config MDIO_I2C
+ 
+ 	  This is library mode.
+ 
++config MDIO_IPQ4019
++	tristate "Qualcomm IPQ4019 MDIO interface support"
++	depends on HAS_IOMEM && OF_MDIO
++	help
++	  This driver supports the MDIO interface found in Qualcomm
++	  IPQ40xx series Soc-s.
++
+ config MDIO_MOXART
+ 	tristate "MOXA ART MDIO interface support"
+ 	depends on ARCH_MOXART || COMPILE_TEST
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -50,6 +50,7 @@ obj-$(CONFIG_MDIO_CAVIUM)	+= mdio-cavium
+ obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
+ obj-$(CONFIG_MDIO_HISI_FEMAC)	+= mdio-hisi-femac.o
+ obj-$(CONFIG_MDIO_I2C)		+= mdio-i2c.o
++obj-$(CONFIG_MDIO_IPQ4019)	+= mdio-ipq4019.o
+ obj-$(CONFIG_MDIO_MOXART)	+= mdio-moxart.o
+ obj-$(CONFIG_MDIO_MSCC_MIIM)	+= mdio-mscc-miim.o
+ obj-$(CONFIG_MDIO_OCTEON)	+= mdio-octeon.o
+--- /dev/null
++++ b/drivers/net/phy/mdio-ipq4019.c
+@@ -0,0 +1,160 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
++/* Copyright (c) 2015, The Linux Foundation. All rights reserved. */
++/* Copyright (c) 2020 Sartura Ltd. */
++
++#include <linux/delay.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/of_address.h>
++#include <linux/of_mdio.h>
++#include <linux/phy.h>
++#include <linux/platform_device.h>
++
++#define MDIO_ADDR_REG				0x44
++#define MDIO_DATA_WRITE_REG			0x48
++#define MDIO_DATA_READ_REG			0x4c
++#define MDIO_CMD_REG				0x50
++#define MDIO_CMD_ACCESS_BUSY		BIT(16)
++#define MDIO_CMD_ACCESS_START		BIT(8)
++#define MDIO_CMD_ACCESS_CODE_READ	0
++#define MDIO_CMD_ACCESS_CODE_WRITE	1
++
++#define ipq4019_MDIO_TIMEOUT	10000
++#define ipq4019_MDIO_SLEEP		10
++
++struct ipq4019_mdio_data {
++	void __iomem	*membase;
++};
++
++static int ipq4019_mdio_wait_busy(struct mii_bus *bus)
++{
++	struct ipq4019_mdio_data *priv = bus->priv;
++	unsigned int busy;
++
++	return readl_poll_timeout(priv->membase + MDIO_CMD_REG, busy,
++				  (busy & MDIO_CMD_ACCESS_BUSY) == 0,
++				  ipq4019_MDIO_SLEEP, ipq4019_MDIO_TIMEOUT);
++}
++
++static int ipq4019_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
++{
++	struct ipq4019_mdio_data *priv = bus->priv;
++	unsigned int cmd;
++
++	/* Reject clause 45 */
++	if (regnum & MII_ADDR_C45)
++		return -EOPNOTSUPP;
++
++	if (ipq4019_mdio_wait_busy(bus))
++		return -ETIMEDOUT;
++
++	/* issue the phy address and reg */
++	writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
++
++	cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_READ;
++
++	/* issue read command */
++	writel(cmd, priv->membase + MDIO_CMD_REG);
++
++	/* Wait read complete */
++	if (ipq4019_mdio_wait_busy(bus))
++		return -ETIMEDOUT;
++
++	/* Read and return data */
++	return readl(priv->membase + MDIO_DATA_READ_REG);
++}
++
++static int ipq4019_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
++							 u16 value)
++{
++	struct ipq4019_mdio_data *priv = bus->priv;
++	unsigned int cmd;
++
++	/* Reject clause 45 */
++	if (regnum & MII_ADDR_C45)
++		return -EOPNOTSUPP;
++
++	if (ipq4019_mdio_wait_busy(bus))
++		return -ETIMEDOUT;
++
++	/* issue the phy address and reg */
++	writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
++
++	/* issue write data */
++	writel(value, priv->membase + MDIO_DATA_WRITE_REG);
++
++	cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_WRITE;
++	/* issue write command */
++	writel(cmd, priv->membase + MDIO_CMD_REG);
++
++	/* Wait write complete */
++	if (ipq4019_mdio_wait_busy(bus))
++		return -ETIMEDOUT;
++
++	return 0;
++}
++
++static int ipq4019_mdio_probe(struct platform_device *pdev)
++{
++	struct ipq4019_mdio_data *priv;
++	struct mii_bus *bus;
++	int ret;
++
++	bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv));
++	if (!bus)
++		return -ENOMEM;
++
++	priv = bus->priv;
++
++	priv->membase = devm_platform_ioremap_resource(pdev, 0);
++	if (IS_ERR(priv->membase))
++		return PTR_ERR(priv->membase);
++
++	bus->name = "ipq4019_mdio";
++	bus->read = ipq4019_mdio_read;
++	bus->write = ipq4019_mdio_write;
++	bus->parent = &pdev->dev;
++	snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id);
++
++	ret = of_mdiobus_register(bus, pdev->dev.of_node);
++	if (ret) {
++		dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
++		return ret;
++	}
++
++	platform_set_drvdata(pdev, bus);
++
++	return 0;
++}
++
++static int ipq4019_mdio_remove(struct platform_device *pdev)
++{
++	struct mii_bus *bus = platform_get_drvdata(pdev);
++
++	mdiobus_unregister(bus);
++
++	return 0;
++}
++
++static const struct of_device_id ipq4019_mdio_dt_ids[] = {
++	{ .compatible = "qcom,ipq4019-mdio" },
++	{ }
++};
++MODULE_DEVICE_TABLE(of, ipq4019_mdio_dt_ids);
++
++static struct platform_driver ipq4019_mdio_driver = {
++	.probe = ipq4019_mdio_probe,
++	.remove = ipq4019_mdio_remove,
++	.driver = {
++		.name = "ipq4019-mdio",
++		.of_match_table = ipq4019_mdio_dt_ids,
++	},
++};
++
++module_platform_driver(ipq4019_mdio_driver);
++
++MODULE_DESCRIPTION("ipq4019 MDIO interface driver");
++MODULE_AUTHOR("Qualcomm Atheros");
++MODULE_LICENSE("Dual BSD/GPL");
diff --git a/target/linux/ipq40xx/patches-5.4/0005-v5.8-02-ARM-dts-qcom-ipq4019-add-MDIO-node.patch b/target/linux/ipq40xx/patches-5.4/0005-02-v5.8-02-ARM-dts-qcom-ipq4019-add-MDIO-node.patch
similarity index 100%
rename from target/linux/ipq40xx/patches-5.4/0005-v5.8-02-ARM-dts-qcom-ipq4019-add-MDIO-node.patch
rename to target/linux/ipq40xx/patches-5.4/0005-02-v5.8-02-ARM-dts-qcom-ipq4019-add-MDIO-node.patch
diff --git a/target/linux/ipq40xx/patches-5.4/700-net-add-qualcomm-mdio.patch b/target/linux/ipq40xx/patches-5.4/700-net-add-qualcomm-mdio.patch
deleted file mode 100644
index 3345d84fb8..0000000000
--- a/target/linux/ipq40xx/patches-5.4/700-net-add-qualcomm-mdio.patch
+++ /dev/null
@@ -1,225 +0,0 @@
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -577,6 +577,13 @@ config XILINX_GMII2RGMII
- 	  the Reduced Gigabit Media Independent Interface(RGMII) between
- 	  Ethernet physical media devices and the Gigabit Ethernet controller.
- 
-+config MDIO_IPQ40XX
-+	tristate "Qualcomm Atheros ipq40xx MDIO interface"
-+	depends on HAS_IOMEM && OF
-+	---help---
-+	  This driver supports the MDIO interface found in Qualcomm
-+	  Atheros ipq40xx Soc chip.
-+
- endif # PHYLIB
- 
- config MICREL_KS8995MA
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -50,6 +50,7 @@ obj-$(CONFIG_MDIO_CAVIUM)	+= mdio-cavium
- obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
- obj-$(CONFIG_MDIO_HISI_FEMAC)	+= mdio-hisi-femac.o
- obj-$(CONFIG_MDIO_I2C)		+= mdio-i2c.o
-+obj-$(CONFIG_MDIO_IPQ40XX)	+= mdio-ipq40xx.o
- obj-$(CONFIG_MDIO_MOXART)	+= mdio-moxart.o
- obj-$(CONFIG_MDIO_MSCC_MIIM)	+= mdio-mscc-miim.o
- obj-$(CONFIG_MDIO_OCTEON)	+= mdio-octeon.o
---- /dev/null
-+++ b/drivers/net/phy/mdio-ipq40xx.c
-@@ -0,0 +1,196 @@
-+/*
-+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
-+ *
-+ * Permission to use, copy, modify, and/or distribute this software for
-+ * any purpose with or without fee is hereby granted, provided that the
-+ * above copyright notice and this permission notice appear in all copies.
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#include <linux/delay.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/mutex.h>
-+#include <linux/io.h>
-+#include <linux/of_address.h>
-+#include <linux/of_mdio.h>
-+#include <linux/phy.h>
-+#include <linux/platform_device.h>
-+
-+#define MDIO_CTRL_0_REG		0x40
-+#define MDIO_CTRL_1_REG		0x44
-+#define MDIO_CTRL_2_REG		0x48
-+#define MDIO_CTRL_3_REG		0x4c
-+#define MDIO_CTRL_4_REG		0x50
-+#define MDIO_CTRL_4_ACCESS_BUSY		BIT(16)
-+#define MDIO_CTRL_4_ACCESS_START		BIT(8)
-+#define MDIO_CTRL_4_ACCESS_CODE_READ		0
-+#define MDIO_CTRL_4_ACCESS_CODE_WRITE	1
-+#define CTRL_0_REG_DEFAULT_VALUE	0x150FF
-+
-+#define IPQ40XX_MDIO_RETRY	1000
-+#define IPQ40XX_MDIO_DELAY	10
-+
-+struct ipq40xx_mdio_data {
-+	struct mii_bus	*mii_bus;
-+	void __iomem	*membase;
-+	struct device	*dev;
-+};
-+
-+static int ipq40xx_mdio_wait_busy(struct ipq40xx_mdio_data *am)
-+{
-+	int i;
-+
-+	for (i = 0; i < IPQ40XX_MDIO_RETRY; i++) {
-+		unsigned int busy;
-+
-+		busy = readl(am->membase + MDIO_CTRL_4_REG) &
-+			MDIO_CTRL_4_ACCESS_BUSY;
-+		if (!busy)
-+			return 0;
-+
-+		/* BUSY might take to be cleard by 15~20 times of loop */
-+		udelay(IPQ40XX_MDIO_DELAY);
-+	}
-+
-+	dev_err(am->dev, "%s: MDIO operation timed out\n", am->mii_bus->name);
-+
-+	return -ETIMEDOUT;
-+}
-+
-+static int ipq40xx_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
-+{
-+	struct ipq40xx_mdio_data *am = bus->priv;
-+	int value = 0;
-+	unsigned int cmd = 0;
-+
-+	lockdep_assert_held(&bus->mdio_lock);
-+
-+	if (ipq40xx_mdio_wait_busy(am))
-+		return -ETIMEDOUT;
-+
-+	/* issue the phy address and reg */
-+	writel((mii_id << 8) | regnum, am->membase + MDIO_CTRL_1_REG);
-+
-+	cmd = MDIO_CTRL_4_ACCESS_START|MDIO_CTRL_4_ACCESS_CODE_READ;
-+
-+	/* issue read command */
-+	writel(cmd, am->membase + MDIO_CTRL_4_REG);
-+
-+	/* Wait read complete */
-+	if (ipq40xx_mdio_wait_busy(am))
-+		return -ETIMEDOUT;
-+
-+	/* Read data */
-+	value = readl(am->membase + MDIO_CTRL_3_REG);
-+
-+	return value;
-+}
-+
-+static int ipq40xx_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
-+			    u16 value)
-+{
-+	struct ipq40xx_mdio_data *am = bus->priv;
-+	unsigned int cmd = 0;
-+
-+	lockdep_assert_held(&bus->mdio_lock);
-+
-+	if (ipq40xx_mdio_wait_busy(am))
-+		return -ETIMEDOUT;
-+
-+	/* issue the phy address and reg */
-+	writel((mii_id << 8) | regnum, am->membase + MDIO_CTRL_1_REG);
-+
-+	/* issue write data */
-+	writel(value, am->membase + MDIO_CTRL_2_REG);
-+
-+	cmd = MDIO_CTRL_4_ACCESS_START|MDIO_CTRL_4_ACCESS_CODE_WRITE;
-+	/* issue write command */
-+	writel(cmd, am->membase + MDIO_CTRL_4_REG);
-+
-+	/* Wait write complete */
-+	if (ipq40xx_mdio_wait_busy(am))
-+		return -ETIMEDOUT;
-+
-+	return 0;
-+}
-+
-+static int ipq40xx_mdio_probe(struct platform_device *pdev)
-+{
-+	struct ipq40xx_mdio_data *am;
-+	struct resource *res;
-+	int i;
-+
-+	am = devm_kzalloc(&pdev->dev, sizeof(*am), GFP_KERNEL);
-+	if (!am)
-+		return -ENOMEM;
-+
-+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+	if (!res) {
-+		dev_err(&pdev->dev, "no iomem resource found\n");
-+		return -ENXIO;
-+	}
-+
-+	am->membase = devm_ioremap_resource(&pdev->dev, res);
-+	if (IS_ERR(am->membase)) {
-+		dev_err(&pdev->dev, "unable to ioremap registers\n");
-+		return PTR_ERR(am->membase);
-+	}
-+
-+	am->mii_bus = devm_mdiobus_alloc(&pdev->dev);
-+	if (!am->mii_bus)
-+		return  -ENOMEM;
-+
-+	writel(CTRL_0_REG_DEFAULT_VALUE, am->membase + MDIO_CTRL_0_REG);
-+
-+	am->mii_bus->name = "ipq40xx_mdio";
-+	am->mii_bus->read = ipq40xx_mdio_read;
-+	am->mii_bus->write = ipq40xx_mdio_write;
-+	am->mii_bus->priv = am;
-+	am->mii_bus->parent = &pdev->dev;
-+	snprintf(am->mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(&pdev->dev));
-+
-+	am->dev = &pdev->dev;
-+	platform_set_drvdata(pdev, am);
-+
-+	return of_mdiobus_register(am->mii_bus, pdev->dev.of_node);
-+}
-+
-+static int ipq40xx_mdio_remove(struct platform_device *pdev)
-+{
-+	struct ipq40xx_mdio_data *am = platform_get_drvdata(pdev);
-+
-+	mdiobus_unregister(am->mii_bus);
-+
-+	return 0;
-+}
-+
-+static const struct of_device_id ipq40xx_mdio_dt_ids[] = {
-+	{ .compatible = "qcom,ipq4019-mdio" },
-+	{ }
-+};
-+MODULE_DEVICE_TABLE(of, ipq40xx_mdio_dt_ids);
-+
-+static struct platform_driver ipq40xx_mdio_driver = {
-+	.probe = ipq40xx_mdio_probe,
-+	.remove = ipq40xx_mdio_remove,
-+	.driver = {
-+		.name = "ipq40xx-mdio",
-+		.of_match_table = ipq40xx_mdio_dt_ids,
-+	},
-+};
-+
-+module_platform_driver(ipq40xx_mdio_driver);
-+
-+#define DRV_VERSION     "1.0"
-+
-+MODULE_DESCRIPTION("IPQ40XX MDIO interface driver");
-+MODULE_AUTHOR("Qualcomm Atheros");
-+MODULE_VERSION(DRV_VERSION);
-+MODULE_LICENSE("Dual BSD/GPL");



More information about the lede-commits mailing list