drv_eth.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2018-11-19 SummerGift first version
  9. * 2018-12-25 zylx fix some bugs
  10. * 2019-06-10 SummerGift optimize PHY state detection process
  11. * 2019-09-03 xiaofan optimize link change detection process
  12. */
  13. #include "drv_config.h"
  14. #include "drv_eth.h"
  15. #include <hal_data.h>
  16. #include <netif/ethernetif.h>
  17. #include <lwipopts.h>
  18. /*
  19. * Emac driver uses CubeMX tool to generate emac and phy's configuration,
  20. * the configuration files can be found in CubeMX_Config folder.
  21. */
  22. /* debug option */
  23. //#define ETH_RX_DUMP
  24. //#define ETH_TX_DUMP
  25. #define MINIMUM_ETHERNET_FRAME_SIZE (60U)
  26. #define ETH_MAX_PACKET_SIZE 1514
  27. #define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE
  28. #define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE
  29. //#define DRV_DEBUG
  30. #define LOG_TAG "drv.eth"
  31. #ifdef DRV_DEBUG
  32. #define DBG_LVL DBG_LOG
  33. #else
  34. #define DBG_LVL DBG_INFO
  35. #endif /* DRV_DEBUG */
  36. #include <rtdbg.h>
  37. #define MAX_ADDR_LEN 6
  38. #undef PHY_FULL_DUPLEX
  39. #define PHY_LINK (1 << 0)
  40. #define PHY_100M (1 << 1)
  41. #define PHY_FULL_DUPLEX (1 << 2)
  42. struct rt_ra6m3_eth
  43. {
  44. /* inherit from ethernet device */
  45. struct eth_device parent;
  46. #ifndef PHY_USING_INTERRUPT_MODE
  47. rt_timer_t poll_link_timer;
  48. #endif
  49. };
  50. static rt_uint8_t *Rx_Buff, *Tx_Buff;
  51. //static ETH_HandleTypeDef EthHandle;
  52. static struct rt_ra6m3_eth ra6m3_eth_device;
  53. #if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP)
  54. #define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
  55. static void dump_hex(const rt_uint8_t *ptr, rt_size_t buflen)
  56. {
  57. unsigned char *buf = (unsigned char *)ptr;
  58. int i, j;
  59. for (i = 0; i < buflen; i += 16)
  60. {
  61. rt_kprintf("%08X: ", i);
  62. for (j = 0; j < 16; j++)
  63. if (i + j < buflen)
  64. rt_kprintf("%02X ", buf[i + j]);
  65. else
  66. rt_kprintf(" ");
  67. rt_kprintf(" ");
  68. for (j = 0; j < 16; j++)
  69. if (i + j < buflen)
  70. rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
  71. rt_kprintf("\n");
  72. }
  73. }
  74. #endif
  75. extern void phy_reset(void);
  76. /* EMAC initialization function */
  77. static rt_err_t rt_ra6m3_eth_init(void)
  78. {
  79. fsp_err_t res;
  80. res = R_ETHER_Open(&g_ether0_ctrl, &g_ether0_cfg);
  81. if (res != FSP_SUCCESS)
  82. LOG_W("R_ETHER_Open failed!, res = %d", res);
  83. return RT_EOK;
  84. }
  85. static rt_err_t rt_ra6m3_eth_open(rt_device_t dev, rt_uint16_t oflag)
  86. {
  87. LOG_D("emac open");
  88. return RT_EOK;
  89. }
  90. static rt_err_t rt_ra6m3_eth_close(rt_device_t dev)
  91. {
  92. LOG_D("emac close");
  93. return RT_EOK;
  94. }
  95. static rt_ssize_t rt_ra6m3_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  96. {
  97. LOG_D("emac read");
  98. rt_set_errno(-RT_ENOSYS);
  99. return 0;
  100. }
  101. static rt_ssize_t rt_ra6m3_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  102. {
  103. LOG_D("emac write");
  104. rt_set_errno(-RT_ENOSYS);
  105. return 0;
  106. }
  107. static rt_err_t rt_ra6m3_eth_control(rt_device_t dev, int cmd, void *args)
  108. {
  109. switch (cmd)
  110. {
  111. case NIOCTL_GADDR:
  112. /* get mac address */
  113. if (args)
  114. {
  115. SMEMCPY(args, g_ether0_ctrl.p_ether_cfg->p_mac_address, 6);
  116. }
  117. else
  118. {
  119. return -RT_ERROR;
  120. }
  121. break;
  122. default :
  123. break;
  124. }
  125. return RT_EOK;
  126. }
  127. /* ethernet device interface */
  128. /* transmit data*/
  129. rt_err_t rt_ra6m3_eth_tx(rt_device_t dev, struct pbuf *p)
  130. {
  131. fsp_err_t res;
  132. struct pbuf *q;
  133. uint8_t *buffer = Tx_Buff;
  134. uint32_t framelength = 0;
  135. uint32_t bufferoffset = 0;
  136. uint32_t byteslefttocopy = 0;
  137. uint32_t payloadoffset = 0;
  138. bufferoffset = 0;
  139. LOG_D("send frame len : %d", p->tot_len);
  140. /* copy frame from pbufs to driver buffers */
  141. for (q = p; q != NULL; q = q->next)
  142. {
  143. /* Get bytes in current lwIP buffer */
  144. byteslefttocopy = q->len;
  145. payloadoffset = 0;
  146. /* Check if the length of data to copy is bigger than Tx buffer size*/
  147. while ((byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE)
  148. {
  149. /* Copy data to Tx buffer*/
  150. SMEMCPY((uint8_t *)((uint8_t *)buffer + bufferoffset), (uint8_t *)((uint8_t *)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset));
  151. byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);
  152. payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);
  153. framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);
  154. bufferoffset = 0;
  155. }
  156. /* Copy the remaining bytes */
  157. SMEMCPY((uint8_t *)((uint8_t *)buffer + bufferoffset), (uint8_t *)((uint8_t *)q->payload + payloadoffset), byteslefttocopy);
  158. bufferoffset = bufferoffset + byteslefttocopy;
  159. framelength = framelength + byteslefttocopy;
  160. }
  161. #ifdef ETH_TX_DUMP
  162. dump_hex(buffer, p->tot_len);
  163. #endif
  164. #ifdef ETH_RX_DUMP
  165. if (p)
  166. {
  167. LOG_E("******p buf frame *********");
  168. for (q = p; q != NULL; q = q->next)
  169. {
  170. dump_hex(q->payload, q->len);
  171. }
  172. }
  173. #endif
  174. res = R_ETHER_Write(&g_ether0_ctrl, buffer, p->tot_len);//>MINIMUM_ETHERNET_FRAME_SIZE?p->tot_len:MINIMUM_ETHERNET_FRAME_SIZE);
  175. if (res != FSP_SUCCESS)
  176. LOG_W("R_ETHER_Write failed!, res = %d", res);
  177. return RT_EOK;
  178. }
  179. /* receive data*/
  180. struct pbuf *rt_ra6m3_eth_rx(rt_device_t dev)
  181. {
  182. struct pbuf *p = NULL;
  183. struct pbuf *q = NULL;
  184. uint32_t len = 0;
  185. uint8_t *buffer = Rx_Buff;
  186. fsp_err_t res;
  187. res = R_ETHER_Read(&g_ether0_ctrl, buffer, &len);
  188. if (res != FSP_SUCCESS)
  189. LOG_D("R_ETHER_Read failed!, res = %d", res);
  190. uint32_t bufferoffset = 0;
  191. uint32_t payloadoffset = 0;
  192. uint32_t byteslefttocopy = 0;
  193. LOG_D("receive frame len : %d", len);
  194. if (len > 0)
  195. {
  196. /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
  197. p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
  198. }
  199. #ifdef ETH_RX_DUMP
  200. if (p)
  201. {
  202. dump_hex(buffer, p->tot_len);
  203. }
  204. #endif
  205. if (p != NULL)
  206. {
  207. bufferoffset = 0;
  208. for (q = p; q != NULL; q = q->next)
  209. {
  210. byteslefttocopy = q->len;
  211. payloadoffset = 0;
  212. /* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/
  213. while ((byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE)
  214. {
  215. /* Copy data to pbuf */
  216. SMEMCPY((uint8_t *)((uint8_t *)q->payload + payloadoffset), (uint8_t *)((uint8_t *)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));
  217. byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
  218. payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
  219. bufferoffset = 0;
  220. }
  221. /* Copy remaining data in pbuf */
  222. SMEMCPY((uint8_t *)((uint8_t *)q->payload + payloadoffset), (uint8_t *)((uint8_t *)buffer + bufferoffset), byteslefttocopy);
  223. bufferoffset = bufferoffset + byteslefttocopy;
  224. }
  225. }
  226. #ifdef ETH_RX_DUMP
  227. if (p)
  228. {
  229. LOG_E("******p buf frame *********");
  230. for (q = p; q != NULL; q = q->next)
  231. {
  232. dump_hex(q->payload, q->len);
  233. }
  234. }
  235. #endif
  236. return p;
  237. }
  238. static void phy_linkchange()
  239. {
  240. static uint32_t phy_speed = 0;
  241. uint32_t phy_speed_new = 0;
  242. fsp_err_t res;
  243. uint32_t p_local_pause;
  244. uint32_t p_partner_pause;
  245. res = R_ETHER_LinkProcess(&g_ether0_ctrl);
  246. if (res != FSP_SUCCESS)
  247. LOG_D("R_ETHER_LinkProcess failed!, res = %d", res);
  248. res = R_ETHER_PHY_LinkStatusGet(&g_ether_phy0_ctrl);
  249. if (res != FSP_SUCCESS)
  250. LOG_D("R_ETHER_PHY_LinkStatusGet failed!, res = %d", res);
  251. if(res == FSP_ERR_ETHER_PHY_ERROR_LINK)
  252. {
  253. LOG_D("link down");
  254. eth_device_linkchange(&ra6m3_eth_device.parent, RT_FALSE);
  255. return;
  256. }
  257. res = R_ETHER_PHY_LinkPartnerAbilityGet(&g_ether_phy0_ctrl,
  258. &phy_speed_new,
  259. &p_local_pause,
  260. &p_partner_pause);
  261. if (res != FSP_SUCCESS)
  262. LOG_D("R_ETHER_PHY_LinkPartnerAbilityGet failed!, res = %d", res);
  263. if(res == FSP_ERR_ETHER_PHY_ERROR_LINK)
  264. {
  265. LOG_I("link down");
  266. eth_device_linkchange(&ra6m3_eth_device.parent, RT_FALSE);
  267. return;
  268. }
  269. if (phy_speed != phy_speed_new)
  270. {
  271. phy_speed = phy_speed_new;
  272. if (phy_speed != ETHER_PHY_LINK_SPEED_NO_LINK)
  273. {
  274. LOG_D("link up");
  275. if (phy_speed == ETHER_PHY_LINK_SPEED_100H || phy_speed == ETHER_PHY_LINK_SPEED_100F)
  276. {
  277. LOG_D("100Mbps");
  278. }
  279. else
  280. {
  281. LOG_D("10Mbps");
  282. }
  283. if (phy_speed == ETHER_PHY_LINK_SPEED_100F || phy_speed == ETHER_PHY_LINK_SPEED_10F)
  284. {
  285. LOG_D("full-duplex");
  286. }
  287. else
  288. {
  289. LOG_D("half-duplex");
  290. }
  291. /* send link up. */
  292. LOG_I("link up");
  293. eth_device_linkchange(&ra6m3_eth_device.parent, RT_TRUE);
  294. }
  295. else
  296. {
  297. LOG_D("link down");
  298. eth_device_linkchange(&ra6m3_eth_device.parent, RT_FALSE);
  299. }
  300. }
  301. }
  302. void user_ether0_callback(ether_callback_args_t * p_args)
  303. {
  304. rt_err_t result;
  305. result = eth_device_ready(&(ra6m3_eth_device.parent));
  306. if (result != RT_EOK)
  307. rt_kprintf("RX err =%d\n", result);
  308. }
  309. /* Register the EMAC device */
  310. static int rt_hw_ra6m3_eth_init(void)
  311. {
  312. rt_err_t state = RT_EOK;
  313. /* Prepare receive and send buffers */
  314. Rx_Buff = (rt_uint8_t *)rt_calloc(1, ETH_MAX_PACKET_SIZE);
  315. if (Rx_Buff == RT_NULL)
  316. {
  317. LOG_E("No memory");
  318. state = -RT_ENOMEM;
  319. goto __exit;
  320. }
  321. Tx_Buff = (rt_uint8_t *)rt_calloc(1, ETH_MAX_PACKET_SIZE);
  322. if (Tx_Buff == RT_NULL)
  323. {
  324. LOG_E("No memory");
  325. state = -RT_ENOMEM;
  326. goto __exit;
  327. }
  328. ra6m3_eth_device.parent.parent.init = NULL;
  329. ra6m3_eth_device.parent.parent.open = rt_ra6m3_eth_open;
  330. ra6m3_eth_device.parent.parent.close = rt_ra6m3_eth_close;
  331. ra6m3_eth_device.parent.parent.read = rt_ra6m3_eth_read;
  332. ra6m3_eth_device.parent.parent.write = rt_ra6m3_eth_write;
  333. ra6m3_eth_device.parent.parent.control = rt_ra6m3_eth_control;
  334. ra6m3_eth_device.parent.parent.user_data = RT_NULL;
  335. ra6m3_eth_device.parent.eth_rx = rt_ra6m3_eth_rx;
  336. ra6m3_eth_device.parent.eth_tx = rt_ra6m3_eth_tx;
  337. rt_ra6m3_eth_init();
  338. /* register eth device */
  339. state = eth_device_init(&(ra6m3_eth_device.parent), "e0");
  340. if (RT_EOK == state)
  341. {
  342. LOG_D("emac device init success");
  343. }
  344. else
  345. {
  346. LOG_E("emac device init faild: %d", state);
  347. state = -RT_ERROR;
  348. goto __exit;
  349. }
  350. ra6m3_eth_device.poll_link_timer = rt_timer_create("phylnk", (void (*)(void*))phy_linkchange,
  351. NULL, RT_TICK_PER_SECOND, RT_TIMER_FLAG_PERIODIC);
  352. if (!ra6m3_eth_device.poll_link_timer || rt_timer_start(ra6m3_eth_device.poll_link_timer) != RT_EOK)
  353. {
  354. LOG_E("Start link change detection timer failed");
  355. }
  356. __exit:
  357. if (state != RT_EOK)
  358. {
  359. if (Rx_Buff)
  360. {
  361. rt_free(Rx_Buff);
  362. }
  363. if (Tx_Buff)
  364. {
  365. rt_free(Tx_Buff);
  366. }
  367. }
  368. return state;
  369. }
  370. INIT_DEVICE_EXPORT(rt_hw_ra6m3_eth_init);