Index: linux-5.4.203/drivers/net/dsa/mt7530.c =================================================================== --- linux-5.4.203.orig/drivers/net/dsa/mt7530.c +++ linux-5.4.203/drivers/net/dsa/mt7530.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "mt7530.h" #include "mt7530_nl.h" @@ -170,28 +171,44 @@ core_clear(struct mt7530_priv *priv, u32 core_rmw(priv, reg, val, 0); } +static void +mtk_w32(struct mt7530_priv *priv, u32 val, unsigned reg) +{ + __raw_writel(val, priv->base + reg); +} + +static u32 +mtk_r32(struct mt7530_priv *priv, unsigned reg) +{ + return __raw_readl(priv->base + reg); +} + static int mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val) { struct mii_bus *bus = priv->bus; u16 page, r, lo, hi; - int ret; - - page = (reg >> 6) & 0x3ff; - r = (reg >> 2) & 0xf; - lo = val & 0xffff; - hi = val >> 16; - - /* MT7530 uses 31 as the pseudo port */ - ret = bus->write(bus, 0x1f, 0x1f, page); - if (ret < 0) - goto err; + int ret = 0; - ret = bus->write(bus, 0x1f, r, lo); - if (ret < 0) - goto err; + if (priv->direct_access){ + mtk_w32(priv, val, reg); + } else { + page = (reg >> 6) & 0x3ff; + r = (reg >> 2) & 0xf; + lo = val & 0xffff; + hi = val >> 16; + + /* MT7530 uses 31 as the pseudo port */ + ret = bus->write(bus, 0x1f, 0x1f, page); + if (ret < 0) + goto err; + + ret = bus->write(bus, 0x1f, r, lo); + if (ret < 0) + goto err; - ret = bus->write(bus, 0x1f, 0x10, hi); + ret = bus->write(bus, 0x1f, 0x10, hi); + } err: if (ret < 0) dev_err(&bus->dev, @@ -206,21 +223,25 @@ mt7530_mii_read(struct mt7530_priv *priv u16 page, r, lo, hi; int ret; - page = (reg >> 6) & 0x3ff; - r = (reg >> 2) & 0xf; + if (priv->direct_access){ + return mtk_r32(priv, reg); + } else { + page = (reg >> 6) & 0x3ff; + r = (reg >> 2) & 0xf; - /* MT7530 uses 31 as the pseudo port */ - ret = bus->write(bus, 0x1f, 0x1f, page); - if (ret < 0) { - dev_err(&bus->dev, - "failed to read mt7530 register\n"); - return ret; - } + /* MT7530 uses 31 as the pseudo port */ + ret = bus->write(bus, 0x1f, 0x1f, page); + if (ret < 0) { + dev_err(&bus->dev, + "failed to read mt7530 register\n"); + return ret; + } - lo = bus->read(bus, 0x1f, r); - hi = bus->read(bus, 0x1f, 0x10); + lo = bus->read(bus, 0x1f, r); + hi = bus->read(bus, 0x1f, 0x10); - return (hi << 16) | (lo & 0xffff); + return (hi << 16) | (lo & 0xffff); + } } void @@ -1906,9 +1927,9 @@ mt7531_phy_supported(struct dsa_switch * 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)) + case 6: /* 1st cpu port supports sgmii/8023z/usxgmii/10gkr */ + if (state->interface != PHY_INTERFACE_MODE_SGMII && state->interface != PHY_INTERFACE_MODE_USXGMII && + state->interface != PHY_INTERFACE_MODE_10GKR && !phy_interface_mode_is_8023z(state->interface)) goto unsupported; break; default: @@ -2017,6 +2038,13 @@ static void mt7531_sgmii_validate(struct phylink_set(supported, 1000baseX_Full); phylink_set(supported, 2500baseX_Full); phylink_set(supported, 2500baseT_Full); + phylink_set(supported, 10000baseKR_Full); + phylink_set(supported, 10000baseT_Full); + phylink_set(supported, 10000baseCR_Full); + phylink_set(supported, 10000baseSR_Full); + phylink_set(supported, 10000baseLR_Full); + phylink_set(supported, 10000baseLRM_Full); + phylink_set(supported, 10000baseER_Full); } } @@ -2165,6 +2193,8 @@ mt7531_mac_config(struct dsa_switch *ds, case PHY_INTERFACE_MODE_NA: case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_2500BASEX: + case PHY_INTERFACE_MODE_USXGMII: + case PHY_INTERFACE_MODE_10GKR: if (phylink_autoneg_inband(mode)) return -EINVAL; @@ -2302,8 +2332,8 @@ static void mt753x_phylink_mac_link_up(s /* 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))) { + if (interface == PHY_INTERFACE_MODE_TRGMII || interface == PHY_INTERFACE_MODE_USXGMII || + interface == PHY_INTERFACE_MODE_10GKR || (phy_interface_mode_is_8023z(interface))) { speed = SPEED_1000; duplex = DUPLEX_FULL; } @@ -2402,8 +2432,8 @@ mt753x_phylink_validate(struct dsa_switc phylink_set_port_modes(mask); - if (state->interface != PHY_INTERFACE_MODE_TRGMII || - !phy_interface_mode_is_8023z(state->interface)) { + if (state->interface != PHY_INTERFACE_MODE_TRGMII || state->interface != PHY_INTERFACE_MODE_USXGMII || + state->interface != PHY_INTERFACE_MODE_10GKR || !phy_interface_mode_is_8023z(state->interface)) { phylink_set(mask, 10baseT_Half); phylink_set(mask, 10baseT_Full); phylink_set(mask, 100baseT_Half); @@ -2607,6 +2637,66 @@ mt753x_phy_write(struct dsa_switch *ds, return priv->info->phy_write(ds, port, regnum, val); } +static int +mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface) +{ + return 0; +} + +static int +mt7988_setup(struct dsa_switch *ds) +{ + struct mt7530_priv *priv = ds->priv; + u32 unused_pm = 0; + int ret, i; + + /* Reset the switch through internal reset */ + mt7530_write(priv, MT7530_SYS_CTRL, + SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST); + + /* 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_unused_port(ds, i)) + unused_pm |= BIT(i); + else 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)); + } + + mt7531_phy_setup(ds); + + /* Group and enable unused ports as a standalone dumb switch. */ + setup_unused_ports(ds, unused_pm); + + 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 const struct dsa_switch_ops mt7530_switch_ops = { .get_tag_protocol = mtk_get_tag_protocol, .setup = mt753x_setup, @@ -2676,12 +2766,28 @@ static const struct mt753x_info mt753x_t .mac_pcs_an_restart = mt7531_sgmii_restart_an, .mac_pcs_link_up = mt7531_sgmii_link_up_force, }, + [ID_MT7988] = { + .id = ID_MT7988, + .sw_setup = mt7988_setup, + .phy_read = mt7531_ind_phy_read, + .phy_write = mt7531_ind_phy_write, + .pad_setup = mt7988_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], }, + { .compatible = "mediatek,mt7988", .data = &mt753x_table[ID_MT7988], }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, mt7530_of_match); @@ -2691,6 +2797,7 @@ mt7530_probe(struct mdio_device *mdiodev { struct mt7530_priv *priv; struct device_node *dn; + struct device_node *switch_node = NULL; int ret; dn = mdiodev->dev.of_node; @@ -2760,6 +2867,16 @@ mt7530_probe(struct mdio_device *mdiodev } } + switch_node = of_find_node_by_name(NULL, "switch0"); + if(switch_node) { + priv->base = of_iomap(switch_node, 0); + if(priv->base == NULL){ + dev_err(&mdiodev->dev, "of_iomap failed\n"); + return -ENOMEM; + } + priv->direct_access = 1; + } + priv->bus = mdiodev->bus; priv->dev = &mdiodev->dev; priv->ds->priv = priv; @@ -2768,9 +2885,12 @@ mt7530_probe(struct mdio_device *mdiodev dev_set_drvdata(&mdiodev->dev, priv); ret = dsa_register_switch(priv->ds); - if (ret) - return ret; - + if (ret) { + if(priv->base) + iounmap(priv->base); + + return ret; + } mt7530_nl_init(&priv); return 0; @@ -2795,6 +2915,9 @@ mt7530_remove(struct mdio_device *mdiode dsa_unregister_switch(priv->ds); mutex_destroy(&priv->reg_mutex); + if(priv->base) + iounmap(priv->base); + mt7530_nl_exit(); } Index: linux-5.4.203/drivers/net/dsa/mt7530.h =================================================================== --- linux-5.4.203.orig/drivers/net/dsa/mt7530.h +++ linux-5.4.203/drivers/net/dsa/mt7530.h @@ -16,6 +16,7 @@ enum mt753x_id { ID_MT7530 = 0, ID_MT7621 = 1, ID_MT7531 = 2, + ID_MT7988 = 3, }; #define NUM_TRGMII_CTRL 5 @@ -51,11 +52,11 @@ enum mt753x_id { #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) ? \ +#define MT753X_MIRROR_REG(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \ MT7531_CFC : MT7530_MFC) -#define MT753X_MIRROR_EN(id) (((id) == ID_MT7531) ? \ +#define MT753X_MIRROR_EN(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \ MT7531_MIRROR_EN : MIRROR_EN) -#define MT753X_MIRROR_MASK(id) (((id) == ID_MT7531) ? \ +#define MT753X_MIRROR_MASK(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \ MT7531_MIRROR_MASK : MIRROR_MASK) /* Registers for BPDU and PAE frame control*/ @@ -261,7 +262,7 @@ enum mt7530_vlan_port_attr { MT7531_FORCE_DPX | \ MT7531_FORCE_RX_FC | \ MT7531_FORCE_TX_FC) -#define PMCR_FORCE_MODE_ID(id) (((id) == ID_MT7531) ? \ +#define PMCR_FORCE_MODE_ID(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \ MT7531_FORCE_MODE : \ PMCR_FORCE_MODE) #define PMCR_LINK_SETTINGS_MASK (PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \ @@ -733,6 +734,8 @@ struct mt7530_priv { struct regulator *core_pwr; struct regulator *io_pwr; struct gpio_desc *reset; + void __iomem *base; + int direct_access; const struct mt753x_info *info; unsigned int id; bool mcm;