1// SPDX-License-Identifier: GPL-2.0
2/* ICSSG Ethernet driver
3 *
4 * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com
5 */
6
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"
14
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
17 * h/w design.
18 */
19
20/* IPG is in core_clk cycles */
21#define MII_RT_TX_IPG_100M 0x17
22#define MII_RT_TX_IPG_1G 0xb
23
24#define ICSSG_QUEUES_MAX 64
25#define ICSSG_QUEUE_OFFSET 0xd00
26#define ICSSG_QUEUE_PEEK_OFFSET 0xe00
27#define ICSSG_QUEUE_CNT_OFFSET 0xe40
28#define ICSSG_QUEUE_RESET_OFFSET 0xf40
29
30#define ICSSG_NUM_TX_QUEUES 8
31
32#define RECYCLE_Q_SLICE0 16
33#define RECYCLE_Q_SLICE1 17
34
35#define ICSSG_NUM_OTHER_QUEUES 5 /* port, host and special queues */
36
37#define PORT_HI_Q_SLICE0 32
38#define PORT_LO_Q_SLICE0 33
39#define HOST_HI_Q_SLICE0 34
40#define HOST_LO_Q_SLICE0 35
41#define HOST_SPL_Q_SLICE0 40 /* Special Queue */
42
43#define PORT_HI_Q_SLICE1 36
44#define PORT_LO_Q_SLICE1 37
45#define HOST_HI_Q_SLICE1 38
46#define HOST_LO_Q_SLICE1 39
47#define HOST_SPL_Q_SLICE1 41 /* Special Queue */
48
49#define MII_RXCFG_DEFAULT (PRUSS_MII_RT_RXCFG_RX_ENABLE | \
50 PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS | \
51 PRUSS_MII_RT_RXCFG_RX_L2_EN | \
52 PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS)
53
54#define MII_TXCFG_DEFAULT (PRUSS_MII_RT_TXCFG_TX_ENABLE | \
55 PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE | \
56 PRUSS_MII_RT_TXCFG_TX_32_MODE_EN | \
57 PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN)
58
59#define ICSSG_CFG_DEFAULT (ICSSG_CFG_TX_L1_EN | \
60 ICSSG_CFG_TX_L2_EN | ICSSG_CFG_RX_L2_G_EN | \
61 ICSSG_CFG_TX_PRU_EN | \
62 ICSSG_CFG_SGMII_MODE)
63
64#define FDB_GEN_CFG1 0x60
65#define SMEM_VLAN_OFFSET 8
66#define SMEM_VLAN_OFFSET_MASK GENMASK(25, 8)
67
68#define FDB_GEN_CFG2 0x64
69#define FDB_VLAN_EN BIT(6)
70#define FDB_HOST_EN BIT(2)
71#define FDB_PRU1_EN BIT(1)
72#define FDB_PRU0_EN BIT(0)
73#define FDB_EN_ALL (FDB_PRU0_EN | FDB_PRU1_EN | \
74 FDB_HOST_EN | FDB_VLAN_EN)
75
76/**
77 * struct map - ICSSG Queue Map
78 * @queue: Queue number
79 * @pd_addr_start: Packet descriptor queue reserved memory
80 * @flags: Flags
81 * @special: Indicates whether this queue is a special queue or not
82 */
83struct map {
84 int queue;
85 u32 pd_addr_start;
86 u32 flags;
87 bool special;
88};
89
90/* Hardware queue map for ICSSG */
91static const struct map hwq_map[2][ICSSG_NUM_OTHER_QUEUES] = {
92 {
93 { PORT_HI_Q_SLICE0, PORT_DESC0_HI, 0x200000, 0 },
94 { PORT_LO_Q_SLICE0, PORT_DESC0_LO, 0, 0 },
95 { HOST_HI_Q_SLICE0, HOST_DESC0_HI, 0x200000, 0 },
96 { HOST_LO_Q_SLICE0, HOST_DESC0_LO, 0, 0 },
97 { HOST_SPL_Q_SLICE0, HOST_SPPD0, 0x400000, 1 },
98 },
99 {
100 { PORT_HI_Q_SLICE1, PORT_DESC1_HI, 0xa00000, 0 },
101 { PORT_LO_Q_SLICE1, PORT_DESC1_LO, 0x800000, 0 },
102 { HOST_HI_Q_SLICE1, HOST_DESC1_HI, 0xa00000, 0 },
103 { HOST_LO_Q_SLICE1, HOST_DESC1_LO, 0x800000, 0 },
104 { HOST_SPL_Q_SLICE1, HOST_SPPD1, 0xc00000, 1 },
105 },
106};
107
108static void icssg_config_mii_init(struct prueth_emac *emac)
109{
110 u32 rxcfg, txcfg, rxcfg_reg, txcfg_reg, pcnt_reg;
111 struct prueth *prueth = emac->prueth;
112 int slice = prueth_emac_slice(emac);
113 struct regmap *mii_rt;
114
115 mii_rt = prueth->mii_rt;
116
117 rxcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RXCFG0 :
118 PRUSS_MII_RT_RXCFG1;
119 txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
120 PRUSS_MII_RT_TXCFG1;
121 pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
122 PRUSS_MII_RT_RX_PCNT1;
123
124 rxcfg = MII_RXCFG_DEFAULT;
125 txcfg = MII_TXCFG_DEFAULT;
126
127 if (slice == ICSS_MII1)
128 rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL;
129
130 /* In MII mode TX lines swapped inside ICSSG, so TX_MUX_SEL cfg need
131 * to be swapped also comparing to RGMII mode.
132 */
133 if (emac->phy_if == PHY_INTERFACE_MODE_MII && slice == ICSS_MII0)
134 txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
135 else if (emac->phy_if != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1)
136 txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
137
138 regmap_write(map: mii_rt, reg: rxcfg_reg, val: rxcfg);
139 regmap_write(map: mii_rt, reg: txcfg_reg, val: txcfg);
140 regmap_write(map: mii_rt, reg: pcnt_reg, val: 0x1);
141}
142
143static void icssg_miig_queues_init(struct prueth *prueth, int slice)
144{
145 struct regmap *miig_rt = prueth->miig_rt;
146 void __iomem *smem = prueth->shram.va;
147 u8 pd[ICSSG_SPECIAL_PD_SIZE];
148 int queue = 0, i, j;
149 u32 *pdword;
150
151 /* reset hwqueues */
152 if (slice)
153 queue = ICSSG_NUM_TX_QUEUES;
154
155 for (i = 0; i < ICSSG_NUM_TX_QUEUES; i++) {
156 regmap_write(map: miig_rt, ICSSG_QUEUE_RESET_OFFSET, val: queue);
157 queue++;
158 }
159
160 queue = slice ? RECYCLE_Q_SLICE1 : RECYCLE_Q_SLICE0;
161 regmap_write(map: miig_rt, ICSSG_QUEUE_RESET_OFFSET, val: queue);
162
163 for (i = 0; i < ICSSG_NUM_OTHER_QUEUES; i++) {
164 regmap_write(map: miig_rt, ICSSG_QUEUE_RESET_OFFSET,
165 val: hwq_map[slice][i].queue);
166 }
167
168 /* initialize packet descriptors in SMEM */
169 /* push pakcet descriptors to hwqueues */
170
171 pdword = (u32 *)pd;
172 for (j = 0; j < ICSSG_NUM_OTHER_QUEUES; j++) {
173 const struct map *mp;
174 int pd_size, num_pds;
175 u32 pdaddr;
176
177 mp = &hwq_map[slice][j];
178 if (mp->special) {
179 pd_size = ICSSG_SPECIAL_PD_SIZE;
180 num_pds = ICSSG_NUM_SPECIAL_PDS;
181 } else {
182 pd_size = ICSSG_NORMAL_PD_SIZE;
183 num_pds = ICSSG_NUM_NORMAL_PDS;
184 }
185
186 for (i = 0; i < num_pds; i++) {
187 memset(pd, 0, pd_size);
188
189 pdword[0] &= ICSSG_FLAG_MASK;
190 pdword[0] |= mp->flags;
191 pdaddr = mp->pd_addr_start + i * pd_size;
192
193 memcpy_toio(smem + pdaddr, pd, pd_size);
194 queue = mp->queue;
195 regmap_write(map: miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue,
196 val: pdaddr);
197 }
198 }
199}
200
201void icssg_config_ipg(struct prueth_emac *emac)
202{
203 struct prueth *prueth = emac->prueth;
204 int slice = prueth_emac_slice(emac);
205
206 switch (emac->speed) {
207 case SPEED_1000:
208 icssg_mii_update_ipg(mii_rt: prueth->mii_rt, mii: slice, MII_RT_TX_IPG_1G);
209 break;
210 case SPEED_100:
211 icssg_mii_update_ipg(mii_rt: prueth->mii_rt, mii: slice, MII_RT_TX_IPG_100M);
212 break;
213 case SPEED_10:
214 /* IPG for 10M is same as 100M */
215 icssg_mii_update_ipg(mii_rt: prueth->mii_rt, mii: slice, MII_RT_TX_IPG_100M);
216 break;
217 default:
218 /* Other links speeds not supported */
219 netdev_err(dev: emac->ndev, format: "Unsupported link speed\n");
220 return;
221 }
222}
223
224static void emac_r30_cmd_init(struct prueth_emac *emac)
225{
226 struct icssg_r30_cmd __iomem *p;
227 int i;
228
229 p = emac->dram.va + MGR_R30_CMD_OFFSET;
230
231 for (i = 0; i < 4; i++)
232 writel(EMAC_NONE, addr: &p->cmd[i]);
233}
234
235static int emac_r30_is_done(struct prueth_emac *emac)
236{
237 const struct icssg_r30_cmd __iomem *p;
238 u32 cmd;
239 int i;
240
241 p = emac->dram.va + MGR_R30_CMD_OFFSET;
242
243 for (i = 0; i < 4; i++) {
244 cmd = readl(addr: &p->cmd[i]);
245 if (cmd != EMAC_NONE)
246 return 0;
247 }
248
249 return 1;
250}
251
252static int prueth_emac_buffer_setup(struct prueth_emac *emac)
253{
254 struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
255 struct icssg_rxq_ctx __iomem *rxq_ctx;
256 struct prueth *prueth = emac->prueth;
257 int slice = prueth_emac_slice(emac);
258 u32 addr;
259 int i;
260
261 /* Layout to have 64KB aligned buffer pool
262 * |BPOOL0|BPOOL1|RX_CTX0|RX_CTX1|
263 */
264
265 addr = lower_32_bits(prueth->msmcram.pa);
266 if (slice)
267 addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
268
269 if (addr % SZ_64K) {
270 dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
271 return -EINVAL;
272 }
273
274 bpool_cfg = emac->dram.va + BUFFER_POOL_0_ADDR_OFFSET;
275 /* workaround for f/w bug. bpool 0 needs to be initilalized */
276 writel(val: addr, addr: &bpool_cfg[0].addr);
277 writel(val: 0, addr: &bpool_cfg[0].len);
278
279 for (i = PRUETH_EMAC_BUF_POOL_START;
280 i < PRUETH_EMAC_BUF_POOL_START + PRUETH_NUM_BUF_POOLS;
281 i++) {
282 writel(val: addr, addr: &bpool_cfg[i].addr);
283 writel(PRUETH_EMAC_BUF_POOL_SIZE, addr: &bpool_cfg[i].len);
284 addr += PRUETH_EMAC_BUF_POOL_SIZE;
285 }
286
287 if (!slice)
288 addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
289 else
290 addr += PRUETH_EMAC_RX_CTX_BUF_SIZE * 2;
291
292 /* Pre-emptible RX buffer queue */
293 rxq_ctx = emac->dram.va + HOST_RX_Q_PRE_CONTEXT_OFFSET;
294 for (i = 0; i < 3; i++)
295 writel(val: addr, addr: &rxq_ctx->start[i]);
296
297 addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
298 writel(val: addr, addr: &rxq_ctx->end);
299
300 /* Express RX buffer queue */
301 rxq_ctx = emac->dram.va + HOST_RX_Q_EXP_CONTEXT_OFFSET;
302 for (i = 0; i < 3; i++)
303 writel(val: addr, addr: &rxq_ctx->start[i]);
304
305 addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
306 writel(val: addr, addr: &rxq_ctx->end);
307
308 return 0;
309}
310
311static void icssg_init_emac_mode(struct prueth *prueth)
312{
313 /* When the device is configured as a bridge and it is being brought
314 * back to the emac mode, the host mac address has to be set as 0.
315 */
316 u8 mac[ETH_ALEN] = { 0 };
317
318 if (prueth->emacs_initialized)
319 return;
320
321 regmap_update_bits(map: prueth->miig_rt, FDB_GEN_CFG1,
322 SMEM_VLAN_OFFSET_MASK, val: 0);
323 regmap_write(map: prueth->miig_rt, FDB_GEN_CFG2, val: 0);
324 /* Clear host MAC address */
325 icssg_class_set_host_mac_addr(miig_rt: prueth->miig_rt, mac);
326}
327
328int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice)
329{
330 void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET;
331 struct icssg_flow_cfg __iomem *flow_cfg;
332 int ret;
333
334 icssg_init_emac_mode(prueth);
335
336 memset_io(config, 0, TAS_GATE_MASK_LIST0);
337 icssg_miig_queues_init(prueth, slice);
338
339 emac->speed = SPEED_1000;
340 emac->duplex = DUPLEX_FULL;
341 if (!phy_interface_mode_is_rgmii(mode: emac->phy_if)) {
342 emac->speed = SPEED_100;
343 emac->duplex = DUPLEX_FULL;
344 }
345 regmap_update_bits(map: prueth->miig_rt, ICSSG_CFG_OFFSET,
346 ICSSG_CFG_DEFAULT, ICSSG_CFG_DEFAULT);
347 icssg_miig_set_interface_mode(miig_rt: prueth->miig_rt, mii: slice, phy_if: emac->phy_if);
348 icssg_config_mii_init(emac);
349 icssg_config_ipg(emac);
350 icssg_update_rgmii_cfg(miig_rt: prueth->miig_rt, emac);
351
352 /* set GPI mode */
353 pruss_cfg_gpimode(pruss: prueth->pruss, pru_id: prueth->pru_id[slice],
354 mode: PRUSS_GPI_MODE_MII);
355
356 /* enable XFR shift for PRU and RTU */
357 pruss_cfg_xfr_enable(pruss: prueth->pruss, pru_type: PRU_TYPE_PRU, enable: true);
358 pruss_cfg_xfr_enable(pruss: prueth->pruss, pru_type: PRU_TYPE_RTU, enable: true);
359
360 /* set C28 to 0x100 */
361 pru_rproc_set_ctable(rproc: prueth->pru[slice], c: PRU_C28, addr: 0x100 << 8);
362 pru_rproc_set_ctable(rproc: prueth->rtu[slice], c: PRU_C28, addr: 0x100 << 8);
363 pru_rproc_set_ctable(rproc: prueth->txpru[slice], c: PRU_C28, addr: 0x100 << 8);
364
365 flow_cfg = config + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET;
366 writew(val: emac->rx_flow_id_base, addr: &flow_cfg->rx_base_flow);
367 writew(val: 0, addr: &flow_cfg->mgm_base_flow);
368 writeb(val: 0, addr: config + SPL_PKT_DEFAULT_PRIORITY);
369 writeb(val: 0, addr: config + QUEUE_NUM_UNTAGGED);
370
371 ret = prueth_emac_buffer_setup(emac);
372 if (ret)
373 return ret;
374
375 emac_r30_cmd_init(emac);
376
377 return 0;
378}
379
380/* Bitmask for ICSSG r30 commands */
381static const struct icssg_r30_cmd emac_r32_bitmask[] = {
382 {{0xffff0004, 0xffff0100, 0xffff0004, EMAC_NONE}}, /* EMAC_PORT_DISABLE */
383 {{0xfffb0040, 0xfeff0200, 0xfeff0200, EMAC_NONE}}, /* EMAC_PORT_BLOCK */
384 {{0xffbb0000, 0xfcff0000, 0xdcfb0000, EMAC_NONE}}, /* EMAC_PORT_FORWARD */
385 {{0xffbb0000, 0xfcff0000, 0xfcff2000, EMAC_NONE}}, /* EMAC_PORT_FORWARD_WO_LEARNING */
386 {{0xffff0001, EMAC_NONE, EMAC_NONE, EMAC_NONE}}, /* ACCEPT ALL */
387 {{0xfffe0002, EMAC_NONE, EMAC_NONE, EMAC_NONE}}, /* ACCEPT TAGGED */
388 {{0xfffc0000, EMAC_NONE, EMAC_NONE, EMAC_NONE}}, /* ACCEPT UNTAGGED and PRIO */
389 {{EMAC_NONE, 0xffff0020, EMAC_NONE, EMAC_NONE}}, /* TAS Trigger List change */
390 {{EMAC_NONE, 0xdfff1000, EMAC_NONE, EMAC_NONE}}, /* TAS set state ENABLE*/
391 {{EMAC_NONE, 0xefff2000, EMAC_NONE, EMAC_NONE}}, /* TAS set state RESET*/
392 {{EMAC_NONE, 0xcfff0000, EMAC_NONE, EMAC_NONE}}, /* TAS set state DISABLE*/
393 {{EMAC_NONE, EMAC_NONE, 0xffff0400, EMAC_NONE}}, /* UC flooding ENABLE*/
394 {{EMAC_NONE, EMAC_NONE, 0xfbff0000, EMAC_NONE}}, /* UC flooding DISABLE*/
395 {{EMAC_NONE, EMAC_NONE, 0xffff0800, EMAC_NONE}}, /* MC flooding ENABLE*/
396 {{EMAC_NONE, EMAC_NONE, 0xf7ff0000, EMAC_NONE}}, /* MC flooding DISABLE*/
397 {{EMAC_NONE, 0xffff4000, EMAC_NONE, EMAC_NONE}}, /* Preemption on Tx ENABLE*/
398 {{EMAC_NONE, 0xbfff0000, EMAC_NONE, EMAC_NONE}}, /* Preemption on Tx DISABLE*/
399 {{0xffff0010, EMAC_NONE, 0xffff0010, EMAC_NONE}}, /* VLAN AWARE*/
400 {{0xffef0000, EMAC_NONE, 0xffef0000, EMAC_NONE}} /* VLAN UNWARE*/
401};
402
403int emac_set_port_state(struct prueth_emac *emac,
404 enum icssg_port_state_cmd cmd)
405{
406 struct icssg_r30_cmd __iomem *p;
407 int ret = -ETIMEDOUT;
408 int done = 0;
409 int i;
410
411 p = emac->dram.va + MGR_R30_CMD_OFFSET;
412
413 if (cmd >= ICSSG_EMAC_PORT_MAX_COMMANDS) {
414 netdev_err(dev: emac->ndev, format: "invalid port command\n");
415 return -EINVAL;
416 }
417
418 /* only one command at a time allowed to firmware */
419 mutex_lock(&emac->cmd_lock);
420
421 for (i = 0; i < 4; i++)
422 writel(val: emac_r32_bitmask[cmd].cmd[i], addr: &p->cmd[i]);
423
424 /* wait for done */
425 ret = read_poll_timeout(emac_r30_is_done, done, done == 1,
426 1000, 10000, false, emac);
427
428 if (ret == -ETIMEDOUT)
429 netdev_err(dev: emac->ndev, format: "timeout waiting for command done\n");
430
431 mutex_unlock(lock: &emac->cmd_lock);
432
433 return ret;
434}
435
436void icssg_config_half_duplex(struct prueth_emac *emac)
437{
438 u32 val;
439
440 if (!emac->half_duplex)
441 return;
442
443 val = get_random_u32();
444 writel(val, addr: emac->dram.va + HD_RAND_SEED_OFFSET);
445}
446
447void icssg_config_set_speed(struct prueth_emac *emac)
448{
449 u8 fw_speed;
450
451 switch (emac->speed) {
452 case SPEED_1000:
453 fw_speed = FW_LINK_SPEED_1G;
454 break;
455 case SPEED_100:
456 fw_speed = FW_LINK_SPEED_100M;
457 break;
458 case SPEED_10:
459 fw_speed = FW_LINK_SPEED_10M;
460 break;
461 default:
462 /* Other links speeds not supported */
463 netdev_err(dev: emac->ndev, format: "Unsupported link speed\n");
464 return;
465 }
466
467 if (emac->duplex == DUPLEX_HALF)
468 fw_speed |= FW_LINK_SPEED_HD;
469
470 writeb(val: fw_speed, addr: emac->dram.va + PORT_LINK_SPEED_OFFSET);
471}
472

source code of linux/drivers/net/ethernet/ti/icssg/icssg_config.c