aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ipq40xx/patches-5.4/0005-01-v5.8-net-phy-mdio-add-IPQ4019-MDIO-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ipq40xx/patches-5.4/0005-01-v5.8-net-phy-mdio-add-IPQ4019-MDIO-driver.patch')
-rw-r--r--target/linux/ipq40xx/patches-5.4/0005-01-v5.8-net-phy-mdio-add-IPQ4019-MDIO-driver.patch210
1 files changed, 210 insertions, 0 deletions
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@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@gmail.com>
+Signed-off-by: Robert Marko <robert.marko@sartura.hr>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Cc: Luka Perkov <luka.perkov@sartura.hr>
+Signed-off-by: David S. Miller <davem@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");