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