lan8742a.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077
  1. /*
  2. * Copyright (c) 2006-2018, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2017-08-25 LongfeiMa transplantation driver of lan8742a
  9. */
  10. #include <rtthread.h>
  11. #include "lan8742a.h"
  12. #include "etharp.h"
  13. #include "ethernetif.h"
  14. #include "stm32h7xx_hal.h"
  15. #include "lwip/opt.h"
  16. #include "lwip/ip_frag.h"
  17. #include "lwip/def.h"
  18. #include "lwip/inet_chksum.h"
  19. #include "lwip/netif.h"
  20. #include "lwip/snmp.h"
  21. #include "lwip/stats.h"
  22. #include "lwip/pbuf.h"
  23. #include "lwipopts.h"
  24. /** @defgroup LAN8742 LAN8742
  25. * @{
  26. */
  27. /* Private typedef -----------------------------------------------------------*/
  28. /* Private define ------------------------------------------------------------*/
  29. /** @defgroup LAN8742_Private_Defines LAN8742 Private Defines
  30. * @{
  31. */
  32. #define LAN8742_SW_RESET_TO ((uint32_t)500U) //software reset timeout deadline
  33. #define LAN8742_INIT_TO ((uint32_t)2000U)//Wait for 2000ms to perform initialization
  34. #define LAN8742_MAX_DEV_ADDR ((uint32_t)31U) //用于初始化时,搜索IC挂载的有效地址
  35. #if defined ( __ICCARM__ ) /*!< IAR Compiler */
  36. #pragma location=0x30040000
  37. ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
  38. #pragma location=0x30040060
  39. ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
  40. #pragma location=0x30040200
  41. uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE]; /* Ethernet Receive Buffers */
  42. #elif defined ( __CC_ARM ) /* MDK ARM Compiler */
  43. __attribute__((at(0x30040000))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
  44. __attribute__((at(0x30040060))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
  45. __attribute__((at(0x30040200))) uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE]; /* Ethernet Receive Buffer */
  46. #elif defined ( __GNUC__ ) /* GNU Compiler */
  47. ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDecripSection"))); /* Ethernet Rx DMA Descriptors */
  48. ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDecripSection"))); /* Ethernet Tx DMA Descriptors */
  49. uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE] __attribute__((section(".RxArraySection"))); /* Ethernet Receive Buffers */
  50. #endif
  51. struct pbuf_custom rx_pbuf[ETH_RX_DESC_CNT];
  52. uint32_t current_pbuf_idx =0;
  53. ETH_HandleTypeDef EthHandle;
  54. ETH_TxPacketConfig TxConfig;
  55. #define MAX_ADDR_LEN 6
  56. struct rt_lan8742_eth
  57. {
  58. /* inherit from ethernet device */
  59. struct eth_device parent;
  60. /* interface address info. */
  61. rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */
  62. };
  63. static struct rt_lan8742_eth lan8742_device;
  64. static struct rt_semaphore sem_lock;
  65. /*******************************************************************************
  66. PHI IO Functions
  67. *******************************************************************************/
  68. /**
  69. * @brief Initializes the MDIO interface GPIO and clocks.
  70. * @param None
  71. * @retval 0 if OK, -1 if ERROR
  72. */
  73. int32_t ETH_PHY_IO_Init(void)
  74. {
  75. /* We assume that MDIO GPIO configuration is already done
  76. in the ETH_MspInit() else it should be done here
  77. */
  78. /* Configure the MDIO Clock */
  79. HAL_ETH_SetMDIOClockRange(&EthHandle);
  80. return 0;
  81. }
  82. /**
  83. * @brief De-Initializes the MDIO interface .
  84. * @param None
  85. * @retval 0 if OK, -1 if ERROR
  86. */
  87. int32_t ETH_PHY_IO_DeInit (void)
  88. {
  89. return 0;
  90. }
  91. /**
  92. * @brief Read a PHY register through the MDIO interface.
  93. * @param DevAddr: PHY port address
  94. * @param RegAddr: PHY register address
  95. * @param pRegVal: pointer to hold the register value
  96. * @retval 0 if OK -1 if Error
  97. */
  98. int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal)
  99. {
  100. if(HAL_ETH_ReadPHYRegister(&EthHandle, DevAddr, RegAddr, pRegVal) != HAL_OK)
  101. {
  102. return -1;
  103. }
  104. return 0;
  105. }
  106. /**
  107. * @brief Write a value to a PHY register through the MDIO interface.
  108. * @param DevAddr: PHY port address
  109. * @param RegAddr: PHY register address
  110. * @param RegVal: Value to be written
  111. * @retval 0 if OK -1 if Error
  112. */
  113. int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal)
  114. {
  115. if(HAL_ETH_WritePHYRegister(&EthHandle, DevAddr, RegAddr, RegVal) != HAL_OK)
  116. {
  117. return -1;
  118. }
  119. return 0;
  120. }
  121. /**
  122. * @brief Get the time in millisecons used for internal PHY driver process.
  123. * @retval Time value
  124. */
  125. int32_t ETH_PHY_IO_GetTick(void)
  126. {
  127. return HAL_GetTick();
  128. }
  129. //IC相关结构体
  130. lan8742_Object_t LAN8742 =
  131. {
  132. 0, //LAN8742.DevAddr
  133. 0, //LAN8742.Is_Initialized
  134. {
  135. ETH_PHY_IO_Init, //LAN8742.IO.Init
  136. ETH_PHY_IO_DeInit, //LAN8742.IO.DeInit
  137. ETH_PHY_IO_WriteReg,//LAN8742.IO.WriteReg
  138. ETH_PHY_IO_ReadReg, //LAN8742.IO.ReadReg
  139. ETH_PHY_IO_GetTick, //LAN8742.IO.GetTick
  140. },
  141. NULL,
  142. };
  143. /*******************************************************************************
  144. Ethernet MSP Routines
  145. *******************************************************************************/
  146. /**
  147. * @brief Initializes the ETH MSP.
  148. * @param heth: ETH handle
  149. * @retval None
  150. */
  151. void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)
  152. {
  153. GPIO_InitTypeDef GPIO_InitStructure;
  154. /* Ethernett MSP init: RMII Mode */
  155. /* Enable GPIOs clocks */
  156. __HAL_RCC_GPIOA_CLK_ENABLE();
  157. __HAL_RCC_GPIOB_CLK_ENABLE();
  158. __HAL_RCC_GPIOC_CLK_ENABLE();
  159. __HAL_RCC_GPIOG_CLK_ENABLE();
  160. /* Ethernet pins configuration ************************************************/
  161. /*
  162. RMII_REF_CLK ----------------------> PA1
  163. RMII_MDIO -------------------------> PA2
  164. RMII_MDC --------------------------> PC1
  165. RMII_MII_CRS_DV -------------------> PA7
  166. RMII_MII_RXD0 ---------------------> PC4
  167. RMII_MII_RXD1 ---------------------> PC5
  168. RMII_MII_RXER ---------------------> PG2
  169. RMII_MII_TX_EN --------------------> PG11
  170. RMII_MII_TXD0 ---------------------> PG13
  171. RMII_MII_TXD1 ---------------------> PB13
  172. */
  173. /* Configure PA1, PA2 and PA7 */
  174. GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
  175. GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
  176. GPIO_InitStructure.Pull = GPIO_NOPULL;
  177. GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
  178. GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
  179. HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
  180. /* Configure PB13 */
  181. GPIO_InitStructure.Pin = GPIO_PIN_13;
  182. HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
  183. /* Configure PC1, PC4 and PC5 */
  184. GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
  185. HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
  186. /* Configure PG2, PG11, PG13 and PG14 */
  187. GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_11 | GPIO_PIN_13;
  188. HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
  189. /* Enable the Ethernet global Interrupt */
  190. HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0);
  191. HAL_NVIC_EnableIRQ(ETH_IRQn);
  192. /* Enable Ethernet clocks */
  193. __HAL_RCC_ETH1MAC_CLK_ENABLE();
  194. __HAL_RCC_ETH1TX_CLK_ENABLE();
  195. __HAL_RCC_ETH1RX_CLK_ENABLE();
  196. }
  197. /**
  198. * @brief Initialize the lan8742 and configure the needed hardware resources
  199. * @param void.
  200. * @retval LAN8742_STATUS_OK if OK
  201. * LAN8742_STATUS_ADDRESS_ERROR if cannot find device address
  202. * LAN8742_STATUS_READ_ERROR if connot read register
  203. * LAN8742_STATUS_WRITE_ERROR if connot write to register
  204. * LAN8742_STATUS_RESET_TIMEOUT if cannot perform a software reset
  205. */
  206. static int32_t LAN8742_Init(lan8742_Object_t *pObj)
  207. {
  208. uint32_t tickstart = 0, regvalue = 0, addr = 0;
  209. int32_t status = LAN8742_STATUS_OK;
  210. if(pObj->Is_Initialized == 0)
  211. {
  212. if(pObj->IO.Init != 0)
  213. {
  214. /* GPIO and Clocks initialization */
  215. pObj->IO.Init();
  216. }
  217. /* for later check */
  218. pObj->DevAddr = LAN8742_MAX_DEV_ADDR + 1;
  219. /* Get the device address from special mode register */
  220. for(addr = 0; addr <= LAN8742_MAX_DEV_ADDR; addr ++)
  221. {
  222. if(pObj->IO.ReadReg(addr, LAN8742_REG_SMR, &regvalue) < 0)
  223. {
  224. status = LAN8742_STATUS_READ_ERROR;
  225. /* Can't read from this device address
  226. continue with next address */
  227. continue;
  228. }
  229. if((regvalue & LAN8742_SMR_PHY_ADDR) == addr)
  230. {
  231. pObj->DevAddr = addr;
  232. status = LAN8742_STATUS_OK;
  233. break;
  234. }
  235. }
  236. if(pObj->DevAddr > LAN8742_MAX_DEV_ADDR)
  237. {
  238. status = LAN8742_STATUS_ADDRESS_ERROR;
  239. }
  240. /* if device address is matched */
  241. if(status == LAN8742_STATUS_OK)
  242. {
  243. /* set a software reset */
  244. if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_REG_BCR, LAN8742_BCR_RESET) >= 0)
  245. {
  246. /* get software reset status */
  247. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_BCR, &regvalue) >= 0)
  248. {
  249. tickstart = pObj->IO.GetTick();
  250. /* wait until software reset is done or timeout occured */
  251. while(regvalue & LAN8742_BCR_RESET)
  252. {
  253. if((pObj->IO.GetTick() - tickstart) <= LAN8742_SW_RESET_TO)
  254. {
  255. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_BCR, &regvalue) < 0)
  256. {
  257. status = LAN8742_STATUS_READ_ERROR;
  258. break;
  259. }
  260. }
  261. else
  262. {
  263. status = LAN8742_STATUS_RESET_TIMEOUT;
  264. }
  265. }
  266. }
  267. else
  268. {
  269. status = LAN8742_STATUS_READ_ERROR;
  270. }
  271. }
  272. else
  273. {
  274. status = LAN8742_STATUS_WRITE_ERROR;
  275. }
  276. }
  277. }
  278. if(status == LAN8742_STATUS_OK)
  279. {
  280. tickstart = pObj->IO.GetTick();
  281. /* Wait for 2s to perform initialization */
  282. while((pObj->IO.GetTick() - tickstart) <= LAN8742_INIT_TO)
  283. {
  284. }
  285. pObj->Is_Initialized = 1;
  286. }
  287. return status;
  288. }
  289. /**
  290. * @brief De-Initialize the lan8742 and it's hardware resources
  291. * @param void.
  292. * @retval LAN8742_STATUS_ERROR / LAN8742_STATUS_OK
  293. */
  294. static int32_t LAN8742_DeInit(lan8742_Object_t *pObj)
  295. {
  296. if(pObj->Is_Initialized)
  297. {
  298. if(pObj->IO.DeInit != 0)
  299. {
  300. if(pObj->IO.DeInit() < 0)
  301. {
  302. return LAN8742_STATUS_ERROR;
  303. }
  304. }
  305. pObj->Is_Initialized = 0;
  306. }
  307. return LAN8742_STATUS_OK;
  308. }
  309. /**
  310. * @brief Disable the LAN8742 power down mode.
  311. * @param pObj: device object LAN8742_Object_t.
  312. * @retval LAN8742_STATUS_OK if OK
  313. * LAN8742_STATUS_READ_ERROR if connot read register
  314. * LAN8742_STATUS_WRITE_ERROR if connot write to register
  315. */
  316. static int32_t LAN8742_DisablePowerDownMode(lan8742_Object_t *pObj)
  317. {
  318. uint32_t readval = 0;
  319. int32_t status = LAN8742_STATUS_OK;
  320. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_BCR, &readval) >= 0)
  321. {
  322. readval &= ~LAN8742_BCR_POWER_DOWN;
  323. /* Apply configuration */
  324. if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_REG_BCR, readval) < 0)
  325. {
  326. status = LAN8742_STATUS_WRITE_ERROR;
  327. }
  328. }
  329. else
  330. {
  331. status = LAN8742_STATUS_READ_ERROR;
  332. }
  333. return status;
  334. }
  335. /**
  336. * @brief Enable the LAN8742 power down mode.
  337. * @param pObj: device object LAN8742_Object_t.
  338. * @retval LAN8742_STATUS_OK if OK
  339. * LAN8742_STATUS_READ_ERROR if connot read register
  340. * LAN8742_STATUS_WRITE_ERROR if connot write to register
  341. */
  342. static int32_t LAN8742_EnablePowerDownMode(lan8742_Object_t *pObj)
  343. {
  344. uint32_t readval = 0;
  345. int32_t status = LAN8742_STATUS_OK;
  346. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_BCR, &readval) >= 0)
  347. {
  348. readval |= LAN8742_BCR_POWER_DOWN;
  349. /* Apply configuration */
  350. if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_REG_BCR, readval) < 0)
  351. {
  352. status = LAN8742_STATUS_WRITE_ERROR;
  353. }
  354. }
  355. else
  356. {
  357. status = LAN8742_STATUS_READ_ERROR;
  358. }
  359. return status;
  360. }
  361. /**
  362. * @brief Start the auto negotiation process.
  363. * @param pObj: device object LAN8742_Object_t.
  364. * @retval LAN8742_STATUS_OK if OK
  365. * LAN8742_STATUS_READ_ERROR if connot read register
  366. * LAN8742_STATUS_WRITE_ERROR if connot write to register
  367. */
  368. static int32_t LAN8742_StartAutoNego(lan8742_Object_t *pObj)
  369. {
  370. uint32_t readval = 0;
  371. int32_t status = LAN8742_STATUS_OK;
  372. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_BCR, &readval) >= 0)
  373. {
  374. readval |= LAN8742_BCR_ANEG_EN;
  375. /* Apply configuration */
  376. if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_REG_BCR, readval) < 0)
  377. {
  378. status = LAN8742_STATUS_WRITE_ERROR;
  379. }
  380. }
  381. else
  382. {
  383. status = LAN8742_STATUS_READ_ERROR;
  384. }
  385. return status;
  386. }
  387. /**
  388. * @brief Get the link state of LAN8742 device.
  389. * @param pObj: Pointer to device object.
  390. * @param pLinkState: Pointer to link state
  391. * @retval LAN8742_STATUS_LINK_DOWN if link is down
  392. * LAN8742_STATUS_AUTONEGO_NOTDONE if Auto nego not completed
  393. * LAN8742_STATUS_100MBITS_FULLDUPLEX if 100Mb/s FD
  394. * LAN8742_STATUS_100MBITS_HALFDUPLEX if 100Mb/s HD
  395. * LAN8742_STATUS_10MBITS_FULLDUPLEX if 10Mb/s FD
  396. * LAN8742_STATUS_10MBITS_HALFDUPLEX if 10Mb/s HD
  397. * LAN8742_STATUS_READ_ERROR if connot read register
  398. * LAN8742_STATUS_WRITE_ERROR if connot write to register
  399. */
  400. static int32_t LAN8742_GetLinkState(lan8742_Object_t *pObj)
  401. {
  402. uint32_t readval = 0;
  403. /* Read Status register */
  404. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_BSR, &readval) < 0)
  405. {
  406. return LAN8742_STATUS_READ_ERROR;
  407. }
  408. /* Read Status register again */
  409. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_BSR, &readval) < 0)
  410. {
  411. return LAN8742_STATUS_READ_ERROR;
  412. }
  413. if((readval & LAN8742_BSR_LINK_STAT) == 0)
  414. {
  415. /* Return Link Down status */
  416. return LAN8742_STATUS_LINK_DOWN;
  417. }
  418. /* Check Auto negotiaition */
  419. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_BCR, &readval) < 0)
  420. {
  421. return LAN8742_STATUS_READ_ERROR;
  422. }
  423. if((readval & LAN8742_BCR_ANEG_EN) != LAN8742_BCR_ANEG_EN)
  424. {
  425. if(((readval & LAN8742_BCR_SPEED_SEL) == LAN8742_BCR_SPEED_SEL) && ((readval & LAN8742_BCR_DUPLEX) == LAN8742_BCR_DUPLEX))
  426. {
  427. return LAN8742_STATUS_100MBITS_FULLDUPLEX;
  428. }
  429. else if ((readval & LAN8742_BCR_SPEED_SEL) == LAN8742_BCR_SPEED_SEL)
  430. {
  431. return LAN8742_STATUS_100MBITS_HALFDUPLEX;
  432. }
  433. else if ((readval & LAN8742_BCR_DUPLEX) == LAN8742_BCR_DUPLEX)
  434. {
  435. return LAN8742_STATUS_10MBITS_FULLDUPLEX;
  436. }
  437. else
  438. {
  439. return LAN8742_STATUS_10MBITS_HALFDUPLEX;
  440. }
  441. }
  442. else /* Auto Nego enabled */
  443. {
  444. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_PSCS, &readval) < 0)
  445. {
  446. return LAN8742_STATUS_READ_ERROR;
  447. }
  448. /* Check if auto nego not done */
  449. if((readval & LAN8742_PHYSCSR_AUTONEGO_DONE) == 0)
  450. {
  451. return LAN8742_STATUS_AUTONEGO_NOTDONE;
  452. }
  453. if((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_100BTX_FD)
  454. {
  455. return LAN8742_STATUS_100MBITS_FULLDUPLEX;
  456. }
  457. else if ((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_100BTX_HD)
  458. {
  459. return LAN8742_STATUS_100MBITS_HALFDUPLEX;
  460. }
  461. else if ((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_10BT_FD)
  462. {
  463. return LAN8742_STATUS_10MBITS_FULLDUPLEX;
  464. }
  465. else
  466. {
  467. return LAN8742_STATUS_10MBITS_HALFDUPLEX;
  468. }
  469. }
  470. }
  471. /**
  472. * @brief Set the link state of LAN8742 device.
  473. * @param pObj: Pointer to device object.
  474. * @param pLinkState: link state can be one of the following
  475. * LAN8742_STATUS_100MBITS_FULLDUPLEX if 100Mb/s FD
  476. * LAN8742_STATUS_100MBITS_HALFDUPLEX if 100Mb/s HD
  477. * LAN8742_STATUS_10MBITS_FULLDUPLEX if 10Mb/s FD
  478. * LAN8742_STATUS_10MBITS_HALFDUPLEX if 10Mb/s HD
  479. * @retval LAN8742_STATUS_OK if OK
  480. * LAN8742_STATUS_ERROR if parameter error
  481. * LAN8742_STATUS_READ_ERROR if connot read register
  482. * LAN8742_STATUS_WRITE_ERROR if connot write to register
  483. */
  484. static int32_t LAN8742_SetLinkState(lan8742_Object_t *pObj, uint32_t LinkState)
  485. {
  486. uint32_t bcrvalue = 0;
  487. int32_t status = LAN8742_STATUS_OK;
  488. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_BCR, &bcrvalue) >= 0)
  489. {
  490. /* Disable link config (Auto nego, speed and duplex) */
  491. bcrvalue &= ~(LAN8742_BCR_ANEG_EN | LAN8742_BCR_SPEED_SEL | LAN8742_BCR_DUPLEX);
  492. if(LinkState == LAN8742_STATUS_100MBITS_FULLDUPLEX)
  493. {
  494. bcrvalue |= (LAN8742_BCR_SPEED_SEL | LAN8742_BCR_DUPLEX);
  495. }
  496. else if (LinkState == LAN8742_STATUS_100MBITS_HALFDUPLEX)
  497. {
  498. bcrvalue |= LAN8742_BCR_SPEED_SEL;
  499. }
  500. else if (LinkState == LAN8742_STATUS_10MBITS_FULLDUPLEX)
  501. {
  502. bcrvalue |= LAN8742_BCR_DUPLEX;
  503. }
  504. else
  505. {
  506. /* Wrong link status parameter */
  507. status = LAN8742_STATUS_ERROR;
  508. }
  509. }
  510. else
  511. {
  512. status = LAN8742_STATUS_READ_ERROR;
  513. }
  514. if(status == LAN8742_STATUS_OK)
  515. {
  516. /* Apply configuration */
  517. if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_REG_BCR, bcrvalue) < 0)
  518. {
  519. status = LAN8742_STATUS_WRITE_ERROR;
  520. }
  521. }
  522. return status;
  523. }
  524. /**
  525. * @brief Enable loopback mode.
  526. * @param pObj: Pointer to device object.
  527. * @retval LAN8742_STATUS_OK if OK
  528. * LAN8742_STATUS_READ_ERROR if connot read register
  529. * LAN8742_STATUS_WRITE_ERROR if connot write to register
  530. */
  531. static int32_t LAN8742_EnableLoopbackMode(lan8742_Object_t *pObj)
  532. {
  533. uint32_t readval = 0;
  534. int32_t status = LAN8742_STATUS_OK;
  535. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_BCR, &readval) >= 0)
  536. {
  537. readval |= LAN8742_BCR_LOOPBACK;
  538. /* Apply configuration */
  539. if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_REG_BCR, readval) < 0)
  540. {
  541. status = LAN8742_STATUS_WRITE_ERROR;
  542. }
  543. }
  544. else
  545. {
  546. status = LAN8742_STATUS_READ_ERROR;
  547. }
  548. return status;
  549. }
  550. /**
  551. * @brief Disable loopback mode.
  552. * @param pObj: Pointer to device object.
  553. * @retval LAN8742_STATUS_OK if OK
  554. * LAN8742_STATUS_READ_ERROR if connot read register
  555. * LAN8742_STATUS_WRITE_ERROR if connot write to register
  556. */
  557. static int32_t LAN8742_DisableLoopbackMode(lan8742_Object_t *pObj)
  558. {
  559. uint32_t readval = 0;
  560. int32_t status = LAN8742_STATUS_OK;
  561. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_BCR, &readval) >= 0)
  562. {
  563. readval &= ~LAN8742_BCR_LOOPBACK;
  564. /* Apply configuration */
  565. if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_REG_BCR, readval) < 0)
  566. {
  567. status = LAN8742_STATUS_WRITE_ERROR;
  568. }
  569. }
  570. else
  571. {
  572. status = LAN8742_STATUS_READ_ERROR;
  573. }
  574. return status;
  575. }
  576. /**
  577. * @brief Enable IT source.
  578. * @param pObj: Pointer to device object.
  579. * @param Interrupt: IT source to be enabled
  580. * should be a value or a combination of the following:
  581. * LAN8742_WOL_IT
  582. * LAN8742_ENERGYON_IT
  583. * LAN8742_AUTONEGO_COMPLETE_IT
  584. * LAN8742_REMOTE_FAULT_IT
  585. * LAN8742_LINK_DOWN_IT
  586. * LAN8742_AUTONEGO_LP_ACK_IT
  587. * LAN8742_PARALLEL_DETECTION_FAULT_IT
  588. * LAN8742_AUTONEGO_PAGE_RECEIVED_IT
  589. * @retval LAN8742_STATUS_OK if OK
  590. * LAN8742_STATUS_READ_ERROR if connot read register
  591. * LAN8742_STATUS_WRITE_ERROR if connot write to register
  592. */
  593. static int32_t LAN8742_EnableIT(lan8742_Object_t *pObj, uint32_t Interrupt)
  594. {
  595. uint32_t readval = 0;
  596. int32_t status = LAN8742_STATUS_OK;
  597. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_IM, &readval) >= 0)
  598. {
  599. readval |= Interrupt;
  600. /* Apply configuration */
  601. if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_REG_IM, readval) < 0)
  602. {
  603. status = LAN8742_STATUS_WRITE_ERROR;
  604. }
  605. }
  606. else
  607. {
  608. status = LAN8742_STATUS_READ_ERROR;
  609. }
  610. return status;
  611. }
  612. /**
  613. * @brief Disable IT source.
  614. * @param pObj: Pointer to device object.
  615. * @param Interrupt: IT source to be disabled
  616. * should be a value or a combination of the following:
  617. * LAN8742_WOL_IT
  618. * LAN8742_ENERGYON_IT
  619. * LAN8742_AUTONEGO_COMPLETE_IT
  620. * LAN8742_REMOTE_FAULT_IT
  621. * LAN8742_LINK_DOWN_IT
  622. * LAN8742_AUTONEGO_LP_ACK_IT
  623. * LAN8742_PARALLEL_DETECTION_FAULT_IT
  624. * LAN8742_AUTONEGO_PAGE_RECEIVED_IT
  625. * @retval LAN8742_STATUS_OK if OK
  626. * LAN8742_STATUS_READ_ERROR if connot read register
  627. * LAN8742_STATUS_WRITE_ERROR if connot write to register
  628. */
  629. static int32_t LAN8742_DisableIT(lan8742_Object_t *pObj, uint32_t Interrupt)
  630. {
  631. uint32_t readval = 0;
  632. int32_t status = LAN8742_STATUS_OK;
  633. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_IM, &readval) >= 0)
  634. {
  635. readval &= ~Interrupt;
  636. /* Apply configuration */
  637. if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_REG_IM, readval) < 0)
  638. {
  639. status = LAN8742_STATUS_WRITE_ERROR;
  640. }
  641. }
  642. else
  643. {
  644. status = LAN8742_STATUS_READ_ERROR;
  645. }
  646. return status;
  647. }
  648. /**
  649. * @brief Clear IT flag.
  650. * @param pObj: Pointer to device object.
  651. * @param Interrupt: IT flag to be cleared
  652. * should be a value or a combination of the following:
  653. * LAN8742_WOL_IT
  654. * LAN8742_ENERGYON_IT
  655. * LAN8742_AUTONEGO_COMPLETE_IT
  656. * LAN8742_REMOTE_FAULT_IT
  657. * LAN8742_LINK_DOWN_IT
  658. * LAN8742_AUTONEGO_LP_ACK_IT
  659. * LAN8742_PARALLEL_DETECTION_FAULT_IT
  660. * LAN8742_AUTONEGO_PAGE_RECEIVED_IT
  661. * @retval LAN8742_STATUS_OK if OK
  662. * LAN8742_STATUS_READ_ERROR if connot read register
  663. */
  664. static int32_t LAN8742_ClearIT(lan8742_Object_t *pObj, uint32_t Interrupt)
  665. {
  666. uint32_t readval = 0;
  667. int32_t status = LAN8742_STATUS_OK;
  668. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_ISF, &readval) < 0)
  669. {
  670. status = LAN8742_STATUS_READ_ERROR;
  671. }
  672. return status;
  673. }
  674. /**
  675. * @brief Get IT Flag status.
  676. * @param pObj: Pointer to device object.
  677. * @param Interrupt: IT Flag to be checked,
  678. * should be a value or a combination of the following:
  679. * LAN8742_WOL_IT
  680. * LAN8742_ENERGYON_IT
  681. * LAN8742_AUTONEGO_COMPLETE_IT
  682. * LAN8742_REMOTE_FAULT_IT
  683. * LAN8742_LINK_DOWN_IT
  684. * LAN8742_AUTONEGO_LP_ACK_IT
  685. * LAN8742_PARALLEL_DETECTION_FAULT_IT
  686. * LAN8742_AUTONEGO_PAGE_RECEIVED_IT
  687. * @retval 1 IT flag is SET
  688. * 0 IT flag is RESET
  689. * LAN8742_STATUS_READ_ERROR if connot read register
  690. */
  691. static int32_t LAN8742_GetITStatus(lan8742_Object_t *pObj, uint32_t Interrupt)
  692. {
  693. uint32_t readval = 0;
  694. int32_t status = 0;
  695. if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_REG_ISF, &readval) >= 0)
  696. {
  697. status = ((readval & Interrupt) == Interrupt);
  698. }
  699. else
  700. {
  701. status = LAN8742_STATUS_READ_ERROR;
  702. }
  703. return status;
  704. }
  705. static rt_err_t rt_lan8742_init(rt_device_t dev)
  706. {
  707. return RT_EOK;
  708. }
  709. static rt_err_t rt_lan8742_open(rt_device_t dev, rt_uint16_t oflag)
  710. {
  711. return RT_EOK;
  712. }
  713. static rt_err_t rt_lan8742_close(rt_device_t dev)
  714. {
  715. LAN8742_DeInit(&LAN8742);
  716. LAN8742_DisableIT(&LAN8742, LAN8742_INT_ALL);
  717. LAN8742_EnablePowerDownMode(&LAN8742);
  718. return RT_EOK;
  719. }
  720. static rt_size_t rt_lan8742_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
  721. {
  722. rt_set_errno(-RT_ENOSYS);
  723. return 0;
  724. }
  725. static rt_size_t rt_lan8742_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
  726. {
  727. rt_set_errno(-RT_ENOSYS);
  728. return 0;
  729. }
  730. static rt_err_t rt_lan8742_control(rt_device_t dev, rt_uint8_t cmd, void *args)
  731. {
  732. switch (cmd)
  733. {
  734. case NIOCTL_GADDR:
  735. /* get mac address */
  736. if (args)
  737. rt_memcpy(args, lan8742_device.dev_addr, 6);
  738. else
  739. return -RT_ERROR;
  740. break;
  741. default :
  742. break;
  743. }
  744. return RT_EOK;
  745. }
  746. /* ethernet device interface */
  747. /* transmit packet. */
  748. rt_err_t rt_lan8742_tx( rt_device_t dev, struct pbuf* p)
  749. {
  750. uint32_t i=0, framelen = 0;
  751. struct pbuf *q;
  752. err_t errval = ERR_OK;
  753. ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT];
  754. /* lock LAN8742 device */
  755. rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
  756. memset(Txbuffer, 0 , 4*sizeof(ETH_BufferTypeDef));
  757. for(q = p; q != NULL; q = q->next)
  758. {
  759. if(i >= ETH_TX_DESC_CNT)
  760. return ERR_IF;
  761. Txbuffer[i].buffer = q->payload;
  762. Txbuffer[i].len = q->len;
  763. framelen += q->len;
  764. if(i>0)
  765. {
  766. Txbuffer[i-1].next = &Txbuffer[i];
  767. }
  768. i++;
  769. }
  770. TxConfig.Length = framelen;
  771. TxConfig.TxBuffer = Txbuffer;
  772. /* Clean and Invalidate data cache */
  773. SCB_CleanInvalidateDCache();
  774. HAL_ETH_Transmit(&EthHandle, &TxConfig, 0);//Transmit an ETH frame in blocking mode
  775. /* unlock LAN8742 device */
  776. rt_sem_release(&sem_lock);
  777. return errval;
  778. }
  779. /* reception packet. */
  780. struct pbuf *rt_lan8742_rx(rt_device_t dev)
  781. {
  782. struct pbuf* p = RT_NULL;
  783. ETH_BufferTypeDef RxBuff;
  784. uint32_t framelength = 0;
  785. /* lock LAN8742 device */
  786. rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
  787. /* Clean and Invalidate data cache */
  788. SCB_CleanInvalidateDCache();
  789. if(HAL_ETH_GetRxDataBuffer(&EthHandle, &RxBuff) == HAL_OK)
  790. {
  791. HAL_ETH_GetRxDataLength(&EthHandle, &framelength);
  792. p = pbuf_alloced_custom(PBUF_RAW, framelength, PBUF_POOL, &rx_pbuf[current_pbuf_idx], RxBuff.buffer, framelength);
  793. if(current_pbuf_idx < (ETH_RX_DESC_CNT -1))
  794. {
  795. current_pbuf_idx++;
  796. }
  797. else
  798. {
  799. current_pbuf_idx = 0;
  800. }
  801. }
  802. HAL_ETH_BuildRxDescriptors(&EthHandle);
  803. /* unlock LAN8742 device */
  804. rt_sem_release(&sem_lock);
  805. return p;
  806. }
  807. /**
  808. * @brief Custom Rx pbuf free callback
  809. * @param pbuf: pbuf to be freed
  810. * @retval None
  811. */
  812. static void pbuf_free_custom(struct pbuf *p)
  813. {
  814. if(p != NULL)
  815. {
  816. p->flags = 0;
  817. p->next = NULL;
  818. p->len = p->tot_len = 0;
  819. p->ref = 0;
  820. p->payload = NULL;
  821. }
  822. }
  823. int rt_hw_lan8742a_init(void)
  824. {
  825. uint32_t idx, duplex, speed = 0;
  826. int32_t PHYLinkState;
  827. ETH_MACConfigTypeDef MACConf;
  828. uint8_t macaddress[6]= {ETH_MAC_ADDR0, ETH_MAC_ADDR1, ETH_MAC_ADDR2,
  829. ETH_MAC_ADDR3, ETH_MAC_ADDR4, ETH_MAC_ADDR5};
  830. EthHandle.Instance = ETH;
  831. EthHandle.Init.MACAddr = macaddress;
  832. EthHandle.Init.MediaInterface = HAL_ETH_RMII_MODE;
  833. EthHandle.Init.RxDesc = DMARxDscrTab;
  834. EthHandle.Init.TxDesc = DMATxDscrTab;
  835. EthHandle.Init.RxBuffLen = ETH_MAX_PACKET_SIZE;
  836. /* configure ethernet peripheral (GPIOs, clocks, MAC, DMA) */
  837. HAL_ETH_Init(&EthHandle);
  838. for(idx = 0; idx < ETH_RX_DESC_CNT; idx ++)
  839. {
  840. HAL_ETH_DescAssignMemory(&EthHandle, idx, Rx_Buff[idx], NULL);
  841. /* Set Custom pbuf free function */
  842. rx_pbuf[idx].custom_free_function = pbuf_free_custom;
  843. }
  844. memset(&TxConfig, 0 , sizeof(ETH_TxPacketConfig));
  845. TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
  846. TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
  847. TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;
  848. /* Initialize the LAN8742 ETH PHY */
  849. LAN8742_Init(&LAN8742);
  850. /* Get link state */
  851. PHYLinkState = LAN8742_GetLinkState(&LAN8742);
  852. /* Get link state */
  853. if(PHYLinkState <= LAN8742_STATUS_LINK_DOWN)
  854. {
  855. //
  856. }
  857. else
  858. {
  859. switch (PHYLinkState)
  860. {
  861. case LAN8742_STATUS_100MBITS_FULLDUPLEX:
  862. duplex = ETH_FULLDUPLEX_MODE;
  863. speed = ETH_SPEED_100M;
  864. break;
  865. case LAN8742_STATUS_100MBITS_HALFDUPLEX:
  866. duplex = ETH_HALFDUPLEX_MODE;
  867. speed = ETH_SPEED_100M;
  868. break;
  869. case LAN8742_STATUS_10MBITS_FULLDUPLEX:
  870. duplex = ETH_FULLDUPLEX_MODE;
  871. speed = ETH_SPEED_10M;
  872. break;
  873. case LAN8742_STATUS_10MBITS_HALFDUPLEX:
  874. duplex = ETH_HALFDUPLEX_MODE;
  875. speed = ETH_SPEED_10M;
  876. break;
  877. default:
  878. duplex = ETH_FULLDUPLEX_MODE;
  879. speed = ETH_SPEED_100M;
  880. break;
  881. }
  882. /* Get MAC Config MAC */
  883. HAL_ETH_GetMACConfig(&EthHandle, &MACConf);
  884. MACConf.DuplexMode = duplex;
  885. MACConf.Speed = speed;
  886. HAL_ETH_SetMACConfig(&EthHandle, &MACConf);
  887. HAL_ETH_Start_IT(&EthHandle);
  888. }
  889. rt_sem_init(&sem_lock, "eth_lock", 1, RT_IPC_FLAG_FIFO);
  890. rt_memcpy(lan8742_device.dev_addr, macaddress, 6);
  891. lan8742_device.parent.parent.init = rt_lan8742_init;
  892. lan8742_device.parent.parent.open = rt_lan8742_open;
  893. lan8742_device.parent.parent.close = rt_lan8742_close;
  894. lan8742_device.parent.parent.read = rt_lan8742_read;
  895. lan8742_device.parent.parent.write = rt_lan8742_write;
  896. lan8742_device.parent.parent.control = rt_lan8742_control;
  897. lan8742_device.parent.parent.user_data = RT_NULL;
  898. lan8742_device.parent.eth_rx = rt_lan8742_rx;
  899. lan8742_device.parent.eth_tx = rt_lan8742_tx;
  900. eth_device_init(&(lan8742_device.parent), "e0");
  901. return 0;
  902. }
  903. INIT_DEVICE_EXPORT(rt_hw_lan8742a_init);
  904. #ifdef RT_USING_LWIP
  905. /**
  906. * @brief This function handles Ethernet interrupt request.
  907. * @param None
  908. * @retval None
  909. */
  910. void ETH_IRQHandler(void)
  911. {
  912. HAL_ETH_IRQHandler(&EthHandle);
  913. }
  914. #endif /* RT_USING_LWIP */
  915. /**
  916. * @brief Ethernet Rx Transfer completed callback
  917. * @param heth: ETH handle
  918. * @retval None
  919. */
  920. void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
  921. {
  922. /* a frame has been received */
  923. eth_device_ready(&(lan8742_device.parent));
  924. }