1
0
Fork 0

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
572ee5d842 ("enetc: Make mdio accessors more generic"), which couldn't
be reverted cleanly due to the existing downstream workaround for the
MDIO erratum.

(cherry picked from commit 344355a498cca71105a1de23b2b519ed2f5f914f)
5.4-rM2-2.2.x-imx-squashed
Claudiu Manoil 2019-08-12 20:26:42 +03:00 committed by Jason Liu
parent 50975b8b38
commit 39c38d3a7b
8 changed files with 163 additions and 100 deletions

View 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

View 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
fsl-enetc-$(CONFIG_ENETC_TSN) += enetc_tsn.o

View File

@ -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, int phy_id, int regnum, u16 value)
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, int phy_id, int regnum)
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;
struct enetc_hw *hw;
bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
if (!bus)
return -ENOMEM;
hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
if (!hw)
return ERR_PTR(-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));
hw->port = port_regs;
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;
}
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;
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;
return hw;
}
EXPORT_SYMBOL_GPL(enetc_hw_alloc);

View File

@ -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);

View File

@ -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 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;
@ -39,7 +51,7 @@ static int enetc_pci_mdio_probe(struct pci_dev *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);
@ -48,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;
@ -64,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;
}

View 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"
@ -760,6 +761,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_pf *pf)
{
struct device *dev = &pf->si->pdev->dev;
@ -846,6 +893,30 @@ static void enetc_configure_sxgmii(struct mii_bus *imdio)
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);

View File

@ -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);

View File

@ -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