Commit a96c5515 authored by Tristram Ha's avatar Tristram Ha Committed by Jakub Kicinski
Browse files

net: dsa: microchip: Add KSZ8895/KSZ8864 switch support



KSZ8895/KSZ8864 is a switch family between KSZ8863/73 and KSZ8795, so it
shares some registers and functions in those switches already
implemented in the KSZ DSA driver.

Signed-off-by: default avatarTristram Ha <tristram.ha@microchip.com>
Tested-by: default avatarPieter Van Trappen <pieter.van.trappen@cern.ch>
Reviewed-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent e3717f2a
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -188,6 +188,8 @@ int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu)
	case KSZ8765_CHIP_ID:
		return ksz8795_change_mtu(dev, frame_size);
	case KSZ8830_CHIP_ID:
	case KSZ8864_CHIP_ID:
	case KSZ8895_CHIP_ID:
		return ksz8863_change_mtu(dev, frame_size);
	}

@@ -384,7 +386,7 @@ static void ksz8863_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
		    u64 *dropped, u64 *cnt)
{
	if (ksz_is_ksz88x3(dev))
	if (is_ksz88xx(dev))
		ksz8863_r_mib_pkt(dev, port, addr, dropped, cnt);
	else
		ksz8795_r_mib_pkt(dev, port, addr, dropped, cnt);
@@ -392,7 +394,7 @@ void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,

void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze)
{
	if (ksz_is_ksz88x3(dev))
	if (is_ksz88xx(dev))
		return;

	/* enable the port for flush/freeze function */
@@ -410,7 +412,8 @@ void ksz8_port_init_cnt(struct ksz_device *dev, int port)
	struct ksz_port_mib *mib = &dev->ports[port].mib;
	u64 *dropped;

	if (!ksz_is_ksz88x3(dev)) {
	/* For KSZ8795 family. */
	if (ksz_is_ksz87xx(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);
@@ -609,11 +612,11 @@ static int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr,
			shifts[STATIC_MAC_FWD_PORTS];
	alu->is_override = (data_hi & masks[STATIC_MAC_TABLE_OVERRIDE]) ? 1 : 0;

	/* KSZ8795 family switches have STATIC_MAC_TABLE_USE_FID and
	/* KSZ8795/KSZ8895 family switches have STATIC_MAC_TABLE_USE_FID and
	 * STATIC_MAC_TABLE_FID definitions off by 1 when doing read on the
	 * static MAC table compared to doing write.
	 */
	if (ksz_is_ksz87xx(dev))
	if (ksz_is_ksz87xx(dev) || ksz_is_8895_family(dev))
		data_hi >>= 1;
	alu->is_static = true;
	alu->is_use_fid = (data_hi & masks[STATIC_MAC_TABLE_USE_FID]) ? 1 : 0;
@@ -1692,7 +1695,8 @@ void ksz8_config_cpu_port(struct dsa_switch *ds)
	for (i = 0; i < dev->phy_port_cnt; i++) {
		p = &dev->ports[i];

		if (!ksz_is_ksz88x3(dev)) {
		/* For KSZ8795 family. */
		if (ksz_is_ksz87xx(dev)) {
			ksz_pread8(dev, i, regs[P_REMOTE_STATUS], &remote);
			if (remote & KSZ8_PORT_FIBER_MODE)
				p->fiber = 1;
+128 −6
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
/*
 * Microchip switch driver main logic
 *
 * Copyright (C) 2017-2019 Microchip Technology Inc.
 * Copyright (C) 2017-2024 Microchip Technology Inc.
 */

#include <linux/delay.h>
@@ -277,7 +277,7 @@ static const struct phylink_mac_ops ksz8_phylink_mac_ops = {
	.mac_link_up	= ksz8_phylink_mac_link_up,
};

static const struct ksz_dev_ops ksz88x3_dev_ops = {
static const struct ksz_dev_ops ksz88xx_dev_ops = {
	.setup = ksz8_setup,
	.get_port_addr = ksz8_get_port_addr,
	.cfg_port_member = ksz8_cfg_port_member,
@@ -572,6 +572,61 @@ static u8 ksz8863_shifts[] = {
	[DYNAMIC_MAC_SRC_PORT]		= 20,
};

static const u16 ksz8895_regs[] = {
	[REG_SW_MAC_ADDR]		= 0x68,
	[REG_IND_CTRL_0]		= 0x6E,
	[REG_IND_DATA_8]		= 0x70,
	[REG_IND_DATA_CHECK]		= 0x72,
	[REG_IND_DATA_HI]		= 0x71,
	[REG_IND_DATA_LO]		= 0x75,
	[REG_IND_MIB_CHECK]		= 0x75,
	[P_FORCE_CTRL]			= 0x0C,
	[P_LINK_STATUS]			= 0x0E,
	[P_LOCAL_CTRL]			= 0x0C,
	[P_NEG_RESTART_CTRL]		= 0x0D,
	[P_REMOTE_STATUS]		= 0x0E,
	[P_SPEED_STATUS]		= 0x09,
	[S_TAIL_TAG_CTRL]		= 0x0C,
	[P_STP_CTRL]			= 0x02,
	[S_START_CTRL]			= 0x01,
	[S_BROADCAST_CTRL]		= 0x06,
	[S_MULTICAST_CTRL]		= 0x04,
};

static const u32 ksz8895_masks[] = {
	[PORT_802_1P_REMAPPING]		= BIT(7),
	[SW_TAIL_TAG_ENABLE]		= BIT(1),
	[MIB_COUNTER_OVERFLOW]		= BIT(7),
	[MIB_COUNTER_VALID]		= BIT(6),
	[VLAN_TABLE_FID]		= GENMASK(6, 0),
	[VLAN_TABLE_MEMBERSHIP]		= GENMASK(11, 7),
	[VLAN_TABLE_VALID]		= BIT(12),
	[STATIC_MAC_TABLE_VALID]	= BIT(21),
	[STATIC_MAC_TABLE_USE_FID]	= BIT(23),
	[STATIC_MAC_TABLE_FID]		= GENMASK(30, 24),
	[STATIC_MAC_TABLE_OVERRIDE]	= BIT(22),
	[STATIC_MAC_TABLE_FWD_PORTS]	= GENMASK(20, 16),
	[DYNAMIC_MAC_TABLE_ENTRIES_H]	= GENMASK(6, 0),
	[DYNAMIC_MAC_TABLE_MAC_EMPTY]	= BIT(7),
	[DYNAMIC_MAC_TABLE_NOT_READY]	= BIT(7),
	[DYNAMIC_MAC_TABLE_ENTRIES]	= GENMASK(31, 29),
	[DYNAMIC_MAC_TABLE_FID]		= GENMASK(22, 16),
	[DYNAMIC_MAC_TABLE_SRC_PORT]	= GENMASK(26, 24),
	[DYNAMIC_MAC_TABLE_TIMESTAMP]	= GENMASK(28, 27),
};

static const u8 ksz8895_shifts[] = {
	[VLAN_TABLE_MEMBERSHIP_S]	= 7,
	[VLAN_TABLE]			= 13,
	[STATIC_MAC_FWD_PORTS]		= 16,
	[STATIC_MAC_FID]		= 24,
	[DYNAMIC_MAC_ENTRIES_H]		= 3,
	[DYNAMIC_MAC_ENTRIES]		= 29,
	[DYNAMIC_MAC_FID]		= 16,
	[DYNAMIC_MAC_TIMESTAMP]		= 27,
	[DYNAMIC_MAC_SRC_PORT]		= 24,
};

static const u16 ksz9477_regs[] = {
	[REG_SW_MAC_ADDR]		= 0x0302,
	[P_STP_CTRL]			= 0x0B04,
@@ -1397,7 +1452,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.port_cnt = 3,
		.num_tx_queues = 4,
		.num_ipms = 4,
		.ops = &ksz88x3_dev_ops,
		.ops = &ksz88xx_dev_ops,
		.phylink_mac_ops = &ksz8830_phylink_mac_ops,
		.mib_names = ksz88xx_mib_names,
		.mib_cnt = ARRAY_SIZE(ksz88xx_mib_names),
@@ -1412,6 +1467,61 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.rd_table = &ksz8873_register_set,
	},

	[KSZ8864] = {
		/* WARNING
		 * =======
		 * KSZ8864 is similar to KSZ8895, except the first port
		 * does not exist.
		 *           external  cpu
		 * KSZ8864   1,2,3      4
		 * KSZ8895   0,1,2,3    4
		 * port_cnt is configured as 5, even though it is 4
		 */
		.chip_id = KSZ8864_CHIP_ID,
		.dev_name = "KSZ8864",
		.num_vlans = 4096,
		.num_alus = 0,
		.num_statics = 32,
		.cpu_ports = 0x10,	/* can be configured as cpu port */
		.port_cnt = 5,		/* total cpu and user ports */
		.num_tx_queues = 4,
		.num_ipms = 4,
		.ops = &ksz88xx_dev_ops,
		.phylink_mac_ops = &ksz8830_phylink_mac_ops,
		.mib_names = ksz88xx_mib_names,
		.mib_cnt = ARRAY_SIZE(ksz88xx_mib_names),
		.reg_mib_cnt = MIB_COUNTER_NUM,
		.regs = ksz8895_regs,
		.masks = ksz8895_masks,
		.shifts = ksz8895_shifts,
		.supports_mii = {false, false, false, false, true},
		.supports_rmii = {false, false, false, false, true},
		.internal_phy = {false, true, true, true, false},
	},

	[KSZ8895] = {
		.chip_id = KSZ8895_CHIP_ID,
		.dev_name = "KSZ8895",
		.num_vlans = 4096,
		.num_alus = 0,
		.num_statics = 32,
		.cpu_ports = 0x10,	/* can be configured as cpu port */
		.port_cnt = 5,		/* total cpu and user ports */
		.num_tx_queues = 4,
		.num_ipms = 4,
		.ops = &ksz88xx_dev_ops,
		.phylink_mac_ops = &ksz8830_phylink_mac_ops,
		.mib_names = ksz88xx_mib_names,
		.mib_cnt = ARRAY_SIZE(ksz88xx_mib_names),
		.reg_mib_cnt = MIB_COUNTER_NUM,
		.regs = ksz8895_regs,
		.masks = ksz8895_masks,
		.shifts = ksz8895_shifts,
		.supports_mii = {false, false, false, false, true},
		.supports_rmii = {false, false, false, false, true},
		.internal_phy = {true, true, true, true, false},
	},

	[KSZ9477] = {
		.chip_id = KSZ9477_CHIP_ID,
		.dev_name = "KSZ9477",
@@ -2937,9 +3047,7 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds,
	struct ksz_device *dev = ds->priv;
	enum dsa_tag_protocol proto = DSA_TAG_PROTO_NONE;

	if (dev->chip_id == KSZ8795_CHIP_ID ||
	    dev->chip_id == KSZ8794_CHIP_ID ||
	    dev->chip_id == KSZ8765_CHIP_ID)
	if (ksz_is_ksz87xx(dev) || ksz_is_8895_family(dev))
		proto = DSA_TAG_PROTO_KSZ8795;

	if (dev->chip_id == KSZ8830_CHIP_ID ||
@@ -3055,6 +3163,8 @@ static int ksz_max_mtu(struct dsa_switch *ds, int port)
	case KSZ8765_CHIP_ID:
		return KSZ8795_HUGE_PACKET_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN;
	case KSZ8830_CHIP_ID:
	case KSZ8864_CHIP_ID:
	case KSZ8895_CHIP_ID:
		return KSZ8863_HUGE_PACKET_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN;
	case KSZ8563_CHIP_ID:
	case KSZ8567_CHIP_ID:
@@ -3412,6 +3522,18 @@ static int ksz_switch_detect(struct ksz_device *dev)
		else
			return -ENODEV;
		break;
	case KSZ8895_FAMILY_ID:
		if (id2 == KSZ8895_CHIP_ID_95 ||
		    id2 == KSZ8895_CHIP_ID_95R)
			dev->chip_id = KSZ8895_CHIP_ID;
		else
			return -ENODEV;
		ret = ksz_read8(dev, REG_KSZ8864_CHIP_ID, &id4);
		if (ret)
			return ret;
		if (id4 & SW_KSZ8864)
			dev->chip_id = KSZ8864_CHIP_ID;
		break;
	default:
		ret = ksz_read32(dev, REG_CHIP_ID0, &id32);
		if (ret)
+23 −2
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/* Microchip switch driver common header
 *
 * Copyright (C) 2017-2019 Microchip Technology Inc.
 * Copyright (C) 2017-2024 Microchip Technology Inc.
 */

#ifndef __KSZ_COMMON_H
@@ -201,6 +201,8 @@ enum ksz_model {
	KSZ8794,
	KSZ8765,
	KSZ8830,
	KSZ8864,
	KSZ8895,
	KSZ9477,
	KSZ9896,
	KSZ9897,
@@ -629,9 +631,21 @@ static inline bool ksz_is_ksz88x3(struct ksz_device *dev)
	return dev->chip_id == KSZ8830_CHIP_ID;
}

static inline bool ksz_is_8895_family(struct ksz_device *dev)
{
	return dev->chip_id == KSZ8895_CHIP_ID ||
	       dev->chip_id == KSZ8864_CHIP_ID;
}

static inline bool is_ksz8(struct ksz_device *dev)
{
	return ksz_is_ksz87xx(dev) || ksz_is_ksz88x3(dev);
	return ksz_is_ksz87xx(dev) || ksz_is_ksz88x3(dev) ||
	       ksz_is_8895_family(dev);
}

static inline bool is_ksz88xx(struct ksz_device *dev)
{
	return ksz_is_ksz88x3(dev) || ksz_is_8895_family(dev);
}

static inline bool is_ksz9477(struct ksz_device *dev)
@@ -665,6 +679,7 @@ static inline bool is_lan937x_tx_phy(struct ksz_device *dev, int port)
#define SW_FAMILY_ID_M			GENMASK(15, 8)
#define KSZ87_FAMILY_ID			0x87
#define KSZ88_FAMILY_ID			0x88
#define KSZ8895_FAMILY_ID		0x95

#define KSZ8_PORT_STATUS_0		0x08
#define KSZ8_PORT_FIBER_MODE		BIT(7)
@@ -673,6 +688,12 @@ static inline bool is_lan937x_tx_phy(struct ksz_device *dev, int port)
#define KSZ87_CHIP_ID_94		0x6
#define KSZ87_CHIP_ID_95		0x9
#define KSZ88_CHIP_ID_63		0x3
#define KSZ8895_CHIP_ID_95		0x4
#define KSZ8895_CHIP_ID_95R		0x6

/* KSZ8895 specific register */
#define REG_KSZ8864_CHIP_ID		0xFE
#define SW_KSZ8864			BIT(7)

#define SW_REV_ID_M			GENMASK(7, 4)

+1 −1
Original line number Diff line number Diff line
@@ -113,7 +113,7 @@ static void ksz_get_default_port_prio_reg(struct ksz_device *dev, int *reg,
static void ksz_get_dscp_prio_reg(struct ksz_device *dev, int *reg,
				  int *per_reg, u8 *mask)
{
	if (ksz_is_ksz87xx(dev)) {
	if (ksz_is_ksz87xx(dev) || ksz_is_8895_family(dev)) {
		*reg = KSZ8765_REG_TOS_DSCP_CTRL;
		*per_reg = 4;
		*mask = GENMASK(1, 0);
+14 −1
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
/*
 * Microchip ksz series register access through SPI
 *
 * Copyright (C) 2017 Microchip Technology Inc.
 * Copyright (C) 2017-2024 Microchip Technology Inc.
 *	Tristram Ha <Tristram.Ha@microchip.com>
 */

@@ -60,6 +60,9 @@ static int ksz_spi_probe(struct spi_device *spi)
		 chip->chip_id == KSZ8794_CHIP_ID ||
		 chip->chip_id == KSZ8765_CHIP_ID)
		regmap_config = ksz8795_regmap_config;
	else if (chip->chip_id == KSZ8895_CHIP_ID ||
		 chip->chip_id == KSZ8864_CHIP_ID)
		regmap_config = ksz8863_regmap_config;
	else
		regmap_config = ksz9477_regmap_config;

@@ -136,10 +139,18 @@ static const struct of_device_id ksz_dt_ids[] = {
		.compatible = "microchip,ksz8863",
		.data = &ksz_switch_chips[KSZ8830]
	},
	{
		.compatible = "microchip,ksz8864",
		.data = &ksz_switch_chips[KSZ8864]
	},
	{
		.compatible = "microchip,ksz8873",
		.data = &ksz_switch_chips[KSZ8830]
	},
	{
		.compatible = "microchip,ksz8895",
		.data = &ksz_switch_chips[KSZ8895]
	},
	{
		.compatible = "microchip,ksz9477",
		.data = &ksz_switch_chips[KSZ9477]
@@ -201,7 +212,9 @@ static const struct spi_device_id ksz_spi_ids[] = {
	{ "ksz8794" },
	{ "ksz8795" },
	{ "ksz8863" },
	{ "ksz8864" },
	{ "ksz8873" },
	{ "ksz8895" },
	{ "ksz9477" },
	{ "ksz9896" },
	{ "ksz9897" },
Loading