Commit f213bbe8 authored by Jose Abreu's avatar Jose Abreu Committed by David S. Miller

net: stmmac: Integrate it with DesignWare XPCS

Adds all the necessary logic so that stmmac can be used with Synopsys
DesignWare XPCS.
Signed-off-by: default avatarJose Abreu <Jose.Abreu@synopsys.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fcb26bd2
...@@ -3,6 +3,7 @@ config STMMAC_ETH ...@@ -3,6 +3,7 @@ config STMMAC_ETH
tristate "STMicroelectronics Multi-Gigabit Ethernet driver" tristate "STMicroelectronics Multi-Gigabit Ethernet driver"
depends on HAS_IOMEM && HAS_DMA depends on HAS_IOMEM && HAS_DMA
select MII select MII
select MDIO_XPCS
select PAGE_POOL select PAGE_POOL
select PHYLINK select PHYLINK
select CRC32 select CRC32
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/stmmac.h> #include <linux/stmmac.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/mdio-xpcs.h>
#include <linux/module.h> #include <linux/module.h>
#if IS_ENABLED(CONFIG_VLAN_8021Q) #if IS_ENABLED(CONFIG_VLAN_8021Q)
#define STMMAC_VLAN_TAG_USED #define STMMAC_VLAN_TAG_USED
...@@ -446,6 +447,8 @@ struct mac_device_info { ...@@ -446,6 +447,8 @@ struct mac_device_info {
const struct stmmac_hwtimestamp *ptp; const struct stmmac_hwtimestamp *ptp;
const struct stmmac_tc_ops *tc; const struct stmmac_tc_ops *tc;
const struct stmmac_mmc_ops *mmc; const struct stmmac_mmc_ops *mmc;
const struct mdio_xpcs_ops *xpcs;
struct mdio_xpcs_args xpcs_args;
struct mii_regs mii; /* MII register Addresses */ struct mii_regs mii; /* MII register Addresses */
struct mac_link link; struct mac_link link;
void __iomem *pcsr; /* vpointer to device CSRs */ void __iomem *pcsr; /* vpointer to device CSRs */
......
...@@ -577,6 +577,18 @@ struct stmmac_mmc_ops { ...@@ -577,6 +577,18 @@ struct stmmac_mmc_ops {
#define stmmac_mmc_read(__priv, __args...) \ #define stmmac_mmc_read(__priv, __args...) \
stmmac_do_void_callback(__priv, mmc, read, __args) stmmac_do_void_callback(__priv, mmc, read, __args)
/* XPCS callbacks */
#define stmmac_xpcs_validate(__priv, __args...) \
stmmac_do_callback(__priv, xpcs, validate, __args)
#define stmmac_xpcs_config(__priv, __args...) \
stmmac_do_callback(__priv, xpcs, config, __args)
#define stmmac_xpcs_get_state(__priv, __args...) \
stmmac_do_callback(__priv, xpcs, get_state, __args)
#define stmmac_xpcs_link_up(__priv, __args...) \
stmmac_do_callback(__priv, xpcs, link_up, __args)
#define stmmac_xpcs_probe(__priv, __args...) \
stmmac_do_callback(__priv, xpcs, probe, __args)
struct stmmac_regs_off { struct stmmac_regs_off {
u32 ptp_off; u32 ptp_off;
u32 mmc_off; u32 mmc_off;
......
...@@ -863,18 +863,26 @@ static void stmmac_validate(struct phylink_config *config, ...@@ -863,18 +863,26 @@ static void stmmac_validate(struct phylink_config *config,
linkmode_and(state->advertising, state->advertising, mac_supported); linkmode_and(state->advertising, state->advertising, mac_supported);
linkmode_andnot(state->advertising, state->advertising, mask); linkmode_andnot(state->advertising, state->advertising, mask);
/* If PCS is supported, check which modes it supports. */
stmmac_xpcs_validate(priv, &priv->hw->xpcs_args, supported, state);
} }
static void stmmac_mac_pcs_get_state(struct phylink_config *config, static void stmmac_mac_pcs_get_state(struct phylink_config *config,
struct phylink_link_state *state) struct phylink_link_state *state)
{ {
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
state->link = 0; state->link = 0;
stmmac_xpcs_get_state(priv, &priv->hw->xpcs_args, state);
} }
static void stmmac_mac_config(struct phylink_config *config, unsigned int mode, static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state) const struct phylink_link_state *state)
{ {
/* Nothing for now. */ struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
stmmac_xpcs_config(priv, &priv->hw->xpcs_args, state);
} }
static void stmmac_mac_an_restart(struct phylink_config *config) static void stmmac_mac_an_restart(struct phylink_config *config)
...@@ -902,6 +910,8 @@ static void stmmac_mac_link_up(struct phylink_config *config, ...@@ -902,6 +910,8 @@ static void stmmac_mac_link_up(struct phylink_config *config,
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
u32 ctrl; u32 ctrl;
stmmac_xpcs_link_up(priv, &priv->hw->xpcs_args, speed, interface);
ctrl = readl(priv->ioaddr + MAC_CTRL_REG); ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
ctrl &= ~priv->hw->link.speed_mask; ctrl &= ~priv->hw->link.speed_mask;
...@@ -1042,6 +1052,7 @@ static int stmmac_phy_setup(struct stmmac_priv *priv) ...@@ -1042,6 +1052,7 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
priv->phylink_config.dev = &priv->dev->dev; priv->phylink_config.dev = &priv->dev->dev;
priv->phylink_config.type = PHYLINK_NETDEV; priv->phylink_config.type = PHYLINK_NETDEV;
priv->phylink_config.pcs_poll = true;
if (!fwnode) if (!fwnode)
fwnode = dev_fwnode(priv->device); fwnode = dev_fwnode(priv->device);
...@@ -2689,7 +2700,8 @@ static int stmmac_open(struct net_device *dev) ...@@ -2689,7 +2700,8 @@ static int stmmac_open(struct net_device *dev)
int ret; int ret;
if (priv->hw->pcs != STMMAC_PCS_TBI && if (priv->hw->pcs != STMMAC_PCS_TBI &&
priv->hw->pcs != STMMAC_PCS_RTBI) { priv->hw->pcs != STMMAC_PCS_RTBI &&
priv->hw->xpcs == NULL) {
ret = stmmac_init_phy(dev); ret = stmmac_init_phy(dev);
if (ret) { if (ret) {
netdev_err(priv->dev, netdev_err(priv->dev,
......
...@@ -382,6 +382,14 @@ int stmmac_mdio_register(struct net_device *ndev) ...@@ -382,6 +382,14 @@ int stmmac_mdio_register(struct net_device *ndev)
max_addr = PHY_MAX_ADDR; max_addr = PHY_MAX_ADDR;
} }
if (mdio_bus_data->has_xpcs) {
priv->hw->xpcs = mdio_xpcs_get_ops();
if (!priv->hw->xpcs) {
err = -ENODEV;
goto bus_register_fail;
}
}
if (mdio_bus_data->needs_reset) if (mdio_bus_data->needs_reset)
new_bus->reset = &stmmac_mdio_reset; new_bus->reset = &stmmac_mdio_reset;
...@@ -433,6 +441,25 @@ int stmmac_mdio_register(struct net_device *ndev) ...@@ -433,6 +441,25 @@ int stmmac_mdio_register(struct net_device *ndev)
found = 1; found = 1;
} }
/* Try to probe the XPCS by scanning all addresses. */
if (priv->hw->xpcs) {
struct mdio_xpcs_args *xpcs = &priv->hw->xpcs_args;
int ret, mode = priv->plat->phy_interface;
max_addr = PHY_MAX_ADDR;
xpcs->bus = new_bus;
for (addr = 0; addr < max_addr; addr++) {
xpcs->addr = addr;
ret = stmmac_xpcs_probe(priv, xpcs, mode);
if (!ret) {
found = 1;
break;
}
}
}
if (!found && !mdio_node) { if (!found && !mdio_node) {
dev_warn(dev, "No PHY found\n"); dev_warn(dev, "No PHY found\n");
mdiobus_unregister(new_bus); mdiobus_unregister(new_bus);
......
...@@ -80,6 +80,7 @@ ...@@ -80,6 +80,7 @@
struct stmmac_mdio_bus_data { struct stmmac_mdio_bus_data {
unsigned int phy_mask; unsigned int phy_mask;
unsigned int has_xpcs;
int *irqs; int *irqs;
int probed_phy_irq; int probed_phy_irq;
bool needs_reset; bool needs_reset;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment