]>
Commit | Line | Data |
---|---|---|
258ce79c ARS |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Xilinx Multirate Ethernet MAC(MRMAC) driver | |
4 | * | |
5 | * Author(s): Ashok Reddy Soma <ashok.reddy.soma@xilinx.com> | |
174d7284 | 6 | * Michal Simek <michal.simek@amd.com> |
258ce79c ARS |
7 | * |
8 | * Copyright (C) 2021 Xilinx, Inc. All rights reserved. | |
9 | */ | |
10 | ||
11 | #include <config.h> | |
d678a59d | 12 | #include <common.h> |
258ce79c ARS |
13 | #include <cpu_func.h> |
14 | #include <dm.h> | |
15 | #include <log.h> | |
16 | #include <net.h> | |
17 | #include <malloc.h> | |
18 | #include <wait_bit.h> | |
19 | #include <asm/io.h> | |
20 | #include <linux/delay.h> | |
21 | #include <linux/ethtool.h> | |
22 | #include "xilinx_axi_mrmac.h" | |
23 | ||
24 | static void axi_mrmac_dma_write(struct mcdma_bd *bd, u32 *desc) | |
25 | { | |
26 | if (IS_ENABLED(CONFIG_PHYS_64BIT)) | |
27 | writeq((unsigned long)bd, desc); | |
28 | else | |
29 | writel((uintptr_t)bd, desc); | |
30 | } | |
31 | ||
32 | /** | |
33 | * axi_mrmac_ethernet_init - MRMAC init function | |
34 | * @priv: MRMAC private structure | |
35 | * | |
36 | * Return: 0 on success, negative value on errors | |
37 | * | |
38 | * This function is called to reset and initialize MRMAC core. This is | |
39 | * typically called during initialization. It does a reset of MRMAC Rx/Tx | |
40 | * channels and Rx/Tx SERDES. It configures MRMAC speed based on mrmac_rate | |
41 | * which is read from DT. This function waits for block lock bit to get set, | |
42 | * if it is not set within 100ms time returns a timeout error. | |
43 | */ | |
44 | static int axi_mrmac_ethernet_init(struct axi_mrmac_priv *priv) | |
45 | { | |
46 | struct mrmac_regs *regs = priv->iobase; | |
47 | u32 reg; | |
48 | u32 ret; | |
49 | ||
50 | /* Perform all the RESET's required */ | |
51 | setbits_le32(®s->reset, MRMAC_RX_SERDES_RST_MASK | MRMAC_RX_RST_MASK | |
52 | | MRMAC_TX_SERDES_RST_MASK | MRMAC_TX_RST_MASK); | |
53 | ||
54 | mdelay(MRMAC_RESET_DELAY); | |
55 | ||
56 | /* Configure Mode register */ | |
57 | reg = readl(®s->mode); | |
58 | ||
59 | log_debug("Configuring MRMAC speed to %d\n", priv->mrmac_rate); | |
60 | ||
61 | if (priv->mrmac_rate == SPEED_25000) { | |
62 | reg &= ~MRMAC_CTL_RATE_CFG_MASK; | |
63 | reg |= MRMAC_CTL_DATA_RATE_25G; | |
64 | reg |= (MRMAC_CTL_AXIS_CFG_25G_IND << MRMAC_CTL_AXIS_CFG_SHIFT); | |
65 | reg |= (MRMAC_CTL_SERDES_WIDTH_25G << | |
66 | MRMAC_CTL_SERDES_WIDTH_SHIFT); | |
67 | } else { | |
68 | reg &= ~MRMAC_CTL_RATE_CFG_MASK; | |
69 | reg |= MRMAC_CTL_DATA_RATE_10G; | |
70 | reg |= (MRMAC_CTL_AXIS_CFG_10G_IND << MRMAC_CTL_AXIS_CFG_SHIFT); | |
71 | reg |= (MRMAC_CTL_SERDES_WIDTH_10G << | |
72 | MRMAC_CTL_SERDES_WIDTH_SHIFT); | |
73 | } | |
74 | ||
75 | /* For tick reg */ | |
76 | reg |= MRMAC_CTL_PM_TICK_MASK; | |
77 | writel(reg, ®s->mode); | |
78 | ||
79 | clrbits_le32(®s->reset, MRMAC_RX_SERDES_RST_MASK | MRMAC_RX_RST_MASK | |
80 | | MRMAC_TX_SERDES_RST_MASK | MRMAC_TX_RST_MASK); | |
81 | ||
82 | mdelay(MRMAC_RESET_DELAY); | |
83 | ||
84 | /* Setup MRMAC hardware options */ | |
85 | setbits_le32(®s->rx_config, MRMAC_RX_DEL_FCS_MASK); | |
86 | setbits_le32(®s->tx_config, MRMAC_TX_INS_FCS_MASK); | |
87 | setbits_le32(®s->tx_config, MRMAC_TX_EN_MASK); | |
88 | setbits_le32(®s->rx_config, MRMAC_RX_EN_MASK); | |
89 | ||
90 | /* Check for block lock bit to be set. This ensures that | |
91 | * MRMAC ethernet IP is functioning normally. | |
92 | */ | |
93 | writel(MRMAC_STS_ALL_MASK, (phys_addr_t)priv->iobase + | |
94 | MRMAC_TX_STS_OFFSET); | |
95 | writel(MRMAC_STS_ALL_MASK, (phys_addr_t)priv->iobase + | |
96 | MRMAC_RX_STS_OFFSET); | |
97 | writel(MRMAC_STS_ALL_MASK, (phys_addr_t)priv->iobase + | |
98 | MRMAC_STATRX_BLKLCK_OFFSET); | |
99 | ||
100 | ret = wait_for_bit_le32((u32 *)((phys_addr_t)priv->iobase + | |
101 | MRMAC_STATRX_BLKLCK_OFFSET), | |
102 | MRMAC_RX_BLKLCK_MASK, true, | |
103 | MRMAC_BLKLCK_TIMEOUT, true); | |
104 | if (ret) { | |
105 | log_warning("Error: MRMAC block lock not complete!\n"); | |
106 | return -EIO; | |
107 | } | |
108 | ||
109 | writel(MRMAC_TICK_TRIGGER, ®s->tick_reg); | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
114 | /** | |
115 | * axi_mcdma_init - Reset MCDMA engine | |
116 | * @priv: MRMAC private structure | |
117 | * | |
118 | * Return: 0 on success, negative value on timeouts | |
119 | * | |
120 | * This function is called to reset and initialize MCDMA engine | |
121 | */ | |
122 | static int axi_mcdma_init(struct axi_mrmac_priv *priv) | |
123 | { | |
124 | u32 ret; | |
125 | ||
126 | /* Reset the engine so the hardware starts from a known state */ | |
127 | writel(XMCDMA_CR_RESET, &priv->mm2s_cmn->control); | |
128 | writel(XMCDMA_CR_RESET, &priv->s2mm_cmn->control); | |
129 | ||
130 | /* Check Tx/Rx MCDMA.RST. Reset is done when the reset bit is low */ | |
131 | ret = wait_for_bit_le32(&priv->mm2s_cmn->control, XMCDMA_CR_RESET, | |
132 | false, MRMAC_DMARST_TIMEOUT, true); | |
133 | if (ret) { | |
134 | log_warning("Tx MCDMA reset Timeout\n"); | |
135 | return -ETIMEDOUT; | |
136 | } | |
137 | ||
138 | ret = wait_for_bit_le32(&priv->s2mm_cmn->control, XMCDMA_CR_RESET, | |
139 | false, MRMAC_DMARST_TIMEOUT, true); | |
140 | if (ret) { | |
141 | log_warning("Rx MCDMA reset Timeout\n"); | |
142 | return -ETIMEDOUT; | |
143 | } | |
144 | ||
145 | /* Enable channel 1 for Tx and Rx */ | |
146 | writel(XMCDMA_CHANNEL_1, &priv->mm2s_cmn->chen); | |
147 | writel(XMCDMA_CHANNEL_1, &priv->s2mm_cmn->chen); | |
148 | ||
149 | return 0; | |
150 | } | |
151 | ||
152 | /** | |
153 | * axi_mrmac_start - MRMAC start | |
154 | * @dev: udevice structure | |
155 | * | |
156 | * Return: 0 on success, negative value on errors | |
157 | * | |
158 | * This is a initialization function of MRMAC. Call MCDMA initialization | |
159 | * function and setup Rx buffer descriptors for starting reception of packets. | |
160 | * Enable Tx and Rx channels and trigger Rx channel fetch. | |
161 | */ | |
162 | static int axi_mrmac_start(struct udevice *dev) | |
163 | { | |
164 | struct axi_mrmac_priv *priv = dev_get_priv(dev); | |
165 | struct mrmac_regs *regs = priv->iobase; | |
166 | ||
167 | /* | |
168 | * Initialize MCDMA engine. MCDMA engine must be initialized before | |
169 | * MRMAC. During MCDMA engine initialization, MCDMA hardware is reset, | |
170 | * since MCDMA reset line is connected to MRMAC, this would ensure a | |
171 | * reset of MRMAC. | |
172 | */ | |
173 | axi_mcdma_init(priv); | |
174 | ||
175 | /* Initialize MRMAC hardware */ | |
176 | if (axi_mrmac_ethernet_init(priv)) | |
177 | return -EIO; | |
178 | ||
179 | /* Disable all Rx interrupts before RxBD space setup */ | |
180 | clrbits_le32(&priv->mcdma_rx->control, XMCDMA_IRQ_ALL_MASK); | |
181 | ||
182 | /* Update current descriptor */ | |
183 | axi_mrmac_dma_write(priv->rx_bd[0], &priv->mcdma_rx->current); | |
184 | ||
185 | /* Setup Rx BD. MRMAC needs atleast two descriptors */ | |
186 | memset(priv->rx_bd[0], 0, RX_BD_TOTAL_SIZE); | |
187 | ||
188 | priv->rx_bd[0]->next_desc = lower_32_bits((u64)priv->rx_bd[1]); | |
189 | priv->rx_bd[0]->buf_addr = lower_32_bits((u64)net_rx_packets[0]); | |
190 | ||
191 | priv->rx_bd[1]->next_desc = lower_32_bits((u64)priv->rx_bd[0]); | |
192 | priv->rx_bd[1]->buf_addr = lower_32_bits((u64)net_rx_packets[1]); | |
193 | ||
194 | if (IS_ENABLED(CONFIG_PHYS_64BIT)) { | |
195 | priv->rx_bd[0]->next_desc_msb = upper_32_bits((u64)priv->rx_bd[1]); | |
196 | priv->rx_bd[0]->buf_addr_msb = upper_32_bits((u64)net_rx_packets[0]); | |
197 | ||
198 | priv->rx_bd[1]->next_desc_msb = upper_32_bits((u64)priv->rx_bd[0]); | |
199 | priv->rx_bd[1]->buf_addr_msb = upper_32_bits((u64)net_rx_packets[1]); | |
200 | } | |
201 | ||
202 | priv->rx_bd[0]->cntrl = PKTSIZE_ALIGN; | |
203 | priv->rx_bd[1]->cntrl = PKTSIZE_ALIGN; | |
204 | ||
205 | /* Flush the last BD so DMA core could see the updates */ | |
206 | flush_cache((phys_addr_t)priv->rx_bd[0], RX_BD_TOTAL_SIZE); | |
207 | ||
208 | /* It is necessary to flush rx buffers because if you don't do it | |
209 | * then cache can contain uninitialized data | |
210 | */ | |
211 | flush_cache((phys_addr_t)priv->rx_bd[0]->buf_addr, RX_BUFF_TOTAL_SIZE); | |
212 | ||
213 | /* Start the hardware */ | |
214 | setbits_le32(&priv->s2mm_cmn->control, XMCDMA_CR_RUNSTOP_MASK); | |
215 | setbits_le32(&priv->mm2s_cmn->control, XMCDMA_CR_RUNSTOP_MASK); | |
216 | setbits_le32(&priv->mcdma_rx->control, XMCDMA_IRQ_ALL_MASK); | |
217 | ||
218 | /* Channel fetch */ | |
219 | setbits_le32(&priv->mcdma_rx->control, XMCDMA_CR_RUNSTOP_MASK); | |
220 | ||
221 | /* Update tail descriptor. Now it's ready to receive data */ | |
222 | axi_mrmac_dma_write(priv->rx_bd[1], &priv->mcdma_rx->tail); | |
223 | ||
224 | /* Enable Tx */ | |
225 | setbits_le32(®s->tx_config, MRMAC_TX_EN_MASK); | |
226 | ||
227 | /* Enable Rx */ | |
228 | setbits_le32(®s->rx_config, MRMAC_RX_EN_MASK); | |
229 | ||
230 | return 0; | |
231 | } | |
232 | ||
233 | /** | |
234 | * axi_mrmac_send - MRMAC Tx function | |
235 | * @dev: udevice structure | |
236 | * @ptr: pointer to Tx buffer | |
237 | * @len: transfer length | |
238 | * | |
239 | * Return: 0 on success, negative value on errors | |
240 | * | |
241 | * This is a Tx send function of MRMAC. Setup Tx buffer descriptors and trigger | |
242 | * transfer. Wait till the data is transferred. | |
243 | */ | |
244 | static int axi_mrmac_send(struct udevice *dev, void *ptr, int len) | |
245 | { | |
246 | struct axi_mrmac_priv *priv = dev_get_priv(dev); | |
247 | u32 ret; | |
248 | ||
249 | #ifdef DEBUG | |
250 | print_buffer(ptr, ptr, 1, len, 16); | |
251 | #endif | |
252 | if (len > PKTSIZE_ALIGN) | |
253 | len = PKTSIZE_ALIGN; | |
254 | ||
255 | /* If size is less than min packet size, pad to min size */ | |
256 | if (len < MIN_PKT_SIZE) { | |
257 | memset(priv->txminframe, 0, MIN_PKT_SIZE); | |
258 | memcpy(priv->txminframe, ptr, len); | |
259 | len = MIN_PKT_SIZE; | |
260 | ptr = priv->txminframe; | |
261 | } | |
262 | ||
263 | writel(XMCDMA_IRQ_ALL_MASK, &priv->mcdma_tx->status); | |
264 | ||
265 | clrbits_le32(&priv->mcdma_tx->control, XMCDMA_CR_RUNSTOP_MASK); | |
266 | ||
267 | /* Flush packet to main memory to be trasfered by DMA */ | |
268 | flush_cache((phys_addr_t)ptr, len); | |
269 | ||
270 | /* Setup Tx BD. MRMAC needs atleast two descriptors */ | |
271 | memset(priv->tx_bd[0], 0, TX_BD_TOTAL_SIZE); | |
272 | ||
273 | priv->tx_bd[0]->next_desc = lower_32_bits((u64)priv->tx_bd[1]); | |
274 | priv->tx_bd[0]->buf_addr = lower_32_bits((u64)ptr); | |
275 | ||
276 | /* At the end of the ring, link the last BD back to the top */ | |
277 | priv->tx_bd[1]->next_desc = lower_32_bits((u64)priv->tx_bd[0]); | |
278 | priv->tx_bd[1]->buf_addr = lower_32_bits((u64)ptr + len / 2); | |
279 | ||
280 | if (IS_ENABLED(CONFIG_PHYS_64BIT)) { | |
281 | priv->tx_bd[0]->next_desc_msb = upper_32_bits((u64)priv->tx_bd[1]); | |
282 | priv->tx_bd[0]->buf_addr_msb = upper_32_bits((u64)ptr); | |
283 | ||
284 | priv->tx_bd[1]->next_desc_msb = upper_32_bits((u64)priv->tx_bd[0]); | |
285 | priv->tx_bd[1]->buf_addr_msb = upper_32_bits((u64)ptr + len / 2); | |
286 | } | |
287 | ||
288 | /* Split Tx data in to half and send in two descriptors */ | |
289 | priv->tx_bd[0]->cntrl = (len / 2) | XMCDMA_BD_CTRL_TXSOF_MASK; | |
290 | priv->tx_bd[1]->cntrl = (len - len / 2) | XMCDMA_BD_CTRL_TXEOF_MASK; | |
291 | ||
292 | /* Flush the last BD so DMA core could see the updates */ | |
293 | flush_cache((phys_addr_t)priv->tx_bd[0], TX_BD_TOTAL_SIZE); | |
294 | ||
295 | if (readl(&priv->mcdma_tx->status) & XMCDMA_CH_IDLE) { | |
296 | axi_mrmac_dma_write(priv->tx_bd[0], &priv->mcdma_tx->current); | |
297 | /* Channel fetch */ | |
298 | setbits_le32(&priv->mcdma_tx->control, XMCDMA_CR_RUNSTOP_MASK); | |
299 | } else { | |
300 | log_warning("Error: current desc is not updated\n"); | |
301 | return -EIO; | |
302 | } | |
303 | ||
304 | setbits_le32(&priv->mcdma_tx->control, XMCDMA_IRQ_ALL_MASK); | |
305 | ||
306 | /* Start transfer */ | |
307 | axi_mrmac_dma_write(priv->tx_bd[1], &priv->mcdma_tx->tail); | |
308 | ||
309 | /* Wait for transmission to complete */ | |
310 | ret = wait_for_bit_le32(&priv->mcdma_tx->status, XMCDMA_IRQ_IOC_MASK, | |
311 | true, 1, true); | |
312 | if (ret) { | |
313 | log_warning("%s: Timeout\n", __func__); | |
314 | return -ETIMEDOUT; | |
315 | } | |
316 | ||
317 | /* Clear status */ | |
318 | priv->tx_bd[0]->sband_stats = 0; | |
319 | priv->tx_bd[1]->sband_stats = 0; | |
320 | ||
321 | log_debug("Sending complete\n"); | |
322 | ||
323 | return 0; | |
324 | } | |
325 | ||
326 | static bool isrxready(struct axi_mrmac_priv *priv) | |
327 | { | |
328 | u32 status; | |
329 | ||
330 | /* Read pending interrupts */ | |
331 | status = readl(&priv->mcdma_rx->status); | |
332 | ||
333 | /* Acknowledge pending interrupts */ | |
334 | writel(status & XMCDMA_IRQ_ALL_MASK, &priv->mcdma_rx->status); | |
335 | ||
336 | /* | |
337 | * If Reception done interrupt is asserted, call Rx call back function | |
338 | * to handle the processed BDs and then raise the according flag. | |
339 | */ | |
340 | if (status & (XMCDMA_IRQ_IOC_MASK | XMCDMA_IRQ_DELAY_MASK)) | |
341 | return 1; | |
342 | ||
343 | return 0; | |
344 | } | |
345 | ||
346 | /** | |
347 | * axi_mrmac_recv - MRMAC Rx function | |
348 | * @dev: udevice structure | |
349 | * @flags: flags from network stack | |
350 | * @packetp pointer to received data | |
351 | * | |
352 | * Return: received data length on success, negative value on errors | |
353 | * | |
354 | * This is a Rx function of MRMAC. Check if any data is received on MCDMA. | |
355 | * Copy buffer pointer to packetp and return received data length. | |
356 | */ | |
357 | static int axi_mrmac_recv(struct udevice *dev, int flags, uchar **packetp) | |
358 | { | |
359 | struct axi_mrmac_priv *priv = dev_get_priv(dev); | |
360 | u32 rx_bd_end; | |
361 | u32 length; | |
362 | ||
363 | /* Wait for an incoming packet */ | |
364 | if (!isrxready(priv)) | |
365 | return -EAGAIN; | |
366 | ||
367 | /* Clear all interrupts */ | |
368 | writel(XMCDMA_IRQ_ALL_MASK, &priv->mcdma_rx->status); | |
369 | ||
370 | /* Disable IRQ for a moment till packet is handled */ | |
371 | clrbits_le32(&priv->mcdma_rx->control, XMCDMA_IRQ_ALL_MASK); | |
372 | ||
373 | /* Disable channel fetch */ | |
374 | clrbits_le32(&priv->mcdma_rx->control, XMCDMA_CR_RUNSTOP_MASK); | |
375 | ||
376 | rx_bd_end = (ulong)priv->rx_bd[0] + roundup(RX_BD_TOTAL_SIZE, | |
377 | ARCH_DMA_MINALIGN); | |
378 | /* Invalidate Rx descriptors to see proper Rx length */ | |
379 | invalidate_dcache_range((phys_addr_t)priv->rx_bd[0], rx_bd_end); | |
380 | ||
381 | length = priv->rx_bd[0]->status & XMCDMA_BD_STS_ACTUAL_LEN_MASK; | |
382 | *packetp = (uchar *)(ulong)priv->rx_bd[0]->buf_addr; | |
383 | ||
384 | if (!length) { | |
385 | length = priv->rx_bd[1]->status & XMCDMA_BD_STS_ACTUAL_LEN_MASK; | |
386 | *packetp = (uchar *)(ulong)priv->rx_bd[1]->buf_addr; | |
387 | } | |
388 | ||
389 | #ifdef DEBUG | |
390 | print_buffer(*packetp, *packetp, 1, length, 16); | |
391 | #endif | |
392 | /* Clear status */ | |
393 | priv->rx_bd[0]->status = 0; | |
394 | priv->rx_bd[1]->status = 0; | |
395 | ||
396 | return length; | |
397 | } | |
398 | ||
399 | /** | |
400 | * axi_mrmac_free_pkt - MRMAC free packet function | |
401 | * @dev: udevice structure | |
402 | * @packet: receive buffer pointer | |
403 | * @length received data length | |
404 | * | |
405 | * Return: 0 on success, negative value on errors | |
406 | * | |
407 | * This is Rx free packet function of MRMAC. Prepare MRMAC for reception of | |
408 | * data again. Invalidate previous data from Rx buffers and set Rx buffer | |
409 | * descriptors. Trigger reception by updating tail descriptor. | |
410 | */ | |
411 | static int axi_mrmac_free_pkt(struct udevice *dev, uchar *packet, int length) | |
412 | { | |
413 | struct axi_mrmac_priv *priv = dev_get_priv(dev); | |
414 | ||
415 | #ifdef DEBUG | |
416 | /* It is useful to clear buffer to be sure that it is consistent */ | |
417 | memset(priv->rx_bd[0]->buf_addr, 0, RX_BUFF_TOTAL_SIZE); | |
418 | #endif | |
419 | /* Disable all Rx interrupts before RxBD space setup */ | |
420 | clrbits_le32(&priv->mcdma_rx->control, XMCDMA_IRQ_ALL_MASK); | |
421 | ||
422 | /* Disable channel fetch */ | |
423 | clrbits_le32(&priv->mcdma_rx->control, XMCDMA_CR_RUNSTOP_MASK); | |
424 | ||
425 | /* Update current descriptor */ | |
426 | axi_mrmac_dma_write(priv->rx_bd[0], &priv->mcdma_rx->current); | |
427 | ||
428 | /* Write bd to HW */ | |
429 | flush_cache((phys_addr_t)priv->rx_bd[0], RX_BD_TOTAL_SIZE); | |
430 | ||
431 | /* It is necessary to flush rx buffers because if you don't do it | |
432 | * then cache will contain previous packet | |
433 | */ | |
434 | flush_cache((phys_addr_t)priv->rx_bd[0]->buf_addr, RX_BUFF_TOTAL_SIZE); | |
435 | ||
436 | /* Enable all IRQ */ | |
437 | setbits_le32(&priv->mcdma_rx->control, XMCDMA_IRQ_ALL_MASK); | |
438 | ||
439 | /* Channel fetch */ | |
440 | setbits_le32(&priv->mcdma_rx->control, XMCDMA_CR_RUNSTOP_MASK); | |
441 | ||
442 | /* Update tail descriptor. Now it's ready to receive data */ | |
443 | axi_mrmac_dma_write(priv->rx_bd[1], &priv->mcdma_rx->tail); | |
444 | ||
445 | log_debug("Rx completed, framelength = %x\n", length); | |
446 | ||
447 | return 0; | |
448 | } | |
449 | ||
450 | /** | |
451 | * axi_mrmac_stop - Stop MCDMA transfers | |
452 | * @dev: udevice structure | |
453 | * | |
454 | * Return: 0 on success, negative value on errors | |
455 | * | |
456 | * Stop MCDMA engine for both Tx and Rx transfers. | |
457 | */ | |
458 | static void axi_mrmac_stop(struct udevice *dev) | |
459 | { | |
460 | struct axi_mrmac_priv *priv = dev_get_priv(dev); | |
461 | ||
462 | /* Stop the hardware */ | |
463 | clrbits_le32(&priv->mcdma_tx->control, XMCDMA_CR_RUNSTOP_MASK); | |
464 | clrbits_le32(&priv->mcdma_rx->control, XMCDMA_CR_RUNSTOP_MASK); | |
465 | ||
466 | log_debug("Halted\n"); | |
467 | } | |
468 | ||
469 | static int axi_mrmac_probe(struct udevice *dev) | |
470 | { | |
471 | struct axi_mrmac_plat *plat = dev_get_plat(dev); | |
472 | struct eth_pdata *pdata = &plat->eth_pdata; | |
473 | struct axi_mrmac_priv *priv = dev_get_priv(dev); | |
474 | ||
475 | priv->iobase = (struct mrmac_regs *)pdata->iobase; | |
476 | ||
477 | priv->mm2s_cmn = plat->mm2s_cmn; | |
478 | priv->mcdma_tx = (struct mcdma_chan_reg *)((phys_addr_t)priv->mm2s_cmn | |
479 | + XMCDMA_CHAN_OFFSET); | |
480 | priv->s2mm_cmn = (struct mcdma_common_regs *)((phys_addr_t)priv->mm2s_cmn | |
481 | + XMCDMA_RX_OFFSET); | |
482 | priv->mcdma_rx = (struct mcdma_chan_reg *)((phys_addr_t)priv->s2mm_cmn | |
483 | + XMCDMA_CHAN_OFFSET); | |
484 | priv->mrmac_rate = plat->mrmac_rate; | |
485 | ||
486 | /* Align buffers to ARCH_DMA_MINALIGN */ | |
487 | priv->tx_bd[0] = memalign(ARCH_DMA_MINALIGN, TX_BD_TOTAL_SIZE); | |
488 | priv->tx_bd[1] = (struct mcdma_bd *)((ulong)priv->tx_bd[0] + | |
489 | sizeof(struct mcdma_bd)); | |
490 | ||
491 | priv->rx_bd[0] = memalign(ARCH_DMA_MINALIGN, RX_BD_TOTAL_SIZE); | |
492 | priv->rx_bd[1] = (struct mcdma_bd *)((ulong)priv->rx_bd[0] + | |
493 | sizeof(struct mcdma_bd)); | |
494 | ||
495 | priv->txminframe = memalign(ARCH_DMA_MINALIGN, MIN_PKT_SIZE); | |
496 | ||
497 | return 0; | |
498 | } | |
499 | ||
500 | static int axi_mrmac_remove(struct udevice *dev) | |
501 | { | |
502 | struct axi_mrmac_priv *priv = dev_get_priv(dev); | |
503 | ||
504 | /* Free buffer descriptors */ | |
505 | free(priv->tx_bd[0]); | |
506 | free(priv->rx_bd[0]); | |
507 | free(priv->txminframe); | |
508 | ||
509 | return 0; | |
510 | } | |
511 | ||
512 | static int axi_mrmac_of_to_plat(struct udevice *dev) | |
513 | { | |
514 | struct axi_mrmac_plat *plat = dev_get_plat(dev); | |
515 | struct eth_pdata *pdata = &plat->eth_pdata; | |
516 | struct ofnode_phandle_args phandle_args; | |
517 | int ret = 0; | |
518 | ||
519 | pdata->iobase = dev_read_addr(dev); | |
520 | ||
521 | ret = dev_read_phandle_with_args(dev, "axistream-connected", NULL, 0, 0, | |
522 | &phandle_args); | |
523 | if (ret) { | |
524 | log_debug("axistream not found\n"); | |
525 | return -EINVAL; | |
526 | } | |
527 | ||
528 | plat->mm2s_cmn = (struct mcdma_common_regs *)ofnode_read_u64_default | |
529 | (phandle_args.node, "reg", -1); | |
530 | if (!plat->mm2s_cmn) { | |
531 | log_warning("MRMAC dma register space not found\n"); | |
532 | return -EINVAL; | |
533 | } | |
534 | ||
535 | /* Set default MRMAC rate to 10000 */ | |
536 | plat->mrmac_rate = dev_read_u32_default(dev, "xlnx,mrmac-rate", 10000); | |
537 | ||
538 | return 0; | |
539 | } | |
540 | ||
541 | static const struct eth_ops axi_mrmac_ops = { | |
542 | .start = axi_mrmac_start, | |
543 | .send = axi_mrmac_send, | |
544 | .recv = axi_mrmac_recv, | |
545 | .free_pkt = axi_mrmac_free_pkt, | |
546 | .stop = axi_mrmac_stop, | |
547 | }; | |
548 | ||
549 | static const struct udevice_id axi_mrmac_ids[] = { | |
550 | { .compatible = "xlnx,mrmac-ethernet-1.0" }, | |
551 | { } | |
552 | }; | |
553 | ||
554 | U_BOOT_DRIVER(axi_mrmac) = { | |
555 | .name = "axi_mrmac", | |
556 | .id = UCLASS_ETH, | |
557 | .of_match = axi_mrmac_ids, | |
558 | .of_to_plat = axi_mrmac_of_to_plat, | |
559 | .probe = axi_mrmac_probe, | |
560 | .remove = axi_mrmac_remove, | |
561 | .ops = &axi_mrmac_ops, | |
562 | .priv_auto = sizeof(struct axi_mrmac_priv), | |
563 | .plat_auto = sizeof(struct axi_mrmac_plat), | |
564 | }; |