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>© 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 = ð_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