drv_eth.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*
  2. * Copyright (c) 2006-2024, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024/04/25 flyingcys first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <rtdevice.h>
  13. #include "board.h"
  14. #define DBG_TAG "drv.eth"
  15. #define DBG_LEVEL DBG_INFO
  16. #include <rtdbg.h>
  17. #include <lwip/sys.h>
  18. #include <netif/ethernetif.h>
  19. #include "drv_eth.h"
  20. // #define ETH_TX_DUMP
  21. // #define ETH_RX_DUMP
  22. #define MAX_ADDR_LEN 6
  23. #define DETECT_THREAD_PRIORITY RT_THREAD_PRIORITY_MAX - 2
  24. #define DETECT_THREAD_STACK_SIZE 4096
  25. struct _dw_eth
  26. {
  27. rt_ubase_t base;
  28. rt_uint32_t irq;
  29. struct eth_device parent; /* inherit from ethernet device */
  30. rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* interface address info, hw address */
  31. struct rt_semaphore rx_sem;
  32. };
  33. static struct _dw_eth dw_eth_device = {0};
  34. #define GMAC_BUF_LEN (1500 + 20)
  35. static uint8_t g_mac_addr[6] = {0xf2, 0x42, 0x9f, 0xa5, 0x0a, 0x72};
  36. static uint8_t g_mac_phy_init_finish = 0;
  37. static eth_mac_handle_t g_mac_handle;
  38. static eth_phy_handle_t g_phy_handle;
  39. static uint8_t SendDataBuf[GMAC_BUF_LEN];
  40. static uint8_t RecvDataBuf[GMAC_BUF_LEN];
  41. static void cvi_ephy_id_init(void)
  42. {
  43. // set rg_ephy_apb_rw_sel 0x0804@[0]=1/APB by using APB interface
  44. mmio_write_32(ETH_PHY_BASE + 0x804, 0x0001);
  45. // Release 0x0800[0]=0/shutdown
  46. mmio_write_32(ETH_PHY_BASE + 0x800, 0x0900);
  47. // Release 0x0800[2]=1/dig_rst_n, Let mii_reg can be accessabile
  48. mmio_write_32(ETH_PHY_BASE + 0x800, 0x0904);
  49. // PHY_ID
  50. mmio_write_32(ETH_PHY_BASE + 0x008, 0x0043);
  51. mmio_write_32(ETH_PHY_BASE + 0x00c, 0x5649);
  52. // switch to MDIO control by ETH_MAC
  53. mmio_write_32(ETH_PHY_BASE + 0x804, 0x0000);
  54. }
  55. static int cvi_eth_mac_phy_enable(uint32_t enable)
  56. {
  57. eth_mac_addr_t addr;
  58. int32_t ret;
  59. if ((g_mac_phy_init_finish == 0) && enable)
  60. {
  61. /* startup mac */
  62. ret = cvi_eth_mac_control(g_mac_handle, CSI_ETH_MAC_CONFIGURE, 1);
  63. if (ret != 0)
  64. {
  65. LOG_E("Failed to control mac");
  66. return -1;
  67. }
  68. /* Start up the PHY */
  69. ret = cvi_eth_phy_power_control(g_phy_handle, CSI_ETH_POWER_FULL);
  70. if (ret != 0)
  71. {
  72. LOG_E("Failed to control phy, ret:0x%d", ret);
  73. return -1;
  74. }
  75. }
  76. /* enable mac TX/RX */
  77. ret = cvi_eth_mac_control(g_mac_handle, CSI_ETH_MAC_CONTROL_TX, enable ? 1 : 0);
  78. if (ret != 0)
  79. {
  80. LOG_E("Failed to enable mac TX");
  81. return ret;
  82. }
  83. ret = cvi_eth_mac_control(g_mac_handle, CSI_ETH_MAC_CONTROL_RX, enable ? 1 : 0);
  84. if (ret != 0)
  85. {
  86. LOG_E("Failed to enable mac RX");
  87. return ret;
  88. }
  89. /* set mac address */
  90. rt_memcpy(addr.b, g_mac_addr, sizeof(g_mac_addr));
  91. ret = cvi_eth_mac_set_macaddr(g_mac_handle, &addr);
  92. if (ret != 0)
  93. {
  94. LOG_E("Failed to set mac address");
  95. return -1;
  96. }
  97. /* adjust mac link parameter */
  98. ret = cvi_eth_mac_control(g_mac_handle, DRV_ETH_MAC_ADJUST_LINK, 1);
  99. if (ret != 0)
  100. {
  101. LOG_E("Failed to adjust link");
  102. return -1;
  103. }
  104. return 0;
  105. }
  106. static int32_t fn_phy_read(uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
  107. {
  108. return dw_eth_mac_phy_read(g_mac_handle, phy_addr, reg_addr, data);
  109. }
  110. static int32_t fn_phy_write(uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
  111. {
  112. return dw_eth_mac_phy_write(g_mac_handle, phy_addr, reg_addr, data);
  113. }
  114. static void dw_gmac_handler_irq(int vector, void *param)
  115. {
  116. gmac_dev_t *mac_dev = (gmac_dev_t *)param;
  117. struct dw_gmac_dma_regs *dma_reg = mac_dev->priv->dma_regs_p;
  118. uint32_t dma_status;
  119. uint32_t event = 0;
  120. /* no ephy or ephy link down */
  121. if (!mac_dev->phy_dev || !mac_dev->phy_dev->link_state)
  122. return;
  123. /* read and clear dma interrupt */
  124. dma_status = dma_reg->status;
  125. /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
  126. dma_reg->status = dma_status & 0x1ffff;
  127. if (dma_status & CVI_DMA_STATUS_RI)
  128. {
  129. LOG_D("CVI_DMA_STATUS_RI");
  130. /* a frame has been received */
  131. eth_device_ready(&(dw_eth_device.parent));
  132. }
  133. if (dma_status & CVI_DMA_STATUS_TI)
  134. {
  135. LOG_D("CVI_DMA_STATUS_TI");
  136. }
  137. if (dma_status & CVI_DMA_STATUS_ERI)
  138. {
  139. LOG_D("CVI_DMA_STATUS_TI");
  140. }
  141. }
  142. static void phy_link_detect(void *param)
  143. {
  144. int link_status = -1;
  145. int link_status_old = -1;
  146. int ret = -1;
  147. while (1)
  148. {
  149. link_status = eth_phy_update_link(g_phy_handle);
  150. LOG_D("eth link status: %d", link_status);
  151. if (link_status_old != link_status)
  152. {
  153. if (link_status == 0)
  154. {
  155. LOG_I("eth link up");
  156. eth_device_linkchange(&(dw_eth_device.parent), RT_TRUE);
  157. }
  158. else
  159. {
  160. LOG_I("eth link down");
  161. eth_device_linkchange(&(dw_eth_device.parent), RT_FALSE);
  162. }
  163. link_status_old = link_status;
  164. }
  165. rt_thread_delay(RT_TICK_PER_SECOND);
  166. }
  167. }
  168. static rt_err_t rt_dw_eth_init(rt_device_t dev)
  169. {
  170. struct _dw_eth *dw_eth;
  171. struct eth_device *eth_dev;
  172. RT_ASSERT(dev != RT_NULL);
  173. eth_dev = rt_container_of(dev, struct eth_device, parent);
  174. if (eth_dev == RT_NULL)
  175. return -RT_ERROR;
  176. dw_eth = rt_container_of(eth_dev, struct _dw_eth, parent);
  177. if (dw_eth == RT_NULL)
  178. return -RT_ERROR;
  179. /* init phy id */
  180. cvi_ephy_id_init();
  181. /* initialize MAC & PHY */
  182. g_mac_handle = cvi_eth_mac_init(dw_eth->base);
  183. if (g_mac_handle == NULL)
  184. return -RT_ERROR;
  185. g_phy_handle = cvi_eth_phy_init(fn_phy_read, fn_phy_write);
  186. dw_eth_mac_connect_phy(g_mac_handle, g_phy_handle);
  187. if (cvi_eth_mac_phy_enable(1))
  188. {
  189. LOG_E("PHY MAC init fail");
  190. return -RT_ERROR;
  191. }
  192. rt_hw_interrupt_install(dw_eth->irq, dw_gmac_handler_irq, g_mac_handle, "e0");
  193. rt_hw_interrupt_umask(dw_eth->irq);
  194. LOG_D("PHY MAC init success");
  195. rt_thread_t link_detect;
  196. link_detect = rt_thread_create("link_detect",
  197. phy_link_detect,
  198. (void *)&dw_eth_device,
  199. DETECT_THREAD_STACK_SIZE,
  200. DETECT_THREAD_PRIORITY,
  201. 2);
  202. if (link_detect != RT_NULL)
  203. {
  204. rt_thread_startup(link_detect);
  205. }
  206. else
  207. {
  208. return -RT_ERROR;
  209. }
  210. return RT_EOK;
  211. }
  212. static rt_err_t rt_dw_eth_control(rt_device_t dev, int cmd, void *args)
  213. {
  214. switch (cmd)
  215. {
  216. case NIOCTL_GADDR:
  217. if (args)
  218. rt_memcpy(args, g_mac_addr, MAX_ADDR_LEN);
  219. break;
  220. default:
  221. break;
  222. }
  223. return RT_EOK;
  224. }
  225. #if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP)
  226. static void packet_dump(const char *msg, const struct pbuf *p)
  227. {
  228. const struct pbuf *q;
  229. rt_uint32_t i, j;
  230. rt_uint8_t *ptr;
  231. rt_kprintf("%s %d byte\n", msg, p->tot_len);
  232. i = 0;
  233. for (q = p; q != RT_NULL; q = q->next)
  234. {
  235. ptr = q->payload;
  236. for (j = 0; j < q->len; j++)
  237. {
  238. if ((i % 8) == 0)
  239. {
  240. rt_kprintf(" ");
  241. }
  242. if ((i % 16) == 0)
  243. {
  244. rt_kprintf("\r\n");
  245. }
  246. rt_kprintf("%02x ", *ptr);
  247. i ++;
  248. ptr ++;
  249. }
  250. }
  251. rt_kprintf("\n\n");
  252. }
  253. #endif
  254. struct pbuf* rt_dw_eth_rx(rt_device_t dev)
  255. {
  256. struct pbuf *p = NULL;
  257. struct pbuf *q = NULL;
  258. uint32_t i = 0;
  259. int32_t len = cvi_eth_mac_read_frame(g_mac_handle, RecvDataBuf, GMAC_BUF_LEN);
  260. if ((len <= 0) || (len > GMAC_BUF_LEN))
  261. {
  262. return NULL;
  263. }
  264. #if RT_LWIP_ETH_PAD_SIZE
  265. len += RT_LWIP_ETH_PAD_SIZE; /* allow room for Ethernet padding */
  266. #endif
  267. p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
  268. if (p == NULL)
  269. {
  270. LOG_E("eth_rx: pbuf_alloc failed");
  271. len = 0;
  272. return NULL;
  273. }
  274. #if RT_LWIP_ETH_PAD_SIZE
  275. pbuf_header(p, -RT_LWIP_ETH_PAD_SIZE); /* drop the padding word */
  276. #endif
  277. /* We iterate over the pbuf chain until we have read the entire
  278. * packet into the pbuf. */
  279. for (q = p; q != NULL; q = q->next)
  280. {
  281. /* Read enough bytes to fill this pbuf in the chain. The
  282. * available data in the pbuf is given by the q->len
  283. * variable.
  284. * This does not necessarily have to be a memcpy, you can also preallocate
  285. * pbufs for a DMA-enabled MAC and after receiving truncate it to the
  286. * actually received size. In this case, ensure the tot_len member of the
  287. * pbuf is the sum of the chained pbuf len members.
  288. */
  289. rt_memcpy((u8_t*)q->payload, (u8_t*)&RecvDataBuf[i], q->len);
  290. i = i + q->len;
  291. }
  292. if ((i != p->tot_len) || (i > len))
  293. {
  294. return NULL;
  295. }
  296. #ifdef ETH_RX_DUMP
  297. packet_dump("RX dump", p);
  298. #endif /* ETH_RX_DUMP */
  299. return p;
  300. }
  301. rt_err_t rt_dw_eth_tx(rt_device_t dev, struct pbuf* p)
  302. {
  303. rt_err_t ret = RT_EOK;
  304. #ifdef ETH_TX_DUMP
  305. packet_dump("send", p);
  306. #endif
  307. struct pbuf *q;
  308. uint32_t len = 0;
  309. #if RT_LWIP_ETH_PAD_SIZE
  310. pbuf_header(p, -RT_LWIP_ETH_PAD_SIZE); /* drop the padding word */
  311. #endif
  312. for (q = p; q != NULL; q = q->next)
  313. {
  314. /* Send the data from the pbuf to the interface, one pbuf at a
  315. time. The size of the data in each pbuf is kept in the ->len
  316. variable. */
  317. MEMCPY((uint8_t *)&SendDataBuf[len], (uint8_t *)q->payload, q->len);
  318. len = len + q->len;
  319. if ((len > GMAC_BUF_LEN) || (len > p->tot_len))
  320. {
  321. LOG_E("rt_dw_eth_tx: error, len=%d, tot_len=%d", len, p->tot_len);
  322. return -RT_ERROR;
  323. }
  324. }
  325. if (len == p->tot_len)
  326. {
  327. if (cvi_eth_mac_send_frame(g_mac_handle, SendDataBuf, len) < 0)
  328. ret = -RT_ERROR;
  329. }
  330. else
  331. ret = -RT_ERROR;
  332. #if RT_LWIP_ETH_PAD_SIZE
  333. pbuf_header(p, RT_LWIP_ETH_PAD_SIZE); /* reclaim the padding word */
  334. #endif
  335. return ret;
  336. }
  337. const static struct rt_device_ops dw_eth_ops =
  338. {
  339. rt_dw_eth_init,
  340. RT_NULL,
  341. RT_NULL,
  342. RT_NULL,
  343. RT_NULL,
  344. rt_dw_eth_control
  345. };
  346. static int rthw_eth_init(void)
  347. {
  348. rt_err_t ret = RT_EOK;
  349. dw_eth_device.base = (rt_ubase_t)DW_MAC_BASE;
  350. dw_eth_device.irq = DW_MAC_IRQ;
  351. dw_eth_device.parent.parent.ops = &dw_eth_ops;
  352. dw_eth_device.parent.eth_rx = rt_dw_eth_rx;
  353. dw_eth_device.parent.eth_tx = rt_dw_eth_tx;
  354. ret = rt_sem_init(&dw_eth_device.rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
  355. if (ret != RT_EOK)
  356. {
  357. LOG_E("rt_sem_init failed: %d", ret);
  358. return ret;
  359. }
  360. ret = eth_device_init(&dw_eth_device.parent, "e0");
  361. if (ret != RT_EOK)
  362. {
  363. LOG_E("eth_device_init failed: %d", ret);
  364. return ret;
  365. }
  366. return RT_EOK;
  367. }
  368. INIT_DEVICE_EXPORT(rthw_eth_init);