Commit | Line | Data |
---|---|---|
d6ddfacd JA |
1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) |
2 | /* | |
3 | * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. | |
4 | * stmmac XGMAC support. | |
5 | */ | |
6 | ||
7 | #include <linux/iopoll.h> | |
8 | #include "stmmac.h" | |
9 | #include "dwxgmac2.h" | |
10 | ||
11 | static int dwxgmac2_dma_reset(void __iomem *ioaddr) | |
12 | { | |
13 | u32 value = readl(ioaddr + XGMAC_DMA_MODE); | |
14 | ||
15 | /* DMA SW reset */ | |
16 | writel(value | XGMAC_SWR, ioaddr + XGMAC_DMA_MODE); | |
17 | ||
18 | return readl_poll_timeout(ioaddr + XGMAC_DMA_MODE, value, | |
19 | !(value & XGMAC_SWR), 0, 100000); | |
20 | } | |
21 | ||
22 | static void dwxgmac2_dma_init(void __iomem *ioaddr, | |
23 | struct stmmac_dma_cfg *dma_cfg, int atds) | |
24 | { | |
25 | u32 value = readl(ioaddr + XGMAC_DMA_SYSBUS_MODE); | |
26 | ||
27 | if (dma_cfg->aal) | |
28 | value |= XGMAC_AAL; | |
29 | ||
968a2978 TR |
30 | if (dma_cfg->eame) |
31 | value |= XGMAC_EAME; | |
32 | ||
33 | writel(value, ioaddr + XGMAC_DMA_SYSBUS_MODE); | |
d6ddfacd JA |
34 | } |
35 | ||
1d84b487 AH |
36 | static void dwxgmac2_dma_init_chan(struct stmmac_priv *priv, |
37 | void __iomem *ioaddr, | |
d6ddfacd JA |
38 | struct stmmac_dma_cfg *dma_cfg, u32 chan) |
39 | { | |
40 | u32 value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(chan)); | |
41 | ||
42 | if (dma_cfg->pblx8) | |
43 | value |= XGMAC_PBLx8; | |
44 | ||
45 | writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(chan)); | |
46 | writel(XGMAC_DMA_INT_DEFAULT_EN, ioaddr + XGMAC_DMA_CH_INT_EN(chan)); | |
47 | } | |
48 | ||
1d84b487 AH |
49 | static void dwxgmac2_dma_init_rx_chan(struct stmmac_priv *priv, |
50 | void __iomem *ioaddr, | |
d6ddfacd | 51 | struct stmmac_dma_cfg *dma_cfg, |
06a80a7d | 52 | dma_addr_t phy, u32 chan) |
d6ddfacd JA |
53 | { |
54 | u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl; | |
55 | u32 value; | |
56 | ||
57 | value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); | |
58 | value &= ~XGMAC_RxPBL; | |
59 | value |= (rxpbl << XGMAC_RxPBL_SHIFT) & XGMAC_RxPBL; | |
60 | writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); | |
61 | ||
06a80a7d JA |
62 | writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_HADDR(chan)); |
63 | writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_LADDR(chan)); | |
d6ddfacd JA |
64 | } |
65 | ||
1d84b487 AH |
66 | static void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv, |
67 | void __iomem *ioaddr, | |
d6ddfacd | 68 | struct stmmac_dma_cfg *dma_cfg, |
06a80a7d | 69 | dma_addr_t phy, u32 chan) |
d6ddfacd JA |
70 | { |
71 | u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl; | |
72 | u32 value; | |
73 | ||
74 | value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); | |
75 | value &= ~XGMAC_TxPBL; | |
76 | value |= (txpbl << XGMAC_TxPBL_SHIFT) & XGMAC_TxPBL; | |
77 | value |= XGMAC_OSP; | |
78 | writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); | |
79 | ||
06a80a7d JA |
80 | writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_HADDR(chan)); |
81 | writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(chan)); | |
d6ddfacd JA |
82 | } |
83 | ||
84 | static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) | |
85 | { | |
86 | u32 value = readl(ioaddr + XGMAC_DMA_SYSBUS_MODE); | |
87 | int i; | |
88 | ||
89 | if (axi->axi_lpi_en) | |
90 | value |= XGMAC_EN_LPI; | |
91 | if (axi->axi_xit_frm) | |
92 | value |= XGMAC_LPI_XIT_PKT; | |
93 | ||
94 | value &= ~XGMAC_WR_OSR_LMT; | |
95 | value |= (axi->axi_wr_osr_lmt << XGMAC_WR_OSR_LMT_SHIFT) & | |
96 | XGMAC_WR_OSR_LMT; | |
97 | ||
98 | value &= ~XGMAC_RD_OSR_LMT; | |
99 | value |= (axi->axi_rd_osr_lmt << XGMAC_RD_OSR_LMT_SHIFT) & | |
100 | XGMAC_RD_OSR_LMT; | |
101 | ||
900a81cc JA |
102 | if (!axi->axi_fb) |
103 | value |= XGMAC_UNDEF; | |
104 | ||
d6ddfacd JA |
105 | value &= ~XGMAC_BLEN; |
106 | for (i = 0; i < AXI_BLEN; i++) { | |
d6ddfacd JA |
107 | switch (axi->axi_blen[i]) { |
108 | case 256: | |
109 | value |= XGMAC_BLEN256; | |
110 | break; | |
111 | case 128: | |
112 | value |= XGMAC_BLEN128; | |
113 | break; | |
114 | case 64: | |
115 | value |= XGMAC_BLEN64; | |
116 | break; | |
117 | case 32: | |
118 | value |= XGMAC_BLEN32; | |
119 | break; | |
120 | case 16: | |
121 | value |= XGMAC_BLEN16; | |
122 | break; | |
123 | case 8: | |
124 | value |= XGMAC_BLEN8; | |
125 | break; | |
126 | case 4: | |
127 | value |= XGMAC_BLEN4; | |
128 | break; | |
129 | } | |
130 | } | |
131 | ||
132 | writel(value, ioaddr + XGMAC_DMA_SYSBUS_MODE); | |
8fe82bd4 JA |
133 | writel(XGMAC_TDPS, ioaddr + XGMAC_TX_EDMA_CTRL); |
134 | writel(XGMAC_RDPS, ioaddr + XGMAC_RX_EDMA_CTRL); | |
d6ddfacd JA |
135 | } |
136 | ||
1d84b487 AH |
137 | static void dwxgmac2_dma_dump_regs(struct stmmac_priv *priv, |
138 | void __iomem *ioaddr, u32 *reg_space) | |
bfc56530 JA |
139 | { |
140 | int i; | |
141 | ||
142 | for (i = (XGMAC_DMA_MODE / 4); i < XGMAC_REGSIZE; i++) | |
143 | reg_space[i] = readl(ioaddr + i * 4); | |
144 | } | |
145 | ||
1d84b487 AH |
146 | static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr, |
147 | int mode, u32 channel, int fifosz, u8 qmode) | |
d6ddfacd JA |
148 | { |
149 | u32 value = readl(ioaddr + XGMAC_MTL_RXQ_OPMODE(channel)); | |
150 | unsigned int rqs = fifosz / 256 - 1; | |
151 | ||
152 | if (mode == SF_DMA_MODE) { | |
153 | value |= XGMAC_RSF; | |
154 | } else { | |
155 | value &= ~XGMAC_RSF; | |
156 | value &= ~XGMAC_RTC; | |
157 | ||
158 | if (mode <= 64) | |
159 | value |= 0x0 << XGMAC_RTC_SHIFT; | |
160 | else if (mode <= 96) | |
161 | value |= 0x2 << XGMAC_RTC_SHIFT; | |
162 | else | |
163 | value |= 0x3 << XGMAC_RTC_SHIFT; | |
164 | } | |
165 | ||
166 | value &= ~XGMAC_RQS; | |
167 | value |= (rqs << XGMAC_RQS_SHIFT) & XGMAC_RQS; | |
168 | ||
ff82cfc7 JA |
169 | if ((fifosz >= 4096) && (qmode != MTL_QUEUE_AVB)) { |
170 | u32 flow = readl(ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(channel)); | |
171 | unsigned int rfd, rfa; | |
172 | ||
173 | value |= XGMAC_EHFC; | |
174 | ||
175 | /* Set Threshold for Activating Flow Control to min 2 frames, | |
176 | * i.e. 1500 * 2 = 3000 bytes. | |
177 | * | |
178 | * Set Threshold for Deactivating Flow Control to min 1 frame, | |
179 | * i.e. 1500 bytes. | |
180 | */ | |
181 | switch (fifosz) { | |
182 | case 4096: | |
183 | /* This violates the above formula because of FIFO size | |
184 | * limit therefore overflow may occur in spite of this. | |
185 | */ | |
186 | rfd = 0x03; /* Full-2.5K */ | |
187 | rfa = 0x01; /* Full-1.5K */ | |
188 | break; | |
189 | ||
ff82cfc7 | 190 | default: |
52f96cd1 JA |
191 | rfd = 0x07; /* Full-4.5K */ |
192 | rfa = 0x04; /* Full-3K */ | |
ff82cfc7 JA |
193 | break; |
194 | } | |
195 | ||
196 | flow &= ~XGMAC_RFD; | |
197 | flow |= rfd << XGMAC_RFD_SHIFT; | |
198 | ||
199 | flow &= ~XGMAC_RFA; | |
200 | flow |= rfa << XGMAC_RFA_SHIFT; | |
201 | ||
202 | writel(flow, ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(channel)); | |
203 | } | |
204 | ||
d6ddfacd JA |
205 | writel(value, ioaddr + XGMAC_MTL_RXQ_OPMODE(channel)); |
206 | ||
207 | /* Enable MTL RX overflow */ | |
208 | value = readl(ioaddr + XGMAC_MTL_QINTEN(channel)); | |
209 | writel(value | XGMAC_RXOIE, ioaddr + XGMAC_MTL_QINTEN(channel)); | |
210 | } | |
211 | ||
1d84b487 AH |
212 | static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr, |
213 | int mode, u32 channel, int fifosz, u8 qmode) | |
d6ddfacd JA |
214 | { |
215 | u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel)); | |
216 | unsigned int tqs = fifosz / 256 - 1; | |
217 | ||
218 | if (mode == SF_DMA_MODE) { | |
219 | value |= XGMAC_TSF; | |
220 | } else { | |
221 | value &= ~XGMAC_TSF; | |
222 | value &= ~XGMAC_TTC; | |
223 | ||
224 | if (mode <= 64) | |
225 | value |= 0x0 << XGMAC_TTC_SHIFT; | |
226 | else if (mode <= 96) | |
227 | value |= 0x2 << XGMAC_TTC_SHIFT; | |
228 | else if (mode <= 128) | |
229 | value |= 0x3 << XGMAC_TTC_SHIFT; | |
230 | else if (mode <= 192) | |
231 | value |= 0x4 << XGMAC_TTC_SHIFT; | |
232 | else if (mode <= 256) | |
233 | value |= 0x5 << XGMAC_TTC_SHIFT; | |
234 | else if (mode <= 384) | |
235 | value |= 0x6 << XGMAC_TTC_SHIFT; | |
236 | else | |
237 | value |= 0x7 << XGMAC_TTC_SHIFT; | |
238 | } | |
239 | ||
ec6ea8e3 JA |
240 | /* Use static TC to Queue mapping */ |
241 | value |= (channel << XGMAC_Q2TCMAP_SHIFT) & XGMAC_Q2TCMAP; | |
242 | ||
d6ddfacd JA |
243 | value &= ~XGMAC_TXQEN; |
244 | if (qmode != MTL_QUEUE_AVB) | |
245 | value |= 0x2 << XGMAC_TXQEN_SHIFT; | |
246 | else | |
247 | value |= 0x1 << XGMAC_TXQEN_SHIFT; | |
248 | ||
249 | value &= ~XGMAC_TQS; | |
250 | value |= (tqs << XGMAC_TQS_SHIFT) & XGMAC_TQS; | |
251 | ||
252 | writel(value, ioaddr + XGMAC_MTL_TXQ_OPMODE(channel)); | |
253 | } | |
254 | ||
1d84b487 AH |
255 | static void dwxgmac2_enable_dma_irq(struct stmmac_priv *priv, |
256 | void __iomem *ioaddr, u32 chan, | |
021bd5e3 | 257 | bool rx, bool tx) |
d6ddfacd | 258 | { |
021bd5e3 JA |
259 | u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan)); |
260 | ||
261 | if (rx) | |
262 | value |= XGMAC_DMA_INT_DEFAULT_RX; | |
263 | if (tx) | |
264 | value |= XGMAC_DMA_INT_DEFAULT_TX; | |
265 | ||
266 | writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan)); | |
d6ddfacd JA |
267 | } |
268 | ||
1d84b487 AH |
269 | static void dwxgmac2_disable_dma_irq(struct stmmac_priv *priv, |
270 | void __iomem *ioaddr, u32 chan, | |
021bd5e3 | 271 | bool rx, bool tx) |
d6ddfacd | 272 | { |
021bd5e3 JA |
273 | u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan)); |
274 | ||
275 | if (rx) | |
276 | value &= ~XGMAC_DMA_INT_DEFAULT_RX; | |
277 | if (tx) | |
278 | value &= ~XGMAC_DMA_INT_DEFAULT_TX; | |
279 | ||
280 | writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan)); | |
d6ddfacd JA |
281 | } |
282 | ||
1d84b487 AH |
283 | static void dwxgmac2_dma_start_tx(struct stmmac_priv *priv, |
284 | void __iomem *ioaddr, u32 chan) | |
d6ddfacd JA |
285 | { |
286 | u32 value; | |
287 | ||
288 | value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); | |
289 | value |= XGMAC_TXST; | |
290 | writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); | |
291 | ||
292 | value = readl(ioaddr + XGMAC_TX_CONFIG); | |
293 | value |= XGMAC_CONFIG_TE; | |
294 | writel(value, ioaddr + XGMAC_TX_CONFIG); | |
295 | } | |
296 | ||
1d84b487 AH |
297 | static void dwxgmac2_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr, |
298 | u32 chan) | |
d6ddfacd JA |
299 | { |
300 | u32 value; | |
301 | ||
302 | value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); | |
303 | value &= ~XGMAC_TXST; | |
304 | writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); | |
305 | ||
306 | value = readl(ioaddr + XGMAC_TX_CONFIG); | |
307 | value &= ~XGMAC_CONFIG_TE; | |
308 | writel(value, ioaddr + XGMAC_TX_CONFIG); | |
309 | } | |
310 | ||
1d84b487 AH |
311 | static void dwxgmac2_dma_start_rx(struct stmmac_priv *priv, |
312 | void __iomem *ioaddr, u32 chan) | |
d6ddfacd JA |
313 | { |
314 | u32 value; | |
315 | ||
316 | value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); | |
317 | value |= XGMAC_RXST; | |
318 | writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); | |
319 | ||
320 | value = readl(ioaddr + XGMAC_RX_CONFIG); | |
321 | value |= XGMAC_CONFIG_RE; | |
322 | writel(value, ioaddr + XGMAC_RX_CONFIG); | |
323 | } | |
324 | ||
1d84b487 AH |
325 | static void dwxgmac2_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr, |
326 | u32 chan) | |
d6ddfacd JA |
327 | { |
328 | u32 value; | |
329 | ||
330 | value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); | |
331 | value &= ~XGMAC_RXST; | |
332 | writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); | |
d6ddfacd JA |
333 | } |
334 | ||
1d84b487 AH |
335 | static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv, |
336 | void __iomem *ioaddr, | |
7e1c520c OBL |
337 | struct stmmac_extra_stats *x, u32 chan, |
338 | u32 dir) | |
d6ddfacd | 339 | { |
38cc3c6d | 340 | struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats); |
d6ddfacd | 341 | u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan)); |
fcc509eb | 342 | u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan)); |
d6ddfacd JA |
343 | int ret = 0; |
344 | ||
7e1c520c OBL |
345 | if (dir == DMA_DIR_RX) |
346 | intr_status &= XGMAC_DMA_STATUS_MSK_RX; | |
347 | else if (dir == DMA_DIR_TX) | |
348 | intr_status &= XGMAC_DMA_STATUS_MSK_TX; | |
349 | ||
d6ddfacd JA |
350 | /* ABNORMAL interrupts */ |
351 | if (unlikely(intr_status & XGMAC_AIS)) { | |
63384883 JA |
352 | if (unlikely(intr_status & XGMAC_RBU)) { |
353 | x->rx_buf_unav_irq++; | |
354 | ret |= handle_rx; | |
355 | } | |
d6ddfacd JA |
356 | if (unlikely(intr_status & XGMAC_TPS)) { |
357 | x->tx_process_stopped_irq++; | |
358 | ret |= tx_hard_error; | |
359 | } | |
360 | if (unlikely(intr_status & XGMAC_FBE)) { | |
361 | x->fatal_bus_error_irq++; | |
362 | ret |= tx_hard_error; | |
363 | } | |
364 | } | |
365 | ||
366 | /* TX/RX NORMAL interrupts */ | |
367 | if (likely(intr_status & XGMAC_NIS)) { | |
d6ddfacd | 368 | if (likely(intr_status & XGMAC_RI)) { |
38cc3c6d PT |
369 | u64_stats_update_begin(&stats->syncp); |
370 | u64_stats_inc(&stats->rx_normal_irq_n[chan]); | |
371 | u64_stats_update_end(&stats->syncp); | |
ae9f346d | 372 | ret |= handle_rx; |
d6ddfacd | 373 | } |
ae9f346d | 374 | if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) { |
38cc3c6d PT |
375 | u64_stats_update_begin(&stats->syncp); |
376 | u64_stats_inc(&stats->tx_normal_irq_n[chan]); | |
377 | u64_stats_update_end(&stats->syncp); | |
d6ddfacd JA |
378 | ret |= handle_tx; |
379 | } | |
380 | } | |
381 | ||
382 | /* Clear interrupts */ | |
fcc509eb | 383 | writel(intr_en & intr_status, ioaddr + XGMAC_DMA_CH_STATUS(chan)); |
d6ddfacd JA |
384 | |
385 | return ret; | |
386 | } | |
387 | ||
075da584 HC |
388 | static int dwxgmac2_get_hw_feature(void __iomem *ioaddr, |
389 | struct dma_features *dma_cap) | |
d6ddfacd JA |
390 | { |
391 | u32 hw_cap; | |
392 | ||
58c1e0ba | 393 | /* MAC HW feature 0 */ |
d6ddfacd | 394 | hw_cap = readl(ioaddr + XGMAC_HW_FEATURE0); |
669a5556 FX |
395 | dma_cap->edma = (hw_cap & XGMAC_HWFEAT_EDMA) >> 31; |
396 | dma_cap->ediffc = (hw_cap & XGMAC_HWFEAT_EDIFFC) >> 30; | |
397 | dma_cap->vxn = (hw_cap & XGMAC_HWFEAT_VXN) >> 29; | |
30d93227 | 398 | dma_cap->vlins = (hw_cap & XGMAC_HWFEAT_SAVLANINS) >> 27; |
58c1e0ba FX |
399 | dma_cap->tssrc = (hw_cap & XGMAC_HWFEAT_TSSTSSEL) >> 25; |
400 | dma_cap->multi_addr = (hw_cap & XGMAC_HWFEAT_ADDMACADRSEL) >> 18; | |
d6ddfacd JA |
401 | dma_cap->rx_coe = (hw_cap & XGMAC_HWFEAT_RXCOESEL) >> 16; |
402 | dma_cap->tx_coe = (hw_cap & XGMAC_HWFEAT_TXCOESEL) >> 14; | |
81b945ae | 403 | dma_cap->eee = (hw_cap & XGMAC_HWFEAT_EEESEL) >> 13; |
d6ddfacd JA |
404 | dma_cap->atime_stamp = (hw_cap & XGMAC_HWFEAT_TSSEL) >> 12; |
405 | dma_cap->av = (hw_cap & XGMAC_HWFEAT_AVSEL) >> 11; | |
08c1ac3b | 406 | dma_cap->av &= !((hw_cap & XGMAC_HWFEAT_RAVSEL) >> 10); |
5904a980 | 407 | dma_cap->arpoffsel = (hw_cap & XGMAC_HWFEAT_ARPOFFSEL) >> 9; |
b6cdf09f | 408 | dma_cap->rmon = (hw_cap & XGMAC_HWFEAT_MMCSEL) >> 8; |
d6ddfacd JA |
409 | dma_cap->pmt_magic_frame = (hw_cap & XGMAC_HWFEAT_MGKSEL) >> 7; |
410 | dma_cap->pmt_remote_wake_up = (hw_cap & XGMAC_HWFEAT_RWKSEL) >> 6; | |
58c1e0ba | 411 | dma_cap->sma_mdio = (hw_cap & XGMAC_HWFEAT_SMASEL) >> 5; |
3cd1cfcb | 412 | dma_cap->vlhash = (hw_cap & XGMAC_HWFEAT_VLHASH) >> 4; |
58c1e0ba | 413 | dma_cap->half_duplex = (hw_cap & XGMAC_HWFEAT_HDSEL) >> 3; |
d6ddfacd JA |
414 | dma_cap->mbps_1000 = (hw_cap & XGMAC_HWFEAT_GMIISEL) >> 1; |
415 | ||
416 | /* MAC HW feature 1 */ | |
417 | hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1); | |
425eabdd | 418 | dma_cap->l3l4fnum = (hw_cap & XGMAC_HWFEAT_L3L4FNUM) >> 27; |
47448ff2 RT |
419 | /* If L3L4FNUM < 8, then the number of L3L4 filters supported by |
420 | * XGMAC is equal to L3L4FNUM. From L3L4FNUM >= 8 the number of | |
421 | * L3L4 filters goes on like 8, 16, 32, ... Current maximum of | |
422 | * L3L4FNUM = 10. | |
423 | */ | |
424 | if (dma_cap->l3l4fnum >= 8 && dma_cap->l3l4fnum <= 10) | |
425 | dma_cap->l3l4fnum = 8 << (dma_cap->l3l4fnum - 8); | |
426 | else if (dma_cap->l3l4fnum > 10) | |
427 | dma_cap->l3l4fnum = 32; | |
428 | ||
c11986b9 | 429 | dma_cap->hash_tb_sz = (hw_cap & XGMAC_HWFEAT_HASHTBLSZ) >> 24; |
669a5556 | 430 | dma_cap->numtc = ((hw_cap & XGMAC_HWFEAT_NUMTC) >> 21) + 1; |
76067459 | 431 | dma_cap->rssen = (hw_cap & XGMAC_HWFEAT_RSSEN) >> 20; |
669a5556 | 432 | dma_cap->dbgmem = (hw_cap & XGMAC_HWFEAT_DBGMEMA) >> 19; |
d6ddfacd | 433 | dma_cap->tsoen = (hw_cap & XGMAC_HWFEAT_TSOEN) >> 18; |
67afd6d1 | 434 | dma_cap->sphen = (hw_cap & XGMAC_HWFEAT_SPHEN) >> 17; |
669a5556 | 435 | dma_cap->dcben = (hw_cap & XGMAC_HWFEAT_DCBEN) >> 16; |
a993db88 JA |
436 | |
437 | dma_cap->addr64 = (hw_cap & XGMAC_HWFEAT_ADDR64) >> 14; | |
438 | switch (dma_cap->addr64) { | |
439 | case 0: | |
440 | dma_cap->addr64 = 32; | |
441 | break; | |
442 | case 1: | |
443 | dma_cap->addr64 = 40; | |
444 | break; | |
445 | case 2: | |
446 | dma_cap->addr64 = 48; | |
447 | break; | |
448 | default: | |
449 | dma_cap->addr64 = 32; | |
450 | break; | |
451 | } | |
452 | ||
669a5556 FX |
453 | dma_cap->advthword = (hw_cap & XGMAC_HWFEAT_ADVTHWORD) >> 13; |
454 | dma_cap->ptoen = (hw_cap & XGMAC_HWFEAT_PTOEN) >> 12; | |
455 | dma_cap->osten = (hw_cap & XGMAC_HWFEAT_OSTEN) >> 11; | |
d6ddfacd JA |
456 | dma_cap->tx_fifo_size = |
457 | 128 << ((hw_cap & XGMAC_HWFEAT_TXFIFOSIZE) >> 6); | |
669a5556 | 458 | dma_cap->pfcen = (hw_cap & XGMAC_HWFEAT_PFCEN) >> 5; |
d6ddfacd JA |
459 | dma_cap->rx_fifo_size = |
460 | 128 << ((hw_cap & XGMAC_HWFEAT_RXFIFOSIZE) >> 0); | |
461 | ||
462 | /* MAC HW feature 2 */ | |
463 | hw_cap = readl(ioaddr + XGMAC_HW_FEATURE2); | |
669a5556 | 464 | dma_cap->aux_snapshot_n = (hw_cap & XGMAC_HWFEAT_AUXSNAPNUM) >> 28; |
d6ddfacd JA |
465 | dma_cap->pps_out_num = (hw_cap & XGMAC_HWFEAT_PPSOUTNUM) >> 24; |
466 | dma_cap->number_tx_channel = | |
467 | ((hw_cap & XGMAC_HWFEAT_TXCHCNT) >> 18) + 1; | |
468 | dma_cap->number_rx_channel = | |
469 | ((hw_cap & XGMAC_HWFEAT_RXCHCNT) >> 12) + 1; | |
470 | dma_cap->number_tx_queues = | |
471 | ((hw_cap & XGMAC_HWFEAT_TXQCNT) >> 6) + 1; | |
472 | dma_cap->number_rx_queues = | |
473 | ((hw_cap & XGMAC_HWFEAT_RXQCNT) >> 0) + 1; | |
56e58d6c JA |
474 | |
475 | /* MAC HW feature 3 */ | |
476 | hw_cap = readl(ioaddr + XGMAC_HW_FEATURE3); | |
669a5556 | 477 | dma_cap->tbs_ch_num = ((hw_cap & XGMAC_HWFEAT_TBSCH) >> 28) + 1; |
6a549b9f | 478 | dma_cap->tbssel = (hw_cap & XGMAC_HWFEAT_TBSSEL) >> 27; |
f0e56c8d | 479 | dma_cap->fpesel = (hw_cap & XGMAC_HWFEAT_FPESEL) >> 26; |
669a5556 | 480 | dma_cap->sgfsel = (hw_cap & XGMAC_HWFEAT_SGFSEL) >> 25; |
8572aec3 JA |
481 | dma_cap->estwid = (hw_cap & XGMAC_HWFEAT_ESTWID) >> 23; |
482 | dma_cap->estdep = (hw_cap & XGMAC_HWFEAT_ESTDEP) >> 20; | |
483 | dma_cap->estsel = (hw_cap & XGMAC_HWFEAT_ESTSEL) >> 19; | |
669a5556 | 484 | dma_cap->ttsfd = (hw_cap & XGMAC_HWFEAT_TTSFD) >> 16; |
56e58d6c | 485 | dma_cap->asp = (hw_cap & XGMAC_HWFEAT_ASP) >> 14; |
30d93227 | 486 | dma_cap->dvlan = (hw_cap & XGMAC_HWFEAT_DVLAN) >> 13; |
d6e1c12c JA |
487 | dma_cap->frpes = (hw_cap & XGMAC_HWFEAT_FRPES) >> 11; |
488 | dma_cap->frpbs = (hw_cap & XGMAC_HWFEAT_FRPPB) >> 9; | |
669a5556 FX |
489 | dma_cap->pou_ost_en = (hw_cap & XGMAC_HWFEAT_POUOST) >> 8; |
490 | dma_cap->frppipe_num = ((hw_cap & XGMAC_HWFEAT_FRPPIPE) >> 5) + 1; | |
491 | dma_cap->cbtisel = (hw_cap & XGMAC_HWFEAT_CBTISEL) >> 4; | |
d6e1c12c | 492 | dma_cap->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3; |
669a5556 FX |
493 | dma_cap->nrvf_num = (hw_cap & XGMAC_HWFEAT_NRVF) >> 0; |
494 | ||
495 | /* MAC HW feature 4 */ | |
496 | hw_cap = readl(ioaddr + XGMAC_HW_FEATURE4); | |
497 | dma_cap->asp |= (hw_cap & XGMAC_HWFEAT_EASP) >> 2; | |
498 | dma_cap->pcsel = (hw_cap & XGMAC_HWFEAT_PCSEL) >> 0; | |
075da584 HC |
499 | |
500 | return 0; | |
d6ddfacd JA |
501 | } |
502 | ||
1d84b487 AH |
503 | static void dwxgmac2_rx_watchdog(struct stmmac_priv *priv, void __iomem *ioaddr, |
504 | u32 riwt, u32 queue) | |
d6ddfacd | 505 | { |
db2f2842 | 506 | writel(riwt & XGMAC_RWT, ioaddr + XGMAC_DMA_CH_Rx_WATCHDOG(queue)); |
d6ddfacd JA |
507 | } |
508 | ||
1d84b487 AH |
509 | static void dwxgmac2_set_rx_ring_len(struct stmmac_priv *priv, |
510 | void __iomem *ioaddr, u32 len, u32 chan) | |
d6ddfacd JA |
511 | { |
512 | writel(len, ioaddr + XGMAC_DMA_CH_RxDESC_RING_LEN(chan)); | |
513 | } | |
514 | ||
1d84b487 AH |
515 | static void dwxgmac2_set_tx_ring_len(struct stmmac_priv *priv, |
516 | void __iomem *ioaddr, u32 len, u32 chan) | |
d6ddfacd JA |
517 | { |
518 | writel(len, ioaddr + XGMAC_DMA_CH_TxDESC_RING_LEN(chan)); | |
519 | } | |
520 | ||
1d84b487 AH |
521 | static void dwxgmac2_set_rx_tail_ptr(struct stmmac_priv *priv, |
522 | void __iomem *ioaddr, u32 ptr, u32 chan) | |
d6ddfacd JA |
523 | { |
524 | writel(ptr, ioaddr + XGMAC_DMA_CH_RxDESC_TAIL_LPTR(chan)); | |
525 | } | |
526 | ||
1d84b487 AH |
527 | static void dwxgmac2_set_tx_tail_ptr(struct stmmac_priv *priv, |
528 | void __iomem *ioaddr, u32 ptr, u32 chan) | |
d6ddfacd JA |
529 | { |
530 | writel(ptr, ioaddr + XGMAC_DMA_CH_TxDESC_TAIL_LPTR(chan)); | |
531 | } | |
532 | ||
1d84b487 AH |
533 | static void dwxgmac2_enable_tso(struct stmmac_priv *priv, void __iomem *ioaddr, |
534 | bool en, u32 chan) | |
d6ddfacd JA |
535 | { |
536 | u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); | |
537 | ||
538 | if (en) | |
539 | value |= XGMAC_TSE; | |
540 | else | |
541 | value &= ~XGMAC_TSE; | |
542 | ||
543 | writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); | |
544 | } | |
545 | ||
1d84b487 AH |
546 | static void dwxgmac2_qmode(struct stmmac_priv *priv, void __iomem *ioaddr, |
547 | u32 channel, u8 qmode) | |
ec6ea8e3 JA |
548 | { |
549 | u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel)); | |
132f2f20 | 550 | u32 flow = readl(ioaddr + XGMAC_RX_FLOW_CTRL); |
ec6ea8e3 JA |
551 | |
552 | value &= ~XGMAC_TXQEN; | |
553 | if (qmode != MTL_QUEUE_AVB) { | |
554 | value |= 0x2 << XGMAC_TXQEN_SHIFT; | |
555 | writel(0, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(channel)); | |
556 | } else { | |
557 | value |= 0x1 << XGMAC_TXQEN_SHIFT; | |
132f2f20 | 558 | writel(flow & (~XGMAC_RFE), ioaddr + XGMAC_RX_FLOW_CTRL); |
ec6ea8e3 JA |
559 | } |
560 | ||
561 | writel(value, ioaddr + XGMAC_MTL_TXQ_OPMODE(channel)); | |
562 | } | |
563 | ||
1d84b487 AH |
564 | static void dwxgmac2_set_bfsize(struct stmmac_priv *priv, void __iomem *ioaddr, |
565 | int bfsize, u32 chan) | |
d6ddfacd JA |
566 | { |
567 | u32 value; | |
568 | ||
569 | value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); | |
11d55fd9 JA |
570 | value &= ~XGMAC_RBSZ; |
571 | value |= bfsize << XGMAC_RBSZ_SHIFT; | |
d6ddfacd JA |
572 | writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); |
573 | } | |
574 | ||
1d84b487 AH |
575 | static void dwxgmac2_enable_sph(struct stmmac_priv *priv, void __iomem *ioaddr, |
576 | bool en, u32 chan) | |
67afd6d1 JA |
577 | { |
578 | u32 value = readl(ioaddr + XGMAC_RX_CONFIG); | |
579 | ||
580 | value &= ~XGMAC_CONFIG_HDSMS; | |
581 | value |= XGMAC_CONFIG_HDSMS_256; /* Segment max 256 bytes */ | |
582 | writel(value, ioaddr + XGMAC_RX_CONFIG); | |
583 | ||
584 | value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(chan)); | |
585 | if (en) | |
586 | value |= XGMAC_SPH; | |
587 | else | |
588 | value &= ~XGMAC_SPH; | |
589 | writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(chan)); | |
590 | } | |
591 | ||
1d84b487 AH |
592 | static int dwxgmac2_enable_tbs(struct stmmac_priv *priv, void __iomem *ioaddr, |
593 | bool en, u32 chan) | |
6a549b9f JA |
594 | { |
595 | u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); | |
596 | ||
597 | if (en) | |
598 | value |= XGMAC_EDSE; | |
599 | else | |
600 | value &= ~XGMAC_EDSE; | |
601 | ||
602 | writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); | |
603 | ||
604 | value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)) & XGMAC_EDSE; | |
605 | if (en && !value) | |
606 | return -EIO; | |
607 | ||
608 | writel(XGMAC_DEF_FTOS, ioaddr + XGMAC_DMA_TBS_CTRL0); | |
609 | writel(XGMAC_DEF_FTOS, ioaddr + XGMAC_DMA_TBS_CTRL1); | |
610 | writel(XGMAC_DEF_FTOS, ioaddr + XGMAC_DMA_TBS_CTRL2); | |
611 | writel(XGMAC_DEF_FTOS, ioaddr + XGMAC_DMA_TBS_CTRL3); | |
612 | return 0; | |
613 | } | |
614 | ||
d6ddfacd JA |
615 | const struct stmmac_dma_ops dwxgmac210_dma_ops = { |
616 | .reset = dwxgmac2_dma_reset, | |
617 | .init = dwxgmac2_dma_init, | |
618 | .init_chan = dwxgmac2_dma_init_chan, | |
619 | .init_rx_chan = dwxgmac2_dma_init_rx_chan, | |
620 | .init_tx_chan = dwxgmac2_dma_init_tx_chan, | |
621 | .axi = dwxgmac2_dma_axi, | |
bfc56530 | 622 | .dump_regs = dwxgmac2_dma_dump_regs, |
d6ddfacd JA |
623 | .dma_rx_mode = dwxgmac2_dma_rx_mode, |
624 | .dma_tx_mode = dwxgmac2_dma_tx_mode, | |
625 | .enable_dma_irq = dwxgmac2_enable_dma_irq, | |
626 | .disable_dma_irq = dwxgmac2_disable_dma_irq, | |
627 | .start_tx = dwxgmac2_dma_start_tx, | |
628 | .stop_tx = dwxgmac2_dma_stop_tx, | |
629 | .start_rx = dwxgmac2_dma_start_rx, | |
630 | .stop_rx = dwxgmac2_dma_stop_rx, | |
631 | .dma_interrupt = dwxgmac2_dma_interrupt, | |
632 | .get_hw_feature = dwxgmac2_get_hw_feature, | |
633 | .rx_watchdog = dwxgmac2_rx_watchdog, | |
634 | .set_rx_ring_len = dwxgmac2_set_rx_ring_len, | |
635 | .set_tx_ring_len = dwxgmac2_set_tx_ring_len, | |
636 | .set_rx_tail_ptr = dwxgmac2_set_rx_tail_ptr, | |
637 | .set_tx_tail_ptr = dwxgmac2_set_tx_tail_ptr, | |
638 | .enable_tso = dwxgmac2_enable_tso, | |
ec6ea8e3 | 639 | .qmode = dwxgmac2_qmode, |
d6ddfacd | 640 | .set_bfsize = dwxgmac2_set_bfsize, |
67afd6d1 | 641 | .enable_sph = dwxgmac2_enable_sph, |
6a549b9f | 642 | .enable_tbs = dwxgmac2_enable_tbs, |
d6ddfacd | 643 | }; |