net: dsa: mt7530: fix link-local frames that ingress vlan filtering ports
[sfrench/cifs-2.6.git] / drivers / net / dsa / mt7530.c
index 3c1f657593a8f364e5db9500d06257f34373af8a..2233f28b9fd195e0e313c80c4846f1eadfd00d6f 100644 (file)
@@ -414,92 +414,57 @@ mt753x_preferred_default_local_cpu_port(struct dsa_switch *ds)
 }
 
 /* Setup port 6 interface mode and TRGMII TX circuit */
-static int
-mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
+static void
+mt7530_setup_port6(struct dsa_switch *ds, phy_interface_t interface)
 {
        struct mt7530_priv *priv = ds->priv;
-       u32 ncpo1, ssc_delta, trgint, xtal;
-
-       xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK;
+       u32 ncpo1, ssc_delta, xtal;
 
-       if (xtal == HWTRAP_XTAL_20MHZ) {
-               dev_err(priv->dev,
-                       "%s: MT7530 with a 20MHz XTAL is not supported!\n",
-                       __func__);
-               return -EINVAL;
-       }
+       /* Disable the MT7530 TRGMII clocks */
+       core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
 
-       switch (interface) {
-       case PHY_INTERFACE_MODE_RGMII:
-               trgint = 0;
-               break;
-       case PHY_INTERFACE_MODE_TRGMII:
-               trgint = 1;
-               if (xtal == HWTRAP_XTAL_25MHZ)
-                       ssc_delta = 0x57;
-               else
-                       ssc_delta = 0x87;
-               if (priv->id == ID_MT7621) {
-                       /* PLL frequency: 125MHz: 1.0GBit */
-                       if (xtal == HWTRAP_XTAL_40MHZ)
-                               ncpo1 = 0x0640;
-                       if (xtal == HWTRAP_XTAL_25MHZ)
-                               ncpo1 = 0x0a00;
-               } else { /* PLL frequency: 250MHz: 2.0Gbit */
-                       if (xtal == HWTRAP_XTAL_40MHZ)
-                               ncpo1 = 0x0c80;
-                       if (xtal == HWTRAP_XTAL_25MHZ)
-                               ncpo1 = 0x1400;
-               }
-               break;
-       default:
-               dev_err(priv->dev, "xMII interface %d not supported\n",
-                       interface);
-               return -EINVAL;
+       if (interface == PHY_INTERFACE_MODE_RGMII) {
+               mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
+                          P6_INTF_MODE(0));
+               return;
        }
 
-       mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
-                  P6_INTF_MODE(trgint));
+       mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, P6_INTF_MODE(1));
 
-       if (trgint) {
-               /* Disable the MT7530 TRGMII clocks */
-               core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
+       xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK;
 
-               /* Setup the MT7530 TRGMII Tx Clock */
-               core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1));
-               core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0));
-               core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta));
-               core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta));
-               core_write(priv, CORE_PLL_GROUP4,
-                          RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN |
-                          RG_SYSPLL_BIAS_LPF_EN);
-               core_write(priv, CORE_PLL_GROUP2,
-                          RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
-                          RG_SYSPLL_POSDIV(1));
-               core_write(priv, CORE_PLL_GROUP7,
-                          RG_LCDDS_PCW_NCPO_CHG | RG_LCCDS_C(3) |
-                          RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
+       if (xtal == HWTRAP_XTAL_25MHZ)
+               ssc_delta = 0x57;
+       else
+               ssc_delta = 0x87;
 
-               /* Enable the MT7530 TRGMII clocks */
-               core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
+       if (priv->id == ID_MT7621) {
+               /* PLL frequency: 125MHz: 1.0GBit */
+               if (xtal == HWTRAP_XTAL_40MHZ)
+                       ncpo1 = 0x0640;
+               if (xtal == HWTRAP_XTAL_25MHZ)
+                       ncpo1 = 0x0a00;
+       } else { /* PLL frequency: 250MHz: 2.0Gbit */
+               if (xtal == HWTRAP_XTAL_40MHZ)
+                       ncpo1 = 0x0c80;
+               if (xtal == HWTRAP_XTAL_25MHZ)
+                       ncpo1 = 0x1400;
        }
 
-       return 0;
-}
+       /* Setup the MT7530 TRGMII Tx Clock */
+       core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1));
+       core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0));
+       core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta));
+       core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta));
+       core_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN |
+                  RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN);
+       core_write(priv, CORE_PLL_GROUP2, RG_SYSPLL_EN_NORMAL |
+                  RG_SYSPLL_VODEN | RG_SYSPLL_POSDIV(1));
+       core_write(priv, CORE_PLL_GROUP7, RG_LCDDS_PCW_NCPO_CHG |
+                  RG_LCCDS_C(3) | RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
 
-static bool mt7531_dual_sgmii_supported(struct mt7530_priv *priv)
-{
-       u32 val;
-
-       val = mt7530_read(priv, MT7531_TOP_SIG_SR);
-
-       return (val & PAD_DUAL_SGMII_EN) != 0;
-}
-
-static int
-mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
-{
-       return 0;
+       /* Enable the MT7530 TRGMII clocks */
+       core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
 }
 
 static void
@@ -510,9 +475,6 @@ mt7531_pll_setup(struct mt7530_priv *priv)
        u32 xtal;
        u32 val;
 
-       if (mt7531_dual_sgmii_supported(priv))
-               return;
-
        val = mt7530_read(priv, MT7531_CREV);
        top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR);
        hwstrap = mt7530_read(priv, MT7531_HWTRAP);
@@ -920,8 +882,6 @@ static const char *p5_intf_modes(unsigned int p5_interface)
                return "PHY P4";
        case P5_INTF_SEL_GMAC5:
                return "GMAC5";
-       case P5_INTF_SEL_GMAC5_SGMII:
-               return "GMAC5_SGMII";
        default:
                return "unknown";
        }
@@ -956,13 +916,8 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
                /* MT7530_P5_MODE_GMAC: P5 -> External phy or 2nd GMAC */
                val &= ~MHWTRAP_P5_DIS;
                break;
-       case P5_DISABLED:
-               interface = PHY_INTERFACE_MODE_NA;
-               break;
        default:
-               dev_err(ds->dev, "Unsupported p5_intf_sel %d\n",
-                       priv->p5_intf_sel);
-               goto unlock_exit;
+               break;
        }
 
        /* Setup RGMII settings */
@@ -992,40 +947,36 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
        dev_dbg(ds->dev, "Setup P5, HWTRAP=0x%x, intf_sel=%s, phy-mode=%s\n",
                val, p5_intf_modes(priv->p5_intf_sel), phy_modes(interface));
 
-       priv->p5_interface = interface;
-
-unlock_exit:
        mutex_unlock(&priv->reg_mutex);
 }
 
 static void
 mt753x_trap_frames(struct mt7530_priv *priv)
 {
-       /* Trap BPDUs to the CPU port(s) */
-       mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
+       /* Trap 802.1X PAE frames and BPDUs to the CPU port(s) and egress them
+        * VLAN-untagged.
+        */
+       mt7530_rmw(priv, MT753X_BPC, MT753X_PAE_EG_TAG_MASK |
+                  MT753X_PAE_PORT_FW_MASK | MT753X_BPDU_EG_TAG_MASK |
+                  MT753X_BPDU_PORT_FW_MASK,
+                  MT753X_PAE_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+                  MT753X_PAE_PORT_FW(MT753X_BPDU_CPU_ONLY) |
+                  MT753X_BPDU_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
                   MT753X_BPDU_CPU_ONLY);
 
-       /* Trap 802.1X PAE frames to the CPU port(s) */
-       mt7530_rmw(priv, MT753X_BPC, MT753X_PAE_PORT_FW_MASK,
-                  MT753X_PAE_PORT_FW(MT753X_BPDU_CPU_ONLY));
-
-       /* Trap LLDP frames with :0E MAC DA to the CPU port(s) */
-       mt7530_rmw(priv, MT753X_RGAC2, MT753X_R0E_PORT_FW_MASK,
+       /* Trap LLDP frames with :0E MAC DA to the CPU port(s) and egress them
+        * VLAN-untagged.
+        */
+       mt7530_rmw(priv, MT753X_RGAC2, MT753X_R0E_EG_TAG_MASK |
+                  MT753X_R0E_PORT_FW_MASK,
+                  MT753X_R0E_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
                   MT753X_R0E_PORT_FW(MT753X_BPDU_CPU_ONLY));
 }
 
-static int
+static void
 mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
 {
        struct mt7530_priv *priv = ds->priv;
-       int ret;
-
-       /* Setup max capability of CPU port at first */
-       if (priv->info->cpu_port_config) {
-               ret = priv->info->cpu_port_config(ds, port);
-               if (ret)
-                       return ret;
-       }
 
        /* Enable Mediatek header mode on the cpu port */
        mt7530_write(priv, MT7530_PVC_P(port),
@@ -1035,10 +986,6 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
        mt7530_set(priv, MT7530_MFC, BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) |
                   UNU_FFP(BIT(port)));
 
-       /* Set CPU port number */
-       if (priv->id == ID_MT7530 || priv->id == ID_MT7621)
-               mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port));
-
        /* Add the CPU port to the CPU port bitmap for MT7531 and the switch on
         * the MT7988 SoC. Trapped frames will be forwarded to the CPU port that
         * is affine to the inbound user port.
@@ -1055,8 +1002,6 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
        /* Set to fallback mode for independent VLAN learning */
        mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
                   MT7530_PORT_FALLBACK_MODE);
-
-       return 0;
 }
 
 static int
@@ -1080,7 +1025,6 @@ 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_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
 
        mutex_unlock(&priv->reg_mutex);
 
@@ -1100,7 +1044,6 @@ mt7530_port_disable(struct dsa_switch *ds, int port)
        priv->ports[port].enable = false;
        mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
                   PCR_MATRIX_CLR);
-       mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
 
        mutex_unlock(&priv->reg_mutex);
 }
@@ -2107,7 +2050,7 @@ mt7530_setup_irq(struct mt7530_priv *priv)
        }
 
        /* This register must be set for MT7530 to properly fire interrupts */
-       if (priv->id != ID_MT7531)
+       if (priv->id == ID_MT7530 || priv->id == ID_MT7621)
                mt7530_set(priv, MT7530_TOP_SIG_CTRL, TOP_SIG_CTRL_NORMAL);
 
        ret = request_threaded_irq(priv->irq, NULL, mt7530_irq_thread_fn,
@@ -2146,24 +2089,40 @@ mt7530_free_irq_common(struct mt7530_priv *priv)
 static void
 mt7530_free_irq(struct mt7530_priv *priv)
 {
-       mt7530_free_mdio_irq(priv);
+       struct device_node *mnp, *np = priv->dev->of_node;
+
+       mnp = of_get_child_by_name(np, "mdio");
+       if (!mnp)
+               mt7530_free_mdio_irq(priv);
+       of_node_put(mnp);
+
        mt7530_free_irq_common(priv);
 }
 
 static int
 mt7530_setup_mdio(struct mt7530_priv *priv)
 {
+       struct device_node *mnp, *np = priv->dev->of_node;
        struct dsa_switch *ds = priv->ds;
        struct device *dev = priv->dev;
        struct mii_bus *bus;
        static int idx;
-       int ret;
+       int ret = 0;
+
+       mnp = of_get_child_by_name(np, "mdio");
+
+       if (mnp && !of_device_is_available(mnp))
+               goto out;
 
        bus = devm_mdiobus_alloc(dev);
-       if (!bus)
-               return -ENOMEM;
+       if (!bus) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (!mnp)
+               ds->user_mii_bus = bus;
 
-       ds->user_mii_bus = bus;
        bus->priv = priv;
        bus->name = KBUILD_MODNAME "-mii";
        snprintf(bus->id, MII_BUS_ID_SIZE, KBUILD_MODNAME "-%d", idx++);
@@ -2174,16 +2133,18 @@ mt7530_setup_mdio(struct mt7530_priv *priv)
        bus->parent = dev;
        bus->phy_mask = ~ds->phys_mii_mask;
 
-       if (priv->irq)
+       if (priv->irq && !mnp)
                mt7530_setup_mdio_irq(priv);
 
-       ret = devm_mdiobus_register(dev, bus);
+       ret = devm_of_mdiobus_register(dev, bus, mnp);
        if (ret) {
                dev_err(dev, "failed to register MDIO bus: %d\n", ret);
-               if (priv->irq)
+               if (priv->irq && !mnp)
                        mt7530_free_mdio_irq(priv);
        }
 
+out:
+       of_node_put(mnp);
        return ret;
 }
 
@@ -2243,11 +2204,11 @@ mt7530_setup(struct dsa_switch *ds)
         */
        if (priv->mcm) {
                reset_control_assert(priv->rstc);
-               usleep_range(1000, 1100);
+               usleep_range(5000, 5100);
                reset_control_deassert(priv->rstc);
        } else {
                gpiod_set_value_cansleep(priv->reset, 0);
-               usleep_range(1000, 1100);
+               usleep_range(5000, 5100);
                gpiod_set_value_cansleep(priv->reset, 1);
        }
 
@@ -2267,6 +2228,12 @@ mt7530_setup(struct dsa_switch *ds)
                return -ENODEV;
        }
 
+       if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_20MHZ) {
+               dev_err(priv->dev,
+                       "MT7530 with a 20MHz XTAL is not supported!\n");
+               return -EINVAL;
+       }
+
        /* Reset the switch through internal reset */
        mt7530_write(priv, MT7530_SYS_CTRL,
                     SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
@@ -2289,14 +2256,18 @@ mt7530_setup(struct dsa_switch *ds)
        val |= MHWTRAP_MANUAL;
        mt7530_write(priv, MT7530_MHWTRAP, val);
 
-       priv->p6_interface = PHY_INTERFACE_MODE_NA;
-
        mt753x_trap_frames(priv);
 
        /* Enable and reset MIB counters */
        mt7530_mib_reset(ds);
 
        for (i = 0; i < MT7530_NUM_PORTS; i++) {
+               /* Clear link settings and enable force mode to force link down
+                * on all ports until they're enabled later.
+                */
+               mt7530_rmw(priv, MT7530_PMCR_P(i), PMCR_LINK_SETTINGS_MASK |
+                          PMCR_FORCE_MODE, PMCR_FORCE_MODE);
+
                /* Disable forwarding by default on all ports */
                mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
                           PCR_MATRIX_CLR);
@@ -2305,9 +2276,7 @@ mt7530_setup(struct dsa_switch *ds)
                mt7530_set(priv, MT7530_PSC_P(i), SA_DIS);
 
                if (dsa_is_cpu_port(ds, i)) {
-                       ret = mt753x_cpu_port_enable(ds, i);
-                       if (ret)
-                               return ret;
+                       mt753x_cpu_port_enable(ds, i);
                } else {
                        mt7530_port_disable(ds, i);
 
@@ -2326,16 +2295,13 @@ mt7530_setup(struct dsa_switch *ds)
                return ret;
 
        /* Setup port 5 */
-       priv->p5_intf_sel = P5_DISABLED;
-       interface = PHY_INTERFACE_MODE_NA;
-
        if (!dsa_is_unused_port(ds, 5)) {
                priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
-               ret = of_get_phy_mode(dsa_to_port(ds, 5)->dn, &interface);
-               if (ret && ret != -ENODEV)
-                       return ret;
        } else {
-               /* Scan the ethernet nodes. look for GMAC1, lookup used phy */
+               /* Scan the ethernet nodes. Look for GMAC1, lookup the used PHY.
+                * Set priv->p5_intf_sel to the appropriate value if PHY muxing
+                * is detected.
+                */
                for_each_child_of_node(dn, mac_np) {
                        if (!of_device_is_compatible(mac_np,
                                                     "mediatek,eth-mac"))
@@ -2366,6 +2332,10 @@ mt7530_setup(struct dsa_switch *ds)
                        of_node_put(phy_node);
                        break;
                }
+
+               if (priv->p5_intf_sel == P5_INTF_SEL_PHY_P0 ||
+                   priv->p5_intf_sel == P5_INTF_SEL_PHY_P4)
+                       mt7530_setup_port5(ds, interface);
        }
 
 #ifdef CONFIG_GPIOLIB
@@ -2376,8 +2346,6 @@ mt7530_setup(struct dsa_switch *ds)
        }
 #endif /* CONFIG_GPIOLIB */
 
-       mt7530_setup_port5(ds, interface);
-
        /* Flush the FDB table */
        ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
        if (ret < 0)
@@ -2402,6 +2370,12 @@ mt7531_setup_common(struct dsa_switch *ds)
                     UNU_FFP_MASK);
 
        for (i = 0; i < MT7530_NUM_PORTS; i++) {
+               /* Clear link settings and enable force mode to force link down
+                * on all ports until they're enabled later.
+                */
+               mt7530_rmw(priv, MT7530_PMCR_P(i), PMCR_LINK_SETTINGS_MASK |
+                          MT7531_FORCE_MODE, MT7531_FORCE_MODE);
+
                /* Disable forwarding by default on all ports */
                mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
                           PCR_MATRIX_CLR);
@@ -2412,9 +2386,7 @@ mt7531_setup_common(struct dsa_switch *ds)
                mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR);
 
                if (dsa_is_cpu_port(ds, i)) {
-                       ret = mt753x_cpu_port_enable(ds, i);
-                       if (ret)
-                               return ret;
+                       mt753x_cpu_port_enable(ds, i);
                } else {
                        mt7530_port_disable(ds, i);
 
@@ -2449,11 +2421,11 @@ mt7531_setup(struct dsa_switch *ds)
         */
        if (priv->mcm) {
                reset_control_assert(priv->rstc);
-               usleep_range(1000, 1100);
+               usleep_range(5000, 5100);
                reset_control_deassert(priv->rstc);
        } else {
                gpiod_set_value_cansleep(priv->reset, 0);
-               usleep_range(1000, 1100);
+               usleep_range(5000, 5100);
                gpiod_set_value_cansleep(priv->reset, 1);
        }
 
@@ -2474,38 +2446,35 @@ mt7531_setup(struct dsa_switch *ds)
                return -ENODEV;
        }
 
-       /* all MACs must be forced link-down before sw reset */
+       /* MT7531AE has got two SGMII units. One for port 5, one for port 6.
+        * MT7531BE has got only one SGMII unit which is for port 6.
+        */
+       val = mt7530_read(priv, MT7531_TOP_SIG_SR);
+       priv->p5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
+
+       /* Force link down on all ports before internal reset */
        for (i = 0; i < MT7530_NUM_PORTS; i++)
                mt7530_write(priv, MT7530_PMCR_P(i), MT7531_FORCE_LNK);
 
        /* Reset the switch through internal reset */
-       mt7530_write(priv, MT7530_SYS_CTRL,
-                    SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
-                    SYS_CTRL_REG_RST);
-
-       mt7531_pll_setup(priv);
-
-       if (mt7531_dual_sgmii_supported(priv)) {
-               priv->p5_intf_sel = P5_INTF_SEL_GMAC5_SGMII;
+       mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_SW_RST | SYS_CTRL_REG_RST);
 
+       if (!priv->p5_sgmii) {
+               mt7531_pll_setup(priv);
+       } else {
                /* Let ds->user_mii_bus be able to access external phy. */
                mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO11_RG_RXD2_MASK,
                           MT7531_EXT_P_MDC_11);
                mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO12_RG_RXD3_MASK,
                           MT7531_EXT_P_MDIO_12);
-       } else {
-               priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
        }
-       dev_dbg(ds->dev, "P5 support %s interface\n",
-               p5_intf_modes(priv->p5_intf_sel));
+
+       if (!dsa_is_unused_port(ds, 5))
+               priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
 
        mt7530_rmw(priv, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK,
                   MT7531_GPIO0_INTERRUPT);
 
-       /* Let phylink decide the interface later. */
-       priv->p5_interface = PHY_INTERFACE_MODE_NA;
-       priv->p6_interface = PHY_INTERFACE_MODE_NA;
-
        /* Enable PHY core PLL, since phy_device has not yet been created
         * provided for phy_[read,write]_mmd_indirect is called, we provide
         * our own mt7531_ind_mmd_phy_[read,write] to complete this
@@ -2535,12 +2504,14 @@ static void mt7530_mac_port_get_caps(struct dsa_switch *ds, int port,
                                     struct phylink_config *config)
 {
        switch (port) {
-       case 0 ... 4: /* Internal phy */
+       /* Ports which are connected to switch PHYs. There is no MII pinout. */
+       case 0 ... 4:
                __set_bit(PHY_INTERFACE_MODE_GMII,
                          config->supported_interfaces);
                break;
 
-       case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
+       /* Port 5 supports rgmii with delays, mii, and gmii. */
+       case 5:
                phy_interface_set_rgmii(config->supported_interfaces);
                __set_bit(PHY_INTERFACE_MODE_MII,
                          config->supported_interfaces);
@@ -2548,7 +2519,8 @@ static void mt7530_mac_port_get_caps(struct dsa_switch *ds, int port,
                          config->supported_interfaces);
                break;
 
-       case 6: /* 1st cpu port */
+       /* Port 6 supports rgmii and trgmii. */
+       case 6:
                __set_bit(PHY_INTERFACE_MODE_RGMII,
                          config->supported_interfaces);
                __set_bit(PHY_INTERFACE_MODE_TRGMII,
@@ -2557,30 +2529,30 @@ static void mt7530_mac_port_get_caps(struct dsa_switch *ds, int port,
        }
 }
 
-static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port)
-{
-       return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII);
-}
-
 static void mt7531_mac_port_get_caps(struct dsa_switch *ds, int port,
                                     struct phylink_config *config)
 {
        struct mt7530_priv *priv = ds->priv;
 
        switch (port) {
-       case 0 ... 4: /* Internal phy */
+       /* Ports which are connected to switch PHYs. There is no MII pinout. */
+       case 0 ... 4:
                __set_bit(PHY_INTERFACE_MODE_GMII,
                          config->supported_interfaces);
                break;
 
-       case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */
-               if (mt7531_is_rgmii_port(priv, port)) {
+       /* Port 5 supports rgmii with delays on MT7531BE, sgmii/802.3z on
+        * MT7531AE.
+        */
+       case 5:
+               if (!priv->p5_sgmii) {
                        phy_interface_set_rgmii(config->supported_interfaces);
                        break;
                }
                fallthrough;
 
-       case 6: /* 1st cpu port supports sgmii/8023z only */
+       /* Port 6 supports sgmii/802.3z. */
+       case 6:
                __set_bit(PHY_INTERFACE_MODE_SGMII,
                          config->supported_interfaces);
                __set_bit(PHY_INTERFACE_MODE_1000BASEX,
@@ -2596,14 +2568,14 @@ static void mt7531_mac_port_get_caps(struct dsa_switch *ds, int port,
 static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port,
                                     struct phylink_config *config)
 {
-       phy_interface_zero(config->supported_interfaces);
-
        switch (port) {
-       case 0 ... 4: /* Internal phy */
+       /* Ports which are connected to switch PHYs. There is no MII pinout. */
+       case 0 ... 3:
                __set_bit(PHY_INTERFACE_MODE_INTERNAL,
                          config->supported_interfaces);
                break;
 
+       /* Port 6 is connected to SoC's XGMII MAC. There is no MII pinout. */
        case 6:
                __set_bit(PHY_INTERFACE_MODE_INTERNAL,
                          config->supported_interfaces);
@@ -2612,41 +2584,24 @@ static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port,
        }
 }
 
-static int
-mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state)
-{
-       struct mt7530_priv *priv = ds->priv;
-
-       return priv->info->pad_setup(ds, state->interface);
-}
-
-static int
+static void
 mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
                  phy_interface_t interface)
 {
        struct mt7530_priv *priv = ds->priv;
 
-       /* Only need to setup port5. */
-       if (port != 5)
-               return 0;
-
-       mt7530_setup_port5(priv->ds, interface);
-
-       return 0;
+       if (port == 5)
+               mt7530_setup_port5(priv->ds, interface);
+       else if (port == 6)
+               mt7530_setup_port6(priv->ds, interface);
 }
 
-static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port,
-                             phy_interface_t interface,
-                             struct phy_device *phydev)
+static void mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port,
+                              phy_interface_t interface,
+                              struct phy_device *phydev)
 {
        u32 val;
 
-       if (!mt7531_is_rgmii_port(priv, port)) {
-               dev_err(priv->dev, "RGMII mode is not available for port %d\n",
-                       port);
-               return -EINVAL;
-       }
-
        val = mt7530_read(priv, MT7531_CLKGEN_CTRL);
        val |= GP_CLK_EN;
        val &= ~GP_MODE_MASK;
@@ -2674,31 +2629,14 @@ static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port,
                case PHY_INTERFACE_MODE_RGMII_ID:
                        break;
                default:
-                       return -EINVAL;
+                       break;
                }
        }
-       mt7530_write(priv, MT7531_CLKGEN_CTRL, val);
-
-       return 0;
-}
-
-static bool mt753x_is_mac_port(u32 port)
-{
-       return (port == 5 || port == 6);
-}
-
-static int
-mt7988_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
-                 phy_interface_t interface)
-{
-       if (dsa_is_cpu_port(ds, port) &&
-           interface == PHY_INTERFACE_MODE_INTERNAL)
-               return 0;
 
-       return -EINVAL;
+       mt7530_write(priv, MT7531_CLKGEN_CTRL, val);
 }
 
-static int
+static void
 mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
                  phy_interface_t interface)
 {
@@ -2706,39 +2644,11 @@ mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
        struct phy_device *phydev;
        struct dsa_port *dp;
 
-       if (!mt753x_is_mac_port(port)) {
-               dev_err(priv->dev, "port %d is not a MAC port\n", port);
-               return -EINVAL;
-       }
-
-       switch (interface) {
-       case PHY_INTERFACE_MODE_RGMII:
-       case PHY_INTERFACE_MODE_RGMII_ID:
-       case PHY_INTERFACE_MODE_RGMII_RXID:
-       case PHY_INTERFACE_MODE_RGMII_TXID:
+       if (phy_interface_mode_is_rgmii(interface)) {
                dp = dsa_to_port(ds, port);
                phydev = dp->user->phydev;
-               return mt7531_rgmii_setup(priv, port, interface, phydev);
-       case PHY_INTERFACE_MODE_SGMII:
-       case PHY_INTERFACE_MODE_NA:
-       case PHY_INTERFACE_MODE_1000BASEX:
-       case PHY_INTERFACE_MODE_2500BASEX:
-               /* handled in SGMII PCS driver */
-               return 0;
-       default:
-               return -EINVAL;
+               mt7531_rgmii_setup(priv, port, interface, phydev);
        }
-
-       return -EINVAL;
-}
-
-static int
-mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
-                 const struct phylink_link_state *state)
-{
-       struct mt7530_priv *priv = ds->priv;
-
-       return priv->info->mac_port_config(ds, port, mode, state->interface);
 }
 
 static struct phylink_pcs *
@@ -2764,54 +2674,13 @@ mt753x_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 ... 4: /* Internal phy */
-               if (state->interface != PHY_INTERFACE_MODE_GMII &&
-                   state->interface != PHY_INTERFACE_MODE_INTERNAL)
-                       goto unsupported;
-               break;
-       case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
-               if (priv->p5_interface == state->interface)
-                       break;
-
-               if (mt753x_mac_config(ds, port, mode, state) < 0)
-                       goto unsupported;
-
-               if (priv->p5_intf_sel != P5_DISABLED)
-                       priv->p5_interface = state->interface;
-               break;
-       case 6: /* 1st cpu port */
-               if (priv->p6_interface == state->interface)
-                       break;
-
-               mt753x_pad_setup(ds, state);
 
-               if (mt753x_mac_config(ds, port, mode, state) < 0)
-                       goto unsupported;
-
-               priv->p6_interface = state->interface;
-               break;
-       default:
-unsupported:
-               dev_err(ds->dev, "%s: unsupported %s port: %i\n",
-                       __func__, phy_modes(state->interface), port);
-               return;
-       }
-
-       mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
-       mcr_new = mcr_cur;
-       mcr_new &= ~PMCR_LINK_SETTINGS_MASK;
-       mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN |
-                  PMCR_BACKPR_EN | PMCR_FORCE_MODE_ID(priv->id);
+       if ((port == 5 || port == 6) && priv->info->mac_port_config)
+               priv->info->mac_port_config(ds, port, mode, state->interface);
 
        /* Are we connected to external phy */
        if (port == 5 && dsa_is_user_port(ds, 5))
-               mcr_new |= PMCR_EXT_PHY;
-
-       if (mcr_new != mcr_cur)
-               mt7530_write(priv, MT7530_PMCR_P(port), mcr_new);
+               mt7530_set(priv, MT7530_PMCR_P(port), PMCR_EXT_PHY);
 }
 
 static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port,
@@ -2835,17 +2704,10 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
 
        mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK;
 
-       /* MT753x MAC works in 1G full duplex mode for all up-clocked
-        * variants.
-        */
-       if (interface == PHY_INTERFACE_MODE_TRGMII ||
-           (phy_interface_mode_is_8023z(interface))) {
-               speed = SPEED_1000;
-               duplex = DUPLEX_FULL;
-       }
-
        switch (speed) {
        case SPEED_1000:
+       case SPEED_2500:
+       case SPEED_10000:
                mcr |= PMCR_FORCE_SPEED_1000;
                break;
        case SPEED_100:
@@ -2863,6 +2725,7 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
        if (mode == MLO_AN_PHY && phydev && phy_init_eee(phydev, false) >= 0) {
                switch (speed) {
                case SPEED_1000:
+               case SPEED_2500:
                        mcr |= PMCR_FORCE_EEE1G;
                        break;
                case SPEED_100:
@@ -2874,63 +2737,6 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
        mt7530_set(priv, MT7530_PMCR_P(port), mcr);
 }
 
-static int
-mt7531_cpu_port_config(struct dsa_switch *ds, int port)
-{
-       struct mt7530_priv *priv = ds->priv;
-       phy_interface_t interface;
-       int speed;
-       int ret;
-
-       switch (port) {
-       case 5:
-               if (mt7531_is_rgmii_port(priv, port))
-                       interface = PHY_INTERFACE_MODE_RGMII;
-               else
-                       interface = PHY_INTERFACE_MODE_2500BASEX;
-
-               priv->p5_interface = interface;
-               break;
-       case 6:
-               interface = PHY_INTERFACE_MODE_2500BASEX;
-
-               priv->p6_interface = interface;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (interface == PHY_INTERFACE_MODE_2500BASEX)
-               speed = SPEED_2500;
-       else
-               speed = SPEED_1000;
-
-       ret = mt7531_mac_config(ds, port, MLO_AN_FIXED, interface);
-       if (ret)
-               return ret;
-       mt7530_write(priv, MT7530_PMCR_P(port),
-                    PMCR_CPU_PORT_SETTING(priv->id));
-       mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL,
-                                  speed, DUPLEX_FULL, true, true);
-
-       return 0;
-}
-
-static int
-mt7988_cpu_port_config(struct dsa_switch *ds, int port)
-{
-       struct mt7530_priv *priv = ds->priv;
-
-       mt7530_write(priv, MT7530_PMCR_P(port),
-                    PMCR_CPU_PORT_SETTING(priv->id));
-
-       mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED,
-                                  PHY_INTERFACE_MODE_INTERNAL, NULL,
-                                  SPEED_10000, DUPLEX_FULL, true, true);
-
-       return 0;
-}
-
 static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
                                    struct phylink_config *config)
 {
@@ -3013,17 +2819,9 @@ static int
 mt753x_setup(struct dsa_switch *ds)
 {
        struct mt7530_priv *priv = ds->priv;
-       int i, ret;
-
-       /* Initialise the PCS devices */
-       for (i = 0; i < priv->ds->num_ports; i++) {
-               priv->pcs[i].pcs.ops = priv->info->pcs_ops;
-               priv->pcs[i].pcs.neg_mode = true;
-               priv->pcs[i].priv = priv;
-               priv->pcs[i].port = i;
-       }
+       int ret = priv->info->sw_setup(ds);
+       int i;
 
-       ret = priv->info->sw_setup(ds);
        if (ret)
                return ret;
 
@@ -3035,8 +2833,16 @@ mt753x_setup(struct dsa_switch *ds)
        if (ret && priv->irq)
                mt7530_free_irq_common(priv);
 
+       /* Initialise the PCS devices */
+       for (i = 0; i < priv->ds->num_ports; i++) {
+               priv->pcs[i].pcs.ops = priv->info->pcs_ops;
+               priv->pcs[i].pcs.neg_mode = true;
+               priv->pcs[i].priv = priv;
+               priv->pcs[i].port = i;
+       }
+
        if (priv->create_sgmii) {
-               ret = priv->create_sgmii(priv, mt7531_dual_sgmii_supported(priv));
+               ret = priv->create_sgmii(priv);
                if (ret && priv->irq)
                        mt7530_free_irq(priv);
        }
@@ -3045,7 +2851,7 @@ mt753x_setup(struct dsa_switch *ds)
 }
 
 static int mt753x_get_mac_eee(struct dsa_switch *ds, int port,
-                             struct ethtool_eee *e)
+                             struct ethtool_keee *e)
 {
        struct mt7530_priv *priv = ds->priv;
        u32 eeecr = mt7530_read(priv, MT7530_PMEEECR_P(port));
@@ -3057,7 +2863,7 @@ static int mt753x_get_mac_eee(struct dsa_switch *ds, int port,
 }
 
 static int mt753x_set_mac_eee(struct dsa_switch *ds, int port,
-                             struct ethtool_eee *e)
+                             struct ethtool_keee *e)
 {
        struct mt7530_priv *priv = ds->priv;
        u32 set, mask = LPI_THRESH_MASK | LPI_MODE_EN;
@@ -3074,9 +2880,34 @@ static int mt753x_set_mac_eee(struct dsa_switch *ds, int port,
        return 0;
 }
 
-static int mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
+static void
+mt753x_conduit_state_change(struct dsa_switch *ds,
+                           const struct net_device *conduit,
+                           bool operational)
 {
-       return 0;
+       struct dsa_port *cpu_dp = conduit->dsa_ptr;
+       struct mt7530_priv *priv = ds->priv;
+       int val = 0;
+       u8 mask;
+
+       /* Set the CPU port to trap frames to for MT7530. Trapped frames will be
+        * forwarded to the numerically smallest CPU port whose conduit
+        * interface is up.
+        */
+       if (priv->id != ID_MT7530 && priv->id != ID_MT7621)
+               return;
+
+       mask = BIT(cpu_dp->index);
+
+       if (operational)
+               priv->active_cpu_ports |= mask;
+       else
+               priv->active_cpu_ports &= ~mask;
+
+       if (priv->active_cpu_ports)
+               val = CPU_EN | CPU_PORT(__ffs(priv->active_cpu_ports));
+
+       mt7530_rmw(priv, MT7530_MFC, CPU_EN | CPU_PORT_MASK, val);
 }
 
 static int mt7988_setup(struct dsa_switch *ds)
@@ -3129,6 +2960,7 @@ const struct dsa_switch_ops mt7530_switch_ops = {
        .phylink_mac_link_up    = mt753x_phylink_mac_link_up,
        .get_mac_eee            = mt753x_get_mac_eee,
        .set_mac_eee            = mt753x_set_mac_eee,
+       .conduit_state_change   = mt753x_conduit_state_change,
 };
 EXPORT_SYMBOL_GPL(mt7530_switch_ops);
 
@@ -3141,7 +2973,6 @@ const struct mt753x_info mt753x_table[] = {
                .phy_write_c22 = mt7530_phy_write_c22,
                .phy_read_c45 = mt7530_phy_read_c45,
                .phy_write_c45 = mt7530_phy_write_c45,
-               .pad_setup = mt7530_pad_clk_setup,
                .mac_port_get_caps = mt7530_mac_port_get_caps,
                .mac_port_config = mt7530_mac_config,
        },
@@ -3153,7 +2984,6 @@ const struct mt753x_info mt753x_table[] = {
                .phy_write_c22 = mt7530_phy_write_c22,
                .phy_read_c45 = mt7530_phy_read_c45,
                .phy_write_c45 = mt7530_phy_write_c45,
-               .pad_setup = mt7530_pad_clk_setup,
                .mac_port_get_caps = mt7530_mac_port_get_caps,
                .mac_port_config = mt7530_mac_config,
        },
@@ -3165,8 +2995,6 @@ const struct mt753x_info mt753x_table[] = {
                .phy_write_c22 = mt7531_ind_c22_phy_write,
                .phy_read_c45 = mt7531_ind_c45_phy_read,
                .phy_write_c45 = mt7531_ind_c45_phy_write,
-               .pad_setup = mt7531_pad_setup,
-               .cpu_port_config = mt7531_cpu_port_config,
                .mac_port_get_caps = mt7531_mac_port_get_caps,
                .mac_port_config = mt7531_mac_config,
        },
@@ -3178,10 +3006,7 @@ const struct mt753x_info mt753x_table[] = {
                .phy_write_c22 = mt7531_ind_c22_phy_write,
                .phy_read_c45 = mt7531_ind_c45_phy_read,
                .phy_write_c45 = mt7531_ind_c45_phy_write,
-               .pad_setup = mt7988_pad_setup,
-               .cpu_port_config = mt7988_cpu_port_config,
                .mac_port_get_caps = mt7988_mac_port_get_caps,
-               .mac_port_config = mt7988_mac_config,
        },
 };
 EXPORT_SYMBOL_GPL(mt753x_table);
@@ -3208,10 +3033,8 @@ mt7530_probe_common(struct mt7530_priv *priv)
        /* Sanity check if these required device operations are filled
         * properly.
         */
-       if (!priv->info->sw_setup || !priv->info->pad_setup ||
-           !priv->info->phy_read_c22 || !priv->info->phy_write_c22 ||
-           !priv->info->mac_port_get_caps ||
-           !priv->info->mac_port_config)
+       if (!priv->info->sw_setup || !priv->info->phy_read_c22 ||
+           !priv->info->phy_write_c22 || !priv->info->mac_port_get_caps)
                return -EINVAL;
 
        priv->id = priv->info->id;