diff options
Diffstat (limited to 'drivers/net/dsa/mt7530.c')
| -rw-r--r-- | drivers/net/dsa/mt7530.c | 216 | 
1 files changed, 185 insertions, 31 deletions
| diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index f06f5fa2f898..96f7c9eede35 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -67,6 +67,11 @@ static const struct mt7530_mib_desc mt7530_mib[] = {  	MIB_DESC(1, 0xb8, "RxArlDrop"),  }; +/* Since phy_device has not yet been created and + * phy_{read,write}_mmd_indirect is not available, we provide our own + * core_{read,write}_mmd_indirect with core_{clear,write,set} wrappers + * to complete this function. + */  static int  core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad)  { @@ -435,38 +440,26 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)  		mt7530_write(priv, MT7530_TRGMII_TD_ODT(i),  			     TD_DM_DRVP(8) | TD_DM_DRVN(8)); -	/* Setup core clock for MT7530 */ -	if (!trgint) { -		/* Disable MT7530 core clock */ -		core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); - -		/* Disable PLL, since phy_device has not yet been created -		 * provided for phy_[read,write]_mmd_indirect is called, we -		 * provide our own core_write_mmd_indirect to complete this -		 * function. -		 */ -		core_write_mmd_indirect(priv, -					CORE_GSWPLL_GRP1, -					MDIO_MMD_VEND2, -					0); +	/* Disable MT7530 core and TRGMII Tx clocks */ +	core_clear(priv, CORE_TRGMII_GSW_CLK_CG, +		   REG_GSWCK_EN | REG_TRGMIICK_EN); -		/* Set core clock into 500Mhz */ -		core_write(priv, CORE_GSWPLL_GRP2, -			   RG_GSWPLL_POSDIV_500M(1) | -			   RG_GSWPLL_FBKDIV_500M(25)); +	/* Setup core clock for MT7530 */ +	/* Disable PLL */ +	core_write(priv, CORE_GSWPLL_GRP1, 0); -		/* Enable PLL */ -		core_write(priv, CORE_GSWPLL_GRP1, -			   RG_GSWPLL_EN_PRE | -			   RG_GSWPLL_POSDIV_200M(2) | -			   RG_GSWPLL_FBKDIV_200M(32)); +	/* Set core clock into 500Mhz */ +	core_write(priv, CORE_GSWPLL_GRP2, +		   RG_GSWPLL_POSDIV_500M(1) | +		   RG_GSWPLL_FBKDIV_500M(25)); -		/* Enable MT7530 core clock */ -		core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); -	} +	/* Enable PLL */ +	core_write(priv, CORE_GSWPLL_GRP1, +		   RG_GSWPLL_EN_PRE | +		   RG_GSWPLL_POSDIV_200M(2) | +		   RG_GSWPLL_FBKDIV_200M(32));  	/* Setup the MT7530 TRGMII Tx Clock */ -	core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);  	core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1));  	core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0));  	core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta)); @@ -480,6 +473,8 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)  	core_write(priv, CORE_PLL_GROUP7,  		   RG_LCDDS_PCW_NCPO_CHG | RG_LCCDS_C(3) |  		   RG_LCDDS_PWDB | RG_LCDDS_ISO_EN); + +	/* Enable MT7530 core and TRGMII Tx clocks */  	core_set(priv, CORE_TRGMII_GSW_CLK_CG,  		 REG_GSWCK_EN | REG_TRGMIICK_EN); @@ -999,8 +994,9 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)  	mt7530_write(priv, MT7530_PVC_P(port),  		     PORT_SPEC_TAG); -	/* Unknown multicast frame forwarding to the cpu port */ -	mt7530_rmw(priv, MT7530_MFC, UNM_FFP_MASK, UNM_FFP(BIT(port))); +	/* Disable flooding by default */ +	mt7530_rmw(priv, MT7530_MFC, BC_FFP_MASK | UNM_FFP_MASK | UNU_FFP_MASK, +		   BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) | UNU_FFP(BIT(port)));  	/* Set CPU port number */  	if (priv->id == ID_MT7621) @@ -1138,6 +1134,56 @@ mt7530_stp_state_set(struct dsa_switch *ds, int port, u8 state)  }  static int +mt7530_port_pre_bridge_flags(struct dsa_switch *ds, int port, +			     struct switchdev_brport_flags flags, +			     struct netlink_ext_ack *extack) +{ +	if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | +			   BR_BCAST_FLOOD)) +		return -EINVAL; + +	return 0; +} + +static int +mt7530_port_bridge_flags(struct dsa_switch *ds, int port, +			 struct switchdev_brport_flags flags, +			 struct netlink_ext_ack *extack) +{ +	struct mt7530_priv *priv = ds->priv; + +	if (flags.mask & BR_LEARNING) +		mt7530_rmw(priv, MT7530_PSC_P(port), SA_DIS, +			   flags.val & BR_LEARNING ? 0 : SA_DIS); + +	if (flags.mask & BR_FLOOD) +		mt7530_rmw(priv, MT7530_MFC, UNU_FFP(BIT(port)), +			   flags.val & BR_FLOOD ? UNU_FFP(BIT(port)) : 0); + +	if (flags.mask & BR_MCAST_FLOOD) +		mt7530_rmw(priv, MT7530_MFC, UNM_FFP(BIT(port)), +			   flags.val & BR_MCAST_FLOOD ? UNM_FFP(BIT(port)) : 0); + +	if (flags.mask & BR_BCAST_FLOOD) +		mt7530_rmw(priv, MT7530_MFC, BC_FFP(BIT(port)), +			   flags.val & BR_BCAST_FLOOD ? BC_FFP(BIT(port)) : 0); + +	return 0; +} + +static int +mt7530_port_set_mrouter(struct dsa_switch *ds, int port, bool mrouter, +			struct netlink_ext_ack *extack) +{ +	struct mt7530_priv *priv = ds->priv; + +	mt7530_rmw(priv, MT7530_MFC, UNM_FFP(BIT(port)), +		   mrouter ? UNM_FFP(BIT(port)) : 0); + +	return 0; +} + +static int  mt7530_port_bridge_join(struct dsa_switch *ds, int port,  			struct net_device *bridge)  { @@ -1349,6 +1395,59 @@ err:  }  static int +mt7530_port_mdb_add(struct dsa_switch *ds, int port, +		    const struct switchdev_obj_port_mdb *mdb) +{ +	struct mt7530_priv *priv = ds->priv; +	const u8 *addr = mdb->addr; +	u16 vid = mdb->vid; +	u8 port_mask = 0; +	int ret; + +	mutex_lock(&priv->reg_mutex); + +	mt7530_fdb_write(priv, vid, 0, addr, 0, STATIC_EMP); +	if (!mt7530_fdb_cmd(priv, MT7530_FDB_READ, NULL)) +		port_mask = (mt7530_read(priv, MT7530_ATRD) >> PORT_MAP) +			    & PORT_MAP_MASK; + +	port_mask |= BIT(port); +	mt7530_fdb_write(priv, vid, port_mask, addr, -1, STATIC_ENT); +	ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, NULL); + +	mutex_unlock(&priv->reg_mutex); + +	return ret; +} + +static int +mt7530_port_mdb_del(struct dsa_switch *ds, int port, +		    const struct switchdev_obj_port_mdb *mdb) +{ +	struct mt7530_priv *priv = ds->priv; +	const u8 *addr = mdb->addr; +	u16 vid = mdb->vid; +	u8 port_mask = 0; +	int ret; + +	mutex_lock(&priv->reg_mutex); + +	mt7530_fdb_write(priv, vid, 0, addr, 0, STATIC_EMP); +	if (!mt7530_fdb_cmd(priv, MT7530_FDB_READ, NULL)) +		port_mask = (mt7530_read(priv, MT7530_ATRD) >> PORT_MAP) +			    & PORT_MAP_MASK; + +	port_mask &= ~BIT(port); +	mt7530_fdb_write(priv, vid, port_mask, addr, -1, +			 port_mask ? STATIC_ENT : STATIC_EMP); +	ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, NULL); + +	mutex_unlock(&priv->reg_mutex); + +	return ret; +} + +static int  mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)  {  	struct mt7530_dummy_poll p; @@ -1820,9 +1919,12 @@ mt7530_setup(struct dsa_switch *ds)  			ret = mt753x_cpu_port_enable(ds, i);  			if (ret)  				return ret; -		} else +		} else {  			mt7530_port_disable(ds, i); +			/* Disable learning by default on all user ports */ +			mt7530_set(priv, MT7530_PSC_P(i), SA_DIS); +		}  		/* Enable consistent egress tag */  		mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,  			   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); @@ -1984,9 +2086,13 @@ mt7531_setup(struct dsa_switch *ds)  			ret = mt753x_cpu_port_enable(ds, i);  			if (ret)  				return ret; -		} else +		} else {  			mt7530_port_disable(ds, i); +			/* Disable learning by default on all user ports */ +			mt7530_set(priv, MT7530_PSC_P(i), SA_DIS); +		} +  		/* Enable consistent egress tag */  		mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,  			   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); @@ -2464,6 +2570,17 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,  			mcr |= PMCR_RX_FC_EN;  	} +	if (mode == MLO_AN_PHY && phydev && phy_init_eee(phydev, 0) >= 0) { +		switch (speed) { +		case SPEED_1000: +			mcr |= PMCR_FORCE_EEE1G; +			break; +		case SPEED_100: +			mcr |= PMCR_FORCE_EEE100; +			break; +		} +	} +  	mt7530_set(priv, MT7530_PMCR_P(port), mcr);  } @@ -2694,6 +2811,36 @@ mt753x_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)  	return priv->info->phy_write(ds, port, regnum, val);  } +static int mt753x_get_mac_eee(struct dsa_switch *ds, int port, +			      struct ethtool_eee *e) +{ +	struct mt7530_priv *priv = ds->priv; +	u32 eeecr = mt7530_read(priv, MT7530_PMEEECR_P(port)); + +	e->tx_lpi_enabled = !(eeecr & LPI_MODE_EN); +	e->tx_lpi_timer = GET_LPI_THRESH(eeecr); + +	return 0; +} + +static int mt753x_set_mac_eee(struct dsa_switch *ds, int port, +			      struct ethtool_eee *e) +{ +	struct mt7530_priv *priv = ds->priv; +	u32 set, mask = LPI_THRESH_MASK | LPI_MODE_EN; + +	if (e->tx_lpi_timer > 0xFFF) +		return -EINVAL; + +	set = SET_LPI_THRESH(e->tx_lpi_timer); +	if (!e->tx_lpi_enabled) +		/* Force LPI Mode without a delay */ +		set |= LPI_MODE_EN; +	mt7530_rmw(priv, MT7530_PMEEECR_P(port), mask, set); + +	return 0; +} +  static const struct dsa_switch_ops mt7530_switch_ops = {  	.get_tag_protocol	= mtk_get_tag_protocol,  	.setup			= mt753x_setup, @@ -2708,11 +2855,16 @@ static const struct dsa_switch_ops mt7530_switch_ops = {  	.port_change_mtu	= mt7530_port_change_mtu,  	.port_max_mtu		= mt7530_port_max_mtu,  	.port_stp_state_set	= mt7530_stp_state_set, +	.port_pre_bridge_flags	= mt7530_port_pre_bridge_flags, +	.port_bridge_flags	= mt7530_port_bridge_flags, +	.port_set_mrouter	= mt7530_port_set_mrouter,  	.port_bridge_join	= mt7530_port_bridge_join,  	.port_bridge_leave	= mt7530_port_bridge_leave,  	.port_fdb_add		= mt7530_port_fdb_add,  	.port_fdb_del		= mt7530_port_fdb_del,  	.port_fdb_dump		= mt7530_port_fdb_dump, +	.port_mdb_add		= mt7530_port_mdb_add, +	.port_mdb_del		= mt7530_port_mdb_del,  	.port_vlan_filtering	= mt7530_port_vlan_filtering,  	.port_vlan_add		= mt7530_port_vlan_add,  	.port_vlan_del		= mt7530_port_vlan_del, @@ -2724,6 +2876,8 @@ static const struct dsa_switch_ops mt7530_switch_ops = {  	.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		= mt753x_get_mac_eee, +	.set_mac_eee		= mt753x_set_mac_eee,  };  static const struct mt753x_info mt753x_table[] = { | 
