net: dsa: mt7530: Add the support of MT7531 switch
authorLanden Chao <landen.chao@mediatek.com>
Fri, 11 Sep 2020 13:48:54 +0000 (21:48 +0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 14 Sep 2020 23:30:39 +0000 (16:30 -0700)
Add new support for MT7531:

MT7531 is the next generation of MT7530. It is also a 7-ports switch with
5 giga embedded phys, 2 cpu ports, and the same MAC logic of MT7530. Cpu
port 6 only supports SGMII interface. Cpu port 5 supports either RGMII
or SGMII in different HW sku, but cannot be muxed to PHY of port 0/4 like
mt7530. Due to SGMII interface support, pll, and pad setting are different
from MT7530. This patch adds different initial setting, and SGMII phylink
handlers of MT7531.

MT7531 SGMII interface can be configured in following mode:
- 'SGMII AN mode' with in-band negotiation capability
    which is compatible with PHY_INTERFACE_MODE_SGMII.
- 'SGMII force mode' without in-band negotiation
    which is compatible with 10B/8B encoding of
    PHY_INTERFACE_MODE_1000BASEX with fixed full-duplex and fixed pause.
- 2.5 times faster clocked 'SGMII force mode' without in-band negotiation
    which is compatible with 10B/8B encoding of
    PHY_INTERFACE_MODE_2500BASEX with fixed full-duplex and fixed pause.

Signed-off-by: Landen Chao <landen.chao@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/Kconfig
drivers/net/dsa/mt7530.c
drivers/net/dsa/mt7530.h

index 06d68a8..2451f61 100644 (file)
@@ -33,12 +33,12 @@ config NET_DSA_LANTIQ_GSWIP
          the xrx200 / VR9 SoC.
 
 config NET_DSA_MT7530
-       tristate "MediaTek MT7530 and MT7621 Ethernet switch support"
+       tristate "MediaTek MT753x and MT7621 Ethernet switch support"
        depends on NET_DSA
        select NET_DSA_TAG_MTK
        help
-         This enables support for the MediaTek MT7530 and MT7621 Ethernet
-         switch chip.
+         This enables support for the MediaTek MT7530, MT7531, and MT7621
+         Ethernet switch chips.
 
 config NET_DSA_MV88E6060
        tristate "Marvell 88E6060 ethernet switch chip support"
index 82a1d13..6138894 100644 (file)
@@ -234,6 +234,12 @@ mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
 }
 
 static u32
+_mt7530_unlocked_read(struct mt7530_dummy_poll *p)
+{
+       return mt7530_mii_read(p->priv, p->reg);
+}
+
+static u32
 _mt7530_read(struct mt7530_dummy_poll *p)
 {
        struct mii_bus          *bus = p->priv->bus;
@@ -483,6 +489,108 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
        return 0;
 }
 
+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)
+{
+       struct mt7530_priv *priv = ds->priv;
+       u32 top_sig;
+       u32 hwstrap;
+       u32 xtal;
+       u32 val;
+
+       if (mt7531_dual_sgmii_supported(priv))
+               return 0;
+
+       val = mt7530_read(priv, MT7531_CREV);
+       top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR);
+       hwstrap = mt7530_read(priv, MT7531_HWTRAP);
+       if ((val & CHIP_REV_M) > 0)
+               xtal = (top_sig & PAD_MCM_SMI_EN) ? HWTRAP_XTAL_FSEL_40MHZ :
+                                                   HWTRAP_XTAL_FSEL_25MHZ;
+       else
+               xtal = hwstrap & HWTRAP_XTAL_FSEL_MASK;
+
+       /* Step 1 : Disable MT7531 COREPLL */
+       val = mt7530_read(priv, MT7531_PLLGP_EN);
+       val &= ~EN_COREPLL;
+       mt7530_write(priv, MT7531_PLLGP_EN, val);
+
+       /* Step 2: switch to XTAL output */
+       val = mt7530_read(priv, MT7531_PLLGP_EN);
+       val |= SW_CLKSW;
+       mt7530_write(priv, MT7531_PLLGP_EN, val);
+
+       val = mt7530_read(priv, MT7531_PLLGP_CR0);
+       val &= ~RG_COREPLL_EN;
+       mt7530_write(priv, MT7531_PLLGP_CR0, val);
+
+       /* Step 3: disable PLLGP and enable program PLLGP */
+       val = mt7530_read(priv, MT7531_PLLGP_EN);
+       val |= SW_PLLGP;
+       mt7530_write(priv, MT7531_PLLGP_EN, val);
+
+       /* Step 4: program COREPLL output frequency to 500MHz */
+       val = mt7530_read(priv, MT7531_PLLGP_CR0);
+       val &= ~RG_COREPLL_POSDIV_M;
+       val |= 2 << RG_COREPLL_POSDIV_S;
+       mt7530_write(priv, MT7531_PLLGP_CR0, val);
+       usleep_range(25, 35);
+
+       switch (xtal) {
+       case HWTRAP_XTAL_FSEL_25MHZ:
+               val = mt7530_read(priv, MT7531_PLLGP_CR0);
+               val &= ~RG_COREPLL_SDM_PCW_M;
+               val |= 0x140000 << RG_COREPLL_SDM_PCW_S;
+               mt7530_write(priv, MT7531_PLLGP_CR0, val);
+               break;
+       case HWTRAP_XTAL_FSEL_40MHZ:
+               val = mt7530_read(priv, MT7531_PLLGP_CR0);
+               val &= ~RG_COREPLL_SDM_PCW_M;
+               val |= 0x190000 << RG_COREPLL_SDM_PCW_S;
+               mt7530_write(priv, MT7531_PLLGP_CR0, val);
+               break;
+       };
+
+       /* Set feedback divide ratio update signal to high */
+       val = mt7530_read(priv, MT7531_PLLGP_CR0);
+       val |= RG_COREPLL_SDM_PCW_CHG;
+       mt7530_write(priv, MT7531_PLLGP_CR0, val);
+       /* Wait for at least 16 XTAL clocks */
+       usleep_range(10, 20);
+
+       /* Step 5: set feedback divide ratio update signal to low */
+       val = mt7530_read(priv, MT7531_PLLGP_CR0);
+       val &= ~RG_COREPLL_SDM_PCW_CHG;
+       mt7530_write(priv, MT7531_PLLGP_CR0, val);
+
+       /* Enable 325M clock for SGMII */
+       mt7530_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000);
+
+       /* Enable 250SSC clock for RGMII */
+       mt7530_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000);
+
+       /* Step 6: Enable MT7531 PLL */
+       val = mt7530_read(priv, MT7531_PLLGP_CR0);
+       val |= RG_COREPLL_EN;
+       mt7530_write(priv, MT7531_PLLGP_CR0, val);
+
+       val = mt7530_read(priv, MT7531_PLLGP_EN);
+       val |= EN_COREPLL;
+       mt7530_write(priv, MT7531_PLLGP_EN, val);
+       usleep_range(25, 35);
+
+       return 0;
+}
+
 static void
 mt7530_mib_reset(struct dsa_switch *ds)
 {
@@ -507,6 +615,217 @@ static int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum,
        return mdiobus_write_nested(priv->bus, port, regnum, val);
 }
 
+static int
+mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
+                       int regnum)
+{
+       struct mii_bus *bus = priv->bus;
+       struct mt7530_dummy_poll p;
+       u32 reg, val;
+       int ret;
+
+       INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
+
+       mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+       ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+                                !(val & MT7531_PHY_ACS_ST), 20, 100000);
+       if (ret < 0) {
+               dev_err(priv->dev, "poll timeout\n");
+               goto out;
+       }
+
+       reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) |
+             MT7531_MDIO_DEV_ADDR(devad) | regnum;
+       mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+
+       ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+                                !(val & MT7531_PHY_ACS_ST), 20, 100000);
+       if (ret < 0) {
+               dev_err(priv->dev, "poll timeout\n");
+               goto out;
+       }
+
+       reg = MT7531_MDIO_CL45_READ | MT7531_MDIO_PHY_ADDR(port) |
+             MT7531_MDIO_DEV_ADDR(devad);
+       mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+
+       ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+                                !(val & MT7531_PHY_ACS_ST), 20, 100000);
+       if (ret < 0) {
+               dev_err(priv->dev, "poll timeout\n");
+               goto out;
+       }
+
+       ret = val & MT7531_MDIO_RW_DATA_MASK;
+out:
+       mutex_unlock(&bus->mdio_lock);
+
+       return ret;
+}
+
+static int
+mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
+                        int regnum, u32 data)
+{
+       struct mii_bus *bus = priv->bus;
+       struct mt7530_dummy_poll p;
+       u32 val, reg;
+       int ret;
+
+       INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
+
+       mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+       ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+                                !(val & MT7531_PHY_ACS_ST), 20, 100000);
+       if (ret < 0) {
+               dev_err(priv->dev, "poll timeout\n");
+               goto out;
+       }
+
+       reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) |
+             MT7531_MDIO_DEV_ADDR(devad) | regnum;
+       mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+
+       ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+                                !(val & MT7531_PHY_ACS_ST), 20, 100000);
+       if (ret < 0) {
+               dev_err(priv->dev, "poll timeout\n");
+               goto out;
+       }
+
+       reg = MT7531_MDIO_CL45_WRITE | MT7531_MDIO_PHY_ADDR(port) |
+             MT7531_MDIO_DEV_ADDR(devad) | data;
+       mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+
+       ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+                                !(val & MT7531_PHY_ACS_ST), 20, 100000);
+       if (ret < 0) {
+               dev_err(priv->dev, "poll timeout\n");
+               goto out;
+       }
+
+out:
+       mutex_unlock(&bus->mdio_lock);
+
+       return ret;
+}
+
+static int
+mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
+{
+       struct mii_bus *bus = priv->bus;
+       struct mt7530_dummy_poll p;
+       int ret;
+       u32 val;
+
+       INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
+
+       mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+       ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+                                !(val & MT7531_PHY_ACS_ST), 20, 100000);
+       if (ret < 0) {
+               dev_err(priv->dev, "poll timeout\n");
+               goto out;
+       }
+
+       val = MT7531_MDIO_CL22_READ | MT7531_MDIO_PHY_ADDR(port) |
+             MT7531_MDIO_REG_ADDR(regnum);
+
+       mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
+
+       ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+                                !(val & MT7531_PHY_ACS_ST), 20, 100000);
+       if (ret < 0) {
+               dev_err(priv->dev, "poll timeout\n");
+               goto out;
+       }
+
+       ret = val & MT7531_MDIO_RW_DATA_MASK;
+out:
+       mutex_unlock(&bus->mdio_lock);
+
+       return ret;
+}
+
+static int
+mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
+                        u16 data)
+{
+       struct mii_bus *bus = priv->bus;
+       struct mt7530_dummy_poll p;
+       int ret;
+       u32 reg;
+
+       INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
+
+       mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+       ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
+                                !(reg & MT7531_PHY_ACS_ST), 20, 100000);
+       if (ret < 0) {
+               dev_err(priv->dev, "poll timeout\n");
+               goto out;
+       }
+
+       reg = MT7531_MDIO_CL22_WRITE | MT7531_MDIO_PHY_ADDR(port) |
+             MT7531_MDIO_REG_ADDR(regnum) | data;
+
+       mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+
+       ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
+                                !(reg & MT7531_PHY_ACS_ST), 20, 100000);
+       if (ret < 0) {
+               dev_err(priv->dev, "poll timeout\n");
+               goto out;
+       }
+
+out:
+       mutex_unlock(&bus->mdio_lock);
+
+       return ret;
+}
+
+static int
+mt7531_ind_phy_read(struct dsa_switch *ds, int port, int regnum)
+{
+       struct mt7530_priv *priv = ds->priv;
+       int devad;
+       int ret;
+
+       if (regnum & MII_ADDR_C45) {
+               devad = (regnum >> MII_DEVADDR_C45_SHIFT) & 0x1f;
+               ret = mt7531_ind_c45_phy_read(priv, port, devad,
+                                             regnum & MII_REGADDR_C45_MASK);
+       } else {
+               ret = mt7531_ind_c22_phy_read(priv, port, regnum);
+       }
+
+       return ret;
+}
+
+static int
+mt7531_ind_phy_write(struct dsa_switch *ds, int port, int regnum,
+                    u16 data)
+{
+       struct mt7530_priv *priv = ds->priv;
+       int devad;
+       int ret;
+
+       if (regnum & MII_ADDR_C45) {
+               devad = (regnum >> MII_DEVADDR_C45_SHIFT) & 0x1f;
+               ret = mt7531_ind_c45_phy_write(priv, port, devad,
+                                              regnum & MII_REGADDR_C45_MASK,
+                                              data);
+       } else {
+               ret = mt7531_ind_c22_phy_write(priv, port, regnum, data);
+       }
+
+       return ret;
+}
+
 static void
 mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset,
                   uint8_t *data)
@@ -623,9 +942,14 @@ unlock_exit:
 }
 
 static int
-mt7530_cpu_port_enable(struct mt7530_priv *priv,
-                      int port)
+mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
 {
+       struct mt7530_priv *priv = ds->priv;
+
+       /* Setup max capability of CPU port at first */
+       if (priv->info->cpu_port_config)
+               priv->info->cpu_port_config(ds, port);
+
        /* Enable Mediatek header mode on the cpu port */
        mt7530_write(priv, MT7530_PVC_P(port),
                     PORT_SPEC_TAG);
@@ -638,7 +962,7 @@ mt7530_cpu_port_enable(struct mt7530_priv *priv,
                mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port));
 
        /* CPU port gets connected to all user ports of
-        * the switch
+        * the switch.
         */
        mt7530_write(priv, MT7530_PCR_P(port),
                     PCR_MATRIX(dsa_user_ports(priv->ds)));
@@ -1132,27 +1456,42 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port,
        return 0;
 }
 
-static int mt7530_port_mirror_add(struct dsa_switch *ds, int port,
+static int mt753x_mirror_port_get(unsigned int id, u32 val)
+{
+       return (id == ID_MT7531) ? MT7531_MIRROR_PORT_GET(val) :
+                                  MIRROR_PORT(val);
+}
+
+static int mt753x_mirror_port_set(unsigned int id, u32 val)
+{
+       return (id == ID_MT7531) ? MT7531_MIRROR_PORT_SET(val) :
+                                  MIRROR_PORT(val);
+}
+
+static int mt753x_port_mirror_add(struct dsa_switch *ds, int port,
                                  struct dsa_mall_mirror_tc_entry *mirror,
                                  bool ingress)
 {
        struct mt7530_priv *priv = ds->priv;
+       int monitor_port;
        u32 val;
 
        /* Check for existent entry */
        if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
                return -EEXIST;
 
-       val = mt7530_read(priv, MT7530_MFC);
+       val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id));
 
        /* MT7530 only supports one monitor port */
-       if (val & MIRROR_EN && MIRROR_PORT(val) != mirror->to_local_port)
+       monitor_port = mt753x_mirror_port_get(priv->id, val);
+       if (val & MT753X_MIRROR_EN(priv->id) &&
+           monitor_port != mirror->to_local_port)
                return -EEXIST;
 
-       val |= MIRROR_EN;
-       val &= ~MIRROR_MASK;
-       val |= mirror->to_local_port;
-       mt7530_write(priv, MT7530_MFC, val);
+       val |= MT753X_MIRROR_EN(priv->id);
+       val &= ~MT753X_MIRROR_MASK(priv->id);
+       val |= mt753x_mirror_port_set(priv->id, mirror->to_local_port);
+       mt7530_write(priv, MT753X_MIRROR_REG(priv->id), val);
 
        val = mt7530_read(priv, MT7530_PCR_P(port));
        if (ingress) {
@@ -1167,7 +1506,7 @@ static int mt7530_port_mirror_add(struct dsa_switch *ds, int port,
        return 0;
 }
 
-static void mt7530_port_mirror_del(struct dsa_switch *ds, int port,
+static void mt753x_port_mirror_del(struct dsa_switch *ds, int port,
                                   struct dsa_mall_mirror_tc_entry *mirror)
 {
        struct mt7530_priv *priv = ds->priv;
@@ -1184,9 +1523,9 @@ static void mt7530_port_mirror_del(struct dsa_switch *ds, int port,
        mt7530_write(priv, MT7530_PCR_P(port), val);
 
        if (!priv->mirror_rx && !priv->mirror_tx) {
-               val = mt7530_read(priv, MT7530_MFC);
-               val &= ~MIRROR_EN;
-               mt7530_write(priv, MT7530_MFC, val);
+               val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id));
+               val &= ~MT753X_MIRROR_EN(priv->id);
+               mt7530_write(priv, MT753X_MIRROR_REG(priv->id), val);
        }
 }
 
@@ -1293,7 +1632,7 @@ mt7530_setup(struct dsa_switch *ds)
                           PCR_MATRIX_CLR);
 
                if (dsa_is_cpu_port(ds, i))
-                       mt7530_cpu_port_enable(priv, i);
+                       mt753x_cpu_port_enable(ds, i);
                else
                        mt7530_port_disable(ds, i);
 
@@ -1354,6 +1693,118 @@ mt7530_setup(struct dsa_switch *ds)
        return 0;
 }
 
+static int
+mt7531_setup(struct dsa_switch *ds)
+{
+       struct mt7530_priv *priv = ds->priv;
+       struct mt7530_dummy_poll p;
+       u32 val, id;
+       int ret, i;
+
+       /* Reset whole chip through gpio pin or memory-mapped registers for
+        * different type of hardware
+        */
+       if (priv->mcm) {
+               reset_control_assert(priv->rstc);
+               usleep_range(1000, 1100);
+               reset_control_deassert(priv->rstc);
+       } else {
+               gpiod_set_value_cansleep(priv->reset, 0);
+               usleep_range(1000, 1100);
+               gpiod_set_value_cansleep(priv->reset, 1);
+       }
+
+       /* Waiting for MT7530 got to stable */
+       INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_HWTRAP);
+       ret = readx_poll_timeout(_mt7530_read, &p, val, val != 0,
+                                20, 1000000);
+       if (ret < 0) {
+               dev_err(priv->dev, "reset timeout\n");
+               return ret;
+       }
+
+       id = mt7530_read(priv, MT7531_CREV);
+       id >>= CHIP_NAME_SHIFT;
+
+       if (id != MT7531_ID) {
+               dev_err(priv->dev, "chip %x can't be supported\n", id);
+               return -ENODEV;
+       }
+
+       /* Reset the switch through internal reset */
+       mt7530_write(priv, MT7530_SYS_CTRL,
+                    SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
+                    SYS_CTRL_REG_RST);
+
+       if (mt7531_dual_sgmii_supported(priv)) {
+               priv->p5_intf_sel = P5_INTF_SEL_GMAC5_SGMII;
+
+               /* Let ds->slave_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));
+
+       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
+        * function.
+        */
+       val = mt7531_ind_c45_phy_read(priv, MT753X_CTRL_PHY_ADDR,
+                                     MDIO_MMD_VEND2, CORE_PLL_GROUP4);
+       val |= MT7531_PHY_PLL_BYPASS_MODE;
+       val &= ~MT7531_PHY_PLL_OFF;
+       mt7531_ind_c45_phy_write(priv, MT753X_CTRL_PHY_ADDR, MDIO_MMD_VEND2,
+                                CORE_PLL_GROUP4, val);
+
+       /* BPDU to CPU port */
+       mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
+                  BIT(MT7530_CPU_PORT));
+       mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
+                  MT753X_BPDU_CPU_ONLY);
+
+       /* Enable and reset MIB counters */
+       mt7530_mib_reset(ds);
+
+       for (i = 0; i < MT7530_NUM_PORTS; i++) {
+               /* Disable forwarding by default on all ports */
+               mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
+                          PCR_MATRIX_CLR);
+
+               mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR);
+
+               if (dsa_is_cpu_port(ds, i))
+                       mt753x_cpu_port_enable(ds, i);
+               else
+                       mt7530_port_disable(ds, i);
+
+               /* Enable consistent egress tag */
+               mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
+                          PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
+       }
+
+       ds->configure_vlan_while_not_filtering = true;
+
+       /* Flush the FDB table */
+       ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
 static bool
 mt7530_phy_mode_supported(struct dsa_switch *ds, int port,
                          const struct phylink_link_state *state)
@@ -1385,6 +1836,40 @@ mt7530_phy_mode_supported(struct dsa_switch *ds, int port,
        return true;
 }
 
+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 bool
+mt7531_phy_mode_supported(struct dsa_switch *ds, int port,
+                         const struct phylink_link_state *state)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       switch (port) {
+       case 0 ... 4: /* Internal phy */
+               if (state->interface != PHY_INTERFACE_MODE_GMII)
+                       return false;
+               break;
+       case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */
+               if (mt7531_is_rgmii_port(priv, port))
+                       return phy_interface_mode_is_rgmii(state->interface);
+               fallthrough;
+       case 6: /* 1st cpu port supports sgmii/8023z only */
+               if (state->interface != PHY_INTERFACE_MODE_SGMII &&
+                   !phy_interface_mode_is_8023z(state->interface))
+                       return false;
+               break;
+       default:
+               dev_err(priv->dev, "%s: unsupported port: %i\n", __func__,
+                       port);
+               return false;
+       }
+
+       return true;
+}
+
 static bool
 mt753x_phy_mode_supported(struct dsa_switch *ds, int port,
                          const struct phylink_link_state *state)
@@ -1417,6 +1902,227 @@ mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
        return 0;
 }
 
+static int 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;
+       val |= GP_MODE(MT7531_GP_MODE_RGMII);
+       val &= ~CLK_SKEW_IN_MASK;
+       val |= CLK_SKEW_IN(MT7531_CLK_SKEW_NO_CHG);
+       val &= ~CLK_SKEW_OUT_MASK;
+       val |= CLK_SKEW_OUT(MT7531_CLK_SKEW_NO_CHG);
+       val |= TXCLK_NO_REVERSE | RXCLK_NO_DELAY;
+
+       /* Do not adjust rgmii delay when vendor phy driver presents. */
+       if (!phydev || phy_driver_is_genphy(phydev)) {
+               val &= ~(TXCLK_NO_REVERSE | RXCLK_NO_DELAY);
+               switch (interface) {
+               case PHY_INTERFACE_MODE_RGMII:
+                       val |= TXCLK_NO_REVERSE;
+                       val |= RXCLK_NO_DELAY;
+                       break;
+               case PHY_INTERFACE_MODE_RGMII_RXID:
+                       val |= TXCLK_NO_REVERSE;
+                       break;
+               case PHY_INTERFACE_MODE_RGMII_TXID:
+                       val |= RXCLK_NO_DELAY;
+                       break;
+               case PHY_INTERFACE_MODE_RGMII_ID:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       mt7530_write(priv, MT7531_CLKGEN_CTRL, val);
+
+       return 0;
+}
+
+static void mt7531_sgmii_validate(struct mt7530_priv *priv, int port,
+                                 unsigned long *supported)
+{
+       /* Port5 supports ethier RGMII or SGMII.
+        * Port6 supports SGMII only.
+        */
+       switch (port) {
+       case 5:
+               if (mt7531_is_rgmii_port(priv, port))
+                       break;
+               fallthrough;
+       case 6:
+               phylink_set(supported, 1000baseX_Full);
+               phylink_set(supported, 2500baseX_Full);
+               phylink_set(supported, 2500baseT_Full);
+       }
+}
+
+static void
+mt7531_sgmii_link_up_force(struct dsa_switch *ds, int port,
+                          unsigned int mode, phy_interface_t interface,
+                          int speed, int duplex)
+{
+       struct mt7530_priv *priv = ds->priv;
+       unsigned int val;
+
+       /* For adjusting speed and duplex of SGMII force mode. */
+       if (interface != PHY_INTERFACE_MODE_SGMII ||
+           phylink_autoneg_inband(mode))
+               return;
+
+       /* SGMII force mode setting */
+       val = mt7530_read(priv, MT7531_SGMII_MODE(port));
+       val &= ~MT7531_SGMII_IF_MODE_MASK;
+
+       switch (speed) {
+       case SPEED_10:
+               val |= MT7531_SGMII_FORCE_SPEED_10;
+               break;
+       case SPEED_100:
+               val |= MT7531_SGMII_FORCE_SPEED_100;
+               break;
+       case SPEED_1000:
+               val |= MT7531_SGMII_FORCE_SPEED_1000;
+               break;
+       }
+
+       /* MT7531 SGMII 1G force mode can only work in full duplex mode,
+        * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not.
+        */
+       if ((speed == SPEED_10 || speed == SPEED_100) &&
+           duplex != DUPLEX_FULL)
+               val |= MT7531_SGMII_FORCE_HALF_DUPLEX;
+
+       mt7530_write(priv, MT7531_SGMII_MODE(port), val);
+}
+
+static bool mt753x_is_mac_port(u32 port)
+{
+       return (port == 5 || port == 6);
+}
+
+static int mt7531_sgmii_setup_mode_force(struct mt7530_priv *priv, u32 port,
+                                        phy_interface_t interface)
+{
+       u32 val;
+
+       if (!mt753x_is_mac_port(port))
+               return -EINVAL;
+
+       mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
+                  MT7531_SGMII_PHYA_PWD);
+
+       val = mt7530_read(priv, MT7531_PHYA_CTRL_SIGNAL3(port));
+       val &= ~MT7531_RG_TPHY_SPEED_MASK;
+       /* Setup 2.5 times faster clock for 2.5Gbps data speeds with 10B/8B
+        * encoding.
+        */
+       val |= (interface == PHY_INTERFACE_MODE_2500BASEX) ?
+               MT7531_RG_TPHY_SPEED_3_125G : MT7531_RG_TPHY_SPEED_1_25G;
+       mt7530_write(priv, MT7531_PHYA_CTRL_SIGNAL3(port), val);
+
+       mt7530_clear(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE);
+
+       /* MT7531 SGMII 1G and 2.5G force mode can only work in full duplex
+        * mode, no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not.
+        */
+       mt7530_rmw(priv, MT7531_SGMII_MODE(port),
+                  MT7531_SGMII_IF_MODE_MASK | MT7531_SGMII_REMOTE_FAULT_DIS,
+                  MT7531_SGMII_FORCE_SPEED_1000);
+
+       mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0);
+
+       return 0;
+}
+
+static int mt7531_sgmii_setup_mode_an(struct mt7530_priv *priv, int port,
+                                     phy_interface_t interface)
+{
+       if (!mt753x_is_mac_port(port))
+               return -EINVAL;
+
+       mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
+                  MT7531_SGMII_PHYA_PWD);
+
+       mt7530_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port),
+                  MT7531_RG_TPHY_SPEED_MASK, MT7531_RG_TPHY_SPEED_1_25G);
+
+       mt7530_set(priv, MT7531_SGMII_MODE(port),
+                  MT7531_SGMII_REMOTE_FAULT_DIS |
+                  MT7531_SGMII_SPEED_DUPLEX_AN);
+
+       mt7530_rmw(priv, MT7531_PCS_SPEED_ABILITY(port),
+                  MT7531_SGMII_TX_CONFIG_MASK, 1);
+
+       mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE);
+
+       mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_RESTART);
+
+       mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0);
+
+       return 0;
+}
+
+static void mt7531_sgmii_restart_an(struct dsa_switch *ds, int port)
+{
+       struct mt7530_priv *priv = ds->priv;
+       u32 val;
+
+       /* Only restart AN when AN is enabled */
+       val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
+       if (val & MT7531_SGMII_AN_ENABLE) {
+               val |= MT7531_SGMII_AN_RESTART;
+               mt7530_write(priv, MT7531_PCS_CONTROL_1(port), val);
+       }
+}
+
+static int
+mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+                 phy_interface_t interface)
+{
+       struct mt7530_priv *priv = ds->priv;
+       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:
+               dp = dsa_to_port(ds, port);
+               phydev = dp->slave->phydev;
+               return mt7531_rgmii_setup(priv, port, interface, phydev);
+       case PHY_INTERFACE_MODE_SGMII:
+               return mt7531_sgmii_setup_mode_an(priv, port, interface);
+       case PHY_INTERFACE_MODE_NA:
+       case PHY_INTERFACE_MODE_1000BASEX:
+       case PHY_INTERFACE_MODE_2500BASEX:
+               if (phylink_autoneg_inband(mode))
+                       return -EINVAL;
+
+               return mt7531_sgmii_setup_mode_force(priv, port, interface);
+       default:
+               return -EINVAL;
+       }
+
+       return -EINVAL;
+}
+
 static int
 mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
                  const struct phylink_link_state *state)
@@ -1448,6 +2154,8 @@ mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
                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)
@@ -1467,7 +2175,8 @@ unsupported:
                return;
        }
 
-       if (phylink_autoneg_inband(mode)) {
+       if (phylink_autoneg_inband(mode) &&
+           state->interface != PHY_INTERFACE_MODE_SGMII) {
                dev_err(ds->dev, "%s: in-band negotiation unsupported\n",
                        __func__);
                return;
@@ -1477,7 +2186,7 @@ unsupported:
        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;
+                  PMCR_BACKPR_EN | PMCR_FORCE_MODE_ID(priv->id);
 
        /* Are we connected to external phy */
        if (port == 5 && dsa_is_user_port(ds, 5))
@@ -1487,7 +2196,18 @@ unsupported:
                mt7530_write(priv, MT7530_PMCR_P(port), mcr_new);
 }
 
-static void mt7530_phylink_mac_link_down(struct dsa_switch *ds, int port,
+static void
+mt753x_phylink_mac_an_restart(struct dsa_switch *ds, int port)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       if (!priv->info->mac_pcs_an_restart)
+               return;
+
+       priv->info->mac_pcs_an_restart(ds, port);
+}
+
+static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port,
                                         unsigned int mode,
                                         phy_interface_t interface)
 {
@@ -1496,7 +2216,19 @@ static void mt7530_phylink_mac_link_down(struct dsa_switch *ds, int port,
        mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
 }
 
-static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port,
+static void mt753x_mac_pcs_link_up(struct dsa_switch *ds, int port,
+                                  unsigned int mode, phy_interface_t interface,
+                                  int speed, int duplex)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       if (!priv->info->mac_pcs_link_up)
+               return;
+
+       priv->info->mac_pcs_link_up(ds, port, mode, interface, speed, duplex);
+}
+
+static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
                                       unsigned int mode,
                                       phy_interface_t interface,
                                       struct phy_device *phydev,
@@ -1506,8 +2238,19 @@ static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port,
        struct mt7530_priv *priv = ds->priv;
        u32 mcr;
 
+       mt753x_mac_pcs_link_up(ds, port, mode, interface, speed, duplex);
+
        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:
                mcr |= PMCR_FORCE_SPEED_1000;
@@ -1527,6 +2270,45 @@ static void mt7530_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;
+
+       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;
+
+               mt7531_pad_setup(ds, interface);
+
+               priv->p6_interface = interface;
+               break;
+       }
+
+       if (interface == PHY_INTERFACE_MODE_2500BASEX)
+               speed = SPEED_2500;
+       else
+               speed = SPEED_1000;
+
+       mt7531_mac_config(ds, port, MLO_AN_FIXED, interface);
+       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 void
 mt7530_mac_port_validate(struct dsa_switch *ds, int port,
                         unsigned long *supported)
@@ -1535,6 +2317,14 @@ mt7530_mac_port_validate(struct dsa_switch *ds, int port,
                phylink_set(supported, 1000baseX_Full);
 }
 
+static void mt7531_mac_port_validate(struct dsa_switch *ds, int port,
+                                    unsigned long *supported)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       mt7531_sgmii_validate(priv, port, supported);
+}
+
 static void
 mt753x_phylink_validate(struct dsa_switch *ds, int port,
                        unsigned long *supported,
@@ -1551,7 +2341,8 @@ mt753x_phylink_validate(struct dsa_switch *ds, int port,
 
        phylink_set_port_modes(mask);
 
-       if (state->interface != PHY_INTERFACE_MODE_TRGMII) {
+       if (state->interface != PHY_INTERFACE_MODE_TRGMII ||
+           !phy_interface_mode_is_8023z(state->interface)) {
                phylink_set(mask, 10baseT_Half);
                phylink_set(mask, 10baseT_Full);
                phylink_set(mask, 100baseT_Half);
@@ -1570,6 +2361,11 @@ mt753x_phylink_validate(struct dsa_switch *ds, int port,
 
        linkmode_and(supported, supported, mask);
        linkmode_and(state->advertising, state->advertising, mask);
+
+       /* We can only operate at 2500BaseX or 1000BaseX.  If requested
+        * to advertise both, only report advertising at 2500BaseX.
+        */
+       phylink_helper_basex_speed(state);
 }
 
 static int
@@ -1613,6 +2409,57 @@ mt7530_phylink_mac_link_state(struct dsa_switch *ds, int port,
 }
 
 static int
+mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port,
+                             struct phylink_link_state *state)
+{
+       u32 status, val;
+       u16 config_reg;
+
+       status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
+       state->link = !!(status & MT7531_SGMII_LINK_STATUS);
+       if (state->interface == PHY_INTERFACE_MODE_SGMII &&
+           (status & MT7531_SGMII_AN_ENABLE)) {
+               val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port));
+               config_reg = val >> 16;
+
+               switch (config_reg & LPA_SGMII_SPD_MASK) {
+               case LPA_SGMII_1000:
+                       state->speed = SPEED_1000;
+                       break;
+               case LPA_SGMII_100:
+                       state->speed = SPEED_100;
+                       break;
+               case LPA_SGMII_10:
+                       state->speed = SPEED_10;
+                       break;
+               default:
+                       dev_err(priv->dev, "invalid sgmii PHY speed\n");
+                       state->link = false;
+                       return -EINVAL;
+               }
+
+               if (config_reg & LPA_SGMII_FULL_DUPLEX)
+                       state->duplex = DUPLEX_FULL;
+               else
+                       state->duplex = DUPLEX_HALF;
+       }
+
+       return 0;
+}
+
+static int
+mt7531_phylink_mac_link_state(struct dsa_switch *ds, int port,
+                             struct phylink_link_state *state)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       if (state->interface == PHY_INTERFACE_MODE_SGMII)
+               return mt7531_sgmii_pcs_get_state_an(priv, port, state);
+
+       return -EOPNOTSUPP;
+}
+
+static int
 mt753x_phylink_mac_link_state(struct dsa_switch *ds, int port,
                              struct phylink_link_state *state)
 {
@@ -1665,13 +2512,14 @@ 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,
-       .port_mirror_add        = mt7530_port_mirror_add,
-       .port_mirror_del        = mt7530_port_mirror_del,
+       .port_mirror_add        = mt753x_port_mirror_add,
+       .port_mirror_del        = mt753x_port_mirror_del,
        .phylink_validate       = mt753x_phylink_validate,
        .phylink_mac_link_state = mt753x_phylink_mac_link_state,
        .phylink_mac_config     = mt753x_phylink_mac_config,
-       .phylink_mac_link_down  = mt7530_phylink_mac_link_down,
-       .phylink_mac_link_up    = mt7530_phylink_mac_link_up,
+       .phylink_mac_an_restart = mt753x_phylink_mac_an_restart,
+       .phylink_mac_link_down  = mt753x_phylink_mac_link_down,
+       .phylink_mac_link_up    = mt753x_phylink_mac_link_up,
 };
 
 static const struct mt753x_info mt753x_table[] = {
@@ -1697,11 +2545,26 @@ static const struct mt753x_info mt753x_table[] = {
                .mac_port_get_state = mt7530_phylink_mac_link_state,
                .mac_port_config = mt7530_mac_config,
        },
+       [ID_MT7531] = {
+               .id = ID_MT7531,
+               .sw_setup = mt7531_setup,
+               .phy_read = mt7531_ind_phy_read,
+               .phy_write = mt7531_ind_phy_write,
+               .pad_setup = mt7531_pad_setup,
+               .cpu_port_config = mt7531_cpu_port_config,
+               .phy_mode_supported = mt7531_phy_mode_supported,
+               .mac_port_validate = mt7531_mac_port_validate,
+               .mac_port_get_state = mt7531_phylink_mac_link_state,
+               .mac_port_config = mt7531_mac_config,
+               .mac_pcs_an_restart = mt7531_sgmii_restart_an,
+               .mac_pcs_link_up = mt7531_sgmii_link_up_force,
+       },
 };
 
 static const struct of_device_id mt7530_of_match[] = {
        { .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], },
        { .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], },
+       { .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, mt7530_of_match);
index 44ac554..9278a8e 100644 (file)
@@ -14,6 +14,7 @@
 enum mt753x_id {
        ID_MT7530 = 0,
        ID_MT7621 = 1,
+       ID_MT7531 = 2,
 };
 
 #define        NUM_TRGMII_CTRL                 5
@@ -41,6 +42,33 @@ enum mt753x_id {
 #define  MIRROR_PORT(x)                        ((x) & 0x7)
 #define  MIRROR_MASK                   0x7
 
+/* Registers for CPU forward control */
+#define MT7531_CFC                     0x4
+#define  MT7531_MIRROR_EN              BIT(19)
+#define  MT7531_MIRROR_MASK            (MIRROR_MASK << 16)
+#define  MT7531_MIRROR_PORT_GET(x)     (((x) >> 16) & MIRROR_MASK)
+#define  MT7531_MIRROR_PORT_SET(x)     (((x) & MIRROR_MASK) << 16)
+#define  MT7531_CPU_PMAP_MASK          GENMASK(7, 0)
+
+#define MT753X_MIRROR_REG(id)          (((id) == ID_MT7531) ? \
+                                        MT7531_CFC : MT7530_MFC)
+#define MT753X_MIRROR_EN(id)           (((id) == ID_MT7531) ? \
+                                        MT7531_MIRROR_EN : MIRROR_EN)
+#define MT753X_MIRROR_MASK(id)         (((id) == ID_MT7531) ? \
+                                        MT7531_MIRROR_MASK : MIRROR_MASK)
+
+/* Registers for BPDU and PAE frame control*/
+#define MT753X_BPC                     0x24
+#define  MT753X_BPDU_PORT_FW_MASK      GENMASK(2, 0)
+
+enum mt753x_bpdu_port_fw {
+       MT753X_BPDU_FOLLOW_MFC,
+       MT753X_BPDU_CPU_EXCLUDE = 4,
+       MT753X_BPDU_CPU_INCLUDE = 5,
+       MT753X_BPDU_CPU_ONLY = 6,
+       MT753X_BPDU_DROP = 7,
+};
+
 /* Registers for address table access */
 #define MT7530_ATA1                    0x74
 #define  STATIC_EMP                    0
@@ -220,10 +248,30 @@ enum mt7530_vlan_port_attr {
 #define  PMCR_FORCE_LNK                        BIT(0)
 #define  PMCR_SPEED_MASK               (PMCR_FORCE_SPEED_100 | \
                                         PMCR_FORCE_SPEED_1000)
+#define  MT7531_FORCE_LNK              BIT(31)
+#define  MT7531_FORCE_SPD              BIT(30)
+#define  MT7531_FORCE_DPX              BIT(29)
+#define  MT7531_FORCE_RX_FC            BIT(28)
+#define  MT7531_FORCE_TX_FC            BIT(27)
+#define  MT7531_FORCE_MODE             (MT7531_FORCE_LNK | \
+                                        MT7531_FORCE_SPD | \
+                                        MT7531_FORCE_DPX | \
+                                        MT7531_FORCE_RX_FC | \
+                                        MT7531_FORCE_TX_FC)
+#define  PMCR_FORCE_MODE_ID(id)                (((id) == ID_MT7531) ? \
+                                        MT7531_FORCE_MODE : \
+                                        PMCR_FORCE_MODE)
 #define  PMCR_LINK_SETTINGS_MASK       (PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \
                                         PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \
                                         PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
                                         PMCR_FORCE_FDX | PMCR_FORCE_LNK)
+#define  PMCR_CPU_PORT_SETTING(id)     (PMCR_FORCE_MODE_ID((id)) | \
+                                        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 | \
+                                        PMCR_FORCE_SPEED_1000 | \
+                                        PMCR_FORCE_FDX | PMCR_FORCE_LNK)
 
 #define MT7530_PMSR_P(x)               (0x3008 + (x) * 0x100)
 #define  PMSR_EEE1G                    BIT(7)
@@ -237,6 +285,10 @@ enum mt7530_vlan_port_attr {
 #define  PMSR_DPX                      BIT(1)
 #define  PMSR_LINK                     BIT(0)
 
+/* Register for port debug count */
+#define MT7531_DBG_CNT(x)              (0x3018 + (x) * 0x100)
+#define  MT7531_DIS_CLR                        BIT(31)
+
 /* Register for MIB */
 #define MT7530_PORT_MIB_COUNTER(x)     (0x4000 + (x) * 0x100)
 #define MT7530_MIB_CCR                 0x4fe0
@@ -254,12 +306,118 @@ enum mt7530_vlan_port_attr {
                                         CCR_RX_OCT_CNT_BAD | \
                                         CCR_TX_OCT_CNT_GOOD | \
                                         CCR_TX_OCT_CNT_BAD)
+
+/* MT7531 SGMII register group */
+#define MT7531_SGMII_REG_BASE          0x5000
+#define MT7531_SGMII_REG(p, r)         (MT7531_SGMII_REG_BASE + \
+                                       ((p) - 5) * 0x1000 + (r))
+
+/* Register forSGMII PCS_CONTROL_1 */
+#define MT7531_PCS_CONTROL_1(p)                MT7531_SGMII_REG(p, 0x00)
+#define  MT7531_SGMII_LINK_STATUS      BIT(18)
+#define  MT7531_SGMII_AN_ENABLE                BIT(12)
+#define  MT7531_SGMII_AN_RESTART       BIT(9)
+
+/* Register for SGMII PCS_SPPED_ABILITY */
+#define MT7531_PCS_SPEED_ABILITY(p)    MT7531_SGMII_REG(p, 0x08)
+#define  MT7531_SGMII_TX_CONFIG_MASK   GENMASK(15, 0)
+#define  MT7531_SGMII_TX_CONFIG                BIT(0)
+
+/* Register for SGMII_MODE */
+#define MT7531_SGMII_MODE(p)           MT7531_SGMII_REG(p, 0x20)
+#define  MT7531_SGMII_REMOTE_FAULT_DIS BIT(8)
+#define  MT7531_SGMII_IF_MODE_MASK     GENMASK(5, 1)
+#define  MT7531_SGMII_FORCE_DUPLEX     BIT(4)
+#define  MT7531_SGMII_FORCE_SPEED_MASK GENMASK(3, 2)
+#define  MT7531_SGMII_FORCE_SPEED_1000 BIT(3)
+#define  MT7531_SGMII_FORCE_SPEED_100  BIT(2)
+#define  MT7531_SGMII_FORCE_SPEED_10   0
+#define  MT7531_SGMII_SPEED_DUPLEX_AN  BIT(1)
+
+enum mt7531_sgmii_force_duplex {
+       MT7531_SGMII_FORCE_FULL_DUPLEX = 0,
+       MT7531_SGMII_FORCE_HALF_DUPLEX = 0x10,
+};
+
+/* Fields of QPHY_PWR_STATE_CTRL */
+#define MT7531_QPHY_PWR_STATE_CTRL(p)  MT7531_SGMII_REG(p, 0xe8)
+#define  MT7531_SGMII_PHYA_PWD         BIT(4)
+
+/* Values of SGMII SPEED */
+#define MT7531_PHYA_CTRL_SIGNAL3(p)    MT7531_SGMII_REG(p, 0x128)
+#define  MT7531_RG_TPHY_SPEED_MASK     (BIT(2) | BIT(3))
+#define  MT7531_RG_TPHY_SPEED_1_25G    0x0
+#define  MT7531_RG_TPHY_SPEED_3_125G   BIT(2)
+
 /* Register for system reset */
 #define MT7530_SYS_CTRL                        0x7000
 #define  SYS_CTRL_PHY_RST              BIT(2)
 #define  SYS_CTRL_SW_RST               BIT(1)
 #define  SYS_CTRL_REG_RST              BIT(0)
 
+/* Register for PHY Indirect Access Control */
+#define MT7531_PHY_IAC                 0x701C
+#define  MT7531_PHY_ACS_ST             BIT(31)
+#define  MT7531_MDIO_REG_ADDR_MASK     (0x1f << 25)
+#define  MT7531_MDIO_PHY_ADDR_MASK     (0x1f << 20)
+#define  MT7531_MDIO_CMD_MASK          (0x3 << 18)
+#define  MT7531_MDIO_ST_MASK           (0x3 << 16)
+#define  MT7531_MDIO_RW_DATA_MASK      (0xffff)
+#define  MT7531_MDIO_REG_ADDR(x)       (((x) & 0x1f) << 25)
+#define  MT7531_MDIO_DEV_ADDR(x)       (((x) & 0x1f) << 25)
+#define  MT7531_MDIO_PHY_ADDR(x)       (((x) & 0x1f) << 20)
+#define  MT7531_MDIO_CMD(x)            (((x) & 0x3) << 18)
+#define  MT7531_MDIO_ST(x)             (((x) & 0x3) << 16)
+
+enum mt7531_phy_iac_cmd {
+       MT7531_MDIO_ADDR = 0,
+       MT7531_MDIO_WRITE = 1,
+       MT7531_MDIO_READ = 2,
+       MT7531_MDIO_READ_CL45 = 3,
+};
+
+/* MDIO_ST: MDIO start field */
+enum mt7531_mdio_st {
+       MT7531_MDIO_ST_CL45 = 0,
+       MT7531_MDIO_ST_CL22 = 1,
+};
+
+#define  MT7531_MDIO_CL22_READ         (MT7531_MDIO_ST(MT7531_MDIO_ST_CL22) | \
+                                        MT7531_MDIO_CMD(MT7531_MDIO_READ))
+#define  MT7531_MDIO_CL22_WRITE                (MT7531_MDIO_ST(MT7531_MDIO_ST_CL22) | \
+                                        MT7531_MDIO_CMD(MT7531_MDIO_WRITE))
+#define  MT7531_MDIO_CL45_ADDR         (MT7531_MDIO_ST(MT7531_MDIO_ST_CL45) | \
+                                        MT7531_MDIO_CMD(MT7531_MDIO_ADDR))
+#define  MT7531_MDIO_CL45_READ         (MT7531_MDIO_ST(MT7531_MDIO_ST_CL45) | \
+                                        MT7531_MDIO_CMD(MT7531_MDIO_READ))
+#define  MT7531_MDIO_CL45_WRITE                (MT7531_MDIO_ST(MT7531_MDIO_ST_CL45) | \
+                                        MT7531_MDIO_CMD(MT7531_MDIO_WRITE))
+
+/* Register for RGMII clock phase */
+#define MT7531_CLKGEN_CTRL             0x7500
+#define  CLK_SKEW_OUT(x)               (((x) & 0x3) << 8)
+#define  CLK_SKEW_OUT_MASK             GENMASK(9, 8)
+#define  CLK_SKEW_IN(x)                        (((x) & 0x3) << 6)
+#define  CLK_SKEW_IN_MASK              GENMASK(7, 6)
+#define  RXCLK_NO_DELAY                        BIT(5)
+#define  TXCLK_NO_REVERSE              BIT(4)
+#define  GP_MODE(x)                    (((x) & 0x3) << 1)
+#define  GP_MODE_MASK                  GENMASK(2, 1)
+#define  GP_CLK_EN                     BIT(0)
+
+enum mt7531_gp_mode {
+       MT7531_GP_MODE_RGMII = 0,
+       MT7531_GP_MODE_MII = 1,
+       MT7531_GP_MODE_REV_MII = 2
+};
+
+enum mt7531_clk_skew {
+       MT7531_CLK_SKEW_NO_CHG = 0,
+       MT7531_CLK_SKEW_DLY_100PPS = 1,
+       MT7531_CLK_SKEW_DLY_200PPS = 2,
+       MT7531_CLK_SKEW_REVERSE = 3,
+};
+
 /* Register for hw trap status */
 #define MT7530_HWTRAP                  0x7800
 #define  HWTRAP_XTAL_MASK              (BIT(10) | BIT(9))
@@ -267,6 +425,16 @@ enum mt7530_vlan_port_attr {
 #define  HWTRAP_XTAL_40MHZ             (BIT(10))
 #define  HWTRAP_XTAL_20MHZ             (BIT(9))
 
+#define MT7531_HWTRAP                  0x7800
+#define  HWTRAP_XTAL_FSEL_MASK         BIT(7)
+#define  HWTRAP_XTAL_FSEL_25MHZ                BIT(7)
+#define  HWTRAP_XTAL_FSEL_40MHZ                0
+/* Unique fields of (M)HWSTRAP for MT7531 */
+#define  XTAL_FSEL_S                   7
+#define  XTAL_FSEL_M                   BIT(7)
+#define  PHY_EN                                BIT(6)
+#define  CHG_STRAP                     BIT(8)
+
 /* Register for hw trap modification */
 #define MT7530_MHWTRAP                 0x7804
 #define  MHWTRAP_PHY0_SEL              BIT(20)
@@ -281,14 +449,37 @@ enum mt7530_vlan_port_attr {
 #define MT7530_TOP_SIG_CTRL            0x7808
 #define  TOP_SIG_CTRL_NORMAL           (BIT(17) | BIT(16))
 
+#define MT7531_TOP_SIG_SR              0x780c
+#define  PAD_DUAL_SGMII_EN             BIT(1)
+#define  PAD_MCM_SMI_EN                        BIT(0)
+
 #define MT7530_IO_DRV_CR               0x7810
 #define  P5_IO_CLK_DRV(x)              ((x) & 0x3)
 #define  P5_IO_DATA_DRV(x)             (((x) & 0x3) << 4)
 
+#define MT7531_CHIP_REV                        0x781C
+
+#define MT7531_PLLGP_EN                        0x7820
+#define  EN_COREPLL                    BIT(2)
+#define  SW_CLKSW                      BIT(1)
+#define  SW_PLLGP                      BIT(0)
+
 #define MT7530_P6ECR                   0x7830
 #define  P6_INTF_MODE_MASK             0x3
 #define  P6_INTF_MODE(x)               ((x) & 0x3)
 
+#define MT7531_PLLGP_CR0               0x78a8
+#define  RG_COREPLL_EN                 BIT(22)
+#define  RG_COREPLL_POSDIV_S           23
+#define  RG_COREPLL_POSDIV_M           0x3800000
+#define  RG_COREPLL_SDM_PCW_S          1
+#define  RG_COREPLL_SDM_PCW_M          0x3ffffe
+#define  RG_COREPLL_SDM_PCW_CHG                BIT(0)
+
+/* Registers for RGMII and SGMII PLL clock */
+#define MT7531_ANA_PLLGP_CR2           0x78b0
+#define MT7531_ANA_PLLGP_CR5           0x78bc
+
 /* Registers for TRGMII on the both side */
 #define MT7530_TRGMII_RCK_CTRL         0x7a00
 #define  RX_RST                                BIT(31)
@@ -327,10 +518,25 @@ enum mt7530_vlan_port_attr {
 #define MT7530_P5RGMIITXCR             0x7b04
 #define  CSR_RGMII_TXC_CFG(x)          ((x) & 0x1f)
 
+/* Registers for GPIO mode */
+#define MT7531_GPIO_MODE0              0x7c0c
+#define  MT7531_GPIO0_MASK             GENMASK(3, 0)
+#define  MT7531_GPIO0_INTERRUPT                1
+
+#define MT7531_GPIO_MODE1              0x7c10
+#define  MT7531_GPIO11_RG_RXD2_MASK    GENMASK(15, 12)
+#define  MT7531_EXT_P_MDC_11           (2 << 12)
+#define  MT7531_GPIO12_RG_RXD3_MASK    GENMASK(19, 16)
+#define  MT7531_EXT_P_MDIO_12          (2 << 16)
+
 #define MT7530_CREV                    0x7ffc
 #define  CHIP_NAME_SHIFT               16
 #define  MT7530_ID                     0x7530
 
+#define MT7531_CREV                    0x781C
+#define  CHIP_REV_M                    0x0f
+#define  MT7531_ID                     0x7531
+
 /* Registers for core PLL access through mmd indirect */
 #define CORE_PLL_GROUP2                        0x401
 #define  RG_SYSPLL_EN_NORMAL           BIT(15)
@@ -347,6 +553,10 @@ enum mt7530_vlan_port_attr {
 #define  RG_SYSPLL_DDSFBK_EN           BIT(12)
 #define  RG_SYSPLL_BIAS_EN             BIT(11)
 #define  RG_SYSPLL_BIAS_LPF_EN         BIT(10)
+#define  MT7531_PHY_PLL_OFF            BIT(5)
+#define  MT7531_PHY_PLL_BYPASS_MODE    BIT(4)
+
+#define MT753X_CTRL_PHY_ADDR           0
 
 #define CORE_PLL_GROUP5                        0x404
 #define  RG_LCDDS_PCW_NCPO1(x)         ((x) & 0xffff)
@@ -425,6 +635,7 @@ enum p5_interface_select {
        P5_INTF_SEL_PHY_P0,
        P5_INTF_SEL_PHY_P4,
        P5_INTF_SEL_GMAC5,
+       P5_INTF_SEL_GMAC5_SGMII,
 };
 
 static const char *p5_intf_modes(unsigned int p5_interface)
@@ -438,6 +649,8 @@ 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";
        }
@@ -458,6 +671,10 @@ static const char *p5_intf_modes(unsigned int p5_interface)
  *                     MAC port
  * @mac_port_config:   Holding the way setting up the PHY attribute to a
  *                     certain MAC port
+ * @mac_pcs_an_restart Holding the way restarting PCS autonegotiation for a
+ *                     certain MAC port
+ * @mac_pcs_link_up:   Holding the way setting up the PHY attribute to the pcs
+ *                     of the certain MAC port
  */
 struct mt753x_info {
        enum mt753x_id id;
@@ -466,6 +683,7 @@ struct mt753x_info {
        int (*phy_read)(struct dsa_switch *ds, int port, int regnum);
        int (*phy_write)(struct dsa_switch *ds, int port, int regnum, u16 val);
        int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface);
+       int (*cpu_port_config)(struct dsa_switch *ds, int port);
        bool (*phy_mode_supported)(struct dsa_switch *ds, int port,
                                   const struct phylink_link_state *state);
        void (*mac_port_validate)(struct dsa_switch *ds, int port,
@@ -475,6 +693,10 @@ struct mt753x_info {
        int (*mac_port_config)(struct dsa_switch *ds, int port,
                               unsigned int mode,
                               phy_interface_t interface);
+       void (*mac_pcs_an_restart)(struct dsa_switch *ds, int port);
+       void (*mac_pcs_link_up)(struct dsa_switch *ds, int port,
+                               unsigned int mode, phy_interface_t interface,
+                               int speed, int duplex);
 };
 
 /* struct mt7530_priv -        This is the main data structure for holding the state