]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
enetc: Make MDIO accessors more generic and export to include/linux/fsl
authorClaudiu Manoil <claudiu.manoil@nxp.com>
Mon, 6 Jan 2020 01:34:13 +0000 (03:34 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 6 Jan 2020 07:22:32 +0000 (23:22 -0800)
Within the LS1028A SoC, the register map for the ENETC MDIO controller
is instantiated a few times: for the central (external) MDIO controller,
for the internal bus of each standalone ENETC port, and for the internal
bus of the Felix switch.

Refactoring is needed to support multiple MDIO buses from multiple
drivers. The enetc_hw structure is made an opaque type and a smaller
enetc_mdio_priv is created.

'mdio_base' - MDIO registers base address - is being parameterized, to
be able to work with different MDIO register bases.

The ENETC MDIO bus operations are exported from the fsl-enetc-mdio
kernel object, the same that registers the central MDIO controller (the
dedicated PF). The ENETC main driver has been changed to select it, and
use its exported helpers to further register its private MDIO bus. The
DSA Felix driver will do the same.

Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/freescale/enetc/Kconfig
drivers/net/ethernet/freescale/enetc/Makefile
drivers/net/ethernet/freescale/enetc/enetc_hw.h
drivers/net/ethernet/freescale/enetc/enetc_mdio.c
drivers/net/ethernet/freescale/enetc/enetc_mdio.h [deleted file]
drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
drivers/net/ethernet/freescale/enetc/enetc_pf.c
drivers/net/ethernet/freescale/enetc/enetc_pf.h
include/linux/fsl/enetc_mdio.h [new file with mode: 0644]

index edad4ca46327dafdf77476974c2b4f5778600d88..fe942de1959725922901167fd0e502e971e1f0c1 100644 (file)
@@ -2,6 +2,7 @@
 config FSL_ENETC
        tristate "ENETC PF driver"
        depends on PCI && PCI_MSI && (ARCH_LAYERSCAPE || COMPILE_TEST)
+       select FSL_ENETC_MDIO
        select PHYLIB
        help
          This driver supports NXP ENETC gigabit ethernet controller PCIe
index d0db33e5b6b7c3565d01b43b8562d72b2ff380bf..74f7ac253b8bbe912ce5e2dfd67548ff7c8badc1 100644 (file)
@@ -3,7 +3,7 @@
 common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o
 
 obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
-fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
+fsl-enetc-y := enetc_pf.o $(common-objs)
 fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
 fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
 
index 8375cd886dbaa92810eac9d3bcc220f562219b79..62554f28ce07e1b366535364851d467059afb2e6 100644 (file)
@@ -200,6 +200,7 @@ enum enetc_bdr_type {TX, RX};
 #define ENETC_PFPMR            0x1900
 #define ENETC_PFPMR_PMACE      BIT(1)
 #define ENETC_PFPMR_MWLM       BIT(0)
+#define ENETC_EMDIO_BASE       0x1c00
 #define ENETC_PSIUMHFR0(n, err)        (((err) ? 0x1d08 : 0x1d00) + (n) * 0x10)
 #define ENETC_PSIUMHFR1(n)     (0x1d04 + (n) * 0x10)
 #define ENETC_PSIMMHFR0(n, err)        (((err) ? 0x1d00 : 0x1d08) + (n) * 0x10)
index 149883c8f0b8c8347864ebac8eec78040d10802f..18c68e048d43a4cf79ffc5ba89af091a71127fd4 100644 (file)
@@ -1,24 +1,35 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
 /* Copyright 2019 NXP */
 
+#include <linux/fsl/enetc_mdio.h>
 #include <linux/mdio.h>
 #include <linux/of_mdio.h>
 #include <linux/iopoll.h>
 #include <linux/of.h>
 
-#include "enetc_mdio.h"
+#include "enetc_pf.h"
 
-#define        ENETC_MDIO_REG_OFFSET   0x1c00
 #define        ENETC_MDIO_CFG  0x0     /* MDIO configuration and status */
 #define        ENETC_MDIO_CTL  0x4     /* MDIO control */
 #define        ENETC_MDIO_DATA 0x8     /* MDIO data */
 #define        ENETC_MDIO_ADDR 0xc     /* MDIO address */
 
-#define enetc_mdio_rd(hw, off) \
-       enetc_port_rd(hw, ENETC_##off + ENETC_MDIO_REG_OFFSET)
-#define enetc_mdio_wr(hw, off, val) \
-       enetc_port_wr(hw, ENETC_##off + ENETC_MDIO_REG_OFFSET, val)
-#define enetc_mdio_rd_reg(off) enetc_mdio_rd(hw, off)
+static inline u32 _enetc_mdio_rd(struct enetc_mdio_priv *mdio_priv, int off)
+{
+       return enetc_port_rd(mdio_priv->hw, mdio_priv->mdio_base + off);
+}
+
+static inline void _enetc_mdio_wr(struct enetc_mdio_priv *mdio_priv, int off,
+                                 u32 val)
+{
+       enetc_port_wr(mdio_priv->hw, mdio_priv->mdio_base + off, val);
+}
+
+#define enetc_mdio_rd(mdio_priv, off) \
+       _enetc_mdio_rd(mdio_priv, ENETC_##off)
+#define enetc_mdio_wr(mdio_priv, off, val) \
+       _enetc_mdio_wr(mdio_priv, ENETC_##off, val)
+#define enetc_mdio_rd_reg(off) enetc_mdio_rd(mdio_priv, off)
 
 #define ENETC_MDC_DIV          258
 
@@ -35,7 +46,7 @@
 #define MDIO_DATA(x)           ((x) & 0xffff)
 
 #define TIMEOUT        1000
-static int enetc_mdio_wait_complete(struct enetc_hw *hw)
+static int enetc_mdio_wait_complete(struct enetc_mdio_priv *mdio_priv)
 {
        u32 val;
 
@@ -46,7 +57,6 @@ static int enetc_mdio_wait_complete(struct enetc_hw *hw)
 int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value)
 {
        struct enetc_mdio_priv *mdio_priv = bus->priv;
-       struct enetc_hw *hw = mdio_priv->hw;
        u32 mdio_ctl, mdio_cfg;
        u16 dev_addr;
        int ret;
@@ -61,39 +71,39 @@ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value)
                mdio_cfg &= ~MDIO_CFG_ENC45;
        }
 
-       enetc_mdio_wr(hw, MDIO_CFG, mdio_cfg);
+       enetc_mdio_wr(mdio_priv, MDIO_CFG, mdio_cfg);
 
-       ret = enetc_mdio_wait_complete(hw);
+       ret = enetc_mdio_wait_complete(mdio_priv);
        if (ret)
                return ret;
 
        /* set port and dev addr */
        mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
-       enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl);
+       enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl);
 
        /* set the register address */
        if (regnum & MII_ADDR_C45) {
-               enetc_mdio_wr(hw, MDIO_ADDR, regnum & 0xffff);
+               enetc_mdio_wr(mdio_priv, MDIO_ADDR, regnum & 0xffff);
 
-               ret = enetc_mdio_wait_complete(hw);
+               ret = enetc_mdio_wait_complete(mdio_priv);
                if (ret)
                        return ret;
        }
 
        /* write the value */
-       enetc_mdio_wr(hw, MDIO_DATA, MDIO_DATA(value));
+       enetc_mdio_wr(mdio_priv, MDIO_DATA, MDIO_DATA(value));
 
-       ret = enetc_mdio_wait_complete(hw);
+       ret = enetc_mdio_wait_complete(mdio_priv);
        if (ret)
                return ret;
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(enetc_mdio_write);
 
 int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
 {
        struct enetc_mdio_priv *mdio_priv = bus->priv;
-       struct enetc_hw *hw = mdio_priv->hw;
        u32 mdio_ctl, mdio_cfg;
        u16 dev_addr, value;
        int ret;
@@ -107,86 +117,56 @@ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
                mdio_cfg &= ~MDIO_CFG_ENC45;
        }
 
-       enetc_mdio_wr(hw, MDIO_CFG, mdio_cfg);
+       enetc_mdio_wr(mdio_priv, MDIO_CFG, mdio_cfg);
 
-       ret = enetc_mdio_wait_complete(hw);
+       ret = enetc_mdio_wait_complete(mdio_priv);
        if (ret)
                return ret;
 
        /* set port and device addr */
        mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
-       enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl);
+       enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl);
 
        /* set the register address */
        if (regnum & MII_ADDR_C45) {
-               enetc_mdio_wr(hw, MDIO_ADDR, regnum & 0xffff);
+               enetc_mdio_wr(mdio_priv, MDIO_ADDR, regnum & 0xffff);
 
-               ret = enetc_mdio_wait_complete(hw);
+               ret = enetc_mdio_wait_complete(mdio_priv);
                if (ret)
                        return ret;
        }
 
        /* initiate the read */
-       enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
+       enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
 
-       ret = enetc_mdio_wait_complete(hw);
+       ret = enetc_mdio_wait_complete(mdio_priv);
        if (ret)
                return ret;
 
        /* return all Fs if nothing was there */
-       if (enetc_mdio_rd(hw, MDIO_CFG) & MDIO_CFG_RD_ER) {
+       if (enetc_mdio_rd(mdio_priv, MDIO_CFG) & MDIO_CFG_RD_ER) {
                dev_dbg(&bus->dev,
                        "Error while reading PHY%d reg at %d.%hhu\n",
                        phy_id, dev_addr, regnum);
                return 0xffff;
        }
 
-       value = enetc_mdio_rd(hw, MDIO_DATA) & 0xffff;
+       value = enetc_mdio_rd(mdio_priv, MDIO_DATA) & 0xffff;
 
        return value;
 }
+EXPORT_SYMBOL_GPL(enetc_mdio_read);
 
-int enetc_mdio_probe(struct enetc_pf *pf)
+struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
 {
-       struct device *dev = &pf->si->pdev->dev;
-       struct enetc_mdio_priv *mdio_priv;
-       struct device_node *np;
-       struct mii_bus *bus;
-       int err;
-
-       bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
-       if (!bus)
-               return -ENOMEM;
-
-       bus->name = "Freescale ENETC MDIO Bus";
-       bus->read = enetc_mdio_read;
-       bus->write = enetc_mdio_write;
-       bus->parent = dev;
-       mdio_priv = bus->priv;
-       mdio_priv->hw = &pf->si->hw;
-       snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
-
-       np = of_get_child_by_name(dev->of_node, "mdio");
-       if (!np) {
-               dev_err(dev, "MDIO node missing\n");
-               return -EINVAL;
-       }
-
-       err = of_mdiobus_register(bus, np);
-       if (err) {
-               of_node_put(np);
-               dev_err(dev, "cannot register MDIO bus\n");
-               return err;
-       }
+       struct enetc_hw *hw;
 
-       of_node_put(np);
-       pf->mdio = bus;
+       hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
+       if (!hw)
+               return ERR_PTR(-ENOMEM);
 
-       return 0;
-}
+       hw->port = port_regs;
 
-void enetc_mdio_remove(struct enetc_pf *pf)
-{
-       if (pf->mdio)
-               mdiobus_unregister(pf->mdio);
+       return hw;
 }
+EXPORT_SYMBOL_GPL(enetc_hw_alloc);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_mdio.h b/drivers/net/ethernet/freescale/enetc/enetc_mdio.h
deleted file mode 100644 (file)
index 60c9a38..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/* Copyright 2019 NXP */
-
-#include <linux/phy.h>
-#include "enetc_pf.h"
-
-struct enetc_mdio_priv {
-       struct enetc_hw *hw;
-};
-
-int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value);
-int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum);
index fbd41ce01f0688552a67e6268e3268442eb33b98..87c0e969da405f89625914b4c308246e5e61a9dc 100644 (file)
@@ -1,7 +1,8 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
 /* Copyright 2019 NXP */
+#include <linux/fsl/enetc_mdio.h>
 #include <linux/of_mdio.h>
-#include "enetc_mdio.h"
+#include "enetc_pf.h"
 
 #define ENETC_MDIO_DEV_ID      0xee01
 #define ENETC_MDIO_DEV_NAME    "FSL PCIe IE Central MDIO"
@@ -13,17 +14,29 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev,
 {
        struct enetc_mdio_priv *mdio_priv;
        struct device *dev = &pdev->dev;
+       void __iomem *port_regs;
        struct enetc_hw *hw;
        struct mii_bus *bus;
        int err;
 
-       hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
-       if (!hw)
-               return -ENOMEM;
+       port_regs = pci_iomap(pdev, 0, 0);
+       if (!port_regs) {
+               dev_err(dev, "iomap failed\n");
+               err = -ENXIO;
+               goto err_ioremap;
+       }
+
+       hw = enetc_hw_alloc(dev, port_regs);
+       if (IS_ERR(enetc_hw_alloc)) {
+               err = PTR_ERR(hw);
+               goto err_hw_alloc;
+       }
 
        bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
-       if (!bus)
-               return -ENOMEM;
+       if (!bus) {
+               err = -ENOMEM;
+               goto err_mdiobus_alloc;
+       }
 
        bus->name = ENETC_MDIO_BUS_NAME;
        bus->read = enetc_mdio_read;
@@ -31,13 +44,14 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev,
        bus->parent = dev;
        mdio_priv = bus->priv;
        mdio_priv->hw = hw;
+       mdio_priv->mdio_base = ENETC_EMDIO_BASE;
        snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
 
        pcie_flr(pdev);
        err = pci_enable_device_mem(pdev);
        if (err) {
                dev_err(dev, "device enable failed\n");
-               return err;
+               goto err_pci_enable;
        }
 
        err = pci_request_region(pdev, 0, KBUILD_MODNAME);
@@ -46,13 +60,6 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev,
                goto err_pci_mem_reg;
        }
 
-       hw->port = pci_iomap(pdev, 0, 0);
-       if (!hw->port) {
-               err = -ENXIO;
-               dev_err(dev, "iomap failed\n");
-               goto err_ioremap;
-       }
-
        err = of_mdiobus_register(bus, dev->of_node);
        if (err)
                goto err_mdiobus_reg;
@@ -62,12 +69,14 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev,
        return 0;
 
 err_mdiobus_reg:
-       iounmap(mdio_priv->hw->port);
-err_ioremap:
        pci_release_mem_regions(pdev);
 err_pci_mem_reg:
        pci_disable_device(pdev);
-
+err_pci_enable:
+err_mdiobus_alloc:
+       iounmap(port_regs);
+err_hw_alloc:
+err_ioremap:
        return err;
 }
 
index e7482d483b288f55b34f069f01d2810f22b4b7b3..fc0d7d99e9a18d26dbd19b5845c629ac40320a29 100644 (file)
@@ -2,6 +2,7 @@
 /* Copyright 2017-2019 NXP */
 
 #include <linux/module.h>
+#include <linux/fsl/enetc_mdio.h>
 #include <linux/of_mdio.h>
 #include <linux/of_net.h>
 #include "enetc_pf.h"
@@ -749,6 +750,52 @@ static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
        enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr);
 }
 
+static int enetc_mdio_probe(struct enetc_pf *pf)
+{
+       struct device *dev = &pf->si->pdev->dev;
+       struct enetc_mdio_priv *mdio_priv;
+       struct device_node *np;
+       struct mii_bus *bus;
+       int err;
+
+       bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+       if (!bus)
+               return -ENOMEM;
+
+       bus->name = "Freescale ENETC MDIO Bus";
+       bus->read = enetc_mdio_read;
+       bus->write = enetc_mdio_write;
+       bus->parent = dev;
+       mdio_priv = bus->priv;
+       mdio_priv->hw = &pf->si->hw;
+       mdio_priv->mdio_base = ENETC_EMDIO_BASE;
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+
+       np = of_get_child_by_name(dev->of_node, "mdio");
+       if (!np) {
+               dev_err(dev, "MDIO node missing\n");
+               return -EINVAL;
+       }
+
+       err = of_mdiobus_register(bus, np);
+       if (err) {
+               of_node_put(np);
+               dev_err(dev, "cannot register MDIO bus\n");
+               return err;
+       }
+
+       of_node_put(np);
+       pf->mdio = bus;
+
+       return 0;
+}
+
+static void enetc_mdio_remove(struct enetc_pf *pf)
+{
+       if (pf->mdio)
+               mdiobus_unregister(pf->mdio);
+}
+
 static int enetc_of_get_phy(struct enetc_ndev_priv *priv)
 {
        struct enetc_pf *pf = enetc_si_priv(priv->si);
index 10dd1b53bb080bf038916e368a969914097d407a..59e65a6f6c3e1ced65331cdb53f98365775e5e2c 100644 (file)
@@ -49,7 +49,3 @@ struct enetc_pf {
 int enetc_msg_psi_init(struct enetc_pf *pf);
 void enetc_msg_psi_free(struct enetc_pf *pf);
 void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int mbox_id, u16 *status);
-
-/* MDIO */
-int enetc_mdio_probe(struct enetc_pf *pf);
-void enetc_mdio_remove(struct enetc_pf *pf);
diff --git a/include/linux/fsl/enetc_mdio.h b/include/linux/fsl/enetc_mdio.h
new file mode 100644 (file)
index 0000000..4875dd3
--- /dev/null
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/* Copyright 2019 NXP */
+
+#ifndef _FSL_ENETC_MDIO_H_
+#define _FSL_ENETC_MDIO_H_
+
+#include <linux/phy.h>
+
+/* PCS registers */
+#define ENETC_PCS_LINK_TIMER1                  0x12
+#define ENETC_PCS_LINK_TIMER1_VAL              0x06a0
+#define ENETC_PCS_LINK_TIMER2                  0x13
+#define ENETC_PCS_LINK_TIMER2_VAL              0x0003
+#define ENETC_PCS_IF_MODE                      0x14
+#define ENETC_PCS_IF_MODE_SGMII_EN             BIT(0)
+#define ENETC_PCS_IF_MODE_USE_SGMII_AN         BIT(1)
+#define ENETC_PCS_IF_MODE_SGMII_SPEED(x)       (((x) << 2) & GENMASK(3, 2))
+
+/* Not a mistake, the SerDes PLL needs to be set at 3.125 GHz by Reset
+ * Configuration Word (RCW, outside Linux control) for 2.5G SGMII mode. The PCS
+ * still thinks it's at gigabit.
+ */
+enum enetc_pcs_speed {
+       ENETC_PCS_SPEED_10      = 0,
+       ENETC_PCS_SPEED_100     = 1,
+       ENETC_PCS_SPEED_1000    = 2,
+       ENETC_PCS_SPEED_2500    = 2,
+};
+
+struct enetc_hw;
+
+struct enetc_mdio_priv {
+       struct enetc_hw *hw;
+       int mdio_base;
+};
+
+#if IS_REACHABLE(CONFIG_FSL_ENETC_MDIO)
+
+int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum);
+int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value);
+struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs);
+
+#else
+
+static inline int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
+{ return -EINVAL; }
+static inline int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum,
+                                  u16 value)
+{ return -EINVAL; }
+struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
+{ return ERR_PTR(-EINVAL); }
+
+#endif
+
+#endif