xref: /linux/drivers/net/ethernet/ti/icssg/icssg_config.c (revision 9410645520e9b820069761f3450ef6661418e279)
1e9b4ece7SMD Danish Anwar // SPDX-License-Identifier: GPL-2.0
2e9b4ece7SMD Danish Anwar /* ICSSG Ethernet driver
3e9b4ece7SMD Danish Anwar  *
4e9b4ece7SMD Danish Anwar  * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com
5e9b4ece7SMD Danish Anwar  */
6e9b4ece7SMD Danish Anwar 
7e9b4ece7SMD Danish Anwar #include <linux/iopoll.h>
8e9b4ece7SMD Danish Anwar #include <linux/regmap.h>
9e9b4ece7SMD Danish Anwar #include <uapi/linux/if_ether.h>
10e9b4ece7SMD Danish Anwar #include "icssg_config.h"
11e9b4ece7SMD Danish Anwar #include "icssg_prueth.h"
12e9b4ece7SMD Danish Anwar #include "icssg_switch_map.h"
13e9b4ece7SMD Danish Anwar #include "icssg_mii_rt.h"
14e9b4ece7SMD Danish Anwar 
15e9b4ece7SMD Danish Anwar /* TX IPG Values to be set for 100M link speed. These values are
16e9b4ece7SMD Danish Anwar  * in ocp_clk cycles. So need change if ocp_clk is changed for a specific
17e9b4ece7SMD Danish Anwar  * h/w design.
18e9b4ece7SMD Danish Anwar  */
19e9b4ece7SMD Danish Anwar 
20e9b4ece7SMD Danish Anwar /* IPG is in core_clk cycles */
21e9b4ece7SMD Danish Anwar #define MII_RT_TX_IPG_100M	0x17
22e9b4ece7SMD Danish Anwar #define MII_RT_TX_IPG_1G	0xb
2395c2e689SDiogo Ivo #define MII_RT_TX_IPG_100M_SR1	0x166
2495c2e689SDiogo Ivo #define MII_RT_TX_IPG_1G_SR1	0x1a
25e9b4ece7SMD Danish Anwar 
26e9b4ece7SMD Danish Anwar #define	ICSSG_QUEUES_MAX		64
27e9b4ece7SMD Danish Anwar #define	ICSSG_QUEUE_OFFSET		0xd00
28e9b4ece7SMD Danish Anwar #define	ICSSG_QUEUE_PEEK_OFFSET		0xe00
29e9b4ece7SMD Danish Anwar #define	ICSSG_QUEUE_CNT_OFFSET		0xe40
30e9b4ece7SMD Danish Anwar #define	ICSSG_QUEUE_RESET_OFFSET	0xf40
31e9b4ece7SMD Danish Anwar 
32e9b4ece7SMD Danish Anwar #define	ICSSG_NUM_TX_QUEUES	8
33e9b4ece7SMD Danish Anwar 
34e9b4ece7SMD Danish Anwar #define	RECYCLE_Q_SLICE0	16
35e9b4ece7SMD Danish Anwar #define	RECYCLE_Q_SLICE1	17
36e9b4ece7SMD Danish Anwar 
37e9b4ece7SMD Danish Anwar #define	ICSSG_NUM_OTHER_QUEUES	5	/* port, host and special queues */
38e9b4ece7SMD Danish Anwar 
39e9b4ece7SMD Danish Anwar #define	PORT_HI_Q_SLICE0	32
40e9b4ece7SMD Danish Anwar #define	PORT_LO_Q_SLICE0	33
41e9b4ece7SMD Danish Anwar #define	HOST_HI_Q_SLICE0	34
42e9b4ece7SMD Danish Anwar #define	HOST_LO_Q_SLICE0	35
43e9b4ece7SMD Danish Anwar #define	HOST_SPL_Q_SLICE0	40	/* Special Queue */
44e9b4ece7SMD Danish Anwar 
45e9b4ece7SMD Danish Anwar #define	PORT_HI_Q_SLICE1	36
46e9b4ece7SMD Danish Anwar #define	PORT_LO_Q_SLICE1	37
47e9b4ece7SMD Danish Anwar #define	HOST_HI_Q_SLICE1	38
48e9b4ece7SMD Danish Anwar #define	HOST_LO_Q_SLICE1	39
49e9b4ece7SMD Danish Anwar #define	HOST_SPL_Q_SLICE1	41	/* Special Queue */
50e9b4ece7SMD Danish Anwar 
51e9b4ece7SMD Danish Anwar #define MII_RXCFG_DEFAULT	(PRUSS_MII_RT_RXCFG_RX_ENABLE | \
52e9b4ece7SMD Danish Anwar 				 PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS | \
53e9b4ece7SMD Danish Anwar 				 PRUSS_MII_RT_RXCFG_RX_L2_EN | \
54e9b4ece7SMD Danish Anwar 				 PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS)
55e9b4ece7SMD Danish Anwar 
56e9b4ece7SMD Danish Anwar #define MII_TXCFG_DEFAULT	(PRUSS_MII_RT_TXCFG_TX_ENABLE | \
57e9b4ece7SMD Danish Anwar 				 PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE | \
58e9b4ece7SMD Danish Anwar 				 PRUSS_MII_RT_TXCFG_TX_32_MODE_EN | \
59e9b4ece7SMD Danish Anwar 				 PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN)
60e9b4ece7SMD Danish Anwar 
61e9b4ece7SMD Danish Anwar #define ICSSG_CFG_DEFAULT	(ICSSG_CFG_TX_L1_EN | \
62e9b4ece7SMD Danish Anwar 				 ICSSG_CFG_TX_L2_EN | ICSSG_CFG_RX_L2_G_EN | \
63e9b4ece7SMD Danish Anwar 				 ICSSG_CFG_TX_PRU_EN | \
64e9b4ece7SMD Danish Anwar 				 ICSSG_CFG_SGMII_MODE)
65e9b4ece7SMD Danish Anwar 
66e9b4ece7SMD Danish Anwar #define FDB_GEN_CFG1		0x60
67e9b4ece7SMD Danish Anwar #define SMEM_VLAN_OFFSET	8
68e9b4ece7SMD Danish Anwar #define SMEM_VLAN_OFFSET_MASK	GENMASK(25, 8)
69e9b4ece7SMD Danish Anwar 
70e9b4ece7SMD Danish Anwar #define FDB_GEN_CFG2		0x64
71e9b4ece7SMD Danish Anwar #define FDB_VLAN_EN		BIT(6)
72e9b4ece7SMD Danish Anwar #define FDB_HOST_EN		BIT(2)
73e9b4ece7SMD Danish Anwar #define FDB_PRU1_EN		BIT(1)
74e9b4ece7SMD Danish Anwar #define FDB_PRU0_EN		BIT(0)
75e9b4ece7SMD Danish Anwar #define FDB_EN_ALL		(FDB_PRU0_EN | FDB_PRU1_EN | \
76e9b4ece7SMD Danish Anwar 				 FDB_HOST_EN | FDB_VLAN_EN)
77e9b4ece7SMD Danish Anwar 
78e9b4ece7SMD Danish Anwar /**
79e9b4ece7SMD Danish Anwar  * struct map - ICSSG Queue Map
80e9b4ece7SMD Danish Anwar  * @queue: Queue number
81e9b4ece7SMD Danish Anwar  * @pd_addr_start: Packet descriptor queue reserved memory
82e9b4ece7SMD Danish Anwar  * @flags: Flags
83e9b4ece7SMD Danish Anwar  * @special: Indicates whether this queue is a special queue or not
84e9b4ece7SMD Danish Anwar  */
85e9b4ece7SMD Danish Anwar struct map {
86e9b4ece7SMD Danish Anwar 	int queue;
87e9b4ece7SMD Danish Anwar 	u32 pd_addr_start;
88e9b4ece7SMD Danish Anwar 	u32 flags;
89e9b4ece7SMD Danish Anwar 	bool special;
90e9b4ece7SMD Danish Anwar };
91e9b4ece7SMD Danish Anwar 
92e9b4ece7SMD Danish Anwar /* Hardware queue map for ICSSG */
93e9b4ece7SMD Danish Anwar static const struct map hwq_map[2][ICSSG_NUM_OTHER_QUEUES] = {
94e9b4ece7SMD Danish Anwar 	{
95e9b4ece7SMD Danish Anwar 		{ PORT_HI_Q_SLICE0, PORT_DESC0_HI, 0x200000, 0 },
96e9b4ece7SMD Danish Anwar 		{ PORT_LO_Q_SLICE0, PORT_DESC0_LO, 0, 0 },
97e9b4ece7SMD Danish Anwar 		{ HOST_HI_Q_SLICE0, HOST_DESC0_HI, 0x200000, 0 },
98e9b4ece7SMD Danish Anwar 		{ HOST_LO_Q_SLICE0, HOST_DESC0_LO, 0, 0 },
99e9b4ece7SMD Danish Anwar 		{ HOST_SPL_Q_SLICE0, HOST_SPPD0, 0x400000, 1 },
100e9b4ece7SMD Danish Anwar 	},
101e9b4ece7SMD Danish Anwar 	{
102e9b4ece7SMD Danish Anwar 		{ PORT_HI_Q_SLICE1, PORT_DESC1_HI, 0xa00000, 0 },
103e9b4ece7SMD Danish Anwar 		{ PORT_LO_Q_SLICE1, PORT_DESC1_LO, 0x800000, 0 },
104e9b4ece7SMD Danish Anwar 		{ HOST_HI_Q_SLICE1, HOST_DESC1_HI, 0xa00000, 0 },
105e9b4ece7SMD Danish Anwar 		{ HOST_LO_Q_SLICE1, HOST_DESC1_LO, 0x800000, 0 },
106e9b4ece7SMD Danish Anwar 		{ HOST_SPL_Q_SLICE1, HOST_SPPD1, 0xc00000, 1 },
107e9b4ece7SMD Danish Anwar 	},
108e9b4ece7SMD Danish Anwar };
109e9b4ece7SMD Danish Anwar 
icssg_config_mii_init_fw_offload(struct prueth_emac * emac)11095540ad6SMD Danish Anwar static void icssg_config_mii_init_fw_offload(struct prueth_emac *emac)
111e9b4ece7SMD Danish Anwar {
112e9b4ece7SMD Danish Anwar 	struct prueth *prueth = emac->prueth;
113abd5576bSMD Danish Anwar 	int mii = prueth_emac_slice(emac);
114abd5576bSMD Danish Anwar 	u32 txcfg_reg, pcnt_reg, txcfg;
115e9b4ece7SMD Danish Anwar 	struct regmap *mii_rt;
116e9b4ece7SMD Danish Anwar 
117e9b4ece7SMD Danish Anwar 	mii_rt = prueth->mii_rt;
118e9b4ece7SMD Danish Anwar 
119abd5576bSMD Danish Anwar 	txcfg_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
120abd5576bSMD Danish Anwar 				       PRUSS_MII_RT_TXCFG1;
121abd5576bSMD Danish Anwar 	pcnt_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
122abd5576bSMD Danish Anwar 				       PRUSS_MII_RT_RX_PCNT1;
123abd5576bSMD Danish Anwar 
124abd5576bSMD Danish Anwar 	txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE |
125abd5576bSMD Danish Anwar 		PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE |
126abd5576bSMD Danish Anwar 		PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN;
127abd5576bSMD Danish Anwar 
128abd5576bSMD Danish Anwar 	if (emac->phy_if == PHY_INTERFACE_MODE_MII && mii == ICSS_MII1)
129abd5576bSMD Danish Anwar 		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
130abd5576bSMD Danish Anwar 	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && mii == ICSS_MII0)
131abd5576bSMD Danish Anwar 		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
132abd5576bSMD Danish Anwar 
133abd5576bSMD Danish Anwar 	regmap_write(mii_rt, txcfg_reg, txcfg);
134abd5576bSMD Danish Anwar 	regmap_write(mii_rt, pcnt_reg, 0x1);
135abd5576bSMD Danish Anwar }
136abd5576bSMD Danish Anwar 
icssg_config_mii_init(struct prueth_emac * emac)137abd5576bSMD Danish Anwar static void icssg_config_mii_init(struct prueth_emac *emac)
138abd5576bSMD Danish Anwar {
139abd5576bSMD Danish Anwar 	struct prueth *prueth = emac->prueth;
140abd5576bSMD Danish Anwar 	int slice = prueth_emac_slice(emac);
141abd5576bSMD Danish Anwar 	u32 txcfg, txcfg_reg, pcnt_reg;
142abd5576bSMD Danish Anwar 	struct regmap *mii_rt;
143abd5576bSMD Danish Anwar 
144abd5576bSMD Danish Anwar 	mii_rt = prueth->mii_rt;
145abd5576bSMD Danish Anwar 
146e9b4ece7SMD Danish Anwar 	txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
147e9b4ece7SMD Danish Anwar 				       PRUSS_MII_RT_TXCFG1;
148e9b4ece7SMD Danish Anwar 	pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
149e9b4ece7SMD Danish Anwar 				       PRUSS_MII_RT_RX_PCNT1;
150e9b4ece7SMD Danish Anwar 
151e9b4ece7SMD Danish Anwar 	txcfg = MII_TXCFG_DEFAULT;
152e9b4ece7SMD Danish Anwar 
153e9b4ece7SMD Danish Anwar 	/* In MII mode TX lines swapped inside ICSSG, so TX_MUX_SEL cfg need
154e9b4ece7SMD Danish Anwar 	 * to be swapped also comparing to RGMII mode.
155e9b4ece7SMD Danish Anwar 	 */
156e9b4ece7SMD Danish Anwar 	if (emac->phy_if == PHY_INTERFACE_MODE_MII && slice == ICSS_MII0)
157e9b4ece7SMD Danish Anwar 		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
158e9b4ece7SMD Danish Anwar 	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1)
159e9b4ece7SMD Danish Anwar 		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
160e9b4ece7SMD Danish Anwar 
161e9b4ece7SMD Danish Anwar 	regmap_write(mii_rt, txcfg_reg, txcfg);
162e9b4ece7SMD Danish Anwar 	regmap_write(mii_rt, pcnt_reg, 0x1);
163e9b4ece7SMD Danish Anwar }
164e9b4ece7SMD Danish Anwar 
icssg_miig_queues_init(struct prueth * prueth,int slice)165e9b4ece7SMD Danish Anwar static void icssg_miig_queues_init(struct prueth *prueth, int slice)
166e9b4ece7SMD Danish Anwar {
167e9b4ece7SMD Danish Anwar 	struct regmap *miig_rt = prueth->miig_rt;
168e9b4ece7SMD Danish Anwar 	void __iomem *smem = prueth->shram.va;
169e9b4ece7SMD Danish Anwar 	u8 pd[ICSSG_SPECIAL_PD_SIZE];
170e9b4ece7SMD Danish Anwar 	int queue = 0, i, j;
171e9b4ece7SMD Danish Anwar 	u32 *pdword;
172e9b4ece7SMD Danish Anwar 
173e9b4ece7SMD Danish Anwar 	/* reset hwqueues */
174e9b4ece7SMD Danish Anwar 	if (slice)
175e9b4ece7SMD Danish Anwar 		queue = ICSSG_NUM_TX_QUEUES;
176e9b4ece7SMD Danish Anwar 
177e9b4ece7SMD Danish Anwar 	for (i = 0; i < ICSSG_NUM_TX_QUEUES; i++) {
178e9b4ece7SMD Danish Anwar 		regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET, queue);
179e9b4ece7SMD Danish Anwar 		queue++;
180e9b4ece7SMD Danish Anwar 	}
181e9b4ece7SMD Danish Anwar 
182e9b4ece7SMD Danish Anwar 	queue = slice ? RECYCLE_Q_SLICE1 : RECYCLE_Q_SLICE0;
183e9b4ece7SMD Danish Anwar 	regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET, queue);
184e9b4ece7SMD Danish Anwar 
185e9b4ece7SMD Danish Anwar 	for (i = 0; i < ICSSG_NUM_OTHER_QUEUES; i++) {
186e9b4ece7SMD Danish Anwar 		regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET,
187e9b4ece7SMD Danish Anwar 			     hwq_map[slice][i].queue);
188e9b4ece7SMD Danish Anwar 	}
189e9b4ece7SMD Danish Anwar 
190e9b4ece7SMD Danish Anwar 	/* initialize packet descriptors in SMEM */
191e9b4ece7SMD Danish Anwar 	/* push pakcet descriptors to hwqueues */
192e9b4ece7SMD Danish Anwar 
193e9b4ece7SMD Danish Anwar 	pdword = (u32 *)pd;
194e9b4ece7SMD Danish Anwar 	for (j = 0; j < ICSSG_NUM_OTHER_QUEUES; j++) {
195e9b4ece7SMD Danish Anwar 		const struct map *mp;
196e9b4ece7SMD Danish Anwar 		int pd_size, num_pds;
197e9b4ece7SMD Danish Anwar 		u32 pdaddr;
198e9b4ece7SMD Danish Anwar 
199e9b4ece7SMD Danish Anwar 		mp = &hwq_map[slice][j];
200e9b4ece7SMD Danish Anwar 		if (mp->special) {
201e9b4ece7SMD Danish Anwar 			pd_size = ICSSG_SPECIAL_PD_SIZE;
202e9b4ece7SMD Danish Anwar 			num_pds = ICSSG_NUM_SPECIAL_PDS;
203e9b4ece7SMD Danish Anwar 		} else	{
204e9b4ece7SMD Danish Anwar 			pd_size = ICSSG_NORMAL_PD_SIZE;
205e9b4ece7SMD Danish Anwar 			num_pds = ICSSG_NUM_NORMAL_PDS;
206e9b4ece7SMD Danish Anwar 		}
207e9b4ece7SMD Danish Anwar 
208e9b4ece7SMD Danish Anwar 		for (i = 0; i < num_pds; i++) {
209e9b4ece7SMD Danish Anwar 			memset(pd, 0, pd_size);
210e9b4ece7SMD Danish Anwar 
211e9b4ece7SMD Danish Anwar 			pdword[0] &= ICSSG_FLAG_MASK;
212e9b4ece7SMD Danish Anwar 			pdword[0] |= mp->flags;
213e9b4ece7SMD Danish Anwar 			pdaddr = mp->pd_addr_start + i * pd_size;
214e9b4ece7SMD Danish Anwar 
215e9b4ece7SMD Danish Anwar 			memcpy_toio(smem + pdaddr, pd, pd_size);
216e9b4ece7SMD Danish Anwar 			queue = mp->queue;
217e9b4ece7SMD Danish Anwar 			regmap_write(miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue,
218e9b4ece7SMD Danish Anwar 				     pdaddr);
219e9b4ece7SMD Danish Anwar 		}
220e9b4ece7SMD Danish Anwar 	}
221e9b4ece7SMD Danish Anwar }
222e9b4ece7SMD Danish Anwar 
icssg_config_ipg(struct prueth_emac * emac)223e9b4ece7SMD Danish Anwar void icssg_config_ipg(struct prueth_emac *emac)
224e9b4ece7SMD Danish Anwar {
225e9b4ece7SMD Danish Anwar 	struct prueth *prueth = emac->prueth;
226e9b4ece7SMD Danish Anwar 	int slice = prueth_emac_slice(emac);
22795c2e689SDiogo Ivo 	u32 ipg;
228e9b4ece7SMD Danish Anwar 
229e9b4ece7SMD Danish Anwar 	switch (emac->speed) {
230e9b4ece7SMD Danish Anwar 	case SPEED_1000:
23195c2e689SDiogo Ivo 		ipg = emac->is_sr1 ? MII_RT_TX_IPG_1G_SR1 : MII_RT_TX_IPG_1G;
232e9b4ece7SMD Danish Anwar 		break;
233e9b4ece7SMD Danish Anwar 	case SPEED_100:
23495c2e689SDiogo Ivo 		ipg = emac->is_sr1 ? MII_RT_TX_IPG_100M_SR1 : MII_RT_TX_IPG_100M;
235e9b4ece7SMD Danish Anwar 		break;
236443a2367SGrygorii Strashko 	case SPEED_10:
23795c2e689SDiogo Ivo 		/* Firmware hardcodes IPG for SR1.0 */
23895c2e689SDiogo Ivo 		if (emac->is_sr1)
23995c2e689SDiogo Ivo 			return;
240443a2367SGrygorii Strashko 		/* IPG for 10M is same as 100M */
24195c2e689SDiogo Ivo 		ipg = MII_RT_TX_IPG_100M;
242443a2367SGrygorii Strashko 		break;
243e9b4ece7SMD Danish Anwar 	default:
244e9b4ece7SMD Danish Anwar 		/* Other links speeds not supported */
245e9b4ece7SMD Danish Anwar 		netdev_err(emac->ndev, "Unsupported link speed\n");
246e9b4ece7SMD Danish Anwar 		return;
247e9b4ece7SMD Danish Anwar 	}
24895c2e689SDiogo Ivo 
24995c2e689SDiogo Ivo 	icssg_mii_update_ipg(prueth->mii_rt, slice, ipg);
250e9b4ece7SMD Danish Anwar }
251a8ea8d53SMD Danish Anwar EXPORT_SYMBOL_GPL(icssg_config_ipg);
252e9b4ece7SMD Danish Anwar 
emac_r30_cmd_init(struct prueth_emac * emac)253e9b4ece7SMD Danish Anwar static void emac_r30_cmd_init(struct prueth_emac *emac)
254e9b4ece7SMD Danish Anwar {
255e9b4ece7SMD Danish Anwar 	struct icssg_r30_cmd __iomem *p;
256e9b4ece7SMD Danish Anwar 	int i;
257e9b4ece7SMD Danish Anwar 
258e9b4ece7SMD Danish Anwar 	p = emac->dram.va + MGR_R30_CMD_OFFSET;
259e9b4ece7SMD Danish Anwar 
260e9b4ece7SMD Danish Anwar 	for (i = 0; i < 4; i++)
261e9b4ece7SMD Danish Anwar 		writel(EMAC_NONE, &p->cmd[i]);
262e9b4ece7SMD Danish Anwar }
263e9b4ece7SMD Danish Anwar 
emac_r30_is_done(struct prueth_emac * emac)264e9b4ece7SMD Danish Anwar static int emac_r30_is_done(struct prueth_emac *emac)
265e9b4ece7SMD Danish Anwar {
266e9b4ece7SMD Danish Anwar 	const struct icssg_r30_cmd __iomem *p;
267e9b4ece7SMD Danish Anwar 	u32 cmd;
268e9b4ece7SMD Danish Anwar 	int i;
269e9b4ece7SMD Danish Anwar 
270e9b4ece7SMD Danish Anwar 	p = emac->dram.va + MGR_R30_CMD_OFFSET;
271e9b4ece7SMD Danish Anwar 
272e9b4ece7SMD Danish Anwar 	for (i = 0; i < 4; i++) {
273e9b4ece7SMD Danish Anwar 		cmd = readl(&p->cmd[i]);
274e9b4ece7SMD Danish Anwar 		if (cmd != EMAC_NONE)
275e9b4ece7SMD Danish Anwar 			return 0;
276e9b4ece7SMD Danish Anwar 	}
277e9b4ece7SMD Danish Anwar 
278e9b4ece7SMD Danish Anwar 	return 1;
279e9b4ece7SMD Danish Anwar }
280e9b4ece7SMD Danish Anwar 
prueth_fw_offload_buffer_setup(struct prueth_emac * emac)28195540ad6SMD Danish Anwar static int prueth_fw_offload_buffer_setup(struct prueth_emac *emac)
282abd5576bSMD Danish Anwar {
283abd5576bSMD Danish Anwar 	struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
284abd5576bSMD Danish Anwar 	struct icssg_rxq_ctx __iomem *rxq_ctx;
285abd5576bSMD Danish Anwar 	struct prueth *prueth = emac->prueth;
286abd5576bSMD Danish Anwar 	int slice = prueth_emac_slice(emac);
287abd5576bSMD Danish Anwar 	u32 addr;
288abd5576bSMD Danish Anwar 	int i;
289abd5576bSMD Danish Anwar 
290abd5576bSMD Danish Anwar 	addr = lower_32_bits(prueth->msmcram.pa);
291abd5576bSMD Danish Anwar 	if (slice)
292abd5576bSMD Danish Anwar 		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
293abd5576bSMD Danish Anwar 
294abd5576bSMD Danish Anwar 	if (addr % SZ_64K) {
295abd5576bSMD Danish Anwar 		dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
296abd5576bSMD Danish Anwar 		return -EINVAL;
297abd5576bSMD Danish Anwar 	}
298abd5576bSMD Danish Anwar 
299abd5576bSMD Danish Anwar 	bpool_cfg = emac->dram.va + BUFFER_POOL_0_ADDR_OFFSET;
300abd5576bSMD Danish Anwar 	/* workaround for f/w bug. bpool 0 needs to be initialized */
301abd5576bSMD Danish Anwar 	for (i = 0; i <  PRUETH_NUM_BUF_POOLS; i++) {
302abd5576bSMD Danish Anwar 		writel(addr, &bpool_cfg[i].addr);
303abd5576bSMD Danish Anwar 		writel(PRUETH_EMAC_BUF_POOL_SIZE, &bpool_cfg[i].len);
304abd5576bSMD Danish Anwar 		addr += PRUETH_EMAC_BUF_POOL_SIZE;
305abd5576bSMD Danish Anwar 	}
306abd5576bSMD Danish Anwar 
307abd5576bSMD Danish Anwar 	if (!slice)
308abd5576bSMD Danish Anwar 		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
309abd5576bSMD Danish Anwar 	else
310abd5576bSMD Danish Anwar 		addr += PRUETH_SW_NUM_BUF_POOLS_HOST * PRUETH_SW_BUF_POOL_SIZE_HOST;
311abd5576bSMD Danish Anwar 
312abd5576bSMD Danish Anwar 	for (i = PRUETH_NUM_BUF_POOLS;
313abd5576bSMD Danish Anwar 	     i < 2 * PRUETH_SW_NUM_BUF_POOLS_HOST + PRUETH_NUM_BUF_POOLS;
314abd5576bSMD Danish Anwar 	     i++) {
315abd5576bSMD Danish Anwar 		/* The driver only uses first 4 queues per PRU so only initialize them */
316abd5576bSMD Danish Anwar 		if (i % PRUETH_SW_NUM_BUF_POOLS_HOST < PRUETH_SW_NUM_BUF_POOLS_PER_PRU) {
317abd5576bSMD Danish Anwar 			writel(addr, &bpool_cfg[i].addr);
318abd5576bSMD Danish Anwar 			writel(PRUETH_SW_BUF_POOL_SIZE_HOST, &bpool_cfg[i].len);
319abd5576bSMD Danish Anwar 			addr += PRUETH_SW_BUF_POOL_SIZE_HOST;
320abd5576bSMD Danish Anwar 		} else {
321abd5576bSMD Danish Anwar 			writel(0, &bpool_cfg[i].addr);
322abd5576bSMD Danish Anwar 			writel(0, &bpool_cfg[i].len);
323abd5576bSMD Danish Anwar 		}
324abd5576bSMD Danish Anwar 	}
325abd5576bSMD Danish Anwar 
326abd5576bSMD Danish Anwar 	if (!slice)
327abd5576bSMD Danish Anwar 		addr += PRUETH_SW_NUM_BUF_POOLS_HOST * PRUETH_SW_BUF_POOL_SIZE_HOST;
328abd5576bSMD Danish Anwar 	else
329abd5576bSMD Danish Anwar 		addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
330abd5576bSMD Danish Anwar 
331abd5576bSMD Danish Anwar 	rxq_ctx = emac->dram.va + HOST_RX_Q_PRE_CONTEXT_OFFSET;
332abd5576bSMD Danish Anwar 	for (i = 0; i < 3; i++)
333abd5576bSMD Danish Anwar 		writel(addr, &rxq_ctx->start[i]);
334abd5576bSMD Danish Anwar 
335abd5576bSMD Danish Anwar 	addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
336abd5576bSMD Danish Anwar 	writel(addr - SZ_2K, &rxq_ctx->end);
337abd5576bSMD Danish Anwar 
338abd5576bSMD Danish Anwar 	return 0;
339abd5576bSMD Danish Anwar }
340abd5576bSMD Danish Anwar 
prueth_emac_buffer_setup(struct prueth_emac * emac)341e9b4ece7SMD Danish Anwar static int prueth_emac_buffer_setup(struct prueth_emac *emac)
342e9b4ece7SMD Danish Anwar {
343e9b4ece7SMD Danish Anwar 	struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
344e9b4ece7SMD Danish Anwar 	struct icssg_rxq_ctx __iomem *rxq_ctx;
345e9b4ece7SMD Danish Anwar 	struct prueth *prueth = emac->prueth;
346e9b4ece7SMD Danish Anwar 	int slice = prueth_emac_slice(emac);
347e9b4ece7SMD Danish Anwar 	u32 addr;
348e9b4ece7SMD Danish Anwar 	int i;
349e9b4ece7SMD Danish Anwar 
350e9b4ece7SMD Danish Anwar 	/* Layout to have 64KB aligned buffer pool
351e9b4ece7SMD Danish Anwar 	 * |BPOOL0|BPOOL1|RX_CTX0|RX_CTX1|
352e9b4ece7SMD Danish Anwar 	 */
353e9b4ece7SMD Danish Anwar 
354e9b4ece7SMD Danish Anwar 	addr = lower_32_bits(prueth->msmcram.pa);
355e9b4ece7SMD Danish Anwar 	if (slice)
356e9b4ece7SMD Danish Anwar 		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
357e9b4ece7SMD Danish Anwar 
358e9b4ece7SMD Danish Anwar 	if (addr % SZ_64K) {
359e9b4ece7SMD Danish Anwar 		dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
360e9b4ece7SMD Danish Anwar 		return -EINVAL;
361e9b4ece7SMD Danish Anwar 	}
362e9b4ece7SMD Danish Anwar 
363e9b4ece7SMD Danish Anwar 	bpool_cfg = emac->dram.va + BUFFER_POOL_0_ADDR_OFFSET;
364e9b4ece7SMD Danish Anwar 	/* workaround for f/w bug. bpool 0 needs to be initilalized */
365e9b4ece7SMD Danish Anwar 	writel(addr, &bpool_cfg[0].addr);
366e9b4ece7SMD Danish Anwar 	writel(0, &bpool_cfg[0].len);
367e9b4ece7SMD Danish Anwar 
368e9b4ece7SMD Danish Anwar 	for (i = PRUETH_EMAC_BUF_POOL_START;
369e9b4ece7SMD Danish Anwar 	     i < PRUETH_EMAC_BUF_POOL_START + PRUETH_NUM_BUF_POOLS;
370e9b4ece7SMD Danish Anwar 	     i++) {
371e9b4ece7SMD Danish Anwar 		writel(addr, &bpool_cfg[i].addr);
372e9b4ece7SMD Danish Anwar 		writel(PRUETH_EMAC_BUF_POOL_SIZE, &bpool_cfg[i].len);
373e9b4ece7SMD Danish Anwar 		addr += PRUETH_EMAC_BUF_POOL_SIZE;
374e9b4ece7SMD Danish Anwar 	}
375e9b4ece7SMD Danish Anwar 
376e9b4ece7SMD Danish Anwar 	if (!slice)
377e9b4ece7SMD Danish Anwar 		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
378e9b4ece7SMD Danish Anwar 	else
379e9b4ece7SMD Danish Anwar 		addr += PRUETH_EMAC_RX_CTX_BUF_SIZE * 2;
380e9b4ece7SMD Danish Anwar 
381e9b4ece7SMD Danish Anwar 	/* Pre-emptible RX buffer queue */
382e9b4ece7SMD Danish Anwar 	rxq_ctx = emac->dram.va + HOST_RX_Q_PRE_CONTEXT_OFFSET;
383e9b4ece7SMD Danish Anwar 	for (i = 0; i < 3; i++)
384e9b4ece7SMD Danish Anwar 		writel(addr, &rxq_ctx->start[i]);
385e9b4ece7SMD Danish Anwar 
386e9b4ece7SMD Danish Anwar 	addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
387e9b4ece7SMD Danish Anwar 	writel(addr, &rxq_ctx->end);
388e9b4ece7SMD Danish Anwar 
389e9b4ece7SMD Danish Anwar 	/* Express RX buffer queue */
390e9b4ece7SMD Danish Anwar 	rxq_ctx = emac->dram.va + HOST_RX_Q_EXP_CONTEXT_OFFSET;
391e9b4ece7SMD Danish Anwar 	for (i = 0; i < 3; i++)
392e9b4ece7SMD Danish Anwar 		writel(addr, &rxq_ctx->start[i]);
393e9b4ece7SMD Danish Anwar 
394e9b4ece7SMD Danish Anwar 	addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
395e9b4ece7SMD Danish Anwar 	writel(addr, &rxq_ctx->end);
396e9b4ece7SMD Danish Anwar 
397e9b4ece7SMD Danish Anwar 	return 0;
398e9b4ece7SMD Danish Anwar }
399e9b4ece7SMD Danish Anwar 
icssg_init_emac_mode(struct prueth * prueth)400e9b4ece7SMD Danish Anwar static void icssg_init_emac_mode(struct prueth *prueth)
401e9b4ece7SMD Danish Anwar {
402e9b4ece7SMD Danish Anwar 	/* When the device is configured as a bridge and it is being brought
403e9b4ece7SMD Danish Anwar 	 * back to the emac mode, the host mac address has to be set as 0.
404e9b4ece7SMD Danish Anwar 	 */
405abd5576bSMD Danish Anwar 	u32 addr = prueth->shram.pa + EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET;
406abd5576bSMD Danish Anwar 	int i;
407e9b4ece7SMD Danish Anwar 	u8 mac[ETH_ALEN] = { 0 };
408e9b4ece7SMD Danish Anwar 
409e9b4ece7SMD Danish Anwar 	if (prueth->emacs_initialized)
410e9b4ece7SMD Danish Anwar 		return;
411e9b4ece7SMD Danish Anwar 
412abd5576bSMD Danish Anwar 	/* Set VLAN TABLE address base */
413abd5576bSMD Danish Anwar 	regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, SMEM_VLAN_OFFSET_MASK,
414abd5576bSMD Danish Anwar 			   addr <<  SMEM_VLAN_OFFSET);
415abd5576bSMD Danish Anwar 	/* Set enable VLAN aware mode, and FDBs for all PRUs */
416abd5576bSMD Danish Anwar 	regmap_write(prueth->miig_rt, FDB_GEN_CFG2, (FDB_PRU0_EN | FDB_PRU1_EN | FDB_HOST_EN));
417abd5576bSMD Danish Anwar 	prueth->vlan_tbl = (struct prueth_vlan_tbl __force *)(prueth->shram.va +
418abd5576bSMD Danish Anwar 			    EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET);
419abd5576bSMD Danish Anwar 	for (i = 0; i < SZ_4K - 1; i++) {
420abd5576bSMD Danish Anwar 		prueth->vlan_tbl[i].fid = i;
421abd5576bSMD Danish Anwar 		prueth->vlan_tbl[i].fid_c1 = 0;
422abd5576bSMD Danish Anwar 	}
423e9b4ece7SMD Danish Anwar 	/* Clear host MAC address */
424e9b4ece7SMD Danish Anwar 	icssg_class_set_host_mac_addr(prueth->miig_rt, mac);
425e9b4ece7SMD Danish Anwar }
426e9b4ece7SMD Danish Anwar 
icssg_init_fw_offload_mode(struct prueth * prueth)42795540ad6SMD Danish Anwar static void icssg_init_fw_offload_mode(struct prueth *prueth)
428abd5576bSMD Danish Anwar {
429abd5576bSMD Danish Anwar 	u32 addr = prueth->shram.pa + EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET;
430abd5576bSMD Danish Anwar 	int i;
431abd5576bSMD Danish Anwar 
432abd5576bSMD Danish Anwar 	if (prueth->emacs_initialized)
433abd5576bSMD Danish Anwar 		return;
434abd5576bSMD Danish Anwar 
435abd5576bSMD Danish Anwar 	/* Set VLAN TABLE address base */
436abd5576bSMD Danish Anwar 	regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, SMEM_VLAN_OFFSET_MASK,
437abd5576bSMD Danish Anwar 			   addr <<  SMEM_VLAN_OFFSET);
438abd5576bSMD Danish Anwar 	/* Set enable VLAN aware mode, and FDBs for all PRUs */
439abd5576bSMD Danish Anwar 	regmap_write(prueth->miig_rt, FDB_GEN_CFG2, FDB_EN_ALL);
440abd5576bSMD Danish Anwar 	prueth->vlan_tbl = (struct prueth_vlan_tbl __force *)(prueth->shram.va +
441abd5576bSMD Danish Anwar 			    EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET);
442abd5576bSMD Danish Anwar 	for (i = 0; i < SZ_4K - 1; i++) {
443abd5576bSMD Danish Anwar 		prueth->vlan_tbl[i].fid = i;
444abd5576bSMD Danish Anwar 		prueth->vlan_tbl[i].fid_c1 = 0;
445abd5576bSMD Danish Anwar 	}
446abd5576bSMD Danish Anwar 
447abd5576bSMD Danish Anwar 	if (prueth->hw_bridge_dev)
448abd5576bSMD Danish Anwar 		icssg_class_set_host_mac_addr(prueth->miig_rt, prueth->hw_bridge_dev->dev_addr);
449abd5576bSMD Danish Anwar 	icssg_set_pvid(prueth, prueth->default_vlan, PRUETH_PORT_HOST);
450abd5576bSMD Danish Anwar }
451abd5576bSMD Danish Anwar 
icssg_config(struct prueth * prueth,struct prueth_emac * emac,int slice)452e9b4ece7SMD Danish Anwar int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice)
453e9b4ece7SMD Danish Anwar {
454e9b4ece7SMD Danish Anwar 	void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET;
455e9b4ece7SMD Danish Anwar 	struct icssg_flow_cfg __iomem *flow_cfg;
456e9b4ece7SMD Danish Anwar 	int ret;
457e9b4ece7SMD Danish Anwar 
45895540ad6SMD Danish Anwar 	if (prueth->is_switch_mode || prueth->is_hsr_offload_mode)
45995540ad6SMD Danish Anwar 		icssg_init_fw_offload_mode(prueth);
460abd5576bSMD Danish Anwar 	else
461e9b4ece7SMD Danish Anwar 		icssg_init_emac_mode(prueth);
462e9b4ece7SMD Danish Anwar 
463e9b4ece7SMD Danish Anwar 	memset_io(config, 0, TAS_GATE_MASK_LIST0);
464e9b4ece7SMD Danish Anwar 	icssg_miig_queues_init(prueth, slice);
465e9b4ece7SMD Danish Anwar 
466e9b4ece7SMD Danish Anwar 	emac->speed = SPEED_1000;
467e9b4ece7SMD Danish Anwar 	emac->duplex = DUPLEX_FULL;
468e9b4ece7SMD Danish Anwar 	if (!phy_interface_mode_is_rgmii(emac->phy_if)) {
469e9b4ece7SMD Danish Anwar 		emac->speed = SPEED_100;
470e9b4ece7SMD Danish Anwar 		emac->duplex = DUPLEX_FULL;
471e9b4ece7SMD Danish Anwar 	}
472e9b4ece7SMD Danish Anwar 	regmap_update_bits(prueth->miig_rt, ICSSG_CFG_OFFSET,
473e9b4ece7SMD Danish Anwar 			   ICSSG_CFG_DEFAULT, ICSSG_CFG_DEFAULT);
474e9b4ece7SMD Danish Anwar 	icssg_miig_set_interface_mode(prueth->miig_rt, slice, emac->phy_if);
47595540ad6SMD Danish Anwar 	if (prueth->is_switch_mode || prueth->is_hsr_offload_mode)
47695540ad6SMD Danish Anwar 		icssg_config_mii_init_fw_offload(emac);
477abd5576bSMD Danish Anwar 	else
478e9b4ece7SMD Danish Anwar 		icssg_config_mii_init(emac);
479e9b4ece7SMD Danish Anwar 	icssg_config_ipg(emac);
480e9b4ece7SMD Danish Anwar 	icssg_update_rgmii_cfg(prueth->miig_rt, emac);
481e9b4ece7SMD Danish Anwar 
482e9b4ece7SMD Danish Anwar 	/* set GPI mode */
483e9b4ece7SMD Danish Anwar 	pruss_cfg_gpimode(prueth->pruss, prueth->pru_id[slice],
484e9b4ece7SMD Danish Anwar 			  PRUSS_GPI_MODE_MII);
485e9b4ece7SMD Danish Anwar 
486e9b4ece7SMD Danish Anwar 	/* enable XFR shift for PRU and RTU */
487e9b4ece7SMD Danish Anwar 	pruss_cfg_xfr_enable(prueth->pruss, PRU_TYPE_PRU, true);
488e9b4ece7SMD Danish Anwar 	pruss_cfg_xfr_enable(prueth->pruss, PRU_TYPE_RTU, true);
489e9b4ece7SMD Danish Anwar 
490e9b4ece7SMD Danish Anwar 	/* set C28 to 0x100 */
491e9b4ece7SMD Danish Anwar 	pru_rproc_set_ctable(prueth->pru[slice], PRU_C28, 0x100 << 8);
492e9b4ece7SMD Danish Anwar 	pru_rproc_set_ctable(prueth->rtu[slice], PRU_C28, 0x100 << 8);
493e9b4ece7SMD Danish Anwar 	pru_rproc_set_ctable(prueth->txpru[slice], PRU_C28, 0x100 << 8);
494e9b4ece7SMD Danish Anwar 
495e9b4ece7SMD Danish Anwar 	flow_cfg = config + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET;
496e9b4ece7SMD Danish Anwar 	writew(emac->rx_flow_id_base, &flow_cfg->rx_base_flow);
497e9b4ece7SMD Danish Anwar 	writew(0, &flow_cfg->mgm_base_flow);
498e9b4ece7SMD Danish Anwar 	writeb(0, config + SPL_PKT_DEFAULT_PRIORITY);
499e9b4ece7SMD Danish Anwar 	writeb(0, config + QUEUE_NUM_UNTAGGED);
500e9b4ece7SMD Danish Anwar 
50195540ad6SMD Danish Anwar 	if (prueth->is_switch_mode || prueth->is_hsr_offload_mode)
50295540ad6SMD Danish Anwar 		ret = prueth_fw_offload_buffer_setup(emac);
503abd5576bSMD Danish Anwar 	else
504e9b4ece7SMD Danish Anwar 		ret = prueth_emac_buffer_setup(emac);
505e9b4ece7SMD Danish Anwar 	if (ret)
506e9b4ece7SMD Danish Anwar 		return ret;
507e9b4ece7SMD Danish Anwar 
508e9b4ece7SMD Danish Anwar 	emac_r30_cmd_init(emac);
509e9b4ece7SMD Danish Anwar 
510e9b4ece7SMD Danish Anwar 	return 0;
511e9b4ece7SMD Danish Anwar }
512a8ea8d53SMD Danish Anwar EXPORT_SYMBOL_GPL(icssg_config);
513e9b4ece7SMD Danish Anwar 
514e9b4ece7SMD Danish Anwar /* Bitmask for ICSSG r30 commands */
515e9b4ece7SMD Danish Anwar static const struct icssg_r30_cmd emac_r32_bitmask[] = {
516389db4fdSMD Danish Anwar 	{{0xffff0004, 0xffff0100, 0xffff0004, EMAC_NONE}},	/* EMAC_PORT_DISABLE */
517e9b4ece7SMD Danish Anwar 	{{0xfffb0040, 0xfeff0200, 0xfeff0200, EMAC_NONE}},	/* EMAC_PORT_BLOCK */
518389db4fdSMD Danish Anwar 	{{0xffbb0000, 0xfcff0000, 0xdcfb0000, EMAC_NONE}},	/* EMAC_PORT_FORWARD */
519e9b4ece7SMD Danish Anwar 	{{0xffbb0000, 0xfcff0000, 0xfcff2000, EMAC_NONE}},	/* EMAC_PORT_FORWARD_WO_LEARNING */
520e9b4ece7SMD Danish Anwar 	{{0xffff0001, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},	/* ACCEPT ALL */
521e9b4ece7SMD Danish Anwar 	{{0xfffe0002, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},	/* ACCEPT TAGGED */
522e9b4ece7SMD Danish Anwar 	{{0xfffc0000, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},	/* ACCEPT UNTAGGED and PRIO */
523e9b4ece7SMD Danish Anwar 	{{EMAC_NONE,  0xffff0020, EMAC_NONE, EMAC_NONE}},	/* TAS Trigger List change */
524e9b4ece7SMD Danish Anwar 	{{EMAC_NONE,  0xdfff1000, EMAC_NONE, EMAC_NONE}},	/* TAS set state ENABLE*/
525e9b4ece7SMD Danish Anwar 	{{EMAC_NONE,  0xefff2000, EMAC_NONE, EMAC_NONE}},	/* TAS set state RESET*/
526e9b4ece7SMD Danish Anwar 	{{EMAC_NONE,  0xcfff0000, EMAC_NONE, EMAC_NONE}},	/* TAS set state DISABLE*/
527e9b4ece7SMD Danish Anwar 	{{EMAC_NONE,  EMAC_NONE,  0xffff0400, EMAC_NONE}},	/* UC flooding ENABLE*/
528e9b4ece7SMD Danish Anwar 	{{EMAC_NONE,  EMAC_NONE,  0xfbff0000, EMAC_NONE}},	/* UC flooding DISABLE*/
529e9b4ece7SMD Danish Anwar 	{{EMAC_NONE,  EMAC_NONE,  0xffff0800, EMAC_NONE}},	/* MC flooding ENABLE*/
530e9b4ece7SMD Danish Anwar 	{{EMAC_NONE,  EMAC_NONE,  0xf7ff0000, EMAC_NONE}},	/* MC flooding DISABLE*/
531e9b4ece7SMD Danish Anwar 	{{EMAC_NONE,  0xffff4000, EMAC_NONE, EMAC_NONE}},	/* Preemption on Tx ENABLE*/
532e9b4ece7SMD Danish Anwar 	{{EMAC_NONE,  0xbfff0000, EMAC_NONE, EMAC_NONE}},	/* Preemption on Tx DISABLE*/
533e9b4ece7SMD Danish Anwar 	{{0xffff0010,  EMAC_NONE, 0xffff0010, EMAC_NONE}},	/* VLAN AWARE*/
534*56375086SRavi Gunasekaran 	{{0xffef0000,  EMAC_NONE, 0xffef0000, EMAC_NONE}},	/* VLAN UNWARE*/
535*56375086SRavi Gunasekaran 	{{0xffff2000, EMAC_NONE, EMAC_NONE, EMAC_NONE}},	/* HSR_RX_OFFLOAD_ENABLE */
536*56375086SRavi Gunasekaran 	{{0xdfff0000, EMAC_NONE, EMAC_NONE, EMAC_NONE}}		/* HSR_RX_OFFLOAD_DISABLE */
537e9b4ece7SMD Danish Anwar };
538e9b4ece7SMD Danish Anwar 
icssg_set_port_state(struct prueth_emac * emac,enum icssg_port_state_cmd cmd)539a8ea8d53SMD Danish Anwar int icssg_set_port_state(struct prueth_emac *emac,
540e9b4ece7SMD Danish Anwar 			 enum icssg_port_state_cmd cmd)
541e9b4ece7SMD Danish Anwar {
542e9b4ece7SMD Danish Anwar 	struct icssg_r30_cmd __iomem *p;
543e9b4ece7SMD Danish Anwar 	int ret = -ETIMEDOUT;
544e9b4ece7SMD Danish Anwar 	int done = 0;
545e9b4ece7SMD Danish Anwar 	int i;
546e9b4ece7SMD Danish Anwar 
547e9b4ece7SMD Danish Anwar 	p = emac->dram.va + MGR_R30_CMD_OFFSET;
548e9b4ece7SMD Danish Anwar 
549e9b4ece7SMD Danish Anwar 	if (cmd >= ICSSG_EMAC_PORT_MAX_COMMANDS) {
550e9b4ece7SMD Danish Anwar 		netdev_err(emac->ndev, "invalid port command\n");
551e9b4ece7SMD Danish Anwar 		return -EINVAL;
552e9b4ece7SMD Danish Anwar 	}
553e9b4ece7SMD Danish Anwar 
554e9b4ece7SMD Danish Anwar 	/* only one command at a time allowed to firmware */
555e9b4ece7SMD Danish Anwar 	mutex_lock(&emac->cmd_lock);
556e9b4ece7SMD Danish Anwar 
557e9b4ece7SMD Danish Anwar 	for (i = 0; i < 4; i++)
558e9b4ece7SMD Danish Anwar 		writel(emac_r32_bitmask[cmd].cmd[i], &p->cmd[i]);
559e9b4ece7SMD Danish Anwar 
560e9b4ece7SMD Danish Anwar 	/* wait for done */
561e9b4ece7SMD Danish Anwar 	ret = read_poll_timeout(emac_r30_is_done, done, done == 1,
562e9b4ece7SMD Danish Anwar 				1000, 10000, false, emac);
563e9b4ece7SMD Danish Anwar 
564e9b4ece7SMD Danish Anwar 	if (ret == -ETIMEDOUT)
565e9b4ece7SMD Danish Anwar 		netdev_err(emac->ndev, "timeout waiting for command done\n");
566e9b4ece7SMD Danish Anwar 
567e9b4ece7SMD Danish Anwar 	mutex_unlock(&emac->cmd_lock);
568e9b4ece7SMD Danish Anwar 
569e9b4ece7SMD Danish Anwar 	return ret;
570e9b4ece7SMD Danish Anwar }
571a8ea8d53SMD Danish Anwar EXPORT_SYMBOL_GPL(icssg_set_port_state);
572e9b4ece7SMD Danish Anwar 
icssg_config_half_duplex(struct prueth_emac * emac)5730a205f0fSMD Danish Anwar void icssg_config_half_duplex(struct prueth_emac *emac)
5740a205f0fSMD Danish Anwar {
5750a205f0fSMD Danish Anwar 	u32 val;
5760a205f0fSMD Danish Anwar 
5770a205f0fSMD Danish Anwar 	if (!emac->half_duplex)
5780a205f0fSMD Danish Anwar 		return;
5790a205f0fSMD Danish Anwar 
5800a205f0fSMD Danish Anwar 	val = get_random_u32();
5810a205f0fSMD Danish Anwar 	writel(val, emac->dram.va + HD_RAND_SEED_OFFSET);
5820a205f0fSMD Danish Anwar }
583a8ea8d53SMD Danish Anwar EXPORT_SYMBOL_GPL(icssg_config_half_duplex);
5840a205f0fSMD Danish Anwar 
icssg_config_set_speed(struct prueth_emac * emac)585e9b4ece7SMD Danish Anwar void icssg_config_set_speed(struct prueth_emac *emac)
586e9b4ece7SMD Danish Anwar {
587e9b4ece7SMD Danish Anwar 	u8 fw_speed;
588e9b4ece7SMD Danish Anwar 
589e9b4ece7SMD Danish Anwar 	switch (emac->speed) {
590e9b4ece7SMD Danish Anwar 	case SPEED_1000:
591e9b4ece7SMD Danish Anwar 		fw_speed = FW_LINK_SPEED_1G;
592e9b4ece7SMD Danish Anwar 		break;
593e9b4ece7SMD Danish Anwar 	case SPEED_100:
594e9b4ece7SMD Danish Anwar 		fw_speed = FW_LINK_SPEED_100M;
595e9b4ece7SMD Danish Anwar 		break;
596443a2367SGrygorii Strashko 	case SPEED_10:
597443a2367SGrygorii Strashko 		fw_speed = FW_LINK_SPEED_10M;
598443a2367SGrygorii Strashko 		break;
599e9b4ece7SMD Danish Anwar 	default:
600e9b4ece7SMD Danish Anwar 		/* Other links speeds not supported */
601e9b4ece7SMD Danish Anwar 		netdev_err(emac->ndev, "Unsupported link speed\n");
602e9b4ece7SMD Danish Anwar 		return;
603e9b4ece7SMD Danish Anwar 	}
604e9b4ece7SMD Danish Anwar 
6050a205f0fSMD Danish Anwar 	if (emac->duplex == DUPLEX_HALF)
6060a205f0fSMD Danish Anwar 		fw_speed |= FW_LINK_SPEED_HD;
6070a205f0fSMD Danish Anwar 
608e9b4ece7SMD Danish Anwar 	writeb(fw_speed, emac->dram.va + PORT_LINK_SPEED_OFFSET);
609e9b4ece7SMD Danish Anwar }
610a8ea8d53SMD Danish Anwar EXPORT_SYMBOL_GPL(icssg_config_set_speed);
611487f7323SMD Danish Anwar 
icssg_send_fdb_msg(struct prueth_emac * emac,struct mgmt_cmd * cmd,struct mgmt_cmd_rsp * rsp)612487f7323SMD Danish Anwar int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd,
613487f7323SMD Danish Anwar 		       struct mgmt_cmd_rsp *rsp)
614487f7323SMD Danish Anwar {
615487f7323SMD Danish Anwar 	struct prueth *prueth = emac->prueth;
616487f7323SMD Danish Anwar 	int slice = prueth_emac_slice(emac);
617487f7323SMD Danish Anwar 	int addr, ret;
618487f7323SMD Danish Anwar 
619487f7323SMD Danish Anwar 	addr = icssg_queue_pop(prueth, slice == 0 ?
620487f7323SMD Danish Anwar 			       ICSSG_CMD_POP_SLICE0 : ICSSG_CMD_POP_SLICE1);
621487f7323SMD Danish Anwar 	if (addr < 0)
622487f7323SMD Danish Anwar 		return addr;
623487f7323SMD Danish Anwar 
624487f7323SMD Danish Anwar 	/* First 4 bytes have FW owned buffer linking info which should
625487f7323SMD Danish Anwar 	 * not be touched
626487f7323SMD Danish Anwar 	 */
627487f7323SMD Danish Anwar 	memcpy_toio(prueth->shram.va + addr + 4, cmd, sizeof(*cmd));
628487f7323SMD Danish Anwar 	icssg_queue_push(prueth, slice == 0 ?
629487f7323SMD Danish Anwar 			 ICSSG_CMD_PUSH_SLICE0 : ICSSG_CMD_PUSH_SLICE1, addr);
630487f7323SMD Danish Anwar 	ret = read_poll_timeout(icssg_queue_pop, addr, addr >= 0,
631487f7323SMD Danish Anwar 				2000, 20000000, false, prueth, slice == 0 ?
632487f7323SMD Danish Anwar 				ICSSG_RSP_POP_SLICE0 : ICSSG_RSP_POP_SLICE1);
633487f7323SMD Danish Anwar 	if (ret) {
634487f7323SMD Danish Anwar 		netdev_err(emac->ndev, "Timedout sending HWQ message\n");
635487f7323SMD Danish Anwar 		return ret;
636487f7323SMD Danish Anwar 	}
637487f7323SMD Danish Anwar 
638487f7323SMD Danish Anwar 	memcpy_fromio(rsp, prueth->shram.va + addr, sizeof(*rsp));
639487f7323SMD Danish Anwar 	/* Return buffer back for to pool */
640487f7323SMD Danish Anwar 	icssg_queue_push(prueth, slice == 0 ?
641487f7323SMD Danish Anwar 			 ICSSG_RSP_PUSH_SLICE0 : ICSSG_RSP_PUSH_SLICE1, addr);
642487f7323SMD Danish Anwar 
643487f7323SMD Danish Anwar 	return 0;
644487f7323SMD Danish Anwar }
645a8ea8d53SMD Danish Anwar EXPORT_SYMBOL_GPL(icssg_send_fdb_msg);
646487f7323SMD Danish Anwar 
icssg_fdb_setup(struct prueth_emac * emac,struct mgmt_cmd * fdb_cmd,const unsigned char * addr,u8 fid,int cmd)647487f7323SMD Danish Anwar static void icssg_fdb_setup(struct prueth_emac *emac, struct mgmt_cmd *fdb_cmd,
648487f7323SMD Danish Anwar 			    const unsigned char *addr, u8 fid, int cmd)
649487f7323SMD Danish Anwar {
650487f7323SMD Danish Anwar 	int slice = prueth_emac_slice(emac);
651487f7323SMD Danish Anwar 	u8 mac_fid[ETH_ALEN + 2];
652487f7323SMD Danish Anwar 	u16 fdb_slot;
653487f7323SMD Danish Anwar 
654487f7323SMD Danish Anwar 	ether_addr_copy(mac_fid, addr);
655487f7323SMD Danish Anwar 
656487f7323SMD Danish Anwar 	/* 1-1 VID-FID mapping is already setup */
657487f7323SMD Danish Anwar 	mac_fid[ETH_ALEN] = fid;
658487f7323SMD Danish Anwar 	mac_fid[ETH_ALEN + 1] = 0;
659487f7323SMD Danish Anwar 
660487f7323SMD Danish Anwar 	fdb_slot = bitrev32(crc32_le(0, mac_fid, 8)) & PRUETH_SWITCH_FDB_MASK;
661487f7323SMD Danish Anwar 
662487f7323SMD Danish Anwar 	fdb_cmd->header = ICSSG_FW_MGMT_CMD_HEADER;
663487f7323SMD Danish Anwar 	fdb_cmd->type   = ICSSG_FW_MGMT_FDB_CMD_TYPE;
664487f7323SMD Danish Anwar 	fdb_cmd->seqnum = ++(emac->prueth->icssg_hwcmdseq);
665487f7323SMD Danish Anwar 	fdb_cmd->param  = cmd;
666487f7323SMD Danish Anwar 	fdb_cmd->param |= (slice << 4);
667487f7323SMD Danish Anwar 
668487f7323SMD Danish Anwar 	memcpy(&fdb_cmd->cmd_args[0], addr, 4);
669487f7323SMD Danish Anwar 	memcpy(&fdb_cmd->cmd_args[1], &addr[4], 2);
670487f7323SMD Danish Anwar 	fdb_cmd->cmd_args[2] = fdb_slot;
671487f7323SMD Danish Anwar 
672487f7323SMD Danish Anwar 	netdev_dbg(emac->ndev, "MAC %pM slot %X FID %X\n", addr, fdb_slot, fid);
673487f7323SMD Danish Anwar }
674487f7323SMD Danish Anwar 
icssg_fdb_add_del(struct prueth_emac * emac,const unsigned char * addr,u8 vid,u8 fid_c2,bool add)675487f7323SMD Danish Anwar int icssg_fdb_add_del(struct prueth_emac *emac, const unsigned char *addr,
676487f7323SMD Danish Anwar 		      u8 vid, u8 fid_c2, bool add)
677487f7323SMD Danish Anwar {
678487f7323SMD Danish Anwar 	struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 };
679487f7323SMD Danish Anwar 	struct mgmt_cmd fdb_cmd = { 0 };
680487f7323SMD Danish Anwar 	u8 fid = vid;
681487f7323SMD Danish Anwar 	int ret;
682487f7323SMD Danish Anwar 
683487f7323SMD Danish Anwar 	icssg_fdb_setup(emac, &fdb_cmd, addr, fid, add ? ICSS_CMD_ADD_FDB : ICSS_CMD_DEL_FDB);
684487f7323SMD Danish Anwar 
685487f7323SMD Danish Anwar 	fid_c2 |= ICSSG_FDB_ENTRY_VALID;
686487f7323SMD Danish Anwar 	fdb_cmd.cmd_args[1] |= ((fid << 16) | (fid_c2 << 24));
687487f7323SMD Danish Anwar 
688487f7323SMD Danish Anwar 	ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp);
689487f7323SMD Danish Anwar 	if (ret)
690487f7323SMD Danish Anwar 		return ret;
691487f7323SMD Danish Anwar 
692487f7323SMD Danish Anwar 	WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum);
693487f7323SMD Danish Anwar 	if (fdb_cmd_rsp.status == 1)
694487f7323SMD Danish Anwar 		return 0;
695487f7323SMD Danish Anwar 
696487f7323SMD Danish Anwar 	return -EINVAL;
697487f7323SMD Danish Anwar }
698a8ea8d53SMD Danish Anwar EXPORT_SYMBOL_GPL(icssg_fdb_add_del);
699487f7323SMD Danish Anwar 
icssg_fdb_lookup(struct prueth_emac * emac,const unsigned char * addr,u8 vid)700487f7323SMD Danish Anwar int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr,
701487f7323SMD Danish Anwar 		     u8 vid)
702487f7323SMD Danish Anwar {
703487f7323SMD Danish Anwar 	struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 };
704487f7323SMD Danish Anwar 	struct mgmt_cmd fdb_cmd = { 0 };
705487f7323SMD Danish Anwar 	struct prueth_fdb_slot *slot;
706487f7323SMD Danish Anwar 	u8 fid = vid;
707487f7323SMD Danish Anwar 	int ret, i;
708487f7323SMD Danish Anwar 
709487f7323SMD Danish Anwar 	icssg_fdb_setup(emac, &fdb_cmd, addr, fid, ICSS_CMD_GET_FDB_SLOT);
710487f7323SMD Danish Anwar 
711487f7323SMD Danish Anwar 	fdb_cmd.cmd_args[1] |= fid << 16;
712487f7323SMD Danish Anwar 
713487f7323SMD Danish Anwar 	ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp);
714487f7323SMD Danish Anwar 	if (ret)
715487f7323SMD Danish Anwar 		return ret;
716487f7323SMD Danish Anwar 
717487f7323SMD Danish Anwar 	WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum);
718487f7323SMD Danish Anwar 
719487f7323SMD Danish Anwar 	slot = (struct prueth_fdb_slot __force *)(emac->dram.va + FDB_CMD_BUFFER);
720487f7323SMD Danish Anwar 	for (i = 0; i < 4; i++) {
721487f7323SMD Danish Anwar 		if (ether_addr_equal(addr, slot->mac) && vid == slot->fid)
722487f7323SMD Danish Anwar 			return (slot->fid_c2 & ~ICSSG_FDB_ENTRY_VALID);
723487f7323SMD Danish Anwar 		slot++;
724487f7323SMD Danish Anwar 	}
725487f7323SMD Danish Anwar 
726487f7323SMD Danish Anwar 	return 0;
727487f7323SMD Danish Anwar }
728a8ea8d53SMD Danish Anwar EXPORT_SYMBOL_GPL(icssg_fdb_lookup);
729487f7323SMD Danish Anwar 
icssg_vtbl_modify(struct prueth_emac * emac,u8 vid,u8 port_mask,u8 untag_mask,bool add)730487f7323SMD Danish Anwar void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask,
731487f7323SMD Danish Anwar 		       u8 untag_mask, bool add)
732487f7323SMD Danish Anwar {
733487f7323SMD Danish Anwar 	struct prueth *prueth = emac->prueth;
734487f7323SMD Danish Anwar 	struct prueth_vlan_tbl *tbl;
735487f7323SMD Danish Anwar 	u8 fid_c1;
736487f7323SMD Danish Anwar 
737487f7323SMD Danish Anwar 	tbl = prueth->vlan_tbl;
738487f7323SMD Danish Anwar 	fid_c1 = tbl[vid].fid_c1;
739487f7323SMD Danish Anwar 
740487f7323SMD Danish Anwar 	/* FID_C1: bit0..2 port membership mask,
741487f7323SMD Danish Anwar 	 * bit3..5 tagging mask for each port
742487f7323SMD Danish Anwar 	 * bit6 Stream VID (not handled currently)
743487f7323SMD Danish Anwar 	 * bit7 MC flood (not handled currently)
744487f7323SMD Danish Anwar 	 */
745487f7323SMD Danish Anwar 	if (add) {
746487f7323SMD Danish Anwar 		fid_c1 |= (port_mask | port_mask << 3);
747487f7323SMD Danish Anwar 		fid_c1 &= ~(untag_mask << 3);
748487f7323SMD Danish Anwar 	} else {
749487f7323SMD Danish Anwar 		fid_c1 &= ~(port_mask | port_mask << 3);
750487f7323SMD Danish Anwar 	}
751487f7323SMD Danish Anwar 
752487f7323SMD Danish Anwar 	tbl[vid].fid_c1 = fid_c1;
753487f7323SMD Danish Anwar }
754a8ea8d53SMD Danish Anwar EXPORT_SYMBOL_GPL(icssg_vtbl_modify);
755487f7323SMD Danish Anwar 
icssg_get_pvid(struct prueth_emac * emac)756487f7323SMD Danish Anwar u16 icssg_get_pvid(struct prueth_emac *emac)
757487f7323SMD Danish Anwar {
758487f7323SMD Danish Anwar 	struct prueth *prueth = emac->prueth;
759487f7323SMD Danish Anwar 	u32 pvid;
760487f7323SMD Danish Anwar 
761487f7323SMD Danish Anwar 	if (emac->port_id == PRUETH_PORT_MII0)
762487f7323SMD Danish Anwar 		pvid = readl(prueth->shram.va + EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET);
763487f7323SMD Danish Anwar 	else
764487f7323SMD Danish Anwar 		pvid = readl(prueth->shram.va + EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET);
765487f7323SMD Danish Anwar 
766487f7323SMD Danish Anwar 	pvid = pvid >> 24;
767487f7323SMD Danish Anwar 
768487f7323SMD Danish Anwar 	return pvid;
769487f7323SMD Danish Anwar }
770a8ea8d53SMD Danish Anwar EXPORT_SYMBOL_GPL(icssg_get_pvid);
771487f7323SMD Danish Anwar 
icssg_set_pvid(struct prueth * prueth,u8 vid,u8 port)772487f7323SMD Danish Anwar void icssg_set_pvid(struct prueth *prueth, u8 vid, u8 port)
773487f7323SMD Danish Anwar {
774487f7323SMD Danish Anwar 	u32 pvid;
775487f7323SMD Danish Anwar 
776487f7323SMD Danish Anwar 	/* only 256 VLANs are supported */
777487f7323SMD Danish Anwar 	pvid = (u32 __force)cpu_to_be32((ETH_P_8021Q << 16) | (vid & 0xff));
778487f7323SMD Danish Anwar 
779487f7323SMD Danish Anwar 	if (port == PRUETH_PORT_MII0)
780487f7323SMD Danish Anwar 		writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET);
781487f7323SMD Danish Anwar 	else if (port == PRUETH_PORT_MII1)
782487f7323SMD Danish Anwar 		writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET);
783487f7323SMD Danish Anwar 	else
784487f7323SMD Danish Anwar 		writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT0_DEFAULT_VLAN_OFFSET);
785487f7323SMD Danish Anwar }
786a8ea8d53SMD Danish Anwar EXPORT_SYMBOL_GPL(icssg_set_pvid);
787