Commit 12ad8f0f authored by Aleksandr Senin's avatar Aleksandr Senin Committed by Benjamin Cabé
Browse files

drivers: eth: dsa_ksz8xxx: Add support for KSZ8463/KSZ8463F



This commit adds basic support for KSZ8463/KSZ8463F chips to the
dsa_ksz8xxx.c driver.

These chips have limited register compatibility with other members
of the KSZ8XXX family - their registers are 16 bits wide as opposed
to the 8-bit registers supported by the driver for KSZ8794 and
KSZ8863. Following the general logic of the existing code,
the 16-bit registers of KSZ8463 are split into 8-bit halves.

For the KSZ8463F chip, it is assumed that both ports are used
in Fiber mode.

A new configuration option, CONFIG_DSA_KSZ_PORT_ISOLATING, has been
added to isolate traffic between DSA slave ports.

The driver has been tested on a custom board with an STM32F7 SoC.

Signed-off-by: default avatarAleksandr Senin <al@meshium.net>
parent 907261b6
Loading
Loading
Loading
Loading
+18 −3
Original line number Diff line number Diff line
@@ -39,23 +39,38 @@ config DSA_KSZ8863
	help
	  Add support for KSZ8863 DSA device driver.

config DSA_KSZ8463
	bool "Support for KSZ8463"
	default y
	depends on DT_HAS_MICROCHIP_KSZ8463_ENABLED
	select DSA_KSZ8XXX
	select SPI if $(dt_compat_on_bus,$(DT_COMPAT_MICROCHIP_KSZ8463),spi)
	help
	  Add support for KSZ8463 DSA device driver.

config DSA_KSZ_TAIL_TAGGING
	bool "Support for tail tagging"
	depends on DSA_KSZ8794 || DSA_KSZ8863
	depends on DSA_KSZ8794 || DSA_KSZ8863 || DSA_KSZ8463
	help
	  Add support for tail tagging on DSA device.

config DSA_TAG_SIZE
	int "DSA tag size in bytes"
	default 1 if DSA_KSZ8794 || DSA_KSZ8863
	default 1 if DSA_KSZ8794 || DSA_KSZ8863 || DSA_KSZ8463
	default 0
	depends on DSA_KSZ_TAIL_TAGGING
	help
	  Set the DSA tag length in bytes.

config DSA_KSZ_PORT_ISOLATING
	bool "Support for ports isolating"
	depends on DSA_KSZ8794 || DSA_KSZ8863 || DSA_KSZ8463
	help
	  Add support for traffic isolation on DSA slave ports

config DSA_SPI
	bool "Support for PHY SPI interface"
	depends on SPI && (DSA_KSZ8794 || DSA_KSZ8863)
	depends on SPI && (DSA_KSZ8794 || DSA_KSZ8863 || DSA_KSZ8463)
	help
	  Use SPI bus to communicate with PHY

+131 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2023 Meshium
 *               Aleksandr Senin <al@meshium.net>
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef __DSA_KSZ8463_H__
#define __DSA_KSZ8463_H__

/* SPI commands */
#define KSZ8463_SPI_CMD_WR (BIT(7))
#define KSZ8463_SPI_CMD_RD (0)

#define KSZ8463_REG_ADDR_HI_PART(x)	(((x) & 0x7FF) >> 4)
#define KSZ8463_REG_ADDR_LO_PART(x)	(((x) & 0x00C) << 4)
#define KSZ8463_SPI_BYTE_ENABLE(x)	(BIT(((x) & 0x3) + 2))

/* PHY registers */
#define KSZ8463_BMCR                                 0x00
#define KSZ8463_BMSR                                 0x01
#define KSZ8463_PHYID1                               0x02
#define KSZ8463_PHYID2                               0x03
#define KSZ8463_ANAR                                 0x04
#define KSZ8463_ANLPAR                               0x05
#define KSZ8463_LINKMD                               0x1D
#define KSZ8463_PHYSCS                               0x1F

/* SWITCH registers */
#define KSZ8463_CHIP_ID0                             0x01
#define KSZ8463_CHIP_ID1                             0x00
#define KSZ8463_GLOBAL_CTRL_1L			     0x02
#define KSZ8463_GLOBAL_CTRL_1H			     0x03
#define KSZ8463_GLOBAL_CTRL_2L			     0x04
#define KSZ8463_GLOBAL_CTRL_2H			     0x05
#define KSZ8463_GLOBAL_CTRL_3L			     0x06
#define KSZ8463_GLOBAL_CTRL_3H			     0x07
#define KSZ8463_GLOBAL_CTRL_6L			     0x0C
#define KSZ8463_GLOBAL_CTRL_6H			     0x0D
#define KSZ8463_GLOBAL_CTRL_7L			     0x0E
#define KSZ8463_GLOBAL_CTRL_7H			     0x0F
#define KSZ8463_GLOBAL_CTRL_8L			     0xAC
#define KSZ8463_GLOBAL_CTRL_8H			     0xAD
#define KSZ8463_GLOBAL_CTRL_9L			     0xAE
#define KSZ8463_GLOBAL_CTRL_9H			     0xAF

#define KSZ8463_CFGR_L				     0xD8

#define KSZ8463_DSP_CNTRL_6L			     0x734
#define KSZ8463_DSP_CNTRL_6H			     0x735

#define KSZ8463_GLOBAL_CTRL1_TAIL_TAG_EN             BIT(0)
#define KSZ8463_GLOBAL_CTRL2_LEG_MAX_PKT_SIZ_CHK_ENA BIT(1)

#define KSZ8463_CTRL2L_PORTn(n)                      (0x6E + ((n) * 0x18))
#define KSZ8463_CTRL2L_VLAN_PORTS_MASK		     0xF8
#define KSZ8463_CTRL2H_PORTn(n)                      (0x6F + ((n) * 0x18))
#define KSZ8463_CTRL2_TRANSMIT_EN                    BIT(2)
#define KSZ8463_CTRL2_RECEIVE_EN                     BIT(1)
#define KSZ8463_CTRL2_LEARNING_DIS                   BIT(0)

#define KSZ8463_STAT2_PORTn(n)                       (0x80 + ((n) * 0x18))
#define KSZ8463_STAT2_LINK_GOOD                      BIT(5)

#define KSZ8463_CHIP_ID0_ID_DEFAULT                  0x84
#define KSZ8463_CHIP_ID1_ID_DEFAULT                  0x43
#define KSZ8463F_CHIP_ID1_ID_DEFAULT                 0x53
#define KSZ8463_RESET_REG	                     0x127
#define KSZ8463_SOFTWARE_RESET_SET                   BIT(0)
#define KSZ8463_SOFTWARE_RESET_CLEAR                 0

#define KSZ8463_P2_COPPER_MODE			     BIT(7)
#define KSZ8463_P1_COPPER_MODE			     BIT(6)
#define KSZ8463_RECV_ADJ			     BIT(5)

enum {
	/* LAN ports for the ksz8463 switch */
	KSZ8463_PORT1 = 0,
	KSZ8463_PORT2,
	/* SWITCH <-> CPU port */
	KSZ8463_PORT3,
};

#define KSZ8463_REG_IND_CTRL_0                        0x31
#define KSZ8463_REG_IND_CTRL_1                        0x30
#define KSZ8463_REG_IND_DATA_8                        0x26
#define KSZ8463_REG_IND_DATA_7                        0x2B
#define KSZ8463_REG_IND_DATA_6                        0x2A
#define KSZ8463_REG_IND_DATA_5                        0x29
#define KSZ8463_REG_IND_DATA_4                        0x28
#define KSZ8463_REG_IND_DATA_3                        0x2F
#define KSZ8463_REG_IND_DATA_2                        0x2E
#define KSZ8463_REG_IND_DATA_1                        0x2D
#define KSZ8463_REG_IND_DATA_0                        0x2C

#define KSZ8463_STATIC_MAC_TABLE_VALID                BIT(3)
#define KSZ8463_STATIC_MAC_TABLE_OVRD                 BIT(4)
#define KSZ8463_STATIC_MAC_TABLE_USE_FID              BIT(5)

#define KSZ8XXX_CHIP_ID0                        KSZ8463_CHIP_ID0
#define KSZ8XXX_CHIP_ID1                        KSZ8463_CHIP_ID1
#define KSZ8XXX_CHIP_ID0_ID_DEFAULT             KSZ8463_CHIP_ID0_ID_DEFAULT
#define KSZ8XXX_CHIP_ID1_ID_DEFAULT             KSZ8463F_CHIP_ID1_ID_DEFAULT
#define KSZ8XXX_FIRST_PORT                      KSZ8463_PORT1
#define KSZ8XXX_LAST_PORT                       KSZ8463_PORT3
#define KSZ8XXX_CPU_PORT                        KSZ8463_PORT3
#define KSZ8XXX_REG_IND_CTRL_0                  KSZ8463_REG_IND_CTRL_0
#define KSZ8XXX_REG_IND_CTRL_1                  KSZ8463_REG_IND_CTRL_1
#define KSZ8XXX_REG_IND_DATA_8                  KSZ8463_REG_IND_DATA_8
#define KSZ8XXX_REG_IND_DATA_7                  KSZ8463_REG_IND_DATA_7
#define KSZ8XXX_REG_IND_DATA_6                  KSZ8463_REG_IND_DATA_6
#define KSZ8XXX_REG_IND_DATA_5                  KSZ8463_REG_IND_DATA_5
#define KSZ8XXX_REG_IND_DATA_4                  KSZ8463_REG_IND_DATA_4
#define KSZ8XXX_REG_IND_DATA_3                  KSZ8463_REG_IND_DATA_3
#define KSZ8XXX_REG_IND_DATA_2                  KSZ8463_REG_IND_DATA_2
#define KSZ8XXX_REG_IND_DATA_1                  KSZ8463_REG_IND_DATA_1
#define KSZ8XXX_REG_IND_DATA_0                  KSZ8463_REG_IND_DATA_0
#define KSZ8XXX_STATIC_MAC_TABLE_VALID          KSZ8463_STATIC_MAC_TABLE_VALID
#define KSZ8XXX_STATIC_MAC_TABLE_OVRD           KSZ8463_STATIC_MAC_TABLE_OVRD
#define KSZ8XXX_STAT2_LINK_GOOD                 KSZ8463_STAT2_LINK_GOOD
#define KSZ8XXX_RESET_REG                       KSZ8463_RESET_REG
#define KSZ8XXX_RESET_SET                       KSZ8463_SOFTWARE_RESET_SET
#define KSZ8XXX_RESET_CLEAR                     KSZ8463_SOFTWARE_RESET_CLEAR
#define KSZ8XXX_STAT2_PORTn                     KSZ8463_STAT2_PORTn
#define KSZ8XXX_CTRL1_PORTn			KSZ8463_CTRL2L_PORTn
#define KSZ8XXX_CTRL1_VLAN_PORTS_MASK		KSZ8463_CTRL2L_VLAN_PORTS_MASK
#define KSZ8XXX_SPI_CMD_RD                      KSZ8463_SPI_CMD_RD
#define KSZ8XXX_SPI_CMD_WR                      KSZ8463_SPI_CMD_WR
#define KSZ8XXX_SOFT_RESET_DURATION             1000
#define KSZ8XXX_HARD_RESET_WAIT                 10000

#endif /* __DSA_KSZ8463_H__ */
+4 −0
Original line number Diff line number Diff line
@@ -234,6 +234,8 @@
#define KSZ8794_GLOBAL_CTRL10_TAIL_TAG_EN            BIT(1)
#define KSZ8794_GLOBAL_CTRL2_LEG_MAX_PKT_SIZ_CHK_DIS BIT(1)

#define KSZ8794_CTRL1_PORTn(n)                       (0x11 + ((n) * 0x10))
#define KSZ8794_CTRL1_VLAN_PORTS_MASK		     0xE0
#define KSZ8794_CTRL2_PORTn(n)                       (0x12 + ((n) * 0x10))
#define KSZ8794_CTRL2_TRANSMIT_EN                    BIT(2)
#define KSZ8794_CTRL2_RECEIVE_EN                     BIT(1)
@@ -321,6 +323,8 @@ enum {
#define KSZ8XXX_RESET_SET                       KSZ8794_PWR_MGNT_MODE_SOFT_DOWN
#define KSZ8XXX_RESET_CLEAR                     0
#define KSZ8XXX_STAT2_PORTn                     KSZ8794_STAT2_PORTn
#define KSZ8XXX_CTRL1_PORTn			KSZ8794_CTRL1_PORTn
#define KSZ8XXX_CTRL1_VLAN_PORTS_MASK		KSZ8794_CTRL1_VLAN_PORTS_MASK
#define KSZ8XXX_SPI_CMD_RD                      KSZ8794_SPI_CMD_RD
#define KSZ8XXX_SPI_CMD_WR                      KSZ8794_SPI_CMD_WR
#define KSZ8XXX_SOFT_RESET_DURATION                     1000
+4 −0
Original line number Diff line number Diff line
@@ -94,6 +94,8 @@
#define KSZ8863_GLOBAL_CTRL1_TAIL_TAG_EN             BIT(6)
#define KSZ8863_GLOBAL_CTRL2_LEG_MAX_PKT_SIZ_CHK_ENA BIT(1)

#define KSZ8863_CTRL1_PORTn(n)                       (0x11 + ((n) * 0x10))
#define KSZ8863_CTRL1_VLAN_PORTS_MASK                0xF8
#define KSZ8863_CTRL2_PORTn(n)                       (0x12 + ((n) * 0x10))
#define KSZ8863_CTRL2_TRANSMIT_EN                    BIT(2)
#define KSZ8863_CTRL2_RECEIVE_EN                     BIT(1)
@@ -157,6 +159,8 @@ enum {
#define KSZ8XXX_RESET_SET                       KSZ8863_SOFTWARE_RESET_SET
#define KSZ8XXX_RESET_CLEAR                     KSZ8863_SOFTWARE_RESET_CLEAR
#define KSZ8XXX_STAT2_PORTn                     KSZ8863_STAT2_PORTn
#define KSZ8XXX_CTRL1_PORTn			KSZ8863_CTRL1_PORTn
#define KSZ8XXX_CTRL1_VLAN_PORTS_MASK		KSZ8863_CTRL1_VLAN_PORTS_MASK
#define KSZ8XXX_SPI_CMD_RD                      KSZ8863_SPI_CMD_RD
#define KSZ8XXX_SPI_CMD_WR                      KSZ8863_SPI_CMD_WR
#define KSZ8XXX_SOFT_RESET_DURATION             1000
+100 −4
Original line number Diff line number Diff line
@@ -30,6 +30,9 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_ETHERNET_LOG_LEVEL);
#elif CONFIG_DSA_KSZ8794
#define DT_DRV_COMPAT microchip_ksz8794
#include "dsa_ksz8794.h"
#elif CONFIG_DSA_KSZ8463
#define DT_DRV_COMPAT microchip_ksz8463
#include "dsa_ksz8463.h"
#else
#error "Unsupported KSZ chipset"
#endif
@@ -59,9 +62,15 @@ static void dsa_ksz8xxx_write_reg(const struct ksz8xxx_data *pdev,
		.count = 1
	};

#if CONFIG_DSA_KSZ8463
	buf[0] = KSZ8XXX_SPI_CMD_WR | KSZ8463_REG_ADDR_HI_PART(reg_addr);
	buf[1] = KSZ8463_REG_ADDR_LO_PART(reg_addr) | KSZ8463_SPI_BYTE_ENABLE(reg_addr);
	buf[2] = value;
#else
	buf[0] = KSZ8XXX_SPI_CMD_WR | ((reg_addr >> 7) & 0x1F);
	buf[1] = (reg_addr << 1) & 0xFE;
	buf[2] = value;
#endif

	spi_write_dt(&pdev->spi, &tx);
#endif
@@ -91,9 +100,15 @@ static void dsa_ksz8xxx_read_reg(const struct ksz8xxx_data *pdev,
		.count = 1
	};

#if CONFIG_DSA_KSZ8463
	buf[0] = KSZ8XXX_SPI_CMD_RD | KSZ8463_REG_ADDR_HI_PART(reg_addr);
	buf[1] = KSZ8463_REG_ADDR_LO_PART(reg_addr) | KSZ8463_SPI_BYTE_ENABLE(reg_addr);
	buf[2] = 0;
#else
	buf[0] = KSZ8XXX_SPI_CMD_RD | ((reg_addr >> 7) & 0x1F);
	buf[1] = (reg_addr << 1) & 0xFE;
	buf[2] = 0x0;
#endif

	if (!spi_transceive_dt(&pdev->spi, &tx, &rx)) {
		*value = buf[2];
@@ -153,7 +168,12 @@ static int dsa_ksz8xxx_probe(struct ksz8xxx_data *pdev)
	dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_CHIP_ID1, &val[1]);

	if (val[0] != KSZ8XXX_CHIP_ID0_ID_DEFAULT ||
#if CONFIG_DSA_KSZ8463
	    (val[1] != KSZ8463_CHIP_ID1_ID_DEFAULT &&
	    val[1] != KSZ8463F_CHIP_ID1_ID_DEFAULT)) {
#else
	    val[1] != KSZ8XXX_CHIP_ID1_ID_DEFAULT) {
#endif
		LOG_ERR("Chip ID mismatch. "
			"Expected %02x%02x but found %02x%02x",
			KSZ8XXX_CHIP_ID0_ID_DEFAULT,
@@ -163,7 +183,7 @@ static int dsa_ksz8xxx_probe(struct ksz8xxx_data *pdev)
		return -ENODEV;
	}

	LOG_DBG("KSZ8794: ID0: 0x%x ID1: 0x%x timeout: %d", val[1], val[0],
	LOG_DBG("KSZ8794: ID0: 0x%x ID1: 0x%x timeout: %d", val[0], val[1],
		timeout);

	return 0;
@@ -260,6 +280,79 @@ static int dsa_ksz8xxx_read_static_mac_table(struct ksz8xxx_data *pdev,
	return 0;
}

#if defined(CONFIG_DSA_KSZ_PORT_ISOLATING)
static int dsa_ksz8xxx_port_isolate(const struct ksz8xxx_data *pdev)
{
	uint8_t tmp, i;

	for (i = KSZ8XXX_FIRST_PORT; i < KSZ8XXX_LAST_PORT; i++) {
		dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_CTRL1_PORTn(i), &tmp);
		tmp &= KSZ8XXX_CTRL1_VLAN_PORTS_MASK;
		tmp |= 1 << KSZ8XXX_CPU_PORT | 1 << i;
		dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_CTRL1_PORTn(i), tmp);
	}

	dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_CTRL1_PORTn(KSZ8XXX_CPU_PORT),
			     &tmp);
	tmp |= ~KSZ8XXX_CTRL1_VLAN_PORTS_MASK;
	dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_CTRL1_PORTn(KSZ8XXX_CPU_PORT),
			      tmp);

	return 0;
}
#endif

#if CONFIG_DSA_KSZ8463
static int dsa_ksz8xxx_switch_setup(struct ksz8xxx_data *pdev)
{
	uint8_t tmp, i;

	dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_CHIP_ID1, &tmp);

	if (tmp == KSZ8463F_CHIP_ID1_ID_DEFAULT) {
		dsa_ksz8xxx_read_reg(pdev, KSZ8463_CFGR_L, &tmp);
		tmp &= ~KSZ8463_P1_COPPER_MODE;
		tmp &= ~KSZ8463_P2_COPPER_MODE;
		dsa_ksz8xxx_write_reg(pdev, KSZ8463_CFGR_L, tmp);
		dsa_ksz8xxx_read_reg(pdev, KSZ8463_DSP_CNTRL_6H, &tmp);
		tmp &= ~KSZ8463_RECV_ADJ;
		dsa_ksz8xxx_write_reg(pdev, KSZ8463_DSP_CNTRL_6H, tmp);
	}

	/*
	 * Loop through ports - The same setup when tail tagging is enabled or
	 * disabled.
	 */
	for (i = KSZ8XXX_FIRST_PORT; i <= KSZ8XXX_LAST_PORT; i++) {

		/* Enable transmission, reception and switch address learning */
		dsa_ksz8xxx_read_reg(pdev, KSZ8463_CTRL2H_PORTn(i), &tmp);
		tmp |= KSZ8463_CTRL2_TRANSMIT_EN;
		tmp |= KSZ8463_CTRL2_RECEIVE_EN;
		tmp &= ~KSZ8463_CTRL2_LEARNING_DIS;
		dsa_ksz8xxx_write_reg(pdev, KSZ8463_CTRL2H_PORTn(i), tmp);
	}

#if defined(CONFIG_DSA_KSZ_TAIL_TAGGING)
	/* Enable tail tag feature */
	dsa_ksz8xxx_read_reg(pdev, KSZ8463_GLOBAL_CTRL_8H, &tmp);
	tmp |= KSZ8463_GLOBAL_CTRL1_TAIL_TAG_EN;
	dsa_ksz8xxx_write_reg(pdev, KSZ8463_GLOBAL_CTRL_8H, tmp);
#else
	/* Disable tail tag feature */
	dsa_ksz8xxx_read_reg(pdev, KSZ8463_GLOBAL_CTRL_8H, &tmp);
	tmp &= ~KSZ8463_GLOBAL_CTRL1_TAIL_TAG_EN;
	dsa_ksz8xxx_write_reg(pdev, KSZ8463_GLOBAL_CTRL_8H, tmp);
#endif

	dsa_ksz8xxx_read_reg(pdev, KSZ8463_GLOBAL_CTRL_2L, &tmp);
	tmp &= ~KSZ8463_GLOBAL_CTRL2_LEG_MAX_PKT_SIZ_CHK_ENA;
	dsa_ksz8xxx_write_reg(pdev, KSZ8463_GLOBAL_CTRL_2L, tmp);

	return 0;
}
#endif

#if CONFIG_DSA_KSZ8863
static int dsa_ksz8xxx_switch_setup(const struct ksz8xxx_data *pdev)
{
@@ -697,6 +790,10 @@ int dsa_hw_init(struct ksz8xxx_data *pdev)
	/* Setup KSZ8794 */
	dsa_ksz8xxx_switch_setup(pdev);

#if defined(CONFIG_DSA_KSZ_PORT_ISOLATING)
	dsa_ksz8xxx_port_isolate(pdev);
#endif

#if DT_INST_NODE_HAS_PROP(0, mii_lowspeed_drivestrength)
	dsa_ksz8794_set_lowspeed_drivestrength(pdev);
#endif
@@ -885,7 +982,7 @@ struct net_pkt *dsa_ksz8xxx_xmit_pkt(struct net_if *iface, struct net_pkt *pkt)
		port_idx = (1 << (ctx->dsa_port_idx));
	}

	NET_DBG("TT - port: 0x%x[%p] LEN: %d 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
	LOG_DBG("TT - port: 0x%x[%p] LEN: %d 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
		port_idx, iface, len, lladst.addr[0], lladst.addr[1],
		lladst.addr[2], lladst.addr[3], lladst.addr[4], lladst.addr[5]);

@@ -948,7 +1045,7 @@ static struct net_if *dsa_ksz8xxx_get_iface(struct net_if *iface,
	iface_sw = net_if_get_by_index(pnum + 2);

	ctx = net_if_l2_data(iface);
	NET_DBG("TT - plen: %d pnum: %d pos: 0x%p dsa_port_idx: %d",
	LOG_DBG("TT - plen: %d pnum: %d pos: 0x%p dsa_port_idx: %d",
		plen - DSA_KSZ8794_EGRESS_TAG_LEN, pnum,
		net_pkt_cursor_get_pos(pkt), ctx->dsa_port_idx);

@@ -1112,5 +1209,4 @@ static struct dsa_api dsa_api_f = {
	};								\
	DT_INST_FOREACH_CHILD_VARGS(n, NET_SLAVE_DEVICE_INIT_INSTANCE, n);


DT_INST_FOREACH_STATUS_OKAY(DSA_DEVICE);
Loading