drv_emac.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. /*
  2. * File : drv_emac.c
  3. * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. *
  19. * Change Logs:
  20. * Date Author Notes
  21. * 2017-08-08 Yang the first version
  22. */
  23. #include <rtthread.h>
  24. #include "lwipopts.h"
  25. #include <netif/ethernetif.h>
  26. #include <board.h>
  27. #include "drv_emac.h"
  28. #include "fsl_iocon.h"
  29. #include "fsl_sctimer.h"
  30. #include "fsl_phy.h"
  31. #define DEBUG
  32. //#define ETH_RX_DUMP
  33. //#define ETH_TX_DUMP
  34. #define ETH_STATISTICS
  35. #ifdef DEBUG
  36. #define ETH_PRINTF rt_kprintf
  37. #else
  38. #define ETH_PRINTF(...)
  39. #endif
  40. #define IOCON_PIO_DIGITAL_EN 0x0100u /*!< Enables digital function */
  41. #define IOCON_PIO_FUNC0 0x00u /*!< Selects pin function 0 */
  42. #define IOCON_PIO_FUNC1 0x01u /*!< Selects pin function 1 */
  43. #define IOCON_PIO_FUNC7 0x07u /*!< Selects pin function 7 */
  44. #define IOCON_PIO_INPFILT_OFF 0x0200u /*!< Input filter disabled */
  45. #define IOCON_PIO_INV_DI 0x00u /*!< Input function is not inverted */
  46. #define IOCON_PIO_MODE_INACT 0x00u /*!< No addition pin function */
  47. #define IOCON_PIO_MODE_PULLUP 0x20u /*!< Selects pull-up function */
  48. #define IOCON_PIO_OPENDRAIN_DI 0x00u /*!< Open drain is disabled */
  49. #define IOCON_PIO_SLEW_FAST 0x0400u /*!< Fast mode, slew rate control is disabled */
  50. #define IOCON_PIO_SLEW_STANDARD 0x00u /*!< Standard mode, output slew rate control is enabled */
  51. #define PIN8_IDX 8u /*!< Pin number for pin 8 in a port 4 */
  52. #define PIN10_IDX 10u /*!< Pin number for pin 10 in a port 4 */
  53. #define PIN11_IDX 11u /*!< Pin number for pin 11 in a port 4 */
  54. #define PIN12_IDX 12u /*!< Pin number for pin 12 in a port 4 */
  55. #define PIN13_IDX 13u /*!< Pin number for pin 13 in a port 4 */
  56. #define PIN14_IDX 14u /*!< Pin number for pin 14 in a port 4 */
  57. #define PIN15_IDX 15u /*!< Pin number for pin 15 in a port 4 */
  58. #define PIN16_IDX 16u /*!< Pin number for pin 16 in a port 4 */
  59. #define PIN17_IDX 17u /*!< Pin number for pin 17 in a port 0 */
  60. #define PIN26_IDX 26u /*!< Pin number for pin 26 in a port 2 */
  61. #define PIN29_IDX 29u /*!< Pin number for pin 29 in a port 0 */
  62. #define PIN30_IDX 30u /*!< Pin number for pin 30 in a port 0 */
  63. #define PORT0_IDX 0u /*!< Port index */
  64. #define PORT2_IDX 2u /*!< Port index */
  65. #define PORT4_IDX 4u /*!< Port index */
  66. #define MAX_ADDR_LEN 6u
  67. #define ENET_RXBD_NUM 4u
  68. #define ENET_TXBD_NUM 4u
  69. #define ENET_ALIGN(x) \
  70. ((unsigned int)((x) + ((ENET_BUFF_ALIGNMENT)-1)) & (unsigned int)(~(unsigned int)((ENET_BUFF_ALIGNMENT)-1)))
  71. #define ENET_RXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN)
  72. #define ENET_TXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN)
  73. struct lpc_emac
  74. {
  75. /* inherit from ethernet device */
  76. struct eth_device parent;
  77. struct rt_semaphore tx_wait;
  78. ENET_Type *base;
  79. enet_handle_t handle;
  80. /* interface address info. */
  81. rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */
  82. uint32_t phyAddr;
  83. uint8_t RxBuffDescrip[ENET_RXBD_NUM * sizeof(enet_rx_bd_struct_t) + ENET_BUFF_ALIGNMENT];
  84. uint8_t TxBuffDescrip[ENET_TXBD_NUM * sizeof(enet_tx_bd_struct_t) + ENET_BUFF_ALIGNMENT];
  85. uint8_t RxDataBuff[ENET_RXBD_NUM * ENET_ALIGN(ENET_RXBUFF_SIZE) + ENET_BUFF_ALIGNMENT];
  86. uint8_t TxDataBuff[ENET_TXBD_NUM * ENET_ALIGN(ENET_TXBUFF_SIZE) + ENET_BUFF_ALIGNMENT];
  87. uint8_t txIdx;
  88. };
  89. static struct lpc_emac lpc_emac_device;
  90. #ifdef ETH_STATISTICS
  91. static uint32_t isr_rx_counter = 0;
  92. static uint32_t isr_tx_counter = 0;
  93. #endif
  94. static inline enet_rx_bd_struct_t *get_rx_desc(uint32_t index)
  95. {
  96. return (enet_rx_bd_struct_t *)ENET_ALIGN(&lpc_emac_device.RxBuffDescrip[index * sizeof(enet_rx_bd_struct_t)]);
  97. }
  98. static inline enet_tx_bd_struct_t *get_tx_desc(uint32_t index)
  99. {
  100. return (enet_tx_bd_struct_t *)ENET_ALIGN(&lpc_emac_device.TxBuffDescrip[index * sizeof(enet_tx_bd_struct_t)]);
  101. }
  102. #if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP)
  103. static void packet_dump(const char * msg, const struct pbuf* p)
  104. {
  105. const struct pbuf* q;
  106. rt_uint32_t i,j;
  107. rt_uint8_t *ptr;
  108. rt_kprintf("%s %d byte\n", msg, p->tot_len);
  109. i=0;
  110. for(q=p; q != RT_NULL; q= q->next)
  111. {
  112. ptr = q->payload;
  113. for(j=0; j<q->len; j++)
  114. {
  115. if( (i%8) == 0 )
  116. {
  117. rt_kprintf(" ");
  118. }
  119. if( (i%16) == 0 )
  120. {
  121. rt_kprintf("\r\n");
  122. }
  123. rt_kprintf("%02x ",*ptr);
  124. i++;
  125. ptr++;
  126. }
  127. }
  128. rt_kprintf("\n\n");
  129. }
  130. #else
  131. #define packet_dump(...)
  132. #endif /* dump */
  133. static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, uint8_t channel, void *param)
  134. {
  135. switch (event)
  136. {
  137. case kENET_RxIntEvent:
  138. #ifdef ETH_STATISTICS
  139. isr_rx_counter++;
  140. #endif
  141. /* a frame has been received */
  142. eth_device_ready(&(lpc_emac_device.parent));
  143. break;
  144. case kENET_TxIntEvent:
  145. #ifdef ETH_STATISTICS
  146. isr_tx_counter++;
  147. #endif
  148. /* set event */
  149. rt_sem_release(&lpc_emac_device.tx_wait);
  150. break;
  151. default:
  152. break;
  153. }
  154. }
  155. static void lcp_emac_io_init(void)
  156. {
  157. const uint32_t port0_pin17_config = (
  158. IOCON_PIO_FUNC7 | /* Pin is configured as ENET_TXD1 */
  159. IOCON_PIO_MODE_INACT | /* No addition pin function */
  160. IOCON_PIO_INV_DI | /* Input function is not inverted */
  161. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  162. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  163. IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
  164. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  165. );
  166. IOCON_PinMuxSet(IOCON, PORT0_IDX, PIN17_IDX, port0_pin17_config); /* PORT0 PIN17 (coords: E14) is configured as ENET_TXD1 */
  167. const uint32_t port2_pin26_config = (
  168. IOCON_PIO_FUNC0 | /* Pin is configured as PIO2_26 */
  169. IOCON_PIO_MODE_PULLUP | /* Selects pull-up function */
  170. IOCON_PIO_INV_DI | /* Input function is not inverted */
  171. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  172. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  173. IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
  174. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  175. );
  176. IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN26_IDX, port2_pin26_config); /* PORT2 PIN26 (coords: H11) is configured as PIO2_26 */
  177. const uint32_t port4_pin10_config = (
  178. IOCON_PIO_FUNC1 | /* Pin is configured as ENET_RX_DV */
  179. IOCON_PIO_MODE_INACT | /* No addition pin function */
  180. IOCON_PIO_INV_DI | /* Input function is not inverted */
  181. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  182. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  183. IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
  184. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  185. );
  186. IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN10_IDX, port4_pin10_config); /* PORT4 PIN10 (coords: B9) is configured as ENET_RX_DV */
  187. const uint32_t port4_pin11_config = (
  188. IOCON_PIO_FUNC1 | /* Pin is configured as ENET_RXD0 */
  189. IOCON_PIO_MODE_INACT | /* No addition pin function */
  190. IOCON_PIO_INV_DI | /* Input function is not inverted */
  191. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  192. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  193. IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
  194. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  195. );
  196. IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN11_IDX, port4_pin11_config); /* PORT4 PIN11 (coords: A9) is configured as ENET_RXD0 */
  197. const uint32_t port4_pin12_config = (
  198. IOCON_PIO_FUNC1 | /* Pin is configured as ENET_RXD1 */
  199. IOCON_PIO_MODE_INACT | /* No addition pin function */
  200. IOCON_PIO_INV_DI | /* Input function is not inverted */
  201. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  202. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  203. IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
  204. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  205. );
  206. IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN12_IDX, port4_pin12_config); /* PORT4 PIN12 (coords: A6) is configured as ENET_RXD1 */
  207. const uint32_t port4_pin13_config = (
  208. IOCON_PIO_FUNC1 | /* Pin is configured as ENET_TX_EN */
  209. IOCON_PIO_MODE_INACT | /* No addition pin function */
  210. IOCON_PIO_INV_DI | /* Input function is not inverted */
  211. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  212. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  213. IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
  214. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  215. );
  216. IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN13_IDX, port4_pin13_config); /* PORT4 PIN13 (coords: B6) is configured as ENET_TX_EN */
  217. const uint32_t port4_pin14_config = (
  218. IOCON_PIO_FUNC1 | /* Pin is configured as ENET_RX_CLK */
  219. IOCON_PIO_MODE_INACT | /* No addition pin function */
  220. IOCON_PIO_INV_DI | /* Input function is not inverted */
  221. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  222. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  223. IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
  224. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  225. );
  226. IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN14_IDX, port4_pin14_config); /* PORT4 PIN14 (coords: B5) is configured as ENET_RX_CLK */
  227. const uint32_t port4_pin15_config = (
  228. IOCON_PIO_FUNC1 | /* Pin is configured as ENET_MDC */
  229. IOCON_PIO_MODE_INACT | /* No addition pin function */
  230. IOCON_PIO_INV_DI | /* Input function is not inverted */
  231. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  232. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  233. IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
  234. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  235. );
  236. IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN15_IDX, port4_pin15_config); /* PORT4 PIN15 (coords: A4) is configured as ENET_MDC */
  237. const uint32_t port4_pin16_config = (
  238. IOCON_PIO_FUNC1 | /* Pin is configured as ENET_MDIO */
  239. IOCON_PIO_MODE_INACT | /* No addition pin function */
  240. IOCON_PIO_INV_DI | /* Input function is not inverted */
  241. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  242. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  243. IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
  244. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  245. );
  246. IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN16_IDX, port4_pin16_config); /* PORT4 PIN16 (coords: C4) is configured as ENET_MDIO */
  247. const uint32_t port4_pin8_config = (
  248. IOCON_PIO_FUNC1 | /* Pin is configured as ENET_TXD0 */
  249. IOCON_PIO_MODE_INACT | /* No addition pin function */
  250. IOCON_PIO_INV_DI | /* Input function is not inverted */
  251. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  252. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  253. IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
  254. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  255. );
  256. IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN8_IDX, port4_pin8_config); /* PORT4 PIN8 (coords: B14) is configured as ENET_TXD0 */
  257. }
  258. static rt_err_t lpc_emac_phy_init(phy_speed_t * speed, phy_duplex_t * duplex)
  259. {
  260. bool link = false;
  261. int32_t status;
  262. RT_ASSERT(speed != NULL);
  263. RT_ASSERT(duplex != NULL);
  264. status = PHY_Init(lpc_emac_device.base, lpc_emac_device.phyAddr, 0);
  265. if (status != kStatus_Success)
  266. {
  267. /* Half duplex. */
  268. *duplex = kPHY_HalfDuplex;
  269. /* 10M speed. */
  270. *speed = kPHY_Speed10M;
  271. eth_device_linkchange(&lpc_emac_device.parent, RT_FALSE);
  272. ETH_PRINTF("PHY_Init failed!\n");
  273. return RT_ERROR;
  274. }
  275. /* Wait for link up and get the actual PHY link speed. */
  276. PHY_GetLinkStatus(lpc_emac_device.base, lpc_emac_device.phyAddr, &link);
  277. while (!link)
  278. {
  279. uint32_t timedelay;
  280. ETH_PRINTF("PHY Wait for link up!\n");
  281. for (timedelay = 0; timedelay < 0xFFFFFU; timedelay++)
  282. {
  283. __ASM("nop");
  284. }
  285. PHY_GetLinkStatus(lpc_emac_device.base, lpc_emac_device.phyAddr, &link);
  286. }
  287. PHY_GetLinkSpeedDuplex(lpc_emac_device.base, lpc_emac_device.phyAddr, speed, duplex);
  288. eth_device_linkchange(&lpc_emac_device.parent, RT_TRUE);
  289. return RT_EOK;
  290. }
  291. static rt_err_t lpc_emac_init(rt_device_t dev)
  292. {
  293. int i;
  294. phy_speed_t speed;
  295. phy_duplex_t duplex;
  296. enet_config_t config;
  297. enet_buffer_config_t buffCfg;
  298. uint32_t rxBufferStartAddr[ENET_RXBD_NUM];
  299. lcp_emac_io_init();
  300. lpc_emac_phy_init(&speed, &duplex);
  301. /* calculate start addresses of all rx buffers */
  302. for (i = 0; i < ENET_RXBD_NUM; i++)
  303. {
  304. rxBufferStartAddr[i] = ENET_ALIGN(&lpc_emac_device.RxDataBuff[i * ENET_ALIGN(ENET_RXBUFF_SIZE)]);
  305. }
  306. buffCfg.rxRingLen = ENET_RXBD_NUM;
  307. buffCfg.txRingLen = ENET_TXBD_NUM;
  308. buffCfg.txDescStartAddrAlign = get_tx_desc(0U);
  309. buffCfg.txDescTailAddrAlign = get_tx_desc(0U);
  310. buffCfg.rxDescStartAddrAlign = get_rx_desc(0U);
  311. buffCfg.rxDescTailAddrAlign = get_rx_desc(ENET_RXBD_NUM);
  312. buffCfg.rxBufferStartAddr = rxBufferStartAddr;
  313. buffCfg.rxBuffSizeAlign = ENET_ALIGN(ENET_RXBUFF_SIZE);
  314. /* Get default configuration 100M RMII. */
  315. ENET_GetDefaultConfig(&config);
  316. /* Use the actual speed and duplex when phy success to finish the autonegotiation. */
  317. config.miiSpeed = (enet_mii_speed_t)speed;
  318. config.miiDuplex = (enet_mii_duplex_t)duplex;
  319. ETH_PRINTF("Auto negotiation, Speed: ");
  320. if (config.miiSpeed == kENET_MiiSpeed100M)
  321. ETH_PRINTF("100M");
  322. else
  323. ETH_PRINTF("10M");
  324. ETH_PRINTF(", Duplex: ");
  325. if (config.miiSpeed == kENET_MiiSpeed100M)
  326. ETH_PRINTF("Full\n");
  327. else
  328. ETH_PRINTF("Half\n");
  329. /* Initialize lpc_emac_device.base. */
  330. ENET_Init(lpc_emac_device.base, &config, &lpc_emac_device.dev_addr[0], CLOCK_GetFreq(kCLOCK_CoreSysClk));
  331. /* Enable the tx/rx interrupt. */
  332. ENET_EnableInterrupts(lpc_emac_device.base, (kENET_DmaTx | kENET_DmaRx));
  333. ENET_CreateHandler(lpc_emac_device.base, &lpc_emac_device.handle, &config, &buffCfg, ethernet_callback, NULL);
  334. /* Initialize Descriptor. */
  335. ENET_DescriptorInit(lpc_emac_device.base, &config, &buffCfg);
  336. /* Active TX/RX. */
  337. ENET_StartRxTx(lpc_emac_device.base, 1, 1);
  338. return RT_EOK;
  339. }
  340. static rt_err_t lpc_emac_open(rt_device_t dev, rt_uint16_t oflag)
  341. {
  342. return RT_EOK;
  343. }
  344. static rt_err_t lpc_emac_close(rt_device_t dev)
  345. {
  346. return RT_EOK;
  347. }
  348. static rt_size_t lpc_emac_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  349. {
  350. rt_set_errno(-RT_ENOSYS);
  351. return 0;
  352. }
  353. static rt_size_t lpc_emac_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  354. {
  355. rt_set_errno(-RT_ENOSYS);
  356. return 0;
  357. }
  358. static rt_err_t lpc_emac_control(rt_device_t dev, int cmd, void *args)
  359. {
  360. switch (cmd)
  361. {
  362. case NIOCTL_GADDR:
  363. /* get mac address */
  364. if (args) rt_memcpy(args, lpc_emac_device.dev_addr, 6);
  365. else return -RT_ERROR;
  366. break;
  367. default :
  368. break;
  369. }
  370. return RT_EOK;
  371. }
  372. /* EtherNet Device Interface */
  373. /* transmit packet. */
  374. rt_err_t lpc_emac_tx(rt_device_t dev, struct pbuf *p)
  375. {
  376. rt_err_t result = RT_EOK;
  377. enet_handle_t * enet_handle = &lpc_emac_device.handle;
  378. ENET_Type *enet_base = lpc_emac_device.base;
  379. uint8_t * data;
  380. uint16_t len;
  381. RT_ASSERT(p != NULL);
  382. RT_ASSERT(enet_handle != RT_NULL);
  383. if (p->tot_len > ENET_TXBUFF_SIZE)
  384. {
  385. return RT_ERROR;
  386. }
  387. packet_dump("TX dump", p);
  388. /* get free tx buffer */
  389. {
  390. rt_err_t result;
  391. result = rt_sem_take(&lpc_emac_device.tx_wait, RT_TICK_PER_SECOND/10);
  392. if (result != RT_EOK)
  393. {
  394. return RT_ERROR;
  395. }
  396. }
  397. // fix RxDataBuff -> TxDataBuff, ENET_RXBUFF_SIZE -> ENET_TXBUFF_SIZE
  398. data = (uint8_t *)ENET_ALIGN(&lpc_emac_device.TxDataBuff[lpc_emac_device.txIdx * ENET_ALIGN(ENET_TXBUFF_SIZE)]);
  399. len = pbuf_copy_partial(p, data, p->tot_len, 0);
  400. lpc_emac_device.txIdx = (lpc_emac_device.txIdx + 1) / ENET_TXBD_NUM;
  401. // fix 'p->len' to 'len', avoid send wrong partial packet.
  402. result = ENET_SendFrame(enet_base, enet_handle, data, len);
  403. if ((result == kStatus_ENET_TxFrameFail) || (result == kStatus_ENET_TxFrameOverLen) || (result == kStatus_ENET_TxFrameBusy))
  404. {
  405. return RT_ERROR;
  406. }
  407. return RT_EOK;
  408. }
  409. /* reception packet. */
  410. struct pbuf *lpc_emac_rx(rt_device_t dev)
  411. {
  412. uint32_t length = 0;
  413. status_t status;
  414. struct pbuf* p = RT_NULL;
  415. enet_handle_t * enet_handle = &lpc_emac_device.handle;
  416. ENET_Type *enet_base = lpc_emac_device.base;
  417. /* Get the Frame size */
  418. status = ENET_GetRxFrameSize(enet_base, enet_handle, &length, 0);
  419. /* Call ENET_ReadFrame when there is a received frame. */
  420. if (length != 0)
  421. {
  422. /* Received valid frame. Deliver the rx buffer with the size equal to length. */
  423. p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL);
  424. if (p != NULL)
  425. {
  426. status = ENET_ReadFrame(enet_base, enet_handle, p->payload, length, 0);
  427. if (status == kStatus_Success)
  428. {
  429. packet_dump("RX dump", p);
  430. return p;
  431. }
  432. else
  433. {
  434. ETH_PRINTF(" A frame read failed\n");
  435. pbuf_free(p);
  436. }
  437. }
  438. else
  439. {
  440. ETH_PRINTF(" pbuf_alloc faild\n");
  441. }
  442. }
  443. else if (status == kStatus_ENET_RxFrameError)
  444. {
  445. ETH_PRINTF("ENET_GetRxFrameSize: kStatus_ENET_RxFrameError\n");
  446. ENET_ReadFrame(enet_base, enet_handle, NULL, 0, 0);
  447. }
  448. return NULL;
  449. }
  450. int lpc_emac_hw_init(void)
  451. {
  452. /* init tx semaphore */
  453. rt_sem_init(&lpc_emac_device.tx_wait, "tx_wait", ENET_TXBD_NUM, RT_IPC_FLAG_FIFO);
  454. lpc_emac_device.phyAddr = 0;
  455. lpc_emac_device.txIdx = 0;
  456. lpc_emac_device.base = ENET;
  457. // OUI 00-60-37 NXP Semiconductors
  458. lpc_emac_device.dev_addr[0] = 0x00;
  459. lpc_emac_device.dev_addr[1] = 0x60;
  460. lpc_emac_device.dev_addr[2] = 0x37;
  461. /* set mac address: (only for test) */
  462. lpc_emac_device.dev_addr[3] = 0x12;
  463. lpc_emac_device.dev_addr[4] = 0x34;
  464. lpc_emac_device.dev_addr[5] = 0x56;
  465. lpc_emac_device.parent.parent.init = lpc_emac_init;
  466. lpc_emac_device.parent.parent.open = lpc_emac_open;
  467. lpc_emac_device.parent.parent.close = lpc_emac_close;
  468. lpc_emac_device.parent.parent.read = lpc_emac_read;
  469. lpc_emac_device.parent.parent.write = lpc_emac_write;
  470. lpc_emac_device.parent.parent.control = lpc_emac_control;
  471. lpc_emac_device.parent.parent.user_data = RT_NULL;
  472. lpc_emac_device.parent.eth_rx = lpc_emac_rx;
  473. lpc_emac_device.parent.eth_tx = lpc_emac_tx;
  474. eth_device_init(&(lpc_emac_device.parent), "e0");
  475. return 0;
  476. }
  477. INIT_DEVICE_EXPORT(lpc_emac_hw_init);
  478. #ifdef ETH_STATISTICS
  479. int emac_stat(void)
  480. {
  481. rt_kprintf("enter rx isr coutner : %d\n", isr_rx_counter);
  482. rt_kprintf("enter tx isr coutner : %d\n", isr_tx_counter);
  483. return 0;
  484. }
  485. #endif
  486. void phy_dump(void)
  487. {
  488. status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr);
  489. int i;
  490. for (i = 0; i < 31; i++)
  491. {
  492. status_t result = kStatus_Success;
  493. uint32_t reg;
  494. result = PHY_Read(lpc_emac_device.base, lpc_emac_device.phyAddr, i, &reg);
  495. if (result == kStatus_Success)
  496. {
  497. rt_kprintf("%02d: %08d\n", i, reg);
  498. }
  499. else
  500. {
  501. rt_kprintf("read register %d faild\n", i);
  502. }
  503. }
  504. }
  505. void emac_dump(void)
  506. {
  507. #define DUMP_REG(__NAME) \
  508. rt_kprintf("%-40s, %08x: %08x\n", #__NAME, (uint32_t)&(lpc_emac_device.base->__NAME), lpc_emac_device.base->__NAME)
  509. DUMP_REG(MAC_CONFIG);
  510. DUMP_REG(MAC_EXT_CONFIG);
  511. DUMP_REG(MAC_FRAME_FILTER);
  512. DUMP_REG(MAC_WD_TIMEROUT);
  513. DUMP_REG(MAC_VLAN_TAG);
  514. DUMP_REG(MAC_TX_FLOW_CTRL_Q[0]);
  515. DUMP_REG(MAC_TX_FLOW_CTRL_Q[1]);
  516. DUMP_REG(MAC_RX_FLOW_CTRL);
  517. DUMP_REG(MAC_TXQ_PRIO_MAP);
  518. DUMP_REG(MAC_RXQ_CTRL[0]);
  519. DUMP_REG(MAC_RXQ_CTRL[1]);
  520. DUMP_REG(MAC_RXQ_CTRL[2]);
  521. DUMP_REG(MAC_INTR_STAT);
  522. DUMP_REG(MAC_INTR_EN);
  523. DUMP_REG(MAC_RXTX_STAT);
  524. DUMP_REG(MAC_PMT_CRTL_STAT);
  525. DUMP_REG(MAC_RWAKE_FRFLT);
  526. DUMP_REG(MAC_LPI_CTRL_STAT);
  527. DUMP_REG(MAC_LPI_TIMER_CTRL);
  528. DUMP_REG(MAC_LPI_ENTR_TIMR);
  529. DUMP_REG(MAC_1US_TIC_COUNTR);
  530. DUMP_REG(MAC_VERSION);
  531. DUMP_REG(MAC_DBG);
  532. DUMP_REG(MAC_HW_FEAT[0]);
  533. DUMP_REG(MAC_HW_FEAT[1]);
  534. DUMP_REG(MAC_HW_FEAT[2]);
  535. DUMP_REG(MAC_MDIO_ADDR);
  536. DUMP_REG(MAC_MDIO_DATA);
  537. DUMP_REG(MAC_ADDR_HIGH);
  538. DUMP_REG(MAC_ADDR_LOW);
  539. DUMP_REG(MAC_TIMESTAMP_CTRL);
  540. DUMP_REG(MAC_SUB_SCND_INCR);
  541. DUMP_REG(MAC_SYS_TIME_SCND);
  542. DUMP_REG(MAC_SYS_TIME_NSCND);
  543. DUMP_REG(MAC_SYS_TIME_SCND_UPD);
  544. DUMP_REG(MAC_SYS_TIME_NSCND_UPD);
  545. DUMP_REG(MAC_SYS_TIMESTMP_ADDEND);
  546. DUMP_REG(MAC_SYS_TIME_HWORD_SCND);
  547. DUMP_REG(MAC_SYS_TIMESTMP_STAT);
  548. DUMP_REG(MAC_TX_TIMESTAMP_STATUS_NANOSECONDS);
  549. DUMP_REG(MAC_TX_TIMESTAMP_STATUS_SECONDS);
  550. DUMP_REG(MAC_TIMESTAMP_INGRESS_CORR_NANOSECOND);
  551. DUMP_REG(MAC_TIMESTAMP_EGRESS_CORR_NANOSECOND);
  552. DUMP_REG(MTL_OP_MODE);
  553. DUMP_REG(MTL_INTR_STAT);
  554. DUMP_REG(MTL_RXQ_DMA_MAP);
  555. DUMP_REG(DMA_MODE);
  556. DUMP_REG(DMA_SYSBUS_MODE);
  557. DUMP_REG(DMA_INTR_STAT);
  558. DUMP_REG(DMA_DBG_STAT);
  559. DUMP_REG(MTL_QUEUE[0].MTL_TXQX_OP_MODE);
  560. DUMP_REG(MTL_QUEUE[0].MTL_TXQX_UNDRFLW);
  561. DUMP_REG(MTL_QUEUE[0].MTL_TXQX_DBG);
  562. DUMP_REG(MTL_QUEUE[0].MTL_TXQX_ETS_CTRL);
  563. DUMP_REG(MTL_QUEUE[0].MTL_TXQX_ETS_STAT);
  564. DUMP_REG(MTL_QUEUE[0].MTL_TXQX_QNTM_WGHT);
  565. DUMP_REG(MTL_QUEUE[0].MTL_TXQX_SNDSLP_CRDT);
  566. DUMP_REG(MTL_QUEUE[0].MTL_TXQX_HI_CRDT);
  567. DUMP_REG(MTL_QUEUE[0].MTL_TXQX_LO_CRDT);
  568. DUMP_REG(MTL_QUEUE[0].MTL_TXQX_INTCTRL_STAT);
  569. DUMP_REG(MTL_QUEUE[0].MTL_RXQX_OP_MODE);
  570. DUMP_REG(MTL_QUEUE[0].MTL_RXQX_MISSPKT_OVRFLW_CNT);
  571. DUMP_REG(MTL_QUEUE[0].MTL_RXQX_DBG);
  572. DUMP_REG(MTL_QUEUE[0].MTL_RXQX_CTRL);
  573. DUMP_REG(MTL_QUEUE[1].MTL_TXQX_OP_MODE);
  574. DUMP_REG(MTL_QUEUE[1].MTL_TXQX_UNDRFLW);
  575. DUMP_REG(MTL_QUEUE[1].MTL_TXQX_DBG);
  576. DUMP_REG(MTL_QUEUE[1].MTL_TXQX_ETS_CTRL);
  577. DUMP_REG(MTL_QUEUE[1].MTL_TXQX_ETS_STAT);
  578. DUMP_REG(MTL_QUEUE[1].MTL_TXQX_QNTM_WGHT);
  579. DUMP_REG(MTL_QUEUE[1].MTL_TXQX_SNDSLP_CRDT);
  580. DUMP_REG(MTL_QUEUE[1].MTL_TXQX_HI_CRDT);
  581. DUMP_REG(MTL_QUEUE[1].MTL_TXQX_LO_CRDT);
  582. DUMP_REG(MTL_QUEUE[1].MTL_TXQX_INTCTRL_STAT);
  583. DUMP_REG(MTL_QUEUE[1].MTL_RXQX_OP_MODE);
  584. DUMP_REG(MTL_QUEUE[1].MTL_RXQX_MISSPKT_OVRFLW_CNT);
  585. DUMP_REG(MTL_QUEUE[1].MTL_RXQX_DBG);
  586. DUMP_REG(MTL_QUEUE[1].MTL_RXQX_CTRL);
  587. DUMP_REG(DMA_CH[0].DMA_CHX_CTRL);
  588. DUMP_REG(DMA_CH[0].DMA_CHX_TX_CTRL);
  589. DUMP_REG(DMA_CH[0].DMA_CHX_RX_CTRL);
  590. DUMP_REG(DMA_CH[0].DMA_CHX_TXDESC_LIST_ADDR);
  591. DUMP_REG(DMA_CH[0].DMA_CHX_RXDESC_LIST_ADDR);
  592. DUMP_REG(DMA_CH[0].DMA_CHX_TXDESC_TAIL_PTR);
  593. DUMP_REG(DMA_CH[0].DMA_CHX_RXDESC_TAIL_PTR);
  594. DUMP_REG(DMA_CH[0].DMA_CHX_TXDESC_RING_LENGTH);
  595. DUMP_REG(DMA_CH[0].DMA_CHX_RXDESC_RING_LENGTH);
  596. DUMP_REG(DMA_CH[0].DMA_CHX_INT_EN);
  597. DUMP_REG(DMA_CH[0].DMA_CHX_RX_INT_WDTIMER);
  598. DUMP_REG(DMA_CH[0].DMA_CHX_SLOT_FUNC_CTRL_STAT);
  599. DUMP_REG(DMA_CH[0].DMA_CHX_CUR_HST_TXDESC);
  600. DUMP_REG(DMA_CH[0].DMA_CHX_CUR_HST_RXDESC);
  601. DUMP_REG(DMA_CH[0].DMA_CHX_CUR_HST_TXBUF);
  602. DUMP_REG(DMA_CH[0].DMA_CHX_CUR_HST_RXBUF);
  603. DUMP_REG(DMA_CH[0].DMA_CHX_STAT);
  604. DUMP_REG(DMA_CH[1].DMA_CHX_CTRL);
  605. DUMP_REG(DMA_CH[1].DMA_CHX_TX_CTRL);
  606. DUMP_REG(DMA_CH[1].DMA_CHX_RX_CTRL);
  607. DUMP_REG(DMA_CH[1].DMA_CHX_TXDESC_LIST_ADDR);
  608. DUMP_REG(DMA_CH[1].DMA_CHX_RXDESC_LIST_ADDR);
  609. DUMP_REG(DMA_CH[1].DMA_CHX_TXDESC_TAIL_PTR);
  610. DUMP_REG(DMA_CH[1].DMA_CHX_RXDESC_TAIL_PTR);
  611. DUMP_REG(DMA_CH[1].DMA_CHX_TXDESC_RING_LENGTH);
  612. DUMP_REG(DMA_CH[1].DMA_CHX_RXDESC_RING_LENGTH);
  613. DUMP_REG(DMA_CH[1].DMA_CHX_INT_EN);
  614. DUMP_REG(DMA_CH[1].DMA_CHX_RX_INT_WDTIMER);
  615. DUMP_REG(DMA_CH[1].DMA_CHX_SLOT_FUNC_CTRL_STAT);
  616. DUMP_REG(DMA_CH[1].DMA_CHX_CUR_HST_TXDESC);
  617. DUMP_REG(DMA_CH[1].DMA_CHX_CUR_HST_RXDESC);
  618. DUMP_REG(DMA_CH[1].DMA_CHX_CUR_HST_TXBUF);
  619. DUMP_REG(DMA_CH[1].DMA_CHX_CUR_HST_RXBUF);
  620. DUMP_REG(DMA_CH[1].DMA_CHX_STAT);
  621. }
  622. void emac_bd_dump(void)
  623. {
  624. int i;
  625. rt_kprintf("rx bd dump: \n");
  626. for (i = 0; i < ENET_RXBD_NUM; i++)
  627. {
  628. enet_rx_bd_struct_t * rx_bd = get_rx_desc(i);
  629. rt_kprintf("buf1: %p, buf2: %p, ctrl: %08x\n",
  630. rx_bd->buff1Addr,
  631. rx_bd->buff2Addr,
  632. rx_bd->control);
  633. }
  634. rt_kprintf("tx bd dump: \n");
  635. for (i = 0; i < ENET_TXBD_NUM; i++)
  636. {
  637. enet_tx_bd_struct_t * tx_bd = get_tx_desc(i);
  638. rt_kprintf("buf1: %p, buf2: %p, len: %08x, ctrl: %08x\n",
  639. tx_bd->buff1Addr,
  640. tx_bd->buff2Addr,
  641. tx_bd->buffLen,
  642. tx_bd->controlStat);
  643. }
  644. }
  645. #ifdef RT_USING_FINSH
  646. #include <finsh.h>
  647. FINSH_FUNCTION_EXPORT(emac_stat, dump emac stat data);
  648. FINSH_FUNCTION_EXPORT(phy_dump, dump phy registers);
  649. FINSH_FUNCTION_EXPORT(emac_dump, dump emac registers);
  650. FINSH_FUNCTION_EXPORT(emac_bd_dump, dump emac tx and rx descriptor);
  651. #endif