diff options
Diffstat (limited to 'drivers/net/dsa/mt7530.c')
| -rw-r--r-- | drivers/net/dsa/mt7530.c | 229 | 
1 files changed, 103 insertions, 126 deletions
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 022466ca1c19..5c444cd722bd 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -67,58 +67,6 @@ static const struct mt7530_mib_desc mt7530_mib[] = {  };  static int -mt7623_trgmii_write(struct mt7530_priv *priv,  u32 reg, u32 val) -{ -	int ret; - -	ret =  regmap_write(priv->ethernet, TRGMII_BASE(reg), val); -	if (ret < 0) -		dev_err(priv->dev, -			"failed to priv write register\n"); -	return ret; -} - -static u32 -mt7623_trgmii_read(struct mt7530_priv *priv, u32 reg) -{ -	int ret; -	u32 val; - -	ret = regmap_read(priv->ethernet, TRGMII_BASE(reg), &val); -	if (ret < 0) { -		dev_err(priv->dev, -			"failed to priv read register\n"); -		return ret; -	} - -	return val; -} - -static void -mt7623_trgmii_rmw(struct mt7530_priv *priv, u32 reg, -		  u32 mask, u32 set) -{ -	u32 val; - -	val = mt7623_trgmii_read(priv, reg); -	val &= ~mask; -	val |= set; -	mt7623_trgmii_write(priv, reg, val); -} - -static void -mt7623_trgmii_set(struct mt7530_priv *priv, u32 reg, u32 val) -{ -	mt7623_trgmii_rmw(priv, reg, 0, val); -} - -static void -mt7623_trgmii_clear(struct mt7530_priv *priv, u32 reg, u32 val) -{ -	mt7623_trgmii_rmw(priv, reg, val, 0); -} - -static int  core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad)  {  	struct mii_bus *bus = priv->bus; @@ -530,27 +478,6 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)  		for (i = 0 ; i < NUM_TRGMII_CTRL; i++)  			mt7530_rmw(priv, MT7530_TRGMII_RD(i),  				   RD_TAP_MASK, RD_TAP(16)); -	else -		if (priv->id != ID_MT7621) -			mt7623_trgmii_set(priv, GSW_INTF_MODE, -					  INTF_MODE_TRGMII); - -	return 0; -} - -static int -mt7623_pad_clk_setup(struct dsa_switch *ds) -{ -	struct mt7530_priv *priv = ds->priv; -	int i; - -	for (i = 0 ; i < NUM_TRGMII_CTRL; i++) -		mt7623_trgmii_write(priv, GSW_TRGMII_TD_ODT(i), -				    TD_DM_DRVP(8) | TD_DM_DRVN(8)); - -	mt7623_trgmii_set(priv, GSW_TRGMII_RCK_CTRL, RX_RST | RXC_DQSISEL); -	mt7623_trgmii_clear(priv, GSW_TRGMII_RCK_CTRL, RX_RST); -  	return 0;  } @@ -563,17 +490,6 @@ mt7530_mib_reset(struct dsa_switch *ds)  	mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_ACTIVATE);  } -static void -mt7530_port_set_status(struct mt7530_priv *priv, int port, int enable) -{ -	u32 mask = PMCR_TX_EN | PMCR_RX_EN; - -	if (enable) -		mt7530_set(priv, MT7530_PMCR_P(port), mask); -	else -		mt7530_clear(priv, MT7530_PMCR_P(port), mask); -} -  static int mt7530_phy_read(struct dsa_switch *ds, int port, int regnum)  {  	struct mt7530_priv *priv = ds->priv; @@ -750,7 +666,7 @@ mt7530_port_enable(struct dsa_switch *ds, int port,  	priv->ports[port].enable = true;  	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,  		   priv->ports[port].pm); -	mt7530_port_set_status(priv, port, 0); +	mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);  	mutex_unlock(&priv->reg_mutex); @@ -773,7 +689,7 @@ mt7530_port_disable(struct dsa_switch *ds, int port)  	priv->ports[port].enable = false;  	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,  		   PCR_MATRIX_CLR); -	mt7530_port_set_status(priv, port, 0); +	mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);  	mutex_unlock(&priv->reg_mutex);  } @@ -857,8 +773,9 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)  	 */  	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,  		   MT7530_PORT_MATRIX_MODE); -	mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK, -		   VLAN_ATTR(MT7530_VLAN_TRANSPARENT)); +	mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK | PVC_EG_TAG_MASK, +		   VLAN_ATTR(MT7530_VLAN_TRANSPARENT) | +		   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));  	for (i = 0; i < MT7530_NUM_PORTS; i++) {  		if (dsa_is_user_port(ds, i) && @@ -874,8 +791,8 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)  	if (all_user_ports_removed) {  		mt7530_write(priv, MT7530_PCR_P(MT7530_CPU_PORT),  			     PCR_MATRIX(dsa_user_ports(priv->ds))); -		mt7530_write(priv, MT7530_PVC_P(MT7530_CPU_PORT), -			     PORT_SPEC_TAG); +		mt7530_write(priv, MT7530_PVC_P(MT7530_CPU_PORT), PORT_SPEC_TAG +			     | PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));  	}  } @@ -901,8 +818,9 @@ mt7530_port_set_vlan_aware(struct dsa_switch *ds, int port)  	/* Set the port as a user port which is to be able to recognize VID  	 * from incoming packets before fetching entry within the VLAN table.  	 */ -	mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK, -		   VLAN_ATTR(MT7530_VLAN_USER)); +	mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK | PVC_EG_TAG_MASK, +		   VLAN_ATTR(MT7530_VLAN_USER) | +		   PVC_EG_TAG(MT7530_VLAN_EG_DISABLED));  }  static void @@ -1222,6 +1140,64 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port,  	return 0;  } +static int mt7530_port_mirror_add(struct dsa_switch *ds, int port, +				  struct dsa_mall_mirror_tc_entry *mirror, +				  bool ingress) +{ +	struct mt7530_priv *priv = ds->priv; +	u32 val; + +	/* Check for existent entry */ +	if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) +		return -EEXIST; + +	val = mt7530_read(priv, MT7530_MFC); + +	/* MT7530 only supports one monitor port */ +	if (val & MIRROR_EN && MIRROR_PORT(val) != mirror->to_local_port) +		return -EEXIST; + +	val |= MIRROR_EN; +	val &= ~MIRROR_MASK; +	val |= mirror->to_local_port; +	mt7530_write(priv, MT7530_MFC, val); + +	val = mt7530_read(priv, MT7530_PCR_P(port)); +	if (ingress) { +		val |= PORT_RX_MIR; +		priv->mirror_rx |= BIT(port); +	} else { +		val |= PORT_TX_MIR; +		priv->mirror_tx |= BIT(port); +	} +	mt7530_write(priv, MT7530_PCR_P(port), val); + +	return 0; +} + +static void mt7530_port_mirror_del(struct dsa_switch *ds, int port, +				   struct dsa_mall_mirror_tc_entry *mirror) +{ +	struct mt7530_priv *priv = ds->priv; +	u32 val; + +	val = mt7530_read(priv, MT7530_PCR_P(port)); +	if (mirror->ingress) { +		val &= ~PORT_RX_MIR; +		priv->mirror_rx &= ~BIT(port); +	} else { +		val &= ~PORT_TX_MIR; +		priv->mirror_tx &= ~BIT(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); +	} +} +  static enum dsa_tag_protocol  mtk_get_tag_protocol(struct dsa_switch *ds, int port,  		     enum dsa_tag_protocol mp) @@ -1256,10 +1232,6 @@ mt7530_setup(struct dsa_switch *ds)  	dn = dsa_to_port(ds, MT7530_CPU_PORT)->master->dev.of_node->parent;  	if (priv->id == ID_MT7530) { -		priv->ethernet = syscon_node_to_regmap(dn); -		if (IS_ERR(priv->ethernet)) -			return PTR_ERR(priv->ethernet); -  		regulator_set_voltage(priv->core_pwr, 1000000, 1000000);  		ret = regulator_enable(priv->core_pwr);  		if (ret < 0) { @@ -1333,6 +1305,10 @@ mt7530_setup(struct dsa_switch *ds)  			mt7530_cpu_port_enable(priv, 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));  	}  	/* Setup port 5 */ @@ -1356,6 +1332,9 @@ mt7530_setup(struct dsa_switch *ds)  				continue;  			phy_node = of_parse_phandle(mac_np, "phy-handle", 0); +			if (!phy_node) +				continue; +  			if (phy_node->parent == priv->dev->of_node->parent) {  				ret = of_get_phy_mode(mac_np, &interface);  				if (ret && ret != -ENODEV) @@ -1418,14 +1397,6 @@ static void mt7530_phylink_mac_config(struct dsa_switch *ds, int port,  		/* Setup TX circuit incluing relevant PAD and driving */  		mt7530_pad_clk_setup(ds, state->interface); -		if (priv->id == ID_MT7530) { -			/* Setup RX circuit, relevant PAD and driving on the -			 * host which must be placed after the setup on the -			 * device side is all finished. -			 */ -			mt7623_pad_clk_setup(ds); -		} -  		priv->p6_interface = state->interface;  		break;  	default: @@ -1441,31 +1412,14 @@ static void mt7530_phylink_mac_config(struct dsa_switch *ds, int port,  	mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));  	mcr_new = mcr_cur; -	mcr_new &= ~(PMCR_FORCE_SPEED_1000 | PMCR_FORCE_SPEED_100 | -		     PMCR_FORCE_FDX | PMCR_TX_FC_EN | PMCR_RX_FC_EN); +	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_FORCE_LNK; +		   PMCR_BACKPR_EN | PMCR_FORCE_MODE;  	/* Are we connected to external phy */  	if (port == 5 && dsa_is_user_port(ds, 5))  		mcr_new |= PMCR_EXT_PHY; -	switch (state->speed) { -	case SPEED_1000: -		mcr_new |= PMCR_FORCE_SPEED_1000; -		break; -	case SPEED_100: -		mcr_new |= PMCR_FORCE_SPEED_100; -		break; -	} -	if (state->duplex == DUPLEX_FULL) { -		mcr_new |= PMCR_FORCE_FDX; -		if (state->pause & MLO_PAUSE_TX) -			mcr_new |= PMCR_TX_FC_EN; -		if (state->pause & MLO_PAUSE_RX) -			mcr_new |= PMCR_RX_FC_EN; -	} -  	if (mcr_new != mcr_cur)  		mt7530_write(priv, MT7530_PMCR_P(port), mcr_new);  } @@ -1476,17 +1430,38 @@ static void mt7530_phylink_mac_link_down(struct dsa_switch *ds, int port,  {  	struct mt7530_priv *priv = ds->priv; -	mt7530_port_set_status(priv, port, 0); +	mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);  }  static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port,  				       unsigned int mode,  				       phy_interface_t interface, -				       struct phy_device *phydev) +				       struct phy_device *phydev, +				       int speed, int duplex, +				       bool tx_pause, bool rx_pause)  {  	struct mt7530_priv *priv = ds->priv; +	u32 mcr; + +	mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK; + +	switch (speed) { +	case SPEED_1000: +		mcr |= PMCR_FORCE_SPEED_1000; +		break; +	case SPEED_100: +		mcr |= PMCR_FORCE_SPEED_100; +		break; +	} +	if (duplex == DUPLEX_FULL) { +		mcr |= PMCR_FORCE_FDX; +		if (tx_pause) +			mcr |= PMCR_TX_FC_EN; +		if (rx_pause) +			mcr |= PMCR_RX_FC_EN; +	} -	mt7530_port_set_status(priv, port, 1); +	mt7530_set(priv, MT7530_PMCR_P(port), mcr);  }  static void mt7530_phylink_validate(struct dsa_switch *ds, int port, @@ -1611,6 +1586,8 @@ 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,  	.phylink_validate	= mt7530_phylink_validate,  	.phylink_mac_link_state = mt7530_phylink_mac_link_state,  	.phylink_mac_config	= mt7530_phylink_mac_config,  |