Commit fd5f5ab0 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'dsa-sja1110'



Vladimir Oltean says:

====================
Add NXP SJA1110 support to the sja1105 DSA driver

The NXP SJA1110 is an automotive Ethernet switch with an embedded Arm
Cortex-M7 microcontroller. The switch has 11 ports (10 external + one
for the DSA-style connection to the microcontroller).
The microcontroller can be disabled and the switch can be controlled
over SPI, a la SJA1105 - this is how this driver handles things.

There are some integrated NXP PHYs (100base-T1 and 100base-TX). Their
initialization is handled by their own PHY drivers, the switch is only
concerned with enabling register accesses to them, by registering two
MDIO buses.

Changes in v3:
- Make sure the VLAN retagging port is enabled and functional
- Dropped SGMII PCS from this series

Changes in v2:
- converted nxp,sja1105 DT bindings to YAML
- registered the PCS MDIO bus and forced auto-probing off for all PHY
  addresses for this bus
- changed the container node name for the 2 MDIO buses from "mdio" to
  "mdios" to avoid matching on the mdio.yaml schema (it's just a
  container node, not an MDIO bus)
- fixed an uninitialized "offset" variable usage in
  sja1110_pcs_mdio_{read,write}
- using the mdiobus_c45_addr macro instead of open-coding that operation
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 173dbbfe 5a8f0974
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -27,10 +27,53 @@ properties:
      - nxp,sja1105q
      - nxp,sja1105r
      - nxp,sja1105s
      - nxp,sja1110a
      - nxp,sja1110b
      - nxp,sja1110c
      - nxp,sja1110d

  reg:
    maxItems: 1

  # Optional container node for the 2 internal MDIO buses of the SJA1110
  # (one for the internal 100base-T1 PHYs and the other for the single
  # 100base-TX PHY). The "reg" property does not have physical significance.
  # The PHY addresses to port correspondence is as follows: for 100base-T1,
  # port 5 has PHY 1, port 6 has PHY 2 etc, while for 100base-TX, port 1 has
  # PHY 1.
  mdios:
    type: object

    properties:
      '#address-cells':
        const: 1
      '#size-cells':
        const: 0

    patternProperties:
      "^mdio@[0-1]$":
        type: object

        allOf:
          - $ref: "http://devicetree.org/schemas/net/mdio.yaml#"

        properties:
          compatible:
            oneOf:
              - enum:
                  - nxp,sja1110-base-t1-mdio
                  - nxp,sja1110-base-tx-mdio

          reg:
            oneOf:
              - enum:
                - 0
                - 1

        required:
          - compatible
          - reg

required:
  - compatible
  - reg
+1 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ obj-$(CONFIG_NET_DSA_SJA1105) += sja1105.o
sja1105-objs := \
    sja1105_spi.o \
    sja1105_main.o \
    sja1105_mdio.o \
    sja1105_flower.o \
    sja1105_ethtool.o \
    sja1105_devlink.o \
+39 −4
Original line number Diff line number Diff line
@@ -13,15 +13,12 @@
#include <linux/mutex.h>
#include "sja1105_static_config.h"

#define SJA1105_NUM_PORTS		5
#define SJA1105_MAX_NUM_PORTS		SJA1105_NUM_PORTS
#define SJA1105_NUM_TC			8
#define SJA1105ET_FDB_BIN_SIZE		4
/* The hardware value is in multiples of 10 ms.
 * The passed parameter is in multiples of 1 ms.
 */
#define SJA1105_AGEING_TIME_MS(ms)	((ms) / 10)
#define SJA1105_NUM_L2_POLICERS		45
#define SJA1105_NUM_L2_POLICERS		SJA1110_MAX_L2_POLICING_COUNT

typedef enum {
	SPI_READ = 0,
@@ -70,6 +67,12 @@ struct sja1105_regs {
	u64 rmii_ref_clk[SJA1105_MAX_NUM_PORTS];
	u64 rmii_ext_tx_clk[SJA1105_MAX_NUM_PORTS];
	u64 stats[__MAX_SJA1105_STATS_AREA][SJA1105_MAX_NUM_PORTS];
	u64 mdio_100base_tx;
	u64 mdio_100base_t1;
};

struct sja1105_mdio_private {
	struct sja1105_private *priv;
};

enum {
@@ -81,6 +84,12 @@ enum {
	SJA1105_SPEED_MAX,
};

enum sja1105_internal_phy_t {
	SJA1105_NO_PHY		= 0,
	SJA1105_PHY_BASE_TX,
	SJA1105_PHY_BASE_T1,
};

struct sja1105_info {
	u64 device_id;
	/* Needed for distinction between P and R, and between Q and S
@@ -99,6 +108,7 @@ struct sja1105_info {
	int ptpegr_ts_bytes;
	int num_cbs_shapers;
	int max_frame_mem;
	int num_ports;
	const struct sja1105_dynamic_table_ops *dyn_ops;
	const struct sja1105_table_ops *static_ops;
	const struct sja1105_regs *regs;
@@ -125,6 +135,7 @@ struct sja1105_info {
	bool supports_rgmii[SJA1105_MAX_NUM_PORTS];
	bool supports_sgmii[SJA1105_MAX_NUM_PORTS];
	bool supports_2500basex[SJA1105_MAX_NUM_PORTS];
	enum sja1105_internal_phy_t internal_phy[SJA1105_MAX_NUM_PORTS];
	const u64 port_speed[SJA1105_SPEED_MAX];
};

@@ -248,6 +259,8 @@ struct sja1105_private {
	enum sja1105_vlan_state vlan_state;
	struct devlink_region **regions;
	struct sja1105_cbs_entry *cbs;
	struct mii_bus *mdio_base_t1;
	struct mii_bus *mdio_base_tx;
	struct sja1105_tagger_data tagger_data;
	struct sja1105_ptp_data ptp_data;
	struct sja1105_tas_data tas_data;
@@ -277,6 +290,10 @@ int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
			   struct netlink_ext_ack *extack);
void sja1105_frame_memory_partitioning(struct sja1105_private *priv);

/* From sja1105_mdio.c */
int sja1105_mdiobus_register(struct dsa_switch *ds);
void sja1105_mdiobus_unregister(struct dsa_switch *ds);

/* From sja1105_devlink.c */
int sja1105_devlink_setup(struct dsa_switch *ds);
void sja1105_devlink_teardown(struct dsa_switch *ds);
@@ -310,6 +327,10 @@ extern const struct sja1105_info sja1105p_info;
extern const struct sja1105_info sja1105q_info;
extern const struct sja1105_info sja1105r_info;
extern const struct sja1105_info sja1105s_info;
extern const struct sja1105_info sja1110a_info;
extern const struct sja1105_info sja1110b_info;
extern const struct sja1105_info sja1110c_info;
extern const struct sja1105_info sja1110d_info;

/* From sja1105_clocking.c */

@@ -326,8 +347,10 @@ typedef enum {
} sja1105_phy_interface_t;

int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port);
int sja1110_setup_rgmii_delay(const void *ctx, int port);
int sja1105_clocking_setup_port(struct sja1105_private *priv, int port);
int sja1105_clocking_setup(struct sja1105_private *priv);
int sja1110_clocking_setup(struct sja1105_private *priv);

/* From sja1105_ethtool.c */
void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data);
@@ -348,6 +371,18 @@ enum sja1105_iotag {
	SJA1105_S_TAG = 1, /* Outer VLAN header */
};

enum sja1110_vlan_type {
	SJA1110_VLAN_INVALID = 0,
	SJA1110_VLAN_C_TAG = 1, /* Single inner VLAN tag */
	SJA1110_VLAN_S_TAG = 2, /* Single outer VLAN tag */
	SJA1110_VLAN_D_TAG = 3, /* Double tagged, use outer tag for lookup */
};

enum sja1110_shaper_type {
	SJA1110_LEAKY_BUCKET_SHAPER = 0,
	SJA1110_CBS_SHAPER = 1,
};

u8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid);
int sja1105et_fdb_add(struct dsa_switch *ds, int port,
		      const unsigned char *addr, u16 vid);
+91 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
#include "sja1105.h"

#define SJA1105_SIZE_CGU_CMD	4
#define SJA1110_BASE_TIMER_CLK	SJA1110_CGU_ADDR(0x74)

/* Common structure for CFG_PAD_MIIx_RX and CFG_PAD_MIIx_TX */
struct sja1105_cfg_pad_mii {
@@ -61,6 +62,12 @@ struct sja1105_cgu_pll_ctrl {
	u64 pd;
};

struct sja1110_cgu_outclk {
	u64 clksrc;
	u64 autoblock;
	u64 pd;
};

enum {
	CLKSRC_MII0_TX_CLK	= 0x00,
	CLKSRC_MII0_RX_CLK	= 0x01,
@@ -461,6 +468,35 @@ sja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
	sja1105_packing(buf, &cmd->txc_pd,          0,  0, size, op);
}

static void
sja1110_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
			       enum packing_op op)
{
	const int size = SJA1105_SIZE_CGU_CMD;
	u64 range = 4;

	/* Fields RXC_RANGE and TXC_RANGE select the input frequency range:
	 * 0 = 2.5MHz
	 * 1 = 25MHz
	 * 2 = 50MHz
	 * 3 = 125MHz
	 * 4 = Automatically determined by port speed.
	 * There's no point in defining a structure different than the one for
	 * SJA1105, so just hardcode the frequency range to automatic, just as
	 * before.
	 */
	sja1105_packing(buf, &cmd->rxc_stable_ovr, 26, 26, size, op);
	sja1105_packing(buf, &cmd->rxc_delay,      25, 21, size, op);
	sja1105_packing(buf, &range,               20, 18, size, op);
	sja1105_packing(buf, &cmd->rxc_bypass,     17, 17, size, op);
	sja1105_packing(buf, &cmd->rxc_pd,         16, 16, size, op);
	sja1105_packing(buf, &cmd->txc_stable_ovr, 10, 10, size, op);
	sja1105_packing(buf, &cmd->txc_delay,       9,  5, size, op);
	sja1105_packing(buf, &range,                4,  2, size, op);
	sja1105_packing(buf, &cmd->txc_bypass,      1,  1, size, op);
	sja1105_packing(buf, &cmd->txc_pd,          0,  0, size, op);
}

/* Valid range in degrees is an integer between 73.8 and 101.7 */
static u64 sja1105_rgmii_delay(u64 phase)
{
@@ -519,6 +555,35 @@ int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port)
				packed_buf, SJA1105_SIZE_CGU_CMD);
}

int sja1110_setup_rgmii_delay(const void *ctx, int port)
{
	const struct sja1105_private *priv = ctx;
	const struct sja1105_regs *regs = priv->info->regs;
	struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};

	pad_mii_id.rxc_pd = 1;
	pad_mii_id.txc_pd = 1;

	if (priv->rgmii_rx_delay[port]) {
		pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
		/* The "BYPASS" bit in SJA1110 is actually a "don't bypass" */
		pad_mii_id.rxc_bypass = 1;
		pad_mii_id.rxc_pd = 0;
	}

	if (priv->rgmii_tx_delay[port]) {
		pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
		pad_mii_id.txc_bypass = 1;
		pad_mii_id.txc_pd = 0;
	}

	sja1110_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);

	return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
				packed_buf, SJA1105_SIZE_CGU_CMD);
}

static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
					sja1105_mii_role_t role)
{
@@ -755,3 +820,29 @@ int sja1105_clocking_setup(struct sja1105_private *priv)
	}
	return 0;
}

static void
sja1110_cgu_outclk_packing(void *buf, struct sja1110_cgu_outclk *outclk,
			   enum packing_op op)
{
	const int size = 4;

	sja1105_packing(buf, &outclk->clksrc,    27, 24, size, op);
	sja1105_packing(buf, &outclk->autoblock, 11, 11, size, op);
	sja1105_packing(buf, &outclk->pd,         0,  0, size, op);
}

/* Power down the BASE_TIMER_CLK in order to disable the watchdog */
int sja1110_clocking_setup(struct sja1105_private *priv)
{
	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
	struct sja1110_cgu_outclk outclk_7_c = {
		.clksrc = 0x5,
		.pd = true,
	};

	sja1110_cgu_outclk_packing(packed_buf, &outclk_7_c, PACK);

	return sja1105_xfer_buf(priv, SPI_WRITE, SJA1110_BASE_TIMER_CLK,
				packed_buf, SJA1105_SIZE_CGU_CMD);
}
+320 −1
Original line number Diff line number Diff line
@@ -106,6 +106,9 @@
#define SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_VL_LOOKUP_ENTRY)

#define SJA1110_SIZE_VL_POLICING_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_VL_POLICING_ENTRY)

#define SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY			\
	SJA1105_SIZE_DYN_CMD

@@ -115,9 +118,15 @@
#define SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY)

#define SJA1110_SIZE_L2_LOOKUP_DYN_CMD				\
	(SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_L2_LOOKUP_ENTRY)

#define SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + 4 + SJA1105_SIZE_VLAN_LOOKUP_ENTRY)

#define SJA1110_SIZE_VLAN_LOOKUP_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_VLAN_LOOKUP_ENTRY)

#define SJA1105_SIZE_L2_FORWARDING_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_FORWARDING_ENTRY)

@@ -133,12 +142,18 @@
#define SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD		\
	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY)

#define SJA1110_SIZE_L2_LOOKUP_PARAMS_DYN_CMD		\
	(SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_L2_LOOKUP_PARAMS_ENTRY)

#define SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD			\
	SJA1105_SIZE_DYN_CMD

#define SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY)

#define SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_GENERAL_PARAMS_ENTRY)

#define SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY)

@@ -151,8 +166,17 @@
#define SJA1105PQRS_SIZE_CBS_DYN_CMD				\
	(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_CBS_ENTRY)

#define SJA1110_SIZE_XMII_PARAMS_DYN_CMD			\
	SJA1110_SIZE_XMII_PARAMS_ENTRY

#define SJA1110_SIZE_L2_POLICING_DYN_CMD			\
	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_POLICING_ENTRY)

#define SJA1110_SIZE_L2_FORWARDING_PARAMS_DYN_CMD		\
	SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY

#define SJA1105_MAX_DYN_CMD_SIZE				\
	SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD
	SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD

struct sja1105_dyn_cmd {
	bool search;
@@ -197,6 +221,19 @@ sja1105pqrs_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
	sja1105_packing(p, &cmd->index,    9,  0, size, op);
}

static void
sja1110_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
			      enum packing_op op)
{
	u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
	sja1105_packing(p, &cmd->index,   11,  0, size, op);
}

static size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
						enum packing_op op)
{
@@ -208,6 +245,18 @@ static size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
	return size;
}

static void
sja1110_vl_policing_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				enum packing_op op)
{
	u8 *p = buf + SJA1105_SIZE_VL_LOOKUP_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->index,   11,  0, size, op);
}

static void
sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				  enum packing_op op)
@@ -326,6 +375,18 @@ sja1105pqrs_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
	return sja1105pqrs_l2_lookup_entry_packing(buf, entry_ptr, op);
}

static size_t sja1110_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
						  enum packing_op op)
{
	struct sja1105_l2_lookup_entry *entry = entry_ptr;
	u8 *cmd = buf + SJA1110_SIZE_L2_LOOKUP_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);

	return sja1110_l2_lookup_entry_packing(buf, entry_ptr, op);
}

static void
sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				enum packing_op op)
@@ -437,6 +498,39 @@ sja1105_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
			SJA1105_SIZE_VLAN_LOOKUP_ENTRY, op);
}

/* In SJA1110 there is no gap between the command and the data, yay... */
static void
sja1110_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				enum packing_op op)
{
	u8 *p = buf + SJA1110_SIZE_VLAN_LOOKUP_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;
	u64 type_entry = 0;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
	/* Hack: treat 'vlanid' field of struct sja1105_vlan_lookup_entry as
	 * cmd->index.
	 */
	sja1105_packing(buf, &cmd->index, 38, 27,
			SJA1110_SIZE_VLAN_LOOKUP_ENTRY, op);

	/* But the VALIDENT bit has disappeared, now we are supposed to
	 * invalidate an entry through the TYPE_ENTRY field of the entry..
	 * This is a hack to transform the non-zero quality of the TYPE_ENTRY
	 * field into a VALIDENT bit.
	 */
	if (op == PACK && !cmd->valident) {
		sja1105_packing(buf, &type_entry, 40, 39,
				SJA1110_SIZE_VLAN_LOOKUP_ENTRY, PACK);
	} else if (op == UNPACK) {
		sja1105_packing(buf, &type_entry, 40, 39,
				SJA1110_SIZE_VLAN_LOOKUP_ENTRY, UNPACK);
		cmd->valident = !!type_entry;
	}
}

static void
sja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				  enum packing_op op)
@@ -450,6 +544,19 @@ sja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
	sja1105_packing(p, &cmd->index,    4,  0, size, op);
}

static void
sja1110_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				  enum packing_op op)
{
	u8 *p = buf + SJA1105_SIZE_L2_FORWARDING_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
	sja1105_packing(p, &cmd->index,    4,  0, size, op);
}

static void
sja1105et_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				 enum packing_op op)
@@ -504,6 +611,19 @@ sja1105pqrs_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
	sja1105_packing(p, &cmd->index,    2,  0, size, op);
}

static void
sja1110_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
			       enum packing_op op)
{
	u8 *p = buf + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
	sja1105_packing(p, &cmd->index,    3,  0, size, op);
}

static void
sja1105et_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				       enum packing_op op)
@@ -536,6 +656,18 @@ sja1105pqrs_l2_lookup_params_cmd_packing(void *buf,
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
}

static void
sja1110_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				     enum packing_op op)
{
	u8 *p = buf + SJA1110_SIZE_L2_LOOKUP_PARAMS_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
}

static void
sja1105et_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				     enum packing_op op)
@@ -570,6 +702,18 @@ sja1105pqrs_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
	sja1105_packing(p, &cmd->rdwrset, 28, 28, size, op);
}

static void
sja1110_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				   enum packing_op op)
{
	u8 *p = buf + SJA1110_SIZE_GENERAL_PARAMS_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
}

static void
sja1105pqrs_avb_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				   enum packing_op op)
@@ -596,6 +740,20 @@ sja1105_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
	sja1105_packing(p, &cmd->index,     5,  0, size, op);
}

static void
sja1110_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
			      enum packing_op op)
{
	u8 *p = buf + SJA1105_SIZE_RETAGGING_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,    31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset,  30, 30, size, op);
	sja1105_packing(p, &cmd->errors,   29, 29, size, op);
	sja1105_packing(p, &cmd->valident, 28, 28, size, op);
	sja1105_packing(p, &cmd->index,     4,  0, size, op);
}

static void sja1105et_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				      enum packing_op op)
{
@@ -635,6 +793,18 @@ static void sja1105pqrs_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
	sja1105_packing(p, &cmd->index,    3,  0, size, op);
}

static void sja1110_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				    enum packing_op op)
{
	u8 *p = buf + SJA1105PQRS_SIZE_CBS_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
	sja1105_packing(p, &cmd->index,    7,  0, size, op);
}

static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
					    enum packing_op op)
{
@@ -650,6 +820,39 @@ static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
	return size;
}

static size_t sja1110_cbs_entry_packing(void *buf, void *entry_ptr,
					enum packing_op op)
{
	const size_t size = SJA1105PQRS_SIZE_CBS_ENTRY;
	struct sja1105_cbs_entry *entry = entry_ptr;
	u64 entry_type = SJA1110_CBS_SHAPER;

	sja1105_packing(buf, &entry_type,       159, 159, size, op);
	sja1105_packing(buf, &entry->credit_lo, 151, 120, size, op);
	sja1105_packing(buf, &entry->credit_hi, 119,  88, size, op);
	sja1105_packing(buf, &entry->send_slope, 87,  56, size, op);
	sja1105_packing(buf, &entry->idle_slope, 55,  24, size, op);
	return size;
}

static void sja1110_dummy_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				      enum packing_op op)
{
}

static void
sja1110_l2_policing_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				enum packing_op op)
{
	u8 *p = buf + SJA1105_SIZE_L2_POLICING_ENTRY;
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(p, &cmd->valid,   31, 31, size, op);
	sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
	sja1105_packing(p, &cmd->errors,  29, 29, size, op);
	sja1105_packing(p, &cmd->index,    6,  0, size, op);
}

#define OP_READ		BIT(0)
#define OP_WRITE	BIT(1)
#define OP_DEL		BIT(2)
@@ -832,6 +1035,122 @@ const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
	},
};

/* SJA1110: Third generation */
const struct sja1105_dynamic_table_ops sja1110_dyn_ops[BLK_IDX_MAX_DYN] = {
	[BLK_IDX_VL_LOOKUP] = {
		.entry_packing = sja1110_vl_lookup_entry_packing,
		.cmd_packing = sja1110_vl_lookup_cmd_packing,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.max_entry_count = SJA1110_MAX_VL_LOOKUP_COUNT,
		.packed_size = SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x124),
	},
	[BLK_IDX_VL_POLICING] = {
		.entry_packing = sja1110_vl_policing_entry_packing,
		.cmd_packing = sja1110_vl_policing_cmd_packing,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.max_entry_count = SJA1110_MAX_VL_POLICING_COUNT,
		.packed_size = SJA1110_SIZE_VL_POLICING_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x310),
	},
	[BLK_IDX_L2_LOOKUP] = {
		.entry_packing = sja1110_dyn_l2_lookup_entry_packing,
		.cmd_packing = sja1105pqrs_l2_lookup_cmd_packing,
		.access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
		.max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
		.packed_size = SJA1110_SIZE_L2_LOOKUP_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x8c),
	},
	[BLK_IDX_VLAN_LOOKUP] = {
		.entry_packing = sja1110_vlan_lookup_entry_packing,
		.cmd_packing = sja1110_vlan_lookup_cmd_packing,
		.access = (OP_READ | OP_WRITE | OP_DEL),
		.max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
		.packed_size = SJA1110_SIZE_VLAN_LOOKUP_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0xb4),
	},
	[BLK_IDX_L2_FORWARDING] = {
		.entry_packing = sja1110_l2_forwarding_entry_packing,
		.cmd_packing = sja1110_l2_forwarding_cmd_packing,
		.max_entry_count = SJA1110_MAX_L2_FORWARDING_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0xa8),
	},
	[BLK_IDX_MAC_CONFIG] = {
		.entry_packing = sja1110_mac_config_entry_packing,
		.cmd_packing = sja1110_mac_config_cmd_packing,
		.max_entry_count = SJA1110_MAX_MAC_CONFIG_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x134),
	},
	[BLK_IDX_L2_LOOKUP_PARAMS] = {
		.entry_packing = sja1110_l2_lookup_params_entry_packing,
		.cmd_packing = sja1110_l2_lookup_params_cmd_packing,
		.max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1110_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x158),
	},
	[BLK_IDX_AVB_PARAMS] = {
		.entry_packing = sja1105pqrs_avb_params_entry_packing,
		.cmd_packing = sja1105pqrs_avb_params_cmd_packing,
		.max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x2000C),
	},
	[BLK_IDX_GENERAL_PARAMS] = {
		.entry_packing = sja1110_general_params_entry_packing,
		.cmd_packing = sja1110_general_params_cmd_packing,
		.max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0xe8),
	},
	[BLK_IDX_RETAGGING] = {
		.entry_packing = sja1110_retagging_entry_packing,
		.cmd_packing = sja1110_retagging_cmd_packing,
		.max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
		.access = (OP_READ | OP_WRITE | OP_DEL),
		.packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0xdc),
	},
	[BLK_IDX_CBS] = {
		.entry_packing = sja1110_cbs_entry_packing,
		.cmd_packing = sja1110_cbs_cmd_packing,
		.max_entry_count = SJA1110_MAX_CBS_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1105PQRS_SIZE_CBS_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0xc4),
	},
	[BLK_IDX_XMII_PARAMS] = {
		.entry_packing = sja1110_xmii_params_entry_packing,
		.cmd_packing = sja1110_dummy_cmd_packing,
		.max_entry_count = SJA1105_MAX_XMII_PARAMS_COUNT,
		.access = (OP_READ | OP_VALID_ANYWAY),
		.packed_size = SJA1110_SIZE_XMII_PARAMS_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x3c),
	},
	[BLK_IDX_L2_POLICING] = {
		.entry_packing = sja1110_l2_policing_entry_packing,
		.cmd_packing = sja1110_l2_policing_cmd_packing,
		.max_entry_count = SJA1110_MAX_L2_POLICING_COUNT,
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.packed_size = SJA1110_SIZE_L2_POLICING_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x2fc),
	},
	[BLK_IDX_L2_FORWARDING_PARAMS] = {
		.entry_packing = sja1110_l2_forwarding_params_entry_packing,
		.cmd_packing = sja1110_dummy_cmd_packing,
		.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
		.access = (OP_READ | OP_VALID_ANYWAY),
		.packed_size = SJA1110_SIZE_L2_FORWARDING_PARAMS_DYN_CMD,
		.addr = SJA1110_SPI_ADDR(0x20000),
	},
};

/* Provides read access to the settings through the dynamic interface
 * of the switch.
 * @blk_idx	is used as key to select from the sja1105_dynamic_table_ops.
Loading