layerscape: add patches-5.4
[openwrt/staging/wigyori.git] / target / linux / layerscape / patches-5.4 / 701-net-0382-enetc-Make-MDIO-accessors-more-generic-and-export-to.patch
diff --git a/target/linux/layerscape/patches-5.4/701-net-0382-enetc-Make-MDIO-accessors-more-generic-and-export-to.patch b/target/linux/layerscape/patches-5.4/701-net-0382-enetc-Make-MDIO-accessors-more-generic-and-export-to.patch
new file mode 100644 (file)
index 0000000..6a1e647
--- /dev/null
@@ -0,0 +1,446 @@
+From 126e6f022c749ac1bf3a607269a106ccd87d0594 Mon Sep 17 00:00:00 2001
+From: Claudiu Manoil <claudiu.manoil@nxp.com>
+Date: Mon, 12 Aug 2019 20:26:42 +0300
+Subject: [PATCH] enetc: Make MDIO accessors more generic and export to
+ include/linux/fsl
+
+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>
+
+Conflicts:
+       drivers/net/ethernet/freescale/enetc/enetc_mdio.c
+       drivers/net/ethernet/freescale/enetc/enetc_mdio.h
+       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
+
+mostly with the previous (downstream version of this commit) patch
+572ee5d842da ("enetc: Make mdio accessors more generic"), which couldn't
+be reverted cleanly due to the existing downstream workaround for the
+MDIO erratum.
+---
+ drivers/net/ethernet/freescale/enetc/Kconfig       |  1 +
+ drivers/net/ethernet/freescale/enetc/Makefile      |  2 +-
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.c  | 76 ++++------------------
+ drivers/net/ethernet/freescale/enetc/enetc_mdio.h  | 12 ----
+ .../net/ethernet/freescale/enetc/enetc_pci_mdio.c  | 41 +++++++-----
+ drivers/net/ethernet/freescale/enetc/enetc_pf.c    | 71 ++++++++++++++++++++
+ drivers/net/ethernet/freescale/enetc/enetc_pf.h    |  5 --
+ include/linux/fsl/enetc_mdio.h                     | 55 ++++++++++++++++
+ 8 files changed, 163 insertions(+), 100 deletions(-)
+ delete mode 100644 drivers/net/ethernet/freescale/enetc/enetc_mdio.h
+ create mode 100644 include/linux/fsl/enetc_mdio.h
+
+--- a/drivers/net/ethernet/freescale/enetc/Kconfig
++++ b/drivers/net/ethernet/freescale/enetc/Kconfig
+@@ -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
+--- a/drivers/net/ethernet/freescale/enetc/Makefile
++++ b/drivers/net/ethernet/freescale/enetc/Makefile
+@@ -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
+ fsl-enetc-$(CONFIG_ENETC_TSN) += enetc_tsn.o
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
+@@ -1,13 +1,13 @@
+ // 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_pf.h"
+-#include "enetc_mdio.h"
+ #define       ENETC_MDIO_CFG  0x0     /* MDIO configuration and status */
+ #define       ENETC_MDIO_CTL  0x4     /* MDIO control */
+@@ -99,6 +99,7 @@ int enetc_mdio_write(struct mii_bus *bus
+       return 0;
+ }
++EXPORT_SYMBOL_GPL(enetc_mdio_write);
+ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
+ {
+@@ -154,73 +155,18 @@ int enetc_mdio_read(struct mii_bus *bus,
+       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;
+-      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;
+-}
++      struct enetc_hw *hw;
+-void enetc_mdio_remove(struct enetc_pf *pf)
+-{
+-      if (pf->mdio)
+-              mdiobus_unregister(pf->mdio);
+-}
+-
+-int enetc_imdio_init(struct enetc_pf *pf)
+-{
+-      struct device *dev = &pf->si->pdev->dev;
+-      struct enetc_mdio_priv *mdio_priv;
+-      struct mii_bus *bus;
++      hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
++      if (!hw)
++              return ERR_PTR(-ENOMEM);
+-      bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+-      if (!bus)
+-              return -ENOMEM;
++      hw->port = port_regs;
+-      bus->name = "FSL ENETC internal 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_PM_IMDIO_BASE;
+-      snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+-
+-      pf->imdio = bus;
+-
+-      return 0;
++      return hw;
+ }
++EXPORT_SYMBOL_GPL(enetc_hw_alloc);
+--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.h
++++ /dev/null
+@@ -1,12 +0,0 @@
+-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+-/* Copyright 2019 NXP */
+-
+-#include <linux/phy.h>
+-
+-struct enetc_mdio_priv {
+-      struct enetc_hw *hw;
+-      int mdio_base;
+-};
+-
+-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);
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
+@@ -1,8 +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_pf.h"
+-#include "enetc_mdio.h"
+ #define ENETC_MDIO_DEV_ID     0xee01
+ #define ENETC_MDIO_DEV_NAME   "FSL PCIe IE Central MDIO"
+@@ -14,17 +14,29 @@ static int enetc_pci_mdio_probe(struct p
+ {
+       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;
+@@ -39,7 +51,7 @@ static int enetc_pci_mdio_probe(struct p
+       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);
+@@ -48,13 +60,6 @@ static int enetc_pci_mdio_probe(struct p
+               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;
+@@ -64,12 +69,14 @@ static int enetc_pci_mdio_probe(struct p
+       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;
+ }
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+@@ -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"
+@@ -760,6 +761,52 @@ static void enetc_pf_netdev_setup(struct
+       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_pf *pf)
+ {
+       struct device *dev = &pf->si->pdev->dev;
+@@ -846,6 +893,30 @@ static void enetc_configure_sxgmii(struc
+                    ENETC_PCS_CR_LANE_RESET | ENETC_PCS_CR_RESET_AN);
+ }
++static int enetc_imdio_init(struct enetc_pf *pf)
++{
++      struct device *dev = &pf->si->pdev->dev;
++      struct enetc_mdio_priv *mdio_priv;
++      struct mii_bus *bus;
++
++      bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
++      if (!bus)
++              return -ENOMEM;
++
++      bus->name = "FSL ENETC internal 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_PM_IMDIO_BASE;
++      snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
++
++      pf->imdio = bus;
++
++      return 0;
++}
++
+ static int enetc_configure_serdes(struct enetc_ndev_priv *priv)
+ {
+       struct enetc_pf *pf = enetc_si_priv(priv->si);
+--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+@@ -53,8 +53,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);
+-int enetc_imdio_init(struct enetc_pf *pf);
+--- /dev/null
++++ b/include/linux/fsl/enetc_mdio.h
+@@ -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