OSDN Git Service

net: stmmac: Integrate it with DesignWare XPCS
authorJose Abreu <Jose.Abreu@synopsys.com>
Mon, 9 Mar 2020 08:36:27 +0000 (09:36 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 10 Mar 2020 03:13:16 +0000 (20:13 -0700)
Adds all the necessary logic so that stmmac can be used with Synopsys
DesignWare XPCS.

Signed-off-by: Jose Abreu <Jose.Abreu@synopsys.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/stmicro/stmmac/Kconfig
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/hwif.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
include/linux/stmmac.h

index 338e25a..9ad927f 100644 (file)
@@ -3,6 +3,7 @@ config STMMAC_ETH
        tristate "STMicroelectronics Multi-Gigabit Ethernet driver"
        depends on HAS_IOMEM && HAS_DMA
        select MII
+       select MDIO_XPCS
        select PAGE_POOL
        select PHYLINK
        select CRC32
index 4870990..9bdbf58 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/netdevice.h>
 #include <linux/stmmac.h>
 #include <linux/phy.h>
+#include <linux/mdio-xpcs.h>
 #include <linux/module.h>
 #if IS_ENABLED(CONFIG_VLAN_8021Q)
 #define STMMAC_VLAN_TAG_USED
@@ -446,6 +447,8 @@ struct mac_device_info {
        const struct stmmac_hwtimestamp *ptp;
        const struct stmmac_tc_ops *tc;
        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 mac_link link;
        void __iomem *pcsr;     /* vpointer to device CSRs */
index df63b03..c71dd99 100644 (file)
@@ -577,6 +577,18 @@ struct stmmac_mmc_ops {
 #define stmmac_mmc_read(__priv, __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 {
        u32 ptp_off;
        u32 mmc_off;
index 3a190cf..f26699d 100644 (file)
@@ -863,18 +863,26 @@ static void stmmac_validate(struct phylink_config *config,
 
        linkmode_and(state->advertising, state->advertising, mac_supported);
        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,
                                     struct phylink_link_state *state)
 {
+       struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
+
        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,
                              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)
@@ -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));
        u32 ctrl;
 
+       stmmac_xpcs_link_up(priv, &priv->hw->xpcs_args, speed, interface);
+
        ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
        ctrl &= ~priv->hw->link.speed_mask;
 
@@ -1042,6 +1052,7 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
 
        priv->phylink_config.dev = &priv->dev->dev;
        priv->phylink_config.type = PHYLINK_NETDEV;
+       priv->phylink_config.pcs_poll = true;
 
        if (!fwnode)
                fwnode = dev_fwnode(priv->device);
@@ -2689,7 +2700,8 @@ static int stmmac_open(struct net_device *dev)
        int ret;
 
        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);
                if (ret) {
                        netdev_err(priv->dev,
index cfe5d8b..b2a707e 100644 (file)
@@ -382,6 +382,14 @@ int stmmac_mdio_register(struct net_device *ndev)
                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)
                new_bus->reset = &stmmac_mdio_reset;
 
@@ -433,6 +441,25 @@ int stmmac_mdio_register(struct net_device *ndev)
                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) {
                dev_warn(dev, "No PHY found\n");
                mdiobus_unregister(new_bus);
index 19190c6..fbafb35 100644 (file)
@@ -80,6 +80,7 @@
 
 struct stmmac_mdio_bus_data {
        unsigned int phy_mask;
+       unsigned int has_xpcs;
        int *irqs;
        int probed_phy_irq;
        bool needs_reset;