]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/M487/m480_eth.c
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2822 1d2547de-c912-0410...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / M487 / m480_eth.c
index cf862da3ea7c9c110ca546ac52c565682435332b..2d45661d003606d220e0bfba536b36a7ebd73a29 100644 (file)
-/**************************************************************************//**
- * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *   1. Redistributions of source code must retain the above copyright notice,
- *      this list of conditions and the following disclaimer.
- *   2. Redistributions in binary form must reproduce the above copyright notice,
- *      this list of conditions and the following disclaimer in the documentation
- *      and/or other materials provided with the distribution.
- *   3. Neither the name of Nuvoton Technology Corp. nor the names of its contributors
- *      may be used to endorse or promote products derived from this software
- *      without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*****************************************************************************/
-#include "FreeRTOS.h"
-#include "list.h"
-#include "FreeRTOS_IP.h"
-
-#include "m480_eth.h"
-
-#define ETH_TRIGGER_RX()    do{EMAC->RXST = 0;}while(0)
-#define ETH_TRIGGER_TX()    do{EMAC->TXST = 0;}while(0)
-#define ETH_ENABLE_TX()     do{EMAC->CTL |= EMAC_CTL_TXON;}while(0)
-#define ETH_ENABLE_RX()     do{EMAC->CTL |= EMAC_CTL_RXON;}while(0)
-#define ETH_DISABLE_TX()    do{EMAC->CTL &= ~EMAC_CTL_TXON;}while(0)
-#define ETH_DISABLE_RX()    do{EMAC->CTL &= ~EMAC_CTL_RXON;}while(0)
-    
-
-struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
-struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
-#ifdef __ICCARM__
-#pragma data_alignment=4
-struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM];
-struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM];
-uint8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
-uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
-#else
-struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
-struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
-uint8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE]  __attribute__ ((aligned(4)));
-uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE]  __attribute__ ((aligned(4)));
-#endif
-struct eth_descriptor volatile *cur_tx_desc_ptr, *cur_rx_desc_ptr, *fin_tx_desc_ptr;
-
-
-// PTP source clock is 84MHz (Real chip using PLL). Each tick is 11.90ns
-// Assume we want to set each tick to 100ns.
-// Increase register = (100 * 2^31) / (10^9) = 214.71 =~ 215 = 0xD7
-// Addend register = 2^32 * tick_freq / (84MHz), where tick_freq = (2^31 / 215) MHz
-// From above equation, addend register = 2^63 / (84M * 215) ~= 510707200 = 0x1E70C600
-
-
-
-static void mdio_write(uint8_t addr, uint8_t reg, uint16_t val)
-{
-
-    EMAC->MIIMDAT = val;
-    EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_WRITE_Msk | EMAC_MIIMCTL_MDCON_Msk;
-
-    while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk);
-
-}
-
-
-static uint16_t mdio_read(uint8_t addr, uint8_t reg)
-{
-    EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk;
-    while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk);
-
-    return(EMAC->MIIMDAT);
-}
-
-static int reset_phy(void)
-{
-
-    uint16_t reg;
-    uint32_t delayCnt;
-
-
-    mdio_write(CONFIG_PHY_ADDR, MII_BMCR, BMCR_RESET);
-
-    delayCnt = 2000;
-    while(delayCnt-- > 0) {
-        if((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0)
-            break;
-
-    }
-
-    if(delayCnt == 0) {
-        NU_DEBUGF(("Reset phy failed\n"));
-        return(-1);
-    }
-
-    mdio_write(CONFIG_PHY_ADDR, MII_ADVERTISE, ADVERTISE_CSMA |
-               ADVERTISE_10HALF |
-               ADVERTISE_10FULL |
-               ADVERTISE_100HALF |
-               ADVERTISE_100FULL);
-
-    reg = mdio_read(CONFIG_PHY_ADDR, MII_BMCR);
-    mdio_write(CONFIG_PHY_ADDR, MII_BMCR, reg | BMCR_ANRESTART);
-
-    delayCnt = 200000;
-    while(delayCnt-- > 0) {
-        if((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
-                == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
-            break;
-    }
-
-    if(delayCnt == 0) {
-        NU_DEBUGF(("AN failed. Set to 100 FULL\n"));
-        EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
-        return(-1);
-    } else {
-        reg = mdio_read(CONFIG_PHY_ADDR, MII_LPA);
-
-        if(reg & ADVERTISE_100FULL) {
-            NU_DEBUGF(("100 full\n"));
-            EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
-        } else if(reg & ADVERTISE_100HALF) {
-            NU_DEBUGF(("100 half\n"));
-            EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk;
-        } else if(reg & ADVERTISE_10FULL) {
-            NU_DEBUGF(("10 full\n"));
-            EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk;
-        } else {
-            NU_DEBUGF(("10 half\n"));
-            EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
-        }
-    }
-       FreeRTOS_printf(("PHY ID 1:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID1)));
-       FreeRTOS_printf(("PHY ID 2:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID2)));
-
-    return(0);
-}
-
-
-static void init_tx_desc(void)
-{
-    uint32_t i;
-
-
-    cur_tx_desc_ptr = fin_tx_desc_ptr = &tx_desc[0];
-
-    for(i = 0; i < TX_DESCRIPTOR_NUM; i++) {
-        tx_desc[i].status1 = TXFD_PADEN | TXFD_CRCAPP | TXFD_INTEN;
-        tx_desc[i].buf = &tx_buf[i][0];
-        tx_desc[i].status2 = 0;
-        tx_desc[i].next = &tx_desc[(i + 1) % TX_DESCRIPTOR_NUM];
-
-    }
-    EMAC->TXDSA = (unsigned int)&tx_desc[0];
-    return;
-}
-
-static void init_rx_desc(void)
-{
-    uint32_t i;
-
-
-    cur_rx_desc_ptr = &rx_desc[0];
-
-    for(i = 0; i < RX_DESCRIPTOR_NUM; i++) {
-        rx_desc[i].status1 = OWNERSHIP_EMAC;
-        rx_desc[i].buf = &rx_buf[i][0];
-        rx_desc[i].status2 = 0;
-        rx_desc[i].next = &rx_desc[(i + 1) % TX_DESCRIPTOR_NUM];
-    }
-    EMAC->RXDSA = (unsigned int)&rx_desc[0];
-    return;
-}
-
-void numaker_set_mac_addr(uint8_t *addr)
-{
-
-    EMAC->CAM0M = (addr[0] << 24) |
-                  (addr[1] << 16) |
-                  (addr[2] << 8) |
-                  addr[3];
-
-    EMAC->CAM0L = (addr[4] << 24) |
-                  (addr[5] << 16);
-
-
-}
-
-static void __eth_clk_pin_init()
-{
-    /* Unlock protected registers */
-    SYS_UnlockReg();
-
-    /* Enable IP clock */
-    CLK_EnableModuleClock(EMAC_MODULE);
-    
-    // Configure MDC clock rate to HCLK / (127 + 1) = 1.25 MHz if system is running at 160 MH
-    CLK_SetModuleClock(EMAC_MODULE, 0, CLK_CLKDIV3_EMAC(127));
-    
-    /* Update System Core Clock */
-    SystemCoreClockUpdate();
-    
-    /*---------------------------------------------------------------------------------------------------------*/
-    /* Init I/O Multi-function                                                                                 */
-    /*---------------------------------------------------------------------------------------------------------*/
-    // Configure RMII pins
-    SYS->GPA_MFPL &= ~(SYS_GPA_MFPL_PA6MFP_Msk | SYS_GPA_MFPL_PA7MFP_Msk);
-    SYS->GPA_MFPL |= SYS_GPA_MFPL_PA6MFP_EMAC_RMII_RXERR | SYS_GPA_MFPL_PA7MFP_EMAC_RMII_CRSDV;
-    SYS->GPC_MFPL &= ~(SYS_GPC_MFPL_PC6MFP_Msk | SYS_GPC_MFPL_PC7MFP_Msk);
-    SYS->GPC_MFPL |= SYS_GPC_MFPL_PC6MFP_EMAC_RMII_RXD1 | SYS_GPC_MFPL_PC7MFP_EMAC_RMII_RXD0;
-    SYS->GPC_MFPH &= ~SYS_GPC_MFPH_PC8MFP_Msk;
-    SYS->GPC_MFPH |= SYS_GPC_MFPH_PC8MFP_EMAC_RMII_REFCLK;
-    SYS->GPE_MFPH &= ~(SYS_GPE_MFPH_PE8MFP_Msk | SYS_GPE_MFPH_PE9MFP_Msk | SYS_GPE_MFPH_PE10MFP_Msk |
-                       SYS_GPE_MFPH_PE11MFP_Msk | SYS_GPE_MFPH_PE12MFP_Msk);
-    SYS->GPE_MFPH |= SYS_GPE_MFPH_PE8MFP_EMAC_RMII_MDC |
-                    SYS_GPE_MFPH_PE9MFP_EMAC_RMII_MDIO |
-                    SYS_GPE_MFPH_PE10MFP_EMAC_RMII_TXD0 |
-                    SYS_GPE_MFPH_PE11MFP_EMAC_RMII_TXD1 |
-                    SYS_GPE_MFPH_PE12MFP_EMAC_RMII_TXEN;
-
-    // Enable high slew rate on all RMII TX output pins
-    PE->SLEWCTL = (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN10_Pos) |
-                  (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN11_Pos) |
-                  (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN12_Pos);
-
-
-    /* Lock protected registers */
-    SYS_LockReg();
-
-
-}
-
-int numaker_eth_init(uint8_t *mac_addr)
-{
-    int ret = 0;
-    // init CLK & pins
-    __eth_clk_pin_init();
-  
-    // Reset MAC
-    EMAC->CTL = EMAC_CTL_RST_Msk;
-    while(EMAC->CTL & EMAC_CTL_RST_Msk) {}
-
-    init_tx_desc();
-    init_rx_desc();
-
-    numaker_set_mac_addr(mac_addr);  // need to reconfigure hardware address 'cos we just RESET emc...
-
-
-    /* Configure the MAC interrupt enable register. */
-    EMAC->INTEN = EMAC_INTEN_RXIEN_Msk |
-                  EMAC_INTEN_TXIEN_Msk |
-                  EMAC_INTEN_RXGDIEN_Msk |
-                  EMAC_INTEN_TXCPIEN_Msk |
-                  EMAC_INTEN_RXBEIEN_Msk |
-                  EMAC_INTEN_TXBEIEN_Msk |
-                  EMAC_INTEN_RDUIEN_Msk |
-                  EMAC_INTEN_TSALMIEN_Msk |
-                  EMAC_INTEN_WOLIEN_Msk;
-
-    /* Configure the MAC control register. */
-    EMAC->CTL = EMAC_CTL_STRIPCRC_Msk | EMAC_CTL_RMIIEN_Msk;
-
-    /* Accept packets for us and all broadcast and multicast packets */
-    EMAC->CAMCTL =  EMAC_CAMCTL_CMPEN_Msk |
-                    EMAC_CAMCTL_AMP_Msk |
-                    EMAC_CAMCTL_ABP_Msk;
-    EMAC->CAMEN = 1;    // Enable CAM entry 0    
-
-    ret= reset_phy();                    
-                    
-    EMAC_ENABLE_RX();
-    EMAC_ENABLE_TX();
-    return ret;
-}
-
-
-
-void  ETH_halt(void)
-{
-
-    EMAC->CTL &= ~(EMAC_CTL_RXON_Msk | EMAC_CTL_TXON_Msk);
-}
-
-unsigned int m_status;
-
-void EMAC_RX_IRQHandler(void)
-{
-//    NU_DEBUGF(("%s ... \r\n", __FUNCTION__));
-    m_status = EMAC->INTSTS & 0xFFFF;
-    EMAC->INTSTS = m_status;
-    if (m_status & EMAC_INTSTS_RXBEIF_Msk) {
-        // Shouldn't goes here, unless descriptor corrupted
-               NU_DEBUGF(("RX descriptor corrupted \r\n"));
-               //return;
-    }
-    // FIX ME: for rx-event, to ack rx_isr into event queue
-        xNetworkCallback('R');
-}
-
-
-void numaker_eth_trigger_rx(void)
-{
-    ETH_TRIGGER_RX();
-}
-
-int numaker_eth_get_rx_buf(uint16_t *len, uint8_t **buf)
-{
-    unsigned int cur_entry, status;
-
-    cur_entry = EMAC->CRXDSA;
-    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
-            return -1;
-    status = cur_rx_desc_ptr->status1;
-
-    if(status & OWNERSHIP_EMAC)
-            return -1;
-
-    if (status & RXFD_RXGD) {
-        *buf = cur_rx_desc_ptr->buf;
-        *len = status & 0xFFFF;
-    }
-    return 0;
-}    
-
-void numaker_eth_rx_next(void)
-{
-    cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC;
-    cur_rx_desc_ptr = cur_rx_desc_ptr->next;    
-}    
-
-void EMAC_TX_IRQHandler(void)
-{
-    unsigned int cur_entry, status;
-
-    status = EMAC->INTSTS & 0xFFFF0000;
-    EMAC->INTSTS = status;
-    if(status & EMAC_INTSTS_TXBEIF_Msk) {
-        // Shouldn't goes here, unless descriptor corrupted
-        return;
-    }
-
-    cur_entry = EMAC->CTXDSA;
-
-    while (cur_entry != (uint32_t)fin_tx_desc_ptr) {
-
-        fin_tx_desc_ptr = fin_tx_desc_ptr->next;
-    }
-    // FIX ME: for tx-event, no-op at this stage
-    xNetworkCallback('T');
-}
-
-uint8_t *numaker_eth_get_tx_buf(void)
-{
-    if(cur_tx_desc_ptr->status1 & OWNERSHIP_EMAC)
-        return(NULL);
-    else
-        return(cur_tx_desc_ptr->buf);
-}
-
-void numaker_eth_trigger_tx(uint16_t length, void *p)
-{
-    struct eth_descriptor volatile *desc;
-    cur_tx_desc_ptr->status2 = (unsigned int)length;
-    desc = cur_tx_desc_ptr->next;    // in case TX is transmitting and overwrite next pointer before we can update cur_tx_desc_ptr
-    cur_tx_desc_ptr->status1 |= OWNERSHIP_EMAC;
-    cur_tx_desc_ptr = desc;
-
-    ETH_TRIGGER_TX();
-
-}
-
-int numaker_eth_link_ok(void)
-{
-    /* first, a dummy read to latch */
-    mdio_read(CONFIG_PHY_ADDR, MII_BMSR);
-    if(mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & BMSR_LSTATUS)
-      return 1;
-    return 0;  
-}
-
-//void numaker_eth_set_cb(eth_callback_t eth_cb, void *userData)
-//{
-//    nu_eth_txrx_cb =  eth_cb;
-//    nu_userData = userData;
-//}
-
-// Provide ethernet devices with a semi-unique MAC address
-void numaker_mac_address(uint8_t *mac)
-{
-    uint32_t uID1;
-    // Fetch word 0
-    uint32_t word0 = *(uint32_t *)0x7F804; // 2KB Data Flash at 0x7F800
-    // Fetch word 1
-    // we only want bottom 16 bits of word1 (MAC bits 32-47)
-    // and bit 9 forced to 1, bit 8 forced to 0
-    // Locally administered MAC, reduced conflicts
-    // http://en.wikipedia.org/wiki/MAC_address
-    uint32_t word1 = *(uint32_t *)0x7F800; // 2KB Data Flash at 0x7F800
-
-    if( word0 == 0xFFFFFFFF )          // Not burn any mac address at 1st 2 words of Data Flash
-    {
-        // with a semi-unique MAC address from the UUID
-        /* Enable FMC ISP function */
-        SYS_UnlockReg();
-        FMC_Open();
-        // = FMC_ReadUID(0);
-        uID1 = FMC_ReadUID(1);
-        word1 = (uID1 & 0x003FFFFF) | ((uID1 & 0x030000) << 6) >> 8;
-        word0 = ((FMC_ReadUID(0) >> 4) << 20) | ((uID1 & 0xFF)<<12) | (FMC_ReadUID(2) & 0xFFF);
-        /* Disable FMC ISP function */
-        FMC_Close();
-        /* Lock protected registers */
-        SYS_LockReg();
-    }
-
-    word1 |= 0x00000200;
-    word1 &= 0x0000FEFF;
-
-    mac[0] = (word1 & 0x0000ff00) >> 8;    
-    mac[1] = (word1 & 0x000000ff);
-    mac[2] = (word0 & 0xff000000) >> 24;
-    mac[3] = (word0 & 0x00ff0000) >> 16;
-    mac[4] = (word0 & 0x0000ff00) >> 8;
-    mac[5] = (word0 & 0x000000ff);
-    
-    NU_DEBUGF(("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]));
-}
-
-void numaker_eth_enable_interrupts(void) {
-  EMAC->INTEN |= EMAC_INTEN_RXIEN_Msk |
-                   EMAC_INTEN_TXIEN_Msk ;
-  NVIC_EnableIRQ(EMAC_RX_IRQn);
-  NVIC_EnableIRQ(EMAC_TX_IRQn);
-}
-
-void numaker_eth_disable_interrupts(void) {
-  NVIC_DisableIRQ(EMAC_RX_IRQn);
-  NVIC_DisableIRQ(EMAC_TX_IRQn);
-}
+/**************************************************************************//**\r
+ * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *   1. Redistributions of source code must retain the above copyright notice,\r
+ *      this list of conditions and the following disclaimer.\r
+ *   2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *      this list of conditions and the following disclaimer in the documentation\r
+ *      and/or other materials provided with the distribution.\r
+ *   3. Neither the name of Nuvoton Technology Corp. nor the names of its contributors\r
+ *      may be used to endorse or promote products derived from this software\r
+ *      without specific prior written permission.\r
+ * \r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*****************************************************************************/\r
+#include "FreeRTOS.h"\r
+#include "list.h"\r
+#include "FreeRTOS_IP.h"\r
+\r
+#include "m480_eth.h"\r
+\r
+#define ETH_TRIGGER_RX()    do{EMAC->RXST = 0;}while(0)\r
+#define ETH_TRIGGER_TX()    do{EMAC->TXST = 0;}while(0)\r
+#define ETH_ENABLE_TX()     do{EMAC->CTL |= EMAC_CTL_TXON;}while(0)\r
+#define ETH_ENABLE_RX()     do{EMAC->CTL |= EMAC_CTL_RXON;}while(0)\r
+#define ETH_DISABLE_TX()    do{EMAC->CTL &= ~EMAC_CTL_TXON;}while(0)\r
+#define ETH_DISABLE_RX()    do{EMAC->CTL &= ~EMAC_CTL_RXON;}while(0)\r
+    \r
+\r
+struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));\r
+struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));\r
+#ifdef __ICCARM__\r
+#pragma data_alignment=4\r
+struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM];\r
+struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM];\r
+uint8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];\r
+uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];\r
+#else\r
+struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));\r
+struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));\r
+uint8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE]  __attribute__ ((aligned(4)));\r
+uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE]  __attribute__ ((aligned(4)));\r
+#endif\r
+struct eth_descriptor volatile *cur_tx_desc_ptr, *cur_rx_desc_ptr, *fin_tx_desc_ptr;\r
+\r
+\r
+// PTP source clock is 84MHz (Real chip using PLL). Each tick is 11.90ns\r
+// Assume we want to set each tick to 100ns.\r
+// Increase register = (100 * 2^31) / (10^9) = 214.71 =~ 215 = 0xD7\r
+// Addend register = 2^32 * tick_freq / (84MHz), where tick_freq = (2^31 / 215) MHz\r
+// From above equation, addend register = 2^63 / (84M * 215) ~= 510707200 = 0x1E70C600\r
+\r
+\r
+\r
+static void mdio_write(uint8_t addr, uint8_t reg, uint16_t val)\r
+{\r
+\r
+    EMAC->MIIMDAT = val;\r
+    EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_WRITE_Msk | EMAC_MIIMCTL_MDCON_Msk;\r
+\r
+    while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk);\r
+\r
+}\r
+\r
+\r
+static uint16_t mdio_read(uint8_t addr, uint8_t reg)\r
+{\r
+    EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk;\r
+    while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk);\r
+\r
+    return(EMAC->MIIMDAT);\r
+}\r
+\r
+static int reset_phy(void)\r
+{\r
+\r
+    uint16_t reg;\r
+    uint32_t delayCnt;\r
+\r
+\r
+    mdio_write(CONFIG_PHY_ADDR, MII_BMCR, BMCR_RESET);\r
+\r
+    delayCnt = 2000;\r
+    while(delayCnt-- > 0) {\r
+        if((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0)\r
+            break;\r
+\r
+    }\r
+\r
+    if(delayCnt == 0) {\r
+        NU_DEBUGF(("Reset phy failed\n"));\r
+        return(-1);\r
+    }\r
+\r
+    mdio_write(CONFIG_PHY_ADDR, MII_ADVERTISE, ADVERTISE_CSMA |\r
+               ADVERTISE_10HALF |\r
+               ADVERTISE_10FULL |\r
+               ADVERTISE_100HALF |\r
+               ADVERTISE_100FULL);\r
+\r
+    reg = mdio_read(CONFIG_PHY_ADDR, MII_BMCR);\r
+    mdio_write(CONFIG_PHY_ADDR, MII_BMCR, reg | BMCR_ANRESTART);\r
+\r
+    delayCnt = 200000;\r
+    while(delayCnt-- > 0) {\r
+        if((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))\r
+                == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))\r
+            break;\r
+    }\r
+\r
+    if(delayCnt == 0) {\r
+        NU_DEBUGF(("AN failed. Set to 100 FULL\n"));\r
+        EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);\r
+        return(-1);\r
+    } else {\r
+        reg = mdio_read(CONFIG_PHY_ADDR, MII_LPA);\r
+\r
+        if(reg & ADVERTISE_100FULL) {\r
+            NU_DEBUGF(("100 full\n"));\r
+            EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);\r
+        } else if(reg & ADVERTISE_100HALF) {\r
+            NU_DEBUGF(("100 half\n"));\r
+            EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk;\r
+        } else if(reg & ADVERTISE_10FULL) {\r
+            NU_DEBUGF(("10 full\n"));\r
+            EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk;\r
+        } else {\r
+            NU_DEBUGF(("10 half\n"));\r
+            EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);\r
+        }\r
+    }\r
+       FreeRTOS_printf(("PHY ID 1:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID1)));\r
+       FreeRTOS_printf(("PHY ID 2:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID2)));\r
+\r
+    return(0);\r
+}\r
+\r
+\r
+static void init_tx_desc(void)\r
+{\r
+    uint32_t i;\r
+\r
+\r
+    cur_tx_desc_ptr = fin_tx_desc_ptr = &tx_desc[0];\r
+\r
+    for(i = 0; i < TX_DESCRIPTOR_NUM; i++) {\r
+        tx_desc[i].status1 = TXFD_PADEN | TXFD_CRCAPP | TXFD_INTEN;\r
+        tx_desc[i].buf = &tx_buf[i][0];\r
+        tx_desc[i].status2 = 0;\r
+        tx_desc[i].next = &tx_desc[(i + 1) % TX_DESCRIPTOR_NUM];\r
+\r
+    }\r
+    EMAC->TXDSA = (unsigned int)&tx_desc[0];\r
+    return;\r
+}\r
+\r
+static void init_rx_desc(void)\r
+{\r
+    uint32_t i;\r
+\r
+\r
+    cur_rx_desc_ptr = &rx_desc[0];\r
+\r
+    for(i = 0; i < RX_DESCRIPTOR_NUM; i++) {\r
+        rx_desc[i].status1 = OWNERSHIP_EMAC;\r
+        rx_desc[i].buf = &rx_buf[i][0];\r
+        rx_desc[i].status2 = 0;\r
+        rx_desc[i].next = &rx_desc[(i + 1) % TX_DESCRIPTOR_NUM];\r
+    }\r
+    EMAC->RXDSA = (unsigned int)&rx_desc[0];\r
+    return;\r
+}\r
+\r
+void numaker_set_mac_addr(uint8_t *addr)\r
+{\r
+\r
+    EMAC->CAM0M = (addr[0] << 24) |\r
+                  (addr[1] << 16) |\r
+                  (addr[2] << 8) |\r
+                  addr[3];\r
+\r
+    EMAC->CAM0L = (addr[4] << 24) |\r
+                  (addr[5] << 16);\r
+\r
+\r
+}\r
+\r
+static void __eth_clk_pin_init()\r
+{\r
+    /* Unlock protected registers */\r
+    SYS_UnlockReg();\r
+\r
+    /* Enable IP clock */\r
+    CLK_EnableModuleClock(EMAC_MODULE);\r
+    \r
+    // Configure MDC clock rate to HCLK / (127 + 1) = 1.25 MHz if system is running at 160 MH\r
+    CLK_SetModuleClock(EMAC_MODULE, 0, CLK_CLKDIV3_EMAC(127));\r
+    \r
+    /* Update System Core Clock */\r
+    SystemCoreClockUpdate();\r
+    \r
+    /*---------------------------------------------------------------------------------------------------------*/\r
+    /* Init I/O Multi-function                                                                                 */\r
+    /*---------------------------------------------------------------------------------------------------------*/\r
+    // Configure RMII pins\r
+    SYS->GPA_MFPL &= ~(SYS_GPA_MFPL_PA6MFP_Msk | SYS_GPA_MFPL_PA7MFP_Msk);\r
+    SYS->GPA_MFPL |= SYS_GPA_MFPL_PA6MFP_EMAC_RMII_RXERR | SYS_GPA_MFPL_PA7MFP_EMAC_RMII_CRSDV;\r
+    SYS->GPC_MFPL &= ~(SYS_GPC_MFPL_PC6MFP_Msk | SYS_GPC_MFPL_PC7MFP_Msk);\r
+    SYS->GPC_MFPL |= SYS_GPC_MFPL_PC6MFP_EMAC_RMII_RXD1 | SYS_GPC_MFPL_PC7MFP_EMAC_RMII_RXD0;\r
+    SYS->GPC_MFPH &= ~SYS_GPC_MFPH_PC8MFP_Msk;\r
+    SYS->GPC_MFPH |= SYS_GPC_MFPH_PC8MFP_EMAC_RMII_REFCLK;\r
+    SYS->GPE_MFPH &= ~(SYS_GPE_MFPH_PE8MFP_Msk | SYS_GPE_MFPH_PE9MFP_Msk | SYS_GPE_MFPH_PE10MFP_Msk |\r
+                       SYS_GPE_MFPH_PE11MFP_Msk | SYS_GPE_MFPH_PE12MFP_Msk);\r
+    SYS->GPE_MFPH |= SYS_GPE_MFPH_PE8MFP_EMAC_RMII_MDC |\r
+                    SYS_GPE_MFPH_PE9MFP_EMAC_RMII_MDIO |\r
+                    SYS_GPE_MFPH_PE10MFP_EMAC_RMII_TXD0 |\r
+                    SYS_GPE_MFPH_PE11MFP_EMAC_RMII_TXD1 |\r
+                    SYS_GPE_MFPH_PE12MFP_EMAC_RMII_TXEN;\r
+\r
+    // Enable high slew rate on all RMII TX output pins\r
+    PE->SLEWCTL = (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN10_Pos) |\r
+                  (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN11_Pos) |\r
+                  (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN12_Pos);\r
+\r
+\r
+    /* Lock protected registers */\r
+    SYS_LockReg();\r
+\r
+\r
+}\r
+\r
+int numaker_eth_init(uint8_t *mac_addr)\r
+{\r
+    int ret = 0;\r
+    // init CLK & pins\r
+    __eth_clk_pin_init();\r
+  \r
+    // Reset MAC\r
+    EMAC->CTL = EMAC_CTL_RST_Msk;\r
+    while(EMAC->CTL & EMAC_CTL_RST_Msk) {}\r
+\r
+    init_tx_desc();\r
+    init_rx_desc();\r
+\r
+    numaker_set_mac_addr(mac_addr);  // need to reconfigure hardware address 'cos we just RESET emc...\r
+\r
+\r
+    /* Configure the MAC interrupt enable register. */\r
+    EMAC->INTEN = EMAC_INTEN_RXIEN_Msk |\r
+                  EMAC_INTEN_TXIEN_Msk |\r
+                  EMAC_INTEN_RXGDIEN_Msk |\r
+                  EMAC_INTEN_TXCPIEN_Msk |\r
+                  EMAC_INTEN_RXBEIEN_Msk |\r
+                  EMAC_INTEN_TXBEIEN_Msk |\r
+                  EMAC_INTEN_RDUIEN_Msk |\r
+                  EMAC_INTEN_TSALMIEN_Msk |\r
+                  EMAC_INTEN_WOLIEN_Msk;\r
+\r
+    /* Configure the MAC control register. */\r
+    EMAC->CTL = EMAC_CTL_STRIPCRC_Msk | EMAC_CTL_RMIIEN_Msk;\r
+\r
+    /* Accept packets for us and all broadcast and multicast packets */\r
+    EMAC->CAMCTL =  EMAC_CAMCTL_CMPEN_Msk |\r
+                    EMAC_CAMCTL_AMP_Msk |\r
+                    EMAC_CAMCTL_ABP_Msk;\r
+    EMAC->CAMEN = 1;    // Enable CAM entry 0    \r
+\r
+    ret= reset_phy();                    \r
+                    \r
+    EMAC_ENABLE_RX();\r
+    EMAC_ENABLE_TX();\r
+    return ret;\r
+}\r
+\r
+\r
+\r
+void  ETH_halt(void)\r
+{\r
+\r
+    EMAC->CTL &= ~(EMAC_CTL_RXON_Msk | EMAC_CTL_TXON_Msk);\r
+}\r
+\r
+unsigned int m_status;\r
+\r
+void EMAC_RX_IRQHandler(void)\r
+{\r
+//    NU_DEBUGF(("%s ... \r\n", __FUNCTION__));\r
+    m_status = EMAC->INTSTS & 0xFFFF;\r
+    EMAC->INTSTS = m_status;\r
+    if (m_status & EMAC_INTSTS_RXBEIF_Msk) {\r
+        // Shouldn't goes here, unless descriptor corrupted\r
+               NU_DEBUGF(("RX descriptor corrupted \r\n"));\r
+               //return;\r
+    }\r
+    // FIX ME: for rx-event, to ack rx_isr into event queue\r
+        xNetworkCallback('R');\r
+}\r
+\r
+\r
+void numaker_eth_trigger_rx(void)\r
+{\r
+    ETH_TRIGGER_RX();\r
+}\r
+\r
+int numaker_eth_get_rx_buf(uint16_t *len, uint8_t **buf)\r
+{\r
+    unsigned int cur_entry, status;\r
+\r
+    cur_entry = EMAC->CRXDSA;\r
+    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\r
+            return -1;\r
+    status = cur_rx_desc_ptr->status1;\r
+\r
+    if(status & OWNERSHIP_EMAC)\r
+            return -1;\r
+\r
+    if (status & RXFD_RXGD) {\r
+        *buf = cur_rx_desc_ptr->buf;\r
+        *len = status & 0xFFFF;\r
+    }\r
+    return 0;\r
+}    \r
+\r
+void numaker_eth_rx_next(void)\r
+{\r
+    cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC;\r
+    cur_rx_desc_ptr = cur_rx_desc_ptr->next;    \r
+}    \r
+\r
+void EMAC_TX_IRQHandler(void)\r
+{\r
+    unsigned int cur_entry, status;\r
+\r
+    status = EMAC->INTSTS & 0xFFFF0000;\r
+    EMAC->INTSTS = status;\r
+    if(status & EMAC_INTSTS_TXBEIF_Msk) {\r
+        // Shouldn't goes here, unless descriptor corrupted\r
+        return;\r
+    }\r
+\r
+    cur_entry = EMAC->CTXDSA;\r
+\r
+    while (cur_entry != (uint32_t)fin_tx_desc_ptr) {\r
+\r
+        fin_tx_desc_ptr = fin_tx_desc_ptr->next;\r
+    }\r
+    // FIX ME: for tx-event, no-op at this stage\r
+    xNetworkCallback('T');\r
+}\r
+\r
+uint8_t *numaker_eth_get_tx_buf(void)\r
+{\r
+    if(cur_tx_desc_ptr->status1 & OWNERSHIP_EMAC)\r
+        return(NULL);\r
+    else\r
+        return(cur_tx_desc_ptr->buf);\r
+}\r
+\r
+void numaker_eth_trigger_tx(uint16_t length, void *p)\r
+{\r
+    struct eth_descriptor volatile *desc;\r
+    cur_tx_desc_ptr->status2 = (unsigned int)length;\r
+    desc = cur_tx_desc_ptr->next;    // in case TX is transmitting and overwrite next pointer before we can update cur_tx_desc_ptr\r
+    cur_tx_desc_ptr->status1 |= OWNERSHIP_EMAC;\r
+    cur_tx_desc_ptr = desc;\r
+\r
+    ETH_TRIGGER_TX();\r
+\r
+}\r
+\r
+int numaker_eth_link_ok(void)\r
+{\r
+    /* first, a dummy read to latch */\r
+    mdio_read(CONFIG_PHY_ADDR, MII_BMSR);\r
+    if(mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & BMSR_LSTATUS)\r
+      return 1;\r
+    return 0;  \r
+}\r
+\r
+//void numaker_eth_set_cb(eth_callback_t eth_cb, void *userData)\r
+//{\r
+//    nu_eth_txrx_cb =  eth_cb;\r
+//    nu_userData = userData;\r
+//}\r
+\r
+// Provide ethernet devices with a semi-unique MAC address\r
+void numaker_mac_address(uint8_t *mac)\r
+{\r
+    uint32_t uID1;\r
+    // Fetch word 0\r
+    uint32_t word0 = *(uint32_t *)0x7F804; // 2KB Data Flash at 0x7F800\r
+    // Fetch word 1\r
+    // we only want bottom 16 bits of word1 (MAC bits 32-47)\r
+    // and bit 9 forced to 1, bit 8 forced to 0\r
+    // Locally administered MAC, reduced conflicts\r
+    // http://en.wikipedia.org/wiki/MAC_address\r
+    uint32_t word1 = *(uint32_t *)0x7F800; // 2KB Data Flash at 0x7F800\r
+\r
+    if( word0 == 0xFFFFFFFF )          // Not burn any mac address at 1st 2 words of Data Flash\r
+    {\r
+        // with a semi-unique MAC address from the UUID\r
+        /* Enable FMC ISP function */\r
+        SYS_UnlockReg();\r
+        FMC_Open();\r
+        // = FMC_ReadUID(0);\r
+        uID1 = FMC_ReadUID(1);\r
+        word1 = (uID1 & 0x003FFFFF) | ((uID1 & 0x030000) << 6) >> 8;\r
+        word0 = ((FMC_ReadUID(0) >> 4) << 20) | ((uID1 & 0xFF)<<12) | (FMC_ReadUID(2) & 0xFFF);\r
+        /* Disable FMC ISP function */\r
+        FMC_Close();\r
+        /* Lock protected registers */\r
+        SYS_LockReg();\r
+    }\r
+\r
+    word1 |= 0x00000200;\r
+    word1 &= 0x0000FEFF;\r
+\r
+    mac[0] = (word1 & 0x0000ff00) >> 8;    \r
+    mac[1] = (word1 & 0x000000ff);\r
+    mac[2] = (word0 & 0xff000000) >> 24;\r
+    mac[3] = (word0 & 0x00ff0000) >> 16;\r
+    mac[4] = (word0 & 0x0000ff00) >> 8;\r
+    mac[5] = (word0 & 0x000000ff);\r
+    \r
+    NU_DEBUGF(("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]));\r
+}\r
+\r
+void numaker_eth_enable_interrupts(void) {\r
+  EMAC->INTEN |= EMAC_INTEN_RXIEN_Msk |\r
+                   EMAC_INTEN_TXIEN_Msk ;\r
+  NVIC_EnableIRQ(EMAC_RX_IRQn);\r
+  NVIC_EnableIRQ(EMAC_TX_IRQn);\r
+}\r
+\r
+void numaker_eth_disable_interrupts(void) {\r
+  NVIC_DisableIRQ(EMAC_RX_IRQn);\r
+  NVIC_DisableIRQ(EMAC_TX_IRQn);\r
+}\r