| M480 BSP V3.05.001 The Board Support Package for M480 Series

emac.c
Go to the documentation of this file.
1 /**************************************************************************/
9 #include <stdio.h>
10 #include <string.h>
11 #include "NuMicro.h"
12
13
23 /* Below are structure, definitions, static variables used locally by EMAC driver and does not want to parse by doxygen unless HIDDEN_SYMBOLS is defined */
30 /* PHY Register Description */
31 #define PHY_CNTL_REG 0x00UL
32 #define PHY_STATUS_REG 0x01UL
33 #define PHY_ID1_REG 0x02UL
34 #define PHY_ID2_REG 0x03UL
35 #define PHY_ANA_REG 0x04UL
36 #define PHY_ANLPA_REG 0x05UL
37 #define PHY_ANE_REG 0x06UL
39 /* PHY Control Register */
40 #define PHY_CNTL_RESET_PHY (1UL << 15UL)
41 #define PHY_CNTL_DR_100MB (1UL << 13UL)
42 #define PHY_CNTL_ENABLE_AN (1UL << 12UL)
43 #define PHY_CNTL_POWER_DOWN (1UL << 11UL)
44 #define PHY_CNTL_RESTART_AN (1UL << 9UL)
45 #define PHY_CNTL_FULLDUPLEX (1UL << 8UL)
46
47 /* PHY Status Register */
48 #define PHY_STATUS_AN_COMPLETE (1UL << 5UL)
49 #define PHY_STATUS_LINK_VALID (1UL << 2UL)
50
51 /* PHY Auto-negotiation Advertisement Register */
52 #define PHY_ANA_DR100_TX_FULL (1UL << 8UL)
53 #define PHY_ANA_DR100_TX_HALF (1UL << 7UL)
54 #define PHY_ANA_DR10_TX_FULL (1UL << 6UL)
55 #define PHY_ANA_DR10_TX_HALF (1UL << 5UL)
56 #define PHY_ANA_IEEE_802_3_CSMA_CD (1UL << 0UL)
57
58 /* PHY Auto-negotiation Link Partner Advertisement Register */
59 #define PHY_ANLPA_DR100_TX_FULL (1UL << 8UL)
60 #define PHY_ANLPA_DR100_TX_HALF (1UL << 7UL)
61 #define PHY_ANLPA_DR10_TX_FULL (1UL << 6UL)
62 #define PHY_ANLPA_DR10_TX_HALF (1UL << 5UL)
63
64 /* EMAC Tx/Rx descriptor's owner bit */
65 #define EMAC_DESC_OWN_EMAC 0x80000000UL
66 #define EMAC_DESC_OWN_CPU 0x00000000UL
68 /* Rx Frame Descriptor Status */
69 #define EMAC_RXFD_RTSAS 0x0080UL
70 #define EMAC_RXFD_RP 0x0040UL
71 #define EMAC_RXFD_ALIE 0x0020UL
72 #define EMAC_RXFD_RXGD 0x0010UL
73 #define EMAC_RXFD_PTLE 0x0008UL
74 #define EMAC_RXFD_CRCE 0x0002UL
75 #define EMAC_RXFD_RXINTR 0x0001UL
77 /* Tx Frame Descriptor's Control bits */
78 #define EMAC_TXFD_TTSEN 0x08UL
79 #define EMAC_TXFD_INTEN 0x04UL
80 #define EMAC_TXFD_CRCAPP 0x02UL
81 #define EMAC_TXFD_PADEN 0x01UL
83 /* Tx Frame Descriptor Status */
84 #define EMAC_TXFD_TXINTR 0x0001UL
85 #define EMAC_TXFD_DEF 0x0002UL
86 #define EMAC_TXFD_TXCP 0x0008UL
87 #define EMAC_TXFD_EXDEF 0x0010UL
88 #define EMAC_TXFD_NCS 0x0020UL
89 #define EMAC_TXFD_TXABT 0x0040UL
90 #define EMAC_TXFD_LC 0x0080UL
91 #define EMAC_TXFD_TXHA 0x0100UL
92 #define EMAC_TXFD_PAU 0x0200UL
93 #define EMAC_TXFD_SQE 0x0400UL
94 #define EMAC_TXFD_TTSAS 0x0800UL
96 /* end of group EMAC_EXPORTED_CONSTANTS */
97
103 typedef struct
104 {
105 uint32_t u32Status1;
106 uint32_t u32Data;
107 uint32_t u32Status2;
108 uint32_t u32Next;
109 uint32_t u32Backup1;
110 uint32_t u32Backup2;
111 } EMAC_DESCRIPTOR_T;
112
114 typedef struct
115 {
116 uint8_t au8Buf[EMAC_MAX_PKT_SIZE];
117 } EMAC_FRAME_T;
118 /* end of group EMAC_EXPORTED_TYPEDEF */
120
121 /* local variables */
122 static volatile EMAC_DESCRIPTOR_T rx_desc[EMAC_RX_DESC_SIZE];
123 static volatile EMAC_FRAME_T rx_buf[EMAC_RX_DESC_SIZE];
124 static volatile EMAC_DESCRIPTOR_T tx_desc[EMAC_TX_DESC_SIZE];
125 static volatile EMAC_FRAME_T tx_buf[EMAC_TX_DESC_SIZE];
126
127
128 static uint32_t u32CurrentTxDesc, u32NextTxDesc, u32CurrentRxDesc;
129 static uint32_t s_u32EnableTs = 0UL;
130
131 static void EMAC_MdioWrite(uint32_t u32Reg, uint32_t u32Addr, uint32_t u32Data);
132 static uint32_t EMAC_MdioRead(uint32_t u32Reg, uint32_t u32Addr);
133 static void EMAC_TxDescInit(void);
134 static void EMAC_RxDescInit(void);
135 static uint32_t EMAC_Subsec2Nsec(uint32_t subsec);
136 static uint32_t EMAC_Nsec2Subsec(uint32_t nsec);
137
150 static void EMAC_MdioWrite(uint32_t u32Reg, uint32_t u32Addr, uint32_t u32Data)
151 {
152 /* Set data register */
153 EMAC->MIIMDAT = u32Data ;
154 /* Set PHY address, PHY register address, busy bit and write bit */
155 EMAC->MIIMCTL = u32Reg | (u32Addr << 8) | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_WRITE_Msk | EMAC_MIIMCTL_MDCON_Msk;
156
157 /* Wait write complete by polling busy bit. */
158 while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk)
159 {
160 ;
161 }
162
163 }
164
171 static uint32_t EMAC_MdioRead(uint32_t u32Reg, uint32_t u32Addr)
172 {
173 /* Set PHY address, PHY register address, busy bit */
174 EMAC->MIIMCTL = u32Reg | (u32Addr << EMAC_MIIMCTL_PHYADDR_Pos) | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk;
175
176 /* Wait read complete by polling busy bit */
177 while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk)
178 {
179 ;
180 }
181
182 /* Get return data */
183 return EMAC->MIIMDAT;
184 }
185
191 void EMAC_PhyInit(void)
192 {
193 uint32_t reg;
194 uint32_t i = 0UL;
195
196 /* Reset Phy Chip */
197 EMAC_MdioWrite(PHY_CNTL_REG, EMAC_PHY_ADDR, PHY_CNTL_RESET_PHY);
198
199 /* Wait until reset complete */
200 while (1)
201 {
202 reg = EMAC_MdioRead(PHY_CNTL_REG, EMAC_PHY_ADDR) ;
203
204 if ((reg & PHY_CNTL_RESET_PHY) == 0UL)
205 {
206 break;
207 }
208 }
209
210 while (!(EMAC_MdioRead(PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_LINK_VALID))
211 {
212 if (i++ > 80000UL) /* Cable not connected */
213 {
214 EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk;
215 EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk;
216 break;
217 }
218 }
219
220 if (i <= 80000UL)
221 {
222 /* Configure auto negotiation capability */
223 EMAC_MdioWrite(PHY_ANA_REG, EMAC_PHY_ADDR, PHY_ANA_DR100_TX_FULL |
224 PHY_ANA_DR100_TX_HALF |
225 PHY_ANA_DR10_TX_FULL |
226 PHY_ANA_DR10_TX_HALF |
227 PHY_ANA_IEEE_802_3_CSMA_CD);
228 /* Restart auto negotiation */
229 EMAC_MdioWrite(PHY_CNTL_REG, EMAC_PHY_ADDR, EMAC_MdioRead(PHY_CNTL_REG, EMAC_PHY_ADDR) | PHY_CNTL_RESTART_AN);
230
231 /* Wait for auto-negotiation complete */
232 while (!(EMAC_MdioRead(PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_AN_COMPLETE))
233 {
234 ;
235 }
236
237 /* Check link valid again. Some PHYs needs to check result after link valid bit set */
238 while (!(EMAC_MdioRead(PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_LINK_VALID))
239 {
240 ;
241 }
242
243 /* Check link partner capability */
244 reg = EMAC_MdioRead(PHY_ANLPA_REG, EMAC_PHY_ADDR) ;
245
246 if (reg & PHY_ANLPA_DR100_TX_FULL)
247 {
248 EMAC->CTL |= EMAC_CTL_OPMODE_Msk;
249 EMAC->CTL |= EMAC_CTL_FUDUP_Msk;
250 }
251 else if (reg & PHY_ANLPA_DR100_TX_HALF)
252 {
253 EMAC->CTL |= EMAC_CTL_OPMODE_Msk;
254 EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk;
255 }
256 else if (reg & PHY_ANLPA_DR10_TX_FULL)
257 {
258 EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk;
259 EMAC->CTL |= EMAC_CTL_FUDUP_Msk;
260 }
261 else
262 {
263 EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk;
264 EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk;
265 }
266 }
267 }
268
274 static void EMAC_TxDescInit(void)
275 {
276 uint32_t i;
277
278 /* Get Frame descriptor's base address. */
279 EMAC->TXDSA = (uint32_t)&tx_desc[0];
280 u32NextTxDesc = u32CurrentTxDesc = (uint32_t)&tx_desc[0];
281
282 for (i = 0UL; i < EMAC_TX_DESC_SIZE; i++)
283 {
284
285 if (s_u32EnableTs)
286 {
287 tx_desc[i].u32Status1 = EMAC_TXFD_PADEN | EMAC_TXFD_CRCAPP | EMAC_TXFD_INTEN;
288 }
289 else
290 {
291 tx_desc[i].u32Status1 = EMAC_TXFD_PADEN | EMAC_TXFD_CRCAPP | EMAC_TXFD_INTEN | EMAC_TXFD_TTSEN;
292 }
293
294 tx_desc[i].u32Data = (uint32_t)((uint32_t)&tx_buf[i]);
295 tx_desc[i].u32Backup1 = tx_desc[i].u32Data;
296 tx_desc[i].u32Status2 = 0UL;
297 tx_desc[i].u32Next = (uint32_t)&tx_desc[(i + 1UL) % EMAC_TX_DESC_SIZE];
298 tx_desc[i].u32Backup2 = tx_desc[i].u32Next;
299
300 }
301
302 }
303
304
310 static void EMAC_RxDescInit(void)
311 {
312
313 uint32_t i;
314
315 /* Get Frame descriptor's base address. */
316 EMAC->RXDSA = (uint32_t)&rx_desc[0];
317 u32CurrentRxDesc = (uint32_t)&rx_desc[0];
318
319 for (i = 0UL; i < EMAC_RX_DESC_SIZE; i++)
320 {
321 rx_desc[i].u32Status1 = EMAC_DESC_OWN_EMAC;
322 rx_desc[i].u32Data = (uint32_t)((uint32_t)&rx_buf[i]);
323 rx_desc[i].u32Backup1 = rx_desc[i].u32Data;
324 rx_desc[i].u32Status2 = 0UL;
325 rx_desc[i].u32Next = (uint32_t)&rx_desc[(i + 1UL) % EMAC_RX_DESC_SIZE];
326 rx_desc[i].u32Backup2 = rx_desc[i].u32Next;
327 }
328
329 }
330
336 static uint32_t EMAC_Subsec2Nsec(uint32_t subsec)
337 {
338 /* 2^31 subsec == 10^9 ns */
339 uint64_t i;
340 i = 1000000000ull * (uint64_t)subsec;
341 i >>= 31;
342 return ((uint32_t)i);
343 }
344
350 static uint32_t EMAC_Nsec2Subsec(uint32_t nsec)
351 {
352 /* 10^9 ns = 2^31 subsec */
353 uint64_t i;
354 i = (1ull << 31) * nsec;
355 i /= 1000000000ull;
356 return ((uint32_t)i);
357 }
358
359 /* end of group EMAC_EXPORTED_FUNCTIONS */
361
362
363
381 void EMAC_Open(uint8_t *pu8MacAddr)
382 {
383 /* Enable transmit and receive descriptor */
384 EMAC_TxDescInit();
385 EMAC_RxDescInit();
386
387 /* Set the CAM Control register and the MAC address value */
388 EMAC_SetMacAddr(pu8MacAddr);
389
390 /* Configure the MAC interrupt enable register. */
391 EMAC->INTEN = EMAC_INTEN_RXIEN_Msk |
392 EMAC_INTEN_TXIEN_Msk |
393 EMAC_INTEN_RXGDIEN_Msk |
394 EMAC_INTEN_TXCPIEN_Msk |
395 EMAC_INTEN_RXBEIEN_Msk |
396 EMAC_INTEN_TXBEIEN_Msk |
397 EMAC_INTEN_RDUIEN_Msk |
398 EMAC_INTEN_TSALMIEN_Msk |
399 EMAC_INTEN_WOLIEN_Msk;
400
401 /* Configure the MAC control register. */
402 EMAC->CTL = EMAC_CTL_STRIPCRC_Msk |
403 EMAC_CTL_RMIIEN_Msk;
404
405 /* Accept packets for us and all broadcast and multicast packets */
406 EMAC->CAMCTL = EMAC_CAMCTL_CMPEN_Msk |
407 EMAC_CAMCTL_AMP_Msk |
408 EMAC_CAMCTL_ABP_Msk;
409
410 /* Limit the max receive frame length to 1514 + 4 */
411 EMAC->MRFL = EMAC_MAX_PKT_SIZE;
412 }
413
420 void EMAC_Close(void)
421 {
422 EMAC->CTL |= EMAC_CTL_RST_Msk;
423
424 while (EMAC->CTL & EMAC_CTL_RST_Msk) {}
425 }
426
432 void EMAC_SetMacAddr(uint8_t *pu8MacAddr)
433 {
434 EMAC_EnableCamEntry(0UL, pu8MacAddr);
435
436 }
437
444 void EMAC_EnableCamEntry(uint32_t u32Entry, uint8_t pu8MacAddr[])
445 {
446 uint32_t u32Lsw, u32Msw;
447 uint32_t reg;
448 u32Lsw = (uint32_t)(((uint32_t)pu8MacAddr[4] << 24) |
449 ((uint32_t)pu8MacAddr[5] << 16));
450 u32Msw = (uint32_t)(((uint32_t)pu8MacAddr[0] << 24) |
451 ((uint32_t)pu8MacAddr[1] << 16) |
452 ((uint32_t)pu8MacAddr[2] << 8) |
453 (uint32_t)pu8MacAddr[3]);
454
455 reg = (uint32_t)&EMAC->CAM0M + u32Entry * 2UL * 4UL;
456 *(uint32_t volatile *)reg = u32Msw;
457 reg = (uint32_t)&EMAC->CAM0L + u32Entry * 2UL * 4UL;
458 *(uint32_t volatile *)reg = u32Lsw;
459
460 EMAC->CAMEN |= (1UL << u32Entry);
461 }
462
468 void EMAC_DisableCamEntry(uint32_t u32Entry)
469 {
470 EMAC->CAMEN &= ~(1UL << u32Entry);
471 }
472
473
483 uint32_t EMAC_RecvPkt(uint8_t *pu8Data, uint32_t *pu32Size)
484 {
485 EMAC_DESCRIPTOR_T *desc;
486 uint32_t status, reg;
487 uint32_t u32Count = 0UL;
488
489 /* Clear Rx interrupt flags */
490 reg = EMAC->INTSTS;
491 EMAC->INTSTS = reg & 0xFFFFUL; /* Clear all RX related interrupt status */
492
493 if (reg & EMAC_INTSTS_RXBEIF_Msk)
494 {
495 /* Bus error occurred, this is usually a bad sign about software bug and will occur again... */
496 while (1) {}
497 }
498 else
499 {
500
501 /* Get Rx Frame Descriptor */
502 desc = (EMAC_DESCRIPTOR_T *)u32CurrentRxDesc;
503
504 /* If we reach last recv Rx descriptor, leave the loop */
505 if ((desc->u32Status1 & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) /* ownership=CPU */
506 {
507
508 status = desc->u32Status1 >> 16;
509
510 /* If Rx frame is good, process received frame */
511 if (status & EMAC_RXFD_RXGD)
512 {
513 /* lower 16 bit in descriptor status1 stores the Rx packet length */
514 *pu32Size = desc->u32Status1 & 0xFFFFUL;
515 memcpy(pu8Data, (uint8_t *)desc->u32Backup1, *pu32Size);
516 u32Count = 1UL;
517 }
518 else
519 {
520 /* Save Error status if necessary */
521 if (status & EMAC_RXFD_RP) {}
522
523 if (status & EMAC_RXFD_ALIE) {}
524
525 if (status & EMAC_RXFD_PTLE) {}
526
527 if (status & EMAC_RXFD_CRCE) {}
528 }
529 }
530 }
531
532 return (u32Count);
533 }
534
548 uint32_t EMAC_RecvPktTS(uint8_t *pu8Data, uint32_t *pu32Size, uint32_t *pu32Sec, uint32_t *pu32Nsec)
549 {
550 EMAC_DESCRIPTOR_T *desc;
551 uint32_t status, reg;
552 uint32_t u32Count = 0UL;
553
554 /* Clear Rx interrupt flags */
555 reg = EMAC->INTSTS;
556 EMAC->INTSTS = reg & 0xFFFFUL; /* Clear all Rx related interrupt status */
557
558 if (reg & EMAC_INTSTS_RXBEIF_Msk)
559 {
560 /* Bus error occurred, this is usually a bad sign about software bug and will occur again... */
561 while (1) {}
562 }
563 else
564 {
565
566 /* Get Rx Frame Descriptor */
567 desc = (EMAC_DESCRIPTOR_T *)u32CurrentRxDesc;
568
569 /* If we reach last recv Rx descriptor, leave the loop */
570 if (EMAC->CRXDSA != (uint32_t)desc)
571 {
572 if ((desc->u32Status1 | EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) /* ownership=CPU */
573 {
574
575 status = desc->u32Status1 >> 16;
576
577 /* If Rx frame is good, process received frame */
578 if (status & EMAC_RXFD_RXGD)
579 {
580 /* lower 16 bit in descriptor status1 stores the Rx packet length */
581 *pu32Size = desc->u32Status1 & 0xFFFFUL;
582 memcpy(pu8Data, (uint8_t *)desc->u32Backup1, *pu32Size);
583
584 *pu32Sec = desc->u32Next; /* second stores in descriptor's NEXT field */
585 *pu32Nsec = EMAC_Subsec2Nsec(desc->u32Data); /* Sub nano second store in DATA field */
586
587 u32Count = 1UL;
588 }
589 else
590 {
591 /* Save Error status if necessary */
592 if (status & EMAC_RXFD_RP) {}
593
594 if (status & EMAC_RXFD_ALIE) {}
595
596 if (status & EMAC_RXFD_PTLE) {}
597
598 if (status & EMAC_RXFD_CRCE) {}
599 }
600 }
601 }
602 }
603
604 return (u32Count);
605 }
606
614 void EMAC_RecvPktDone(void)
615 {
616 EMAC_DESCRIPTOR_T *desc;
617 /* Get Rx Frame Descriptor */
618 desc = (EMAC_DESCRIPTOR_T *)u32CurrentRxDesc;
619
620 /* Restore descriptor link list and data pointer they will be overwrite if time stamp enabled */
621 desc->u32Data = desc->u32Backup1;
622 desc->u32Next = desc->u32Backup2;
623
624 /* Change ownership to DMA for next use */
625 desc->u32Status1 |= EMAC_DESC_OWN_EMAC;
626
627 /* Get Next Frame Descriptor pointer to process */
628 desc = (EMAC_DESCRIPTOR_T *)desc->u32Next;
629
630 /* Save last processed Rx descriptor */
631 u32CurrentRxDesc = (uint32_t)desc;
632
633 EMAC_TRIGGER_RX();
634 }
635
636
646 uint32_t EMAC_SendPkt(uint8_t *pu8Data, uint32_t u32Size)
647 {
648 EMAC_DESCRIPTOR_T *desc;
649 uint32_t status;
650 uint32_t ret = 0UL;
651 /* Get Tx frame descriptor & data pointer */
652 desc = (EMAC_DESCRIPTOR_T *)u32NextTxDesc;
653
654 status = desc->u32Status1;
655
656 /* Check descriptor ownership */
657 if ((status & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC)
658 {
659 memcpy((uint8_t *)desc->u32Data, pu8Data, u32Size);
660
661 /* Set Tx descriptor transmit byte count */
662 desc->u32Status2 = u32Size;
663
664 /* Change descriptor ownership to EMAC */
665 desc->u32Status1 |= EMAC_DESC_OWN_EMAC;
666
667 /* Get next Tx descriptor */
668 u32NextTxDesc = (uint32_t)(desc->u32Next);
669
670 /* Trigger EMAC to send the packet */
671 EMAC_TRIGGER_TX();
672 ret = 1UL;
673 }
674
675 return (ret);
676 }
677
678
686 uint32_t EMAC_SendPktDone(void)
687 {
688 EMAC_DESCRIPTOR_T *desc;
689 uint32_t status, reg;
690 uint32_t last_tx_desc;
691 uint32_t u32Count = 0UL;
692
693 reg = EMAC->INTSTS;
694 /* Clear Tx interrupt flags */
695 EMAC->INTSTS = reg & (0xFFFF0000UL & ~EMAC_INTSTS_TSALMIF_Msk);
696
697
698 if (reg & EMAC_INTSTS_TXBEIF_Msk)
699 {
700 /* Bus error occurred, this is usually a bad sign about software bug and will occur again... */
701 while (1) {}
702 }
703 else
704 {
705 /* Process the descriptor(s). */
706 last_tx_desc = EMAC->CTXDSA ;
707 /* Get our first descriptor to process */
708 desc = (EMAC_DESCRIPTOR_T *) u32CurrentTxDesc;
709
710 do
711 {
712 /* Descriptor ownership is still EMAC, so this packet haven't been send. */
713 if (desc->u32Status1 & EMAC_DESC_OWN_EMAC)
714 {
715 break;
716 }
717
718 /* Get Tx status stored in descriptor */
719 status = desc->u32Status2 >> 16UL;
720
721 if (status & EMAC_TXFD_TXCP)
722 {
723 u32Count++;
724 }
725 else
726 {
727 /* Do nothing here on error. */
728 if (status & EMAC_TXFD_TXABT) {}
729
730 if (status & EMAC_TXFD_DEF) {}
731
732 if (status & EMAC_TXFD_PAU) {}
733
734 if (status & EMAC_TXFD_EXDEF) {}
735
736 if (status & EMAC_TXFD_NCS) {}
737
738 if (status & EMAC_TXFD_SQE) {}
739
740 if (status & EMAC_TXFD_LC) {}
741
742 if (status & EMAC_TXFD_TXHA) {}
743 }
744
745 /* restore descriptor link list and data pointer they will be overwrite if time stamp enabled */
746 desc->u32Data = desc->u32Backup1;
747 desc->u32Next = desc->u32Backup2;
748 /* go to next descriptor in link */
749 desc = (EMAC_DESCRIPTOR_T *)desc->u32Next;
750 } while (last_tx_desc != (uint32_t)desc); /* If we reach last sent Tx descriptor, leave the loop */
751
752 /* Save last processed Tx descriptor */
753 u32CurrentTxDesc = (uint32_t)desc;
754 }
755
756 return (u32Count);
757 }
758
769 uint32_t EMAC_SendPktDoneTS(uint32_t *pu32Sec, uint32_t *pu32Nsec)
770 {
771
772 EMAC_DESCRIPTOR_T *desc;
773 uint32_t status, reg;
774 uint32_t u32Count = 0UL;
775
776 reg = EMAC->INTSTS;
777 /* Clear Tx interrupt flags */
778 EMAC->INTSTS = reg & (0xFFFF0000UL & ~EMAC_INTSTS_TSALMIF_Msk);
779
780
781 if (reg & EMAC_INTSTS_TXBEIF_Msk)
782 {
783 /* Bus error occurred, this is usually a bad sign about software bug and will occur again... */
784 while (1) {}
785 }
786 else
787 {
788 /* Process the descriptor.
789 Get our first descriptor to process */
790 desc = (EMAC_DESCRIPTOR_T *) u32CurrentTxDesc;
791
792 /* Descriptor ownership is still EMAC, so this packet haven't been send. */
793 if ((desc->u32Status1 & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC)
794 {
795 /* Get Tx status stored in descriptor */
796 status = desc->u32Status2 >> 16UL;
797
798 if (status & EMAC_TXFD_TXCP)
799 {
800 u32Count = 1UL;
801 *pu32Sec = desc->u32Next; /* second stores in descriptor's NEXT field */
802 *pu32Nsec = EMAC_Subsec2Nsec(desc->u32Data); /* Sub nano second store in DATA field */
803 }
804 else
805 {
806 /* Do nothing here on error. */
807 if (status & EMAC_TXFD_TXABT) {}
808
809 if (status & EMAC_TXFD_DEF) {}
810
811 if (status & EMAC_TXFD_PAU) {}
812
813 if (status & EMAC_TXFD_EXDEF) {}
814
815 if (status & EMAC_TXFD_NCS) {}
816
817 if (status & EMAC_TXFD_SQE) {}
818
819 if (status & EMAC_TXFD_LC) {}
820
821 if (status & EMAC_TXFD_TXHA) {}
822 }
823
824 /* restore descriptor link list and data pointer they will be overwrite if time stamp enabled */
825 desc->u32Data = desc->u32Backup1;
826 desc->u32Next = desc->u32Backup2;
827 /* go to next descriptor in link */
828 desc = (EMAC_DESCRIPTOR_T *)desc->u32Next;
829
830 /* Save last processed Tx descriptor */
831 u32CurrentTxDesc = (uint32_t)desc;
832 }
833 }
834
835 return (u32Count);
836 }
837
844 void EMAC_EnableTS(uint32_t u32Sec, uint32_t u32Nsec)
845 {
846 double f;
847 uint32_t reg;
848 EMAC->TSCTL = EMAC_TSCTL_TSEN_Msk;
849 EMAC->UPDSEC = u32Sec; /* Assume current time is 0 sec + 0 nano sec */
850 EMAC->UPDSUBSEC = EMAC_Nsec2Subsec(u32Nsec);
851
852 /* PTP source clock is 160MHz (Real chip using PLL). Each tick is 6.25ns
853 Assume we want to set each tick to 100ns.
854 Increase register = (100 * 2^31) / (10^9) = 214.71 =~ 215 = 0xD7
855 Addend register = 2^32 * tick_freq / (160MHz), where tick_freq = (2^31 / 215) MHz
856 From above equation, addend register = 2^63 / (160M * 215) ~= 268121280 = 0xFFB34C0
857 So:
858 EMAC->TSIR = 0xD7;
859 EMAC->TSAR = 0x1E70C600; */
860 f = (100.0 * 2147483648.0) / (1000000000.0) + 0.5;
861 EMAC->TSINC = (reg = (uint32_t)f);
862 f = (double)9223372036854775808.0 / ((double)(CLK_GetHCLKFreq()) * (double)reg);
863 EMAC->TSADDEND = (uint32_t)f;
864 EMAC->TSCTL |= (EMAC_TSCTL_TSUPDATE_Msk | EMAC_TSCTL_TSIEN_Msk | EMAC_TSCTL_TSMODE_Msk); /* Fine update */
865 }
866
872 void EMAC_DisableTS(void)
873 {
874 EMAC->TSCTL = 0UL;
875 }
876
883 void EMAC_GetTime(uint32_t *pu32Sec, uint32_t *pu32Nsec)
884 {
885 /* Must read TSLSR firstly. Hardware will preserve TSMSR value at the time TSLSR read. */
886 *pu32Nsec = EMAC_Subsec2Nsec(EMAC->TSSUBSEC);
887 *pu32Sec = EMAC->TSSEC;
888 }
889
896 void EMAC_SetTime(uint32_t u32Sec, uint32_t u32Nsec)
897 {
898 /* Disable time stamp counter before update time value (clear EMAC_TSCTL_TSIEN_Msk) */
899 EMAC->TSCTL = EMAC_TSCTL_TSEN_Msk;
900 EMAC->UPDSEC = u32Sec;
901 EMAC->UPDSUBSEC = EMAC_Nsec2Subsec(u32Nsec);
902 EMAC->TSCTL |= (EMAC_TSCTL_TSIEN_Msk | EMAC_TSCTL_TSMODE_Msk);
903
904 }
905
912 void EMAC_EnableAlarm(uint32_t u32Sec, uint32_t u32Nsec)
913 {
914
915 EMAC->ALMSEC = u32Sec;
916 EMAC->ALMSUBSEC = EMAC_Nsec2Subsec(u32Nsec);
917 EMAC->TSCTL |= EMAC_TSCTL_TSALMEN_Msk;
918
919 }
920
926 void EMAC_DisableAlarm(void)
927 {
928
929 EMAC->TSCTL &= ~EMAC_TSCTL_TSALMEN_Msk;
930
931 }
932
940 void EMAC_UpdateTime(uint32_t u32Neg, uint32_t u32Sec, uint32_t u32Nsec)
941 {
942 EMAC->UPDSEC = u32Sec;
943 EMAC->UPDSUBSEC = EMAC_Nsec2Subsec(u32Nsec);
944
945 if (u32Neg)
946 {
947 EMAC->UPDSUBSEC |= BIT31; /* Set bit 31 indicates this is a negative value */
948 }
949
950 EMAC->TSCTL |= EMAC_TSCTL_TSUPDATE_Msk;
951
952 }
953
965 uint32_t EMAC_CheckLinkStatus(void)
966 {
967 uint32_t reg, ret = EMAC_LINK_DOWN;
968
969 /* Check link valid again */
970 if (EMAC_MdioRead(PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_LINK_VALID)
971 {
972 /* Check link partner capability */
973 reg = EMAC_MdioRead(PHY_ANLPA_REG, EMAC_PHY_ADDR) ;
974
975 if (reg & PHY_ANLPA_DR100_TX_FULL)
976 {
977 EMAC->CTL |= EMAC_CTL_OPMODE_Msk;
978 EMAC->CTL |= EMAC_CTL_FUDUP_Msk;
979 ret = EMAC_LINK_100F;
980 }
981 else if (reg & PHY_ANLPA_DR100_TX_HALF)
982 {
983 EMAC->CTL |= EMAC_CTL_OPMODE_Msk;
984 EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk;
985 ret = EMAC_LINK_100H;
986 }
987 else if (reg & PHY_ANLPA_DR10_TX_FULL)
988 {
989 EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk;
990 EMAC->CTL |= EMAC_CTL_FUDUP_Msk;
991 ret = EMAC_LINK_10F;
992 }
993 else
994 {
995 EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk;
996 EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk;
997 ret = EMAC_LINK_10H;
998 }
999 }
1000
1001 return ret;
1002 }
1003
1011 int32_t EMAC_FillCamEntry(uint8_t pu8MacAddr[])
1012 {
1013 uint32_t *EMAC_CAMxM;
1014 uint32_t *EMAC_CAMxL;
1015 int32_t index;
1016 uint8_t mac[6];
1017
1018 for (index = 0; index < EMAC_CAMENTRY_NB; index ++)
1019 {
1020 EMAC_CAMxM = (uint32_t *)((uint32_t)&EMAC->CAM0M + (index * 8));
1021 EMAC_CAMxL = (uint32_t *)((uint32_t)&EMAC->CAM0L + (index * 8));
1022
1023 mac[0] = (*EMAC_CAMxM >> 24) & 0xff;
1024 mac[1] = (*EMAC_CAMxM >> 16) & 0xff;
1025 mac[2] = (*EMAC_CAMxM >> 8) & 0xff;
1026 mac[3] = (*EMAC_CAMxM) & 0xff;
1027 mac[4] = (*EMAC_CAMxL >> 24) & 0xff;
1028 mac[5] = (*EMAC_CAMxL >> 16) & 0xff;
1029
1030 if (memcmp(mac, pu8MacAddr, sizeof(mac)) == 0)
1031 {
1032 goto exit_emac_fillcamentry;
1033 }
1034
1035 if (*EMAC_CAMxM == 0 && *EMAC_CAMxL == 0)
1036 {
1037 break;
1038 }
1039 }
1040
1041 if (index < EMAC_CAMENTRY_NB)
1042 {
1043 EMAC_EnableCamEntry(index, pu8MacAddr);
1044 goto exit_emac_fillcamentry;
1045 }
1046
1047 return -1;
1048
1049 exit_emac_fillcamentry:
1050
1051 return index;
1052 }
1053
1062 uint32_t EMAC_SendPktWoCopy(uint32_t u32Size)
1063 {
1064 EMAC_DESCRIPTOR_T *desc;
1065 uint32_t status;
1066 uint32_t ret = 0UL;
1067 /* Get Tx frame descriptor & data pointer */
1068 desc = (EMAC_DESCRIPTOR_T *)u32NextTxDesc;
1069
1070 status = desc->u32Status1;
1071
1072 /* Check descriptor ownership */
1073 if ((status & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC)
1074 {
1075 /* Set Tx descriptor transmit byte count */
1076 desc->u32Status2 = u32Size;
1077
1078 /* Change descriptor ownership to EMAC */
1079 desc->u32Status1 |= EMAC_DESC_OWN_EMAC;
1080
1081 /* Get next Tx descriptor */
1082 u32NextTxDesc = (uint32_t)(desc->u32Next);
1083
1084 /* Trigger EMAC to send the packet */
1085 EMAC_TRIGGER_TX();
1086 ret = 1UL;
1087 }
1088
1089 return (ret);
1090 }
1091
1098 uint8_t *EMAC_ClaimFreeTXBuf(void)
1099 {
1100 EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)u32NextTxDesc;
1101
1102 if (desc->u32Status1 & EMAC_DESC_OWN_EMAC)
1103 {
1104 return (NULL);
1105 }
1106 else
1107 {
1108 return (uint8_t *)desc->u32Data;
1109 }
1110 }
1111
1118 uint32_t EMAC_GetAvailRXBufSize(void)
1119 {
1120 EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)u32CurrentRxDesc;
1121
1122 if ((desc->u32Status1 & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) /* ownership=CPU */
1123 {
1124 uint32_t status = desc->u32Status1 >> 16;
1125
1126 /* It is good and no CRC error. */
1127 if ((status & EMAC_RXFD_RXGD) && !(status & EMAC_RXFD_CRCE))
1128 {
1129 return desc->u32Status1 & 0xFFFFUL;
1130 }
1131 else
1132 {
1133 // Drop it
1134 EMAC_RecvPktDone();
1135 }
1136 }
1137
1138 return 0;
1139 }
1140
1141
1150 void EMAC_RecvPktDoneWoRxTrigger(void)
1151 {
1152 EMAC_DESCRIPTOR_T *desc;
1153 /* Get Rx Frame Descriptor */
1154 desc = (EMAC_DESCRIPTOR_T *)u32CurrentRxDesc;
1155
1156 /* Restore descriptor link list and data pointer they will be overwrite if time stamp enabled */
1157 desc->u32Data = desc->u32Backup1;
1158 desc->u32Next = desc->u32Backup2;
1159
1160 /* Change ownership to DMA for next use */
1161 desc->u32Status1 |= EMAC_DESC_OWN_EMAC;
1162
1163 /* Get Next Frame Descriptor pointer to process */
1164 desc = (EMAC_DESCRIPTOR_T *)desc->u32Next;
1165
1166 /* Save last processed Rx descriptor */
1167 u32CurrentRxDesc = (uint32_t)desc;
1168 }
1169
1170 /* end of group EMAC_EXPORTED_FUNCTIONS */
1172 /* end of group EMAC_Driver */
1174 /* end of group Standard_Driver */
1176
1177 /*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/
EMAC_INTEN_TSALMIEN_Msk
#define EMAC_INTEN_TSALMIEN_Msk
Definition: emac_reg.h:3612
EMAC_FillCamEntry
int32_t EMAC_FillCamEntry(uint8_t pu8MacAddr[])
Fill a MAC address to list and enable.
Definition: emac.c:1011
EMAC_SetTime
void EMAC_SetTime(uint32_t u32Sec, uint32_t u32Nsec)
Set current time stamp.
Definition: emac.c:896
EMAC
#define EMAC
Definition: M480.h:390
BIT31
#define BIT31
Bit 31 mask of an 32 bit integer.
Definition: M480.h:645
EMAC_MIIMCTL_WRITE_Msk
#define EMAC_MIIMCTL_WRITE_Msk
Definition: emac_reg.h:3513
EMAC_PhyInit
void EMAC_PhyInit(void)
EMAC_TX_DESC_SIZE
#define EMAC_TX_DESC_SIZE
Definition: emac.h:33
EMAC_SetMacAddr
void EMAC_SetMacAddr(uint8_t *pu8MacAddr)
Set the device MAC address.
Definition: emac.c:432
EMAC_MIIMCTL_BUSY_Msk
#define EMAC_MIIMCTL_BUSY_Msk
Definition: emac_reg.h:3516
EMAC_GetTime
void EMAC_GetTime(uint32_t *pu32Sec, uint32_t *pu32Nsec)
Get current time stamp.
Definition: emac.c:883
EMAC_LINK_DOWN
#define EMAC_LINK_DOWN
Definition: emac.h:37
EMAC_CAMCTL_AMP_Msk
#define EMAC_CAMCTL_AMP_Msk
Definition: emac_reg.h:3156
EMAC_INTEN_RXBEIEN_Msk
#define EMAC_INTEN_RXBEIEN_Msk
Definition: emac_reg.h:3576
EMAC_LINK_10H
#define EMAC_LINK_10H
Definition: emac.h:41
EMAC_EnableAlarm
void EMAC_EnableAlarm(uint32_t u32Sec, uint32_t u32Nsec)
Enable alarm function and set alarm time.
Definition: emac.c:912
EMAC_DisableTS
void EMAC_DisableTS(void)
Disable IEEE1588 time stamp function.
Definition: emac.c:872
EMAC_CTL_STRIPCRC_Msk
#define EMAC_CTL_STRIPCRC_Msk
Definition: emac_reg.h:3471
NuMicro.h
NuMicro peripheral access layer header file.
EMAC_CTL_OPMODE_Msk
#define EMAC_CTL_OPMODE_Msk
Definition: emac_reg.h:3495
EMAC_PHY_ADDR
#define EMAC_PHY_ADDR
Definition: emac.h:31
EMAC_CAMCTL_ABP_Msk
#define EMAC_CAMCTL_ABP_Msk
Definition: emac_reg.h:3159
EMAC_TSCTL_TSEN_Msk
#define EMAC_TSCTL_TSEN_Msk
Definition: emac_reg.h:3735
EMAC_INTEN_TXBEIEN_Msk
#define EMAC_INTEN_TXBEIEN_Msk
Definition: emac_reg.h:3609
EMAC_DisableAlarm
void EMAC_DisableAlarm(void)
Disable alarm function.
Definition: emac.c:926
EMAC_INTEN_TXIEN_Msk
#define EMAC_INTEN_TXIEN_Msk
Definition: emac_reg.h:3585
EMAC_EnableTS
void EMAC_EnableTS(uint32_t u32Sec, uint32_t u32Nsec)
Enable IEEE1588 time stamp function and set current time.
Definition: emac.c:844
EMAC_EnableCamEntry
void EMAC_EnableCamEntry(uint32_t u32Entry, uint8_t pu8MacAddr[])
Fill a CAM entry for MAC address comparison.
Definition: emac.c:444
EMAC_RX_DESC_SIZE
#define EMAC_RX_DESC_SIZE
Definition: emac.h:32
EMAC_CheckLinkStatus
uint32_t EMAC_CheckLinkStatus(void)
Check Ethernet link status.
Definition: emac.c:965
EMAC_INTEN_RXGDIEN_Msk
#define EMAC_INTEN_RXGDIEN_Msk
Definition: emac_reg.h:3555
EMAC_TSCTL_TSMODE_Msk
#define EMAC_TSCTL_TSMODE_Msk
Definition: emac_reg.h:3741
EMAC_CAMENTRY_NB
#define EMAC_CAMENTRY_NB
Definition: emac.h:34
EMAC_INTEN_TXCPIEN_Msk
#define EMAC_INTEN_TXCPIEN_Msk
Definition: emac_reg.h:3591
EMAC_RecvPkt
uint32_t EMAC_RecvPkt(uint8_t *pu8Data, uint32_t *pu32Size)
Receive an Ethernet packet.
Definition: emac.c:483
EMAC_LINK_100F
#define EMAC_LINK_100F
Definition: emac.h:38
EMAC_INTEN_RXIEN_Msk
#define EMAC_INTEN_RXIEN_Msk
Definition: emac_reg.h:3543
EMAC_TRIGGER_TX
#define EMAC_TRIGGER_TX()
Trigger EMAC Tx function.
Definition: emac.h:163
EMAC_SendPktDone
uint32_t EMAC_SendPktDone(void)
Clean up process after packet(s) are sent.
Definition: emac.c:686
EMAC_Close
void EMAC_Close(void)
This function stop all receive and transmit activity and disable MAC interface.
Definition: emac.c:420
EMAC_DisableCamEntry
void EMAC_DisableCamEntry(uint32_t u32Entry)
Disable a specified CAM entry.
Definition: emac.c:468
EMAC_Open
void EMAC_Open(uint8_t *pu8MacAddr)
Initialize EMAC interface, including descriptors, MAC address, and PHY.
Definition: emac.c:381
EMAC_LINK_10F
#define EMAC_LINK_10F
Definition: emac.h:40
EMAC_RecvPktDone
void EMAC_RecvPktDone(void)
Clean up process after a packet is received.
Definition: emac.c:614
EMAC_TSCTL_TSUPDATE_Msk
#define EMAC_TSCTL_TSUPDATE_Msk
Definition: emac_reg.h:3744
EMAC_INTSTS_TXBEIF_Msk
#define EMAC_INTSTS_TXBEIF_Msk
Definition: emac_reg.h:3681
EMAC_RecvPktDoneWoRxTrigger
void EMAC_RecvPktDoneWoRxTrigger(void)
Clean up process after a packet is received.
Definition: emac.c:1150
EMAC_UpdateTime
void EMAC_UpdateTime(uint32_t u32Neg, uint32_t u32Sec, uint32_t u32Nsec)
Add a offset to current time.
Definition: emac.c:940
EMAC_SendPktWoCopy
uint32_t EMAC_SendPktWoCopy(uint32_t u32Size)
Send an Ethernet packet.
Definition: emac.c:1062
EMAC_MAX_PKT_SIZE
#define EMAC_MAX_PKT_SIZE
Definition: emac.h:35
EMAC_SendPktDoneTS
uint32_t EMAC_SendPktDoneTS(uint32_t *pu32Sec, uint32_t *pu32Nsec)
Clean up process after a packet is sent, and get the time stamp while packet is sent.
Definition: emac.c:769
EMAC_CTL_RMIIEN_Msk
#define EMAC_CTL_RMIIEN_Msk
Definition: emac_reg.h:3498
EMAC_INTEN_RDUIEN_Msk
#define EMAC_INTEN_RDUIEN_Msk
Definition: emac_reg.h:3573
EMAC_CTL_FUDUP_Msk
#define EMAC_CTL_FUDUP_Msk
Definition: emac_reg.h:3489
CLK_GetHCLKFreq
uint32_t CLK_GetHCLKFreq(void)
Get HCLK frequency.
Definition: clk.c:244
EMAC_INTSTS_TSALMIF_Msk
#define EMAC_INTSTS_TSALMIF_Msk
Definition: emac_reg.h:3684
EMAC_GetAvailRXBufSize
uint32_t EMAC_GetAvailRXBufSize(void)
Get data length of avaiable RX buffer.
Definition: emac.c:1118
EMAC_INTSTS_RXBEIF_Msk
#define EMAC_INTSTS_RXBEIF_Msk
Definition: emac_reg.h:3648
EMAC_MIIMCTL_PHYADDR_Pos
#define EMAC_MIIMCTL_PHYADDR_Pos
Definition: emac_reg.h:3509
NULL
#define NULL
NULL pointer.
Definition: M480.h:604
EMAC_TRIGGER_RX
#define EMAC_TRIGGER_RX()
Trigger EMAC Rx function.
Definition: emac.h:156
EMAC_INTEN_WOLIEN_Msk
#define EMAC_INTEN_WOLIEN_Msk
Definition: emac_reg.h:3582
EMAC_SendPkt
uint32_t EMAC_SendPkt(uint8_t *pu8Data, uint32_t u32Size)
Send an Ethernet packet.
Definition: emac.c:646
EMAC_CTL_RST_Msk
#define EMAC_CTL_RST_Msk
Definition: emac_reg.h:3501
EMAC_CAMCTL_CMPEN_Msk
#define EMAC_CAMCTL_CMPEN_Msk
Definition: emac_reg.h:3165
EMAC_TSCTL_TSIEN_Msk
#define EMAC_TSCTL_TSIEN_Msk
Definition: emac_reg.h:3738
EMAC_LINK_100H
#define EMAC_LINK_100H
Definition: emac.h:39
EMAC_MIIMCTL_MDCON_Msk
#define EMAC_MIIMCTL_MDCON_Msk
Definition: emac_reg.h:3522
EMAC_TSCTL_TSALMEN_Msk
#define EMAC_TSCTL_TSALMEN_Msk
Definition: emac_reg.h:3747
EMAC_ClaimFreeTXBuf
uint8_t * EMAC_ClaimFreeTXBuf(void)
Get avaiable TX buffer address.
Definition: emac.c:1098
EMAC_RecvPktTS
uint32_t EMAC_RecvPktTS(uint8_t *pu8Data, uint32_t *pu32Size, uint32_t *pu32Sec, uint32_t *pu32Nsec)
Receive an Ethernet packet and the time stamp while it's received.
Definition: emac.c:548