1 /**
2   ******************************************************************************
3   * @file    bflb_emac.c
4   * @version V1.0
5   * @date    2022-09-27
6   * @brief   This file is the low hardware abstraction layer file
7   ******************************************************************************
8   * @attention
9   *
10   * <h2><center>&copy; COPYRIGHT(c) 2022 Bouffalo Lab</center></h2>
11   *
12   * Redistribution and use in source and binary forms, with or without modification,
13   * are permitted provided that the following conditions are met:
14   *   1. Redistributions of source code must retain the above copyright notice,
15   *      this list of conditions and the following disclaimer.
16   *   2. Redistributions in binary form must reproduce the above copyright notice,
17   *      this list of conditions and the following disclaimer in the documentation
18   *      and/or other materials provided with the distribution.
19   *   3. Neither the name of Bouffalo Lab nor the names of its contributors
20   *      may be used to endorse or promote products derived from this software
21   *      without specific prior written permission.
22   *
23   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33   *
34   ******************************************************************************
35   */
36 #include "bflb_emac.h"
37 #include "bflb_clock.h"
38 #include "bflb_l1c.h"
39 #include "hardware/emac_reg.h"
40 
41 /* private definition */
42 // #define TAG                   "EMAC_BD: "
43 #define EMAC_TX_COMMON_FLAGS (EMAC_BD_TX_RD_MASK | EMAC_BD_TX_IRQ_MASK | EMAC_BD_TX_PAD_MASK | EMAC_BD_TX_CRC_MASK | EMAC_BD_TX_EOF_MASK)
44 #define EMAC_RX_COMMON_FLAGS ((ETH_MAX_PACKET_SIZE << 16) | EMAC_BD_RX_IRQ_MASK)
45 
46 /**
47  *  @brief Note: Always write DWORD1 (buffer addr) first then DWORD0 for racing concern.
48  */
49 struct bflb_emac_bd_desc_s {
50     uint32_t C_S_L;  /*!< Buffer Descriptors(BD) control,status,length */
51     uint32_t Buffer; /*!< BD buffer address */
52 };
53 
54 /**
55  * @brief emac handle type definition
56  * @param bd             Tx descriptor header pointer
57  * @param tx_index_emac  TX index: EMAC
58  * @param tx_index_cpu   TX index: CPU/SW
59  * @param tx_buff_limit  TX index max
60  * @param rsv0           rsv0
61  * @param rx_index_emac  RX index: EMAC
62  * @param rx_index_cpu   RX index: CPU/SW
63  * @param rx_buff_limit  RX index max
64  * @param rsv1           rsv1
65  *
66  */
67 struct bflb_emac_handle_s {
68     struct bflb_emac_bd_desc_s *bd;
69     uint8_t tx_index_emac;
70     uint8_t tx_index_cpu;
71     uint8_t tx_buff_limit;
72     uint8_t rsv0;
73     uint8_t rx_index_emac;
74     uint8_t rx_index_cpu;
75     uint8_t rx_buff_limit;
76     uint8_t rsv1;
77 };
78 
79 static struct bflb_emac_handle_s eth_handle;
80 static struct bflb_emac_handle_s *thiz = NULL;
81 
82 /**
83  *
84  * @brief get emac current active buffer describe index
85  * @param dev
86  * @param bdt @ref emac buffer descriptors type define
87  * @return uint32_t
88  *
89  */
bflb_emac_bd_get_cur_active(struct bflb_device_s * dev,uint8_t bdt)90 uint32_t bflb_emac_bd_get_cur_active(struct bflb_device_s *dev, uint8_t bdt)
91 {
92     uint32_t bd = 0;
93     uint32_t reg_base;
94     reg_base = dev->reg_base;
95 
96     bd = getreg32(reg_base + EMAC_TX_BD_NUM_OFFSET);
97 
98     if (bdt == EMAC_BD_TYPE_TX) {
99         bd &= EMAC_TXBDPTR_MASK;
100         bd >>= EMAC_TXBDPTR_SHIFT;
101     }
102 
103     if (bdt == EMAC_BD_TYPE_RX) {
104         bd &= EMAC_RXBDPTR_MASK;
105         bd >>= EMAC_RXBDPTR_SHIFT;
106     }
107 
108     return bd;
109 }
110 /**
111  * @brief
112  *
113  * @param index
114  *
115  */
bflb_emac_bd_rx_enqueue(uint32_t index)116 void bflb_emac_bd_rx_enqueue(uint32_t index)
117 {
118     thiz->rx_index_emac = index;
119 }
120 
121 /**
122  * @brief
123  *
124  * @param index
125  *
126  */
bflb_emac_bd_rx_on_err(uint32_t index)127 void bflb_emac_bd_rx_on_err(uint32_t index)
128 {
129     /* handle error */
130     if (thiz->bd[index].C_S_L & EMAC_BD_RX_OR_MASK) {
131         printf("EMAC RX OR Error at %s:%d\r\n", __func__, __LINE__);
132     }
133 
134     if (thiz->bd[index].C_S_L & EMAC_BD_RX_RE_MASK) {
135         printf("MAC RX RE Error at %s:%d\r\n", __func__, __LINE__);
136     }
137 
138     if (thiz->bd[index].C_S_L & EMAC_BD_RX_DN_MASK) {
139         printf("MAC RX DN Error at %s:%d\r\n", __func__, __LINE__);
140     }
141 
142     if (thiz->bd[index].C_S_L & EMAC_BD_RX_TL_MASK) {
143         printf("MAC RX TL Error at %s:%d\r\n", __func__, __LINE__);
144     }
145 
146     if (thiz->bd[index].C_S_L & EMAC_BD_RX_CRC_MASK) {
147         printf("MAC RX CRC Error at %s:%d\r\n", __func__, __LINE__);
148     }
149 
150     if (thiz->bd[index].C_S_L & EMAC_BD_RX_LC_MASK) {
151         printf("MAC RX LC Error at %s:%d\r\n", __func__, __LINE__);
152     }
153 
154     thiz->bd[index].C_S_L &= ~0xff;
155     /* RX BD is ready for RX */
156     thiz->bd[index].C_S_L |= EMAC_BD_RX_E_MASK;
157 }
158 
159 /**
160  * @brief this func will be called in ISR
161  *
162  * @param index
163  *
164  */
bflb_emac_bd_tx_dequeue(uint32_t index)165 void bflb_emac_bd_tx_dequeue(uint32_t index)
166 {
167     struct bflb_emac_bd_desc_s *DMADesc;
168 
169     thiz->tx_index_emac = index;
170     DMADesc = &thiz->bd[thiz->tx_index_emac];
171     /* release this tx BD to SW (HW will do this) */
172     DMADesc->C_S_L &= ~EMAC_BD_TX_RD_MASK;
173 }
174 
175 /**
176  * @brief
177  *
178  * @param index
179  * @return int
180  */
bflb_emac_bd_tx_on_err(uint32_t index)181 void bflb_emac_bd_tx_on_err(uint32_t index)
182 {
183     /* handle error */
184     if (thiz->bd[index].C_S_L & EMAC_BD_TX_UR_MASK) {
185         printf("%s:%d\r\n", __func__, __LINE__);
186     }
187 
188     if (thiz->bd[index].C_S_L & EMAC_BD_TX_RTRY_MASK) {
189         printf("%s:%d\r\n", __func__, __LINE__);
190     }
191 
192     if (thiz->bd[index].C_S_L & EMAC_BD_TX_RL_MASK) {
193         printf("%s:%d\r\n", __func__, __LINE__);
194     }
195 
196     if (thiz->bd[index].C_S_L & EMAC_BD_TX_LC_MASK) {
197         printf("%s:%d\r\n", __func__, __LINE__);
198     }
199 
200     if (thiz->bd[index].C_S_L & EMAC_BD_TX_DF_MASK) {
201         printf("%s:%d\r\n", __func__, __LINE__);
202     }
203 
204     if (thiz->bd[index].C_S_L & EMAC_BD_TX_CS_MASK) {
205         printf("%s:%d\r\n", __func__, __LINE__);
206     }
207 
208     thiz->bd[index].C_S_L &= ~0xff;
209 }
210 /**
211  * @brief
212  *
213  * @param none
214  * @return int
215  */
emac_bd_fragment_support(void)216 int emac_bd_fragment_support(void)
217 {
218 #if defined(BL616) || defined(BL808)
219     return 1;
220 #elif defined(BL702)
221     return 0;
222 #elif defined(BL628)
223     return 1;
224 #endif
225 }
226 /**
227  * @brief
228  *
229  * @param flags
230  * @param len
231  * @param data_in
232  * @return int
233  */
bflb_emac_bd_tx_enqueue(uint32_t flags,uint32_t len,const uint8_t * data_in)234 int bflb_emac_bd_tx_enqueue(uint32_t flags, uint32_t len, const uint8_t *data_in)
235 {
236     uint32_t err = 0;
237     struct bflb_emac_bd_desc_s *DMADesc;
238     uint32_t tx_flags = EMAC_TX_COMMON_FLAGS;
239     DMADesc = &thiz->bd[thiz->tx_index_cpu];
240 
241     if (flags & EMAC_FRAGMENT_PACKET) {
242         /* Fragment packet, clear EOF */
243         tx_flags &= ~EMAC_BD_TX_EOF_MASK;
244     }
245 
246     if (DMADesc->C_S_L & EMAC_BD_TX_RD_MASK) {
247         /* no free BD, lost sync with DMA TX? */
248         err = 4;
249         //printf(TAG"%s:%d\n", __func__, __LINE__);
250     } else {
251 #if defined(BL616)
252         __ASM volatile("fence");
253 #endif
254         // printf("tx q flags:%d,len:%d,data:0x%x\r\n", flags, len, data_in);
255         if (flags & EMAC_NOCOPY_PACKET) {
256             DMADesc->Buffer = (uint32_t)(uintptr_t)data_in;
257         } else {
258             // memcpy((void *)(uintptr_t)(DMADesc->Buffer), data_in, len);
259             arch_memcpy_fast((void *)(uintptr_t)(DMADesc->Buffer), data_in, len);
260         }
261 
262 #ifdef EMAC_DO_FLUSH_DATA
263 #if defined(BL616)
264         bflb_l1c_dcache_invalidate_range((void *)DMADesc->Buffer, len);
265 #endif
266 #endif
267         DMADesc->C_S_L = tx_flags | (len << EMAC_BD_TX_LEN_SHIFT);
268 
269         /* move to next TX BD */
270         if ((++thiz->tx_index_cpu) > thiz->tx_buff_limit) {
271             /* the last BD */
272             DMADesc->C_S_L |= EMAC_BD_TX_WR_MASK;
273             /* wrap back */
274             thiz->tx_index_cpu = 0;
275         }
276     }
277 
278     return err;
279 }
280 
281 /**
282  * @brief
283  *
284  * @param flags
285  * @param len
286  * @param data_out
287  * @return int
288  */
bflb_emac_bd_rx_dequeue(uint32_t flags,uint32_t * len,uint8_t * data_out)289 int bflb_emac_bd_rx_dequeue(uint32_t flags, uint32_t *len, uint8_t *data_out)
290 {
291     uint32_t err = 0;
292     struct bflb_emac_bd_desc_s *DMADesc;
293 
294     DMADesc = &thiz->bd[thiz->rx_index_cpu];
295 
296     if (DMADesc->C_S_L & EMAC_BD_RX_E_MASK) {
297         /* current RX BD is empty */
298         err = 4;
299         *len = 0;
300     } else {
301         *len = (thiz->bd[thiz->rx_index_cpu].C_S_L & EMAC_BD_RX_LEN_MASK) >> EMAC_BD_RX_LEN_SHIFT;
302 #ifdef EMAC_DO_FLUSH_DATA
303 #if defined(BL616)
304         bflb_l1c_dcache_invalidate_range((void *)DMADesc->Buffer, *len);
305 #endif
306 #endif
307         if (data_out) {
308             // memcpy(data_out, (const void *)(uintptr_t)DMADesc->Buffer, *len);
309             arch_memcpy_fast(data_out, (const void *)(uintptr_t)DMADesc->Buffer, *len);
310         }
311 
312         /* RX BD can be used for another receive */
313         DMADesc->C_S_L |= EMAC_BD_RX_E_MASK;
314 
315         /* move to next RX BD */
316         if ((++thiz->rx_index_cpu) > thiz->rx_buff_limit) {
317             /* the last BD */
318             DMADesc->C_S_L |= EMAC_BD_RX_WR_MASK;
319             /* wrap back */
320             thiz->rx_index_cpu = thiz->tx_buff_limit + 1;
321         }
322     }
323 
324     return err;
325 }
326 
327 /**
328  * @brief bflb emac init
329  *
330  * @param dev
331  * @param config
332  *
333  */
bflb_emac_init(struct bflb_device_s * dev,const struct bflb_emac_config_s * config)334 void bflb_emac_init(struct bflb_device_s *dev, const struct bflb_emac_config_s *config)
335 {
336     uint32_t reg_base;
337     uint32_t reg_val;
338 
339 #if defined(BL616) || defined(BL808)
340 #define GLB_EMAC_CLK_OUT_ADDRESS (0x20000390)
341 #define GLB_UNGATE_CFG2_ADDRESS  (0x20000588)
342 
343     /* GLB select inside clock or Not */
344     reg_val = getreg32(GLB_EMAC_CLK_OUT_ADDRESS);
345     if (config->inside_clk == EMAC_CLK_USE_INTERNAL) {
346         reg_val |= (1 << 5);
347         reg_val |= (1 << 6);
348         reg_val &= ~(1 << 7);
349         reg_val |= (1 << 10);
350     } else {
351         reg_val &= ~(1 << 5);
352         reg_val &= ~(1 << 6);
353         reg_val &= ~(1 << 7);
354     }
355     putreg32(reg_val, GLB_EMAC_CLK_OUT_ADDRESS);
356 
357     /* ungate emac clock */
358     reg_val = getreg32(GLB_UNGATE_CFG2_ADDRESS);
359     reg_val |= (1 << 23);
360     putreg32(reg_val, GLB_UNGATE_CFG2_ADDRESS);
361 #elif defined(BL702)
362     /* enable audio clock and GLB select inside clock or Not */
363 // #define PDS_AUDIO_PLL_EN_ADDRESS (0x4000E41C)
364 #define GLB_UNGATE_CFG1_ADDRESS (0x40000024)
365 #define GLB_CLOCK_CFG3_ADDRESS  (0x4000000C)
366 
367     // reg_val = getreg32(PDS_AUDIO_PLL_EN_ADDRESS);
368     // reg_val |= (1 << 7);
369     // putreg32(reg_val, PDS_AUDIO_PLL_EN_ADDRESS);
370 
371     reg_val = getreg32(GLB_CLOCK_CFG3_ADDRESS);
372     if (config->inside_clk == EMAC_CLK_USE_INTERNAL) {
373         reg_val |= (1 << 5);
374     } else {
375         reg_val &= ~(1 << 5);
376     }
377     putreg32(reg_val, GLB_CLOCK_CFG3_ADDRESS);
378 
379     /* ungate emac clock */
380     reg_val = getreg32(GLB_UNGATE_CFG1_ADDRESS);
381     reg_val |= (1 << 0x0d);
382     putreg32(reg_val, GLB_UNGATE_CFG1_ADDRESS);
383 #endif
384 
385     reg_base = dev->reg_base;
386     /* set mac defualt config , enable rmii and other*/
387     reg_val = getreg32(reg_base + EMAC_MODE_OFFSET);
388     reg_val |= (EMAC_RMII_EN);
389     reg_val |= (EMAC_PRO);
390     reg_val |= (EMAC_BRO);
391     reg_val &= ~(EMAC_NOPRE);
392     reg_val |= (EMAC_PAD);
393     reg_val |= (EMAC_CRCEN);
394     reg_val &= ~(EMAC_HUGEN);
395     reg_val |= (EMAC_RECSMALL);
396     reg_val |= (EMAC_IFG);
397     putreg32(reg_val, reg_base + EMAC_MODE_OFFSET);
398 
399     /* set inter frame gap defualt value */
400     reg_val = getreg32(reg_base + EMAC_IPGT_OFFSET);
401     reg_val &= ~(EMAC_IPGT_MASK);
402     reg_val |= (0x18) << EMAC_IPGT_SHIFT;
403     putreg32(reg_val, reg_base + EMAC_IPGT_OFFSET);
404 
405     /* set MII interface */
406     reg_val = getreg32(reg_base + EMAC_MIIMODE_OFFSET);
407     reg_val |= EMAC_MIINOPRE;
408     reg_val &= ~(EMAC_CLKDIV_MASK);
409     reg_val |= (config->mii_clk_div) << EMAC_CLKDIV_SHIFT;
410     putreg32(reg_val, reg_base + EMAC_MIIMODE_OFFSET);
411 
412     /* set collision */
413     reg_val = getreg32(reg_base + EMAC_COLLCONFIG_OFFSET);
414     reg_val &= ~(EMAC_MAXFL_MASK | EMAC_COLLVALID_MASK);
415     reg_val |= (0xf) << EMAC_MAXFL_SHIFT;
416     reg_val |= (0x10) << EMAC_COLLVALID_SHIFT;
417     putreg32(reg_val, reg_base + EMAC_COLLCONFIG_OFFSET);
418 
419     /* set frame length */
420     reg_val = getreg32(reg_base + EMAC_PACKETLEN_OFFSET);
421     reg_val &= ~(EMAC_MINFL_MASK | EMAC_MAXFL_MASK);
422     reg_val |= (config->min_frame_len) << EMAC_MINFL_SHIFT;
423     reg_val |= (config->max_frame_len) << EMAC_MAXFL_SHIFT;
424     putreg32(reg_val, reg_base + EMAC_PACKETLEN_OFFSET);
425 
426     /* set emac address */
427     reg_val = getreg32(reg_base + EMAC_MAC_ADDR0_OFFSET);
428     reg_val &= ~(EMAC_MAC_B2_MASK | EMAC_MAC_B3_MASK | EMAC_MAC_B4_MASK | EMAC_MAC_B5_MASK);
429     reg_val |= (config->mac_addr[5]) << EMAC_MAC_B5_SHIFT;
430     reg_val |= (config->mac_addr[4]) << EMAC_MAC_B4_SHIFT;
431     reg_val |= (config->mac_addr[3]) << EMAC_MAC_B3_SHIFT;
432     reg_val |= (config->mac_addr[2]) << EMAC_MAC_B2_SHIFT;
433     putreg32(reg_val, reg_base + EMAC_MAC_ADDR0_OFFSET);
434     reg_val = getreg32(reg_base + EMAC_MAC_ADDR1_OFFSET);
435     reg_val &= ~(EMAC_MAC_B0_MASK | EMAC_MAC_B1_MASK);
436     reg_val |= (config->mac_addr[1]) << EMAC_MAC_B1_SHIFT;
437     reg_val |= (config->mac_addr[0]) << EMAC_MAC_B0_SHIFT;
438     putreg32(reg_val, reg_base + EMAC_MAC_ADDR1_OFFSET);
439 }
440 
441 /**
442  * @brief bflb emac deinit
443  *
444  * @param dev
445  *
446  */
bflb_emac_deinit(struct bflb_device_s * dev)447 void bflb_emac_deinit(struct bflb_device_s *dev)
448 {
449     uint32_t reg_base;
450     uint32_t reg_val;
451 
452     reg_base = dev->reg_base;
453 
454     reg_val = getreg32(reg_base + EMAC_MODE_OFFSET);
455     reg_val &= ~(EMAC_TX_EN | EMAC_RX_EN);
456     putreg32(reg_val, reg_base + EMAC_MODE_OFFSET);
457 }
458 
459 /**
460  * @brief bflb emac interrupt enable
461  *
462  * @param dev
463  * @param flag
464  * @param enable
465  *
466  */
bflb_emac_int_enable(struct bflb_device_s * dev,uint32_t flag,bool enable)467 void bflb_emac_int_enable(struct bflb_device_s *dev, uint32_t flag, bool enable)
468 {
469     uint32_t reg_base;
470     uint32_t reg_val_mask; // reg_val_en;
471 
472     reg_base = dev->reg_base;
473     reg_val_mask = getreg32(reg_base + EMAC_INT_MASK_OFFSET);
474     if (enable) {
475         reg_val_mask &= ~(flag);
476     } else {
477         reg_val_mask |= (flag);
478     }
479     putreg32(reg_val_mask, reg_base + EMAC_INT_MASK_OFFSET);
480 };
481 
482 /**
483  * @brief bflb emac interrupt clear
484  *
485  * @param dev
486  * @param flag
487  *
488  */
bflb_emac_int_clear(struct bflb_device_s * dev,uint32_t flag)489 void bflb_emac_int_clear(struct bflb_device_s *dev, uint32_t flag)
490 {
491     putreg32(flag, dev->reg_base + EMAC_INT_SOURCE_OFFSET);
492 }
493 
494 /**
495  * @brief bflb emac get interrupt status
496  *
497  * @param dev
498  * @return uint32_t
499  */
bflb_emac_get_int_status(struct bflb_device_s * dev)500 uint32_t bflb_emac_get_int_status(struct bflb_device_s *dev)
501 {
502     uint32_t reg_base;
503     uint32_t reg_sts_val, reg_mask_val;
504 
505     reg_base = dev->reg_base;
506     reg_sts_val = getreg32(reg_base + EMAC_INT_SOURCE_OFFSET);
507     reg_mask_val = getreg32(reg_base + EMAC_INT_MASK_OFFSET);
508 
509     return (reg_sts_val & (~reg_mask_val));
510 }
511 
512 /**
513  * @brief emac dma description list init
514  *
515  * @param reg_base
516  * @param handle
517  * @param tx_buff
518  * @param tx_buff_cnt
519  * @param rx_buff
520  * @param rx_buff_cnt
521  *
522  */
emac_dma_desc_list_init(uint32_t reg_base,struct bflb_emac_handle_s * handle,uint8_t * tx_buff,uint32_t tx_buff_cnt,uint8_t * rx_buff,uint32_t rx_buff_cnt)523 static void emac_dma_desc_list_init(uint32_t reg_base, struct bflb_emac_handle_s *handle, uint8_t *tx_buff, uint32_t tx_buff_cnt, uint8_t *rx_buff, uint32_t rx_buff_cnt)
524 {
525     uint32_t i = 0;
526 
527     /* Set the Ethernet handler env */
528     handle->bd = (struct bflb_emac_bd_desc_s *)(uintptr_t)(reg_base + EMAC_DMA_DESC_OFFSET);
529     handle->tx_index_emac = 0;
530     handle->tx_index_cpu = 0;
531     handle->tx_buff_limit = tx_buff_cnt - 1;
532     /* The receive descriptors' address starts right after the last transmit BD. */
533     handle->rx_index_emac = tx_buff_cnt;
534     handle->rx_index_cpu = tx_buff_cnt;
535     handle->rx_buff_limit = tx_buff_cnt + rx_buff_cnt - 1;
536 
537     /* Fill each DMARxDesc descriptor with the right values */
538     for (i = 0; i < tx_buff_cnt; i++) {
539         /* Get the pointer on the ith member of the Tx Desc list */
540         handle->bd[i].Buffer = (NULL == tx_buff) ? 0 : (uint32_t)(uintptr_t)(tx_buff + (ETH_MAX_PACKET_SIZE * i));
541         handle->bd[i].C_S_L = 0;
542     }
543 
544     /* For the last TX DMA Descriptor, it should be wrap back */
545     handle->bd[handle->tx_buff_limit].C_S_L |= EMAC_BD_TX_WR_MASK;
546 
547     for (i = tx_buff_cnt; i < (tx_buff_cnt + rx_buff_cnt); i++) {
548         /* Get the pointer on the ith member of the Rx Desc list */
549         handle->bd[i].Buffer = (NULL == rx_buff) ? 0 : (uint32_t)(uintptr_t)(rx_buff + (ETH_MAX_PACKET_SIZE * (i - tx_buff_cnt)));
550         handle->bd[i].C_S_L = (ETH_MAX_PACKET_SIZE << 16) | EMAC_BD_RX_IRQ_MASK | EMAC_BD_RX_E_MASK;
551     }
552 
553     /* For the last RX DMA Descriptor, it should be wrap back */
554     handle->bd[handle->rx_buff_limit].C_S_L |= EMAC_BD_RX_WR_MASK;
555 
556     /* For the TX DMA Descriptor, it will wrap to 0 according to EMAC_TX_BD_NUM*/
557     putreg32(tx_buff_cnt, reg_base + EMAC_TX_BD_NUM_OFFSET);
558 }
559 
560 /**
561  * @brief emac buffer description init
562  *
563  * @param eth_tx_buff
564  * @param tx_buf_count
565  * @param eth_rx_buff
566  * @param rx_buf_count
567  *
568  */
bflb_emac_bd_init(struct bflb_device_s * dev,uint8_t * eth_tx_buff,uint8_t tx_buf_count,uint8_t * eth_rx_buff,uint8_t rx_buf_count)569 void bflb_emac_bd_init(struct bflb_device_s *dev, uint8_t *eth_tx_buff, uint8_t tx_buf_count, uint8_t *eth_rx_buff, uint8_t rx_buf_count)
570 {
571     thiz = &eth_handle;
572     uint32_t reg_base;
573     reg_base = dev->reg_base;
574     /* init the BDs in emac with buffer address */
575     emac_dma_desc_list_init(reg_base, thiz, (uint8_t *)eth_tx_buff, tx_buf_count, (uint8_t *)eth_rx_buff, rx_buf_count);
576 }
577 
578 /**
579  * @brief bflb emac phy register read
580  *
581  * @param dev
582  * @param phy_reg
583  * @param phy_reg_val
584  * @return int
585  *
586  */
bflb_emac_phy_reg_read(struct bflb_device_s * dev,uint16_t phy_reg,uint16_t * phy_reg_val)587 int bflb_emac_phy_reg_read(struct bflb_device_s *dev, uint16_t phy_reg, uint16_t *phy_reg_val)
588 {
589     uint32_t reg_val;
590 
591     /* Set Register Address */
592     reg_val = getreg32(dev->reg_base + EMAC_MIIADDRESS_OFFSET);
593     reg_val &= ~(EMAC_RGAD_MASK);
594     reg_val |= ((uint32_t)phy_reg << EMAC_RGAD_SHIFT);
595     putreg32(reg_val, dev->reg_base + EMAC_MIIADDRESS_OFFSET);
596 
597     /* Trigger read */
598     reg_val = getreg32(dev->reg_base + EMAC_MIICOMMAND_OFFSET);
599     reg_val |= (EMAC_RSTAT);
600     putreg32(reg_val, dev->reg_base + EMAC_MIICOMMAND_OFFSET);
601 
602     __ASM volatile("nop");
603     __ASM volatile("nop");
604     __ASM volatile("nop");
605     __ASM volatile("nop");
606 
607     do {
608         reg_val = getreg32(dev->reg_base + EMAC_MIISTATUS_OFFSET);
609         bflb_mtimer_delay_us(16);
610     } while ((reg_val & (EMAC_MIIM_BUSY)) != 0);
611 
612     *phy_reg_val = getreg32(dev->reg_base + EMAC_MIIRX_DATA_OFFSET);
613 
614     return 0;
615 }
616 
617 /**
618  * @brief bflb emac phy register write
619  *
620  * @param dev
621  * @param phy_reg
622  * @param phy_reg_val
623  * @return int
624  *
625  */
bflb_emac_phy_reg_write(struct bflb_device_s * dev,uint16_t phy_reg,uint16_t phy_reg_val)626 int bflb_emac_phy_reg_write(struct bflb_device_s *dev, uint16_t phy_reg, uint16_t phy_reg_val)
627 {
628     uint32_t reg_val;
629 
630     /* Set Register Address */
631     reg_val = getreg32(dev->reg_base + EMAC_MIIADDRESS_OFFSET);
632     reg_val &= ~(EMAC_RGAD_MASK);
633     reg_val |= ((uint32_t)phy_reg << EMAC_RGAD_SHIFT);
634     putreg32(reg_val, dev->reg_base + EMAC_MIIADDRESS_OFFSET);
635 
636     /* Set Write data */
637     putreg32(phy_reg_val, dev->reg_base + EMAC_MIITX_DATA_OFFSET);
638 
639     /* Trigger write */
640     reg_val = getreg32(dev->reg_base + EMAC_MIICOMMAND_OFFSET);
641     reg_val |= (EMAC_WCTRLDATA);
642     putreg32(reg_val, dev->reg_base + EMAC_MIICOMMAND_OFFSET);
643 
644     __ASM volatile("nop");
645     __ASM volatile("nop");
646     __ASM volatile("nop");
647     __ASM volatile("nop");
648 
649     do {
650         reg_val = getreg32(dev->reg_base + EMAC_MIISTATUS_OFFSET);
651         bflb_mtimer_delay_us(16);
652     } while ((reg_val & (EMAC_MIIM_BUSY)) != 0);
653 
654     return 0;
655 }
656 
657 /**
658  * @brief bflb emac feature control
659  *
660  * @param dev
661  * @param cmd
662  * @param arg
663  * @return int
664  *
665  */
bflb_emac_feature_control(struct bflb_device_s * dev,int cmd,size_t arg)666 int bflb_emac_feature_control(struct bflb_device_s *dev, int cmd, size_t arg)
667 {
668     int ret = 0;
669     uint32_t reg_val;
670     uint32_t reg_base;
671 
672     reg_base = dev->reg_base;
673     switch (cmd) {
674         case EMAC_CMD_NO_PREAMBLE_MODE:
675             reg_val = getreg32(reg_base + EMAC_MODE_OFFSET);
676             if (arg) {
677                 reg_val |= EMAC_NOPRE;
678             } else {
679                 reg_val &= ~(EMAC_NOPRE);
680             }
681             putreg32(reg_val, reg_base + EMAC_MODE_OFFSET);
682             break;
683 
684         case EMAC_CMD_EN_PROMISCUOUS:
685             reg_val = getreg32(reg_base + EMAC_MODE_OFFSET);
686             if (arg) {
687                 reg_val |= EMAC_PRO;
688             } else {
689                 reg_val &= ~(EMAC_PRO);
690             }
691             putreg32(reg_val, reg_base + EMAC_MODE_OFFSET);
692             break;
693 
694         case EMAC_CMD_FRAME_GAP_CHECK:
695             reg_val = getreg32(reg_base + EMAC_MODE_OFFSET);
696             if (arg) {
697                 reg_val |= EMAC_IFG;
698             } else {
699                 reg_val &= ~(EMAC_IFG);
700             }
701             putreg32(reg_val, reg_base + EMAC_MODE_OFFSET);
702             break;
703 
704         case EMAC_CMD_FULL_DUPLEX:
705             reg_val = getreg32(reg_base + EMAC_MODE_OFFSET);
706             if (arg) {
707                 reg_val |= EMAC_FULLD;
708             } else {
709                 reg_val &= ~(EMAC_FULLD);
710             }
711             putreg32(reg_val, reg_base + EMAC_MODE_OFFSET);
712             break;
713 
714         case EMAC_CMD_EN_TX_CRC_FIELD:
715             reg_val = getreg32(reg_base + EMAC_MODE_OFFSET);
716             if (arg) {
717                 reg_val |= EMAC_CRCEN;
718             } else {
719                 reg_val &= ~(EMAC_CRCEN);
720             }
721             putreg32(reg_val, reg_base + EMAC_MODE_OFFSET);
722             break;
723 
724         case EMAC_CMD_RECV_HUGE_FRAMES:
725             reg_val = getreg32(reg_base + EMAC_MODE_OFFSET);
726             if (arg) {
727                 reg_val |= EMAC_HUGEN;
728             } else {
729                 reg_val &= ~(EMAC_HUGEN);
730             }
731             putreg32(reg_val, reg_base + EMAC_MODE_OFFSET);
732             break;
733 
734         case EMAC_CMD_EN_AUTO_PADDING:
735             reg_val = getreg32(reg_base + EMAC_MODE_OFFSET);
736             if (arg) {
737                 reg_val |= EMAC_PAD;
738             } else {
739                 reg_val &= ~(EMAC_PAD);
740             }
741             putreg32(reg_val, reg_base + EMAC_MODE_OFFSET);
742             break;
743 
744         case EMAC_CMD_RECV_SMALL_FRAME:
745             reg_val = getreg32(reg_base + EMAC_MODE_OFFSET);
746             if (arg) {
747                 reg_val |= EMAC_RECSMALL;
748             } else {
749                 reg_val &= ~(EMAC_RECSMALL);
750             }
751             putreg32(reg_val, reg_base + EMAC_MODE_OFFSET);
752             break;
753 
754         case EMAC_CMD_SET_PHY_ADDRESS:
755             reg_val = getreg32(reg_base + EMAC_MIIADDRESS_OFFSET);
756             reg_val &= ~(EMAC_FIAD_MASK);
757             reg_val |= (uint32_t)(arg << EMAC_FIAD_SHIFT);
758             putreg32(reg_val, reg_base + EMAC_MIIADDRESS_OFFSET);
759             break;
760 
761         case EMAC_CMD_SET_MAXRET:
762             reg_val = getreg32(reg_base + EMAC_COLLCONFIG_OFFSET);
763             reg_val &= ~(EMAC_MAXFL_MASK);
764             reg_val |= (arg) << EMAC_MAXFL_SHIFT;
765             putreg32(reg_val, reg_base + EMAC_COLLCONFIG_OFFSET);
766             break;
767 
768         case EMAC_CMD_SET_COLLVALID:
769             reg_val = getreg32(reg_base + EMAC_COLLCONFIG_OFFSET);
770             reg_val &= ~(EMAC_COLLVALID_MASK);
771             reg_val |= (arg) << EMAC_COLLVALID_SHIFT;
772             putreg32(reg_val, reg_base + EMAC_COLLCONFIG_OFFSET);
773             break;
774 
775         case EMAC_CMD_SET_PACKET_GAP:
776             reg_val = getreg32(reg_base + EMAC_IPGT_OFFSET);
777             reg_val &= ~(EMAC_IPGT_MASK);
778             reg_val |= (arg) << EMAC_IPGT_SHIFT;
779             putreg32(reg_val, reg_base + EMAC_IPGT_OFFSET);
780             break;
781 
782         default:
783             ret = -EPERM;
784             break;
785     }
786     return ret;
787 }
788 
789 /**
790  * @brief bflb emac stop
791  *
792  * @param dev
793  *
794  */
bflb_emac_stop(struct bflb_device_s * dev)795 void bflb_emac_stop(struct bflb_device_s *dev)
796 {
797     /* disable emac */
798     uint32_t reg_val;
799 
800     reg_val = getreg32(dev->reg_base + EMAC_MODE_OFFSET);
801     reg_val &= ~(EMAC_TX_EN | EMAC_RX_EN);
802     putreg32(reg_val, dev->reg_base + EMAC_MODE_OFFSET);
803 }
804 
805 /**
806  * @brief bflb emac start
807  *
808  * @param dev
809  *
810  */
bflb_emac_start(struct bflb_device_s * dev)811 void bflb_emac_start(struct bflb_device_s *dev)
812 {
813     /* enable emac */
814     uint32_t reg_val;
815 
816     reg_val = getreg32(dev->reg_base + EMAC_MODE_OFFSET);
817     reg_val |= (EMAC_TX_EN | EMAC_RX_EN);
818     putreg32(reg_val, dev->reg_base + EMAC_MODE_OFFSET);
819 }
820 
821 /**
822  * @brief bflb emac start tx
823  *
824  * @param dev
825  *
826  */
bflb_emac_start_tx(struct bflb_device_s * dev)827 void bflb_emac_start_tx(struct bflb_device_s *dev)
828 {
829     uint32_t reg_val;
830 
831     reg_val = getreg32(dev->reg_base + EMAC_MODE_OFFSET);
832     reg_val |= (EMAC_TX_EN);
833     putreg32(reg_val, dev->reg_base + EMAC_MODE_OFFSET);
834 }
835 
836 /**
837  * @brief bflb emac stop tx
838  *
839  * @param dev
840  *
841  */
bflb_emac_stop_tx(struct bflb_device_s * dev)842 void bflb_emac_stop_tx(struct bflb_device_s *dev)
843 {
844     uint32_t reg_val;
845 
846     reg_val = getreg32(dev->reg_base + EMAC_MODE_OFFSET);
847     reg_val &= ~(EMAC_TX_EN);
848     putreg32(reg_val, dev->reg_base + EMAC_MODE_OFFSET);
849 }
850 
851 /**
852  * @brief bflb emac start rx
853  *
854  * @param dev
855  *
856  */
bflb_emac_start_rx(struct bflb_device_s * dev)857 void bflb_emac_start_rx(struct bflb_device_s *dev)
858 {
859     uint32_t reg_val;
860 
861     reg_val = getreg32(dev->reg_base + EMAC_MODE_OFFSET);
862     reg_val |= (EMAC_RX_EN);
863     putreg32(reg_val, dev->reg_base + EMAC_MODE_OFFSET);
864 }
865 
866 /**
867  * @brief bflb emac stop rx
868  *
869  * @param dev
870  *
871  */
bflb_emac_stop_rx(struct bflb_device_s * dev)872 void bflb_emac_stop_rx(struct bflb_device_s *dev)
873 {
874     uint32_t reg_val;
875 
876     reg_val = getreg32(dev->reg_base + EMAC_MODE_OFFSET);
877     reg_val &= ~(EMAC_RX_EN);
878     putreg32(reg_val, dev->reg_base + EMAC_MODE_OFFSET);
879 }
880