1 // SPDX-License-Identifier: GPL-2.0
2 /* ICSSG Ethernet driver
4 * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com
7 #include <linux/iopoll.h>
8 #include <linux/regmap.h>
9 #include <uapi/linux/if_ether.h>
10 #include "icssg_config.h"
11 #include "icssg_prueth.h"
12 #include "icssg_switch_map.h"
13 #include "icssg_mii_rt.h"
15 /* TX IPG Values to be set for 100M link speed. These values are
16 * in ocp_clk cycles. So need change if ocp_clk is changed for a specific
20 /* IPG is in core_clk cycles */
21 #define MII_RT_TX_IPG_100M 0x17
22 #define MII_RT_TX_IPG_1G 0xb
23 #define MII_RT_TX_IPG_100M_SR1 0x166
24 #define MII_RT_TX_IPG_1G_SR1 0x1a
26 #define ICSSG_QUEUES_MAX 64
27 #define ICSSG_QUEUE_OFFSET 0xd00
28 #define ICSSG_QUEUE_PEEK_OFFSET 0xe00
29 #define ICSSG_QUEUE_CNT_OFFSET 0xe40
30 #define ICSSG_QUEUE_RESET_OFFSET 0xf40
32 #define ICSSG_NUM_TX_QUEUES 8
34 #define RECYCLE_Q_SLICE0 16
35 #define RECYCLE_Q_SLICE1 17
37 #define ICSSG_NUM_OTHER_QUEUES 5 /* port, host and special queues */
39 #define PORT_HI_Q_SLICE0 32
40 #define PORT_LO_Q_SLICE0 33
41 #define HOST_HI_Q_SLICE0 34
42 #define HOST_LO_Q_SLICE0 35
43 #define HOST_SPL_Q_SLICE0 40 /* Special Queue */
45 #define PORT_HI_Q_SLICE1 36
46 #define PORT_LO_Q_SLICE1 37
47 #define HOST_HI_Q_SLICE1 38
48 #define HOST_LO_Q_SLICE1 39
49 #define HOST_SPL_Q_SLICE1 41 /* Special Queue */
51 #define MII_RXCFG_DEFAULT (PRUSS_MII_RT_RXCFG_RX_ENABLE | \
52 PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS | \
53 PRUSS_MII_RT_RXCFG_RX_L2_EN | \
54 PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS)
56 #define MII_TXCFG_DEFAULT (PRUSS_MII_RT_TXCFG_TX_ENABLE | \
57 PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE | \
58 PRUSS_MII_RT_TXCFG_TX_32_MODE_EN | \
59 PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN)
61 #define ICSSG_CFG_DEFAULT (ICSSG_CFG_TX_L1_EN | \
62 ICSSG_CFG_TX_L2_EN | ICSSG_CFG_RX_L2_G_EN | \
63 ICSSG_CFG_TX_PRU_EN | \
66 #define FDB_GEN_CFG1 0x60
67 #define SMEM_VLAN_OFFSET 8
68 #define SMEM_VLAN_OFFSET_MASK GENMASK(25, 8)
70 #define FDB_GEN_CFG2 0x64
71 #define FDB_VLAN_EN BIT(6)
72 #define FDB_HOST_EN BIT(2)
73 #define FDB_PRU1_EN BIT(1)
74 #define FDB_PRU0_EN BIT(0)
75 #define FDB_EN_ALL (FDB_PRU0_EN | FDB_PRU1_EN | \
76 FDB_HOST_EN | FDB_VLAN_EN)
79 * struct map - ICSSG Queue Map
80 * @queue: Queue number
81 * @pd_addr_start: Packet descriptor queue reserved memory
83 * @special: Indicates whether this queue is a special queue or not
92 /* Hardware queue map for ICSSG */
93 static const struct map hwq_map
[2][ICSSG_NUM_OTHER_QUEUES
] = {
95 { PORT_HI_Q_SLICE0
, PORT_DESC0_HI
, 0x200000, 0 },
96 { PORT_LO_Q_SLICE0
, PORT_DESC0_LO
, 0, 0 },
97 { HOST_HI_Q_SLICE0
, HOST_DESC0_HI
, 0x200000, 0 },
98 { HOST_LO_Q_SLICE0
, HOST_DESC0_LO
, 0, 0 },
99 { HOST_SPL_Q_SLICE0
, HOST_SPPD0
, 0x400000, 1 },
102 { PORT_HI_Q_SLICE1
, PORT_DESC1_HI
, 0xa00000, 0 },
103 { PORT_LO_Q_SLICE1
, PORT_DESC1_LO
, 0x800000, 0 },
104 { HOST_HI_Q_SLICE1
, HOST_DESC1_HI
, 0xa00000, 0 },
105 { HOST_LO_Q_SLICE1
, HOST_DESC1_LO
, 0x800000, 0 },
106 { HOST_SPL_Q_SLICE1
, HOST_SPPD1
, 0xc00000, 1 },
110 static void icssg_config_mii_init_fw_offload(struct prueth_emac
*emac
)
112 struct prueth
*prueth
= emac
->prueth
;
113 int mii
= prueth_emac_slice(emac
);
114 u32 txcfg_reg
, pcnt_reg
, txcfg
;
115 struct regmap
*mii_rt
;
117 mii_rt
= prueth
->mii_rt
;
119 txcfg_reg
= (mii
== ICSS_MII0
) ? PRUSS_MII_RT_TXCFG0
:
121 pcnt_reg
= (mii
== ICSS_MII0
) ? PRUSS_MII_RT_RX_PCNT0
:
122 PRUSS_MII_RT_RX_PCNT1
;
124 txcfg
= PRUSS_MII_RT_TXCFG_TX_ENABLE
|
125 PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE
|
126 PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN
;
128 if (emac
->phy_if
== PHY_INTERFACE_MODE_MII
&& mii
== ICSS_MII1
)
129 txcfg
|= PRUSS_MII_RT_TXCFG_TX_MUX_SEL
;
130 else if (emac
->phy_if
!= PHY_INTERFACE_MODE_MII
&& mii
== ICSS_MII0
)
131 txcfg
|= PRUSS_MII_RT_TXCFG_TX_MUX_SEL
;
133 regmap_write(mii_rt
, txcfg_reg
, txcfg
);
134 regmap_write(mii_rt
, pcnt_reg
, 0x1);
137 static void icssg_config_mii_init(struct prueth_emac
*emac
)
139 struct prueth
*prueth
= emac
->prueth
;
140 int slice
= prueth_emac_slice(emac
);
141 u32 txcfg
, txcfg_reg
, pcnt_reg
;
142 struct regmap
*mii_rt
;
144 mii_rt
= prueth
->mii_rt
;
146 txcfg_reg
= (slice
== ICSS_MII0
) ? PRUSS_MII_RT_TXCFG0
:
148 pcnt_reg
= (slice
== ICSS_MII0
) ? PRUSS_MII_RT_RX_PCNT0
:
149 PRUSS_MII_RT_RX_PCNT1
;
151 txcfg
= MII_TXCFG_DEFAULT
;
153 /* In MII mode TX lines swapped inside ICSSG, so TX_MUX_SEL cfg need
154 * to be swapped also comparing to RGMII mode.
156 if (emac
->phy_if
== PHY_INTERFACE_MODE_MII
&& slice
== ICSS_MII0
)
157 txcfg
|= PRUSS_MII_RT_TXCFG_TX_MUX_SEL
;
158 else if (emac
->phy_if
!= PHY_INTERFACE_MODE_MII
&& slice
== ICSS_MII1
)
159 txcfg
|= PRUSS_MII_RT_TXCFG_TX_MUX_SEL
;
161 regmap_write(mii_rt
, txcfg_reg
, txcfg
);
162 regmap_write(mii_rt
, pcnt_reg
, 0x1);
165 static void icssg_miig_queues_init(struct prueth
*prueth
, int slice
)
167 struct regmap
*miig_rt
= prueth
->miig_rt
;
168 void __iomem
*smem
= prueth
->shram
.va
;
169 u8 pd
[ICSSG_SPECIAL_PD_SIZE
];
175 queue
= ICSSG_NUM_TX_QUEUES
;
177 for (i
= 0; i
< ICSSG_NUM_TX_QUEUES
; i
++) {
178 regmap_write(miig_rt
, ICSSG_QUEUE_RESET_OFFSET
, queue
);
182 queue
= slice
? RECYCLE_Q_SLICE1
: RECYCLE_Q_SLICE0
;
183 regmap_write(miig_rt
, ICSSG_QUEUE_RESET_OFFSET
, queue
);
185 for (i
= 0; i
< ICSSG_NUM_OTHER_QUEUES
; i
++) {
186 regmap_write(miig_rt
, ICSSG_QUEUE_RESET_OFFSET
,
187 hwq_map
[slice
][i
].queue
);
190 /* initialize packet descriptors in SMEM */
191 /* push pakcet descriptors to hwqueues */
194 for (j
= 0; j
< ICSSG_NUM_OTHER_QUEUES
; j
++) {
195 const struct map
*mp
;
196 int pd_size
, num_pds
;
199 mp
= &hwq_map
[slice
][j
];
201 pd_size
= ICSSG_SPECIAL_PD_SIZE
;
202 num_pds
= ICSSG_NUM_SPECIAL_PDS
;
204 pd_size
= ICSSG_NORMAL_PD_SIZE
;
205 num_pds
= ICSSG_NUM_NORMAL_PDS
;
208 for (i
= 0; i
< num_pds
; i
++) {
209 memset(pd
, 0, pd_size
);
211 pdword
[0] &= ICSSG_FLAG_MASK
;
212 pdword
[0] |= mp
->flags
;
213 pdaddr
= mp
->pd_addr_start
+ i
* pd_size
;
215 memcpy_toio(smem
+ pdaddr
, pd
, pd_size
);
217 regmap_write(miig_rt
, ICSSG_QUEUE_OFFSET
+ 4 * queue
,
223 void icssg_config_ipg(struct prueth_emac
*emac
)
225 struct prueth
*prueth
= emac
->prueth
;
226 int slice
= prueth_emac_slice(emac
);
229 switch (emac
->speed
) {
231 ipg
= emac
->is_sr1
? MII_RT_TX_IPG_1G_SR1
: MII_RT_TX_IPG_1G
;
234 ipg
= emac
->is_sr1
? MII_RT_TX_IPG_100M_SR1
: MII_RT_TX_IPG_100M
;
237 /* Firmware hardcodes IPG for SR1.0 */
240 /* IPG for 10M is same as 100M */
241 ipg
= MII_RT_TX_IPG_100M
;
244 /* Other links speeds not supported */
245 netdev_err(emac
->ndev
, "Unsupported link speed\n");
249 icssg_mii_update_ipg(prueth
->mii_rt
, slice
, ipg
);
251 EXPORT_SYMBOL_GPL(icssg_config_ipg
);
253 static void emac_r30_cmd_init(struct prueth_emac
*emac
)
255 struct icssg_r30_cmd __iomem
*p
;
258 p
= emac
->dram
.va
+ MGR_R30_CMD_OFFSET
;
260 for (i
= 0; i
< 4; i
++)
261 writel(EMAC_NONE
, &p
->cmd
[i
]);
264 static int emac_r30_is_done(struct prueth_emac
*emac
)
266 const struct icssg_r30_cmd __iomem
*p
;
270 p
= emac
->dram
.va
+ MGR_R30_CMD_OFFSET
;
272 for (i
= 0; i
< 4; i
++) {
273 cmd
= readl(&p
->cmd
[i
]);
274 if (cmd
!= EMAC_NONE
)
281 static int prueth_fw_offload_buffer_setup(struct prueth_emac
*emac
)
283 struct icssg_buffer_pool_cfg __iomem
*bpool_cfg
;
284 struct icssg_rxq_ctx __iomem
*rxq_ctx
;
285 struct prueth
*prueth
= emac
->prueth
;
286 int slice
= prueth_emac_slice(emac
);
290 addr
= lower_32_bits(prueth
->msmcram
.pa
);
292 addr
+= PRUETH_NUM_BUF_POOLS
* PRUETH_EMAC_BUF_POOL_SIZE
;
295 dev_warn(prueth
->dev
, "buffer pool needs to be 64KB aligned\n");
299 bpool_cfg
= emac
->dram
.va
+ BUFFER_POOL_0_ADDR_OFFSET
;
300 /* workaround for f/w bug. bpool 0 needs to be initialized */
301 for (i
= 0; i
< PRUETH_NUM_BUF_POOLS
; i
++) {
302 writel(addr
, &bpool_cfg
[i
].addr
);
303 writel(PRUETH_EMAC_BUF_POOL_SIZE
, &bpool_cfg
[i
].len
);
304 addr
+= PRUETH_EMAC_BUF_POOL_SIZE
;
308 addr
+= PRUETH_NUM_BUF_POOLS
* PRUETH_EMAC_BUF_POOL_SIZE
;
310 addr
+= PRUETH_SW_NUM_BUF_POOLS_HOST
* PRUETH_SW_BUF_POOL_SIZE_HOST
;
312 for (i
= PRUETH_NUM_BUF_POOLS
;
313 i
< 2 * PRUETH_SW_NUM_BUF_POOLS_HOST
+ PRUETH_NUM_BUF_POOLS
;
315 /* The driver only uses first 4 queues per PRU so only initialize them */
316 if (i
% PRUETH_SW_NUM_BUF_POOLS_HOST
< PRUETH_SW_NUM_BUF_POOLS_PER_PRU
) {
317 writel(addr
, &bpool_cfg
[i
].addr
);
318 writel(PRUETH_SW_BUF_POOL_SIZE_HOST
, &bpool_cfg
[i
].len
);
319 addr
+= PRUETH_SW_BUF_POOL_SIZE_HOST
;
321 writel(0, &bpool_cfg
[i
].addr
);
322 writel(0, &bpool_cfg
[i
].len
);
327 addr
+= PRUETH_SW_NUM_BUF_POOLS_HOST
* PRUETH_SW_BUF_POOL_SIZE_HOST
;
329 addr
+= PRUETH_EMAC_RX_CTX_BUF_SIZE
;
331 rxq_ctx
= emac
->dram
.va
+ HOST_RX_Q_PRE_CONTEXT_OFFSET
;
332 for (i
= 0; i
< 3; i
++)
333 writel(addr
, &rxq_ctx
->start
[i
]);
335 addr
+= PRUETH_EMAC_RX_CTX_BUF_SIZE
;
336 writel(addr
- SZ_2K
, &rxq_ctx
->end
);
341 static int prueth_emac_buffer_setup(struct prueth_emac
*emac
)
343 struct icssg_buffer_pool_cfg __iomem
*bpool_cfg
;
344 struct icssg_rxq_ctx __iomem
*rxq_ctx
;
345 struct prueth
*prueth
= emac
->prueth
;
346 int slice
= prueth_emac_slice(emac
);
350 /* Layout to have 64KB aligned buffer pool
351 * |BPOOL0|BPOOL1|RX_CTX0|RX_CTX1|
354 addr
= lower_32_bits(prueth
->msmcram
.pa
);
356 addr
+= PRUETH_NUM_BUF_POOLS
* PRUETH_EMAC_BUF_POOL_SIZE
;
359 dev_warn(prueth
->dev
, "buffer pool needs to be 64KB aligned\n");
363 bpool_cfg
= emac
->dram
.va
+ BUFFER_POOL_0_ADDR_OFFSET
;
364 /* workaround for f/w bug. bpool 0 needs to be initilalized */
365 writel(addr
, &bpool_cfg
[0].addr
);
366 writel(0, &bpool_cfg
[0].len
);
368 for (i
= PRUETH_EMAC_BUF_POOL_START
;
369 i
< PRUETH_EMAC_BUF_POOL_START
+ PRUETH_NUM_BUF_POOLS
;
371 writel(addr
, &bpool_cfg
[i
].addr
);
372 writel(PRUETH_EMAC_BUF_POOL_SIZE
, &bpool_cfg
[i
].len
);
373 addr
+= PRUETH_EMAC_BUF_POOL_SIZE
;
377 addr
+= PRUETH_NUM_BUF_POOLS
* PRUETH_EMAC_BUF_POOL_SIZE
;
379 addr
+= PRUETH_EMAC_RX_CTX_BUF_SIZE
* 2;
381 /* Pre-emptible RX buffer queue */
382 rxq_ctx
= emac
->dram
.va
+ HOST_RX_Q_PRE_CONTEXT_OFFSET
;
383 for (i
= 0; i
< 3; i
++)
384 writel(addr
, &rxq_ctx
->start
[i
]);
386 addr
+= PRUETH_EMAC_RX_CTX_BUF_SIZE
;
387 writel(addr
, &rxq_ctx
->end
);
389 /* Express RX buffer queue */
390 rxq_ctx
= emac
->dram
.va
+ HOST_RX_Q_EXP_CONTEXT_OFFSET
;
391 for (i
= 0; i
< 3; i
++)
392 writel(addr
, &rxq_ctx
->start
[i
]);
394 addr
+= PRUETH_EMAC_RX_CTX_BUF_SIZE
;
395 writel(addr
, &rxq_ctx
->end
);
400 static void icssg_init_emac_mode(struct prueth
*prueth
)
402 /* When the device is configured as a bridge and it is being brought
403 * back to the emac mode, the host mac address has to be set as 0.
405 u32 addr
= prueth
->shram
.pa
+ EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET
;
407 u8 mac
[ETH_ALEN
] = { 0 };
409 if (prueth
->emacs_initialized
)
412 /* Set VLAN TABLE address base */
413 regmap_update_bits(prueth
->miig_rt
, FDB_GEN_CFG1
, SMEM_VLAN_OFFSET_MASK
,
414 addr
<< SMEM_VLAN_OFFSET
);
415 /* Set enable VLAN aware mode, and FDBs for all PRUs */
416 regmap_write(prueth
->miig_rt
, FDB_GEN_CFG2
, (FDB_PRU0_EN
| FDB_PRU1_EN
| FDB_HOST_EN
));
417 prueth
->vlan_tbl
= (struct prueth_vlan_tbl __force
*)(prueth
->shram
.va
+
418 EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET
);
419 for (i
= 0; i
< SZ_4K
- 1; i
++) {
420 prueth
->vlan_tbl
[i
].fid
= i
;
421 prueth
->vlan_tbl
[i
].fid_c1
= 0;
423 /* Clear host MAC address */
424 icssg_class_set_host_mac_addr(prueth
->miig_rt
, mac
);
427 static void icssg_init_fw_offload_mode(struct prueth
*prueth
)
429 u32 addr
= prueth
->shram
.pa
+ EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET
;
432 if (prueth
->emacs_initialized
)
435 /* Set VLAN TABLE address base */
436 regmap_update_bits(prueth
->miig_rt
, FDB_GEN_CFG1
, SMEM_VLAN_OFFSET_MASK
,
437 addr
<< SMEM_VLAN_OFFSET
);
438 /* Set enable VLAN aware mode, and FDBs for all PRUs */
439 regmap_write(prueth
->miig_rt
, FDB_GEN_CFG2
, FDB_EN_ALL
);
440 prueth
->vlan_tbl
= (struct prueth_vlan_tbl __force
*)(prueth
->shram
.va
+
441 EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET
);
442 for (i
= 0; i
< SZ_4K
- 1; i
++) {
443 prueth
->vlan_tbl
[i
].fid
= i
;
444 prueth
->vlan_tbl
[i
].fid_c1
= 0;
447 if (prueth
->hw_bridge_dev
)
448 icssg_class_set_host_mac_addr(prueth
->miig_rt
, prueth
->hw_bridge_dev
->dev_addr
);
449 icssg_set_pvid(prueth
, prueth
->default_vlan
, PRUETH_PORT_HOST
);
452 int icssg_config(struct prueth
*prueth
, struct prueth_emac
*emac
, int slice
)
454 void __iomem
*config
= emac
->dram
.va
+ ICSSG_CONFIG_OFFSET
;
455 struct icssg_flow_cfg __iomem
*flow_cfg
;
458 if (prueth
->is_switch_mode
|| prueth
->is_hsr_offload_mode
)
459 icssg_init_fw_offload_mode(prueth
);
461 icssg_init_emac_mode(prueth
);
463 memset_io(config
, 0, TAS_GATE_MASK_LIST0
);
464 icssg_miig_queues_init(prueth
, slice
);
466 emac
->speed
= SPEED_1000
;
467 emac
->duplex
= DUPLEX_FULL
;
468 if (!phy_interface_mode_is_rgmii(emac
->phy_if
)) {
469 emac
->speed
= SPEED_100
;
470 emac
->duplex
= DUPLEX_FULL
;
472 regmap_update_bits(prueth
->miig_rt
, ICSSG_CFG_OFFSET
,
473 ICSSG_CFG_DEFAULT
, ICSSG_CFG_DEFAULT
);
474 icssg_miig_set_interface_mode(prueth
->miig_rt
, slice
, emac
->phy_if
);
475 if (prueth
->is_switch_mode
|| prueth
->is_hsr_offload_mode
)
476 icssg_config_mii_init_fw_offload(emac
);
478 icssg_config_mii_init(emac
);
479 icssg_config_ipg(emac
);
480 icssg_update_rgmii_cfg(prueth
->miig_rt
, emac
);
483 pruss_cfg_gpimode(prueth
->pruss
, prueth
->pru_id
[slice
],
486 /* enable XFR shift for PRU and RTU */
487 pruss_cfg_xfr_enable(prueth
->pruss
, PRU_TYPE_PRU
, true);
488 pruss_cfg_xfr_enable(prueth
->pruss
, PRU_TYPE_RTU
, true);
490 /* set C28 to 0x100 */
491 pru_rproc_set_ctable(prueth
->pru
[slice
], PRU_C28
, 0x100 << 8);
492 pru_rproc_set_ctable(prueth
->rtu
[slice
], PRU_C28
, 0x100 << 8);
493 pru_rproc_set_ctable(prueth
->txpru
[slice
], PRU_C28
, 0x100 << 8);
495 flow_cfg
= config
+ PSI_L_REGULAR_FLOW_ID_BASE_OFFSET
;
496 writew(emac
->rx_flow_id_base
, &flow_cfg
->rx_base_flow
);
497 writew(0, &flow_cfg
->mgm_base_flow
);
498 writeb(0, config
+ SPL_PKT_DEFAULT_PRIORITY
);
499 writeb(0, config
+ QUEUE_NUM_UNTAGGED
);
501 if (prueth
->is_switch_mode
|| prueth
->is_hsr_offload_mode
)
502 ret
= prueth_fw_offload_buffer_setup(emac
);
504 ret
= prueth_emac_buffer_setup(emac
);
508 emac_r30_cmd_init(emac
);
512 EXPORT_SYMBOL_GPL(icssg_config
);
514 /* Bitmask for ICSSG r30 commands */
515 static const struct icssg_r30_cmd emac_r32_bitmask
[] = {
516 {{0xffff0004, 0xffff0100, 0xffff0004, EMAC_NONE
}}, /* EMAC_PORT_DISABLE */
517 {{0xfffb0040, 0xfeff0200, 0xfeff0200, EMAC_NONE
}}, /* EMAC_PORT_BLOCK */
518 {{0xffbb0000, 0xfcff0000, 0xdcfb0000, EMAC_NONE
}}, /* EMAC_PORT_FORWARD */
519 {{0xffbb0000, 0xfcff0000, 0xfcff2000, EMAC_NONE
}}, /* EMAC_PORT_FORWARD_WO_LEARNING */
520 {{0xffff0001, EMAC_NONE
, EMAC_NONE
, EMAC_NONE
}}, /* ACCEPT ALL */
521 {{0xfffe0002, EMAC_NONE
, EMAC_NONE
, EMAC_NONE
}}, /* ACCEPT TAGGED */
522 {{0xfffc0000, EMAC_NONE
, EMAC_NONE
, EMAC_NONE
}}, /* ACCEPT UNTAGGED and PRIO */
523 {{EMAC_NONE
, 0xffff0020, EMAC_NONE
, EMAC_NONE
}}, /* TAS Trigger List change */
524 {{EMAC_NONE
, 0xdfff1000, EMAC_NONE
, EMAC_NONE
}}, /* TAS set state ENABLE*/
525 {{EMAC_NONE
, 0xefff2000, EMAC_NONE
, EMAC_NONE
}}, /* TAS set state RESET*/
526 {{EMAC_NONE
, 0xcfff0000, EMAC_NONE
, EMAC_NONE
}}, /* TAS set state DISABLE*/
527 {{EMAC_NONE
, EMAC_NONE
, 0xffff0400, EMAC_NONE
}}, /* UC flooding ENABLE*/
528 {{EMAC_NONE
, EMAC_NONE
, 0xfbff0000, EMAC_NONE
}}, /* UC flooding DISABLE*/
529 {{EMAC_NONE
, EMAC_NONE
, 0xffff0800, EMAC_NONE
}}, /* MC flooding ENABLE*/
530 {{EMAC_NONE
, EMAC_NONE
, 0xf7ff0000, EMAC_NONE
}}, /* MC flooding DISABLE*/
531 {{EMAC_NONE
, 0xffff4000, EMAC_NONE
, EMAC_NONE
}}, /* Preemption on Tx ENABLE*/
532 {{EMAC_NONE
, 0xbfff0000, EMAC_NONE
, EMAC_NONE
}}, /* Preemption on Tx DISABLE*/
533 {{0xffff0010, EMAC_NONE
, 0xffff0010, EMAC_NONE
}}, /* VLAN AWARE*/
534 {{0xffef0000, EMAC_NONE
, 0xffef0000, EMAC_NONE
}}, /* VLAN UNWARE*/
535 {{0xffff2000, EMAC_NONE
, EMAC_NONE
, EMAC_NONE
}}, /* HSR_RX_OFFLOAD_ENABLE */
536 {{0xdfff0000, EMAC_NONE
, EMAC_NONE
, EMAC_NONE
}} /* HSR_RX_OFFLOAD_DISABLE */
539 int icssg_set_port_state(struct prueth_emac
*emac
,
540 enum icssg_port_state_cmd cmd
)
542 struct icssg_r30_cmd __iomem
*p
;
543 int ret
= -ETIMEDOUT
;
547 p
= emac
->dram
.va
+ MGR_R30_CMD_OFFSET
;
549 if (cmd
>= ICSSG_EMAC_PORT_MAX_COMMANDS
) {
550 netdev_err(emac
->ndev
, "invalid port command\n");
554 /* only one command at a time allowed to firmware */
555 mutex_lock(&emac
->cmd_lock
);
557 for (i
= 0; i
< 4; i
++)
558 writel(emac_r32_bitmask
[cmd
].cmd
[i
], &p
->cmd
[i
]);
561 ret
= read_poll_timeout(emac_r30_is_done
, done
, done
== 1,
562 1000, 10000, false, emac
);
564 if (ret
== -ETIMEDOUT
)
565 netdev_err(emac
->ndev
, "timeout waiting for command done\n");
567 mutex_unlock(&emac
->cmd_lock
);
571 EXPORT_SYMBOL_GPL(icssg_set_port_state
);
573 void icssg_config_half_duplex(struct prueth_emac
*emac
)
577 if (!emac
->half_duplex
)
580 val
= get_random_u32();
581 writel(val
, emac
->dram
.va
+ HD_RAND_SEED_OFFSET
);
583 EXPORT_SYMBOL_GPL(icssg_config_half_duplex
);
585 void icssg_config_set_speed(struct prueth_emac
*emac
)
589 switch (emac
->speed
) {
591 fw_speed
= FW_LINK_SPEED_1G
;
594 fw_speed
= FW_LINK_SPEED_100M
;
597 fw_speed
= FW_LINK_SPEED_10M
;
600 /* Other links speeds not supported */
601 netdev_err(emac
->ndev
, "Unsupported link speed\n");
605 if (emac
->duplex
== DUPLEX_HALF
)
606 fw_speed
|= FW_LINK_SPEED_HD
;
608 writeb(fw_speed
, emac
->dram
.va
+ PORT_LINK_SPEED_OFFSET
);
610 EXPORT_SYMBOL_GPL(icssg_config_set_speed
);
612 int icssg_send_fdb_msg(struct prueth_emac
*emac
, struct mgmt_cmd
*cmd
,
613 struct mgmt_cmd_rsp
*rsp
)
615 struct prueth
*prueth
= emac
->prueth
;
616 int slice
= prueth_emac_slice(emac
);
619 addr
= icssg_queue_pop(prueth
, slice
== 0 ?
620 ICSSG_CMD_POP_SLICE0
: ICSSG_CMD_POP_SLICE1
);
624 /* First 4 bytes have FW owned buffer linking info which should
627 memcpy_toio(prueth
->shram
.va
+ addr
+ 4, cmd
, sizeof(*cmd
));
628 icssg_queue_push(prueth
, slice
== 0 ?
629 ICSSG_CMD_PUSH_SLICE0
: ICSSG_CMD_PUSH_SLICE1
, addr
);
630 ret
= read_poll_timeout(icssg_queue_pop
, addr
, addr
>= 0,
631 2000, 20000000, false, prueth
, slice
== 0 ?
632 ICSSG_RSP_POP_SLICE0
: ICSSG_RSP_POP_SLICE1
);
634 netdev_err(emac
->ndev
, "Timedout sending HWQ message\n");
638 memcpy_fromio(rsp
, prueth
->shram
.va
+ addr
, sizeof(*rsp
));
639 /* Return buffer back for to pool */
640 icssg_queue_push(prueth
, slice
== 0 ?
641 ICSSG_RSP_PUSH_SLICE0
: ICSSG_RSP_PUSH_SLICE1
, addr
);
645 EXPORT_SYMBOL_GPL(icssg_send_fdb_msg
);
647 static void icssg_fdb_setup(struct prueth_emac
*emac
, struct mgmt_cmd
*fdb_cmd
,
648 const unsigned char *addr
, u8 fid
, int cmd
)
650 int slice
= prueth_emac_slice(emac
);
651 u8 mac_fid
[ETH_ALEN
+ 2];
654 ether_addr_copy(mac_fid
, addr
);
656 /* 1-1 VID-FID mapping is already setup */
657 mac_fid
[ETH_ALEN
] = fid
;
658 mac_fid
[ETH_ALEN
+ 1] = 0;
660 fdb_slot
= bitrev32(crc32_le(0, mac_fid
, 8)) & PRUETH_SWITCH_FDB_MASK
;
662 fdb_cmd
->header
= ICSSG_FW_MGMT_CMD_HEADER
;
663 fdb_cmd
->type
= ICSSG_FW_MGMT_FDB_CMD_TYPE
;
664 fdb_cmd
->seqnum
= ++(emac
->prueth
->icssg_hwcmdseq
);
665 fdb_cmd
->param
= cmd
;
666 fdb_cmd
->param
|= (slice
<< 4);
668 memcpy(&fdb_cmd
->cmd_args
[0], addr
, 4);
669 memcpy(&fdb_cmd
->cmd_args
[1], &addr
[4], 2);
670 fdb_cmd
->cmd_args
[2] = fdb_slot
;
672 netdev_dbg(emac
->ndev
, "MAC %pM slot %X FID %X\n", addr
, fdb_slot
, fid
);
675 int icssg_fdb_add_del(struct prueth_emac
*emac
, const unsigned char *addr
,
676 u8 vid
, u8 fid_c2
, bool add
)
678 struct mgmt_cmd_rsp fdb_cmd_rsp
= { 0 };
679 struct mgmt_cmd fdb_cmd
= { 0 };
683 icssg_fdb_setup(emac
, &fdb_cmd
, addr
, fid
, add
? ICSS_CMD_ADD_FDB
: ICSS_CMD_DEL_FDB
);
685 fid_c2
|= ICSSG_FDB_ENTRY_VALID
;
686 fdb_cmd
.cmd_args
[1] |= ((fid
<< 16) | (fid_c2
<< 24));
688 ret
= icssg_send_fdb_msg(emac
, &fdb_cmd
, &fdb_cmd_rsp
);
692 WARN_ON(fdb_cmd
.seqnum
!= fdb_cmd_rsp
.seqnum
);
693 if (fdb_cmd_rsp
.status
== 1)
698 EXPORT_SYMBOL_GPL(icssg_fdb_add_del
);
700 int icssg_fdb_lookup(struct prueth_emac
*emac
, const unsigned char *addr
,
703 struct mgmt_cmd_rsp fdb_cmd_rsp
= { 0 };
704 struct mgmt_cmd fdb_cmd
= { 0 };
705 struct prueth_fdb_slot
*slot
;
709 icssg_fdb_setup(emac
, &fdb_cmd
, addr
, fid
, ICSS_CMD_GET_FDB_SLOT
);
711 fdb_cmd
.cmd_args
[1] |= fid
<< 16;
713 ret
= icssg_send_fdb_msg(emac
, &fdb_cmd
, &fdb_cmd_rsp
);
717 WARN_ON(fdb_cmd
.seqnum
!= fdb_cmd_rsp
.seqnum
);
719 slot
= (struct prueth_fdb_slot __force
*)(emac
->dram
.va
+ FDB_CMD_BUFFER
);
720 for (i
= 0; i
< 4; i
++) {
721 if (ether_addr_equal(addr
, slot
->mac
) && vid
== slot
->fid
)
722 return (slot
->fid_c2
& ~ICSSG_FDB_ENTRY_VALID
);
728 EXPORT_SYMBOL_GPL(icssg_fdb_lookup
);
730 void icssg_vtbl_modify(struct prueth_emac
*emac
, u8 vid
, u8 port_mask
,
731 u8 untag_mask
, bool add
)
733 struct prueth
*prueth
= emac
->prueth
;
734 struct prueth_vlan_tbl
*tbl
;
737 tbl
= prueth
->vlan_tbl
;
738 spin_lock(&prueth
->vtbl_lock
);
739 fid_c1
= tbl
[vid
].fid_c1
;
741 /* FID_C1: bit0..2 port membership mask,
742 * bit3..5 tagging mask for each port
743 * bit6 Stream VID (not handled currently)
744 * bit7 MC flood (not handled currently)
747 fid_c1
|= (port_mask
| port_mask
<< 3);
748 fid_c1
&= ~(untag_mask
<< 3);
750 fid_c1
&= ~(port_mask
| port_mask
<< 3);
753 tbl
[vid
].fid_c1
= fid_c1
;
754 spin_unlock(&prueth
->vtbl_lock
);
756 EXPORT_SYMBOL_GPL(icssg_vtbl_modify
);
758 u16
icssg_get_pvid(struct prueth_emac
*emac
)
760 struct prueth
*prueth
= emac
->prueth
;
763 if (emac
->port_id
== PRUETH_PORT_MII0
)
764 pvid
= readl(prueth
->shram
.va
+ EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET
);
766 pvid
= readl(prueth
->shram
.va
+ EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET
);
772 EXPORT_SYMBOL_GPL(icssg_get_pvid
);
774 void icssg_set_pvid(struct prueth
*prueth
, u8 vid
, u8 port
)
778 /* only 256 VLANs are supported */
779 pvid
= (u32 __force
)cpu_to_be32((ETH_P_8021Q
<< 16) | (vid
& 0xff));
781 if (port
== PRUETH_PORT_MII0
)
782 writel(pvid
, prueth
->shram
.va
+ EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET
);
783 else if (port
== PRUETH_PORT_MII1
)
784 writel(pvid
, prueth
->shram
.va
+ EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET
);
786 writel(pvid
, prueth
->shram
.va
+ EMAC_ICSSG_SWITCH_PORT0_DEFAULT_VLAN_OFFSET
);
788 EXPORT_SYMBOL_GPL(icssg_set_pvid
);