2020-09-07 15:47:15 +00:00
|
|
|
From: Landen Chao <landen.chao@mediatek.com>
|
|
|
|
Date: Fri, 4 Sep 2020 22:21:59 +0800
|
|
|
|
Subject: [PATCH] net: dsa: mt7530: Add the support of MT7531 switch
|
|
|
|
|
|
|
|
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>
|
|
|
|
---
|
|
|
|
|
|
|
|
--- a/drivers/net/dsa/mt7530.c
|
|
|
|
+++ b/drivers/net/dsa/mt7530.c
|
|
|
|
@@ -234,6 +234,12 @@ mt7530_write(struct mt7530_priv *priv, u
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2021-03-17 18:22:56 +00:00
|
|
|
@@ -481,6 +487,108 @@ mt7530_pad_clk_setup(struct dsa_switch *
|
2020-09-07 15:47:15 +00:00
|
|
|
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 val;
|
|
|
|
+ u32 top_sig;
|
|
|
|
+ u32 hwstrap;
|
|
|
|
+ u32 xtal;
|
|
|
|
+
|
|
|
|
+ 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)
|
|
|
|
{
|
2021-03-17 18:22:56 +00:00
|
|
|
@@ -505,6 +613,217 @@ static int mt7530_phy_write(struct dsa_s
|
2020-09-07 15:47:15 +00:00
|
|
|
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)
|
2021-03-17 18:22:56 +00:00
|
|
|
@@ -621,9 +940,14 @@ unlock_exit:
|
2020-09-07 15:47:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-03-17 18:22:56 +00:00
|
|
|
@@ -636,7 +960,7 @@ mt7530_cpu_port_enable(struct mt7530_pri
|
2020-09-07 15:47:15 +00:00
|
|
|
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)));
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1122,27 +1446,42 @@ mt7530_port_vlan_del(struct dsa_switch *
|
2020-09-07 15:47:15 +00:00
|
|
|
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) {
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1157,7 +1496,7 @@ static int mt7530_port_mirror_add(struct
|
2020-09-07 15:47:15 +00:00
|
|
|
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;
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1174,9 +1513,9 @@ static void mt7530_port_mirror_del(struc
|
2020-09-07 15:47:15 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1282,7 +1621,7 @@ mt7530_setup(struct dsa_switch *ds)
|
2020-09-07 15:47:15 +00:00
|
|
|
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);
|
|
|
|
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1336,6 +1675,118 @@ mt7530_setup(struct dsa_switch *ds)
|
2020-09-07 15:47:15 +00:00
|
|
|
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)
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1374,6 +1825,47 @@ unsupported:
|
2020-09-07 15:47:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
+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_supported(struct dsa_switch *ds, int port,
|
|
|
|
+ const struct phylink_link_state *state)
|
|
|
|
+{
|
|
|
|
+ struct mt7530_priv *priv = ds->priv;
|
|
|
|
+
|
|
|
|
+ switch (port) {
|
|
|
|
+ case 0: /* Internal phy */
|
|
|
|
+ case 1:
|
|
|
|
+ case 2:
|
|
|
|
+ case 3:
|
|
|
|
+ case 4:
|
|
|
|
+ if (state->interface != PHY_INTERFACE_MODE_GMII)
|
|
|
|
+ goto unsupported;
|
|
|
|
+ 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))
|
|
|
|
+ goto unsupported;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ dev_err(priv->dev, "%s: unsupported port: %i\n", __func__,
|
|
|
|
+ port);
|
|
|
|
+ goto unsupported;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+
|
|
|
|
+unsupported:
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
static bool
|
|
|
|
mt753x_phy_mode_supported(struct dsa_switch *ds, int port,
|
|
|
|
const struct phylink_link_state *state)
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1406,6 +1898,227 @@ mt7530_mac_config(struct dsa_switch *ds,
|
2020-09-07 15:47:15 +00:00
|
|
|
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;
|
|
|
|
+ const 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)
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1441,6 +2154,8 @@ mt753x_phylink_mac_config(struct dsa_swi
|
2020-09-07 15:47:15 +00:00
|
|
|
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)
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1460,7 +2175,8 @@ unsupported:
|
2020-09-07 15:47:15 +00:00
|
|
|
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;
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1470,7 +2186,7 @@ unsupported:
|
2020-09-07 15:47:15 +00:00
|
|
|
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))
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1480,7 +2196,18 @@ unsupported:
|
2020-09-07 15:47:15 +00:00
|
|
|
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)
|
|
|
|
{
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1489,7 +2216,19 @@ static void mt7530_phylink_mac_link_down
|
2020-09-07 15:47:15 +00:00
|
|
|
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,
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1499,18 +2238,29 @@ static void mt7530_phylink_mac_link_up(s
|
2020-09-07 15:47:15 +00:00
|
|
|
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;
|
|
|
|
if (priv->eee_enable & BIT(port))
|
|
|
|
- mcr_new |= PMCR_FORCE_EEE1G;
|
|
|
|
+ mcr |= PMCR_FORCE_EEE1G;
|
|
|
|
break;
|
|
|
|
case SPEED_100:
|
|
|
|
mcr |= PMCR_FORCE_SPEED_100;
|
|
|
|
if (priv->eee_enable & BIT(port))
|
|
|
|
- mcr_new |= PMCR_FORCE_EEE100;
|
|
|
|
+ mcr |= PMCR_FORCE_EEE100;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (duplex == DUPLEX_FULL) {
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1524,6 +2274,45 @@ static void mt7530_phylink_mac_link_up(s
|
2020-09-07 15:47:15 +00:00
|
|
|
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)
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1532,6 +2321,14 @@ mt7530_mac_port_validate(struct dsa_swit
|
2020-09-07 15:47:15 +00:00
|
|
|
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,
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1548,7 +2345,8 @@ mt753x_phylink_validate(struct dsa_switc
|
2020-09-07 15:47:15 +00:00
|
|
|
|
|
|
|
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);
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1567,6 +2365,11 @@ mt753x_phylink_validate(struct dsa_switc
|
2020-09-07 15:47:15 +00:00
|
|
|
|
|
|
|
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
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1657,6 +2460,63 @@ static int mt7530_set_mac_eee(struct dsa
|
2020-09-07 15:47:15 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
+#ifdef notyet
|
|
|
|
+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;
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+mt7531_phylink_mac_link_state(struct dsa_switch *ds, int port,
|
|
|
|
+ struct phylink_link_state *state)
|
|
|
|
+{
|
|
|
|
+#ifdef notyet
|
|
|
|
+ struct mt7530_priv *priv = ds->priv;
|
|
|
|
+
|
|
|
|
+ if (state->interface == PHY_INTERFACE_MODE_SGMII)
|
|
|
|
+ return mt7531_sgmii_pcs_get_state_an(priv, port, state);
|
|
|
|
+#else
|
|
|
|
+ return mt7530_phylink_mac_link_state(ds, port, state);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ return -EOPNOTSUPP;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
static int
|
|
|
|
mt753x_phylink_mac_link_state(struct dsa_switch *ds, int port,
|
|
|
|
struct phylink_link_state *state)
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1710,13 +2570,14 @@ static const struct dsa_switch_ops mt753
|
2020-09-07 15:47:15 +00:00
|
|
|
.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,
|
|
|
|
.get_mac_eee = mt7530_get_mac_eee,
|
|
|
|
.set_mac_eee = mt7530_set_mac_eee,
|
|
|
|
};
|
2021-06-03 18:46:59 +00:00
|
|
|
@@ -1744,11 +2605,26 @@ static const struct mt753x_info mt753x_t
|
2020-09-07 15:47:15 +00:00
|
|
|
.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_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);
|
|
|
|
--- a/drivers/net/dsa/mt7530.h
|
|
|
|
+++ b/drivers/net/dsa/mt7530.h
|
|
|
|
@@ -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
|
|
|
|
@@ -222,10 +250,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)
|
|
|
|
@@ -245,6 +293,10 @@ enum mt7530_vlan_port_attr {
|
|
|
|
#define LPI_THRESH(x) ((x & 0xFFF) << 4)
|
|
|
|
#define LPI_MODE_EN 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
|
|
|
|
@@ -262,12 +314,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))
|
|
|
|
@@ -275,6 +433,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)
|
|
|
|
@@ -289,14 +457,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)
|
|
|
|
@@ -335,10 +526,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)
|
|
|
|
@@ -355,6 +561,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)
|
|
|
|
@@ -433,6 +643,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)
|
|
|
|
@@ -446,6 +657,8 @@ static const char *p5_intf_modes(unsigne
|
|
|
|
return "PHY P4";
|
|
|
|
case P5_INTF_SEL_GMAC5:
|
|
|
|
return "GMAC5";
|
|
|
|
+ case P5_INTF_SEL_GMAC5_SGMII:
|
|
|
|
+ return "GMAC5_SGMII";
|
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
@@ -466,6 +679,10 @@ static const char *p5_intf_modes(unsigne
|
|
|
|
* 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;
|
|
|
|
@@ -474,6 +691,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,
|
|
|
|
@@ -483,6 +701,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
|