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