1 /*
2 * Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <rtthread.h>
17 #include <mmu.h>
18
19 #include "dw_eth_mac.h"
20 #include "cache.h"
21 #include "string.h"
22 #include "drv_ioremap.h"
23
24
25 #define roundup(x, y) ( \
26 { \
27 const typeof(y) __y = y; \
28 (((x) + (__y - 1)) / __y) * __y; \
29 } \
30 )
31
32 #define CONFIG_GMAC_NUM 2
33
34 static gmac_dev_t gmac_instance[CONFIG_GMAC_NUM];
35
designware_read_hwaddr(eth_mac_handle_t handle)36 static int32_t designware_read_hwaddr(eth_mac_handle_t handle)
37 {
38 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
39 struct dw_gmac_mac_regs *mac_reg = mac_dev->priv->mac_regs_p;
40 uint32_t macid_lo, macid_hi;
41 uint8_t mac_id[6] = {0};
42
43 macid_hi = mac_reg->macaddr0hi;
44 macid_lo = mac_reg->macaddr0lo;
45
46 mac_id[0] = macid_lo & 0xff;
47 mac_id[1] = (macid_lo >> 8) & 0xff;
48 mac_id[2] = (macid_lo >> 16) & 0xff;
49 mac_id[3] = (macid_lo >> 24) & 0xff;
50 mac_id[4] = macid_hi & 0xff;
51 mac_id[5] = (macid_hi >> 8) & 0xff;
52
53 memcpy(mac_dev->mac_addr, mac_id, sizeof(mac_id));
54
55 return 0;
56 }
57
designware_write_hwaddr(eth_mac_handle_t handle)58 static int32_t designware_write_hwaddr(eth_mac_handle_t handle)
59 {
60 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
61 struct dw_gmac_mac_regs *mac_reg = mac_dev->priv->mac_regs_p;
62
63 uint32_t macid_lo, macid_hi;
64 uint8_t *mac_id = mac_dev->mac_addr;
65
66 macid_lo = mac_id[0] + (mac_id[1] << 8) + (mac_id[2] << 16) +
67 (mac_id[3] << 24);
68 macid_hi = mac_id[4] + (mac_id[5] << 8);
69
70 mac_reg->macaddr0hi = macid_hi;
71 mac_reg->macaddr0lo = macid_lo;
72
73 return 0;
74 }
75
tx_descs_init(eth_mac_handle_t handle)76 static void tx_descs_init(eth_mac_handle_t handle)
77 {
78 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
79 struct dw_gmac_priv *priv = mac_dev->priv;
80 struct dw_gmac_dma_regs *dma_reg = priv->dma_regs_p;
81 struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0];
82 char *txbuffs = &priv->txbuffs[0];
83 struct dmamacdescr *desc_p;
84 uint32_t idx;
85
86 for (idx = 0; idx < CVI_CONFIG_TX_DESCR_NUM; idx ++) {
87 desc_p = &desc_table_p[idx];
88 #ifdef RT_USING_SMART
89 desc_p->dmamac_addr = (unsigned long)rt_kmem_v2p((void *)&txbuffs[idx * CVI_CONFIG_ETH_BUFSIZE]);
90 desc_p->dmamac_next = (unsigned long)rt_kmem_v2p((void *)&desc_table_p[idx + 1]);
91 #else
92 desc_p->dmamac_addr = (unsigned long)&txbuffs[idx * CVI_CONFIG_ETH_BUFSIZE];
93 desc_p->dmamac_next = (unsigned long)&desc_table_p[idx + 1];
94 #endif
95
96 #if defined(CONFIG_DW_ALTDESCRIPTOR)
97 desc_p->txrx_status &= ~(CVI_DESC_TXSTS_TXINT | CVI_DESC_TXSTS_TXLAST |
98 CVI_DESC_TXSTS_TXFIRST | CVI_DESC_TXSTS_TXCRCDIS |
99 CVI_DESC_TXSTS_TXCHECKINSCTRL |
100 CVI_DESC_TXSTS_TXRINGEND | CVI_DESC_TXSTS_TXPADDIS);
101
102 desc_p->txrx_status |= CVI_DESC_TXSTS_TXCHAIN;
103 desc_p->dmamac_cntl = 0;
104 desc_p->txrx_status &= ~(CVI_DESC_TXSTS_MSK | CVI_DESC_TXSTS_OWNBYDMA);
105 #else
106 desc_p->dmamac_cntl = CVI_DESC_TXCTRL_TXCHAIN;
107 desc_p->txrx_status = 0;
108 #endif
109 }
110
111 /* Correcting the last pointer of the chain */
112 #ifdef RT_USING_SMART
113 desc_p->dmamac_next = (unsigned long)rt_kmem_v2p((void *)&desc_table_p[0]);
114 #else
115 desc_p->dmamac_next = (unsigned long)&desc_table_p[0];
116 #endif
117
118 /* Flush all Tx buffer descriptors at once */
119 rt_hw_cpu_dcache_clean((void *)priv->tx_mac_descrtable, sizeof(priv->tx_mac_descrtable));
120
121 #ifdef RT_USING_SMART
122 dma_reg->txdesclistaddr = (rt_ubase_t)rt_kmem_v2p((void *)&desc_table_p[0]);
123 #else
124 dma_reg->txdesclistaddr = (reg_type)&desc_table_p[0];
125 #endif
126
127 priv->tx_currdescnum = 0;
128 }
129
rx_descs_init(eth_mac_handle_t handle)130 static void rx_descs_init(eth_mac_handle_t handle)
131 {
132 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
133 struct dw_gmac_priv *priv = mac_dev->priv;
134 struct dw_gmac_dma_regs *dma_reg = priv->dma_regs_p;
135 struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
136 char *rxbuffs = &priv->rxbuffs[0];
137 struct dmamacdescr *desc_p;
138 uint32_t idx;
139
140 /* Before passing buffers to GMAC we need to make sure zeros
141 * written there right after "priv" structure allocation were
142 * flushed into RAM.
143 * Otherwise there's a chance to get some of them flushed in RAM when
144 * GMAC is already pushing data to RAM via DMA. This way incoming from
145 * GMAC data will be corrupted. */
146 rt_hw_cpu_dcache_clean((void *)rxbuffs, CVI_RX_TOTAL_BUFSIZE);
147
148 for (idx = 0; idx < CVI_CONFIG_RX_DESCR_NUM; idx++) {
149 desc_p = &desc_table_p[idx];
150 #ifdef RT_USING_SMART
151 desc_p->dmamac_addr = (unsigned long)rt_kmem_v2p((void *)&rxbuffs[idx * CVI_CONFIG_ETH_BUFSIZE]);
152 desc_p->dmamac_next = (unsigned long)rt_kmem_v2p((void *)&desc_table_p[idx + 1]);
153 #else
154 desc_p->dmamac_addr = (unsigned long)&rxbuffs[idx * CVI_CONFIG_ETH_BUFSIZE];
155 desc_p->dmamac_next = (unsigned long)&desc_table_p[idx + 1];
156 #endif
157
158 desc_p->dmamac_cntl = (CVI_MAC_MAX_FRAME_SZ & CVI_DESC_RXCTRL_SIZE1MASK) | CVI_DESC_RXCTRL_RXCHAIN;
159
160 desc_p->txrx_status = CVI_DESC_RXSTS_OWNBYDMA;
161 }
162
163 /* Correcting the last pointer of the chain */
164 #ifdef RT_USING_SMART
165 desc_p->dmamac_next = (unsigned long)rt_kmem_v2p((void *)&desc_table_p[0]);
166 #else
167 desc_p->dmamac_next = (unsigned long)&desc_table_p[0];
168 #endif
169
170 /* Flush all Rx buffer descriptors at once */
171 rt_hw_cpu_dcache_clean((void *)priv->rx_mac_descrtable, sizeof(priv->rx_mac_descrtable));
172
173 #ifdef RT_USING_SMART
174 dma_reg->rxdesclistaddr = (rt_ubase_t)rt_kmem_v2p((void *)&desc_table_p[0]);
175 #else
176 dma_reg->rxdesclistaddr = (reg_type)&desc_table_p[0];
177 #endif
178
179 priv->rx_currdescnum = 0;
180 }
181
designware_adjust_link(eth_mac_handle_t handle)182 static int32_t designware_adjust_link(eth_mac_handle_t handle)
183 {
184 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
185 struct dw_gmac_priv *priv = mac_dev->priv;
186 struct dw_gmac_mac_regs *mac_reg = priv->mac_regs_p;
187 eth_link_info_t *link_info = &mac_dev->phy_dev->priv->link_info;
188 eth_link_state_t link_state = mac_dev->phy_dev->link_state;
189
190 uint32_t conf = mac_reg->conf | CVI_FRAMEBURSTENABLE | CVI_DISABLERXOWN;
191
192 if (!link_state) {
193 rt_kprintf("eth No link.\n");
194 return 0;
195 }
196
197 if (link_info->speed != CSI_ETH_SPEED_1G)
198 conf |= CVI_MII_PORTSELECT;
199 else
200 conf &= ~CVI_MII_PORTSELECT;
201
202 if (link_info->speed == CSI_ETH_SPEED_100M)
203 conf |= CVI_FES_100;
204
205 if (link_info->duplex)
206 conf |= CVI_FULLDPLXMODE;
207
208 mac_reg->conf = conf;
209
210 rt_kprintf("Speed: %s, duplex: %s\n",
211 (link_info->speed) ? "100M" : "10M",
212 (link_info->duplex) ? "full" : "half");
213
214 return 0;
215 }
216
designware_eth_init(eth_mac_handle_t handle)217 static int32_t designware_eth_init(eth_mac_handle_t handle)
218 {
219 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
220 struct dw_gmac_mac_regs *mac_reg = mac_dev->priv->mac_regs_p;
221 struct dw_gmac_dma_regs *dma_reg = mac_dev->priv->dma_regs_p;
222
223 uint32_t start;
224
225 dma_reg->busmode |= CVI_DMAMAC_SRST;
226
227 start = rt_tick_get_millisecond();
228 while (dma_reg->busmode & CVI_DMAMAC_SRST) {
229 if ((rt_tick_get_millisecond() - start) >= CVI_CONFIG_MACRESET_TIMEOUT) {
230 rt_kprintf("DMA reset timeout\n");
231 return -ETIMEDOUT;
232 }
233
234 rt_thread_mdelay(100);
235 };
236
237 /*
238 * Soft reset above clears HW address registers.
239 * So we have to set it here once again.
240 */
241 // designware_read_hwaddr(handle);
242 // designware_write_hwaddr(handle);
243
244 rx_descs_init(handle);
245 tx_descs_init(handle);
246
247 dma_reg->busmode = (CVI_FIXEDBURST | CVI_PRIORXTX_41 | CVI_DMA_PBL);
248
249 // mac_reg->framefilt = 0x10;
250 // mac_reg->flowcontrol = 0x8;
251 // dma_reg->wdtforri = 0xff;
252 // dma_reg->axibus = 0x0012100F;
253
254 #ifndef CONFIG_DW_MAC_FORCE_THRESHOLD_MODE
255 dma_reg->opmode |= (CVI_FLUSHTXFIFO | CVI_STOREFORWARD);
256 #else
257 dma_reg->opmode |= CVI_FLUSHTXFIFO;
258 #endif
259
260 dma_reg->opmode |= (CVI_RXSTART | CVI_TXSTART);
261 dma_reg->opmode = 0x2202906;
262 dma_reg->busmode = 0x3900800;
263 mac_reg->conf = 0x41cc00;
264 dma_reg->intenable = 0x10040;
265
266 #ifdef CONFIG_DW_AXI_BURST_LEN
267 dma_reg->axibus = (CONFIG_DW_AXI_BURST_LEN & 0x1FF >> 1);
268 #endif
269
270 /* Start up the PHY */
271 /* adjust link */
272 return 0;
273 }
274
designware_eth_enable(eth_mac_handle_t handle,int32_t control)275 static int32_t designware_eth_enable(eth_mac_handle_t handle, int32_t control)
276 {
277 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
278 struct dw_gmac_mac_regs *mac_reg = mac_dev->priv->mac_regs_p;
279 eth_link_state_t link_state = mac_dev->phy_dev->link_state;
280
281 // if (link_state == ETH_LINK_DOWN)
282 // return -1;
283
284 switch (control) {
285 case CSI_ETH_MAC_CONTROL_TX:
286 mac_reg->conf |= CVI_TXENABLE;
287 break;
288 case CSI_ETH_MAC_CONTROL_RX:
289 mac_reg->conf |= CVI_RXENABLE;
290 break;
291 default:
292 break;
293 }
294
295 return 0;
296 }
designware_eth_disable(eth_mac_handle_t handle,int32_t arg)297 static int32_t designware_eth_disable(eth_mac_handle_t handle, int32_t arg)
298 {
299 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
300 struct dw_gmac_mac_regs *mac_reg = mac_dev->priv->mac_regs_p;
301
302 switch (arg) {
303 case CSI_ETH_MAC_CONTROL_TX:
304 mac_reg->conf &= ~CVI_TXENABLE;
305 break;
306 case CSI_ETH_MAC_CONTROL_RX:
307 mac_reg->conf &= ~CVI_RXENABLE;
308 break;
309 default:
310 break;
311 }
312
313 return 0;
314 }
315
designware_eth_start(eth_mac_handle_t handle)316 static int32_t designware_eth_start(eth_mac_handle_t handle)
317 {
318 int32_t ret;
319
320 ret = designware_eth_init(handle);
321 if (ret)
322 return ret;
323
324 return 0;
325 }
326
designware_eth_stop(eth_mac_handle_t handle)327 void designware_eth_stop(eth_mac_handle_t handle)
328 {
329 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
330 struct dw_gmac_mac_regs *mac_reg = mac_dev->priv->mac_regs_p;
331 struct dw_gmac_dma_regs *dma_reg = mac_dev->priv->dma_regs_p;
332
333 mac_reg->conf &= ~(CVI_RXENABLE | CVI_TXENABLE);
334 dma_reg->opmode &= ~(CVI_RXSTART | CVI_TXSTART);
335
336 //phy_shutdown(priv->phydev);
337 }
338
designware_eth_send(eth_mac_handle_t handle,const uint8_t * frame,uint32_t length)339 static int32_t designware_eth_send(eth_mac_handle_t handle, const uint8_t *frame, uint32_t length)
340 {
341 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
342 struct dw_gmac_priv *priv = mac_dev->priv;
343 struct dw_gmac_dma_regs *dma_reg = mac_dev->priv->dma_regs_p;
344 uint32_t desc_num = priv->tx_currdescnum;
345 struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
346 uint64_t desc_start = (uint64_t)desc_p;
347 uint64_t desc_end = desc_start + roundup(sizeof(*desc_p), DW_GMAC_DMA_ALIGN);
348 uint64_t data_start = (uint64_t)DRV_IOREMAP((void *)desc_p->dmamac_addr, 0x1000);
349 uint64_t data_end = data_start + roundup(length, DW_GMAC_DMA_ALIGN);
350 uint32_t count = 0;
351
352 /*
353 * Strictly we only need to invalidate the "txrx_status" field
354 * for the following check, but on some platforms we cannot
355 * invalidate only 4 bytes, so we flush the entire descriptor,
356 * which is 16 bytes in total. This is safe because the
357 * individual descriptors in the array are each aligned to
358 * DW_GMAC_DMA_ALIGN and padded appropriately.
359 */
360
361 /* Check if the descriptor is owned by CPU */
362 while (1)
363 {
364 rt_hw_cpu_dcache_invalidate((void *)desc_start, desc_end - desc_start);
365 if (!(desc_p->txrx_status & CVI_DESC_TXSTS_OWNBYDMA))
366 {
367 break;
368 }
369
370 if (count > 1000)
371 {
372 rt_kprintf("desc onwer is DMA\n");
373 return -1;
374 }
375 count ++;
376 rt_thread_mdelay(1);
377 }
378
379 memcpy((void *)data_start, frame, length);
380
381 /* Flush data to be sent */
382 rt_hw_cpu_dcache_clean((void *)data_start, data_end - data_start);
383
384 #if defined(CONFIG_DW_ALTDESCRIPTOR)
385 desc_p->txrx_status |= CVI_DESC_TXSTS_TXFIRST | CVI_DESC_TXSTS_TXLAST;
386 desc_p->dmamac_cntl &= ~CVI_DESC_TXCTRL_SIZE1MASK;
387 desc_p->dmamac_cntl |= (length << CVI_DESC_TXCTRL_SIZE1SHFT) &
388 CVI_DESC_TXCTRL_SIZE1MASK;
389
390 desc_p->txrx_status &= ~(CVI_DESC_TXSTS_MSK);
391 desc_p->txrx_status |= CVI_DESC_TXSTS_OWNBYDMA;
392 #else
393 desc_p->dmamac_cntl &= ~CVI_DESC_TXCTRL_SIZE1MASK;
394 desc_p->dmamac_cntl |= ((length << CVI_DESC_TXCTRL_SIZE1SHFT) &
395 CVI_DESC_TXCTRL_SIZE1MASK) | CVI_DESC_TXCTRL_TXLAST |
396 CVI_DESC_TXCTRL_TXFIRST;
397
398 desc_p->txrx_status = CVI_DESC_TXSTS_OWNBYDMA;
399 #endif
400
401 /* Flush modified buffer descriptor */
402 rt_hw_cpu_dcache_clean((void *)desc_start, desc_end - desc_start);
403
404 /* Test the wrap-around condition. */
405 if (++desc_num >= CVI_CONFIG_TX_DESCR_NUM)
406 desc_num = 0;
407
408 priv->tx_currdescnum = desc_num;
409
410 /* Start the transmission */
411 dma_reg->txpolldemand = CVI_POLL_DATA;
412
413 return 0;
414 }
415
designware_eth_recv(eth_mac_handle_t handle,uint8_t ** packetp)416 static int32_t designware_eth_recv(eth_mac_handle_t handle, uint8_t **packetp)
417 {
418 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
419 struct dw_gmac_priv *priv = mac_dev->priv;
420 uint32_t status, desc_num = priv->rx_currdescnum;
421 struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
422 int32_t length = -1;
423 uint64_t desc_start = (uint64_t)desc_p;
424 uint64_t desc_end = desc_start + roundup(sizeof(*desc_p), DW_GMAC_DMA_ALIGN);
425 uint64_t data_start = (uint64_t)DRV_IOREMAP((void *)desc_p->dmamac_addr, 0x1000);
426 uint64_t data_end;
427
428 /* Invalidate entire buffer descriptor */
429 rt_hw_cpu_dcache_invalidate((void *)desc_start, desc_end - desc_start);
430 status = desc_p->txrx_status;
431 /* Check if the owner is the CPU */
432 if (!(status & CVI_DESC_RXSTS_OWNBYDMA))
433 {
434 length = (status & CVI_DESC_RXSTS_FRMLENMSK) >> CVI_DESC_RXSTS_FRMLENSHFT;
435
436 /* Invalidate received data */
437 data_end = data_start + roundup(length, DW_GMAC_DMA_ALIGN);
438
439 rt_hw_cpu_dcache_invalidate((void *)data_start, data_end - data_start);
440 *packetp = (uint8_t *)data_start;
441 }
442
443 return length;
444 }
445
designware_free_pkt(eth_mac_handle_t handle)446 static int32_t designware_free_pkt(eth_mac_handle_t handle)
447 {
448 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
449 struct dw_gmac_priv *priv = mac_dev->priv;
450 uint32_t desc_num = priv->rx_currdescnum;
451 struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
452 uint64_t desc_start = (uint64_t)desc_p;
453 uint64_t desc_end = desc_start + roundup(sizeof(*desc_p), DW_GMAC_DMA_ALIGN);
454
455 /*
456 * Make the current descriptor valid again and go to
457 * the next one
458 */
459 desc_p->txrx_status |= CVI_DESC_RXSTS_OWNBYDMA;
460
461 /* Flush only status field - others weren't changed */
462 rt_hw_cpu_dcache_clean((void *)desc_start, desc_end - desc_start);
463
464 /* Test the wrap-around condition. */
465 if (++desc_num >= CVI_CONFIG_RX_DESCR_NUM)
466 desc_num = 0;
467 priv->rx_currdescnum = desc_num;
468
469 return 0;
470 }
471
472 /**
473 \brief Connect phy device to mac device.
474 \param[in] handle_mac mac handle
475 \param[in] handle_phy phy handle
476 */
dw_eth_mac_connect_phy(eth_mac_handle_t handle_mac,eth_phy_handle_t handle_phy)477 void dw_eth_mac_connect_phy(eth_mac_handle_t handle_mac, eth_phy_handle_t handle_phy)
478 {
479 RT_ASSERT(handle_mac);
480 RT_ASSERT(handle_phy);
481 gmac_dev_t *mac_dev = (gmac_dev_t *)handle_mac;
482 eth_phy_dev_t *phy_dev = (eth_phy_dev_t *)handle_phy;
483
484 mac_dev->phy_dev = phy_dev;
485 }
486
487 /**
488 \brief Read Ethernet PHY Register through Management Interface.
489 \param[in] handle ethernet handle
490 \param[in] phy_addr 5-bit device address
491 \param[in] reg_addr 5-bit register address
492 \param[out] data Pointer where the result is written to
493 \return error code
494 */
dw_eth_mac_phy_read(eth_mac_handle_t handle,uint8_t phy_addr,uint8_t reg_addr,uint16_t * data)495 int32_t dw_eth_mac_phy_read(eth_mac_handle_t handle, uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
496 {
497 RT_ASSERT(handle);
498 RT_ASSERT(data);
499 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
500 struct dw_gmac_priv *priv = mac_dev->priv;
501 struct dw_gmac_mac_regs *mac_reg = priv->mac_regs_p;
502 uint16_t miiaddr;
503 int32_t start;
504
505 miiaddr = ((phy_addr << CVI_MIIADDRSHIFT) & CVI_MII_ADDRMSK) | ((reg_addr << CVI_MIIREGSHIFT) & CVI_MII_REGMSK);
506
507 mac_reg->miiaddr = (miiaddr | CVI_MII_CLKRANGE_150_250M | CVI_MII_BUSY);
508
509 start = rt_tick_get_millisecond();
510 while ((rt_tick_get_millisecond() - start) < CVI_CONFIG_MDIO_TIMEOUT)
511 {
512 if (!(mac_reg->miiaddr & CVI_MII_BUSY))
513 {
514 *data = mac_reg->miidata;
515 return 0;
516 }
517 rt_hw_us_delay(10);
518 };
519
520 return -1;
521 }
522
523 /**
524 \brief Write Ethernet PHY Register through Management Interface.
525 \param[in] handle ethernet handle
526 \param[in] phy_addr 5-bit device address
527 \param[in] reg_addr 5-bit register address
528 \param[in] data 16-bit data to write
529 \return error code
530 */
dw_eth_mac_phy_write(eth_mac_handle_t handle,uint8_t phy_addr,uint8_t reg_addr,uint16_t data)531 int32_t dw_eth_mac_phy_write(eth_mac_handle_t handle, uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
532 {
533 RT_ASSERT(handle);
534 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
535 struct dw_gmac_priv *priv = mac_dev->priv;
536 struct dw_gmac_mac_regs *mac_reg = priv->mac_regs_p;
537 uint16_t miiaddr;
538 int32_t start;
539
540 mac_reg->miidata = data;
541 miiaddr = ((phy_addr << CVI_MIIADDRSHIFT) & CVI_MII_ADDRMSK) |
542 ((reg_addr << CVI_MIIREGSHIFT) & CVI_MII_REGMSK) | CVI_MII_WRITE;
543
544 mac_reg->miiaddr = (miiaddr | CVI_MII_CLKRANGE_150_250M | CVI_MII_BUSY);
545
546 start = rt_tick_get_millisecond();
547 while ((rt_tick_get_millisecond() - start) < CVI_CONFIG_MDIO_TIMEOUT) {
548 if (!(mac_reg->miiaddr & CVI_MII_BUSY)) {
549 return 0;
550 }
551 rt_hw_us_delay(10);
552 };
553
554 return -1;
555 }
556
557 /**
558 \brief Control Ethernet Interface.
559 \param[in] handle ethernet handle
560 \param[in] control Operation
561 \param[in] arg Argument of operation (optional)
562 \return error code
563 */
cvi_eth_mac_control(eth_mac_handle_t handle,uint32_t control,uint32_t arg)564 int32_t cvi_eth_mac_control(eth_mac_handle_t handle, uint32_t control, uint32_t arg)
565 {
566 RT_ASSERT(handle);
567
568 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
569 int32_t ret = 0;
570
571 RT_ASSERT(mac_dev->phy_dev);
572
573 switch (control) {
574 case CSI_ETH_MAC_CONFIGURE:
575 if (arg) {
576 /* startup mac */
577 ret = designware_eth_start(handle);
578 } else {
579 /* stop mac */
580 designware_eth_stop(handle);
581 }
582 break;
583
584 case DRV_ETH_MAC_ADJUST_LINK:
585 ret = designware_adjust_link(handle);
586 break;
587
588 case CSI_ETH_MAC_CONTROL_TX:
589 if (arg) {
590 /* enable TX */
591 ret = designware_eth_enable(handle, CSI_ETH_MAC_CONTROL_TX);
592 } else {
593 /* disable TX */
594 ret = designware_eth_disable(handle, CSI_ETH_MAC_CONTROL_TX);
595 }
596 break;
597
598 case CSI_ETH_MAC_CONTROL_RX:
599 if (arg) {
600 /* enable RX */
601 ret = designware_eth_enable(handle, CSI_ETH_MAC_CONTROL_RX);
602 } else {
603 /* disable RX */
604 ret = designware_eth_disable(handle, CSI_ETH_MAC_CONTROL_RX);
605 }
606 break;
607
608 case DRV_ETH_MAC_CONTROL_IRQ:
609 if (arg) {
610 /* enable interrupt */
611 } else {
612 /* disable interrupt */
613 }
614 break;
615
616 default:
617 break;
618 };
619
620 return ret;
621 }
622
623 /**
624 \brief Get Ethernet MAC Address.
625 \param[in] handle ethernet handle
626 \param[in] mac Pointer to address
627 \return error code
628 */
cvi_eth_mac_get_macaddr(eth_mac_handle_t handle,eth_mac_addr_t * mac)629 int32_t cvi_eth_mac_get_macaddr(eth_mac_handle_t handle, eth_mac_addr_t *mac)
630 {
631 RT_ASSERT(handle);
632 RT_ASSERT(mac);
633
634 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
635
636 designware_read_hwaddr(handle);
637
638 memcpy(mac->b, mac_dev->mac_addr, sizeof(mac_dev->mac_addr));
639
640 return 0;
641 }
642
643 /**
644 \brief Set Ethernet MAC Address.
645 \param[in] handle ethernet handle
646 \param[in] mac Pointer to address
647 \return error code
648 */
cvi_eth_mac_set_macaddr(eth_mac_handle_t handle,const eth_mac_addr_t * mac)649 int32_t cvi_eth_mac_set_macaddr(eth_mac_handle_t handle, const eth_mac_addr_t *mac)
650 {
651 RT_ASSERT(handle);
652 RT_ASSERT(mac);
653
654 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
655 memcpy(mac_dev->mac_addr, mac->b, sizeof(mac->b));
656
657 designware_write_hwaddr(handle);
658
659 return 0;
660 }
661
662 /**
663 \brief Send Ethernet frame.
664 \param[in] handle ethernet handle
665 \param[in] frame Pointer to frame buffer with data to send
666 \param[in] len Frame buffer length in bytes
667 \return error code
668 */
cvi_eth_mac_send_frame(eth_mac_handle_t handle,const uint8_t * frame,uint32_t len)669 int32_t cvi_eth_mac_send_frame(eth_mac_handle_t handle, const uint8_t *frame, uint32_t len)
670 {
671 RT_ASSERT(handle);
672 RT_ASSERT(frame);
673
674 return designware_eth_send(handle, frame, len);
675 }
676
677 /**
678 \brief Read data of received Ethernet frame.
679 \param[in] handle ethernet handle
680 \param[in] frame Pointer to frame buffer for data to read into
681 \param[in] len Frame buffer length in bytes
682 \return number of data bytes read or execution status
683 - value >= 0: number of data bytes read
684 - value < 0: error occurred, value is execution status as defined with execution_status
685 */
cvi_eth_mac_read_frame(eth_mac_handle_t handle,uint8_t * frame,uint32_t len)686 int32_t cvi_eth_mac_read_frame(eth_mac_handle_t handle, uint8_t *frame, uint32_t len)
687 {
688 RT_ASSERT(handle);
689 RT_ASSERT(frame);
690
691 uint8_t *packet = NULL;
692 int32_t actual_length;
693
694 actual_length = designware_eth_recv(handle, &packet);
695
696 if (actual_length < 0) {
697 return -1;
698 }
699
700 /* process received packet */
701 actual_length = (actual_length > len) ? len : actual_length;
702
703 if (packet != NULL) {
704 memcpy(frame, packet, actual_length);
705 }
706
707 designware_free_pkt(handle);
708
709 return actual_length;
710 }
711
712
713 /**
714 \brief This function is used to initialize Ethernet device and register an event callback.
715 \param[in] idx device id
716 \param[in] cb callback to handle ethernet event
717 \return return ethernet handle if success
718 */
cvi_eth_mac_init(rt_ubase_t base)719 eth_mac_handle_t cvi_eth_mac_init(rt_ubase_t base)
720 {
721 gmac_dev_t *mac_dev = &gmac_instance[0];
722 struct dw_gmac_priv *priv, *priv_unalign;
723
724 mac_dev->base = base;
725
726 priv = memalign(DW_GMAC_DMA_ALIGN, sizeof(struct dw_gmac_priv), (void **)&priv_unalign);
727 if (!priv)
728 {
729 rt_kprintf("malloc fail\n");
730 return NULL;
731 }
732
733 memset(priv_unalign, 0, sizeof(struct dw_gmac_priv) + DW_GMAC_DMA_ALIGN);
734
735 priv->mac_regs_p = (struct dw_gmac_mac_regs *)mac_dev->base;
736 priv->dma_regs_p = (struct dw_gmac_dma_regs *)(mac_dev->base + CVI_DW_DMA_BASE_OFFSET);
737
738 mac_dev->priv_unalign = priv_unalign;
739 mac_dev->priv = priv;
740
741 return (eth_mac_handle_t)mac_dev;
742 }
743
744 /**
745 \brief This function is used to de-initialize Ethernet device.
746 \param[in] handle ethernet handle
747 \return error code
748 */
de_eth_gmac_deinit(eth_mac_handle_t handle)749 void de_eth_gmac_deinit(eth_mac_handle_t handle)
750 {
751 RT_ASSERT(handle);
752 gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
753
754 if (mac_dev->priv_unalign)
755 {
756 rt_free(mac_dev->priv_unalign);
757 mac_dev->priv_unalign = RT_NULL;
758 }
759 }
760