PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/m480_eth.c

https://gitlab.com/21mece13/FreeRTOS
C | 448 lines | 285 code | 94 blank | 69 comment | 32 complexity | d4d617c3791fdf8770f708be5368d7d2 MD5 | raw file
  1. /**************************************************************************//**
  2. * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without modification,
  5. * are permitted provided that the following conditions are met:
  6. * 1. Redistributions of source code must retain the above copyright notice,
  7. * this list of conditions and the following disclaimer.
  8. * 2. Redistributions in binary form must reproduce the above copyright notice,
  9. * this list of conditions and the following disclaimer in the documentation
  10. * and/or other materials provided with the distribution.
  11. * 3. Neither the name of Nuvoton Technology Corp. nor the names of its contributors
  12. * may be used to endorse or promote products derived from this software
  13. * without specific prior written permission.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. *****************************************************************************/
  26. #include "FreeRTOS.h"
  27. #include "list.h"
  28. #include "FreeRTOS_IP.h"
  29. #include "m480_eth.h"
  30. #define ETH_TRIGGER_RX() do{EMAC->RXST = 0;}while(0)
  31. #define ETH_TRIGGER_TX() do{EMAC->TXST = 0;}while(0)
  32. #define ETH_ENABLE_TX() do{EMAC->CTL |= EMAC_CTL_TXON;}while(0)
  33. #define ETH_ENABLE_RX() do{EMAC->CTL |= EMAC_CTL_RXON;}while(0)
  34. #define ETH_DISABLE_TX() do{EMAC->CTL &= ~EMAC_CTL_TXON;}while(0)
  35. #define ETH_DISABLE_RX() do{EMAC->CTL &= ~EMAC_CTL_RXON;}while(0)
  36. struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
  37. struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
  38. #ifdef __ICCARM__
  39. #pragma data_alignment=4
  40. struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM];
  41. struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM];
  42. uint8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
  43. uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
  44. #else
  45. struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
  46. struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
  47. uint8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE] __attribute__ ((aligned(4)));
  48. uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE] __attribute__ ((aligned(4)));
  49. #endif
  50. struct eth_descriptor volatile *cur_tx_desc_ptr, *cur_rx_desc_ptr, *fin_tx_desc_ptr;
  51. // PTP source clock is 84MHz (Real chip using PLL). Each tick is 11.90ns
  52. // Assume we want to set each tick to 100ns.
  53. // Increase register = (100 * 2^31) / (10^9) = 214.71 =~ 215 = 0xD7
  54. // Addend register = 2^32 * tick_freq / (84MHz), where tick_freq = (2^31 / 215) MHz
  55. // From above equation, addend register = 2^63 / (84M * 215) ~= 510707200 = 0x1E70C600
  56. static void mdio_write(uint8_t addr, uint8_t reg, uint16_t val)
  57. {
  58. EMAC->MIIMDAT = val;
  59. EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_WRITE_Msk | EMAC_MIIMCTL_MDCON_Msk;
  60. while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk);
  61. }
  62. static uint16_t mdio_read(uint8_t addr, uint8_t reg)
  63. {
  64. EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk;
  65. while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk);
  66. return(EMAC->MIIMDAT);
  67. }
  68. static int reset_phy(void)
  69. {
  70. uint16_t reg;
  71. uint32_t delayCnt;
  72. mdio_write(CONFIG_PHY_ADDR, MII_BMCR, BMCR_RESET);
  73. delayCnt = 2000;
  74. while(delayCnt-- > 0) {
  75. if((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0)
  76. break;
  77. }
  78. if(delayCnt == 0) {
  79. NU_DEBUGF(("Reset phy failed\n"));
  80. return(-1);
  81. }
  82. mdio_write(CONFIG_PHY_ADDR, MII_ADVERTISE, ADVERTISE_CSMA |
  83. ADVERTISE_10HALF |
  84. ADVERTISE_10FULL |
  85. ADVERTISE_100HALF |
  86. ADVERTISE_100FULL);
  87. reg = mdio_read(CONFIG_PHY_ADDR, MII_BMCR);
  88. mdio_write(CONFIG_PHY_ADDR, MII_BMCR, reg | BMCR_ANRESTART);
  89. delayCnt = 200000;
  90. while(delayCnt-- > 0) {
  91. if((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
  92. == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
  93. break;
  94. }
  95. if(delayCnt == 0) {
  96. NU_DEBUGF(("AN failed. Set to 100 FULL\n"));
  97. EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
  98. return(-1);
  99. } else {
  100. reg = mdio_read(CONFIG_PHY_ADDR, MII_LPA);
  101. if(reg & ADVERTISE_100FULL) {
  102. NU_DEBUGF(("100 full\n"));
  103. EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
  104. } else if(reg & ADVERTISE_100HALF) {
  105. NU_DEBUGF(("100 half\n"));
  106. EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk;
  107. } else if(reg & ADVERTISE_10FULL) {
  108. NU_DEBUGF(("10 full\n"));
  109. EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk;
  110. } else {
  111. NU_DEBUGF(("10 half\n"));
  112. EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
  113. }
  114. }
  115. FreeRTOS_printf(("PHY ID 1:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID1)));
  116. FreeRTOS_printf(("PHY ID 2:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID2)));
  117. return(0);
  118. }
  119. static void init_tx_desc(void)
  120. {
  121. uint32_t i;
  122. cur_tx_desc_ptr = fin_tx_desc_ptr = &tx_desc[0];
  123. for(i = 0; i < TX_DESCRIPTOR_NUM; i++) {
  124. tx_desc[i].status1 = TXFD_PADEN | TXFD_CRCAPP | TXFD_INTEN;
  125. tx_desc[i].buf = &tx_buf[i][0];
  126. tx_desc[i].status2 = 0;
  127. tx_desc[i].next = &tx_desc[(i + 1) % TX_DESCRIPTOR_NUM];
  128. }
  129. EMAC->TXDSA = (unsigned int)&tx_desc[0];
  130. return;
  131. }
  132. static void init_rx_desc(void)
  133. {
  134. uint32_t i;
  135. cur_rx_desc_ptr = &rx_desc[0];
  136. for(i = 0; i < RX_DESCRIPTOR_NUM; i++) {
  137. rx_desc[i].status1 = OWNERSHIP_EMAC;
  138. rx_desc[i].buf = &rx_buf[i][0];
  139. rx_desc[i].status2 = 0;
  140. rx_desc[i].next = &rx_desc[(i + 1) % TX_DESCRIPTOR_NUM];
  141. }
  142. EMAC->RXDSA = (unsigned int)&rx_desc[0];
  143. return;
  144. }
  145. void numaker_set_mac_addr(uint8_t *addr)
  146. {
  147. EMAC->CAM0M = (addr[0] << 24) |
  148. (addr[1] << 16) |
  149. (addr[2] << 8) |
  150. addr[3];
  151. EMAC->CAM0L = (addr[4] << 24) |
  152. (addr[5] << 16);
  153. }
  154. static void __eth_clk_pin_init()
  155. {
  156. /* Unlock protected registers */
  157. SYS_UnlockReg();
  158. /* Enable IP clock */
  159. CLK_EnableModuleClock(EMAC_MODULE);
  160. // Configure MDC clock rate to HCLK / (127 + 1) = 1.25 MHz if system is running at 160 MH
  161. CLK_SetModuleClock(EMAC_MODULE, 0, CLK_CLKDIV3_EMAC(127));
  162. /* Update System Core Clock */
  163. SystemCoreClockUpdate();
  164. /*---------------------------------------------------------------------------------------------------------*/
  165. /* Init I/O Multi-function */
  166. /*---------------------------------------------------------------------------------------------------------*/
  167. // Configure RMII pins
  168. SYS->GPA_MFPL &= ~(SYS_GPA_MFPL_PA6MFP_Msk | SYS_GPA_MFPL_PA7MFP_Msk);
  169. SYS->GPA_MFPL |= SYS_GPA_MFPL_PA6MFP_EMAC_RMII_RXERR | SYS_GPA_MFPL_PA7MFP_EMAC_RMII_CRSDV;
  170. SYS->GPC_MFPL &= ~(SYS_GPC_MFPL_PC6MFP_Msk | SYS_GPC_MFPL_PC7MFP_Msk);
  171. SYS->GPC_MFPL |= SYS_GPC_MFPL_PC6MFP_EMAC_RMII_RXD1 | SYS_GPC_MFPL_PC7MFP_EMAC_RMII_RXD0;
  172. SYS->GPC_MFPH &= ~SYS_GPC_MFPH_PC8MFP_Msk;
  173. SYS->GPC_MFPH |= SYS_GPC_MFPH_PC8MFP_EMAC_RMII_REFCLK;
  174. SYS->GPE_MFPH &= ~(SYS_GPE_MFPH_PE8MFP_Msk | SYS_GPE_MFPH_PE9MFP_Msk | SYS_GPE_MFPH_PE10MFP_Msk |
  175. SYS_GPE_MFPH_PE11MFP_Msk | SYS_GPE_MFPH_PE12MFP_Msk);
  176. SYS->GPE_MFPH |= SYS_GPE_MFPH_PE8MFP_EMAC_RMII_MDC |
  177. SYS_GPE_MFPH_PE9MFP_EMAC_RMII_MDIO |
  178. SYS_GPE_MFPH_PE10MFP_EMAC_RMII_TXD0 |
  179. SYS_GPE_MFPH_PE11MFP_EMAC_RMII_TXD1 |
  180. SYS_GPE_MFPH_PE12MFP_EMAC_RMII_TXEN;
  181. // Enable high slew rate on all RMII TX output pins
  182. PE->SLEWCTL = (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN10_Pos) |
  183. (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN11_Pos) |
  184. (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN12_Pos);
  185. /* Lock protected registers */
  186. SYS_LockReg();
  187. }
  188. int numaker_eth_init(uint8_t *mac_addr)
  189. {
  190. int ret = 0;
  191. // init CLK & pins
  192. __eth_clk_pin_init();
  193. // Reset MAC
  194. EMAC->CTL = EMAC_CTL_RST_Msk;
  195. while(EMAC->CTL & EMAC_CTL_RST_Msk) {}
  196. init_tx_desc();
  197. init_rx_desc();
  198. numaker_set_mac_addr(mac_addr); // need to reconfigure hardware address 'cos we just RESET emc...
  199. /* Configure the MAC interrupt enable register. */
  200. EMAC->INTEN = EMAC_INTEN_RXIEN_Msk |
  201. EMAC_INTEN_TXIEN_Msk |
  202. EMAC_INTEN_RXGDIEN_Msk |
  203. EMAC_INTEN_TXCPIEN_Msk |
  204. EMAC_INTEN_RXBEIEN_Msk |
  205. EMAC_INTEN_TXBEIEN_Msk |
  206. EMAC_INTEN_RDUIEN_Msk |
  207. EMAC_INTEN_TSALMIEN_Msk |
  208. EMAC_INTEN_WOLIEN_Msk;
  209. /* Configure the MAC control register. */
  210. EMAC->CTL = EMAC_CTL_STRIPCRC_Msk | EMAC_CTL_RMIIEN_Msk;
  211. /* Accept packets for us and all broadcast and multicast packets */
  212. EMAC->CAMCTL = EMAC_CAMCTL_CMPEN_Msk |
  213. EMAC_CAMCTL_AMP_Msk |
  214. EMAC_CAMCTL_ABP_Msk;
  215. EMAC->CAMEN = 1; // Enable CAM entry 0
  216. ret= reset_phy();
  217. EMAC_ENABLE_RX();
  218. EMAC_ENABLE_TX();
  219. return ret;
  220. }
  221. void ETH_halt(void)
  222. {
  223. EMAC->CTL &= ~(EMAC_CTL_RXON_Msk | EMAC_CTL_TXON_Msk);
  224. }
  225. unsigned int m_status;
  226. void EMAC_RX_IRQHandler(void)
  227. {
  228. // NU_DEBUGF(("%s ... \r\n", __FUNCTION__));
  229. m_status = EMAC->INTSTS & 0xFFFF;
  230. EMAC->INTSTS = m_status;
  231. if (m_status & EMAC_INTSTS_RXBEIF_Msk) {
  232. // Shouldn't goes here, unless descriptor corrupted
  233. NU_DEBUGF(("RX descriptor corrupted \r\n"));
  234. //return;
  235. }
  236. // FIX ME: for rx-event, to ack rx_isr into event queue
  237. xNetworkCallback('R');
  238. }
  239. void numaker_eth_trigger_rx(void)
  240. {
  241. ETH_TRIGGER_RX();
  242. }
  243. int numaker_eth_get_rx_buf(uint16_t *len, uint8_t **buf)
  244. {
  245. unsigned int cur_entry, status;
  246. cur_entry = EMAC->CRXDSA;
  247. if ((cur_entry == (uint32_t)cur_rx_desc_ptr) && (!(m_status & EMAC_INTSTS_RDUIF_Msk))) // cur_entry may equal to cur_rx_desc_ptr if RDU occures
  248. return -1;
  249. status = cur_rx_desc_ptr->status1;
  250. if(status & OWNERSHIP_EMAC)
  251. return -1;
  252. if (status & RXFD_RXGD) {
  253. *buf = cur_rx_desc_ptr->buf;
  254. *len = status & 0xFFFF;
  255. }
  256. return 0;
  257. }
  258. void numaker_eth_rx_next(void)
  259. {
  260. cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC;
  261. cur_rx_desc_ptr = cur_rx_desc_ptr->next;
  262. }
  263. void EMAC_TX_IRQHandler(void)
  264. {
  265. unsigned int cur_entry, status;
  266. status = EMAC->INTSTS & 0xFFFF0000;
  267. EMAC->INTSTS = status;
  268. if(status & EMAC_INTSTS_TXBEIF_Msk) {
  269. // Shouldn't goes here, unless descriptor corrupted
  270. return;
  271. }
  272. cur_entry = EMAC->CTXDSA;
  273. while (cur_entry != (uint32_t)fin_tx_desc_ptr) {
  274. fin_tx_desc_ptr = fin_tx_desc_ptr->next;
  275. }
  276. // FIX ME: for tx-event, no-op at this stage
  277. xNetworkCallback('T');
  278. }
  279. uint8_t *numaker_eth_get_tx_buf(void)
  280. {
  281. if(cur_tx_desc_ptr->status1 & OWNERSHIP_EMAC)
  282. return(NULL);
  283. else
  284. return(cur_tx_desc_ptr->buf);
  285. }
  286. void numaker_eth_trigger_tx(uint16_t length, void *p)
  287. {
  288. struct eth_descriptor volatile *desc;
  289. cur_tx_desc_ptr->status2 = (unsigned int)length;
  290. desc = cur_tx_desc_ptr->next; // in case TX is transmitting and overwrite next pointer before we can update cur_tx_desc_ptr
  291. cur_tx_desc_ptr->status1 |= OWNERSHIP_EMAC;
  292. cur_tx_desc_ptr = desc;
  293. ETH_TRIGGER_TX();
  294. }
  295. int numaker_eth_link_ok(void)
  296. {
  297. /* first, a dummy read to latch */
  298. mdio_read(CONFIG_PHY_ADDR, MII_BMSR);
  299. if(mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & BMSR_LSTATUS)
  300. return 1;
  301. return 0;
  302. }
  303. //void numaker_eth_set_cb(eth_callback_t eth_cb, void *userData)
  304. //{
  305. // nu_eth_txrx_cb = eth_cb;
  306. // nu_userData = userData;
  307. //}
  308. // Provide ethernet devices with a semi-unique MAC address
  309. void numaker_mac_address(uint8_t *mac)
  310. {
  311. uint32_t uID1;
  312. // Fetch word 0
  313. uint32_t word0 = *(uint32_t *)0x7F804; // 2KB Data Flash at 0x7F800
  314. // Fetch word 1
  315. // we only want bottom 16 bits of word1 (MAC bits 32-47)
  316. // and bit 9 forced to 1, bit 8 forced to 0
  317. // Locally administered MAC, reduced conflicts
  318. // http://en.wikipedia.org/wiki/MAC_address
  319. uint32_t word1 = *(uint32_t *)0x7F800; // 2KB Data Flash at 0x7F800
  320. if( word0 == 0xFFFFFFFF ) // Not burn any mac address at 1st 2 words of Data Flash
  321. {
  322. // with a semi-unique MAC address from the UUID
  323. /* Enable FMC ISP function */
  324. SYS_UnlockReg();
  325. FMC_Open();
  326. // = FMC_ReadUID(0);
  327. uID1 = FMC_ReadUID(1);
  328. word1 = (uID1 & 0x003FFFFF) | ((uID1 & 0x030000) << 6) >> 8;
  329. word0 = ((FMC_ReadUID(0) >> 4) << 20) | ((uID1 & 0xFF)<<12) | (FMC_ReadUID(2) & 0xFFF);
  330. /* Disable FMC ISP function */
  331. FMC_Close();
  332. /* Lock protected registers */
  333. SYS_LockReg();
  334. }
  335. word1 |= 0x00000200;
  336. word1 &= 0x0000FEFF;
  337. mac[0] = (word1 & 0x0000ff00) >> 8;
  338. mac[1] = (word1 & 0x000000ff);
  339. mac[2] = (word0 & 0xff000000) >> 24;
  340. mac[3] = (word0 & 0x00ff0000) >> 16;
  341. mac[4] = (word0 & 0x0000ff00) >> 8;
  342. mac[5] = (word0 & 0x000000ff);
  343. NU_DEBUGF(("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]));
  344. }
  345. void numaker_eth_enable_interrupts(void) {
  346. EMAC->INTEN |= EMAC_INTEN_RXIEN_Msk |
  347. EMAC_INTEN_TXIEN_Msk ;
  348. NVIC_EnableIRQ(EMAC_RX_IRQn);
  349. NVIC_EnableIRQ(EMAC_TX_IRQn);
  350. }
  351. void numaker_eth_disable_interrupts(void) {
  352. NVIC_DisableIRQ(EMAC_RX_IRQn);
  353. NVIC_DisableIRQ(EMAC_TX_IRQn);
  354. }