Commit 8aa9ebcc authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: dsa: Introduce driver for NXP SJA1105 5-port L2 switch

At this moment the following is supported:
* Link state management through phylib
* Autonomous L2 forwarding managed through iproute2 bridge commands.

IP termination must be done currently through the master netdevice,
since the switch is unmanaged at this point and using
DSA_TAG_PROTO_NONE.
Signed-off-by: default avatarVladimir Oltean <olteanv@gmail.com>
Signed-off-by: default avatarGeorg Waibel <georg.waibel@sensor-technik.de>
Acked-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 554aae35
......@@ -11120,6 +11120,12 @@ S: Maintained
F: Documentation/devicetree/bindings/sound/sgtl5000.txt
F: sound/soc/codecs/sgtl5000*
NXP SJA1105 ETHERNET SWITCH DRIVER
M: Vladimir Oltean <olteanv@gmail.com>
L: linux-kernel@vger.kernel.org
S: Maintained
F: drivers/net/dsa/sja1105
NXP TDA998X DRM DRIVER
M: Russell King <linux@armlinux.org.uk>
S: Maintained
......
......@@ -51,6 +51,8 @@ source "drivers/net/dsa/microchip/Kconfig"
source "drivers/net/dsa/mv88e6xxx/Kconfig"
source "drivers/net/dsa/sja1105/Kconfig"
config NET_DSA_QCA8K
tristate "Qualcomm Atheros QCA8K Ethernet switch family support"
depends on NET_DSA
......
......@@ -18,3 +18,4 @@ obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx.o
obj-y += b53/
obj-y += microchip/
obj-y += mv88e6xxx/
obj-y += sja1105/
config NET_DSA_SJA1105
tristate "NXP SJA1105 Ethernet switch family support"
depends on NET_DSA && SPI
select PACKING
select CRC32
help
This is the driver for the NXP SJA1105 automotive Ethernet switch
family. These are 5-port devices and are managed over an SPI
interface. Probing is handled based on OF bindings and so is the
linkage to phylib. The driver supports the following revisions:
- SJA1105E (Gen. 1, No TT-Ethernet)
- SJA1105T (Gen. 1, TT-Ethernet)
- SJA1105P (Gen. 2, No SGMII, No TT-Ethernet)
- SJA1105Q (Gen. 2, No SGMII, TT-Ethernet)
- SJA1105R (Gen. 2, SGMII, No TT-Ethernet)
- SJA1105S (Gen. 2, SGMII, TT-Ethernet)
obj-$(CONFIG_NET_DSA_SJA1105) += sja1105.o
sja1105-objs := \
sja1105_spi.o \
sja1105_main.o \
sja1105_clocking.o \
sja1105_static_config.o \
sja1105_dynamic_config.o \
/* SPDX-License-Identifier: GPL-2.0
* Copyright (c) 2018, Sensor-Technik Wiedemann GmbH
* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
*/
#ifndef _SJA1105_H
#define _SJA1105_H
#include <linux/dsa/sja1105.h>
#include <net/dsa.h>
#include "sja1105_static_config.h"
#define SJA1105_NUM_PORTS 5
#define SJA1105_NUM_TC 8
#define SJA1105ET_FDB_BIN_SIZE 4
/* Keeps the different addresses between E/T and P/Q/R/S */
struct sja1105_regs {
u64 device_id;
u64 prod_id;
u64 status;
u64 rgu;
u64 config;
u64 rmii_pll1;
u64 pad_mii_tx[SJA1105_NUM_PORTS];
u64 cgu_idiv[SJA1105_NUM_PORTS];
u64 rgmii_pad_mii_tx[SJA1105_NUM_PORTS];
u64 mii_tx_clk[SJA1105_NUM_PORTS];
u64 mii_rx_clk[SJA1105_NUM_PORTS];
u64 mii_ext_tx_clk[SJA1105_NUM_PORTS];
u64 mii_ext_rx_clk[SJA1105_NUM_PORTS];
u64 rgmii_tx_clk[SJA1105_NUM_PORTS];
u64 rmii_ref_clk[SJA1105_NUM_PORTS];
u64 rmii_ext_tx_clk[SJA1105_NUM_PORTS];
u64 mac[SJA1105_NUM_PORTS];
u64 mac_hl1[SJA1105_NUM_PORTS];
u64 mac_hl2[SJA1105_NUM_PORTS];
u64 qlevel[SJA1105_NUM_PORTS];
};
struct sja1105_info {
u64 device_id;
/* Needed for distinction between P and R, and between Q and S
* (since the parts with/without SGMII share the same
* switch core and device_id)
*/
u64 part_no;
const struct sja1105_dynamic_table_ops *dyn_ops;
const struct sja1105_table_ops *static_ops;
const struct sja1105_regs *regs;
int (*reset_cmd)(const void *ctx, const void *data);
const char *name;
};
struct sja1105_private {
struct sja1105_static_config static_config;
const struct sja1105_info *info;
struct gpio_desc *reset_gpio;
struct spi_device *spidev;
struct dsa_switch *ds;
};
#include "sja1105_dynamic_config.h"
struct sja1105_spi_message {
u64 access;
u64 read_count;
u64 address;
};
typedef enum {
SPI_READ = 0,
SPI_WRITE = 1,
} sja1105_spi_rw_mode_t;
/* From sja1105_spi.c */
int sja1105_spi_send_packed_buf(const struct sja1105_private *priv,
sja1105_spi_rw_mode_t rw, u64 reg_addr,
void *packed_buf, size_t size_bytes);
int sja1105_spi_send_int(const struct sja1105_private *priv,
sja1105_spi_rw_mode_t rw, u64 reg_addr,
u64 *value, u64 size_bytes);
int sja1105_spi_send_long_packed_buf(const struct sja1105_private *priv,
sja1105_spi_rw_mode_t rw, u64 base_addr,
void *packed_buf, u64 buf_len);
int sja1105_static_config_upload(struct sja1105_private *priv);
extern struct sja1105_info sja1105e_info;
extern struct sja1105_info sja1105t_info;
extern struct sja1105_info sja1105p_info;
extern struct sja1105_info sja1105q_info;
extern struct sja1105_info sja1105r_info;
extern struct sja1105_info sja1105s_info;
/* From sja1105_clocking.c */
typedef enum {
XMII_MAC = 0,
XMII_PHY = 1,
} sja1105_mii_role_t;
typedef enum {
XMII_MODE_MII = 0,
XMII_MODE_RMII = 1,
XMII_MODE_RGMII = 2,
} sja1105_phy_interface_t;
typedef enum {
SJA1105_SPEED_10MBPS = 3,
SJA1105_SPEED_100MBPS = 2,
SJA1105_SPEED_1000MBPS = 1,
SJA1105_SPEED_AUTO = 0,
} sja1105_speed_t;
int sja1105_clocking_setup_port(struct sja1105_private *priv, int port);
int sja1105_clocking_setup(struct sja1105_private *priv);
/* From sja1105_dynamic_config.c */
int sja1105_dynamic_config_read(struct sja1105_private *priv,
enum sja1105_blk_idx blk_idx,
int index, void *entry);
int sja1105_dynamic_config_write(struct sja1105_private *priv,
enum sja1105_blk_idx blk_idx,
int index, void *entry, bool keep);
/* Common implementations for the static and dynamic configs */
size_t sja1105_l2_forwarding_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
size_t sja1105pqrs_l2_lookup_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
size_t sja1105et_l2_lookup_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
size_t sja1105_vlan_lookup_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
size_t sja1105pqrs_mac_config_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
#endif
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0
* Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com>
*/
#ifndef _SJA1105_DYNAMIC_CONFIG_H
#define _SJA1105_DYNAMIC_CONFIG_H
#include "sja1105.h"
#include <linux/packing.h>
struct sja1105_dyn_cmd {
u64 valid;
u64 rdwrset;
u64 errors;
u64 valident;
u64 index;
};
struct sja1105_dynamic_table_ops {
/* This returns size_t just to keep same prototype as the
* static config ops, of which we are reusing some functions.
*/
size_t (*entry_packing)(void *buf, void *entry_ptr, enum packing_op op);
void (*cmd_packing)(void *buf, struct sja1105_dyn_cmd *cmd,
enum packing_op op);
size_t max_entry_count;
size_t packed_size;
u64 addr;
u8 access;
};
struct sja1105_mgmt_entry {
u64 tsreg;
u64 takets;
u64 macaddr;
u64 destports;
u64 enfport;
u64 index;
};
extern struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN];
extern struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN];
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) 2016-2018, NXP Semiconductors
* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
*/
#ifndef _SJA1105_STATIC_CONFIG_H
#define _SJA1105_STATIC_CONFIG_H
#include <linux/packing.h>
#include <linux/types.h>
#include <asm/types.h>
#define SJA1105_SIZE_DEVICE_ID 4
#define SJA1105_SIZE_TABLE_HEADER 12
#define SJA1105_SIZE_L2_POLICING_ENTRY 8
#define SJA1105_SIZE_VLAN_LOOKUP_ENTRY 8
#define SJA1105_SIZE_L2_FORWARDING_ENTRY 8
#define SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY 12
#define SJA1105_SIZE_XMII_PARAMS_ENTRY 4
#define SJA1105ET_SIZE_L2_LOOKUP_ENTRY 12
#define SJA1105ET_SIZE_MAC_CONFIG_ENTRY 28
#define SJA1105ET_SIZE_L2_LOOKUP_PARAMS_ENTRY 4
#define SJA1105ET_SIZE_GENERAL_PARAMS_ENTRY 40
#define SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY 20
#define SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY 32
#define SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY 16
#define SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY 44
/* UM10944.pdf Page 11, Table 2. Configuration Blocks */
enum {
BLKID_L2_LOOKUP = 0x05,
BLKID_L2_POLICING = 0x06,
BLKID_VLAN_LOOKUP = 0x07,
BLKID_L2_FORWARDING = 0x08,
BLKID_MAC_CONFIG = 0x09,
BLKID_L2_LOOKUP_PARAMS = 0x0D,
BLKID_L2_FORWARDING_PARAMS = 0x0E,
BLKID_GENERAL_PARAMS = 0x11,
BLKID_XMII_PARAMS = 0x4E,
};
enum sja1105_blk_idx {
BLK_IDX_L2_LOOKUP = 0,
BLK_IDX_L2_POLICING,
BLK_IDX_VLAN_LOOKUP,
BLK_IDX_L2_FORWARDING,
BLK_IDX_MAC_CONFIG,
BLK_IDX_L2_LOOKUP_PARAMS,
BLK_IDX_L2_FORWARDING_PARAMS,
BLK_IDX_GENERAL_PARAMS,
BLK_IDX_XMII_PARAMS,
BLK_IDX_MAX,
/* Fake block indices that are only valid for dynamic access */
BLK_IDX_MGMT_ROUTE,
BLK_IDX_MAX_DYN,
BLK_IDX_INVAL = -1,
};
#define SJA1105_MAX_L2_LOOKUP_COUNT 1024
#define SJA1105_MAX_L2_POLICING_COUNT 45
#define SJA1105_MAX_VLAN_LOOKUP_COUNT 4096
#define SJA1105_MAX_L2_FORWARDING_COUNT 13
#define SJA1105_MAX_MAC_CONFIG_COUNT 5
#define SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT 1
#define SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT 1
#define SJA1105_MAX_GENERAL_PARAMS_COUNT 1
#define SJA1105_MAX_XMII_PARAMS_COUNT 1
#define SJA1105_MAX_FRAME_MEMORY 929
#define SJA1105E_DEVICE_ID 0x9C00000Cull
#define SJA1105T_DEVICE_ID 0x9E00030Eull
#define SJA1105PR_DEVICE_ID 0xAF00030Eull
#define SJA1105QS_DEVICE_ID 0xAE00030Eull
#define SJA1105ET_PART_NO 0x9A83
#define SJA1105P_PART_NO 0x9A84
#define SJA1105Q_PART_NO 0x9A85
#define SJA1105R_PART_NO 0x9A86
#define SJA1105S_PART_NO 0x9A87
struct sja1105_general_params_entry {
u64 vllupformat;
u64 mirr_ptacu;
u64 switchid;
u64 hostprio;
u64 mac_fltres1;
u64 mac_fltres0;
u64 mac_flt1;
u64 mac_flt0;
u64 incl_srcpt1;
u64 incl_srcpt0;
u64 send_meta1;
u64 send_meta0;
u64 casc_port;
u64 host_port;
u64 mirr_port;
u64 vlmarker;
u64 vlmask;
u64 tpid;
u64 ignore2stf;
u64 tpid2;
/* P/Q/R/S only */
u64 queue_ts;
u64 egrmirrvid;
u64 egrmirrpcp;
u64 egrmirrdei;
u64 replay_port;
};
struct sja1105_vlan_lookup_entry {
u64 ving_mirr;
u64 vegr_mirr;
u64 vmemb_port;
u64 vlan_bc;
u64 tag_port;
u64 vlanid;
};
struct sja1105_l2_lookup_entry {
u64 vlanid;
u64 macaddr;
u64 destports;
u64 enfport;
u64 index;
};
struct sja1105_l2_lookup_params_entry {
u64 maxage; /* Shared */
u64 dyn_tbsz; /* E/T only */
u64 poly; /* E/T only */
u64 shared_learn; /* Shared */
u64 no_enf_hostprt; /* Shared */
u64 no_mgmt_learn; /* Shared */
};
struct sja1105_l2_forwarding_entry {
u64 bc_domain;
u64 reach_port;
u64 fl_domain;
u64 vlan_pmap[8];
};
struct sja1105_l2_forwarding_params_entry {
u64 max_dynp;
u64 part_spc[8];
};
struct sja1105_l2_policing_entry {
u64 sharindx;
u64 smax;
u64 rate;
u64 maxlen;
u64 partition;
};
struct sja1105_mac_config_entry {
u64 top[8];
u64 base[8];
u64 enabled[8];
u64 ifg;
u64 speed;
u64 tp_delin;
u64 tp_delout;
u64 maxage;
u64 vlanprio;
u64 vlanid;
u64 ing_mirr;
u64 egr_mirr;
u64 drpnona664;
u64 drpdtag;
u64 drpuntag;
u64 retag;
u64 dyn_learn;
u64 egress;
u64 ingress;
};
struct sja1105_xmii_params_entry {
u64 phy_mac[5];
u64 xmii_mode[5];
};
struct sja1105_table_header {
u64 block_id;
u64 len;
u64 crc;
};
struct sja1105_table_ops {
size_t (*packing)(void *buf, void *entry_ptr, enum packing_op op);
size_t unpacked_entry_size;
size_t packed_entry_size;
size_t max_entry_count;
};
struct sja1105_table {
const struct sja1105_table_ops *ops;
size_t entry_count;
void *entries;
};
struct sja1105_static_config {
u64 device_id;
struct sja1105_table tables[BLK_IDX_MAX];
};
extern struct sja1105_table_ops sja1105e_table_ops[BLK_IDX_MAX];
extern struct sja1105_table_ops sja1105t_table_ops[BLK_IDX_MAX];
extern struct sja1105_table_ops sja1105p_table_ops[BLK_IDX_MAX];
extern struct sja1105_table_ops sja1105q_table_ops[BLK_IDX_MAX];
extern struct sja1105_table_ops sja1105r_table_ops[BLK_IDX_MAX];
extern struct sja1105_table_ops sja1105s_table_ops[BLK_IDX_MAX];
size_t sja1105_table_header_packing(void *buf, void *hdr, enum packing_op op);
void
sja1105_table_header_pack_with_crc(void *buf, struct sja1105_table_header *hdr);
size_t
sja1105_static_config_get_length(const struct sja1105_static_config *config);
typedef enum {
SJA1105_CONFIG_OK = 0,
SJA1105_MISSING_L2_POLICING_TABLE,
SJA1105_MISSING_L2_FORWARDING_TABLE,
SJA1105_MISSING_L2_FORWARDING_PARAMS_TABLE,
SJA1105_MISSING_GENERAL_PARAMS_TABLE,
SJA1105_MISSING_VLAN_TABLE,
SJA1105_MISSING_XMII_TABLE,
SJA1105_MISSING_MAC_TABLE,
SJA1105_OVERCOMMITTED_FRAME_MEMORY,
} sja1105_config_valid_t;
extern const char *sja1105_static_config_error_msg[];
sja1105_config_valid_t
sja1105_static_config_check_valid(const struct sja1105_static_config *config);
void
sja1105_static_config_pack(void *buf, struct sja1105_static_config *config);
int sja1105_static_config_init(struct sja1105_static_config *config,
const struct sja1105_table_ops *static_ops,
u64 device_id);
void sja1105_static_config_free(struct sja1105_static_config *config);
u32 sja1105_crc32(const void *buf, size_t len);
void sja1105_pack(void *buf, const u64 *val, int start, int end, size_t len);
void sja1105_unpack(const void *buf, u64 *val, int start, int end, size_t len);
void sja1105_packing(void *buf, u64 *val, int start, int end,
size_t len, enum packing_op op);
#endif
/* SPDX-License-Identifier: GPL-2.0
* Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com>
*/
/* Included by drivers/net/dsa/sja1105/sja1105.h */
#ifndef _NET_DSA_SJA1105_H
#define _NET_DSA_SJA1105_H
/* The switch can only be convinced to stay in unmanaged mode and not trap any
* link-local traffic by actually telling it to filter frames sent at the
* 00:00:00:00:00:00 destination MAC.
*/
#define SJA1105_LINKLOCAL_FILTER_A 0x000000000000ull
#define SJA1105_LINKLOCAL_FILTER_A_MASK 0xFFFFFFFFFFFFull
#define SJA1105_LINKLOCAL_FILTER_B 0x000000000000ull
#define SJA1105_LINKLOCAL_FILTER_B_MASK 0xFFFFFFFFFFFFull
#endif /* _NET_DSA_SJA1105_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment