]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
net: dsa: mt7530: Convert to PHYLINK API
authorRené van Dorst <opensource@vdorst.com>
Mon, 2 Sep 2019 13:02:24 +0000 (15:02 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 4 Sep 2019 22:28:23 +0000 (00:28 +0200)
Convert mt7530 to PHYLINK API

Signed-off-by: René van Dorst <opensource@vdorst.com>
Tested-by: Frank Wunderlich <frank-w@public-files.de>
Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/mt7530.c
drivers/net/dsa/mt7530.h

index c48e29486b10b50c82d416966945c725fefc822c..ecc13b57e61980eb8341a26bd8af626b9140b3be 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/of_mdio.h>
 #include <linux/of_net.h>
 #include <linux/of_platform.h>
-#include <linux/phy.h>
+#include <linux/phylink.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
@@ -633,63 +633,6 @@ mt7530_get_sset_count(struct dsa_switch *ds, int port, int sset)
        return ARRAY_SIZE(mt7530_mib);
 }
 
-static void mt7530_adjust_link(struct dsa_switch *ds, int port,
-                              struct phy_device *phydev)
-{
-       struct mt7530_priv *priv = ds->priv;
-
-       if (phy_is_pseudo_fixed_link(phydev)) {
-               dev_dbg(priv->dev, "phy-mode for master device = %x\n",
-                       phydev->interface);
-
-               /* Setup TX circuit incluing relevant PAD and driving */
-               mt7530_pad_clk_setup(ds, phydev->interface);
-
-               if (priv->id == ID_MT7530) {
-                       /* Setup RX circuit, relevant PAD and driving on the
-                        * host which must be placed after the setup on the
-                        * device side is all finished.
-                        */
-                       mt7623_pad_clk_setup(ds);
-               }
-       } else {
-               u16 lcl_adv = 0, rmt_adv = 0;
-               u8 flowctrl;
-               u32 mcr = PMCR_USERP_LINK | PMCR_FORCE_MODE;
-
-               switch (phydev->speed) {
-               case SPEED_1000:
-                       mcr |= PMCR_FORCE_SPEED_1000;
-                       break;
-               case SPEED_100:
-                       mcr |= PMCR_FORCE_SPEED_100;
-                       break;
-               }
-
-               if (phydev->link)
-                       mcr |= PMCR_FORCE_LNK;
-
-               if (phydev->duplex) {
-                       mcr |= PMCR_FORCE_FDX;
-
-                       if (phydev->pause)
-                               rmt_adv = LPA_PAUSE_CAP;
-                       if (phydev->asym_pause)
-                               rmt_adv |= LPA_PAUSE_ASYM;
-
-                       lcl_adv = linkmode_adv_to_lcl_adv_t(
-                               phydev->advertising);
-                       flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
-
-                       if (flowctrl & FLOW_CTRL_TX)
-                               mcr |= PMCR_TX_FC_EN;
-                       if (flowctrl & FLOW_CTRL_RX)
-                               mcr |= PMCR_RX_FC_EN;
-               }
-               mt7530_write(priv, MT7530_PMCR_P(port), mcr);
-       }
-}
-
 static int
 mt7530_cpu_port_enable(struct mt7530_priv *priv,
                       int port)
@@ -698,9 +641,6 @@ mt7530_cpu_port_enable(struct mt7530_priv *priv,
        mt7530_write(priv, MT7530_PVC_P(port),
                     PORT_SPEC_TAG);
 
-       /* Setup the MAC by default for the cpu port */
-       mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPUP_LINK);
-
        /* Disable auto learning on the cpu port */
        mt7530_set(priv, MT7530_PSC_P(port), SA_DIS);
 
@@ -731,9 +671,6 @@ mt7530_port_enable(struct dsa_switch *ds, int port,
 
        mutex_lock(&priv->reg_mutex);
 
-       /* Setup the MAC for the user port */
-       mt7530_write(priv, MT7530_PMCR_P(port), PMCR_USERP_LINK);
-
        /* Allow the user port gets connected to the cpu port and also
         * restore the port matrix if the port is the member of a certain
         * bridge.
@@ -742,7 +679,7 @@ mt7530_port_enable(struct dsa_switch *ds, int port,
        priv->ports[port].enable = true;
        mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
                   priv->ports[port].pm);
-       mt7530_port_set_status(priv, port, 1);
+       mt7530_port_set_status(priv, port, 0);
 
        mutex_unlock(&priv->reg_mutex);
 
@@ -1232,10 +1169,10 @@ static int
 mt7530_setup(struct dsa_switch *ds)
 {
        struct mt7530_priv *priv = ds->priv;
-       int ret, i;
-       u32 id, val;
-       struct device_node *dn;
        struct mt7530_dummy_poll p;
+       struct device_node *dn;
+       u32 id, val;
+       int ret, i;
 
        /* The parent node of master netdev which holds the common system
         * controller also is the container for two GMACs nodes representing
@@ -1305,6 +1242,8 @@ mt7530_setup(struct dsa_switch *ds)
        val |= MHWTRAP_MANUAL;
        mt7530_write(priv, MT7530_MHWTRAP, val);
 
+       priv->p6_interface = PHY_INTERFACE_MODE_NA;
+
        /* Enable and reset MIB counters */
        mt7530_mib_reset(ds);
 
@@ -1329,6 +1268,191 @@ mt7530_setup(struct dsa_switch *ds)
        return 0;
 }
 
+static void mt7530_phylink_mac_config(struct dsa_switch *ds, int port,
+                                     unsigned int mode,
+                                     const struct phylink_link_state *state)
+{
+       struct mt7530_priv *priv = ds->priv;
+       u32 mcr_cur, mcr_new;
+
+       switch (port) {
+       case 0: /* Internal phy */
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+               if (state->interface != PHY_INTERFACE_MODE_GMII)
+                       return;
+               break;
+       /* case 5: Port 5 is not supported! */
+       case 6: /* 1st cpu port */
+               if (priv->p6_interface == state->interface)
+                       break;
+
+               if (state->interface != PHY_INTERFACE_MODE_RGMII &&
+                   state->interface != PHY_INTERFACE_MODE_TRGMII)
+                       return;
+
+               /* Setup TX circuit incluing relevant PAD and driving */
+               mt7530_pad_clk_setup(ds, state->interface);
+
+               if (priv->id == ID_MT7530) {
+                       /* Setup RX circuit, relevant PAD and driving on the
+                        * host which must be placed after the setup on the
+                        * device side is all finished.
+                        */
+                       mt7623_pad_clk_setup(ds);
+               }
+
+               priv->p6_interface = state->interface;
+               break;
+       default:
+               dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
+               return;
+       }
+
+       if (phylink_autoneg_inband(mode)) {
+               dev_err(ds->dev, "%s: in-band negotiation unsupported\n",
+                       __func__);
+               return;
+       }
+
+       mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
+       mcr_new = mcr_cur;
+       mcr_new &= ~(PMCR_FORCE_SPEED_1000 | PMCR_FORCE_SPEED_100 |
+                    PMCR_FORCE_FDX | PMCR_TX_FC_EN | PMCR_RX_FC_EN);
+       mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN |
+                  PMCR_BACKPR_EN | PMCR_FORCE_MODE | PMCR_FORCE_LNK;
+
+       switch (state->speed) {
+       case SPEED_1000:
+               mcr_new |= PMCR_FORCE_SPEED_1000;
+               break;
+       case SPEED_100:
+               mcr_new |= PMCR_FORCE_SPEED_100;
+               break;
+       }
+       if (state->duplex == DUPLEX_FULL) {
+               mcr_new |= PMCR_FORCE_FDX;
+               if (state->pause & MLO_PAUSE_TX)
+                       mcr_new |= PMCR_TX_FC_EN;
+               if (state->pause & MLO_PAUSE_RX)
+                       mcr_new |= PMCR_RX_FC_EN;
+       }
+
+       if (mcr_new != mcr_cur)
+               mt7530_write(priv, MT7530_PMCR_P(port), mcr_new);
+}
+
+static void mt7530_phylink_mac_link_down(struct dsa_switch *ds, int port,
+                                        unsigned int mode,
+                                        phy_interface_t interface)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       mt7530_port_set_status(priv, port, 0);
+}
+
+static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port,
+                                      unsigned int mode,
+                                      phy_interface_t interface,
+                                      struct phy_device *phydev)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       mt7530_port_set_status(priv, port, 1);
+}
+
+static void mt7530_phylink_validate(struct dsa_switch *ds, int port,
+                                   unsigned long *supported,
+                                   struct phylink_link_state *state)
+{
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+       switch (port) {
+       case 0: /* Internal phy */
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+               if (state->interface != PHY_INTERFACE_MODE_NA &&
+                   state->interface != PHY_INTERFACE_MODE_GMII)
+                       goto unsupported;
+               break;
+       /* case 5: Port 5 not supported! */
+       case 6: /* 1st cpu port */
+               if (state->interface != PHY_INTERFACE_MODE_NA &&
+                   state->interface != PHY_INTERFACE_MODE_RGMII &&
+                   state->interface != PHY_INTERFACE_MODE_TRGMII)
+                       goto unsupported;
+               break;
+       default:
+               dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
+unsupported:
+               linkmode_zero(supported);
+               return;
+       }
+
+       phylink_set_port_modes(mask);
+       phylink_set(mask, Autoneg);
+
+       if (state->interface != PHY_INTERFACE_MODE_TRGMII) {
+               phylink_set(mask, 10baseT_Half);
+               phylink_set(mask, 10baseT_Full);
+               phylink_set(mask, 100baseT_Half);
+               phylink_set(mask, 100baseT_Full);
+               phylink_set(mask, 1000baseT_Half);
+       }
+
+       phylink_set(mask, 1000baseT_Full);
+
+       phylink_set(mask, Pause);
+       phylink_set(mask, Asym_Pause);
+
+       linkmode_and(supported, supported, mask);
+       linkmode_and(state->advertising, state->advertising, mask);
+}
+
+static int
+mt7530_phylink_mac_link_state(struct dsa_switch *ds, int port,
+                             struct phylink_link_state *state)
+{
+       struct mt7530_priv *priv = ds->priv;
+       u32 pmsr;
+
+       if (port < 0 || port >= MT7530_NUM_PORTS)
+               return -EINVAL;
+
+       pmsr = mt7530_read(priv, MT7530_PMSR_P(port));
+
+       state->link = (pmsr & PMSR_LINK);
+       state->an_complete = state->link;
+       state->duplex = !!(pmsr & PMSR_DPX);
+
+       switch (pmsr & PMSR_SPEED_MASK) {
+       case PMSR_SPEED_10:
+               state->speed = SPEED_10;
+               break;
+       case PMSR_SPEED_100:
+               state->speed = SPEED_100;
+               break;
+       case PMSR_SPEED_1000:
+               state->speed = SPEED_1000;
+               break;
+       default:
+               state->speed = SPEED_UNKNOWN;
+               break;
+       }
+
+       state->pause &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX);
+       if (pmsr & PMSR_RX_FC)
+               state->pause |= MLO_PAUSE_RX;
+       if (pmsr & PMSR_TX_FC)
+               state->pause |= MLO_PAUSE_TX;
+
+       return 1;
+}
+
 static const struct dsa_switch_ops mt7530_switch_ops = {
        .get_tag_protocol       = mtk_get_tag_protocol,
        .setup                  = mt7530_setup,
@@ -1337,7 +1461,6 @@ static const struct dsa_switch_ops mt7530_switch_ops = {
        .phy_write              = mt7530_phy_write,
        .get_ethtool_stats      = mt7530_get_ethtool_stats,
        .get_sset_count         = mt7530_get_sset_count,
-       .adjust_link            = mt7530_adjust_link,
        .port_enable            = mt7530_port_enable,
        .port_disable           = mt7530_port_disable,
        .port_stp_state_set     = mt7530_stp_state_set,
@@ -1350,6 +1473,11 @@ static const struct dsa_switch_ops mt7530_switch_ops = {
        .port_vlan_prepare      = mt7530_port_vlan_prepare,
        .port_vlan_add          = mt7530_port_vlan_add,
        .port_vlan_del          = mt7530_port_vlan_del,
+       .phylink_validate       = mt7530_phylink_validate,
+       .phylink_mac_link_state = mt7530_phylink_mac_link_state,
+       .phylink_mac_config     = mt7530_phylink_mac_config,
+       .phylink_mac_link_down  = mt7530_phylink_mac_link_down,
+       .phylink_mac_link_up    = mt7530_phylink_mac_link_up,
 };
 
 static const struct of_device_id mt7530_of_match[] = {
index bfac90f481026ff2d24e88633daf5af4e2c2c29e..107dd04acede3afa7b07c79436975e2af5d9c004 100644 (file)
@@ -198,26 +198,20 @@ enum mt7530_vlan_port_attr {
 #define  PMCR_FORCE_SPEED_100          BIT(2)
 #define  PMCR_FORCE_FDX                        BIT(1)
 #define  PMCR_FORCE_LNK                        BIT(0)
-#define  PMCR_COMMON_LINK              (PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
-                                        PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \
-                                        PMCR_TX_EN | PMCR_RX_EN | \
-                                        PMCR_TX_FC_EN | PMCR_RX_FC_EN)
-#define  PMCR_CPUP_LINK                        (PMCR_COMMON_LINK | PMCR_FORCE_MODE | \
-                                        PMCR_FORCE_SPEED_1000 | \
-                                        PMCR_FORCE_FDX | \
-                                        PMCR_FORCE_LNK)
-#define  PMCR_USERP_LINK               PMCR_COMMON_LINK
-#define  PMCR_FIXED_LINK               (PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
-                                        PMCR_FORCE_MODE | PMCR_TX_EN | \
-                                        PMCR_RX_EN | PMCR_BACKPR_EN | \
-                                        PMCR_BACKOFF_EN | \
-                                        PMCR_FORCE_SPEED_1000 | \
-                                        PMCR_FORCE_FDX | \
-                                        PMCR_FORCE_LNK)
-#define PMCR_FIXED_LINK_FC             (PMCR_FIXED_LINK | \
-                                        PMCR_TX_FC_EN | PMCR_RX_FC_EN)
+#define  PMCR_SPEED_MASK               (PMCR_FORCE_SPEED_100 | \
+                                        PMCR_FORCE_SPEED_1000)
 
 #define MT7530_PMSR_P(x)               (0x3008 + (x) * 0x100)
+#define  PMSR_EEE1G                    BIT(7)
+#define  PMSR_EEE100M                  BIT(6)
+#define  PMSR_RX_FC                    BIT(5)
+#define  PMSR_TX_FC                    BIT(4)
+#define  PMSR_SPEED_1000               BIT(3)
+#define  PMSR_SPEED_100                        BIT(2)
+#define  PMSR_SPEED_10                 0x00
+#define  PMSR_SPEED_MASK               (PMSR_SPEED_100 | PMSR_SPEED_1000)
+#define  PMSR_DPX                      BIT(1)
+#define  PMSR_LINK                     BIT(0)
 
 /* Register for MIB */
 #define MT7530_PORT_MIB_COUNTER(x)     (0x4000 + (x) * 0x100)
@@ -423,6 +417,7 @@ struct mt7530_port {
  * @ports:             Holding the state among ports
  * @reg_mutex:         The lock for protecting among process accessing
  *                     registers
+ * @p6_interface       Holding the current port 6 interface
  */
 struct mt7530_priv {
        struct device           *dev;
@@ -435,6 +430,7 @@ struct mt7530_priv {
        struct gpio_desc        *reset;
        unsigned int            id;
        bool                    mcm;
+       phy_interface_t         p6_interface;
 
        struct mt7530_port      ports[MT7530_NUM_PORTS];
        /* protect among processes for registers access*/