Skip to content

Commit 3e77e59

Browse files
vladimirolteandavem330
authored andcommitted
net: dsa: sja1105: add support for the SJA1110 switch family
The SJA1110 is basically an SJA1105 with more ports, some integrated PHYs (100base-T1 and 100base-TX) and an embedded microcontroller which can be disabled, and the switch core can be controlled by a host running Linux, over SPI. This patch contains: - the static and dynamic config packing functions, for the tables that are common with SJA1105 - one more static config tables which is "unique" to the SJA1110 (actually it is a rehash of stuff that was placed somewhere else in SJA1105): the PCP Remapping Table - a reset and clock configuration procedure for the SJA1110 switch. This resets just the switch subsystem, and gates off the clock which powers on the embedded microcontroller. - an RGMII delay configuration procedure for SJA1110, which is very similar to SJA1105, but different enough for us to be unable to reuse it (this is a pattern that repeats itself) - some adaptations to dynamic config table entries which are no longer programmed in the same way. For example, to delete a VLAN, you used to write an entry through the dynamic reconfiguration interface with the desired VLAN ID, and with the VALIDENT bit set to false. Now, the VLAN table entries contain a TYPE_ENTRY field, which must be set to zero (in a backwards-incompatible way) in order for the entry to be deleted, or to some other entry for the VLAN to match "inner tagged" or "outer tagged" packets. - a similar thing for the static config: the xMII Mode Parameters Table encoding for SGMII and MII (the latter just when attached to a 100base-TX PHY) just isn't what it used to be in SJA1105. They are identical, except there is an extra "special" bit which needs to be set. Set it. Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 070f5b7 commit 3e77e59

File tree

8 files changed

+1312
-12
lines changed

8 files changed

+1312
-12
lines changed

drivers/net/dsa/sja1105/sja1105.h

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,12 @@
1313
#include <linux/mutex.h>
1414
#include "sja1105_static_config.h"
1515

16-
#define SJA1105_NUM_PORTS 5
17-
#define SJA1105_MAX_NUM_PORTS SJA1105_NUM_PORTS
18-
#define SJA1105_NUM_TC 8
1916
#define SJA1105ET_FDB_BIN_SIZE 4
2017
/* The hardware value is in multiples of 10 ms.
2118
* The passed parameter is in multiples of 1 ms.
2219
*/
2320
#define SJA1105_AGEING_TIME_MS(ms) ((ms) / 10)
24-
#define SJA1105_NUM_L2_POLICERS 45
21+
#define SJA1105_NUM_L2_POLICERS SJA1110_MAX_L2_POLICING_COUNT
2522

2623
typedef enum {
2724
SPI_READ = 0,
@@ -99,6 +96,7 @@ struct sja1105_info {
9996
int ptpegr_ts_bytes;
10097
int num_cbs_shapers;
10198
int max_frame_mem;
99+
int num_ports;
102100
const struct sja1105_dynamic_table_ops *dyn_ops;
103101
const struct sja1105_table_ops *static_ops;
104102
const struct sja1105_regs *regs;
@@ -310,6 +308,10 @@ extern const struct sja1105_info sja1105p_info;
310308
extern const struct sja1105_info sja1105q_info;
311309
extern const struct sja1105_info sja1105r_info;
312310
extern const struct sja1105_info sja1105s_info;
311+
extern const struct sja1105_info sja1110a_info;
312+
extern const struct sja1105_info sja1110b_info;
313+
extern const struct sja1105_info sja1110c_info;
314+
extern const struct sja1105_info sja1110d_info;
313315

314316
/* From sja1105_clocking.c */
315317

@@ -326,8 +328,10 @@ typedef enum {
326328
} sja1105_phy_interface_t;
327329

328330
int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port);
331+
int sja1110_setup_rgmii_delay(const void *ctx, int port);
329332
int sja1105_clocking_setup_port(struct sja1105_private *priv, int port);
330333
int sja1105_clocking_setup(struct sja1105_private *priv);
334+
int sja1110_clocking_setup(struct sja1105_private *priv);
331335

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

355+
enum sja1110_vlan_type {
356+
SJA1110_VLAN_INVALID = 0,
357+
SJA1110_VLAN_C_TAG = 1, /* Single inner VLAN tag */
358+
SJA1110_VLAN_S_TAG = 2, /* Single outer VLAN tag */
359+
SJA1110_VLAN_D_TAG = 3, /* Double tagged, use outer tag for lookup */
360+
};
361+
362+
enum sja1110_shaper_type {
363+
SJA1110_LEAKY_BUCKET_SHAPER = 0,
364+
SJA1110_CBS_SHAPER = 1,
365+
};
366+
351367
u8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid);
352368
int sja1105et_fdb_add(struct dsa_switch *ds, int port,
353369
const unsigned char *addr, u16 vid);

drivers/net/dsa/sja1105/sja1105_clocking.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "sja1105.h"
77

88
#define SJA1105_SIZE_CGU_CMD 4
9+
#define SJA1110_BASE_TIMER_CLK SJA1110_CGU_ADDR(0x74)
910

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

65+
struct sja1110_cgu_outclk {
66+
u64 clksrc;
67+
u64 autoblock;
68+
u64 pd;
69+
};
70+
6471
enum {
6572
CLKSRC_MII0_TX_CLK = 0x00,
6673
CLKSRC_MII0_RX_CLK = 0x01,
@@ -461,6 +468,35 @@ sja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
461468
sja1105_packing(buf, &cmd->txc_pd, 0, 0, size, op);
462469
}
463470

471+
static void
472+
sja1110_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
473+
enum packing_op op)
474+
{
475+
const int size = SJA1105_SIZE_CGU_CMD;
476+
u64 range = 4;
477+
478+
/* Fields RXC_RANGE and TXC_RANGE select the input frequency range:
479+
* 0 = 2.5MHz
480+
* 1 = 25MHz
481+
* 2 = 50MHz
482+
* 3 = 125MHz
483+
* 4 = Automatically determined by port speed.
484+
* There's no point in defining a structure different than the one for
485+
* SJA1105, so just hardcode the frequency range to automatic, just as
486+
* before.
487+
*/
488+
sja1105_packing(buf, &cmd->rxc_stable_ovr, 26, 26, size, op);
489+
sja1105_packing(buf, &cmd->rxc_delay, 25, 21, size, op);
490+
sja1105_packing(buf, &range, 20, 18, size, op);
491+
sja1105_packing(buf, &cmd->rxc_bypass, 17, 17, size, op);
492+
sja1105_packing(buf, &cmd->rxc_pd, 16, 16, size, op);
493+
sja1105_packing(buf, &cmd->txc_stable_ovr, 10, 10, size, op);
494+
sja1105_packing(buf, &cmd->txc_delay, 9, 5, size, op);
495+
sja1105_packing(buf, &range, 4, 2, size, op);
496+
sja1105_packing(buf, &cmd->txc_bypass, 1, 1, size, op);
497+
sja1105_packing(buf, &cmd->txc_pd, 0, 0, size, op);
498+
}
499+
464500
/* Valid range in degrees is an integer between 73.8 and 101.7 */
465501
static u64 sja1105_rgmii_delay(u64 phase)
466502
{
@@ -519,6 +555,35 @@ int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port)
519555
packed_buf, SJA1105_SIZE_CGU_CMD);
520556
}
521557

558+
int sja1110_setup_rgmii_delay(const void *ctx, int port)
559+
{
560+
const struct sja1105_private *priv = ctx;
561+
const struct sja1105_regs *regs = priv->info->regs;
562+
struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
563+
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
564+
565+
pad_mii_id.rxc_pd = 1;
566+
pad_mii_id.txc_pd = 1;
567+
568+
if (priv->rgmii_rx_delay[port]) {
569+
pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
570+
/* The "BYPASS" bit in SJA1110 is actually a "don't bypass" */
571+
pad_mii_id.rxc_bypass = 1;
572+
pad_mii_id.rxc_pd = 0;
573+
}
574+
575+
if (priv->rgmii_tx_delay[port]) {
576+
pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
577+
pad_mii_id.txc_bypass = 1;
578+
pad_mii_id.txc_pd = 0;
579+
}
580+
581+
sja1110_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
582+
583+
return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
584+
packed_buf, SJA1105_SIZE_CGU_CMD);
585+
}
586+
522587
static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
523588
sja1105_mii_role_t role)
524589
{
@@ -755,3 +820,29 @@ int sja1105_clocking_setup(struct sja1105_private *priv)
755820
}
756821
return 0;
757822
}
823+
824+
static void
825+
sja1110_cgu_outclk_packing(void *buf, struct sja1110_cgu_outclk *outclk,
826+
enum packing_op op)
827+
{
828+
const int size = 4;
829+
830+
sja1105_packing(buf, &outclk->clksrc, 27, 24, size, op);
831+
sja1105_packing(buf, &outclk->autoblock, 11, 11, size, op);
832+
sja1105_packing(buf, &outclk->pd, 0, 0, size, op);
833+
}
834+
835+
/* Power down the BASE_TIMER_CLK in order to disable the watchdog */
836+
int sja1110_clocking_setup(struct sja1105_private *priv)
837+
{
838+
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
839+
struct sja1110_cgu_outclk outclk_7_c = {
840+
.clksrc = 0x5,
841+
.pd = true,
842+
};
843+
844+
sja1110_cgu_outclk_packing(packed_buf, &outclk_7_c, PACK);
845+
846+
return sja1105_xfer_buf(priv, SPI_WRITE, SJA1110_BASE_TIMER_CLK,
847+
packed_buf, SJA1105_SIZE_CGU_CMD);
848+
}

0 commit comments

Comments
 (0)