File Index
Files and directories
Sign in
FILE

icssg_config.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/ti/icssg/icssg_config.c C
  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#define MII_RT_TX_IPG_100M_SR1	0x166
 24#define MII_RT_TX_IPG_1G_SR1	0x1a
 25
 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
 31
 32#define	ICSSG_NUM_TX_QUEUES	8
 33
 34#define	RECYCLE_Q_SLICE0	16
 35#define	RECYCLE_Q_SLICE1	17
 36
 37#define	ICSSG_NUM_OTHER_QUEUES	5	/* port, host and special queues */
 38
 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 */
 44
 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 */
 50
 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)
 55
 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)
 60
 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 | \
 64				 ICSSG_CFG_SGMII_MODE)
 65
 66#define FDB_GEN_CFG1		0x60
 67#define SMEM_VLAN_OFFSET	8
 68#define SMEM_VLAN_OFFSET_MASK	GENMASK(25, 8)
 69#define FDB_HASH_SIZE_MASK	GENMASK(6, 3)
 70#define FDB_HASH_SIZE_SHIFT	3
 71#define FDB_HASH_SIZE		3
 72
 73#define FDB_GEN_CFG2		0x64
 74#define FDB_VLAN_EN		BIT(6)
 75#define FDB_HOST_EN		BIT(2)
 76#define FDB_PRU1_EN		BIT(1)
 77#define FDB_PRU0_EN		BIT(0)
 78#define FDB_EN_ALL		(FDB_PRU0_EN | FDB_PRU1_EN | \
 79				 FDB_HOST_EN | FDB_VLAN_EN)
 80
 81/**
 82 * struct map - ICSSG Queue Map
 83 * @queue: Queue number
 84 * @pd_addr_start: Packet descriptor queue reserved memory
 85 * @flags: Flags
 86 * @special: Indicates whether this queue is a special queue or not
 87 */
 88struct map {
 89	int queue;
 90	u32 pd_addr_start;
 91	u32 flags;
 92	bool special;
 93};
 94
 95/* Hardware queue map for ICSSG */
 96static const struct map hwq_map[2][ICSSG_NUM_OTHER_QUEUES] = {
 97	{
 98		{ PORT_HI_Q_SLICE0, PORT_DESC0_HI, 0x200000, 0 },
 99		{ PORT_LO_Q_SLICE0, PORT_DESC0_LO, 0, 0 },
100		{ HOST_HI_Q_SLICE0, HOST_DESC0_HI, 0x200000, 0 },
101		{ HOST_LO_Q_SLICE0, HOST_DESC0_LO, 0, 0 },
102		{ HOST_SPL_Q_SLICE0, HOST_SPPD0, 0x400000, 1 },
103	},
104	{
105		{ PORT_HI_Q_SLICE1, PORT_DESC1_HI, 0xa00000, 0 },
106		{ PORT_LO_Q_SLICE1, PORT_DESC1_LO, 0x800000, 0 },
107		{ HOST_HI_Q_SLICE1, HOST_DESC1_HI, 0xa00000, 0 },
108		{ HOST_LO_Q_SLICE1, HOST_DESC1_LO, 0x800000, 0 },
109		{ HOST_SPL_Q_SLICE1, HOST_SPPD1, 0xc00000, 1 },
110	},
111};
112
113static void icssg_config_mii_init_fw_offload(struct prueth_emac *emac)
114{
115	struct prueth *prueth = emac->prueth;
116	int mii = prueth_emac_slice(emac);
117	u32 txcfg_reg, pcnt_reg, txcfg;
118	struct regmap *mii_rt;
119
120	mii_rt = prueth->mii_rt;
121
122	txcfg_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
123				       PRUSS_MII_RT_TXCFG1;
124	pcnt_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
125				       PRUSS_MII_RT_RX_PCNT1;
126
127	txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE |
128		PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE |
129		PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN;
130
131	if (emac->phy_if == PHY_INTERFACE_MODE_MII && mii == ICSS_MII1)
132		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
133	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && mii == ICSS_MII0)
134		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
135
136	regmap_write(mii_rt, txcfg_reg, txcfg);
137	regmap_write(mii_rt, pcnt_reg, 0x1);
138}
139
140static void icssg_config_mii_init(struct prueth_emac *emac)
141{
142	struct prueth *prueth = emac->prueth;
143	int slice = prueth_emac_slice(emac);
144	u32 txcfg, txcfg_reg, pcnt_reg;
145	struct regmap *mii_rt;
146
147	mii_rt = prueth->mii_rt;
148
149	txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
150				       PRUSS_MII_RT_TXCFG1;
151	pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
152				       PRUSS_MII_RT_RX_PCNT1;
153
154	txcfg = MII_TXCFG_DEFAULT;
155
156	/* In MII mode TX lines swapped inside ICSSG, so TX_MUX_SEL cfg need
157	 * to be swapped also comparing to RGMII mode.
158	 */
159	if (emac->phy_if == PHY_INTERFACE_MODE_MII && slice == ICSS_MII0)
160		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
161	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1)
162		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
163
164	regmap_write(mii_rt, txcfg_reg, txcfg);
165	regmap_write(mii_rt, pcnt_reg, 0x1);
166}
167
168static void icssg_miig_queues_init(struct prueth *prueth, int slice)
169{
170	struct regmap *miig_rt = prueth->miig_rt;
171	void __iomem *smem = prueth->shram.va;
172	u8 pd[ICSSG_SPECIAL_PD_SIZE];
173	int queue = 0, i, j;
174	u32 *pdword;
175
176	/* reset hwqueues */
177	if (slice)
178		queue = ICSSG_NUM_TX_QUEUES;
179
180	for (i = 0; i < ICSSG_NUM_TX_QUEUES; i++) {
181		regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET, queue);
182		queue++;
183	}
184
185	queue = slice ? RECYCLE_Q_SLICE1 : RECYCLE_Q_SLICE0;
186	regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET, queue);
187
188	for (i = 0; i < ICSSG_NUM_OTHER_QUEUES; i++) {
189		regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET,
190			     hwq_map[slice][i].queue);
191	}
192
193	/* initialize packet descriptors in SMEM */
194	/* push pakcet descriptors to hwqueues */
195
196	pdword = (u32 *)pd;
197	for (j = 0; j < ICSSG_NUM_OTHER_QUEUES; j++) {
198		const struct map *mp;
199		int pd_size, num_pds;
200		u32 pdaddr;
201
202		mp = &hwq_map[slice][j];
203		if (mp->special) {
204			pd_size = ICSSG_SPECIAL_PD_SIZE;
205			num_pds = ICSSG_NUM_SPECIAL_PDS;
206		} else	{
207			pd_size = ICSSG_NORMAL_PD_SIZE;
208			num_pds = ICSSG_NUM_NORMAL_PDS;
209		}
210
211		for (i = 0; i < num_pds; i++) {
212			memset(pd, 0, pd_size);
213
214			pdword[0] &= ICSSG_FLAG_MASK;
215			pdword[0] |= mp->flags;
216			pdaddr = mp->pd_addr_start + i * pd_size;
217
218			memcpy_toio(smem + pdaddr, pd, pd_size);
219			queue = mp->queue;
220			regmap_write(miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue,
221				     pdaddr);
222		}
223	}
224}
225
226void icssg_config_ipg(struct prueth_emac *emac)
227{
228	struct prueth *prueth = emac->prueth;
229	int slice = prueth_emac_slice(emac);
230	u32 ipg;
231
232	switch (emac->speed) {
233	case SPEED_1000:
234		ipg = emac->is_sr1 ? MII_RT_TX_IPG_1G_SR1 : MII_RT_TX_IPG_1G;
235		break;
236	case SPEED_100:
237		ipg = emac->is_sr1 ? MII_RT_TX_IPG_100M_SR1 : MII_RT_TX_IPG_100M;
238		break;
239	case SPEED_10:
240		/* Firmware hardcodes IPG for SR1.0 */
241		if (emac->is_sr1)
242			return;
243		/* IPG for 10M is same as 100M */
244		ipg = MII_RT_TX_IPG_100M;
245		break;
246	default:
247		/* Other links speeds not supported */
248		netdev_err(emac->ndev, "Unsupported link speed\n");
249		return;
250	}
251
252	icssg_mii_update_ipg(prueth->mii_rt, slice, ipg);
253}
254EXPORT_SYMBOL_GPL(icssg_config_ipg);
255
256static void emac_r30_cmd_init(struct prueth_emac *emac)
257{
258	struct icssg_r30_cmd __iomem *p;
259	int i;
260
261	p = emac->dram.va + MGR_R30_CMD_OFFSET;
262
263	for (i = 0; i < 4; i++)
264		writel(EMAC_NONE, &p->cmd[i]);
265}
266
267static int emac_r30_is_done(struct prueth_emac *emac)
268{
269	const struct icssg_r30_cmd __iomem *p;
270	u32 cmd;
271	int i;
272
273	p = emac->dram.va + MGR_R30_CMD_OFFSET;
274
275	for (i = 0; i < 4; i++) {
276		cmd = readl(&p->cmd[i]);
277		if (cmd != EMAC_NONE)
278			return 0;
279	}
280
281	return 1;
282}
283
284static int prueth_fw_offload_buffer_setup(struct prueth_emac *emac)
285{
286	struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
287	struct icssg_rxq_ctx __iomem *rxq_ctx;
288	struct prueth *prueth = emac->prueth;
289	int slice = prueth_emac_slice(emac);
290	u32 addr;
291	int i;
292
293	addr = lower_32_bits(prueth->msmcram.pa);
294	if (slice) {
295		if (prueth->pdata.banked_ms_ram)
296			addr += MSMC_RAM_BANK_SIZE;
297		else
298			addr += PRUETH_SW_TOTAL_BUF_SIZE_PER_SLICE;
299	}
300
301	if (addr % SZ_64K) {
302		dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
303		return -EINVAL;
304	}
305
306	bpool_cfg = emac->dram.va + BUFFER_POOL_0_ADDR_OFFSET;
307
308	/* Configure buffer pools for forwarding buffers
309	 * - used by firmware to store packets to be forwarded to other port
310	 * - 8 total pools per slice
311	 */
312	for (i = 0; i <  PRUETH_NUM_FWD_BUF_POOLS_PER_SLICE; i++) {
313		writel(addr, &bpool_cfg[i].addr);
314		writel(PRUETH_SW_FWD_BUF_POOL_SIZE, &bpool_cfg[i].len);
315		addr += PRUETH_SW_FWD_BUF_POOL_SIZE;
316	}
317
318	/* Configure buffer pools for Local Injection buffers
319	 *  - used by firmware to store packets received from host core
320	 *  - 16 total pools per slice
321	 */
322	for (i = 0; i < PRUETH_NUM_LI_BUF_POOLS_PER_SLICE; i++) {
323		int cfg_idx = i + PRUETH_NUM_FWD_BUF_POOLS_PER_SLICE;
324
325		/* The driver only uses first 4 queues per PRU,
326		 * so only initialize buffer for them
327		 */
328		if ((i % PRUETH_NUM_LI_BUF_POOLS_PER_PORT_PER_SLICE)
329			 < PRUETH_SW_USED_LI_BUF_POOLS_PER_PORT_PER_SLICE) {
330			writel(addr, &bpool_cfg[cfg_idx].addr);
331			writel(PRUETH_SW_LI_BUF_POOL_SIZE,
332			       &bpool_cfg[cfg_idx].len);
333			addr += PRUETH_SW_LI_BUF_POOL_SIZE;
334		} else {
335			writel(0, &bpool_cfg[cfg_idx].addr);
336			writel(0, &bpool_cfg[cfg_idx].len);
337		}
338	}
339
340	/* Express RX buffer queue
341	 *  - used by firmware to store express packets to be transmitted
342	 *    to the host core
343	 */
344	rxq_ctx = emac->dram.va + HOST_RX_Q_EXP_CONTEXT_OFFSET;
345	for (i = 0; i < 3; i++)
346		writel(addr, &rxq_ctx->start[i]);
347
348	addr += PRUETH_SW_HOST_EXP_BUF_POOL_SIZE;
349	writel(addr, &rxq_ctx->end);
350
351	/* Pre-emptible RX buffer queue
352	 *  - used by firmware to store preemptible packets to be transmitted
353	 *    to the host core
354	 */
355	rxq_ctx = emac->dram.va + HOST_RX_Q_PRE_CONTEXT_OFFSET;
356	for (i = 0; i < 3; i++)
357		writel(addr, &rxq_ctx->start[i]);
358
359	addr += PRUETH_SW_HOST_PRE_BUF_POOL_SIZE;
360	writel(addr, &rxq_ctx->end);
361
362	/* Set pointer for default dropped packet write
363	 *  - used by firmware to temporarily store packet to be dropped
364	 */
365	rxq_ctx = emac->dram.va + DEFAULT_MSMC_Q_OFFSET;
366	writel(addr, &rxq_ctx->start[0]);
367
368	return 0;
369}
370
371static int prueth_emac_buffer_setup(struct prueth_emac *emac)
372{
373	struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
374	struct icssg_rxq_ctx __iomem *rxq_ctx;
375	struct prueth *prueth = emac->prueth;
376	int slice = prueth_emac_slice(emac);
377	u32 addr;
378	int i;
379
380	addr = lower_32_bits(prueth->msmcram.pa);
381	if (slice) {
382		if (prueth->pdata.banked_ms_ram)
383			addr += MSMC_RAM_BANK_SIZE;
384		else
385			addr += PRUETH_EMAC_TOTAL_BUF_SIZE_PER_SLICE;
386	}
387
388	if (addr % SZ_64K) {
389		dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
390		return -EINVAL;
391	}
392
393	bpool_cfg = emac->dram.va + BUFFER_POOL_0_ADDR_OFFSET;
394
395	/* Configure buffer pools for forwarding buffers
396	 *  - in mac mode - no forwarding so initialize all pools to 0
397	 *  - 8 total pools per slice
398	 */
399	for (i = 0; i <  PRUETH_NUM_FWD_BUF_POOLS_PER_SLICE; i++) {
400		writel(0, &bpool_cfg[i].addr);
401		writel(0, &bpool_cfg[i].len);
402	}
403
404	/* Configure buffer pools for Local Injection buffers
405	 *  - used by firmware to store packets received from host core
406	 *  - 16 total pools per slice
407	 */
408	bpool_cfg = emac->dram.va + BUFFER_POOL_0_ADDR_OFFSET;
409	for (i = 0; i < PRUETH_NUM_LI_BUF_POOLS_PER_SLICE; i++) {
410		int cfg_idx = i + PRUETH_NUM_FWD_BUF_POOLS_PER_SLICE;
411
412		/* In EMAC mode, only first 4 buffers are used,
413		 * as 1 slice needs to handle only 1 port
414		 */
415		if (i < PRUETH_EMAC_USED_LI_BUF_POOLS_PER_PORT_PER_SLICE) {
416			writel(addr, &bpool_cfg[cfg_idx].addr);
417			writel(PRUETH_EMAC_LI_BUF_POOL_SIZE,
418			       &bpool_cfg[cfg_idx].len);
419			addr += PRUETH_EMAC_LI_BUF_POOL_SIZE;
420		} else {
421			writel(0, &bpool_cfg[cfg_idx].addr);
422			writel(0, &bpool_cfg[cfg_idx].len);
423		}
424	}
425
426	/* Express RX buffer queue
427	 *  - used by firmware to store express packets to be transmitted
428	 *    to host core
429	 */
430	rxq_ctx = emac->dram.va + HOST_RX_Q_EXP_CONTEXT_OFFSET;
431	for (i = 0; i < 3; i++)
432		writel(addr, &rxq_ctx->start[i]);
433
434	addr += PRUETH_EMAC_HOST_EXP_BUF_POOL_SIZE;
435	writel(addr, &rxq_ctx->end);
436
437	/* Pre-emptible RX buffer queue
438	 *  - used by firmware to store preemptible packets to be transmitted
439	 *    to host core
440	 */
441	rxq_ctx = emac->dram.va + HOST_RX_Q_PRE_CONTEXT_OFFSET;
442	for (i = 0; i < 3; i++)
443		writel(addr, &rxq_ctx->start[i]);
444
445	addr += PRUETH_EMAC_HOST_PRE_BUF_POOL_SIZE;
446	writel(addr, &rxq_ctx->end);
447
448	/* Set pointer for default dropped packet write
449	 *  - used by firmware to temporarily store packet to be dropped
450	 */
451	rxq_ctx = emac->dram.va + DEFAULT_MSMC_Q_OFFSET;
452	writel(addr, &rxq_ctx->start[0]);
453
454	return 0;
455}
456
457void icssg_init_emac_mode(struct prueth *prueth)
458{
459	/* When the device is configured as a bridge and it is being brought
460	 * back to the emac mode, the host mac address has to be set as 0.
461	 */
462	u32 addr = prueth->shram.pa + EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET;
463	int i;
464	u8 mac[ETH_ALEN] = { 0 };
465
466	/* Set VLAN TABLE address base */
467	regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, SMEM_VLAN_OFFSET_MASK,
468			   addr <<  SMEM_VLAN_OFFSET);
469	regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, FDB_HASH_SIZE_MASK,
470			   FDB_HASH_SIZE << FDB_HASH_SIZE_SHIFT);
471	/* Set enable VLAN aware mode, and FDBs for all PRUs */
472	regmap_write(prueth->miig_rt, FDB_GEN_CFG2, (FDB_PRU0_EN | FDB_PRU1_EN | FDB_HOST_EN));
473	prueth->vlan_tbl = (struct prueth_vlan_tbl __force *)(prueth->shram.va +
474			    EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET);
475	for (i = 0; i < SZ_4K - 1; i++) {
476		prueth->vlan_tbl[i].fid = i;
477		prueth->vlan_tbl[i].fid_c1 = 0;
478	}
479	/* Clear host MAC address */
480	icssg_class_set_host_mac_addr(prueth->miig_rt, mac);
481}
482EXPORT_SYMBOL_GPL(icssg_init_emac_mode);
483
484void icssg_init_fw_offload_mode(struct prueth *prueth)
485{
486	u32 addr = prueth->shram.pa + EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET;
487	int i;
488
489	/* Set VLAN TABLE address base */
490	regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, SMEM_VLAN_OFFSET_MASK,
491			   addr <<  SMEM_VLAN_OFFSET);
492	regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, FDB_HASH_SIZE_MASK,
493			   FDB_HASH_SIZE << FDB_HASH_SIZE_SHIFT);
494	/* Set enable VLAN aware mode, and FDBs for all PRUs */
495	regmap_write(prueth->miig_rt, FDB_GEN_CFG2, FDB_EN_ALL);
496	prueth->vlan_tbl = (struct prueth_vlan_tbl __force *)(prueth->shram.va +
497			    EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET);
498	for (i = 0; i < SZ_4K - 1; i++) {
499		prueth->vlan_tbl[i].fid = i;
500		prueth->vlan_tbl[i].fid_c1 = 0;
501	}
502
503	if (prueth->hw_bridge_dev)
504		icssg_class_set_host_mac_addr(prueth->miig_rt, prueth->hw_bridge_dev->dev_addr);
505	icssg_set_pvid(prueth, prueth->default_vlan, PRUETH_PORT_HOST);
506}
507EXPORT_SYMBOL_GPL(icssg_init_fw_offload_mode);
508
509int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice)
510{
511	void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET;
512	struct icssg_flow_cfg __iomem *flow_cfg;
513	int ret;
514
515	memset_io(config, 0, TAS_GATE_MASK_LIST0);
516	icssg_miig_queues_init(prueth, slice);
517
518	emac->speed = SPEED_1000;
519	emac->duplex = DUPLEX_FULL;
520	if (!phy_interface_mode_is_rgmii(emac->phy_if)) {
521		emac->speed = SPEED_100;
522		emac->duplex = DUPLEX_FULL;
523	}
524	regmap_update_bits(prueth->miig_rt, ICSSG_CFG_OFFSET,
525			   ICSSG_CFG_DEFAULT, ICSSG_CFG_DEFAULT);
526	icssg_miig_set_interface_mode(prueth->miig_rt, slice, emac->phy_if);
527	if (prueth->is_switch_mode || prueth->is_hsr_offload_mode)
528		icssg_config_mii_init_fw_offload(emac);
529	else
530		icssg_config_mii_init(emac);
531	icssg_config_ipg(emac);
532	icssg_update_rgmii_cfg(prueth->miig_rt, emac);
533
534	/* set GPI mode */
535	pruss_cfg_gpimode(prueth->pruss, prueth->pru_id[slice],
536			  PRUSS_GPI_MODE_MII);
537
538	/* enable XFR shift for PRU and RTU */
539	pruss_cfg_xfr_enable(prueth->pruss, PRU_TYPE_PRU, true);
540	pruss_cfg_xfr_enable(prueth->pruss, PRU_TYPE_RTU, true);
541
542	/* set C28 to 0x100 */
543	pru_rproc_set_ctable(prueth->pru[slice], PRU_C28, 0x100 << 8);
544	pru_rproc_set_ctable(prueth->rtu[slice], PRU_C28, 0x100 << 8);
545	pru_rproc_set_ctable(prueth->txpru[slice], PRU_C28, 0x100 << 8);
546
547	flow_cfg = config + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET;
548	writew(emac->rx_flow_id_base, &flow_cfg->rx_base_flow);
549	writew(0, &flow_cfg->mgm_base_flow);
550	writeb(0, config + SPL_PKT_DEFAULT_PRIORITY);
551	writeb(0, config + QUEUE_NUM_UNTAGGED);
552
553	if (prueth->is_switch_mode || prueth->is_hsr_offload_mode)
554		ret = prueth_fw_offload_buffer_setup(emac);
555	else
556		ret = prueth_emac_buffer_setup(emac);
557	if (ret)
558		return ret;
559
560	emac_r30_cmd_init(emac);
561
562	return 0;
563}
564EXPORT_SYMBOL_GPL(icssg_config);
565
566/* Bitmask for ICSSG r30 commands */
567static const struct icssg_r30_cmd emac_r32_bitmask[] = {
568	{{0xffff0004, 0xffff0100, 0xffff0004, EMAC_NONE}},	/* EMAC_PORT_DISABLE */
569	{{0xfffb0040, 0xfeff0200, 0xfeff0200, EMAC_NONE}},	/* EMAC_PORT_BLOCK */
570	{{0xffbb0000, 0xfcff0000, 0xdcfb0000, EMAC_NONE}},	/* EMAC_PORT_FORWARD */
571	{{0xffbb0000, 0xfcff0000, 0xfcff2000, EMAC_NONE}},	/* EMAC_PORT_FORWARD_WO_LEARNING */
572	{{0xffff0001, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},	/* ACCEPT ALL */
573	{{0xfffe0002, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},	/* ACCEPT TAGGED */
574	{{0xfffc0000, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},	/* ACCEPT UNTAGGED and PRIO */
575	{{EMAC_NONE,  0xffff0020, EMAC_NONE, EMAC_NONE}},	/* TAS Trigger List change */
576	{{EMAC_NONE,  0xdfff1000, EMAC_NONE, EMAC_NONE}},	/* TAS set state ENABLE*/
577	{{EMAC_NONE,  0xefff2000, EMAC_NONE, EMAC_NONE}},	/* TAS set state RESET*/
578	{{EMAC_NONE,  0xcfff0000, EMAC_NONE, EMAC_NONE}},	/* TAS set state DISABLE*/
579	{{EMAC_NONE,  EMAC_NONE,  0xffff0400, EMAC_NONE}},	/* UC flooding ENABLE*/
580	{{EMAC_NONE,  EMAC_NONE,  0xfbff0000, EMAC_NONE}},	/* UC flooding DISABLE*/
581	{{EMAC_NONE,  EMAC_NONE,  0xffff0800, EMAC_NONE}},	/* MC flooding ENABLE*/
582	{{EMAC_NONE,  EMAC_NONE,  0xf7ff0000, EMAC_NONE}},	/* MC flooding DISABLE*/
583	{{EMAC_NONE,  0xffff4000, EMAC_NONE, EMAC_NONE}},	/* Preemption on Tx ENABLE*/
584	{{EMAC_NONE,  0xbfff0000, EMAC_NONE, EMAC_NONE}},	/* Preemption on Tx DISABLE*/
585	{{0xffff0010,  EMAC_NONE, 0xffff0010, EMAC_NONE}},	/* VLAN AWARE*/
586	{{0xffef0000,  EMAC_NONE, 0xffef0000, EMAC_NONE}},	/* VLAN UNWARE*/
587	{{0xffff2000, EMAC_NONE, EMAC_NONE, EMAC_NONE}},	/* HSR_RX_OFFLOAD_ENABLE */
588	{{0xdfff0000, EMAC_NONE, EMAC_NONE, EMAC_NONE}}		/* HSR_RX_OFFLOAD_DISABLE */
589};
590
591int icssg_set_port_state(struct prueth_emac *emac,
592			 enum icssg_port_state_cmd cmd)
593{
594	struct icssg_r30_cmd __iomem *p;
595	int ret = -ETIMEDOUT;
596	int done = 0;
597	int i;
598
599	p = emac->dram.va + MGR_R30_CMD_OFFSET;
600
601	if (cmd >= ICSSG_EMAC_PORT_MAX_COMMANDS) {
602		netdev_err(emac->ndev, "invalid port command\n");
603		return -EINVAL;
604	}
605
606	/* only one command at a time allowed to firmware */
607	mutex_lock(&emac->cmd_lock);
608
609	for (i = 0; i < 4; i++)
610		writel(emac_r32_bitmask[cmd].cmd[i], &p->cmd[i]);
611
612	/* wait for done */
613	ret = read_poll_timeout(emac_r30_is_done, done, done == 1,
614				1000, 10000, false, emac);
615
616	if (ret == -ETIMEDOUT)
617		netdev_err(emac->ndev, "timeout waiting for command done\n");
618
619	mutex_unlock(&emac->cmd_lock);
620
621	return ret;
622}
623EXPORT_SYMBOL_GPL(icssg_set_port_state);
624
625void icssg_config_half_duplex(struct prueth_emac *emac)
626{
627	u32 val;
628
629	if (!emac->half_duplex)
630		return;
631
632	val = get_random_u32();
633	writel(val, emac->dram.va + HD_RAND_SEED_OFFSET);
634}
635EXPORT_SYMBOL_GPL(icssg_config_half_duplex);
636
637void icssg_config_set_speed(struct prueth_emac *emac)
638{
639	u8 fw_speed;
640
641	switch (emac->speed) {
642	case SPEED_1000:
643		fw_speed = FW_LINK_SPEED_1G;
644		break;
645	case SPEED_100:
646		fw_speed = FW_LINK_SPEED_100M;
647		break;
648	case SPEED_10:
649		fw_speed = FW_LINK_SPEED_10M;
650		break;
651	default:
652		/* Other links speeds not supported */
653		netdev_err(emac->ndev, "Unsupported link speed\n");
654		return;
655	}
656
657	if (emac->duplex == DUPLEX_HALF)
658		fw_speed |= FW_LINK_SPEED_HD;
659
660	writeb(fw_speed, emac->dram.va + PORT_LINK_SPEED_OFFSET);
661}
662EXPORT_SYMBOL_GPL(icssg_config_set_speed);
663
664int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd,
665		       struct mgmt_cmd_rsp *rsp)
666{
667	struct prueth *prueth = emac->prueth;
668	int slice = prueth_emac_slice(emac);
669	int addr, ret;
670
671	addr = icssg_queue_pop(prueth, slice == 0 ?
672			       ICSSG_CMD_POP_SLICE0 : ICSSG_CMD_POP_SLICE1);
673	if (addr < 0)
674		return addr;
675
676	/* First 4 bytes have FW owned buffer linking info which should
677	 * not be touched
678	 */
679	memcpy_toio(prueth->shram.va + addr + 4, cmd, sizeof(*cmd));
680	icssg_queue_push(prueth, slice == 0 ?
681			 ICSSG_CMD_PUSH_SLICE0 : ICSSG_CMD_PUSH_SLICE1, addr);
682	ret = read_poll_timeout(icssg_queue_pop, addr, addr >= 0,
683				2000, 20000000, false, prueth, slice == 0 ?
684				ICSSG_RSP_POP_SLICE0 : ICSSG_RSP_POP_SLICE1);
685	if (ret) {
686		netdev_err(emac->ndev, "Timedout sending HWQ message\n");
687		return ret;
688	}
689
690	memcpy_fromio(rsp, prueth->shram.va + addr, sizeof(*rsp));
691	/* Return buffer back for to pool */
692	icssg_queue_push(prueth, slice == 0 ?
693			 ICSSG_RSP_PUSH_SLICE0 : ICSSG_RSP_PUSH_SLICE1, addr);
694
695	return 0;
696}
697EXPORT_SYMBOL_GPL(icssg_send_fdb_msg);
698
699static void icssg_fdb_setup(struct prueth_emac *emac, struct mgmt_cmd *fdb_cmd,
700			    const unsigned char *addr, u8 fid, int cmd)
701{
702	int slice = prueth_emac_slice(emac);
703	u8 mac_fid[ETH_ALEN + 2];
704	u16 fdb_slot;
705
706	ether_addr_copy(mac_fid, addr);
707
708	/* 1-1 VID-FID mapping is already setup */
709	mac_fid[ETH_ALEN] = fid;
710	mac_fid[ETH_ALEN + 1] = 0;
711
712	fdb_slot = bitrev32(crc32_le(0, mac_fid, 8)) & PRUETH_SWITCH_FDB_MASK;
713
714	fdb_cmd->header = ICSSG_FW_MGMT_CMD_HEADER;
715	fdb_cmd->type   = ICSSG_FW_MGMT_FDB_CMD_TYPE;
716	fdb_cmd->seqnum = ++(emac->prueth->icssg_hwcmdseq);
717	fdb_cmd->param  = cmd;
718	fdb_cmd->param |= (slice << 4);
719
720	memcpy(&fdb_cmd->cmd_args[0], addr, 4);
721	memcpy(&fdb_cmd->cmd_args[1], &addr[4], 2);
722	fdb_cmd->cmd_args[2] = fdb_slot;
723
724	netdev_dbg(emac->ndev, "MAC %pM slot %X FID %X\n", addr, fdb_slot, fid);
725}
726
727int icssg_fdb_add_del(struct prueth_emac *emac, const unsigned char *addr,
728		      u8 vid, u8 fid_c2, bool add)
729{
730	struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 };
731	struct mgmt_cmd fdb_cmd = { 0 };
732	u8 fid = vid;
733	int ret;
734
735	icssg_fdb_setup(emac, &fdb_cmd, addr, fid, add ? ICSS_CMD_ADD_FDB : ICSS_CMD_DEL_FDB);
736
737	fid_c2 |= ICSSG_FDB_ENTRY_VALID;
738	fdb_cmd.cmd_args[1] |= ((fid << 16) | (fid_c2 << 24));
739
740	ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp);
741	if (ret)
742		return ret;
743
744	WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum);
745	if (fdb_cmd_rsp.status == 1)
746		return 0;
747
748	return -EINVAL;
749}
750EXPORT_SYMBOL_GPL(icssg_fdb_add_del);
751
752int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr,
753		     u8 vid)
754{
755	struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 };
756	struct mgmt_cmd fdb_cmd = { 0 };
757	struct prueth_fdb_slot *slot;
758	u8 fid = vid;
759	int ret, i;
760
761	icssg_fdb_setup(emac, &fdb_cmd, addr, fid, ICSS_CMD_GET_FDB_SLOT);
762
763	fdb_cmd.cmd_args[1] |= fid << 16;
764
765	ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp);
766	if (ret)
767		return ret;
768
769	WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum);
770
771	slot = (struct prueth_fdb_slot __force *)(emac->dram.va + FDB_CMD_BUFFER);
772	for (i = 0; i < 4; i++) {
773		if (ether_addr_equal(addr, slot->mac) && vid == slot->fid)
774			return (slot->fid_c2 & ~ICSSG_FDB_ENTRY_VALID);
775		slot++;
776	}
777
778	return 0;
779}
780EXPORT_SYMBOL_GPL(icssg_fdb_lookup);
781
782void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask,
783		       u8 untag_mask, bool add)
784{
785	struct prueth *prueth = emac->prueth;
786	struct prueth_vlan_tbl *tbl;
787	u8 fid_c1;
788
789	tbl = prueth->vlan_tbl;
790	spin_lock(&prueth->vtbl_lock);
791	fid_c1 = tbl[vid].fid_c1;
792
793	/* FID_C1: bit0..2 port membership mask,
794	 * bit3..5 tagging mask for each port
795	 * bit6 Stream VID (not handled currently)
796	 * bit7 MC flood (not handled currently)
797	 */
798	if (add) {
799		fid_c1 |= (port_mask | port_mask << 3);
800		fid_c1 &= ~(untag_mask << 3);
801	} else {
802		fid_c1 &= ~(port_mask | port_mask << 3);
803	}
804
805	tbl[vid].fid_c1 = fid_c1;
806	spin_unlock(&prueth->vtbl_lock);
807}
808EXPORT_SYMBOL_GPL(icssg_vtbl_modify);
809
810u16 icssg_get_pvid(struct prueth_emac *emac)
811{
812	struct prueth *prueth = emac->prueth;
813	u32 pvid;
814
815	if (emac->port_id == PRUETH_PORT_MII0)
816		pvid = readl(prueth->shram.va + EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET);
817	else
818		pvid = readl(prueth->shram.va + EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET);
819
820	pvid = pvid >> 24;
821
822	return pvid;
823}
824EXPORT_SYMBOL_GPL(icssg_get_pvid);
825
826void icssg_set_pvid(struct prueth *prueth, u8 vid, u8 port)
827{
828	u32 pvid;
829
830	/* only 256 VLANs are supported */
831	pvid = (u32 __force)cpu_to_be32((ETH_P_8021Q << 16) | (vid & 0xff));
832
833	if (port == PRUETH_PORT_MII0)
834		writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET);
835	else if (port == PRUETH_PORT_MII1)
836		writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET);
837	else
838		writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT0_DEFAULT_VLAN_OFFSET);
839}
840EXPORT_SYMBOL_GPL(icssg_set_pvid);
841
842int emac_fdb_flow_id_updated(struct prueth_emac *emac)
843{
844	struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 };
845	int slice = prueth_emac_slice(emac);
846	struct mgmt_cmd fdb_cmd = { 0 };
847	int ret;
848
849	fdb_cmd.header = ICSSG_FW_MGMT_CMD_HEADER;
850	fdb_cmd.type   = ICSSG_FW_MGMT_FDB_CMD_TYPE_RX_FLOW;
851	fdb_cmd.seqnum = ++(emac->prueth->icssg_hwcmdseq);
852	fdb_cmd.param  = 0;
853
854	fdb_cmd.param |= (slice << 4);
855	fdb_cmd.cmd_args[0] = 0;
856
857	ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp);
858	if (ret)
859		return ret;
860
861	WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum);
862	return fdb_cmd_rsp.status == 1 ? 0 : -EINVAL;
863}
864EXPORT_SYMBOL_GPL(emac_fdb_flow_id_updated);
~/ Read-only file preview.