diff options
Diffstat (limited to 'drivers/net/dsa/qca8k.c')
| -rw-r--r-- | drivers/net/dsa/qca8k.c | 435 | 
1 files changed, 330 insertions, 105 deletions
| diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index a984f06f6f04..ea7f12778922 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -889,62 +889,183 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)  }  static int -qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv) +qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv)  { -	struct device_node *port_dn; -	phy_interface_t mode; -	struct dsa_port *dp; -	u32 val; +	u32 mask = 0; +	int ret = 0; -	/* CPU port is already checked */ -	dp = dsa_to_port(priv->ds, 0); +	/* SoC specific settings for ipq8064. +	 * If more device require this consider adding +	 * a dedicated binding. +	 */ +	if (of_machine_is_compatible("qcom,ipq8064")) +		mask |= QCA8K_MAC_PWR_RGMII0_1_8V; + +	/* SoC specific settings for ipq8065 */ +	if (of_machine_is_compatible("qcom,ipq8065")) +		mask |= QCA8K_MAC_PWR_RGMII1_1_8V; + +	if (mask) { +		ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, +				QCA8K_MAC_PWR_RGMII0_1_8V | +				QCA8K_MAC_PWR_RGMII1_1_8V, +				mask); +	} + +	return ret; +} -	port_dn = dp->dn; +static int qca8k_find_cpu_port(struct dsa_switch *ds) +{ +	struct qca8k_priv *priv = ds->priv; -	/* Check if port 0 is set to the correct type */ -	of_get_phy_mode(port_dn, &mode); -	if (mode != PHY_INTERFACE_MODE_RGMII_ID && -	    mode != PHY_INTERFACE_MODE_RGMII_RXID && -	    mode != PHY_INTERFACE_MODE_RGMII_TXID) { +	/* Find the connected cpu port. Valid port are 0 or 6 */ +	if (dsa_is_cpu_port(ds, 0))  		return 0; + +	dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); + +	if (dsa_is_cpu_port(ds, 6)) +		return 6; + +	return -EINVAL; +} + +static int +qca8k_setup_of_pws_reg(struct qca8k_priv *priv) +{ +	struct device_node *node = priv->dev->of_node; +	const struct qca8k_match_data *data; +	u32 val = 0; +	int ret; + +	/* QCA8327 require to set to the correct mode. +	 * His bigger brother QCA8328 have the 172 pin layout. +	 * Should be applied by default but we set this just to make sure. +	 */ +	if (priv->switch_id == QCA8K_ID_QCA8327) { +		data = of_device_get_match_data(priv->dev); + +		/* Set the correct package of 148 pin for QCA8327 */ +		if (data->reduced_package) +			val |= QCA8327_PWS_PACKAGE148_EN; + +		ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, +				val); +		if (ret) +			return ret;  	} -	switch (mode) { -	case PHY_INTERFACE_MODE_RGMII_ID: -	case PHY_INTERFACE_MODE_RGMII_RXID: -		if (of_property_read_u32(port_dn, "rx-internal-delay-ps", &val)) -			val = 2; -		else -			/* Switch regs accept value in ns, convert ps to ns */ -			val = val / 1000; +	if (of_property_read_bool(node, "qca,ignore-power-on-sel")) +		val |= QCA8K_PWS_POWER_ON_SEL; -		if (val > QCA8K_MAX_DELAY) { -			dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); -			val = 3; +	if (of_property_read_bool(node, "qca,led-open-drain")) { +		if (!(val & QCA8K_PWS_POWER_ON_SEL)) { +			dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); +			return -EINVAL;  		} -		priv->rgmii_rx_delay = val; -		/* Stop here if we need to check only for rx delay */ -		if (mode != PHY_INTERFACE_MODE_RGMII_ID) -			break; +		val |= QCA8K_PWS_LED_OPEN_EN_CSR; +	} -		fallthrough; -	case PHY_INTERFACE_MODE_RGMII_TXID: -		if (of_property_read_u32(port_dn, "tx-internal-delay-ps", &val)) -			val = 1; -		else -			/* Switch regs accept value in ns, convert ps to ns */ -			val = val / 1000; +	return qca8k_rmw(priv, QCA8K_REG_PWS, +			QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, +			val); +} -		if (val > QCA8K_MAX_DELAY) { -			dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); -			val = 3; -		} +static int +qca8k_parse_port_config(struct qca8k_priv *priv) +{ +	int port, cpu_port_index = -1, ret; +	struct device_node *port_dn; +	phy_interface_t mode; +	struct dsa_port *dp; +	u32 delay; -		priv->rgmii_tx_delay = val; -		break; -	default: -		return 0; +	/* We have 2 CPU port. Check them */ +	for (port = 0; port < QCA8K_NUM_PORTS && cpu_port_index < QCA8K_NUM_CPU_PORTS; port++) { +		/* Skip every other port */ +		if (port != 0 && port != 6) +			continue; + +		dp = dsa_to_port(priv->ds, port); +		port_dn = dp->dn; +		cpu_port_index++; + +		if (!of_device_is_available(port_dn)) +			continue; + +		ret = of_get_phy_mode(port_dn, &mode); +		if (ret) +			continue; + +		switch (mode) { +		case PHY_INTERFACE_MODE_RGMII: +		case PHY_INTERFACE_MODE_RGMII_ID: +		case PHY_INTERFACE_MODE_RGMII_TXID: +		case PHY_INTERFACE_MODE_RGMII_RXID: +		case PHY_INTERFACE_MODE_SGMII: +			delay = 0; + +			if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) +				/* Switch regs accept value in ns, convert ps to ns */ +				delay = delay / 1000; +			else if (mode == PHY_INTERFACE_MODE_RGMII_ID || +				 mode == PHY_INTERFACE_MODE_RGMII_TXID) +				delay = 1; + +			if (delay > QCA8K_MAX_DELAY) { +				dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); +				delay = 3; +			} + +			priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; + +			delay = 0; + +			if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) +				/* Switch regs accept value in ns, convert ps to ns */ +				delay = delay / 1000; +			else if (mode == PHY_INTERFACE_MODE_RGMII_ID || +				 mode == PHY_INTERFACE_MODE_RGMII_RXID) +				delay = 2; + +			if (delay > QCA8K_MAX_DELAY) { +				dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); +				delay = 3; +			} + +			priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; + +			/* Skip sgmii parsing for rgmii* mode */ +			if (mode == PHY_INTERFACE_MODE_RGMII || +			    mode == PHY_INTERFACE_MODE_RGMII_ID || +			    mode == PHY_INTERFACE_MODE_RGMII_TXID || +			    mode == PHY_INTERFACE_MODE_RGMII_RXID) +				break; + +			if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) +				priv->ports_config.sgmii_tx_clk_falling_edge = true; + +			if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) +				priv->ports_config.sgmii_rx_clk_falling_edge = true; + +			if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { +				priv->ports_config.sgmii_enable_pll = true; + +				if (priv->switch_id == QCA8K_ID_QCA8327) { +					dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); +					priv->ports_config.sgmii_enable_pll = false; +				} + +				if (priv->switch_revision < 2) +					dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); +			} + +			break; +		default: +			continue; +		}  	}  	return 0; @@ -954,15 +1075,20 @@ static int  qca8k_setup(struct dsa_switch *ds)  {  	struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -	int ret, i; +	int cpu_port, ret, i;  	u32 mask; -	/* Make sure that port 0 is the cpu port */ -	if (!dsa_is_cpu_port(ds, 0)) { -		dev_err(priv->dev, "port 0 is not the CPU port"); -		return -EINVAL; +	cpu_port = qca8k_find_cpu_port(ds); +	if (cpu_port < 0) { +		dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); +		return cpu_port;  	} +	/* Parse CPU port config to be later used in phy_link mac_config */ +	ret = qca8k_parse_port_config(priv); +	if (ret) +		return ret; +  	mutex_init(&priv->reg_mutex);  	/* Start by setting up the register mapping */ @@ -975,7 +1101,11 @@ qca8k_setup(struct dsa_switch *ds)  	if (ret)  		return ret; -	ret = qca8k_setup_of_rgmii_delay(priv); +	ret = qca8k_setup_of_pws_reg(priv); +	if (ret) +		return ret; + +	ret = qca8k_setup_mac_pwr_sel(priv);  	if (ret)  		return ret; @@ -992,41 +1122,49 @@ qca8k_setup(struct dsa_switch *ds)  	if (ret)  		dev_warn(priv->dev, "mib init failed"); -	/* Enable QCA header mode on the cpu port */ -	ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT), -			  QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | -			  QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); -	if (ret) { -		dev_err(priv->dev, "failed enabling QCA header mode"); -		return ret; -	} - -	/* Disable forwarding by default on all ports */ +	/* Initial setup of all ports */  	for (i = 0; i < QCA8K_NUM_PORTS; i++) { +		/* Disable forwarding by default on all ports */  		ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),  				QCA8K_PORT_LOOKUP_MEMBER, 0);  		if (ret)  			return ret; -	} -	/* Disable MAC by default on all ports */ -	for (i = 1; i < QCA8K_NUM_PORTS; i++) -		qca8k_port_set_status(priv, i, 0); +		/* Enable QCA header mode on all cpu ports */ +		if (dsa_is_cpu_port(ds, i)) { +			ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), +					  QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | +					  QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); +			if (ret) { +				dev_err(priv->dev, "failed enabling QCA header mode"); +				return ret; +			} +		} + +		/* Disable MAC by default on all user ports */ +		if (dsa_is_user_port(ds, i)) +			qca8k_port_set_status(priv, i, 0); +	} -	/* Forward all unknown frames to CPU port for Linux processing */ +	/* Forward all unknown frames to CPU port for Linux processing +	 * Notice that in multi-cpu config only one port should be set +	 * for igmp, unknown, multicast and broadcast packet +	 */  	ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, -			  BIT(0) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | -			  BIT(0) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | -			  BIT(0) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S | -			  BIT(0) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S); +			  BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | +			  BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | +			  BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S | +			  BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);  	if (ret)  		return ret; -	/* Setup connection between CPU port & user ports */ +	/* Setup connection between CPU port & user ports +	 * Configure specific switch configuration for ports +	 */  	for (i = 0; i < QCA8K_NUM_PORTS; i++) {  		/* CPU port gets connected to all user ports of the switch */  		if (dsa_is_cpu_port(ds, i)) { -			ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT), +			ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),  					QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));  			if (ret)  				return ret; @@ -1038,7 +1176,7 @@ qca8k_setup(struct dsa_switch *ds)  			ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),  					QCA8K_PORT_LOOKUP_MEMBER, -					BIT(QCA8K_CPU_PORT)); +					BIT(cpu_port));  			if (ret)  				return ret; @@ -1063,16 +1201,14 @@ qca8k_setup(struct dsa_switch *ds)  			if (ret)  				return ret;  		} -	} -	/* The port 5 of the qca8337 have some problem in flood condition. The -	 * original legacy driver had some specific buffer and priority settings -	 * for the different port suggested by the QCA switch team. Add this -	 * missing settings to improve switch stability under load condition. -	 * This problem is limited to qca8337 and other qca8k switch are not affected. -	 */ -	if (priv->switch_id == QCA8K_ID_QCA8337) { -		for (i = 0; i < QCA8K_NUM_PORTS; i++) { +		/* The port 5 of the qca8337 have some problem in flood condition. The +		 * original legacy driver had some specific buffer and priority settings +		 * for the different port suggested by the QCA switch team. Add this +		 * missing settings to improve switch stability under load condition. +		 * This problem is limited to qca8337 and other qca8k switch are not affected. +		 */ +		if (priv->switch_id == QCA8K_ID_QCA8337) {  			switch (i) {  			/* The 2 CPU port and port 5 requires some different  			 * priority than any other ports. @@ -1108,6 +1244,12 @@ qca8k_setup(struct dsa_switch *ds)  				  QCA8K_PORT_HOL_CTRL1_WRED_EN,  				  mask);  		} + +		/* Set initial MTU for every port. +		 * We have only have a general MTU setting. So track +		 * every port and set the max across all port. +		 */ +		priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN;  	}  	/* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ @@ -1121,8 +1263,6 @@ qca8k_setup(struct dsa_switch *ds)  	}  	/* Setup our port MTUs to match power on defaults */ -	for (i = 0; i < QCA8K_NUM_PORTS; i++) -		priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN;  	ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN);  	if (ret)  		dev_warn(priv->dev, "failed setting MTU settings"); @@ -1137,12 +1277,53 @@ qca8k_setup(struct dsa_switch *ds)  }  static void +qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, +				      u32 reg) +{ +	u32 delay, val = 0; +	int ret; + +	/* Delay can be declared in 3 different way. +	 * Mode to rgmii and internal-delay standard binding defined +	 * rgmii-id or rgmii-tx/rx phy mode set. +	 * The parse logic set a delay different than 0 only when one +	 * of the 3 different way is used. In all other case delay is +	 * not enabled. With ID or TX/RXID delay is enabled and set +	 * to the default and recommended value. +	 */ +	if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { +		delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; + +		val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | +			QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; +	} + +	if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { +		delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; + +		val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | +			QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; +	} + +	/* Set RGMII delay based on the selected values */ +	ret = qca8k_rmw(priv, reg, +			QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | +			QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | +			QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | +			QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, +			val); +	if (ret) +		dev_err(priv->dev, "Failed to set internal delay for CPU port%d", +			cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); +} + +static void  qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,  			 const struct phylink_link_state *state)  {  	struct qca8k_priv *priv = ds->priv; +	int cpu_port_index, ret;  	u32 reg, val; -	int ret;  	switch (port) {  	case 0: /* 1st CPU port */ @@ -1154,6 +1335,7 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,  			return;  		reg = QCA8K_REG_PORT0_PAD_CTRL; +		cpu_port_index = QCA8K_CPU_PORT0;  		break;  	case 1:  	case 2: @@ -1172,6 +1354,7 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,  			return;  		reg = QCA8K_REG_PORT6_PAD_CTRL; +		cpu_port_index = QCA8K_CPU_PORT6;  		break;  	default:  		dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); @@ -1186,23 +1369,18 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,  	switch (state->interface) {  	case PHY_INTERFACE_MODE_RGMII: -		/* RGMII mode means no delay so don't enable the delay */ -		qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); -		break;  	case PHY_INTERFACE_MODE_RGMII_ID:  	case PHY_INTERFACE_MODE_RGMII_TXID:  	case PHY_INTERFACE_MODE_RGMII_RXID: -		/* RGMII_ID needs internal delay. This is enabled through -		 * PORT5_PAD_CTRL for all ports, rather than individual port -		 * registers +		qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); + +		/* Configure rgmii delay */ +		qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); + +		/* QCA8337 requires to set rgmii rx delay for all ports. +		 * This is enabled through PORT5_PAD_CTRL for all ports, +		 * rather than individual port registers.  		 */ -		qca8k_write(priv, reg, -			    QCA8K_PORT_PAD_RGMII_EN | -			    QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) | -			    QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) | -			    QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | -			    QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); -		/* QCA8337 requires to set rgmii rx delay */  		if (priv->switch_id == QCA8K_ID_QCA8337)  			qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,  				    QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); @@ -1227,8 +1405,11 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,  		if (ret)  			return; -		val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | -			QCA8K_SGMII_EN_TX | QCA8K_SGMII_EN_SD; +		val |= QCA8K_SGMII_EN_SD; + +		if (priv->ports_config.sgmii_enable_pll) +			val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | +			       QCA8K_SGMII_EN_TX;  		if (dsa_is_cpu_port(ds, port)) {  			/* CPU port, we're talking to the CPU MAC, be a PHY */ @@ -1243,6 +1424,35 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,  		}  		qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); + +		/* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and +		 * falling edge is set writing in the PORT0 PAD reg +		 */ +		if (priv->switch_id == QCA8K_ID_QCA8327 || +		    priv->switch_id == QCA8K_ID_QCA8337) +			reg = QCA8K_REG_PORT0_PAD_CTRL; + +		val = 0; + +		/* SGMII Clock phase configuration */ +		if (priv->ports_config.sgmii_rx_clk_falling_edge) +			val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; + +		if (priv->ports_config.sgmii_tx_clk_falling_edge) +			val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; + +		if (val) +			ret = qca8k_rmw(priv, reg, +					QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | +					QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, +					val); + +		/* From original code is reported port instability as SGMII also +		 * require delay set. Apply advised values here or take them from DT. +		 */ +		if (state->interface == PHY_INTERFACE_MODE_SGMII) +			qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); +  		break;  	default:  		dev_err(ds->dev, "xMII mode %s not supported for port %d\n", @@ -1522,10 +1732,15 @@ static int  qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)  {  	struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -	int port_mask = BIT(QCA8K_CPU_PORT); +	int port_mask, cpu_port;  	int i, ret; -	for (i = 1; i < QCA8K_NUM_PORTS; i++) { +	cpu_port = dsa_to_port(ds, port)->cpu_dp->index; +	port_mask = BIT(cpu_port); + +	for (i = 0; i < QCA8K_NUM_PORTS; i++) { +		if (dsa_is_cpu_port(ds, i)) +			continue;  		if (dsa_to_port(ds, i)->bridge_dev != br)  			continue;  		/* Add this port to the portvlan mask of the other ports @@ -1551,9 +1766,13 @@ static void  qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br)  {  	struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -	int i; +	int cpu_port, i; -	for (i = 1; i < QCA8K_NUM_PORTS; i++) { +	cpu_port = dsa_to_port(ds, port)->cpu_dp->index; + +	for (i = 0; i < QCA8K_NUM_PORTS; i++) { +		if (dsa_is_cpu_port(ds, i)) +			continue;  		if (dsa_to_port(ds, i)->bridge_dev != br)  			continue;  		/* Remove this port to the portvlan mask of the other ports @@ -1568,7 +1787,7 @@ qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br)  	 * this port  	 */  	qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -		  QCA8K_PORT_LOOKUP_MEMBER, BIT(QCA8K_CPU_PORT)); +		  QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));  }  static int @@ -1939,7 +2158,12 @@ static int qca8k_resume(struct device *dev)  static SIMPLE_DEV_PM_OPS(qca8k_pm_ops,  			 qca8k_suspend, qca8k_resume); -static const struct qca8k_match_data qca832x = { +static const struct qca8k_match_data qca8327 = { +	.id = QCA8K_ID_QCA8327, +	.reduced_package = true, +}; + +static const struct qca8k_match_data qca8328 = {  	.id = QCA8K_ID_QCA8327,  }; @@ -1948,7 +2172,8 @@ static const struct qca8k_match_data qca833x = {  };  static const struct of_device_id qca8k_of_match[] = { -	{ .compatible = "qca,qca8327", .data = &qca832x }, +	{ .compatible = "qca,qca8327", .data = &qca8327 }, +	{ .compatible = "qca,qca8328", .data = &qca8328 },  	{ .compatible = "qca,qca8334", .data = &qca833x },  	{ .compatible = "qca,qca8337", .data = &qca833x },  	{ /* sentinel */ }, |