net: dsa: microchip: ksz8795: add support for ksz88xx chips
We add support for the ksz8863 and ksz8873 chips which are using the same register patterns but other offsets as the ksz8795. Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									9f73e11250
								
							
						
					
					
						commit
						4b20a07e10
					
				| @ -72,9 +72,60 @@ static const u8 ksz8795_shifts[] = { | ||||
| 	[DYNAMIC_MAC_SRC_PORT]		= 24, | ||||
| }; | ||||
| 
 | ||||
| static const struct { | ||||
| static const u8 ksz8863_regs[] = { | ||||
| 	[REG_IND_CTRL_0]		= 0x79, | ||||
| 	[REG_IND_DATA_8]		= 0x7B, | ||||
| 	[REG_IND_DATA_CHECK]		= 0x7B, | ||||
| 	[REG_IND_DATA_HI]		= 0x7C, | ||||
| 	[REG_IND_DATA_LO]		= 0x80, | ||||
| 	[REG_IND_MIB_CHECK]		= 0x80, | ||||
| 	[P_FORCE_CTRL]			= 0x0C, | ||||
| 	[P_LINK_STATUS]			= 0x0E, | ||||
| 	[P_LOCAL_CTRL]			= 0x0C, | ||||
| 	[P_NEG_RESTART_CTRL]		= 0x0D, | ||||
| 	[P_REMOTE_STATUS]		= 0x0E, | ||||
| 	[P_SPEED_STATUS]		= 0x0F, | ||||
| 	[S_TAIL_TAG_CTRL]		= 0x03, | ||||
| }; | ||||
| 
 | ||||
| static const u32 ksz8863_masks[] = { | ||||
| 	[PORT_802_1P_REMAPPING]		= BIT(3), | ||||
| 	[SW_TAIL_TAG_ENABLE]		= BIT(6), | ||||
| 	[MIB_COUNTER_OVERFLOW]		= BIT(7), | ||||
| 	[MIB_COUNTER_VALID]		= BIT(6), | ||||
| 	[VLAN_TABLE_FID]		= GENMASK(15, 12), | ||||
| 	[VLAN_TABLE_MEMBERSHIP]		= GENMASK(18, 16), | ||||
| 	[VLAN_TABLE_VALID]		= BIT(19), | ||||
| 	[STATIC_MAC_TABLE_VALID]	= BIT(19), | ||||
| 	[STATIC_MAC_TABLE_USE_FID]	= BIT(21), | ||||
| 	[STATIC_MAC_TABLE_FID]		= GENMASK(29, 26), | ||||
| 	[STATIC_MAC_TABLE_OVERRIDE]	= BIT(20), | ||||
| 	[STATIC_MAC_TABLE_FWD_PORTS]	= GENMASK(18, 16), | ||||
| 	[DYNAMIC_MAC_TABLE_ENTRIES_H]	= GENMASK(5, 0), | ||||
| 	[DYNAMIC_MAC_TABLE_MAC_EMPTY]	= BIT(7), | ||||
| 	[DYNAMIC_MAC_TABLE_NOT_READY]	= BIT(7), | ||||
| 	[DYNAMIC_MAC_TABLE_ENTRIES]	= GENMASK(31, 28), | ||||
| 	[DYNAMIC_MAC_TABLE_FID]		= GENMASK(19, 16), | ||||
| 	[DYNAMIC_MAC_TABLE_SRC_PORT]	= GENMASK(21, 20), | ||||
| 	[DYNAMIC_MAC_TABLE_TIMESTAMP]	= GENMASK(23, 22), | ||||
| }; | ||||
| 
 | ||||
| static u8 ksz8863_shifts[] = { | ||||
| 	[VLAN_TABLE_MEMBERSHIP_S]	= 16, | ||||
| 	[STATIC_MAC_FWD_PORTS]		= 16, | ||||
| 	[STATIC_MAC_FID]		= 22, | ||||
| 	[DYNAMIC_MAC_ENTRIES_H]		= 3, | ||||
| 	[DYNAMIC_MAC_ENTRIES]		= 24, | ||||
| 	[DYNAMIC_MAC_FID]		= 16, | ||||
| 	[DYNAMIC_MAC_TIMESTAMP]		= 24, | ||||
| 	[DYNAMIC_MAC_SRC_PORT]		= 20, | ||||
| }; | ||||
| 
 | ||||
| struct mib_names { | ||||
| 	char string[ETH_GSTRING_LEN]; | ||||
| } mib_names[] = { | ||||
| }; | ||||
| 
 | ||||
| static const struct mib_names ksz87xx_mib_names[] = { | ||||
| 	{ "rx_hi" }, | ||||
| 	{ "rx_undersize" }, | ||||
| 	{ "rx_fragments" }, | ||||
| @ -113,6 +164,48 @@ static const struct { | ||||
| 	{ "tx_discards" }, | ||||
| }; | ||||
| 
 | ||||
| static const struct mib_names ksz88xx_mib_names[] = { | ||||
| 	{ "rx" }, | ||||
| 	{ "rx_hi" }, | ||||
| 	{ "rx_undersize" }, | ||||
| 	{ "rx_fragments" }, | ||||
| 	{ "rx_oversize" }, | ||||
| 	{ "rx_jabbers" }, | ||||
| 	{ "rx_symbol_err" }, | ||||
| 	{ "rx_crc_err" }, | ||||
| 	{ "rx_align_err" }, | ||||
| 	{ "rx_mac_ctrl" }, | ||||
| 	{ "rx_pause" }, | ||||
| 	{ "rx_bcast" }, | ||||
| 	{ "rx_mcast" }, | ||||
| 	{ "rx_ucast" }, | ||||
| 	{ "rx_64_or_less" }, | ||||
| 	{ "rx_65_127" }, | ||||
| 	{ "rx_128_255" }, | ||||
| 	{ "rx_256_511" }, | ||||
| 	{ "rx_512_1023" }, | ||||
| 	{ "rx_1024_1522" }, | ||||
| 	{ "tx" }, | ||||
| 	{ "tx_hi" }, | ||||
| 	{ "tx_late_col" }, | ||||
| 	{ "tx_pause" }, | ||||
| 	{ "tx_bcast" }, | ||||
| 	{ "tx_mcast" }, | ||||
| 	{ "tx_ucast" }, | ||||
| 	{ "tx_deferred" }, | ||||
| 	{ "tx_total_col" }, | ||||
| 	{ "tx_exc_col" }, | ||||
| 	{ "tx_single_col" }, | ||||
| 	{ "tx_mult_col" }, | ||||
| 	{ "rx_discards" }, | ||||
| 	{ "tx_discards" }, | ||||
| }; | ||||
| 
 | ||||
| static bool ksz_is_ksz88x3(struct ksz_device *dev) | ||||
| { | ||||
| 	return dev->chip_id == 0x8830; | ||||
| } | ||||
| 
 | ||||
| static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) | ||||
| { | ||||
| 	regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); | ||||
| @ -127,10 +220,18 @@ static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, | ||||
| 
 | ||||
| static int ksz8_reset_switch(struct ksz_device *dev) | ||||
| { | ||||
| 	/* reset switch */ | ||||
| 	ksz_write8(dev, REG_POWER_MANAGEMENT_1, | ||||
| 		   SW_SOFTWARE_POWER_DOWN << SW_POWER_MANAGEMENT_MODE_S); | ||||
| 	ksz_write8(dev, REG_POWER_MANAGEMENT_1, 0); | ||||
| 	if (ksz_is_ksz88x3(dev)) { | ||||
| 		/* reset switch */ | ||||
| 		ksz_cfg(dev, KSZ8863_REG_SW_RESET, | ||||
| 			KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, true); | ||||
| 		ksz_cfg(dev, KSZ8863_REG_SW_RESET, | ||||
| 			KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, false); | ||||
| 	} else { | ||||
| 		/* reset switch */ | ||||
| 		ksz_write8(dev, REG_POWER_MANAGEMENT_1, | ||||
| 			   SW_SOFTWARE_POWER_DOWN << SW_POWER_MANAGEMENT_MODE_S); | ||||
| 		ksz_write8(dev, REG_POWER_MANAGEMENT_1, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @ -204,8 +305,8 @@ static void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt) | ||||
| 	mutex_unlock(&dev->alu_mutex); | ||||
| } | ||||
| 
 | ||||
| static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, | ||||
| 			   u64 *dropped, u64 *cnt) | ||||
| static void ksz8795_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, | ||||
| 			      u64 *dropped, u64 *cnt) | ||||
| { | ||||
| 	struct ksz8 *ksz8 = dev->priv; | ||||
| 	const u32 *masks; | ||||
| @ -219,8 +320,8 @@ static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, | ||||
| 	regs = ksz8->regs; | ||||
| 
 | ||||
| 	addr -= dev->reg_mib_cnt; | ||||
| 	ctrl_addr = (KS_MIB_TOTAL_RX_1 - KS_MIB_TOTAL_RX_0) * port; | ||||
| 	ctrl_addr += addr + KS_MIB_TOTAL_RX_0; | ||||
| 	ctrl_addr = (KSZ8795_MIB_TOTAL_RX_1 - KSZ8795_MIB_TOTAL_RX_0) * port; | ||||
| 	ctrl_addr += addr + KSZ8795_MIB_TOTAL_RX_0; | ||||
| 	ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ); | ||||
| 
 | ||||
| 	mutex_lock(&dev->alu_mutex); | ||||
| @ -257,8 +358,52 @@ static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, | ||||
| 	mutex_unlock(&dev->alu_mutex); | ||||
| } | ||||
| 
 | ||||
| static void ksz8863_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, | ||||
| 			      u64 *dropped, u64 *cnt) | ||||
| { | ||||
| 	struct ksz8 *ksz8 = dev->priv; | ||||
| 	const u8 *regs = ksz8->regs; | ||||
| 	u32 *last = (u32 *)dropped; | ||||
| 	u16 ctrl_addr; | ||||
| 	u32 data; | ||||
| 	u32 cur; | ||||
| 
 | ||||
| 	addr -= dev->reg_mib_cnt; | ||||
| 	ctrl_addr = addr ? KSZ8863_MIB_PACKET_DROPPED_TX_0 : | ||||
| 			   KSZ8863_MIB_PACKET_DROPPED_RX_0; | ||||
| 	ctrl_addr += port; | ||||
| 	ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ); | ||||
| 
 | ||||
| 	mutex_lock(&dev->alu_mutex); | ||||
| 	ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr); | ||||
| 	ksz_read32(dev, regs[REG_IND_DATA_LO], &data); | ||||
| 	mutex_unlock(&dev->alu_mutex); | ||||
| 
 | ||||
| 	data &= MIB_PACKET_DROPPED; | ||||
| 	cur = last[addr]; | ||||
| 	if (data != cur) { | ||||
| 		last[addr] = data; | ||||
| 		if (data < cur) | ||||
| 			data += MIB_PACKET_DROPPED + 1; | ||||
| 		data -= cur; | ||||
| 		*cnt += data; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, | ||||
| 			   u64 *dropped, u64 *cnt) | ||||
| { | ||||
| 	if (ksz_is_ksz88x3(dev)) | ||||
| 		ksz8863_r_mib_pkt(dev, port, addr, dropped, cnt); | ||||
| 	else | ||||
| 		ksz8795_r_mib_pkt(dev, port, addr, dropped, cnt); | ||||
| } | ||||
| 
 | ||||
| static void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze) | ||||
| { | ||||
| 	if (ksz_is_ksz88x3(dev)) | ||||
| 		return; | ||||
| 
 | ||||
| 	/* enable the port for flush/freeze function */ | ||||
| 	if (freeze) | ||||
| 		ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true); | ||||
| @ -272,11 +417,14 @@ static void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze) | ||||
| static void ksz8_port_init_cnt(struct ksz_device *dev, int port) | ||||
| { | ||||
| 	struct ksz_port_mib *mib = &dev->ports[port].mib; | ||||
| 	u64 *dropped; | ||||
| 
 | ||||
| 	/* flush all enabled port MIB counters */ | ||||
| 	ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true); | ||||
| 	ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FLUSH, true); | ||||
| 	ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false); | ||||
| 	if (!ksz_is_ksz88x3(dev)) { | ||||
| 		/* flush all enabled port MIB counters */ | ||||
| 		ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true); | ||||
| 		ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FLUSH, true); | ||||
| 		ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false); | ||||
| 	} | ||||
| 
 | ||||
| 	mib->cnt_ptr = 0; | ||||
| 
 | ||||
| @ -287,10 +435,13 @@ static void ksz8_port_init_cnt(struct ksz_device *dev, int port) | ||||
| 		++mib->cnt_ptr; | ||||
| 	} | ||||
| 
 | ||||
| 	/* last one in storage */ | ||||
| 	dropped = &mib->counters[dev->mib_cnt]; | ||||
| 
 | ||||
| 	/* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */ | ||||
| 	while (mib->cnt_ptr < dev->mib_cnt) { | ||||
| 		dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr, | ||||
| 					NULL, &mib->counters[mib->cnt_ptr]); | ||||
| 					dropped, &mib->counters[mib->cnt_ptr]); | ||||
| 		++mib->cnt_ptr; | ||||
| 	} | ||||
| 	mib->cnt_ptr = 0; | ||||
| @ -588,8 +739,13 @@ static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) | ||||
| 			data |= PHY_LOOPBACK; | ||||
| 		if (ctrl & PORT_FORCE_100_MBIT) | ||||
| 			data |= PHY_SPEED_100MBIT; | ||||
| 		if (!(ctrl & PORT_AUTO_NEG_DISABLE)) | ||||
| 			data |= PHY_AUTO_NEG_ENABLE; | ||||
| 		if (ksz_is_ksz88x3(dev)) { | ||||
| 			if ((ctrl & PORT_AUTO_NEG_ENABLE)) | ||||
| 				data |= PHY_AUTO_NEG_ENABLE; | ||||
| 		} else { | ||||
| 			if (!(ctrl & PORT_AUTO_NEG_DISABLE)) | ||||
| 				data |= PHY_AUTO_NEG_ENABLE; | ||||
| 		} | ||||
| 		if (restart & PORT_POWER_DOWN) | ||||
| 			data |= PHY_POWER_DOWN; | ||||
| 		if (restart & PORT_AUTO_NEG_RESTART) | ||||
| @ -623,7 +779,10 @@ static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) | ||||
| 		data = KSZ8795_ID_HI; | ||||
| 		break; | ||||
| 	case PHY_REG_ID_2: | ||||
| 		data = KSZ8795_ID_LO; | ||||
| 		if (ksz_is_ksz88x3(dev)) | ||||
| 			data = KSZ8863_ID_LO; | ||||
| 		else | ||||
| 			data = KSZ8795_ID_LO; | ||||
| 		break; | ||||
| 	case PHY_REG_AUTO_NEGOTIATION: | ||||
| 		ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl); | ||||
| @ -686,14 +845,22 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) | ||||
| 			ksz_pwrite8(dev, p, regs[P_SPEED_STATUS], data); | ||||
| 		ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); | ||||
| 		data = ctrl; | ||||
| 		if (!(val & PHY_AUTO_NEG_ENABLE)) | ||||
| 			data |= PORT_AUTO_NEG_DISABLE; | ||||
| 		else | ||||
| 			data &= ~PORT_AUTO_NEG_DISABLE; | ||||
| 		if (ksz_is_ksz88x3(dev)) { | ||||
| 			if ((val & PHY_AUTO_NEG_ENABLE)) | ||||
| 				data |= PORT_AUTO_NEG_ENABLE; | ||||
| 			else | ||||
| 				data &= ~PORT_AUTO_NEG_ENABLE; | ||||
| 		} else { | ||||
| 			if (!(val & PHY_AUTO_NEG_ENABLE)) | ||||
| 				data |= PORT_AUTO_NEG_DISABLE; | ||||
| 			else | ||||
| 				data &= ~PORT_AUTO_NEG_DISABLE; | ||||
| 
 | ||||
| 			/* Fiber port does not support auto-negotiation. */ | ||||
| 			if (dev->ports[p].fiber) | ||||
| 				data |= PORT_AUTO_NEG_DISABLE; | ||||
| 		} | ||||
| 
 | ||||
| 		/* Fiber port does not support auto-negotiation. */ | ||||
| 		if (dev->ports[p].fiber) | ||||
| 			data |= PORT_AUTO_NEG_DISABLE; | ||||
| 		if (val & PHY_SPEED_100MBIT) | ||||
| 			data |= PORT_FORCE_100_MBIT; | ||||
| 		else | ||||
| @ -767,7 +934,11 @@ static enum dsa_tag_protocol ksz8_get_tag_protocol(struct dsa_switch *ds, | ||||
| 						   int port, | ||||
| 						   enum dsa_tag_protocol mp) | ||||
| { | ||||
| 	return DSA_TAG_PROTO_KSZ8795; | ||||
| 	struct ksz_device *dev = ds->priv; | ||||
| 
 | ||||
| 	/* ksz88x3 uses the same tag schema as KSZ9893 */ | ||||
| 	return ksz_is_ksz88x3(dev) ? | ||||
| 		DSA_TAG_PROTO_KSZ9893 : DSA_TAG_PROTO_KSZ8795; | ||||
| } | ||||
| 
 | ||||
| static void ksz8_get_strings(struct dsa_switch *ds, int port, | ||||
| @ -777,8 +948,8 @@ static void ksz8_get_strings(struct dsa_switch *ds, int port, | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < dev->mib_cnt; i++) { | ||||
| 		memcpy(buf + i * ETH_GSTRING_LEN, mib_names[i].string, | ||||
| 		       ETH_GSTRING_LEN); | ||||
| 		memcpy(buf + i * ETH_GSTRING_LEN, | ||||
| 		       dev->mib_names[i].string, ETH_GSTRING_LEN); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -904,6 +1075,9 @@ static int ksz8_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag, | ||||
| { | ||||
| 	struct ksz_device *dev = ds->priv; | ||||
| 
 | ||||
| 	if (ksz_is_ksz88x3(dev)) | ||||
| 		return -ENOTSUPP; | ||||
| 
 | ||||
| 	ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag); | ||||
| 
 | ||||
| 	return 0; | ||||
| @ -918,6 +1092,9 @@ static int ksz8_port_vlan_add(struct dsa_switch *ds, int port, | ||||
| 	u16 data, new_pvid = 0; | ||||
| 	u8 fid, member, valid; | ||||
| 
 | ||||
| 	if (ksz_is_ksz88x3(dev)) | ||||
| 		return -ENOTSUPP; | ||||
| 
 | ||||
| 	ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged); | ||||
| 
 | ||||
| 	ksz8_r_vlan_table(dev, vlan->vid, &data); | ||||
| @ -958,6 +1135,9 @@ static int ksz8_port_vlan_del(struct dsa_switch *ds, int port, | ||||
| 	u16 data, pvid, new_pvid = 0; | ||||
| 	u8 fid, member, valid; | ||||
| 
 | ||||
| 	if (ksz_is_ksz88x3(dev)) | ||||
| 		return -ENOTSUPP; | ||||
| 
 | ||||
| 	ksz_pread16(dev, port, REG_PORT_CTRL_VID, &pvid); | ||||
| 	pvid = pvid & 0xFFF; | ||||
| 
 | ||||
| @ -1091,7 +1271,8 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port) | ||||
| 	/* enable broadcast storm limit */ | ||||
| 	ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true); | ||||
| 
 | ||||
| 	ksz8795_set_prio_queue(dev, port, 4); | ||||
| 	if (!ksz_is_ksz88x3(dev)) | ||||
| 		ksz8795_set_prio_queue(dev, port, 4); | ||||
| 
 | ||||
| 	/* disable DiffServ priority */ | ||||
| 	ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_ENABLE, false); | ||||
| @ -1104,7 +1285,8 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port) | ||||
| 	ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_ENABLE, true); | ||||
| 
 | ||||
| 	if (cpu_port) { | ||||
| 		ksz8795_cpu_interface_select(dev, port); | ||||
| 		if (!ksz_is_ksz88x3(dev)) | ||||
| 			ksz8795_cpu_interface_select(dev, port); | ||||
| 
 | ||||
| 		member = dev->port_mask; | ||||
| 	} else { | ||||
| @ -1156,9 +1338,11 @@ static void ksz8_config_cpu_port(struct dsa_switch *ds) | ||||
| 		p = &dev->ports[i]; | ||||
| 		if (!p->on) | ||||
| 			continue; | ||||
| 		ksz_pread8(dev, i, regs[P_REMOTE_STATUS], &remote); | ||||
| 		if (remote & PORT_FIBER_MODE) | ||||
| 			p->fiber = 1; | ||||
| 		if (!ksz_is_ksz88x3(dev)) { | ||||
| 			ksz_pread8(dev, i, regs[P_REMOTE_STATUS], &remote); | ||||
| 			if (remote & PORT_FIBER_MODE) | ||||
| 				p->fiber = 1; | ||||
| 		} | ||||
| 		if (p->fiber) | ||||
| 			ksz_port_cfg(dev, i, P_STP_CTRL, PORT_FORCE_FLOW_CTRL, | ||||
| 				     true); | ||||
| @ -1277,19 +1461,30 @@ static int ksz8_switch_detect(struct ksz_device *dev) | ||||
| 
 | ||||
| 	id1 = id16 >> 8; | ||||
| 	id2 = id16 & SW_CHIP_ID_M; | ||||
| 	if (id1 != FAMILY_ID || | ||||
| 	    (id2 != CHIP_ID_94 && id2 != CHIP_ID_95)) | ||||
| 
 | ||||
| 	switch (id1) { | ||||
| 	case KSZ87_FAMILY_ID: | ||||
| 		if ((id2 != CHIP_ID_94 && id2 != CHIP_ID_95)) | ||||
| 			return -ENODEV; | ||||
| 
 | ||||
| 		if (id2 == CHIP_ID_95) { | ||||
| 			u8 val; | ||||
| 
 | ||||
| 			id2 = 0x95; | ||||
| 			ksz_read8(dev, REG_PORT_STATUS_0, &val); | ||||
| 			if (val & PORT_FIBER_MODE) | ||||
| 				id2 = 0x65; | ||||
| 		} else if (id2 == CHIP_ID_94) { | ||||
| 			id2 = 0x94; | ||||
| 		} | ||||
| 		break; | ||||
| 	case KSZ88_FAMILY_ID: | ||||
| 		if (id2 != CHIP_ID_63) | ||||
| 			return -ENODEV; | ||||
| 		break; | ||||
| 	default: | ||||
| 		dev_err(dev->dev, "invalid family id: %d\n", id1); | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	if (id2 == CHIP_ID_95) { | ||||
| 		u8 val; | ||||
| 
 | ||||
| 		id2 = 0x95; | ||||
| 		ksz_read8(dev, REG_PORT_1_STATUS_0, &val); | ||||
| 		if (val & PORT_FIBER_MODE) | ||||
| 			id2 = 0x65; | ||||
| 	} else if (id2 == CHIP_ID_94) { | ||||
| 		id2 = 0x94; | ||||
| 	} | ||||
| 	id16 &= ~0xff; | ||||
| 	id16 |= id2; | ||||
| @ -1350,6 +1545,15 @@ static const struct ksz_chip_data ksz8_switch_chips[] = { | ||||
| 		.cpu_ports = 0x10,	/* can be configured as cpu port */ | ||||
| 		.port_cnt = 5,		/* total cpu and user ports */ | ||||
| 	}, | ||||
| 	{ | ||||
| 		.chip_id = 0x8830, | ||||
| 		.dev_name = "KSZ8863/KSZ8873", | ||||
| 		.num_vlans = 16, | ||||
| 		.num_alus = 0, | ||||
| 		.num_statics = 8, | ||||
| 		.cpu_ports = 0x4,	/* can be configured as cpu port */ | ||||
| 		.port_cnt = 3, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static int ksz8_switch_init(struct ksz_device *dev) | ||||
| @ -1382,12 +1586,21 @@ static int ksz8_switch_init(struct ksz_device *dev) | ||||
| 	if (!dev->cpu_ports) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	ksz8->regs = ksz8795_regs; | ||||
| 	ksz8->masks = ksz8795_masks; | ||||
| 	ksz8->shifts = ksz8795_shifts; | ||||
| 	if (ksz_is_ksz88x3(dev)) { | ||||
| 		ksz8->regs = ksz8863_regs; | ||||
| 		ksz8->masks = ksz8863_masks; | ||||
| 		ksz8->shifts = ksz8863_shifts; | ||||
| 		dev->mib_cnt = ARRAY_SIZE(ksz88xx_mib_names); | ||||
| 		dev->mib_names = ksz88xx_mib_names; | ||||
| 	} else { | ||||
| 		ksz8->regs = ksz8795_regs; | ||||
| 		ksz8->masks = ksz8795_masks; | ||||
| 		ksz8->shifts = ksz8795_shifts; | ||||
| 		dev->mib_cnt = ARRAY_SIZE(ksz87xx_mib_names); | ||||
| 		dev->mib_names = ksz87xx_mib_names; | ||||
| 	} | ||||
| 
 | ||||
| 	dev->reg_mib_cnt = KSZ8795_COUNTER_NUM; | ||||
| 	dev->mib_cnt = ARRAY_SIZE(mib_names); | ||||
| 	dev->reg_mib_cnt = MIB_COUNTER_NUM; | ||||
| 
 | ||||
| 	dev->ports = devm_kzalloc(dev->dev, | ||||
| 				  dev->port_cnt * sizeof(struct ksz_port), | ||||
|  | ||||
| @ -16,7 +16,8 @@ | ||||
| 
 | ||||
| #define REG_CHIP_ID0			0x00 | ||||
| 
 | ||||
| #define FAMILY_ID			0x87 | ||||
| #define KSZ87_FAMILY_ID			0x87 | ||||
| #define KSZ88_FAMILY_ID			0x88 | ||||
| 
 | ||||
| #define REG_CHIP_ID1			0x01 | ||||
| 
 | ||||
| @ -28,6 +29,12 @@ | ||||
| 
 | ||||
| #define CHIP_ID_94			0x60 | ||||
| #define CHIP_ID_95			0x90 | ||||
| #define CHIP_ID_63			0x30 | ||||
| 
 | ||||
| #define KSZ8863_REG_SW_RESET		0x43 | ||||
| 
 | ||||
| #define KSZ8863_GLOBAL_SOFTWARE_RESET	BIT(4) | ||||
| #define KSZ8863_PCS_RESET		BIT(0) | ||||
| 
 | ||||
| #define REG_SW_CTRL_0			0x02 | ||||
| 
 | ||||
| @ -267,6 +274,7 @@ | ||||
| #define REG_PORT_3_CTRL_9		0x3C | ||||
| #define REG_PORT_4_CTRL_9		0x4C | ||||
| 
 | ||||
| #define PORT_AUTO_NEG_ENABLE		BIT(7) | ||||
| #define PORT_AUTO_NEG_DISABLE		BIT(7) | ||||
| #define PORT_FORCE_100_MBIT		BIT(6) | ||||
| #define PORT_FORCE_FULL_DUPLEX		BIT(5) | ||||
| @ -800,6 +808,7 @@ | ||||
| 
 | ||||
| #define KSZ8795_ID_HI			0x0022 | ||||
| #define KSZ8795_ID_LO			0x1550 | ||||
| #define KSZ8863_ID_LO			0x1430 | ||||
| 
 | ||||
| #define KSZ8795_SW_ID			0x8795 | ||||
| 
 | ||||
| @ -830,7 +839,7 @@ | ||||
| 
 | ||||
| #define KS_PRIO_IN_REG			4 | ||||
| 
 | ||||
| #define KSZ8795_COUNTER_NUM		0x20 | ||||
| #define MIB_COUNTER_NUM		0x20 | ||||
| 
 | ||||
| /* Common names used by other drivers */ | ||||
| 
 | ||||
| @ -876,26 +885,13 @@ | ||||
| 
 | ||||
| #define MIB_COUNTER_VALUE		0x3FFFFFFF | ||||
| 
 | ||||
| #define KS_MIB_TOTAL_RX_0		0x100 | ||||
| #define KS_MIB_TOTAL_TX_0		0x101 | ||||
| #define KS_MIB_PACKET_DROPPED_RX_0	0x102 | ||||
| #define KS_MIB_PACKET_DROPPED_TX_0	0x103 | ||||
| #define KS_MIB_TOTAL_RX_1		0x104 | ||||
| #define KS_MIB_TOTAL_TX_1		0x105 | ||||
| #define KS_MIB_PACKET_DROPPED_TX_1	0x106 | ||||
| #define KS_MIB_PACKET_DROPPED_RX_1	0x107 | ||||
| #define KS_MIB_TOTAL_RX_2		0x108 | ||||
| #define KS_MIB_TOTAL_TX_2		0x109 | ||||
| #define KS_MIB_PACKET_DROPPED_TX_2	0x10A | ||||
| #define KS_MIB_PACKET_DROPPED_RX_2	0x10B | ||||
| #define KS_MIB_TOTAL_RX_3		0x10C | ||||
| #define KS_MIB_TOTAL_TX_3		0x10D | ||||
| #define KS_MIB_PACKET_DROPPED_TX_3	0x10E | ||||
| #define KS_MIB_PACKET_DROPPED_RX_3	0x10F | ||||
| #define KS_MIB_TOTAL_RX_4		0x110 | ||||
| #define KS_MIB_TOTAL_TX_4		0x111 | ||||
| #define KS_MIB_PACKET_DROPPED_TX_4	0x112 | ||||
| #define KS_MIB_PACKET_DROPPED_RX_4	0x113 | ||||
| #define KSZ8795_MIB_TOTAL_RX_0		0x100 | ||||
| #define KSZ8795_MIB_TOTAL_TX_0		0x101 | ||||
| #define KSZ8795_MIB_TOTAL_RX_1		0x104 | ||||
| #define KSZ8795_MIB_TOTAL_TX_1		0x105 | ||||
| 
 | ||||
| #define KSZ8863_MIB_PACKET_DROPPED_TX_0 0x100 | ||||
| #define KSZ8863_MIB_PACKET_DROPPED_RX_0 0x105 | ||||
| 
 | ||||
| #define MIB_PACKET_DROPPED		0x0000FFFF | ||||
| 
 | ||||
|  | ||||
| @ -71,6 +71,7 @@ struct ksz_device { | ||||
| 	int port_cnt; | ||||
| 	int reg_mib_cnt; | ||||
| 	int mib_cnt; | ||||
| 	const struct mib_names *mib_names; | ||||
| 	phy_interface_t compat_interface; | ||||
| 	u32 regs_size; | ||||
| 	bool phy_errata_9477; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user