drv_emac.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. /*
  2. * COPYRIGHT (C) 2018, Real-Thread Information Technology Ltd
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2015-07-15 Bernard The first version
  9. */
  10. #include <board.h>
  11. #include <rtthread.h>
  12. #include "drv_emac.h"
  13. #if defined(RT_USING_LWIP)
  14. #include <finsh.h>
  15. #include <stdint.h>
  16. #include <netif/ethernetif.h>
  17. #include <lwip/opt.h>
  18. #include "MK64F12.h"
  19. #include "fsl_port.h"
  20. #include "fsl_enet.h"
  21. #include "fsl_phy.h"
  22. //#define DRV_EMAC_DEBUG
  23. //#define DRV_EMAC_RX_DUMP
  24. //#define DRV_EMAC_TX_DUMP
  25. #ifdef DRV_EMAC_DEBUG
  26. #define DEBUG_PRINTF(...) rt_kprintf(__VA_ARGS__)
  27. #else
  28. #define DEBUG_PRINTF(...)
  29. #endif
  30. #define MAX_ADDR_LEN 6
  31. #define ENET_RX_RING_LEN (16)
  32. #define ENET_TX_RING_LEN (8)
  33. #define K64_EMAC_DEVICE(eth) (struct emac_device*)(eth)
  34. #define ENET_ALIGN(x) \
  35. ((unsigned int)((x) + ((ENET_BUFF_ALIGNMENT)-1)) & (unsigned int)(~(unsigned int)((ENET_BUFF_ALIGNMENT)-1)))
  36. #define ENET_RXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN)
  37. #define ENET_TXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN)
  38. #define ENET_ETH_MAX_FLEN (1522) // recommended size for a VLAN frame
  39. struct emac_device
  40. {
  41. /* inherit from Ethernet device */
  42. struct eth_device parent;
  43. rt_align(64) enet_rx_bd_struct_t RxBuffDescrip[ENET_RX_RING_LEN];
  44. rt_align(64) enet_tx_bd_struct_t TxBuffDescrip[ENET_TX_RING_LEN];
  45. rt_align(64) uint8_t RxDataBuff[ENET_RX_RING_LEN * ENET_ALIGN(ENET_RXBUFF_SIZE)];
  46. rt_align(64) uint8_t TxDataBuff[ENET_TX_RING_LEN * ENET_ALIGN(ENET_TXBUFF_SIZE)];
  47. enet_handle_t enet_handle;
  48. rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* MAC address */
  49. struct rt_semaphore tx_wait;
  50. };
  51. static struct emac_device _emac;
  52. static void setup_k64_io_enet(void)
  53. {
  54. port_pin_config_t configENET = {0};
  55. #ifndef FEATURE_UVISOR
  56. /* Disable MPU only when uVisor is not around. */
  57. SYSMPU->CESR &= ~SYSMPU_CESR_VLD_MASK;
  58. #endif/*FEATURE_UVISOR*/
  59. /* Affects PORTC_PCR16 register */
  60. PORT_SetPinMux(PORTC, 16u, kPORT_MuxAlt4);
  61. /* Affects PORTC_PCR17 register */
  62. PORT_SetPinMux(PORTC, 17u, kPORT_MuxAlt4);
  63. /* Affects PORTC_PCR18 register */
  64. PORT_SetPinMux(PORTC, 18u, kPORT_MuxAlt4);
  65. /* Affects PORTC_PCR19 register */
  66. PORT_SetPinMux(PORTC, 19u, kPORT_MuxAlt4);
  67. /* Affects PORTB_PCR1 register */
  68. PORT_SetPinMux(PORTB, 1u, kPORT_MuxAlt4);
  69. configENET.openDrainEnable = kPORT_OpenDrainEnable;
  70. configENET.mux = kPORT_MuxAlt4;
  71. configENET.pullSelect = kPORT_PullUp;
  72. /* Ungate the port clock */
  73. CLOCK_EnableClock(kCLOCK_PortA);
  74. /* Affects PORTB_PCR0 register */
  75. PORT_SetPinConfig(PORTB, 0u, &configENET);
  76. /* Affects PORTA_PCR13 register */
  77. PORT_SetPinMux(PORTA, 13u, kPORT_MuxAlt4);
  78. /* Affects PORTA_PCR12 register */
  79. PORT_SetPinMux(PORTA, 12u, kPORT_MuxAlt4);
  80. /* Affects PORTA_PCR14 register */
  81. PORT_SetPinMux(PORTA, 14u, kPORT_MuxAlt4);
  82. /* Affects PORTA_PCR5 register */
  83. PORT_SetPinMux(PORTA, 5u, kPORT_MuxAlt4);
  84. /* Affects PORTA_PCR16 register */
  85. PORT_SetPinMux(PORTA, 16u, kPORT_MuxAlt4);
  86. /* Affects PORTA_PCR17 register */
  87. PORT_SetPinMux(PORTA, 17u, kPORT_MuxAlt4);
  88. /* Affects PORTA_PCR15 register */
  89. PORT_SetPinMux(PORTA, 15u, kPORT_MuxAlt4);
  90. /* Affects PORTA_PCR28 register */
  91. PORT_SetPinMux(PORTA, 28u, kPORT_MuxAlt4);
  92. }
  93. static void setup_enet_clock_init(void)
  94. {
  95. CLOCK_EnableClock(kCLOCK_PortC);
  96. CLOCK_EnableClock(kCLOCK_PortB);
  97. /* Select the Ethernet timestamp clock source */
  98. CLOCK_SetEnetTime0Clock(0x2);
  99. }
  100. static void enet_mac_rx_isr(struct emac_device* emac)
  101. {
  102. rt_err_t result;
  103. result = eth_device_ready(&(_emac.parent));
  104. if( result != RT_EOK )
  105. {
  106. DEBUG_PRINTF("RX err =%d\n", result );
  107. }
  108. }
  109. static void enet_mac_tx_isr(struct emac_device* emac)
  110. {
  111. rt_sem_release(&emac->tx_wait);
  112. }
  113. static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *param)
  114. {
  115. struct emac_device* emac = param;
  116. switch (event)
  117. {
  118. case kENET_RxEvent:
  119. enet_mac_rx_isr(emac);
  120. break;
  121. case kENET_TxEvent:
  122. enet_mac_tx_isr(emac);
  123. break;
  124. default:
  125. break;
  126. }
  127. }
  128. static rt_err_t k64_emac_init(rt_device_t dev)
  129. {
  130. struct emac_device* emac = K64_EMAC_DEVICE(dev);
  131. enet_handle_t * enet_handle = &emac->enet_handle;
  132. bool link = false;
  133. uint32_t phyAddr = 0;
  134. phy_speed_t phy_speed;
  135. phy_duplex_t phy_duplex;
  136. uint32_t sysClock;
  137. enet_buffer_config_t buffCfg;
  138. enet_config_t config;
  139. /* initialize config according to emac device */
  140. setup_enet_clock_init();
  141. /* enable iomux and clock */
  142. setup_k64_io_enet();
  143. /* prepare the buffer configuration. */
  144. buffCfg.rxBdNumber = ENET_RX_RING_LEN; /* Receive buffer descriptor number. */
  145. buffCfg.txBdNumber = ENET_TX_RING_LEN; /* Transmit buffer descriptor number. */
  146. buffCfg.rxBuffSizeAlign = ENET_ALIGN(ENET_RXBUFF_SIZE); /* Aligned receive data buffer size. */
  147. buffCfg.txBuffSizeAlign = ENET_ALIGN(ENET_TXBUFF_SIZE); /* Aligned transmit data buffer size. */
  148. buffCfg.rxBdStartAddrAlign = emac->RxBuffDescrip; /* Aligned receive buffer descriptor start address. */
  149. buffCfg.txBdStartAddrAlign = emac->TxBuffDescrip; /* Aligned transmit buffer descriptor start address. */
  150. buffCfg.rxBufferAlign = emac->RxDataBuff; /* Receive data buffer start address. */
  151. buffCfg.txBufferAlign = emac->TxDataBuff; /* Transmit data buffer start address. */
  152. sysClock = CLOCK_GetFreq(kCLOCK_CoreSysClk);
  153. DEBUG_PRINTF("sysClock: %d\n", sysClock);
  154. ENET_GetDefaultConfig(&config);
  155. PHY_Init(ENET, 0, CLOCK_GetFreq(kCLOCK_CoreSysClk));
  156. if (PHY_GetLinkStatus(ENET, phyAddr, &link) == kStatus_Success)
  157. {
  158. if (link)
  159. {
  160. DEBUG_PRINTF("phy link up\n");
  161. /* Get link information from PHY */
  162. PHY_GetLinkSpeedDuplex(ENET, phyAddr, &phy_speed, &phy_duplex);
  163. /* Change the MII speed and duplex for actual link status. */
  164. config.miiSpeed = (enet_mii_speed_t)phy_speed;
  165. config.miiDuplex = (enet_mii_duplex_t)phy_duplex;
  166. config.interrupt = kENET_RxFrameInterrupt | kENET_TxFrameInterrupt;
  167. }
  168. else
  169. {
  170. DEBUG_PRINTF("phy link down\n");
  171. }
  172. config.rxMaxFrameLen = ENET_ETH_MAX_FLEN;
  173. config.macSpecialConfig = kENET_ControlFlowControlEnable;
  174. config.txAccelerConfig = 0;
  175. config.rxAccelerConfig = kENET_RxAccelMacCheckEnabled;
  176. ENET_Init(ENET, enet_handle, &config, &buffCfg, emac->dev_addr, sysClock);
  177. ENET_SetCallback(enet_handle, ethernet_callback, emac);
  178. ENET_ActiveRead(ENET);
  179. }
  180. else
  181. {
  182. DEBUG_PRINTF("read phy failed\n");
  183. }
  184. return RT_EOK;
  185. }
  186. static rt_err_t k64_emac_open(rt_device_t dev, rt_uint16_t oflag)
  187. {
  188. return RT_EOK;
  189. }
  190. static rt_err_t k64_emac_close(rt_device_t dev)
  191. {
  192. return RT_EOK;
  193. }
  194. static rt_size_t k64_emac_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
  195. {
  196. rt_set_errno(-RT_ENOSYS);
  197. return 0;
  198. }
  199. static rt_size_t k64_emac_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
  200. {
  201. rt_set_errno(-RT_ENOSYS);
  202. return 0;
  203. }
  204. static rt_err_t k64_emac_control(rt_device_t dev, int cmd, void *args)
  205. {
  206. struct emac_device *emac;
  207. DEBUG_PRINTF("k64_emac_control\n");
  208. emac = K64_EMAC_DEVICE(dev);
  209. RT_ASSERT(emac != RT_NULL);
  210. switch(cmd)
  211. {
  212. case NIOCTL_GADDR:
  213. /* get MAC address */
  214. if(args) rt_memcpy(args, emac->dev_addr, 6);
  215. else return -RT_ERROR;
  216. break;
  217. default :
  218. break;
  219. }
  220. return RT_EOK;
  221. }
  222. static rt_err_t k64_emac_tx(rt_device_t dev, struct pbuf* p)
  223. {
  224. rt_err_t result = RT_EOK;
  225. struct emac_device *emac = K64_EMAC_DEVICE(dev);
  226. enet_handle_t * enet_handle = &emac->enet_handle;
  227. RT_ASSERT(p != NULL);
  228. DEBUG_PRINTF("k64_emac_tx: %d\n", p->len);
  229. emac = K64_EMAC_DEVICE(dev);
  230. RT_ASSERT(emac != RT_NULL);
  231. #ifdef DRV_EMAC_RX_DUMP
  232. {
  233. int i;
  234. uint8_t * buf;
  235. buf = (uint8_t *)p->payload;
  236. for (i = 0; i < p->len; i++)
  237. {
  238. DEBUG_PRINTF("%02X ", buf[i]);
  239. if (i % 16 == 15)
  240. DEBUG_PRINTF("\n");
  241. }
  242. DEBUG_PRINTF("\n");
  243. }
  244. #endif
  245. do
  246. {
  247. result = ENET_SendFrame(ENET, enet_handle, p->payload, p->len);
  248. if (result == kStatus_ENET_TxFrameBusy)
  249. {
  250. rt_sem_take(&emac->tx_wait, RT_WAITING_FOREVER);
  251. }
  252. } while (result == kStatus_ENET_TxFrameBusy);
  253. return RT_EOK;
  254. }
  255. struct pbuf *k64_emac_rx(rt_device_t dev)
  256. {
  257. uint32_t length = 0;
  258. status_t status;
  259. enet_data_error_stats_t eErrStatic;
  260. struct pbuf* p = RT_NULL;
  261. struct emac_device *emac = K64_EMAC_DEVICE(dev);
  262. enet_handle_t * enet_handle = &emac->enet_handle;
  263. RT_ASSERT(emac != RT_NULL);
  264. DEBUG_PRINTF("k64_emac_rx\n");
  265. /* Get the Frame size */
  266. status = ENET_GetRxFrameSize(enet_handle, &length);
  267. if (status == kStatus_ENET_RxFrameError)
  268. {
  269. /* Update the received buffer when error happened. */
  270. /* Get the error information of the received g_frame. */
  271. ENET_GetRxErrBeforeReadFrame(enet_handle, &eErrStatic);
  272. /* update the receive buffer. */
  273. ENET_ReadFrame(ENET, enet_handle, NULL, 0);
  274. DEBUG_PRINTF("receive frame faild\n");
  275. return p;
  276. }
  277. /* Call ENET_ReadFrame when there is a received frame. */
  278. if (length != 0)
  279. {
  280. /* Received valid frame. Deliver the rx buffer with the size equal to length. */
  281. p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL);
  282. }
  283. if (p != NULL)
  284. {
  285. status = ENET_ReadFrame(ENET, enet_handle, p->payload, length);
  286. if (status == kStatus_Success)
  287. {
  288. #ifdef DRV_EMAC_RX_DUMP
  289. uint8_t *buf;
  290. int i;
  291. DEBUG_PRINTF(" A frame received. the length:%d\n", p->len);
  292. buf = (uint8_t *)p->payload;
  293. for (i = 0; i < p->len; i++)
  294. {
  295. DEBUG_PRINTF("%02X ", buf[i]);
  296. if (i % 16 == 15)
  297. DEBUG_PRINTF("\n");
  298. }
  299. DEBUG_PRINTF("\n");
  300. #endif
  301. }
  302. else
  303. {
  304. DEBUG_PRINTF(" A frame read failed\n");
  305. pbuf_free(p);
  306. }
  307. }
  308. return p;
  309. }
  310. int drv_emac_hw_init(void)
  311. {
  312. /* use the test MAC address */
  313. _emac.dev_addr[0] = 0x00;
  314. _emac.dev_addr[1] = 0x04;
  315. _emac.dev_addr[2] = 0x9f;
  316. _emac.dev_addr[3] = 0xc4;
  317. _emac.dev_addr[4] = 0x44;
  318. _emac.dev_addr[5] = 0x22;
  319. _emac.parent.parent.init = k64_emac_init;
  320. _emac.parent.parent.open = k64_emac_open;
  321. _emac.parent.parent.close = k64_emac_close;
  322. _emac.parent.parent.read = k64_emac_read;
  323. _emac.parent.parent.write = k64_emac_write;
  324. _emac.parent.parent.control = k64_emac_control;
  325. _emac.parent.parent.user_data = RT_NULL;
  326. _emac.parent.eth_rx = k64_emac_rx;
  327. _emac.parent.eth_tx = k64_emac_tx;
  328. /* init tx semaphore */
  329. rt_sem_init(&_emac.tx_wait, "tx_wait", ENET_TX_RING_LEN - 1, RT_IPC_FLAG_FIFO);
  330. /* register ETH device */
  331. eth_device_init(&(_emac.parent), "e0");
  332. return 0;
  333. }
  334. INIT_DEVICE_EXPORT(drv_emac_hw_init);
  335. #ifdef DRV_EMAC_DEBUG
  336. long k64_dump_tx_bd(void)
  337. {
  338. int i;
  339. enet_tx_bd_struct_t *txbd = _emac.TxBuffDescrip;
  340. for (i = 0; i < ENET_RX_RING_LEN; i++)
  341. {
  342. DEBUG_PRINTF("status: %04X, length: %04X, data: %08X\n", txbd[i].control, txbd[i].length, (uint32_t)txbd[i].buffer);
  343. }
  344. return 0;
  345. }
  346. FINSH_FUNCTION_EXPORT(k64_dump_tx_bd, dump all receive buffer descriptor);
  347. MSH_CMD_EXPORT(k64_dump_tx_bd, dump all receive buffer descriptor);
  348. long k64_dump_rx_bd(void)
  349. {
  350. int i;
  351. enet_rx_bd_struct_t *rxbd = _emac.RxBuffDescrip;
  352. for (i = 0; i < ENET_RX_RING_LEN; i++)
  353. {
  354. DEBUG_PRINTF("bd:%08X, ", (void *)&rxbd[i]);
  355. //rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, (void *)&rxbd[i], sizeof(enet_rx_bd_struct_t));
  356. DEBUG_PRINTF("status:%04X, length:%04X, data:%08X ", rxbd[i].control, rxbd[i].length, (uint32_t)rxbd[i].buffer);
  357. #ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
  358. DEBUG_PRINTF("ce:%04X/%04X/%04X ", rxbd[i].controlExtend0, rxbd[i].controlExtend1, rxbd[i].controlExtend2);
  359. DEBUG_PRINTF("crc:%04X, len:%04X, type:%04X, ts:%04X", rxbd[i].payloadCheckSum, rxbd[i].headerLength, rxbd[i].protocolTyte, rxbd[i].timestamp);
  360. #endif
  361. DEBUG_PRINTF("\n");
  362. }
  363. return 0;
  364. }
  365. FINSH_FUNCTION_EXPORT(k64_dump_rx_bd, dump all receive buffer descriptor);
  366. MSH_CMD_EXPORT(k64_dump_rx_bd, dump all receive buffer descriptor);
  367. #endif
  368. #endif