drv_emac.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2020-2-7 Wayne First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_EMAC)
  14. #if defined(RT_USING_LWIP)
  15. #include <rtdevice.h>
  16. #include "NuMicro.h"
  17. #include <netif/ethernetif.h>
  18. #include <netif/etharp.h>
  19. #include <lwip/icmp.h>
  20. #include "lwipopts.h"
  21. #include "drv_pdma.h"
  22. /* Private define ---------------------------------------------------------------*/
  23. // RT_DEV_NAME_PREFIX e
  24. #if !defined(NU_EMAC_PDMA_MEMCOPY)
  25. #define NU_EMAC_PDMA_MEMCOPY
  26. #endif
  27. #if !defined(NU_EMAC_PDMA_MEMCOPY_THRESHOLD)
  28. #define NU_EMAC_PDMA_MEMCOPY_THRESHOLD 128
  29. #endif
  30. #define NU_EMAC_DEBUG
  31. #if defined(NU_EMAC_DEBUG)
  32. // #define NU_EMAC_RX_DUMP
  33. // #define NU_EMAC_TX_DUMP
  34. #define NU_EMAC_TRACE rt_kprintf
  35. #else
  36. #define NU_EMAC_TRACE(...)
  37. #endif
  38. #define NU_EMAC_TID_STACK_SIZE 256
  39. /* Private typedef --------------------------------------------------------------*/
  40. struct nu_emac
  41. {
  42. struct eth_device eth;
  43. rt_uint8_t mac_addr[6];
  44. struct rt_semaphore eth_sem;
  45. };
  46. typedef struct nu_emac *nu_emac_t;
  47. /* Private functions ------------------------------------------------------------*/
  48. #if defined(NU_EMAC_RX_DUMP) || defined(NU_EMAC_TX_DUMP)
  49. static void nu_emac_pkt_dump(const char *msg, const struct pbuf *p);
  50. #endif
  51. #if LWIP_IPV4 && LWIP_IGMP
  52. static err_t nu_igmp_mac_filter(struct netif *netif, const ip4_addr_t *ip4_addr, enum netif_mac_filter_action action);
  53. #endif
  54. static void nu_emac_halt(void);
  55. static void nu_emac_reinit(void);
  56. static void link_monitor(void *param);
  57. static rt_err_t nu_emac_init(rt_device_t dev);
  58. static rt_err_t nu_emac_open(rt_device_t dev, rt_uint16_t oflag);
  59. static rt_err_t nu_emac_close(rt_device_t dev);
  60. static rt_size_t nu_emac_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
  61. static rt_size_t nu_emac_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
  62. static rt_err_t nu_emac_control(rt_device_t dev, int cmd, void *args);
  63. static rt_err_t nu_emac_tx(rt_device_t dev, struct pbuf *p);
  64. static struct pbuf *nu_emac_rx(rt_device_t dev);
  65. static rt_err_t rt_hw_nu_emac_register(char *dev_name);
  66. static int rt_hw_nu_emac_init(void);
  67. static void *nu_emac_memcpy(void *dest, void *src, unsigned int count);
  68. /* Public functions -------------------------------------------------------------*/
  69. /* Private variables ------------------------------------------------------------*/
  70. static struct nu_emac nu_emac_dev = {0};
  71. static struct rt_thread eth_tid;
  72. static rt_uint8_t eth_stack[NU_EMAC_TID_STACK_SIZE];
  73. #if defined(NU_EMAC_RX_DUMP) || defined(NU_EMAC_TX_DUMP)
  74. static void nu_emac_pkt_dump(const char *msg, const struct pbuf *p)
  75. {
  76. rt_uint32_t i;
  77. rt_uint8_t *ptr = p->payload;
  78. NU_EMAC_TRACE("%s %d byte\n", msg, p->tot_len);
  79. for (i = 0; i < p->tot_len; i++)
  80. {
  81. if ((i % 8) == 0)
  82. {
  83. NU_EMAC_TRACE(" ");
  84. }
  85. if ((i % 16) == 0)
  86. {
  87. NU_EMAC_TRACE("\r\n");
  88. }
  89. NU_EMAC_TRACE("%02x ", *ptr);
  90. ptr++;
  91. }
  92. NU_EMAC_TRACE("\n\n");
  93. }
  94. #endif /* dump */
  95. static void nu_emac_halt(void)
  96. {
  97. EMAC_DISABLE_RX();
  98. EMAC_DISABLE_TX();
  99. }
  100. static void *nu_emac_memcpy(void *dest, void *src, unsigned int count)
  101. {
  102. #if defined(NU_EMAC_PDMA_MEMCOPY)
  103. if (count >= NU_EMAC_PDMA_MEMCOPY_THRESHOLD)
  104. return nu_pdma_memcpy(dest, src, count);
  105. #endif
  106. return rt_memcpy(dest, src, count);
  107. }
  108. static void nu_emac_reinit(void)
  109. {
  110. rt_uint32_t EMAC_CAMxM[EMAC_CAMENTRY_NB];
  111. rt_uint32_t EMAC_CAMxL[EMAC_CAMENTRY_NB];
  112. rt_uint32_t EMAC_CAMEN;
  113. // Backup MAC address.
  114. EMAC_CAMEN = EMAC->CAMEN;
  115. for (rt_uint8_t index = 0 ; index < EMAC_CAMENTRY_NB; index ++)
  116. {
  117. rt_uint32_t *CAMxM = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0M + (index * 8));
  118. rt_uint32_t *CAMxL = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0L + (index * 8));
  119. EMAC_CAMxM[index] = *CAMxM;
  120. EMAC_CAMxL[index] = *CAMxL;
  121. }
  122. nu_emac_halt();
  123. EMAC_Close();
  124. EMAC_Open((uint8_t *)&nu_emac_dev.mac_addr[0]);
  125. EMAC_ENABLE_TX();
  126. EMAC_ENABLE_RX();
  127. // Restore MAC address.
  128. for (rt_uint8_t index = 0 ; index < EMAC_CAMENTRY_NB; index ++)
  129. {
  130. rt_uint32_t *CAMxM = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0M + (index * 8));
  131. rt_uint32_t *CAMxL = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0L + (index * 8));
  132. *CAMxM = EMAC_CAMxM[index];
  133. *CAMxL = EMAC_CAMxL[index];
  134. }
  135. EMAC->CAMEN = EMAC_CAMEN;
  136. }
  137. #if LWIP_IPV4 && LWIP_IGMP
  138. static err_t nu_igmp_mac_filter(struct netif *netif, const ip4_addr_t *ip4_addr, enum netif_mac_filter_action action)
  139. {
  140. rt_uint8_t mac[6];
  141. int32_t ret = 0;
  142. const uint8_t *p = (const uint8_t *)ip4_addr;
  143. mac[0] = 0x01;
  144. mac[1] = 0x00;
  145. mac[2] = 0x5E;
  146. mac[3] = *(p + 1) & 0x7F;
  147. mac[4] = *(p + 2);
  148. mac[5] = *(p + 3);
  149. ret = EMAC_FillCamEntry((uint8_t *)&mac[0]);
  150. if (ret >= 0)
  151. {
  152. NU_EMAC_TRACE("%s %s %s ", __FUNCTION__, (action == NETIF_ADD_MAC_FILTER) ? "add" : "del", ip4addr_ntoa(ip4_addr));
  153. NU_EMAC_TRACE("%02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  154. }
  155. return (ret >= 0) ? RT_EOK : -(RT_ERROR);
  156. }
  157. #endif /* LWIP_IPV4 && LWIP_IGMP */
  158. static void link_monitor(void *param)
  159. {
  160. nu_emac_t psNuEMAC = (nu_emac_t)param;
  161. uint32_t LinkStatus_Last = EMAC_LINK_DOWN;
  162. EMAC_PhyInit();
  163. while (1)
  164. {
  165. uint32_t LinkStatus_Current = EMAC_CheckLinkStatus();
  166. /* linkchange */
  167. if (LinkStatus_Last != LinkStatus_Current)
  168. {
  169. switch (LinkStatus_Current)
  170. {
  171. case EMAC_LINK_DOWN:
  172. NU_EMAC_TRACE("Link status: Down\n");
  173. break;
  174. case EMAC_LINK_100F:
  175. NU_EMAC_TRACE("Link status: 100F\n");
  176. break;
  177. case EMAC_LINK_100H:
  178. NU_EMAC_TRACE("Link status: 100H\n");
  179. break;
  180. case EMAC_LINK_10F:
  181. NU_EMAC_TRACE("Link status: 10F\n");
  182. break;
  183. case EMAC_LINK_10H:
  184. NU_EMAC_TRACE("Link status: 10H\n");
  185. break;
  186. } /* switch( LinkStatus_Current ) */
  187. /* Send link status to upper layer. */
  188. if (LinkStatus_Current == EMAC_LINK_DOWN)
  189. eth_device_linkchange(&psNuEMAC->eth, RT_FALSE);
  190. else
  191. eth_device_linkchange(&psNuEMAC->eth, RT_TRUE);
  192. LinkStatus_Last = LinkStatus_Current;
  193. } /* if ( LinkStatus_Last != LinkStatus_Current ) */
  194. rt_thread_delay(RT_TICK_PER_SECOND);
  195. } /* while(1) */
  196. }
  197. static rt_err_t nu_emac_init(rt_device_t dev)
  198. {
  199. rt_err_t result;
  200. nu_emac_t psNuEMAC = (nu_emac_t)dev;
  201. EMAC_Close();
  202. EMAC_Open((uint8_t *)&psNuEMAC->mac_addr[0]);
  203. EMAC_ENABLE_RX();
  204. EMAC_ENABLE_TX();
  205. NVIC_SetPriority(EMAC_TX_IRQn, 1);
  206. NVIC_EnableIRQ(EMAC_TX_IRQn);
  207. NVIC_SetPriority(EMAC_RX_IRQn, 1);
  208. NVIC_EnableIRQ(EMAC_RX_IRQn);
  209. result = rt_sem_init(&psNuEMAC->eth_sem, "eth_sem", 0, RT_IPC_FLAG_FIFO);
  210. RT_ASSERT(result == RT_EOK);
  211. result = rt_thread_init(&eth_tid, "eth", link_monitor, (void *)psNuEMAC, eth_stack, sizeof(eth_stack), RT_THREAD_PRIORITY_MAX - 2, 10);
  212. RT_ASSERT(result == RT_EOK);
  213. rt_thread_startup(&eth_tid);
  214. #if defined(LWIP_IPV4) && defined(LWIP_IGMP)
  215. netif_set_igmp_mac_filter(psNuEMAC->eth.netif, nu_igmp_mac_filter);
  216. #endif /* LWIP_IPV4 && LWIP_IGMP */
  217. return RT_EOK;
  218. }
  219. static rt_err_t nu_emac_open(rt_device_t dev, rt_uint16_t oflag)
  220. {
  221. return RT_EOK;
  222. }
  223. static rt_err_t nu_emac_close(rt_device_t dev)
  224. {
  225. return RT_EOK;
  226. }
  227. static rt_size_t nu_emac_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  228. {
  229. rt_set_errno(-RT_ENOSYS);
  230. return 0;
  231. }
  232. static rt_size_t nu_emac_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  233. {
  234. rt_set_errno(-RT_ENOSYS);
  235. return 0;
  236. }
  237. static rt_err_t nu_emac_control(rt_device_t dev, int cmd, void *args)
  238. {
  239. nu_emac_t psNuEMAC = (nu_emac_t)dev;
  240. switch (cmd)
  241. {
  242. case NIOCTL_GADDR:
  243. /* Get MAC address */
  244. if (args)
  245. rt_memcpy(args, &psNuEMAC->mac_addr[0], 6);
  246. else
  247. return -RT_ERROR;
  248. break;
  249. default :
  250. break;
  251. }
  252. return RT_EOK;
  253. }
  254. static rt_err_t nu_emac_tx(rt_device_t dev, struct pbuf *p)
  255. {
  256. rt_err_t result;
  257. nu_emac_t psNuEMAC = (nu_emac_t)dev;
  258. struct pbuf *q;
  259. rt_uint32_t offset = 0;
  260. rt_uint8_t *buf = (rt_uint8_t *)EMAC_ClaimFreeTXBuf();
  261. /* Get free TX buffer */
  262. if (buf == RT_NULL)
  263. {
  264. result = rt_sem_control(&psNuEMAC->eth_sem, RT_IPC_CMD_RESET, 0);
  265. RT_ASSERT(result == RT_EOK);
  266. EMAC_CLEAR_INT_FLAG(EMAC, EMAC_INTSTS_TXCPIF_Msk);
  267. EMAC_ENABLE_INT(EMAC, EMAC_INTEN_TXCPIEN_Msk);
  268. do
  269. {
  270. while (rt_sem_take(&psNuEMAC->eth_sem, 10) != RT_EOK) ;
  271. buf = (rt_uint8_t *)EMAC_ClaimFreeTXBuf();
  272. }
  273. while (buf == RT_NULL);
  274. }
  275. for (q = p; q != NULL; q = q->next)
  276. {
  277. rt_uint8_t *ptr;
  278. rt_uint32_t len;
  279. len = q->len;
  280. ptr = q->payload;
  281. nu_emac_memcpy(&buf[offset], ptr, len);
  282. offset += len;
  283. }
  284. #if defined(NU_EMAC_TX_DUMP)
  285. nu_emac_pkt_dump("TX dump", p);
  286. #endif
  287. /* Return SUCCESS */
  288. return (EMAC_SendPktWoCopy(offset) == 1) ? RT_EOK : RT_ERROR;
  289. }
  290. static struct pbuf *nu_emac_rx(rt_device_t dev)
  291. {
  292. struct pbuf *p = RT_NULL;
  293. uint8_t *pu8DataBuf = NULL;
  294. unsigned int avaialbe_size;
  295. if ((avaialbe_size = EMAC_GetAvailRXBufSize(&pu8DataBuf)) > 0)
  296. {
  297. /* Allocate RX packet buffer. */
  298. p = pbuf_alloc(PBUF_RAW, avaialbe_size, PBUF_RAM);
  299. if (p != RT_NULL)
  300. {
  301. RT_ASSERT(p->next == RT_NULL);
  302. nu_emac_memcpy((void *)p->payload, (void *)pu8DataBuf, avaialbe_size);
  303. #if defined(NU_EMAC_RX_DUMP)
  304. nu_emac_pkt_dump("RX dump", p);
  305. #endif
  306. }
  307. else
  308. {
  309. NU_EMAC_TRACE("Can't allocate memory for RX packet.(%d)\n", avaialbe_size);
  310. }
  311. /* Update RX descriptor */
  312. EMAC_RecvPktDoneWoRxTrigger();
  313. } // if ( (avaialbe_size= EMAC_GetAvaiableRXBufSize()) > 0 )
  314. else
  315. {
  316. /* No avaiable RX packet, we enable RXGD/RDUIEN interrupts. */
  317. if (!(EMAC->INTEN & EMAC_INTEN_RDUIEN_Msk))
  318. {
  319. EMAC_CLEAR_INT_FLAG(EMAC, (EMAC_INTSTS_RDUIF_Msk | EMAC_INTSTS_RXGDIF_Msk));
  320. EMAC_ENABLE_INT(EMAC, (EMAC_INTEN_RDUIEN_Msk | EMAC_INTEN_RXGDIEN_Msk));
  321. }
  322. else
  323. {
  324. EMAC_CLEAR_INT_FLAG(EMAC, EMAC_INTSTS_RXGDIF_Msk);
  325. EMAC_ENABLE_INT(EMAC, EMAC_INTEN_RXGDIEN_Msk);
  326. }
  327. EMAC_TRIGGER_RX();
  328. } //else
  329. return p;
  330. }
  331. void EMAC_RX_IRQHandler(void)
  332. {
  333. /* Enter interrupt */
  334. rt_interrupt_enter();
  335. /* No RX descriptor avaiable, we need to get data from RX pool */
  336. if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_RDUIF_Msk))
  337. {
  338. EMAC_DISABLE_INT(EMAC, (EMAC_INTEN_RDUIEN_Msk | EMAC_INTEN_RXGDIEN_Msk));
  339. eth_device_ready(&nu_emac_dev.eth);
  340. }
  341. /* A good packet ready. */
  342. else if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_RXGDIF_Msk))
  343. {
  344. EMAC_DISABLE_INT(EMAC, EMAC_INTEN_RXGDIEN_Msk);
  345. eth_device_ready(&nu_emac_dev.eth);
  346. }
  347. /* Receive Bus Error Interrupt */
  348. if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_RXBEIF_Msk))
  349. {
  350. NU_EMAC_TRACE("Reinit Rx EMAC\n");
  351. EMAC_CLEAR_INT_FLAG(EMAC, EMAC_INTSTS_RXBEIF_Msk);
  352. nu_emac_reinit();
  353. }
  354. /* Leave interrupt */
  355. rt_interrupt_leave();
  356. }
  357. void EMAC_TX_IRQHandler(void)
  358. {
  359. /* Enter interrupt */
  360. rt_interrupt_enter();
  361. unsigned int status = EMAC->INTSTS;
  362. /* Wake-up suspended process to send */
  363. if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_TXCPIF_Msk))
  364. {
  365. rt_err_t result;
  366. EMAC_DISABLE_INT(EMAC, EMAC_INTEN_TXCPIEN_Msk);
  367. result = rt_sem_release(&nu_emac_dev.eth_sem);
  368. RT_ASSERT(result == RT_EOK);
  369. }
  370. if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_TXBEIF_Msk))
  371. {
  372. NU_EMAC_TRACE("Reinit Tx EMAC\n");
  373. EMAC->INTSTS = EMAC_INTSTS_TXBEIF_Msk;
  374. EMAC_CLEAR_INT_FLAG(EMAC, EMAC_INTSTS_TXBEIF_Msk);
  375. nu_emac_reinit();
  376. }
  377. else
  378. EMAC_SendPktDone();
  379. /* Leave interrupt */
  380. rt_interrupt_leave();
  381. }
  382. static rt_err_t rt_hw_nu_emac_register(char *dev_name)
  383. {
  384. rt_uint32_t value = 0;
  385. nu_emac_t psNuEMAC = (nu_emac_t)&nu_emac_dev;
  386. /* Read UID from FMC */
  387. SYS_UnlockReg();
  388. FMC_Open();
  389. for (rt_uint8_t i = 0; i < 3; i++)
  390. {
  391. value += FMC_ReadUID(i);
  392. }
  393. FMC_Close();
  394. SYS_LockReg();
  395. /* Assign MAC address */
  396. psNuEMAC->mac_addr[0] = 0x82;
  397. psNuEMAC->mac_addr[1] = 0x06;
  398. psNuEMAC->mac_addr[2] = 0x21;
  399. psNuEMAC->mac_addr[3] = (value >> 16) & 0xff;
  400. psNuEMAC->mac_addr[4] = (value >> 8) & 0xff;
  401. psNuEMAC->mac_addr[5] = (value) & 0xff;
  402. NU_EMAC_TRACE("MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", \
  403. psNuEMAC->mac_addr[0], \
  404. psNuEMAC->mac_addr[1], \
  405. psNuEMAC->mac_addr[2], \
  406. psNuEMAC->mac_addr[3], \
  407. psNuEMAC->mac_addr[4], \
  408. psNuEMAC->mac_addr[5]);
  409. /* Register member functions */
  410. psNuEMAC->eth.parent.init = nu_emac_init;
  411. psNuEMAC->eth.parent.open = nu_emac_open;
  412. psNuEMAC->eth.parent.close = nu_emac_close;
  413. psNuEMAC->eth.parent.read = nu_emac_read;
  414. psNuEMAC->eth.parent.write = nu_emac_write;
  415. psNuEMAC->eth.parent.control = nu_emac_control;
  416. psNuEMAC->eth.parent.user_data = RT_NULL;
  417. psNuEMAC->eth.eth_rx = nu_emac_rx;
  418. psNuEMAC->eth.eth_tx = nu_emac_tx;
  419. /* Register eth device */
  420. return eth_device_init(&nu_emac_dev.eth, dev_name);
  421. }
  422. static int rt_hw_nu_emac_init(void)
  423. {
  424. return rt_hw_nu_emac_register("e0");
  425. }
  426. INIT_APP_EXPORT(rt_hw_nu_emac_init);
  427. #endif /* #if defined( RT_USING_LWIP ) */
  428. #endif /* #if defined( BSP_USING_EMAC ) */