mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-23 15:32:33 +00:00
447 lines
13 KiB
Diff
447 lines
13 KiB
Diff
|
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
|