drv_eth.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  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. * 2021-06-16 songchao support emac driver
  9. * 2021-06-29 songchao add phy link detect
  10. * 2021-08-13 songchao support dual mac and reduse copy
  11. */
  12. #include "drv_eth.h"
  13. #define DBG_TAG "drv.enet"
  14. #define DBG_LVL DBG_LOG
  15. #include <rtdbg.h>
  16. #define BSP_USING_IMX6ULL_ART_PI
  17. #if (defined(RT_USING_ENET1)) || (defined(RT_USING_ENET2))
  18. #ifdef BSP_USING_IMX6ULL_ART_PI
  19. static struct imx6ull_iomuxc mdio_gpio[2] =
  20. {
  21. {IOMUXC_GPIO1_IO06_ENET1_MDIO,0U,0xB029},
  22. {IOMUXC_GPIO1_IO07_ENET1_MDC,0U,0xB0E9}
  23. };
  24. #else
  25. static struct imx6ull_iomuxc mdio_gpio[2] =
  26. {
  27. {IOMUXC_GPIO1_IO06_ENET2_MDIO,0U,0xB029},
  28. {IOMUXC_GPIO1_IO07_ENET2_MDC,0U,0xB0E9},
  29. };
  30. #endif
  31. enum
  32. {
  33. #ifdef RT_USING_ENET1
  34. DEV_ENET1,
  35. #endif
  36. #ifdef RT_USING_ENET2
  37. DEV_ENET2,
  38. #endif
  39. DEV_ENET_MAX,
  40. };
  41. static struct rt_imx6ul_ethps _imx6ul_eth_device[DEV_ENET_MAX] =
  42. {
  43. #ifdef RT_USING_ENET1
  44. {
  45. .dev_addr = {0xa8,0x5e,0x45,0x91,0x92,0x93},
  46. .mac_name = "e1",
  47. .irq_name = "emac1_intr",
  48. .enet_phy_base_addr = ENET1,
  49. .irq_num = IMX_INT_ENET1,
  50. .phy_num = ENET_PHY1,
  51. .mac_num = 1,
  52. .phy_base_addr = GPIO5,
  53. .phy_gpio_pin = 9,
  54. .phy_id = 7,
  55. .buffConfig =
  56. {
  57. ENET_RXBD_NUM,
  58. ENET_TXBD_NUM,
  59. ENET_RXBUFF_ALIGN_SIZE,
  60. ENET_TXBUFF_ALIGN_SIZE,
  61. RT_NULL,
  62. RT_NULL,
  63. RT_NULL,
  64. RT_NULL,
  65. RT_NULL,
  66. RT_NULL,
  67. RT_NULL,
  68. RT_NULL,
  69. ENET_RXBUFF_TOTAL_SIZE,
  70. ENET_TXBUFF_TOTAL_SIZE
  71. },
  72. .gpio =
  73. {
  74. {IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09,0U,0x110B0},
  75. {IOMUXC_ENET1_RX_DATA0_ENET1_RDATA00,0U,0xB0E9},
  76. {IOMUXC_ENET1_RX_DATA1_ENET1_RDATA01,0U,0xB0E9},
  77. {IOMUXC_ENET1_RX_EN_ENET1_RX_EN,0U,0xB0E9},
  78. {IOMUXC_ENET1_RX_ER_ENET1_RX_ER,0U,0xB0E9},
  79. {IOMUXC_ENET1_TX_CLK_ENET1_REF_CLK1,1U,0x00F0},
  80. {IOMUXC_ENET1_TX_DATA0_ENET1_TDATA00,0U,0xB0E9},
  81. {IOMUXC_ENET1_TX_DATA1_ENET1_TDATA01,0U,0xB0E9},
  82. {IOMUXC_ENET1_TX_EN_ENET1_TX_EN,0U,0xB0E9}
  83. }
  84. },
  85. #endif
  86. #ifdef RT_USING_ENET2
  87. {
  88. .dev_addr = {0xa8,0x5e,0x45,0x01,0x02,0x03},
  89. .mac_name = "e2",
  90. .irq_name = "emac2_intr",
  91. .enet_phy_base_addr = ENET2,
  92. .irq_num = IMX_INT_ENET2,
  93. .phy_num = ENET_PHY2,
  94. .mac_num = 2,
  95. .phy_base_addr = GPIO5,
  96. .phy_gpio_pin = 6,
  97. .phy_id = 7,
  98. .buffConfig =
  99. {
  100. ENET_RXBD_NUM,
  101. ENET_TXBD_NUM,
  102. ENET_RXBUFF_ALIGN_SIZE,
  103. ENET_TXBUFF_ALIGN_SIZE,
  104. RT_NULL,
  105. RT_NULL,
  106. RT_NULL,
  107. RT_NULL,
  108. RT_NULL,
  109. RT_NULL,
  110. RT_NULL,
  111. RT_NULL,
  112. ENET_RXBUFF_TOTAL_SIZE,
  113. ENET_TXBUFF_TOTAL_SIZE
  114. },
  115. .gpio =
  116. {
  117. {IOMUXC_SNVS_SNVS_TAMPER6_GPIO5_IO06,0U,0x110B0},
  118. {IOMUXC_ENET2_RX_DATA0_ENET2_RDATA00,0U,0xB0E9},
  119. {IOMUXC_ENET2_RX_DATA1_ENET2_RDATA01,0U,0xB0E9},
  120. {IOMUXC_ENET2_RX_EN_ENET2_RX_EN,0U,0xB0E9},
  121. {IOMUXC_ENET2_RX_ER_ENET2_RX_ER,0U,0xB0E9},
  122. {IOMUXC_ENET2_TX_CLK_ENET2_REF_CLK2,1U,0x00F0},
  123. {IOMUXC_ENET2_TX_DATA0_ENET2_TDATA00,0U,0xB0E9},
  124. {IOMUXC_ENET2_TX_DATA1_ENET2_TDATA01,0U,0xB0E9},
  125. {IOMUXC_ENET2_TX_EN_ENET2_TX_EN,0U,0xB0E9}
  126. }
  127. },
  128. #endif
  129. };
  130. void imx6ul_eth_link_change(struct rt_imx6ul_ethps *imx6ul_device,rt_bool_t up)
  131. {
  132. if(up)
  133. {
  134. LOG_D("enet%d link up",imx6ul_device->mac_num);
  135. eth_device_linkchange(&imx6ul_device->parent, RT_TRUE);
  136. imx6ul_device->phy_link_status = RT_TRUE;
  137. }
  138. else
  139. {
  140. LOG_D("enet%d link down",imx6ul_device->mac_num);
  141. eth_device_linkchange(&imx6ul_device->parent, RT_FALSE);
  142. imx6ul_device->phy_link_status = RT_FALSE;
  143. }
  144. }
  145. void ENET_InitModuleClock(void)
  146. {
  147. const clock_enet_pll_config_t config = {true, true, false, 1, 1};
  148. CLOCK_InitEnetPll(&config);
  149. }
  150. rt_err_t enet_buffer_init(enet_buffer_config_t *buffConfig)
  151. {
  152. void *tx_buff_addr = RT_NULL;
  153. void *rx_buff_addr = RT_NULL;
  154. void *tx_bd_addr = RT_NULL;
  155. void *rx_bd_addr = RT_NULL;
  156. if(((SYS_PAGE_SIZE<<RX_BUFFER_INDEX_NUM)<buffConfig->rxBufferTotalSize)||
  157. ((SYS_PAGE_SIZE<<TX_BUFFER_INDEX_NUM)<buffConfig->txBufferTotalSize))
  158. {
  159. LOG_E("ERROR: alloc mem not enough for enet driver");
  160. return RT_ERROR;
  161. }
  162. rx_buff_addr = rt_pages_alloc(RX_BUFFER_INDEX_NUM);
  163. if(!rx_buff_addr)
  164. {
  165. LOG_E("ERROR: rx buff page alloc failed");
  166. return RT_ERROR;
  167. }
  168. buffConfig->rxBufferAlign = (void *)rt_ioremap_nocache(virtual_to_physical(rx_buff_addr), (SYS_PAGE_SIZE<<RX_BUFFER_INDEX_NUM));
  169. buffConfig->rxPhyBufferAlign = (void *)virtual_to_physical(rx_buff_addr);
  170. tx_buff_addr = rt_pages_alloc(TX_BUFFER_INDEX_NUM);
  171. if(!tx_buff_addr)
  172. {
  173. LOG_E("ERROR: tx buff page alloc failed");
  174. return RT_ERROR;
  175. }
  176. buffConfig->txBufferAlign = (void *)rt_ioremap_nocache(virtual_to_physical(tx_buff_addr), (SYS_PAGE_SIZE<<TX_BUFFER_INDEX_NUM));
  177. buffConfig->txPhyBufferAlign = (void *)virtual_to_physical(tx_buff_addr);
  178. rx_bd_addr = rt_pages_alloc(RX_BD_INDEX_NUM);
  179. if(!rx_bd_addr)
  180. {
  181. LOG_E("ERROR: rx bd page alloc failed");
  182. return RT_ERROR;
  183. }
  184. buffConfig->rxBdStartAddrAlign = (void *)rt_ioremap_nocache(virtual_to_physical(rx_bd_addr), (SYS_PAGE_SIZE<<RX_BD_INDEX_NUM));
  185. buffConfig->rxPhyBdStartAddrAlign = virtual_to_physical(rx_bd_addr);
  186. tx_bd_addr = rt_pages_alloc(TX_BD_INDEX_NUM);
  187. if(!tx_bd_addr)
  188. {
  189. LOG_E("ERROR: tx bd page alloc failed");
  190. return RT_ERROR;
  191. }
  192. buffConfig->txBdStartAddrAlign = (void *)rt_ioremap_nocache(virtual_to_physical(tx_bd_addr), (SYS_PAGE_SIZE<<TX_BD_INDEX_NUM));
  193. buffConfig->txPhyBdStartAddrAlign = virtual_to_physical(tx_bd_addr);
  194. return RT_EOK;
  195. }
  196. /* EMAC initialization function */
  197. static rt_err_t rt_imx6ul_eth_init(rt_device_t dev)
  198. {
  199. rt_err_t state;
  200. struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)dev;
  201. ENET_Type *base_addr = RT_NULL;
  202. enet_config_t *config;
  203. enet_handle_t *handle;
  204. enet_buffer_config_t *buffConfig;
  205. rt_uint32_t reg_value;
  206. imx6ul_device->enet_virtual_base_addr = (ENET_Type *)rt_ioremap((void *)imx6ul_device->enet_phy_base_addr,SYS_PAGE_SIZE);
  207. base_addr = imx6ul_device->enet_virtual_base_addr;
  208. config = &imx6ul_device->config;
  209. handle = &imx6ul_device->handle;
  210. buffConfig = &imx6ul_device->buffConfig;
  211. for (int i=0; i<GET_ARRAY_NUM(imx6ul_device->gpio); i++)
  212. {
  213. imx6ull_gpio_init(&imx6ul_device->gpio[i]);
  214. }
  215. IOMUXC_GPR_Type *GPR1 = (IOMUXC_GPR_Type *)rt_ioremap((void *)IOMUXC_GPR,0x1000);
  216. if(imx6ul_device->mac_num == 1)
  217. {
  218. reg_value = GPR1->GPR1;
  219. reg_value &= ~(IOMUXC_GPR_GPR1_ENET1_CLK_SEL_MASK
  220. | IOMUXC_GPR_GPR1_ENET1_CLK_SEL_MASK);
  221. reg_value |= IOMUXC_GPR_GPR1_ENET1_TX_CLK_DIR(1);
  222. reg_value |= IOMUXC_GPR_GPR1_ENET1_CLK_SEL(0);
  223. GPR1->GPR1 = reg_value;
  224. }
  225. else if(imx6ul_device->mac_num == 2)
  226. {
  227. reg_value = GPR1->GPR1;
  228. reg_value &= ~(IOMUXC_GPR_GPR1_ENET2_CLK_SEL_MASK
  229. | IOMUXC_GPR_GPR1_ENET2_CLK_SEL_MASK);
  230. reg_value |= IOMUXC_GPR_GPR1_ENET2_TX_CLK_DIR(1);
  231. reg_value |= IOMUXC_GPR_GPR1_ENET2_CLK_SEL(0);
  232. GPR1->GPR1 = reg_value;
  233. }
  234. ENET_InitModuleClock();
  235. ENET_GetDefaultConfig(config);
  236. config->interrupt |= (ENET_RX_INTERRUPT);
  237. state = enet_buffer_init(buffConfig);
  238. if(state != RT_EOK)
  239. {
  240. return state;
  241. }
  242. ENET_Init(base_addr, handle, config, buffConfig, &imx6ul_device->dev_addr[0], SYS_CLOCK_HZ);
  243. ENET_ActiveRead(base_addr);
  244. rt_hw_interrupt_install(imx6ul_device->irq_num, (rt_isr_handler_t)ENET_DriverIRQHandler, (void *)base_addr,imx6ul_device->irq_name);
  245. rt_hw_interrupt_umask(imx6ul_device->irq_num);
  246. return RT_EOK;
  247. }
  248. static rt_err_t rt_imx6ul_eth_control(rt_device_t dev, int cmd, void *args)
  249. {
  250. struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)dev;
  251. switch (cmd)
  252. {
  253. case NIOCTL_GADDR:
  254. /* get MAC address */
  255. if (args)
  256. {
  257. OCOTP_Type *ocotp_base;
  258. rt_uint32_t uid[2];
  259. rt_uint32_t uid_crc = 0;
  260. ocotp_base = (OCOTP_Type *)rt_ioremap((void*)OCOTP_BASE, 0x1000);
  261. uid[0] = ocotp_base->CFG0;
  262. uid[1] = ocotp_base->CFG1;
  263. rt_iounmap(ocotp_base);
  264. LOG_D("UNIQUE_ID is %x%x",uid[0], uid[1]);
  265. uid_crc = uid[0] - uid[1];
  266. LOG_D("UNIQUE_ID change to 32 bits %x", uid_crc);
  267. if (imx6ul_device->enet_phy_base_addr == ENET1)
  268. {
  269. imx6ul_device->dev_addr[0] = 0xa8;
  270. imx6ul_device->dev_addr[1] = 0x5e;
  271. imx6ul_device->dev_addr[2] = 0x45;
  272. imx6ul_device->dev_addr[3] = (uid_crc>>16) & 0x7f;
  273. imx6ul_device->dev_addr[4] = (uid_crc>>8) & 0xff;
  274. imx6ul_device->dev_addr[5] = uid_crc & 0xff;
  275. }
  276. else /*if (imx6ul_device->enet_phy_base_addr == ENET2)*/
  277. {
  278. imx6ul_device->dev_addr[0] = 0xa8;
  279. imx6ul_device->dev_addr[1] = 0x5e;
  280. imx6ul_device->dev_addr[2] = 0x46;
  281. imx6ul_device->dev_addr[3] = (uid_crc >> 16) & 0x7f;
  282. imx6ul_device->dev_addr[4] = (uid_crc >> 8) & 0xff;
  283. imx6ul_device->dev_addr[5] = uid_crc & 0xff;
  284. }
  285. rt_memcpy(args, imx6ul_device->dev_addr, MAX_ADDR_LEN);
  286. }
  287. else
  288. {
  289. return -RT_ERROR;
  290. }
  291. break;
  292. default :
  293. break;
  294. }
  295. return RT_EOK;
  296. }
  297. static status_t read_data_from_eth(rt_device_t dev,void *read_data,uint16_t *read_length)
  298. {
  299. status_t status = 0;
  300. uint16_t length = 0;
  301. ENET_Type *base_addr = RT_NULL;
  302. enet_config_t *config;
  303. enet_handle_t *handle;
  304. enet_buffer_config_t *buffConfig;
  305. struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)dev;
  306. base_addr = imx6ul_device->enet_virtual_base_addr;
  307. config = &imx6ul_device->config;
  308. handle = &imx6ul_device->handle;
  309. buffConfig = &imx6ul_device->buffConfig;
  310. /* Get the Frame size */
  311. status = ENET_ReadFrame(base_addr,handle,config,read_data,&length);
  312. if((status == kStatus_ENET_RxFrameEmpty)||(status == kStatus_ENET_RxFrameError))
  313. {
  314. ENET_EnableInterrupts(base_addr,ENET_RX_INTERRUPT);
  315. if(status == kStatus_ENET_RxFrameError)
  316. {
  317. /*recv error happend reinitialize mac*/
  318. ENET_Init(base_addr, handle, config, buffConfig, &imx6ul_device->dev_addr[0], SYS_CLOCK_HZ);
  319. ENET_ActiveRead(base_addr);
  320. return kStatus_ENET_RxFrameError;
  321. }
  322. else if(status == kStatus_ENET_RxFrameEmpty)
  323. {
  324. return kStatus_ENET_RxFrameEmpty;
  325. }
  326. }
  327. *read_length = length;
  328. return status;
  329. }
  330. /* transmit data*/
  331. rt_err_t rt_imx6ul_eth_tx(rt_device_t dev, struct pbuf *p)
  332. {
  333. rt_err_t ret = RT_ERROR;
  334. struct pbuf *q = RT_NULL;
  335. uint16_t offset = 0;
  336. uint32_t last_flag = 0;
  337. status_t status;
  338. ENET_Type *base_addr = RT_NULL;
  339. enet_handle_t *handle;
  340. struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)dev;
  341. base_addr = imx6ul_device->enet_virtual_base_addr;
  342. handle = &imx6ul_device->handle;
  343. RT_ASSERT(p);
  344. for(q = p;q != RT_NULL;q=q->next)
  345. {
  346. if(q->next == RT_NULL)
  347. {
  348. last_flag = 1;
  349. }
  350. else
  351. {
  352. last_flag = 0;
  353. }
  354. status = ENET_SendFrame(base_addr, handle, q->payload, q->len,last_flag);
  355. offset = offset + q->len;
  356. if(status == kStatus_Success)
  357. {
  358. }
  359. else
  360. {
  361. return RT_ERROR;
  362. }
  363. }
  364. if(offset > ENET_FRAME_MAX_FRAMELEN)
  365. {
  366. LOG_E("net error send length %d exceed max length",offset);
  367. }
  368. return ret;
  369. }
  370. struct pbuf *rt_imx6ul_eth_rx(rt_device_t dev)
  371. {
  372. static struct pbuf *p_s = RT_NULL;
  373. struct pbuf *p = RT_NULL;
  374. status_t status;
  375. uint16_t length = 0;
  376. if(p_s == RT_NULL)
  377. {
  378. p_s = pbuf_alloc(PBUF_RAW, ENET_FRAME_MAX_FRAMELEN, PBUF_POOL);
  379. if(p_s == RT_NULL)
  380. {
  381. return RT_NULL;
  382. }
  383. }
  384. p = p_s;
  385. status = read_data_from_eth(dev,p->payload,&length);
  386. if(status == kStatus_ENET_RxFrameEmpty)
  387. {
  388. return RT_NULL;
  389. }
  390. else if(status == kStatus_ENET_RxFrameError)
  391. {
  392. return RT_NULL;
  393. }
  394. if(length > ENET_FRAME_MAX_FRAMELEN)
  395. {
  396. LOG_E("net error recv length %d exceed max length",length);
  397. return RT_NULL;
  398. }
  399. pbuf_realloc(p, length);
  400. p_s = RT_NULL;
  401. return p;
  402. }
  403. int32_t get_instance_by_base(void *base)
  404. {
  405. int32_t i = 0;
  406. int32_t instance = 0;
  407. for(i = 0; i < DEV_ENET_MAX; i ++)
  408. {
  409. if((void *)_imx6ul_eth_device[i].enet_virtual_base_addr == base)
  410. {
  411. break;
  412. }
  413. }
  414. if(i == DEV_ENET_MAX)
  415. {
  416. return -1;
  417. }
  418. return instance;
  419. }
  420. void rx_enet_callback(void *base)
  421. {
  422. int32_t instance = 0;
  423. instance = get_instance_by_base(base);
  424. if(instance == -1)
  425. {
  426. LOG_E("interrput match base addr error");
  427. return;
  428. }
  429. eth_device_ready(&(_imx6ul_eth_device[instance].parent));
  430. ENET_DisableInterrupts(base,ENET_RX_INTERRUPT);
  431. }
  432. void tx_enet_callback(void *base)
  433. {
  434. ENET_DisableInterrupts(base,ENET_TX_INTERRUPT);
  435. }
  436. /*phy link detect thread*/
  437. static void phy_detect_thread_entry(void *param)
  438. {
  439. bool link = false;
  440. phy_speed_t speed;
  441. phy_duplex_t duplex;
  442. ENET_Type *base_addr = RT_NULL;
  443. struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)param;
  444. base_addr = imx6ul_device->enet_virtual_base_addr;
  445. phy_reset(imx6ul_device->phy_base_addr,imx6ul_device->phy_gpio_pin);
  446. PHY_Init(base_addr, imx6ul_device->phy_num, SYS_CLOCK_HZ,imx6ul_device->phy_id);
  447. PHY_GetLinkStatus(base_addr, imx6ul_device->phy_num, &link);
  448. if (link)
  449. {
  450. /* Get the actual PHY link speed. */
  451. PHY_GetLinkSpeedDuplex(base_addr, imx6ul_device->phy_num, &speed, &duplex);
  452. /* Change the MII speed and duplex for actual link status. */
  453. imx6ul_device->config.miiSpeed = (enet_mii_speed_t)speed;
  454. imx6ul_device->config.miiDuplex = (enet_mii_duplex_t)duplex;
  455. }
  456. else
  457. {
  458. LOG_W("PHY Link down, please check the cable connection and link partner setting.");
  459. }
  460. while(1)
  461. {
  462. PHY_GetLinkStatus(base_addr, imx6ul_device->phy_num, &link);
  463. if(link != imx6ul_device->phy_link_status)
  464. {
  465. if(link == true)
  466. {
  467. PHY_StartNegotiation(base_addr,imx6ul_device->phy_num);
  468. }
  469. imx6ul_eth_link_change(imx6ul_device,link);
  470. }
  471. rt_thread_delay(DETECT_DELAY_ONE_SECOND);
  472. }
  473. }
  474. _internal_ro struct rt_device_ops _k_enet_ops =
  475. {
  476. .init = rt_imx6ul_eth_init,
  477. .control = rt_imx6ul_eth_control,
  478. };
  479. static int imx6ul_eth_init(void)
  480. {
  481. rt_err_t state = RT_EOK;
  482. char link_detect[10];
  483. imx6ull_gpio_init(&mdio_gpio[0]);
  484. imx6ull_gpio_init(&mdio_gpio[1]);
  485. for (int idx=0; idx<GET_ARRAY_NUM(_imx6ul_eth_device); idx++)
  486. {
  487. _imx6ul_eth_device[idx].parent.parent.ops = &_k_enet_ops;
  488. _imx6ul_eth_device[idx].parent.eth_rx = rt_imx6ul_eth_rx;
  489. _imx6ul_eth_device[idx].parent.eth_tx = rt_imx6ul_eth_tx;
  490. _imx6ul_eth_device[idx].phy_link_status = RT_FALSE;
  491. /* register eth device */
  492. state = eth_device_init(&(_imx6ul_eth_device[idx].parent), _imx6ul_eth_device[idx].mac_name);
  493. if (RT_EOK == state)
  494. {
  495. LOG_I("emac device init success");
  496. }
  497. else
  498. {
  499. LOG_E("emac device init faild: %d", state);
  500. state = -RT_ERROR;
  501. }
  502. rt_sprintf(link_detect,"link_d%d",_imx6ul_eth_device[idx].mac_num);
  503. /* start phy link detect */
  504. rt_thread_t phy_link_tid;
  505. phy_link_tid = rt_thread_create(link_detect,
  506. phy_detect_thread_entry,
  507. &_imx6ul_eth_device[idx],
  508. 4096,
  509. RT_THREAD_PRIORITY_MAX - 2,
  510. 2);
  511. if (phy_link_tid != RT_NULL)
  512. {
  513. rt_thread_startup(phy_link_tid);
  514. }
  515. memset(link_detect,0,sizeof(link_detect));
  516. }
  517. return state;
  518. }
  519. INIT_DEVICE_EXPORT(imx6ul_eth_init);
  520. #endif