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: Aleksandr Senin <al@meshium.net>
This commit is contained in:
Aleksandr Senin 2023-11-05 12:24:46 +03:00 committed by Benjamin Cabé
parent 907261b619
commit 12ad8f0f6e
6 changed files with 266 additions and 7 deletions

View File

@ -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

View File

@ -0,0 +1,131 @@
/*
* 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__ */

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -0,0 +1,9 @@
# Copyright (c) 2023 Aleksandr Senin <al@meshium.net>
# SPDX-License-Identifier: Apache-2.0
description: |
KSZ8463 ethernet switch
compatible: "microchip,ksz8463"
include: [microchip_dsa.yaml]