sam_gmac.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. * Copyright (c)
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Email Notes
  8. * 2022-04-06 Kevin.Liu kevin.liu.mchp@gmail.com First Release
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #include <rtdbg.h>
  13. #include <netif/ethernetif.h>
  14. #include <lwipopts.h>
  15. #include <atmel_start.h>
  16. #include <peripheral_clk_config.h>
  17. #include <ieee8023_mii_standard_config.h>
  18. #include "board.h"
  19. #include "sam_gmac.h"
  20. #ifdef RT_USING_LWIP
  21. struct rt_sam_eth
  22. {
  23. /* inherit from ethernet device */
  24. struct eth_device parent;
  25. struct mac_async_descriptor *macif;
  26. struct ethernet_phy_descriptor *phyif;
  27. #ifdef RT_USING_TIMER_SOFT
  28. rt_timer_t phy_monitor_timer;
  29. #else
  30. rt_thread_t phy_monitor_tid;
  31. #endif
  32. /* ethernet MAC address */
  33. rt_uint8_t mac_addr[NETIF_MAX_HWADDR_LEN];
  34. /* GMAC Link Speed */
  35. gmac_speed_type link_speed;
  36. /* GMAC Link Mode */
  37. gmac_duplex_type link_mode;
  38. };
  39. static struct rt_sam_eth sam_eth_device;
  40. /**
  41. * @brief Called by GMAC RX interrupt, will notify RX task
  42. *
  43. * @note Will call eth_device_ready to notify RX task.
  44. *
  45. * @param
  46. *
  47. * @return
  48. */
  49. static void rt_sam_gmac_rxcb(void)
  50. {
  51. rt_err_t result;
  52. /* enter interrupt */
  53. rt_interrupt_enter();
  54. result = eth_device_ready(&sam_eth_device.parent);
  55. if (result != RT_EOK)
  56. LOG_E("rt_sam_gmac_rxcb error");
  57. /* leave interrupt */
  58. rt_interrupt_leave();
  59. }
  60. /**
  61. * @brief Initialize the MAC hardware
  62. *
  63. * @note Will set MAC filter by using input MAC address.
  64. *
  65. * @param gmac_dev GMAC device description.
  66. *
  67. * @return
  68. */
  69. static inline void rt_sam_gmac_init(struct rt_sam_eth *gmac_dev)
  70. {
  71. struct mac_async_filter filter;
  72. /* set MAC hardware address */
  73. rt_memcpy(filter.mac, sam_eth_device.mac_addr, NETIF_MAX_HWADDR_LEN);
  74. filter.tid_enable = false;
  75. mac_async_set_filter(gmac_dev->macif, 0, &filter);
  76. mac_async_register_callback(gmac_dev->macif, MAC_ASYNC_RECEIVE_CB, (FUNC_PTR)rt_sam_gmac_rxcb);
  77. }
  78. static rt_err_t rt_sam_eth_init(rt_device_t dev)
  79. {
  80. LOG_D("gmac init");
  81. return RT_EOK;
  82. }
  83. static rt_err_t rt_sam_eth_open(rt_device_t dev, rt_uint16_t oflag)
  84. {
  85. LOG_D("gmac open");
  86. return RT_EOK;
  87. }
  88. static rt_err_t rt_sam_eth_close(rt_device_t dev)
  89. {
  90. LOG_D("gmac close");
  91. return RT_EOK;
  92. }
  93. static rt_ssize_t rt_sam_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  94. {
  95. LOG_D("gmac read");
  96. rt_set_errno(-RT_ENOSYS);
  97. return 0;
  98. }
  99. static rt_ssize_t rt_sam_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  100. {
  101. LOG_D("gmac write");
  102. rt_set_errno(-RT_ENOSYS);
  103. return 0;
  104. }
  105. static rt_err_t rt_sam_eth_control(rt_device_t dev, int cmd, void *args)
  106. {
  107. rt_err_t ret = RT_EOK;
  108. switch (cmd)
  109. {
  110. case NIOCTL_GADDR:
  111. /* get mac address */
  112. if (args)
  113. rt_memcpy(args, sam_eth_device.mac_addr, 6);
  114. break;
  115. default :
  116. break;
  117. }
  118. return ret;
  119. }
  120. /**
  121. * @brief Transmission packet though the MAC hardware
  122. *
  123. * @note Send package to MAC.
  124. *
  125. * @param dev the RT net device input.
  126. *
  127. * @param p stored message will be sent to MAC.
  128. *
  129. * @return RT_EOK.
  130. */
  131. rt_err_t rt_sam_eth_tx(rt_device_t dev, struct pbuf *p)
  132. {
  133. struct rt_sam_eth *gmac_dev = (struct rt_sam_eth *)dev->user_data;
  134. struct pbuf * q;
  135. void * tbuf;
  136. uint8_t * pos;
  137. #if ETH_PAD_SIZE
  138. pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
  139. #endif
  140. if (p->tot_len == p->len)
  141. {
  142. mac_async_write(gmac_dev->macif, p->payload, p->tot_len);
  143. }
  144. else
  145. {
  146. tbuf = mem_malloc(LWIP_MEM_ALIGN_SIZE(p->tot_len));
  147. pos = tbuf;
  148. if (tbuf == NULL)
  149. {
  150. return ERR_MEM;
  151. }
  152. for (q = p; q != NULL; q = q->next)
  153. {
  154. rt_memcpy(pos, q->payload, q->len);
  155. pos += q->len;
  156. }
  157. mac_async_write(gmac_dev->macif, tbuf, p->tot_len);
  158. mem_free(tbuf);
  159. }
  160. #if ETH_PAD_SIZE
  161. pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
  162. #endif
  163. LINK_STATS_INC(link.xmit);
  164. return ERR_OK;
  165. }
  166. /**
  167. * @brief Receive packet from the MAC hardware
  168. *
  169. * @note Returned pbuf filled with the received packet (including MAC header)
  170. *
  171. * @param dev the RT net device input.
  172. *
  173. * @return NULL on memory error
  174. */
  175. struct pbuf *rt_sam_eth_rx(rt_device_t dev)
  176. {
  177. struct rt_sam_eth *gmac_dev = (struct rt_sam_eth *)dev->user_data;
  178. struct pbuf * p;
  179. u16_t len;
  180. len = mac_async_read_len(gmac_dev->macif); /* Obtain the size of the packet */
  181. if (len == 0)
  182. {
  183. return NULL;
  184. }
  185. #if ETH_PAD_SIZE
  186. len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
  187. #endif
  188. /* Allocate a pbuf as one large chunk, This include protocol header */
  189. p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
  190. if (p != NULL)
  191. {
  192. #if ETH_PAD_SIZE
  193. pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
  194. #endif
  195. /* Read the entire packet into the pbuf. */
  196. mac_async_read(gmac_dev->macif, p->payload, p->len);
  197. #if ETH_PAD_SIZE
  198. pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
  199. #endif
  200. LINK_STATS_INC(link.recv);
  201. }
  202. else
  203. {
  204. mac_async_read(gmac_dev->macif, NULL, 0);
  205. LINK_STATS_INC(link.memerr);
  206. LINK_STATS_INC(link.drop);
  207. }
  208. return p;
  209. }
  210. /**
  211. * @brief PHY link status monitor task - timer task or thread
  212. *
  213. * @note Will check link status, link mode and link speed
  214. *
  215. * @param parameter input parameter passing to the function.
  216. *
  217. * @return
  218. */
  219. static void rt_sam_eth_monitor(void *parameter)
  220. {
  221. struct rt_sam_eth *sam_eth = (struct rt_sam_eth *)parameter;
  222. bool link_up;
  223. int32_t ret;
  224. uint16_t val;
  225. static rt_uint8_t link_count = 0;
  226. #ifndef RT_USING_TIMER_SOFT
  227. while (1)
  228. {
  229. #endif
  230. ret = ethernet_phy_get_link_status(sam_eth->phyif, &link_up);
  231. if (ERR_NONE == ret)
  232. {
  233. if (link_up)
  234. {
  235. /* send link up. */
  236. eth_device_linkchange(&sam_eth->parent, RT_TRUE);
  237. }
  238. else
  239. {
  240. /* send link down. */
  241. eth_device_linkchange(&sam_eth->parent, RT_FALSE);;
  242. }
  243. }
  244. ret = ethernet_phy_read_reg(sam_eth->phyif, MDIO_REG1_BMSR, &val);
  245. if (ERR_NONE == ret)
  246. {
  247. if (val & (MDIO_REG1_BIT_100BASE_TX_FD | MDIO_REG1_BIT_100BASE_TX_HD))
  248. {
  249. LOG_D("100Mbps");
  250. sam_eth_device.link_speed = GMAC_SPEED_100MBPS;
  251. }
  252. else
  253. {
  254. LOG_D("10Mbps");
  255. sam_eth_device.link_speed = GMAC_SPEED_10MBPS;
  256. }
  257. if (val & (MDIO_REG1_BIT_100BASE_TX_FD | MDIO_REG1_BIT_10BASE_T_FD))
  258. {
  259. LOG_D("100Mbps");
  260. sam_eth_device.link_mode = GMAC_FULL_DUPLEX;
  261. }
  262. else
  263. {
  264. LOG_D("10Mbps");
  265. sam_eth_device.link_mode = GMAC_HALF_DUPLEX;
  266. }
  267. }
  268. if (link_count >= 10)
  269. {
  270. link_count = 0;
  271. /* Restart an auto-negotiation */
  272. ethernet_phy_restart_autoneg(sam_eth->phyif);
  273. }
  274. #ifndef RT_USING_TIMER_SOFT
  275. rt_thread_mdelay(1000);
  276. }
  277. #endif
  278. }
  279. /**
  280. * @brief Register the GMAC Ethernet device.
  281. *
  282. * @note
  283. *
  284. * @param
  285. *
  286. * @return RT_OK or -RT_ERROR.
  287. */
  288. static int rt_hw_sam_eth_init(void)
  289. {
  290. rt_err_t state = RT_EOK;
  291. #if CONF_AT24MAC_ADDRESS != 0
  292. rt_uint8_t addr = 0x9A;
  293. #endif
  294. sam_eth_device.macif = &MACIF;
  295. sam_eth_device.phyif = &MACIF_PHY_desc;
  296. sam_eth_device.link_speed = GMAC_SPEED_100MBPS;
  297. sam_eth_device.link_mode = GMAC_FULL_DUPLEX;
  298. #if CONF_AT24MAC_ADDRESS != 0
  299. i2c_m_sync_enable(&I2C_0);
  300. i2c_m_sync_set_slaveaddr(&I2C_0, CONF_AT24MAC_ADDRESS, I2C_M_SEVEN);
  301. io_write(&(I2C_0.io), &addr, 1);
  302. io_read(&(I2C_0.io), sam_eth_device.mac_addr, 6);
  303. #else
  304. /* set mac to 0x11 if no EEPROM mounted */
  305. memset(sam_eth_device.mac_addr, 0x11, 6);
  306. #endif
  307. sam_eth_device.parent.parent.init = rt_sam_eth_init;
  308. sam_eth_device.parent.parent.open = rt_sam_eth_open;
  309. sam_eth_device.parent.parent.close = rt_sam_eth_close;
  310. sam_eth_device.parent.parent.read = rt_sam_eth_read;
  311. sam_eth_device.parent.parent.write = rt_sam_eth_write;
  312. sam_eth_device.parent.parent.control = rt_sam_eth_control;
  313. sam_eth_device.parent.parent.user_data = (void *)&sam_eth_device;
  314. sam_eth_device.parent.eth_rx = rt_sam_eth_rx;
  315. sam_eth_device.parent.eth_tx = rt_sam_eth_tx;
  316. rt_sam_gmac_init(&sam_eth_device);
  317. /* register eth device */
  318. state = eth_device_init(&(sam_eth_device.parent), "e0");
  319. if (RT_EOK == state)
  320. {
  321. LOG_D("gmac device init success");
  322. }
  323. else
  324. {
  325. LOG_E("gmac device init faild: %d", state);
  326. state = -RT_ERROR;
  327. goto outs;
  328. }
  329. /* start SAM PHY monitor */
  330. #ifdef RT_USING_TIMER_SOFT
  331. sam_eth_device.phy_monitor_timer = rt_timer_create("phylnk",
  332. rt_sam_eth_monitor,
  333. (void *)&sam_eth_device,
  334. 10*RT_TICK_PER_SECOND,
  335. RT_TIMER_FLAG_PERIODIC);
  336. if (RT_NULL != sam_eth_device.phy_monitor_timer)
  337. {
  338. rt_timer_start(sam_eth_device.phy_monitor_timer);
  339. }
  340. else
  341. {
  342. state = -RT_ERROR;
  343. LOG_E("gmac rt_timer_create faild: %d", state);
  344. }
  345. #else
  346. sam_eth_device.phy_monitor_tid = rt_thread_create("phy",
  347. rt_sam_eth_monitor,
  348. (void *)&sam_eth_device,
  349. 1024,
  350. RT_THREAD_PRIORITY_MAX - 2,
  351. 2);
  352. if (sam_eth_device.phy_monitor_tid != RT_NULL)
  353. {
  354. rt_thread_startup(sam_eth_device.phy_monitor_tid);
  355. }
  356. else
  357. {
  358. state = -RT_ERROR;
  359. LOG_E("gmac rt_thread_create faild: %d", state);
  360. }
  361. #endif
  362. outs:
  363. return state;
  364. }
  365. INIT_DEVICE_EXPORT(rt_hw_sam_eth_init);
  366. #endif /* BSP_USING_ETH_ARTPI */