net: dsa: ocelot: felix: utilize shared mscc-miim driver for indirect MDIO access
authorColin Foster <colin.foster@in-advantage.com>
Mon, 29 Nov 2021 01:57:37 +0000 (17:57 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 29 Nov 2021 13:02:00 +0000 (13:02 +0000)
Switch to a shared MDIO access implementation by way of the mdio-mscc-miim
driver.

Signed-off-by: Colin Foster <colin.foster@in-advantage.com>
Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/ocelot/Kconfig
drivers/net/dsa/ocelot/seville_vsc9953.c
drivers/net/mdio/mdio-mscc-miim.c
include/linux/mdio/mdio-mscc-miim.h [new file with mode: 0644]

index 9948544..220b0b0 100644 (file)
@@ -21,6 +21,7 @@ config NET_DSA_MSCC_SEVILLE
        depends on NET_VENDOR_MICROSEMI
        depends on HAS_IOMEM
        depends on PTP_1588_CLOCK_OPTIONAL
+       select MDIO_MSCC_MIIM
        select MSCC_OCELOT_SWITCH_LIB
        select NET_DSA_TAG_OCELOT_8021Q
        select NET_DSA_TAG_OCELOT
index db12492..b9be889 100644 (file)
@@ -6,19 +6,14 @@
 #include <soc/mscc/ocelot_vcap.h>
 #include <soc/mscc/ocelot_sys.h>
 #include <soc/mscc/ocelot.h>
+#include <linux/mdio/mdio-mscc-miim.h>
+#include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 #include <linux/pcs-lynx.h>
 #include <linux/dsa/ocelot.h>
 #include <linux/iopoll.h>
-#include <linux/of_mdio.h>
 #include "felix.h"
 
-#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 VSC9953_VCAP_POLICER_BASE              11
 #define VSC9953_VCAP_POLICER_MAX               31
 #define VSC9953_VCAP_POLICER_BASE2             120
@@ -862,7 +857,6 @@ static struct vcap_props vsc9953_vcap_props[] = {
 #define VSC9953_INIT_TIMEOUT                   50000
 #define VSC9953_GCB_RST_SLEEP                  100
 #define VSC9953_SYS_RAMINIT_SLEEP              80
-#define VCS9953_MII_TIMEOUT                    10000
 
 static int vsc9953_gcb_soft_rst_status(struct ocelot *ocelot)
 {
@@ -882,82 +876,6 @@ static int vsc9953_sys_ram_init_status(struct ocelot *ocelot)
        return val;
 }
 
-static int vsc9953_gcb_miim_pending_status(struct ocelot *ocelot)
-{
-       int val;
-
-       ocelot_field_read(ocelot, GCB_MIIM_MII_STATUS_PENDING, &val);
-
-       return val;
-}
-
-static int vsc9953_gcb_miim_busy_status(struct ocelot *ocelot)
-{
-       int val;
-
-       ocelot_field_read(ocelot, GCB_MIIM_MII_STATUS_BUSY, &val);
-
-       return val;
-}
-
-static int vsc9953_mdio_write(struct mii_bus *bus, int phy_id, int regnum,
-                             u16 value)
-{
-       struct ocelot *ocelot = bus->priv;
-       int err, cmd, val;
-
-       /* Wait while MIIM controller becomes idle */
-       err = readx_poll_timeout(vsc9953_gcb_miim_pending_status, ocelot,
-                                val, !val, 10, VCS9953_MII_TIMEOUT);
-       if (err) {
-               dev_err(ocelot->dev, "MDIO write: pending timeout\n");
-               goto out;
-       }
-
-       cmd = MSCC_MIIM_CMD_VLD | (phy_id << MSCC_MIIM_CMD_PHYAD_SHIFT) |
-             (regnum << MSCC_MIIM_CMD_REGAD_SHIFT) |
-             (value << MSCC_MIIM_CMD_WRDATA_SHIFT) |
-             MSCC_MIIM_CMD_OPR_WRITE;
-
-       ocelot_write(ocelot, cmd, GCB_MIIM_MII_CMD);
-
-out:
-       return err;
-}
-
-static int vsc9953_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
-{
-       struct ocelot *ocelot = bus->priv;
-       int err, cmd, val;
-
-       /* Wait until MIIM controller becomes idle */
-       err = readx_poll_timeout(vsc9953_gcb_miim_pending_status, ocelot,
-                                val, !val, 10, VCS9953_MII_TIMEOUT);
-       if (err) {
-               dev_err(ocelot->dev, "MDIO read: pending timeout\n");
-               goto out;
-       }
-
-       /* Write the MIIM COMMAND register */
-       cmd = MSCC_MIIM_CMD_VLD | (phy_id << MSCC_MIIM_CMD_PHYAD_SHIFT) |
-             (regnum << MSCC_MIIM_CMD_REGAD_SHIFT) | MSCC_MIIM_CMD_OPR_READ;
-
-       ocelot_write(ocelot, cmd, GCB_MIIM_MII_CMD);
-
-       /* Wait while read operation via the MIIM controller is in progress */
-       err = readx_poll_timeout(vsc9953_gcb_miim_busy_status, ocelot,
-                                val, !val, 10, VCS9953_MII_TIMEOUT);
-       if (err) {
-               dev_err(ocelot->dev, "MDIO read: busy timeout\n");
-               goto out;
-       }
-
-       val = ocelot_read(ocelot, GCB_MIIM_MII_DATA);
-
-       err = val & 0xFFFF;
-out:
-       return err;
-}
 
 /* CORE_ENA is in SYS:SYSTEM:RESET_CFG
  * MEM_INIT is in SYS:SYSTEM:RESET_CFG
@@ -1101,16 +1019,14 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot)
                return -ENOMEM;
        }
 
-       bus = devm_mdiobus_alloc(dev);
-       if (!bus)
-               return -ENOMEM;
+       rc = mscc_miim_setup(dev, &bus, "VSC9953 internal MDIO bus",
+                            ocelot->targets[GCB],
+                            ocelot->map[GCB][GCB_MIIM_MII_STATUS & REG_MASK]);
 
-       bus->name = "VSC9953 internal MDIO bus";
-       bus->read = vsc9953_mdio_read;
-       bus->write = vsc9953_mdio_write;
-       bus->parent = dev;
-       bus->priv = ocelot;
-       snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
+       if (rc) {
+               dev_err(dev, "failed to setup MDIO bus\n");
+               return rc;
+       }
 
        /* Needed in order to initialize the bus mutex lock */
        rc = of_mdiobus_register(bus, NULL);
index e016b32..2d420c9 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
+#include <linux/mdio/mdio-mscc-miim.h>
 #include <linux/module.h>
 #include <linux/of_mdio.h>
 #include <linux/phy.h>
@@ -37,7 +38,9 @@
 
 struct mscc_miim_dev {
        struct regmap *regs;
+       int mii_status_offset;
        struct regmap *phy_regs;
+       int phy_reset_offset;
 };
 
 /* When high resolution timers aren't built-in: we can't use usleep_range() as
@@ -56,7 +59,8 @@ static int mscc_miim_status(struct mii_bus *bus)
        struct mscc_miim_dev *miim = bus->priv;
        int val, ret;
 
-       ret = regmap_read(miim->regs, MSCC_MIIM_REG_STATUS, &val);
+       ret = regmap_read(miim->regs,
+                         MSCC_MIIM_REG_STATUS + miim->mii_status_offset, &val);
        if (ret < 0) {
                WARN_ONCE(1, "mscc miim status read error %d\n", ret);
                return ret;
@@ -93,7 +97,9 @@ static int mscc_miim_read(struct mii_bus *bus, int mii_id, int regnum)
        if (ret)
                goto out;
 
-       ret = regmap_write(miim->regs, MSCC_MIIM_REG_CMD, MSCC_MIIM_CMD_VLD |
+       ret = regmap_write(miim->regs,
+                          MSCC_MIIM_REG_CMD + miim->mii_status_offset,
+                          MSCC_MIIM_CMD_VLD |
                           (mii_id << MSCC_MIIM_CMD_PHYAD_SHIFT) |
                           (regnum << MSCC_MIIM_CMD_REGAD_SHIFT) |
                           MSCC_MIIM_CMD_OPR_READ);
@@ -107,8 +113,8 @@ static int mscc_miim_read(struct mii_bus *bus, int mii_id, int regnum)
        if (ret)
                goto out;
 
-       ret = regmap_read(miim->regs, MSCC_MIIM_REG_DATA, &val);
-
+       ret = regmap_read(miim->regs,
+                         MSCC_MIIM_REG_DATA + miim->mii_status_offset, &val);
        if (ret < 0) {
                WARN_ONCE(1, "mscc miim read data reg error %d\n", ret);
                goto out;
@@ -134,7 +140,9 @@ static int mscc_miim_write(struct mii_bus *bus, int mii_id,
        if (ret < 0)
                goto out;
 
-       ret = regmap_write(miim->regs, MSCC_MIIM_REG_CMD, MSCC_MIIM_CMD_VLD |
+       ret = regmap_write(miim->regs,
+                          MSCC_MIIM_REG_CMD + miim->mii_status_offset,
+                          MSCC_MIIM_CMD_VLD |
                           (mii_id << MSCC_MIIM_CMD_PHYAD_SHIFT) |
                           (regnum << MSCC_MIIM_CMD_REGAD_SHIFT) |
                           (value << MSCC_MIIM_CMD_WRDATA_SHIFT) |
@@ -149,16 +157,19 @@ out:
 static int mscc_miim_reset(struct mii_bus *bus)
 {
        struct mscc_miim_dev *miim = bus->priv;
+       int offset = miim->phy_reset_offset;
        int ret;
 
        if (miim->phy_regs) {
-               ret = regmap_write(miim->phy_regs, MSCC_PHY_REG_PHY_CFG, 0);
+               ret = regmap_write(miim->phy_regs,
+                                  MSCC_PHY_REG_PHY_CFG + offset, 0);
                if (ret < 0) {
                        WARN_ONCE(1, "mscc reset set error %d\n", ret);
                        return ret;
                }
 
-               ret = regmap_write(miim->phy_regs, MSCC_PHY_REG_PHY_CFG, 0x1ff);
+               ret = regmap_write(miim->phy_regs,
+                                  MSCC_PHY_REG_PHY_CFG + offset, 0x1ff);
                if (ret < 0) {
                        WARN_ONCE(1, "mscc reset clear error %d\n", ret);
                        return ret;
@@ -176,8 +187,8 @@ static const struct regmap_config mscc_miim_regmap_config = {
        .reg_stride     = 4,
 };
 
-static int mscc_miim_setup(struct device *dev, struct mii_bus **pbus,
-                          struct regmap *mii_regmap)
+int mscc_miim_setup(struct device *dev, struct mii_bus **pbus, const char *name,
+                   struct regmap *mii_regmap, int status_offset)
 {
        struct mscc_miim_dev *miim;
        struct mii_bus *bus;
@@ -186,7 +197,7 @@ static int mscc_miim_setup(struct device *dev, struct mii_bus **pbus,
        if (!bus)
                return -ENOMEM;
 
-       bus->name = "mscc_miim";
+       bus->name = name;
        bus->read = mscc_miim_read;
        bus->write = mscc_miim_write;
        bus->reset = mscc_miim_reset;
@@ -198,9 +209,13 @@ static int mscc_miim_setup(struct device *dev, struct mii_bus **pbus,
        *pbus = bus;
 
        miim->regs = mii_regmap;
+       miim->mii_status_offset = status_offset;
+
+       *pbus = bus;
 
        return 0;
 }
+EXPORT_SYMBOL(mscc_miim_setup);
 
 static int mscc_miim_probe(struct platform_device *pdev)
 {
@@ -237,7 +252,7 @@ static int mscc_miim_probe(struct platform_device *pdev)
                return PTR_ERR(phy_regmap);
        }
 
-       ret = mscc_miim_setup(&pdev->dev, &bus, mii_regmap);
+       ret = mscc_miim_setup(&pdev->dev, &bus, "mscc_miim", mii_regmap, 0);
        if (ret < 0) {
                dev_err(&pdev->dev, "Unable to setup the MDIO bus\n");
                return ret;
@@ -245,6 +260,7 @@ static int mscc_miim_probe(struct platform_device *pdev)
 
        miim = bus->priv;
        miim->phy_regs = phy_regmap;
+       miim->phy_reset_offset = 0;
 
        ret = of_mdiobus_register(bus, pdev->dev.of_node);
        if (ret < 0) {
diff --git a/include/linux/mdio/mdio-mscc-miim.h b/include/linux/mdio/mdio-mscc-miim.h
new file mode 100644 (file)
index 0000000..5b4ed2c
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Driver for the MDIO interface of Microsemi network switches.
+ *
+ * Author: Colin Foster <colin.foster@in-advantage.com>
+ * Copyright (C) 2021 Innovative Advantage
+ */
+#ifndef MDIO_MSCC_MIIM_H
+#define MDIO_MSCC_MIIM_H
+
+#include <linux/device.h>
+#include <linux/phy.h>
+#include <linux/regmap.h>
+
+int mscc_miim_setup(struct device *device, struct mii_bus **bus,
+                   const char *name, struct regmap *mii_regmap,
+                   int status_offset);
+
+#endif