mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			[M487/NUC472] Support DHCP & TCP sample, also remove legacy emac
							parent
							
								
									89209b6cd5
								
							
						
					
					
						commit
						401f09c479
					
				| 
						 | 
				
			
			@ -1,26 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2012-2015, ARM Limited, All Rights Reserved
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 * 
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
 * not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * 
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 * 
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef LWIPOPTS_CONF_H
 | 
			
		||||
#define LWIPOPTS_CONF_H
 | 
			
		||||
 | 
			
		||||
#define LWIP_TRANSPORT_ETHERNET       1
 | 
			
		||||
#define ETH_PAD_SIZE                  2
 | 
			
		||||
 | 
			
		||||
#define MEM_SIZE                      (16*1024)//(8*1024)//(16*1024)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -1,530 +0,0 @@
 | 
			
		|||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Ethernet Interface Skeleton
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
 | 
			
		||||
 * 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. The name of the author may not be used to endorse or promote products
 | 
			
		||||
 *    derived from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of the lwIP TCP/IP stack.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Adam Dunkels <adam@sics.se>
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This file is a skeleton for developing Ethernet network interface
 | 
			
		||||
 * drivers for lwIP. Add code to the low_level functions and do a
 | 
			
		||||
 * search-and-replace for the word "ethernetif" to replace it with
 | 
			
		||||
 * something that better describes your network interface.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lwip/opt.h"
 | 
			
		||||
 | 
			
		||||
#include "lwip/def.h"
 | 
			
		||||
#include "lwip/mem.h"
 | 
			
		||||
#include "lwip/pbuf.h"
 | 
			
		||||
#include "lwip/sys.h"
 | 
			
		||||
#include <lwip/stats.h>
 | 
			
		||||
#include <lwip/snmp.h>
 | 
			
		||||
#include "netif/etharp.h"
 | 
			
		||||
#include "lwip/ethip6.h"
 | 
			
		||||
#include "netif/ppp/pppoe.h"
 | 
			
		||||
#include "m480_eth.h"
 | 
			
		||||
#include "string.h"
 | 
			
		||||
 | 
			
		||||
#include "eth_arch.h"
 | 
			
		||||
#include "sys_arch.h"
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#include "mbed_interface.h"
 | 
			
		||||
#include "cmsis.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Define those to better describe your network interface. */
 | 
			
		||||
#define IFNAME0 'e'
 | 
			
		||||
#define IFNAME1 'n'
 | 
			
		||||
 | 
			
		||||
// Fow now, all interrupt handling happens inside one single handler, so we need to figure
 | 
			
		||||
// out what actually triggered the interrupt.
 | 
			
		||||
static volatile uint8_t emac_timer_fired;
 | 
			
		||||
volatile uint8_t allow_net_callbacks;
 | 
			
		||||
 | 
			
		||||
struct netif *_netif;
 | 
			
		||||
 | 
			
		||||
unsigned char my_mac_addr[6] = {0x02, 0x00, 0xac, 0x55, 0x66, 0x88};
 | 
			
		||||
extern u8_t my_mac_addr[6];
 | 
			
		||||
extern int ETH_link_ok(void);
 | 
			
		||||
extern void EMAC_RX_Action(void);
 | 
			
		||||
 | 
			
		||||
sys_sem_t RxReadySem; /**< RX packet ready semaphore */
 | 
			
		||||
 | 
			
		||||
static void __phy_task(void *data);
 | 
			
		||||
static void __packet_rx_task(void *data);
 | 
			
		||||
/**
 | 
			
		||||
 * Helper struct to hold private data used to operate your ethernet interface.
 | 
			
		||||
 * Keeping the ethernet address of the MAC in this struct is not necessary
 | 
			
		||||
 * as it is already kept in the struct netif.
 | 
			
		||||
 * But this is only an example, anyway...
 | 
			
		||||
 */
 | 
			
		||||
struct ethernetif {
 | 
			
		||||
    struct eth_addr *ethaddr;
 | 
			
		||||
    /* Add whatever per-interface state that is needed here. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Override mbed_mac_address of mbed_interface.c to provide ethernet devices with a semi-unique MAC address
 | 
			
		||||
void mbed_mac_address(char *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);
 | 
			
		||||
//    printf("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * In this function, the hardware should be initialized.
 | 
			
		||||
 * Called from ethernetif_init().
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the already initialized lwip network interface structure
 | 
			
		||||
 *        for this ethernetif
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
low_level_init(struct netif *netif)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /* set MAC hardware address length */
 | 
			
		||||
    netif->hwaddr_len = ETH_HWADDR_LEN;
 | 
			
		||||
 | 
			
		||||
  /* set MAC hardware address */
 | 
			
		||||
#if 1  // set MAC HW address
 | 
			
		||||
#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
 | 
			
		||||
  netif->hwaddr[0] = MBED_MAC_ADDR_0;
 | 
			
		||||
  netif->hwaddr[1] = MBED_MAC_ADDR_1;
 | 
			
		||||
  netif->hwaddr[2] = MBED_MAC_ADDR_2;
 | 
			
		||||
  netif->hwaddr[3] = MBED_MAC_ADDR_3;
 | 
			
		||||
  netif->hwaddr[4] = MBED_MAC_ADDR_4;
 | 
			
		||||
  netif->hwaddr[5] = MBED_MAC_ADDR_5;
 | 
			
		||||
#else
 | 
			
		||||
  mbed_mac_address((char *)netif->hwaddr);
 | 
			
		||||
#endif  /* set MAC HW address */
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
    netif->hwaddr[0] = my_mac_addr[0];
 | 
			
		||||
    netif->hwaddr[1] = my_mac_addr[1];
 | 
			
		||||
    netif->hwaddr[2] = my_mac_addr[2];
 | 
			
		||||
    netif->hwaddr[3] = my_mac_addr[3];
 | 
			
		||||
    netif->hwaddr[4] = my_mac_addr[4];
 | 
			
		||||
    netif->hwaddr[5] = my_mac_addr[5];
 | 
			
		||||
#endif // endif 
 | 
			
		||||
	
 | 
			
		||||
    /* maximum transfer unit */
 | 
			
		||||
    netif->mtu = 1500;
 | 
			
		||||
 | 
			
		||||
    /* device capabilities */
 | 
			
		||||
    /* NETIF_FLAG_LINK_UP should be enabled by netif_set_link_up() */
 | 
			
		||||
    netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET; 
 | 
			
		||||
#ifdef LWIP_IGMP
 | 
			
		||||
    netif->flags |= NETIF_FLAG_IGMP;
 | 
			
		||||
#endif
 | 
			
		||||
#if LWIP_IPV6_MLD
 | 
			
		||||
    netif->flags |= NETIF_FLAG_MLD6;
 | 
			
		||||
#endif
 | 
			
		||||
    // TODO: enable clock & configure GPIO function
 | 
			
		||||
    ETH_init(netif->hwaddr);
 | 
			
		||||
 | 
			
		||||
#if LWIP_IGMP
 | 
			
		||||
    EMAC_ENABLE_RECV_BCASTPKT();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if LWIP_IPV6_MLD
 | 
			
		||||
    EMAC_ENABLE_RECV_MCASTPKT();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This function should do the actual transmission of the packet. The packet is
 | 
			
		||||
 * contained in the pbuf that is passed to the function. This pbuf
 | 
			
		||||
 * might be chained.
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the lwip network interface structure for this ethernetif
 | 
			
		||||
 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
 | 
			
		||||
 * @return ERR_OK if the packet could be sent
 | 
			
		||||
 *         an err_t value if the packet couldn't be sent
 | 
			
		||||
 *
 | 
			
		||||
 * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
 | 
			
		||||
 *       strange results. You might consider waiting for space in the DMA queue
 | 
			
		||||
 *       to become availale since the stack doesn't retry to send a packet
 | 
			
		||||
 *       dropped because of memory failure (except for the TCP timers).
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static err_t
 | 
			
		||||
low_level_output(struct netif *netif, struct pbuf *p)
 | 
			
		||||
{
 | 
			
		||||
    struct pbuf *q;
 | 
			
		||||
    u8_t *buf = NULL;
 | 
			
		||||
    u16_t len = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    buf = ETH_get_tx_buf();
 | 
			
		||||
    if(buf == NULL)
 | 
			
		||||
        return ERR_MEM;
 | 
			
		||||
#if ETH_PAD_SIZE
 | 
			
		||||
    pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    for(q = p; q != NULL; q = q->next) {
 | 
			
		||||
        memcpy((u8_t*)&buf[len], q->payload, q->len);
 | 
			
		||||
        len = len + q->len;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef TIME_STAMPING
 | 
			
		||||
    ETH_trigger_tx(len, p->flags & PBUF_FLAG_GET_TXTS ? p : NULL);
 | 
			
		||||
#else
 | 
			
		||||
    ETH_trigger_tx(len, NULL);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ETH_PAD_SIZE
 | 
			
		||||
    pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    LINK_STATS_INC(link.xmit);
 | 
			
		||||
 | 
			
		||||
    return ERR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Should allocate a pbuf and transfer the bytes of the incoming
 | 
			
		||||
 * packet from the interface into the pbuf.
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the lwip network interface structure for this ethernetif
 | 
			
		||||
 * @return a pbuf filled with the received packet (including MAC header)
 | 
			
		||||
 *         NULL on memory error
 | 
			
		||||
 */
 | 
			
		||||
static struct pbuf *
 | 
			
		||||
low_level_input(struct netif *netif, u16_t len, u8_t *buf)
 | 
			
		||||
{
 | 
			
		||||
    struct pbuf *p, *q;
 | 
			
		||||
 | 
			
		||||
#if ETH_PAD_SIZE
 | 
			
		||||
    len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /* We allocate a pbuf chain of pbufs from the pool. */
 | 
			
		||||
    p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
 | 
			
		||||
 | 
			
		||||
    if (p != NULL) {
 | 
			
		||||
 | 
			
		||||
#if ETH_PAD_SIZE
 | 
			
		||||
        pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        len = 0;
 | 
			
		||||
        /* We iterate over the pbuf chain until we have read the entire
 | 
			
		||||
        * packet into the pbuf. */
 | 
			
		||||
        for(q = p; q != NULL; q = q->next) {
 | 
			
		||||
            memcpy((u8_t*)q->payload, (u8_t*)&buf[len], q->len);
 | 
			
		||||
            len = len + q->len;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if ETH_PAD_SIZE
 | 
			
		||||
        pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        LINK_STATS_INC(link.recv);
 | 
			
		||||
    } else {
 | 
			
		||||
        // do nothing. drop the packet
 | 
			
		||||
        LINK_STATS_INC(link.memerr);
 | 
			
		||||
        LINK_STATS_INC(link.drop);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This function should be called when a packet is ready to be read
 | 
			
		||||
 * from the interface. It uses the function low_level_input() that
 | 
			
		||||
 * should handle the actual reception of bytes from the network
 | 
			
		||||
 * interface. Then the type of the received packet is determined and
 | 
			
		||||
 * the appropriate input function is called.
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the lwip network interface structure for this ethernetif
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
ethernetif_input(u16_t len, u8_t *buf, u32_t s, u32_t ns)
 | 
			
		||||
{
 | 
			
		||||
    struct eth_hdr *ethhdr;
 | 
			
		||||
    struct pbuf *p;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /* move received packet into a new pbuf */
 | 
			
		||||
    p = low_level_input(_netif, len, buf);
 | 
			
		||||
    /* no packet could be read, silently ignore this */
 | 
			
		||||
    if (p == NULL) return;
 | 
			
		||||
#ifdef TIME_STAMPING
 | 
			
		||||
    p->ts_sec = s;
 | 
			
		||||
    p->ts_nsec = ns;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /* points to packet payload, which starts with an Ethernet header */
 | 
			
		||||
    ethhdr = p->payload;
 | 
			
		||||
 | 
			
		||||
    switch (htons(ethhdr->type)) {
 | 
			
		||||
    /* IP or ARP packet? */
 | 
			
		||||
    case ETHTYPE_IP:
 | 
			
		||||
    case ETHTYPE_ARP:
 | 
			
		||||
#if PPPOE_SUPPORT
 | 
			
		||||
    /* PPPoE packet? */
 | 
			
		||||
    case ETHTYPE_PPPOEDISC:
 | 
			
		||||
    case ETHTYPE_PPPOE:
 | 
			
		||||
#endif /* PPPOE_SUPPORT */
 | 
			
		||||
        /* full packet send to tcpip_thread to process */
 | 
			
		||||
        if (_netif->input(p, _netif)!=ERR_OK) {
 | 
			
		||||
            LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
 | 
			
		||||
            pbuf_free(p);
 | 
			
		||||
            p = NULL;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        pbuf_free(p);
 | 
			
		||||
        p = NULL;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef    TIME_STAMPING
 | 
			
		||||
void
 | 
			
		||||
ethernetif_loopback_input(struct pbuf *p)           // TODO: make sure packet not drop in input()
 | 
			
		||||
{
 | 
			
		||||
    /* pass all packets to ethernet_input, which decides what packets it supports */
 | 
			
		||||
    if (netif->input(p, netif) != ERR_OK) {
 | 
			
		||||
        LWIP_DEBUGF(NETIF_DEBUG, ("k64f_enetif_input: input error\n"));
 | 
			
		||||
        /* Free buffer */
 | 
			
		||||
        pbuf_free(p);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Should be called at the beginning of the program to set up the
 | 
			
		||||
 * network interface. It calls the function low_level_init() to do the
 | 
			
		||||
 * actual setup of the hardware.
 | 
			
		||||
 *
 | 
			
		||||
 * This function should be passed as a parameter to netif_add().
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the lwip network interface structure for this ethernetif
 | 
			
		||||
 * @return ERR_OK if the loopif is initialized
 | 
			
		||||
 *         ERR_MEM if private data couldn't be allocated
 | 
			
		||||
 *         any other err_t on error
 | 
			
		||||
 */
 | 
			
		||||
err_t
 | 
			
		||||
 eth_arch_enetif_init(struct netif *netif)
 | 
			
		||||
{
 | 
			
		||||
    err_t err;
 | 
			
		||||
    struct ethernetif *ethernetif;
 | 
			
		||||
 | 
			
		||||
    LWIP_ASSERT("netif != NULL", (netif != NULL));
 | 
			
		||||
 | 
			
		||||
    _netif = netif;
 | 
			
		||||
    ethernetif = mem_malloc(sizeof(struct ethernetif));
 | 
			
		||||
    if (ethernetif == NULL) {
 | 
			
		||||
        LWIP_DEBUGF(NETIF_DEBUG, (" eth_arch_enetif_init: out of memory\n"));
 | 
			
		||||
        return ERR_MEM;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
   // Chris: The initialization code uses osDelay, so timers neet to run
 | 
			
		||||
   // SysTick_Init();
 | 
			
		||||
	
 | 
			
		||||
#if LWIP_NETIF_HOSTNAME
 | 
			
		||||
    /* Initialize interface hostname */
 | 
			
		||||
    netif->hostname = "m480";
 | 
			
		||||
#endif /* LWIP_NETIF_HOSTNAME */
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Initialize the snmp variables and counters inside the struct netif.
 | 
			
		||||
     * The last argument should be replaced with your link speed, in units
 | 
			
		||||
     * of bits per second.
 | 
			
		||||
     */
 | 
			
		||||
    NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
 | 
			
		||||
 | 
			
		||||
    netif->state = ethernetif;
 | 
			
		||||
    netif->name[0] = IFNAME0;
 | 
			
		||||
    netif->name[1] = IFNAME1;
 | 
			
		||||
    /* We directly use etharp_output() here to save a function call.
 | 
			
		||||
     * You can instead declare your own function an call etharp_output()
 | 
			
		||||
     * from it if you have to do some checks before sending (e.g. if link
 | 
			
		||||
     * is available...) */
 | 
			
		||||
#if LWIP_IPV4
 | 
			
		||||
    netif->output = etharp_output;
 | 
			
		||||
#endif
 | 
			
		||||
#if LWIP_IPV6
 | 
			
		||||
    netif->output_ip6 = ethip6_output;
 | 
			
		||||
#endif
 | 
			
		||||
    netif->linkoutput = low_level_output;
 | 
			
		||||
 | 
			
		||||
    ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
 | 
			
		||||
 | 
			
		||||
    /* initialize the hardware */
 | 
			
		||||
    low_level_init(netif);
 | 
			
		||||
 | 
			
		||||
    /* Packet receive task */
 | 
			
		||||
 | 
			
		||||
    err = sys_sem_new(&RxReadySem, 0);
 | 
			
		||||
    if(err != ERR_OK) {
 | 
			
		||||
        LWIP_ASSERT("RxReadySem creation error", (err == ERR_OK));
 | 
			
		||||
    }
 | 
			
		||||
	// In GCC code, DEFAULT_THREAD_STACKSIZE 512 bytes is not enough for rx_task
 | 
			
		||||
#if defined (__GNUC__)	
 | 
			
		||||
    // mbed OS 2.0, DEFAULT_THREAD_STACKSIZE*3
 | 
			
		||||
	// mbed OS 5.0, DEFAULT_THREAD_STACKSIZE*5 
 | 
			
		||||
	sys_thread_new("receive_thread", __packet_rx_task, &RxReadySem, DEFAULT_THREAD_STACKSIZE*5, osPriorityNormal);
 | 
			
		||||
#else
 | 
			
		||||
	sys_thread_new("receive_thread", __packet_rx_task, &RxReadySem, DEFAULT_THREAD_STACKSIZE, osPriorityNormal);
 | 
			
		||||
#endif
 | 
			
		||||
    /* PHY monitoring task */
 | 
			
		||||
#if defined (__GNUC__)		
 | 
			
		||||
    // mbed OS 2.0, DEFAULT_THREAD_STACKSIZE
 | 
			
		||||
	// mbed OS 5.0, DEFAULT_THREAD_STACKSIZE*2
 | 
			
		||||
    sys_thread_new("phy_thread", __phy_task, netif, DEFAULT_THREAD_STACKSIZE*2, osPriorityNormal);
 | 
			
		||||
#else
 | 
			
		||||
    sys_thread_new("phy_thread", __phy_task, netif, DEFAULT_THREAD_STACKSIZE, osPriorityNormal);
 | 
			
		||||
#endif	
 | 
			
		||||
    /* Allow the PHY task to detect the initial link state and set up the proper flags */
 | 
			
		||||
    osDelay(10);
 | 
			
		||||
	
 | 
			
		||||
    return ERR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void eth_arch_enable_interrupts(void) {
 | 
			
		||||
//  enet_hal_config_interrupt(BOARD_DEBUG_ENET_INSTANCE_ADDR, (kEnetTxFrameInterrupt | kEnetRxFrameInterrupt), true);
 | 
			
		||||
    EMAC->INTEN |= EMAC_INTEN_RXIEN_Msk |
 | 
			
		||||
                   EMAC_INTEN_TXIEN_Msk ;
 | 
			
		||||
	NVIC_EnableIRQ(EMAC_RX_IRQn);
 | 
			
		||||
	NVIC_EnableIRQ(EMAC_TX_IRQn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void eth_arch_disable_interrupts(void) {
 | 
			
		||||
	NVIC_DisableIRQ(EMAC_RX_IRQn);
 | 
			
		||||
	NVIC_DisableIRQ(EMAC_TX_IRQn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Defines the PHY link speed */
 | 
			
		||||
typedef enum _phy_speed
 | 
			
		||||
{
 | 
			
		||||
    kPHY_Speed10M = 0U, /* ENET PHY 10M speed. */
 | 
			
		||||
    kPHY_Speed100M      /* ENET PHY 100M speed. */
 | 
			
		||||
} phy_speed_t;
 | 
			
		||||
 | 
			
		||||
/* Defines the PHY link duplex. */
 | 
			
		||||
typedef enum _phy_duplex
 | 
			
		||||
{
 | 
			
		||||
    kPHY_HalfDuplex = 0U, /* ENET PHY half duplex. */
 | 
			
		||||
    kPHY_FullDuplex       /* ENET PHY full duplex. */
 | 
			
		||||
} phy_duplex_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int connected;
 | 
			
		||||
    phy_speed_t speed;
 | 
			
		||||
    phy_duplex_t duplex;
 | 
			
		||||
} PHY_STATE;
 | 
			
		||||
 | 
			
		||||
#define STATE_UNKNOWN           (-1)
 | 
			
		||||
 | 
			
		||||
static void __phy_task(void *data) {
 | 
			
		||||
  struct netif *netif = (struct netif*)data;
 | 
			
		||||
//  PHY_STATE crt_state = {STATE_UNKNOWN, (phy_speed_t)STATE_UNKNOWN, (phy_duplex_t)STATE_UNKNOWN};
 | 
			
		||||
//  PHY_STATE prev_state;
 | 
			
		||||
 | 
			
		||||
//  prev_state = crt_state;
 | 
			
		||||
  while (1) {
 | 
			
		||||
    // Get current status
 | 
			
		||||
    // Get the actual PHY link speed
 | 
			
		||||
    // Compare with previous state
 | 
			
		||||
			
 | 
			
		||||
			if( !(ETH_link_ok()) && (netif->flags & NETIF_FLAG_LINK_UP) ) {
 | 
			
		||||
				/* tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1); */
 | 
			
		||||
				netif_set_link_down(netif);
 | 
			
		||||
				LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING|LWIP_DBG_ON, ("Link Down\r\n"));	
 | 
			
		||||
			}else if ( ETH_link_ok() && !(netif->flags & NETIF_FLAG_LINK_UP) ) { 
 | 
			
		||||
				/* tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1); */
 | 
			
		||||
				netif_set_link_up(netif);
 | 
			
		||||
				LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING|LWIP_DBG_ON, ("Link Up\r\n"));
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
    osDelay(200);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ack_emac_rx_isr()
 | 
			
		||||
{
 | 
			
		||||
  sys_sem_signal(&RxReadySem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __packet_rx_task(void *data) {
 | 
			
		||||
 | 
			
		||||
  while (1) {
 | 
			
		||||
    /* Wait for receive task to wakeup */
 | 
			
		||||
    sys_arch_sem_wait(&RxReadySem, 0);
 | 
			
		||||
	EMAC_RX_Action();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,69 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Nuvoton Technology Corp.
 | 
			
		||||
 *
 | 
			
		||||
 * See file CREDITS for list of people who contributed to this
 | 
			
		||||
 * project.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 | 
			
		||||
 * MA 02111-1307 USA
 | 
			
		||||
 *
 | 
			
		||||
 * Description:  EMAC driver header file
 | 
			
		||||
 */
 | 
			
		||||
#ifndef __ETHERNETIF_H__
 | 
			
		||||
#define __ETHERNETIF_H__
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "lwip/err.h"
 | 
			
		||||
#include "lwip/netif.h"
 | 
			
		||||
 | 
			
		||||
#if defined(__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//extern sys_sem_t tx_sem;
 | 
			
		||||
extern sys_sem_t rx_sem;
 | 
			
		||||
 | 
			
		||||
//err_t ethernetif_init(struct netif *netif);
 | 
			
		||||
//err_t ethernetif_input(struct netif *netif);
 | 
			
		||||
//struct netif *ethernetif_register(void);
 | 
			
		||||
//int ethernetif_poll(void);
 | 
			
		||||
 | 
			
		||||
#if defined(__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef SERVER
 | 
			
		||||
 | 
			
		||||
#define MAC_ADDR0 0x00
 | 
			
		||||
#define MAC_ADDR1 0x00
 | 
			
		||||
#define MAC_ADDR2 0x00
 | 
			
		||||
#define MAC_ADDR3 0x00
 | 
			
		||||
#define MAC_ADDR4 0x00
 | 
			
		||||
#define MAC_ADDR5 0x01
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#define MAC_ADDR0 0x00
 | 
			
		||||
#define MAC_ADDR1 0x00
 | 
			
		||||
#define MAC_ADDR2 0x00
 | 
			
		||||
#define MAC_ADDR3 0x00
 | 
			
		||||
#define MAC_ADDR4 0x00
 | 
			
		||||
//#define MAC_ADDR5 0x02
 | 
			
		||||
#define MAC_ADDR5 0x03
 | 
			
		||||
//#define MAC_ADDR5 0x04
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -1,26 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2012-2015, ARM Limited, All Rights Reserved
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 * 
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
 * not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * 
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 * 
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef LWIPOPTS_CONF_H
 | 
			
		||||
#define LWIPOPTS_CONF_H
 | 
			
		||||
 | 
			
		||||
#define LWIP_TRANSPORT_ETHERNET       1
 | 
			
		||||
#define ETH_PAD_SIZE                  2
 | 
			
		||||
 | 
			
		||||
#define MEM_SIZE                      (16*1024)//(8*1024)//(16*1024)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -1,357 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2013 Nuvoton Technology Corp.
 | 
			
		||||
 *
 | 
			
		||||
 * See file CREDITS for list of people who contributed to this
 | 
			
		||||
 * project.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 | 
			
		||||
 * MA 02111-1307 USA
 | 
			
		||||
 *
 | 
			
		||||
 * Description:   NUC472 MAC driver source file
 | 
			
		||||
 */
 | 
			
		||||
#include "nuc472_eth.h"
 | 
			
		||||
#include "lwip/opt.h"
 | 
			
		||||
#include "lwip/def.h"
 | 
			
		||||
#include "mbed_toolchain.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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
#ifdef __ICCARM__
 | 
			
		||||
#pragma data_alignment=4
 | 
			
		||||
struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM];
 | 
			
		||||
struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM];
 | 
			
		||||
#else
 | 
			
		||||
struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
 | 
			
		||||
struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
 | 
			
		||||
#endif
 | 
			
		||||
*/
 | 
			
		||||
struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] MBED_ALIGN(4);
 | 
			
		||||
struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] MBED_ALIGN(4);
 | 
			
		||||
 | 
			
		||||
struct eth_descriptor volatile *cur_tx_desc_ptr, *cur_rx_desc_ptr, *fin_tx_desc_ptr;
 | 
			
		||||
 | 
			
		||||
u8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE]  MBED_ALIGN(4);
 | 
			
		||||
u8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE]  MBED_ALIGN(4);
 | 
			
		||||
 | 
			
		||||
extern void ethernetif_input(u16_t len, u8_t *buf, u32_t s, u32_t ns);
 | 
			
		||||
extern void ethernetif_loopback_input(struct pbuf *p);
 | 
			
		||||
extern void ack_emac_rx_isr(void);
 | 
			
		||||
 | 
			
		||||
// 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(u8_t addr, u8_t reg, u16_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 u16_t mdio_read(u8_t addr, u8_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)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    u16_t reg;
 | 
			
		||||
    u32_t delay;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    mdio_write(CONFIG_PHY_ADDR, MII_BMCR, BMCR_RESET);
 | 
			
		||||
 | 
			
		||||
    delay = 2000;
 | 
			
		||||
    while(delay-- > 0) {
 | 
			
		||||
        if((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0)
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(delay == 0) {
 | 
			
		||||
        LWIP_DEBUGF(LWIP_DBG_LEVEL_SEVERE|LWIP_DBG_ON,("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);
 | 
			
		||||
 | 
			
		||||
    delay = 200000;
 | 
			
		||||
    while(delay-- > 0) {
 | 
			
		||||
        if((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
 | 
			
		||||
                == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(delay == 0) {
 | 
			
		||||
        LWIP_DEBUGF(LWIP_DBG_LEVEL_SEVERE|LWIP_DBG_ON , ("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) {
 | 
			
		||||
            LWIP_DEBUGF(LWIP_DBG_LEVEL_ALL|LWIP_DBG_ON, ("100 full\n"));
 | 
			
		||||
            EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
 | 
			
		||||
        } else if(reg & ADVERTISE_100HALF) {
 | 
			
		||||
            LWIP_DEBUGF(LWIP_DBG_LEVEL_ALL|LWIP_DBG_ON, ("100 half\n"));
 | 
			
		||||
            EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk;
 | 
			
		||||
        } else if(reg & ADVERTISE_10FULL) {
 | 
			
		||||
            LWIP_DEBUGF(LWIP_DBG_LEVEL_ALL|LWIP_DBG_ON, ("10 full\n"));
 | 
			
		||||
            EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk;
 | 
			
		||||
        } else {
 | 
			
		||||
            LWIP_DEBUGF(LWIP_DBG_LEVEL_ALL|LWIP_DBG_ON, ("10 half\n"));
 | 
			
		||||
            EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void init_tx_desc(void)
 | 
			
		||||
{
 | 
			
		||||
    u32_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)
 | 
			
		||||
{
 | 
			
		||||
    u32_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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_mac_addr(u8_t *addr)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    EMAC->CAM0M = (addr[0] << 24) |
 | 
			
		||||
                  (addr[1] << 16) |
 | 
			
		||||
                  (addr[2] << 8) |
 | 
			
		||||
                  addr[3];
 | 
			
		||||
 | 
			
		||||
    EMAC->CAM0L = (addr[4] << 24) |
 | 
			
		||||
                  (addr[5] << 16);
 | 
			
		||||
 | 
			
		||||
    EMAC->CAMCTL = EMAC_CAMCTL_CMPEN_Msk | EMAC_CAMCTL_AMP_Msk | EMAC_CAMCTL_ABP_Msk;
 | 
			
		||||
    EMAC->CAMEN = 1;    // Enable CAM entry 0
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __eth_clk_pin_init()
 | 
			
		||||
{
 | 
			
		||||
	 /* Enable IP clock */
 | 
			
		||||
    CLK_EnableModuleClock(EMAC_MODULE);
 | 
			
		||||
    // Configure MDC clock rate to HCLK / (127 + 1) = 656 kHz if system is running at 84 MHz
 | 
			
		||||
    CLK_SetModuleClock(EMAC_MODULE, 0, CLK_CLKDIV3_EMAC(127));
 | 
			
		||||
    /*---------------------------------------------------------------------------------------------------------*/
 | 
			
		||||
    /* Init I/O Multi-function                                                                                 */
 | 
			
		||||
    /*---------------------------------------------------------------------------------------------------------*/
 | 
			
		||||
    // Configure RMII pins
 | 
			
		||||
    SYS->GPC_MFPL &= ~( SYS_GPC_MFPL_PC0MFP_Msk | SYS_GPC_MFPL_PC1MFP_Msk |
 | 
			
		||||
                    SYS_GPC_MFPL_PC2MFP_Msk | SYS_GPC_MFPL_PC3MFP_Msk |
 | 
			
		||||
                    SYS_GPC_MFPL_PC4MFP_Msk | SYS_GPC_MFPL_PC6MFP_Msk | SYS_GPC_MFPL_PC7MFP_Msk ); 
 | 
			
		||||
    SYS->GPC_MFPL |= SYS_GPC_MFPL_PC0MFP_EMAC_REFCLK |
 | 
			
		||||
                    SYS_GPC_MFPL_PC1MFP_EMAC_MII_RXERR |
 | 
			
		||||
                    SYS_GPC_MFPL_PC2MFP_EMAC_MII_RXDV |
 | 
			
		||||
                    SYS_GPC_MFPL_PC3MFP_EMAC_MII_RXD1 |
 | 
			
		||||
                    SYS_GPC_MFPL_PC4MFP_EMAC_MII_RXD0 |
 | 
			
		||||
                    SYS_GPC_MFPL_PC6MFP_EMAC_MII_TXD0 |
 | 
			
		||||
                    SYS_GPC_MFPL_PC7MFP_EMAC_MII_TXD1;
 | 
			
		||||
 | 
			
		||||
    SYS->GPC_MFPH &= ~SYS_GPC_MFPH_PC8MFP_Msk;
 | 
			
		||||
    SYS->GPC_MFPH |= SYS_GPC_MFPH_PC8MFP_EMAC_MII_TXEN;
 | 
			
		||||
    // Enable high slew rate on all RMII pins
 | 
			
		||||
    PC->SLEWCTL |= 0x1DF;
 | 
			
		||||
 | 
			
		||||
    // Configure MDC, MDIO at PB14 & PB15
 | 
			
		||||
    SYS->GPB_MFPH &= ~(SYS_GPB_MFPH_PB14MFP_Msk | SYS_GPB_MFPH_PB15MFP_Msk);
 | 
			
		||||
    SYS->GPB_MFPH |= SYS_GPB_MFPH_PB14MFP_EMAC_MII_MDC | SYS_GPB_MFPH_PB15MFP_EMAC_MII_MDIO;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ETH_init(u8_t *mac_addr)
 | 
			
		||||
{
 | 
			
		||||
	// init CLK & pins
 | 
			
		||||
	__eth_clk_pin_init();
 | 
			
		||||
	
 | 
			
		||||
    // Reset MAC
 | 
			
		||||
    EMAC->CTL = EMAC_CTL_RST_Msk;
 | 
			
		||||
 | 
			
		||||
    init_tx_desc();
 | 
			
		||||
    init_rx_desc();
 | 
			
		||||
 | 
			
		||||
    set_mac_addr(mac_addr);  // need to reconfigure hardware address 'cos we just RESET emc...
 | 
			
		||||
    reset_phy();
 | 
			
		||||
 | 
			
		||||
    EMAC->CTL |= EMAC_CTL_STRIPCRC_Msk | EMAC_CTL_RXON_Msk | EMAC_CTL_TXON_Msk | EMAC_CTL_RMIIEN_Msk | EMAC_CTL_RMIIRXCTL_Msk;
 | 
			
		||||
    EMAC->INTEN |= EMAC_INTEN_RXIEN_Msk |
 | 
			
		||||
                   EMAC_INTEN_RXGDIEN_Msk |
 | 
			
		||||
                   EMAC_INTEN_RDUIEN_Msk |
 | 
			
		||||
                   EMAC_INTEN_RXBEIEN_Msk |
 | 
			
		||||
                   EMAC_INTEN_TXIEN_Msk |
 | 
			
		||||
                   EMAC_INTEN_TXABTIEN_Msk |
 | 
			
		||||
                   EMAC_INTEN_TXCPIEN_Msk |
 | 
			
		||||
                   EMAC_INTEN_TXBEIEN_Msk;
 | 
			
		||||
    EMAC->RXST = 0;  // trigger Rx
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void  ETH_halt(void)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    EMAC->CTL &= ~(EMAC_CTL_RXON_Msk | EMAC_CTL_TXON_Msk);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int m_status;
 | 
			
		||||
 | 
			
		||||
void EMAC_RX_IRQHandler(void)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    m_status = EMAC->INTSTS & 0xFFFF;
 | 
			
		||||
    EMAC->INTSTS = m_status;
 | 
			
		||||
    if (m_status & EMAC_INTSTS_RXBEIF_Msk) {
 | 
			
		||||
        // Shouldn't goes here, unless descriptor corrupted
 | 
			
		||||
		LWIP_DEBUGF(LWIP_DBG_LEVEL_SERIOUS|LWIP_DBG_ON, ("RX descriptor corrupted \r\n"));
 | 
			
		||||
		//return;
 | 
			
		||||
    }
 | 
			
		||||
	ack_emac_rx_isr();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EMAC_RX_Action(void)
 | 
			
		||||
{
 | 
			
		||||
    unsigned int cur_entry, status;
 | 
			
		||||
    do {
 | 
			
		||||
 | 
			
		||||
        cur_entry = EMAC->CRXDSA;
 | 
			
		||||
 | 
			
		||||
        if ((cur_entry == (u32_t)cur_rx_desc_ptr) && (!(m_status & EMAC_INTSTS_RDUIF_Msk)))  // cur_entry may equal to cur_rx_desc_ptr if RDU occures
 | 
			
		||||
            break;
 | 
			
		||||
        status = cur_rx_desc_ptr->status1;
 | 
			
		||||
 | 
			
		||||
        if(status & OWNERSHIP_EMAC)
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        if (status & RXFD_RXGD) {
 | 
			
		||||
			// Lwip will invoke osMutexWait for resource protection, so ethernetif_input can't be called in EMAC_RX_IRQHandler.
 | 
			
		||||
            ethernetif_input(status & 0xFFFF, cur_rx_desc_ptr->buf, cur_rx_desc_ptr->status2, (u32_t)cur_rx_desc_ptr->next);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC;
 | 
			
		||||
        cur_rx_desc_ptr = cur_rx_desc_ptr->next;
 | 
			
		||||
 | 
			
		||||
    } while (1);
 | 
			
		||||
 | 
			
		||||
    ETH_TRIGGER_RX();
 | 
			
		||||
//	eth_arch_tcpip_thread();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 != (u32_t)fin_tx_desc_ptr) {
 | 
			
		||||
 | 
			
		||||
        fin_tx_desc_ptr = fin_tx_desc_ptr->next;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u8_t *ETH_get_tx_buf(void)
 | 
			
		||||
{
 | 
			
		||||
    if(cur_tx_desc_ptr->status1 & OWNERSHIP_EMAC)
 | 
			
		||||
        return(NULL);
 | 
			
		||||
    else
 | 
			
		||||
        return(cur_tx_desc_ptr->buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ETH_trigger_tx(u16_t length, struct pbuf *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 ETH_link_ok()
 | 
			
		||||
{
 | 
			
		||||
	/* 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;	
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,150 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2013 Nuvoton Technology Corp.
 | 
			
		||||
 *
 | 
			
		||||
 * See file CREDITS for list of people who contributed to this
 | 
			
		||||
 * project.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 | 
			
		||||
 * MA 02111-1307 USA
 | 
			
		||||
 *
 | 
			
		||||
 * Description:   NUC472 EMAC driver header file
 | 
			
		||||
 */
 | 
			
		||||
#include "lwip/def.h"
 | 
			
		||||
#include "lwip/pbuf.h"
 | 
			
		||||
#include "NUC472_442.h"
 | 
			
		||||
#ifndef  _NUC472_ETH_
 | 
			
		||||
#define  _NUC472_ETH_
 | 
			
		||||
 | 
			
		||||
/* Generic MII registers. */
 | 
			
		||||
 | 
			
		||||
#define MII_BMCR            0x00        /* Basic mode control register */
 | 
			
		||||
#define MII_BMSR            0x01        /* Basic mode status register  */
 | 
			
		||||
#define MII_PHYSID1         0x02        /* PHYS ID 1                   */
 | 
			
		||||
#define MII_PHYSID2         0x03        /* PHYS ID 2                   */
 | 
			
		||||
#define MII_ADVERTISE       0x04        /* Advertisement control reg   */
 | 
			
		||||
#define MII_LPA             0x05        /* Link partner ability reg    */
 | 
			
		||||
#define MII_EXPANSION       0x06        /* Expansion register          */
 | 
			
		||||
#define MII_DCOUNTER        0x12        /* Disconnect counter          */
 | 
			
		||||
#define MII_FCSCOUNTER      0x13        /* False carrier counter       */
 | 
			
		||||
#define MII_NWAYTEST        0x14        /* N-way auto-neg test reg     */
 | 
			
		||||
#define MII_RERRCOUNTER     0x15        /* Receive error counter       */
 | 
			
		||||
#define MII_SREVISION       0x16        /* Silicon revision            */
 | 
			
		||||
#define MII_RESV1           0x17        /* Reserved...                 */
 | 
			
		||||
#define MII_LBRERROR        0x18        /* Lpback, rx, bypass error    */
 | 
			
		||||
#define MII_PHYADDR         0x19        /* PHY address                 */
 | 
			
		||||
#define MII_RESV2           0x1a        /* Reserved...                 */
 | 
			
		||||
#define MII_TPISTATUS       0x1b        /* TPI status for 10mbps       */
 | 
			
		||||
#define MII_NCONFIG         0x1c        /* Network interface config    */
 | 
			
		||||
 | 
			
		||||
/* Basic mode control register. */
 | 
			
		||||
#define BMCR_RESV               0x007f  /* Unused...                   */
 | 
			
		||||
#define BMCR_CTST               0x0080  /* Collision test              */
 | 
			
		||||
#define BMCR_FULLDPLX           0x0100  /* Full duplex                 */
 | 
			
		||||
#define BMCR_ANRESTART          0x0200  /* Auto negotiation restart    */
 | 
			
		||||
#define BMCR_ISOLATE            0x0400  /* Disconnect DP83840 from MII */
 | 
			
		||||
#define BMCR_PDOWN              0x0800  /* Powerdown the DP83840       */
 | 
			
		||||
#define BMCR_ANENABLE           0x1000  /* Enable auto negotiation     */
 | 
			
		||||
#define BMCR_SPEED100           0x2000  /* Select 100Mbps              */
 | 
			
		||||
#define BMCR_LOOPBACK           0x4000  /* TXD loopback bits           */
 | 
			
		||||
#define BMCR_RESET              0x8000  /* Reset the DP83840           */
 | 
			
		||||
 | 
			
		||||
/* Basic mode status register. */
 | 
			
		||||
#define BMSR_ERCAP              0x0001  /* Ext-reg capability          */
 | 
			
		||||
#define BMSR_JCD                0x0002  /* Jabber detected             */
 | 
			
		||||
#define BMSR_LSTATUS            0x0004  /* Link status                 */
 | 
			
		||||
#define BMSR_ANEGCAPABLE        0x0008  /* Able to do auto-negotiation */
 | 
			
		||||
#define BMSR_RFAULT             0x0010  /* Remote fault detected       */
 | 
			
		||||
#define BMSR_ANEGCOMPLETE       0x0020  /* Auto-negotiation complete   */
 | 
			
		||||
#define BMSR_RESV               0x07c0  /* Unused...                   */
 | 
			
		||||
#define BMSR_10HALF             0x0800  /* Can do 10mbps, half-duplex  */
 | 
			
		||||
#define BMSR_10FULL             0x1000  /* Can do 10mbps, full-duplex  */
 | 
			
		||||
#define BMSR_100HALF            0x2000  /* Can do 100mbps, half-duplex */
 | 
			
		||||
#define BMSR_100FULL            0x4000  /* Can do 100mbps, full-duplex */
 | 
			
		||||
#define BMSR_100BASE4           0x8000  /* Can do 100mbps, 4k packets  */
 | 
			
		||||
 | 
			
		||||
/* Advertisement control register. */
 | 
			
		||||
#define ADVERTISE_SLCT          0x001f  /* Selector bits               */
 | 
			
		||||
#define ADVERTISE_CSMA          0x0001  /* Only selector supported     */
 | 
			
		||||
#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
 | 
			
		||||
#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
 | 
			
		||||
#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
 | 
			
		||||
#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
 | 
			
		||||
#define ADVERTISE_100BASE4      0x0200  /* Try for 100mbps 4k packets  */
 | 
			
		||||
#define ADVERTISE_RESV          0x1c00  /* Unused...                   */
 | 
			
		||||
#define ADVERTISE_RFAULT        0x2000  /* Say we can detect faults    */
 | 
			
		||||
#define ADVERTISE_LPACK         0x4000  /* Ack link partners response  */
 | 
			
		||||
#define ADVERTISE_NPAGE         0x8000  /* Next page bit               */
 | 
			
		||||
 | 
			
		||||
#define RX_DESCRIPTOR_NUM 4 //2    // 4: Max Number of Rx Frame Descriptors
 | 
			
		||||
#define TX_DESCRIPTOR_NUM 4 //2    // 4: Max number of Tx Frame Descriptors
 | 
			
		||||
 | 
			
		||||
#define PACKET_BUFFER_SIZE  1520
 | 
			
		||||
 | 
			
		||||
#define CONFIG_PHY_ADDR     1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Frame Descriptor's Owner bit
 | 
			
		||||
#define OWNERSHIP_EMAC 0x80000000  // 1 = EMAC
 | 
			
		||||
//#define OWNERSHIP_CPU 0x7fffffff  // 0 = CPU
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Rx Frame Descriptor Status
 | 
			
		||||
#define RXFD_RXGD    0x00100000  // Receiving Good Packet Received
 | 
			
		||||
#define RXFD_RTSAS   0x00800000  // RX Time Stamp Available 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Tx Frame Descriptor's Control bits
 | 
			
		||||
#define TXFD_TTSEN    0x08    // Tx Time Stamp Enable
 | 
			
		||||
#define TXFD_INTEN    0x04    // Interrupt Enable
 | 
			
		||||
#define TXFD_CRCAPP   0x02    // Append CRC
 | 
			
		||||
#define TXFD_PADEN    0x01    // Padding Enable
 | 
			
		||||
 | 
			
		||||
// Tx Frame Descriptor Status
 | 
			
		||||
#define TXFD_TXCP    0x00080000  // Transmission Completion
 | 
			
		||||
#define TXFD_TTSAS   0x08000000  // TX Time Stamp Available
 | 
			
		||||
 | 
			
		||||
// Tx/Rx buffer descriptor structure
 | 
			
		||||
struct eth_descriptor;
 | 
			
		||||
struct eth_descriptor {
 | 
			
		||||
    u32_t  status1;
 | 
			
		||||
    u8_t *buf;
 | 
			
		||||
    u32_t  status2;
 | 
			
		||||
    struct eth_descriptor *next;
 | 
			
		||||
#ifdef TIME_STAMPING
 | 
			
		||||
    u32_t backup1;
 | 
			
		||||
    u32_t backup2;
 | 
			
		||||
    u32_t reserved1;
 | 
			
		||||
    u32_t reserved2;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef TIME_STAMPING
 | 
			
		||||
 | 
			
		||||
#define ETH_TS_ENABLE() do{EMAC->TSCTL = EMAC_TSCTL_TSEN_Msk;}while(0)
 | 
			
		||||
#define ETH_TS_START() do{EMAC->TSCTL |= (EMAC_TSCTL_TSMODE_Msk | EMAC_TSCTL_TSIEN_Msk);}while(0)
 | 
			
		||||
s32_t ETH_settime(u32_t sec, u32_t nsec);
 | 
			
		||||
s32_t ETH_gettime(u32_t *sec, u32_t *nsec);
 | 
			
		||||
s32_t ETH_updatetime(u32_t neg, u32_t sec, u32_t nsec);
 | 
			
		||||
s32_t ETH_adjtimex(int ppm);
 | 
			
		||||
void ETH_setinc(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern void ETH_init(u8_t *mac_addr);
 | 
			
		||||
extern u8_t *ETH_get_tx_buf(void);
 | 
			
		||||
extern void ETH_trigger_tx(u16_t length, struct pbuf *p);
 | 
			
		||||
 | 
			
		||||
#endif  /* _NUC472_ETH_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -1,529 +0,0 @@
 | 
			
		|||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Ethernet Interface Skeleton
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
 | 
			
		||||
 * 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. The name of the author may not be used to endorse or promote products
 | 
			
		||||
 *    derived from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of the lwIP TCP/IP stack.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Adam Dunkels <adam@sics.se>
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This file is a skeleton for developing Ethernet network interface
 | 
			
		||||
 * drivers for lwIP. Add code to the low_level functions and do a
 | 
			
		||||
 * search-and-replace for the word "ethernetif" to replace it with
 | 
			
		||||
 * something that better describes your network interface.
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
#include "lwip/opt.h"
 | 
			
		||||
 | 
			
		||||
#include "lwip/def.h"
 | 
			
		||||
#include "lwip/mem.h"
 | 
			
		||||
#include "lwip/pbuf.h"
 | 
			
		||||
#include "lwip/sys.h"
 | 
			
		||||
#include <lwip/stats.h>
 | 
			
		||||
#include <lwip/snmp.h>
 | 
			
		||||
#include "netif/etharp.h"
 | 
			
		||||
#include "lwip/ethip6.h"
 | 
			
		||||
#include "netif/ppp/pppoe.h"
 | 
			
		||||
#include "nuc472_eth.h"
 | 
			
		||||
#include "string.h"
 | 
			
		||||
 | 
			
		||||
#include "eth_arch.h"
 | 
			
		||||
#include "sys_arch.h"
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#include "mbed_interface.h"
 | 
			
		||||
#include "cmsis.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Define those to better describe your network interface. */
 | 
			
		||||
#define IFNAME0 'e'
 | 
			
		||||
#define IFNAME1 'n'
 | 
			
		||||
 | 
			
		||||
// Fow now, all interrupt handling happens inside one single handler, so we need to figure
 | 
			
		||||
// out what actually triggered the interrupt.
 | 
			
		||||
static volatile uint8_t emac_timer_fired;
 | 
			
		||||
volatile uint8_t allow_net_callbacks;
 | 
			
		||||
 | 
			
		||||
struct netif *_netif;
 | 
			
		||||
 | 
			
		||||
unsigned char my_mac_addr[6] = {0x02, 0x00, 0xac, 0x55, 0x66, 0x77};
 | 
			
		||||
extern u8_t my_mac_addr[6];
 | 
			
		||||
extern int ETH_link_ok(void);
 | 
			
		||||
extern void EMAC_RX_Action(void);
 | 
			
		||||
 | 
			
		||||
sys_sem_t RxReadySem; /**< RX packet ready semaphore */
 | 
			
		||||
 | 
			
		||||
static void __phy_task(void *data);
 | 
			
		||||
static void __packet_rx_task(void *data);
 | 
			
		||||
/**
 | 
			
		||||
 * Helper struct to hold private data used to operate your ethernet interface.
 | 
			
		||||
 * Keeping the ethernet address of the MAC in this struct is not necessary
 | 
			
		||||
 * as it is already kept in the struct netif.
 | 
			
		||||
 * But this is only an example, anyway...
 | 
			
		||||
 */
 | 
			
		||||
struct ethernetif {
 | 
			
		||||
    struct eth_addr *ethaddr;
 | 
			
		||||
    /* Add whatever per-interface state that is needed here. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Override mbed_mac_address of mbed_interface.c to provide ethernet devices with a semi-unique MAC address
 | 
			
		||||
void mbed_mac_address(char *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);
 | 
			
		||||
    
 | 
			
		||||
    LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING|LWIP_DBG_ON, ("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * In this function, the hardware should be initialized.
 | 
			
		||||
 * Called from ethernetif_init().
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the already initialized lwip network interface structure
 | 
			
		||||
 *        for this ethernetif
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
low_level_init(struct netif *netif)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /* set MAC hardware address length */
 | 
			
		||||
    netif->hwaddr_len = ETH_HWADDR_LEN;
 | 
			
		||||
 | 
			
		||||
  /* set MAC hardware address */
 | 
			
		||||
#if 1  // set MAC HW address
 | 
			
		||||
#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
 | 
			
		||||
  netif->hwaddr[0] = MBED_MAC_ADDR_0;
 | 
			
		||||
  netif->hwaddr[1] = MBED_MAC_ADDR_1;
 | 
			
		||||
  netif->hwaddr[2] = MBED_MAC_ADDR_2;
 | 
			
		||||
  netif->hwaddr[3] = MBED_MAC_ADDR_3;
 | 
			
		||||
  netif->hwaddr[4] = MBED_MAC_ADDR_4;
 | 
			
		||||
  netif->hwaddr[5] = MBED_MAC_ADDR_5;
 | 
			
		||||
#else
 | 
			
		||||
  mbed_mac_address((char *)netif->hwaddr);
 | 
			
		||||
#endif  /* set MAC HW address */
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
    netif->hwaddr[0] = my_mac_addr[0];
 | 
			
		||||
    netif->hwaddr[1] = my_mac_addr[1];
 | 
			
		||||
    netif->hwaddr[2] = my_mac_addr[2];
 | 
			
		||||
    netif->hwaddr[3] = my_mac_addr[3];
 | 
			
		||||
    netif->hwaddr[4] = my_mac_addr[4];
 | 
			
		||||
    netif->hwaddr[5] = my_mac_addr[5];
 | 
			
		||||
#endif // endif 
 | 
			
		||||
	
 | 
			
		||||
    /* maximum transfer unit */
 | 
			
		||||
    netif->mtu = 1500;
 | 
			
		||||
 | 
			
		||||
    /* device capabilities */
 | 
			
		||||
    /* NETIF_FLAG_LINK_UP should be enabled by netif_set_link_up() */
 | 
			
		||||
    netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET; 
 | 
			
		||||
#ifdef LWIP_IGMP
 | 
			
		||||
    netif->flags |= NETIF_FLAG_IGMP;
 | 
			
		||||
#endif
 | 
			
		||||
#if LWIP_IPV6_MLD
 | 
			
		||||
    netif->flags |= NETIF_FLAG_MLD6;
 | 
			
		||||
#endif
 | 
			
		||||
    // TODO: enable clock & configure GPIO function
 | 
			
		||||
    ETH_init(netif->hwaddr);
 | 
			
		||||
 | 
			
		||||
#if LWIP_IGMP
 | 
			
		||||
    EMAC_ENABLE_RECV_BCASTPKT();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if LWIP_IPV6_MLD
 | 
			
		||||
    EMAC_ENABLE_RECV_MCASTPKT();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This function should do the actual transmission of the packet. The packet is
 | 
			
		||||
 * contained in the pbuf that is passed to the function. This pbuf
 | 
			
		||||
 * might be chained.
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the lwip network interface structure for this ethernetif
 | 
			
		||||
 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
 | 
			
		||||
 * @return ERR_OK if the packet could be sent
 | 
			
		||||
 *         an err_t value if the packet couldn't be sent
 | 
			
		||||
 *
 | 
			
		||||
 * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
 | 
			
		||||
 *       strange results. You might consider waiting for space in the DMA queue
 | 
			
		||||
 *       to become availale since the stack doesn't retry to send a packet
 | 
			
		||||
 *       dropped because of memory failure (except for the TCP timers).
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static err_t
 | 
			
		||||
low_level_output(struct netif *netif, struct pbuf *p)
 | 
			
		||||
{
 | 
			
		||||
    struct pbuf *q;
 | 
			
		||||
    u8_t *buf = NULL;
 | 
			
		||||
    u16_t len = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    buf = ETH_get_tx_buf();
 | 
			
		||||
    if(buf == NULL)
 | 
			
		||||
        return ERR_MEM;
 | 
			
		||||
#if ETH_PAD_SIZE
 | 
			
		||||
    pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    for(q = p; q != NULL; q = q->next) {
 | 
			
		||||
        memcpy((u8_t*)&buf[len], q->payload, q->len);
 | 
			
		||||
        len = len + q->len;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef TIME_STAMPING
 | 
			
		||||
    ETH_trigger_tx(len, p->flags & PBUF_FLAG_GET_TXTS ? p : NULL);
 | 
			
		||||
#else
 | 
			
		||||
    ETH_trigger_tx(len, NULL);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ETH_PAD_SIZE
 | 
			
		||||
    pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    LINK_STATS_INC(link.xmit);
 | 
			
		||||
 | 
			
		||||
    return ERR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Should allocate a pbuf and transfer the bytes of the incoming
 | 
			
		||||
 * packet from the interface into the pbuf.
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the lwip network interface structure for this ethernetif
 | 
			
		||||
 * @return a pbuf filled with the received packet (including MAC header)
 | 
			
		||||
 *         NULL on memory error
 | 
			
		||||
 */
 | 
			
		||||
static struct pbuf *
 | 
			
		||||
low_level_input(struct netif *netif, u16_t len, u8_t *buf)
 | 
			
		||||
{
 | 
			
		||||
    struct pbuf *p, *q;
 | 
			
		||||
 | 
			
		||||
#if ETH_PAD_SIZE
 | 
			
		||||
    len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /* We allocate a pbuf chain of pbufs from the pool. */
 | 
			
		||||
    p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
 | 
			
		||||
 | 
			
		||||
    if (p != NULL) {
 | 
			
		||||
 | 
			
		||||
#if ETH_PAD_SIZE
 | 
			
		||||
        pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        len = 0;
 | 
			
		||||
        /* We iterate over the pbuf chain until we have read the entire
 | 
			
		||||
        * packet into the pbuf. */
 | 
			
		||||
        for(q = p; q != NULL; q = q->next) {
 | 
			
		||||
            memcpy((u8_t*)q->payload, (u8_t*)&buf[len], q->len);
 | 
			
		||||
            len = len + q->len;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if ETH_PAD_SIZE
 | 
			
		||||
        pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        LINK_STATS_INC(link.recv);
 | 
			
		||||
    } else {
 | 
			
		||||
        // do nothing. drop the packet
 | 
			
		||||
        LINK_STATS_INC(link.memerr);
 | 
			
		||||
        LINK_STATS_INC(link.drop);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This function should be called when a packet is ready to be read
 | 
			
		||||
 * from the interface. It uses the function low_level_input() that
 | 
			
		||||
 * should handle the actual reception of bytes from the network
 | 
			
		||||
 * interface. Then the type of the received packet is determined and
 | 
			
		||||
 * the appropriate input function is called.
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the lwip network interface structure for this ethernetif
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
ethernetif_input(u16_t len, u8_t *buf, u32_t s, u32_t ns)
 | 
			
		||||
{
 | 
			
		||||
    struct eth_hdr *ethhdr;
 | 
			
		||||
    struct pbuf *p;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /* move received packet into a new pbuf */
 | 
			
		||||
    p = low_level_input(_netif, len, buf);
 | 
			
		||||
    /* no packet could be read, silently ignore this */
 | 
			
		||||
    if (p == NULL) return;
 | 
			
		||||
#ifdef TIME_STAMPING
 | 
			
		||||
    p->ts_sec = s;
 | 
			
		||||
    p->ts_nsec = ns;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /* points to packet payload, which starts with an Ethernet header */
 | 
			
		||||
    ethhdr = p->payload;
 | 
			
		||||
 | 
			
		||||
    switch (htons(ethhdr->type)) {
 | 
			
		||||
    /* IP or ARP packet? */
 | 
			
		||||
    case ETHTYPE_IP:
 | 
			
		||||
    case ETHTYPE_ARP:
 | 
			
		||||
#if PPPOE_SUPPORT
 | 
			
		||||
    /* PPPoE packet? */
 | 
			
		||||
    case ETHTYPE_PPPOEDISC:
 | 
			
		||||
    case ETHTYPE_PPPOE:
 | 
			
		||||
#endif /* PPPOE_SUPPORT */
 | 
			
		||||
        /* full packet send to tcpip_thread to process */
 | 
			
		||||
        if (_netif->input(p, _netif)!=ERR_OK) {
 | 
			
		||||
            LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
 | 
			
		||||
            pbuf_free(p);
 | 
			
		||||
            p = NULL;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        pbuf_free(p);
 | 
			
		||||
        p = NULL;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef    TIME_STAMPING
 | 
			
		||||
void
 | 
			
		||||
ethernetif_loopback_input(struct pbuf *p)           // TODO: make sure packet not drop in input()
 | 
			
		||||
{
 | 
			
		||||
    /* pass all packets to ethernet_input, which decides what packets it supports */
 | 
			
		||||
    if (netif->input(p, netif) != ERR_OK) {
 | 
			
		||||
        LWIP_DEBUGF(NETIF_DEBUG, ("netif_input: input error\n"));
 | 
			
		||||
        /* Free buffer */
 | 
			
		||||
        pbuf_free(p);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Should be called at the beginning of the program to set up the
 | 
			
		||||
 * network interface. It calls the function low_level_init() to do the
 | 
			
		||||
 * actual setup of the hardware.
 | 
			
		||||
 *
 | 
			
		||||
 * This function should be passed as a parameter to netif_add().
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the lwip network interface structure for this ethernetif
 | 
			
		||||
 * @return ERR_OK if the loopif is initialized
 | 
			
		||||
 *         ERR_MEM if private data couldn't be allocated
 | 
			
		||||
 *         any other err_t on error
 | 
			
		||||
 */
 | 
			
		||||
err_t
 | 
			
		||||
 eth_arch_enetif_init(struct netif *netif)
 | 
			
		||||
{
 | 
			
		||||
    err_t err;
 | 
			
		||||
    struct ethernetif *ethernetif;
 | 
			
		||||
 | 
			
		||||
    LWIP_ASSERT("netif != NULL", (netif != NULL));
 | 
			
		||||
 | 
			
		||||
    _netif = netif;
 | 
			
		||||
    ethernetif = mem_malloc(sizeof(struct ethernetif));
 | 
			
		||||
    if (ethernetif == NULL) {
 | 
			
		||||
        LWIP_DEBUGF(NETIF_DEBUG, (" eth_arch_enetif_init: out of memory\n"));
 | 
			
		||||
        return ERR_MEM;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
   // Chris: The initialization code uses osDelay, so timers neet to run
 | 
			
		||||
   // SysTick_Init();
 | 
			
		||||
	
 | 
			
		||||
#if LWIP_NETIF_HOSTNAME
 | 
			
		||||
    /* Initialize interface hostname */
 | 
			
		||||
    netif->hostname = "nuc472";
 | 
			
		||||
#endif /* LWIP_NETIF_HOSTNAME */
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Initialize the snmp variables and counters inside the struct netif.
 | 
			
		||||
     * The last argument should be replaced with your link speed, in units
 | 
			
		||||
     * of bits per second.
 | 
			
		||||
     */
 | 
			
		||||
    NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
 | 
			
		||||
 | 
			
		||||
    netif->state = ethernetif;
 | 
			
		||||
    netif->name[0] = IFNAME0;
 | 
			
		||||
    netif->name[1] = IFNAME1;
 | 
			
		||||
    /* We directly use etharp_output() here to save a function call.
 | 
			
		||||
     * You can instead declare your own function an call etharp_output()
 | 
			
		||||
     * from it if you have to do some checks before sending (e.g. if link
 | 
			
		||||
     * is available...) */
 | 
			
		||||
#if LWIP_IPV4
 | 
			
		||||
    netif->output = etharp_output;
 | 
			
		||||
#endif
 | 
			
		||||
#if LWIP_IPV6
 | 
			
		||||
    netif->output_ip6 = ethip6_output;
 | 
			
		||||
#endif
 | 
			
		||||
    netif->linkoutput = low_level_output;
 | 
			
		||||
 | 
			
		||||
    ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
 | 
			
		||||
 | 
			
		||||
    /* initialize the hardware */
 | 
			
		||||
    low_level_init(netif);
 | 
			
		||||
 | 
			
		||||
    /* Packet receive task */
 | 
			
		||||
 | 
			
		||||
    err = sys_sem_new(&RxReadySem, 0);
 | 
			
		||||
    if(err != ERR_OK) LWIP_ASSERT("RxReadySem creation error", (err == ERR_OK));
 | 
			
		||||
	// In GCC code, DEFAULT_THREAD_STACKSIZE 512 bytes is not enough for rx_task
 | 
			
		||||
#if defined (__GNUC__)	
 | 
			
		||||
    // mbed OS 2.0, DEFAULT_THREAD_STACKSIZE*3
 | 
			
		||||
	// mbed OS 5.0, DEFAULT_THREAD_STACKSIZE*5 
 | 
			
		||||
	sys_thread_new("nuc472_emac_rx_thread", __packet_rx_task, &RxReadySem, DEFAULT_THREAD_STACKSIZE*5, osPriorityNormal);
 | 
			
		||||
#else
 | 
			
		||||
	sys_thread_new("nuc472_emac_rx_thread", __packet_rx_task, &RxReadySem, DEFAULT_THREAD_STACKSIZE, osPriorityNormal);
 | 
			
		||||
#endif
 | 
			
		||||
    /* PHY monitoring task */
 | 
			
		||||
#if defined (__GNUC__)		
 | 
			
		||||
    // mbed OS 2.0, DEFAULT_THREAD_STACKSIZE
 | 
			
		||||
	// mbed OS 5.0, DEFAULT_THREAD_STACKSIZE*2
 | 
			
		||||
    sys_thread_new("nuc472_emac_phy_thread", __phy_task, netif, DEFAULT_THREAD_STACKSIZE*2, osPriorityNormal);
 | 
			
		||||
#else
 | 
			
		||||
    sys_thread_new("nuc472_emac_phy_thread", __phy_task, netif, DEFAULT_THREAD_STACKSIZE, osPriorityNormal);
 | 
			
		||||
#endif	
 | 
			
		||||
    /* Allow the PHY task to detect the initial link state and set up the proper flags */
 | 
			
		||||
    osDelay(10);
 | 
			
		||||
	
 | 
			
		||||
    return ERR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void eth_arch_enable_interrupts(void) {
 | 
			
		||||
//  enet_hal_config_interrupt(BOARD_DEBUG_ENET_INSTANCE_ADDR, (kEnetTxFrameInterrupt | kEnetRxFrameInterrupt), true);
 | 
			
		||||
    EMAC->INTEN |= EMAC_INTEN_RXIEN_Msk |
 | 
			
		||||
                   EMAC_INTEN_TXIEN_Msk ;
 | 
			
		||||
	NVIC_EnableIRQ(EMAC_RX_IRQn);
 | 
			
		||||
	NVIC_EnableIRQ(EMAC_TX_IRQn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void eth_arch_disable_interrupts(void) {
 | 
			
		||||
	NVIC_DisableIRQ(EMAC_RX_IRQn);
 | 
			
		||||
	NVIC_DisableIRQ(EMAC_TX_IRQn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Defines the PHY link speed */
 | 
			
		||||
typedef enum _phy_speed
 | 
			
		||||
{
 | 
			
		||||
    kPHY_Speed10M = 0U, /* ENET PHY 10M speed. */
 | 
			
		||||
    kPHY_Speed100M      /* ENET PHY 100M speed. */
 | 
			
		||||
} phy_speed_t;
 | 
			
		||||
 | 
			
		||||
/* Defines the PHY link duplex. */
 | 
			
		||||
typedef enum _phy_duplex
 | 
			
		||||
{
 | 
			
		||||
    kPHY_HalfDuplex = 0U, /* ENET PHY half duplex. */
 | 
			
		||||
    kPHY_FullDuplex       /* ENET PHY full duplex. */
 | 
			
		||||
} phy_duplex_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int connected;
 | 
			
		||||
    phy_speed_t speed;
 | 
			
		||||
    phy_duplex_t duplex;
 | 
			
		||||
} PHY_STATE;
 | 
			
		||||
 | 
			
		||||
#define STATE_UNKNOWN           (-1)
 | 
			
		||||
 | 
			
		||||
static void __phy_task(void *data) {
 | 
			
		||||
  struct netif *netif = (struct netif*)data;
 | 
			
		||||
//  PHY_STATE crt_state = {STATE_UNKNOWN, (phy_speed_t)STATE_UNKNOWN, (phy_duplex_t)STATE_UNKNOWN};
 | 
			
		||||
//  PHY_STATE prev_state;
 | 
			
		||||
 | 
			
		||||
//  prev_state = crt_state;
 | 
			
		||||
  while (1) {
 | 
			
		||||
    // Get current status
 | 
			
		||||
    // Get the actual PHY link speed
 | 
			
		||||
    // Compare with previous state
 | 
			
		||||
			
 | 
			
		||||
			if( !(ETH_link_ok()) && (netif->flags & NETIF_FLAG_LINK_UP) ) {
 | 
			
		||||
				/* tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1); */
 | 
			
		||||
				netif_set_link_down(netif);
 | 
			
		||||
				LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING|LWIP_DBG_ON, ("Link Down\r\n"));	
 | 
			
		||||
			}else if ( ETH_link_ok() && !(netif->flags & NETIF_FLAG_LINK_UP) ) { 
 | 
			
		||||
				/* tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1); */
 | 
			
		||||
				netif_set_link_up(netif);
 | 
			
		||||
				LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING|LWIP_DBG_ON, ("Link Up\r\n"));
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
    osDelay(200);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ack_emac_rx_isr()
 | 
			
		||||
{
 | 
			
		||||
  sys_sem_signal(&RxReadySem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __packet_rx_task(void *data) {
 | 
			
		||||
 | 
			
		||||
  while (1) {
 | 
			
		||||
    /* Wait for receive task to wakeup */
 | 
			
		||||
    sys_arch_sem_wait(&RxReadySem, 0);
 | 
			
		||||
	EMAC_RX_Action();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,69 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2013 Nuvoton Technology Corp.
 | 
			
		||||
 *
 | 
			
		||||
 * See file CREDITS for list of people who contributed to this
 | 
			
		||||
 * project.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 | 
			
		||||
 * MA 02111-1307 USA
 | 
			
		||||
 *
 | 
			
		||||
 * Description:  EMAC driver header file
 | 
			
		||||
 */
 | 
			
		||||
#ifndef __ETHERNETIF_H__
 | 
			
		||||
#define __ETHERNETIF_H__
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "lwip/err.h"
 | 
			
		||||
#include "lwip/netif.h"
 | 
			
		||||
 | 
			
		||||
#if defined(__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//extern sys_sem_t tx_sem;
 | 
			
		||||
extern sys_sem_t rx_sem;
 | 
			
		||||
 | 
			
		||||
//err_t ethernetif_init(struct netif *netif);
 | 
			
		||||
//err_t ethernetif_input(struct netif *netif);
 | 
			
		||||
//struct netif *ethernetif_register(void);
 | 
			
		||||
//int ethernetif_poll(void);
 | 
			
		||||
 | 
			
		||||
#if defined(__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef SERVER
 | 
			
		||||
 | 
			
		||||
#define MAC_ADDR0 0x00
 | 
			
		||||
#define MAC_ADDR1 0x00
 | 
			
		||||
#define MAC_ADDR2 0x00
 | 
			
		||||
#define MAC_ADDR3 0x00
 | 
			
		||||
#define MAC_ADDR4 0x00
 | 
			
		||||
#define MAC_ADDR5 0x01
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#define MAC_ADDR0 0x00
 | 
			
		||||
#define MAC_ADDR1 0x00
 | 
			
		||||
#define MAC_ADDR2 0x00
 | 
			
		||||
#define MAC_ADDR3 0x00
 | 
			
		||||
#define MAC_ADDR4 0x00
 | 
			
		||||
//#define MAC_ADDR5 0x02
 | 
			
		||||
#define MAC_ADDR5 0x03
 | 
			
		||||
//#define MAC_ADDR5 0x04
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2017 Nuvoton Technology Corp.
 | 
			
		||||
 * Copyright (c) 2018 Nuvoton Technology Corp.
 | 
			
		||||
 *
 | 
			
		||||
 * See file CREDITS for list of people who contributed to this
 | 
			
		||||
 * project.
 | 
			
		||||
| 
						 | 
				
			
			@ -22,9 +22,8 @@
 | 
			
		|||
 * Description:   M480 MAC driver source file
 | 
			
		||||
 */
 | 
			
		||||
#include "m480_eth.h"
 | 
			
		||||
#include "lwip/opt.h"
 | 
			
		||||
#include "lwip/def.h"
 | 
			
		||||
#include "mbed_toolchain.h"
 | 
			
		||||
#include "numaker_eth_hal.h"
 | 
			
		||||
 | 
			
		||||
#define ETH_TRIGGER_RX()    do{EMAC->RXST = 0;}while(0)
 | 
			
		||||
#define ETH_TRIGGER_TX()    do{EMAC->TXST = 0;}while(0)
 | 
			
		||||
| 
						 | 
				
			
			@ -32,28 +31,19 @@
 | 
			
		|||
#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)
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
#ifdef __ICCARM__
 | 
			
		||||
#pragma data_alignment=4
 | 
			
		||||
struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM];
 | 
			
		||||
struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM];
 | 
			
		||||
#else
 | 
			
		||||
struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
 | 
			
		||||
struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
 | 
			
		||||
#endif
 | 
			
		||||
*/
 | 
			
		||||
MBED_ALIGN(4) struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM];
 | 
			
		||||
MBED_ALIGN(4) struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM];
 | 
			
		||||
 | 
			
		||||
struct eth_descriptor volatile *cur_tx_desc_ptr, *cur_rx_desc_ptr, *fin_tx_desc_ptr;
 | 
			
		||||
 | 
			
		||||
MBED_ALIGN(4) u8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
 | 
			
		||||
MBED_ALIGN(4) u8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
 | 
			
		||||
MBED_ALIGN(4) uint8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
 | 
			
		||||
MBED_ALIGN(4) uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
 | 
			
		||||
 | 
			
		||||
eth_callback_t nu_eth_txrx_cb = NULL;
 | 
			
		||||
void *nu_userData = NULL;
 | 
			
		||||
 | 
			
		||||
extern void ethernetif_input(u16_t len, u8_t *buf, u32_t s, u32_t ns);
 | 
			
		||||
extern void ethernetif_loopback_input(struct pbuf *p);
 | 
			
		||||
extern void ack_emac_rx_isr(void);
 | 
			
		||||
 | 
			
		||||
// PTP source clock is 84MHz (Real chip using PLL). Each tick is 11.90ns
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +52,9 @@ extern void ack_emac_rx_isr(void);
 | 
			
		|||
// 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(u8_t addr, u8_t reg, u16_t val)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void mdio_write(uint8_t addr, uint8_t reg, uint16_t val)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    EMAC->MIIMDAT = val;
 | 
			
		||||
| 
						 | 
				
			
			@ -73,8 +65,7 @@ static void mdio_write(u8_t addr, u8_t reg, u16_t val)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static u16_t mdio_read(u8_t addr, u8_t reg)
 | 
			
		||||
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);
 | 
			
		||||
| 
						 | 
				
			
			@ -82,12 +73,12 @@ static u16_t mdio_read(u8_t addr, u8_t reg)
 | 
			
		|||
    return(EMAC->MIIMDAT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int reset_phy(void)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    u16_t reg;
 | 
			
		||||
    u32_t delayCnt;
 | 
			
		||||
    uint16_t reg;
 | 
			
		||||
    uint32_t delayCnt;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    mdio_write(CONFIG_PHY_ADDR, MII_BMCR, BMCR_RESET);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -99,10 +90,10 @@ static int reset_phy(void)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    if(delayCnt == 0) {
 | 
			
		||||
        LWIP_DEBUGF(LWIP_DBG_LEVEL_SEVERE|LWIP_DBG_ON,("Reset phy failed\n"));
 | 
			
		||||
        NU_DEBUGF(("Reset phy failed\n"));
 | 
			
		||||
        return(-1);
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
    mdio_write(CONFIG_PHY_ADDR, MII_ADVERTISE, ADVERTISE_CSMA |
 | 
			
		||||
               ADVERTISE_10HALF |
 | 
			
		||||
               ADVERTISE_10FULL |
 | 
			
		||||
| 
						 | 
				
			
			@ -120,37 +111,36 @@ static int reset_phy(void)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    if(delayCnt == 0) {
 | 
			
		||||
        LWIP_DEBUGF(LWIP_DBG_LEVEL_SEVERE|LWIP_DBG_ON , ("AN failed. Set to 100 FULL\n"));
 | 
			
		||||
        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) {
 | 
			
		||||
            LWIP_DEBUGF(LWIP_DBG_LEVEL_ALL|LWIP_DBG_ON, ("100 full\n"));
 | 
			
		||||
            NU_DEBUGF(("100 full\n"));
 | 
			
		||||
            EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
 | 
			
		||||
        } else if(reg & ADVERTISE_100HALF) {
 | 
			
		||||
            LWIP_DEBUGF(LWIP_DBG_LEVEL_ALL|LWIP_DBG_ON, ("100 half\n"));
 | 
			
		||||
            NU_DEBUGF(("100 half\n"));
 | 
			
		||||
            EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk;
 | 
			
		||||
        } else if(reg & ADVERTISE_10FULL) {
 | 
			
		||||
            LWIP_DEBUGF(LWIP_DBG_LEVEL_ALL|LWIP_DBG_ON, ("10 full\n"));
 | 
			
		||||
            NU_DEBUGF(("10 full\n"));
 | 
			
		||||
            EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk;
 | 
			
		||||
        } else {
 | 
			
		||||
            LWIP_DEBUGF(LWIP_DBG_LEVEL_ALL|LWIP_DBG_ON, ("10 half\n"));
 | 
			
		||||
            NU_DEBUGF(("10 half\n"));
 | 
			
		||||
            EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	printf("PHY ID 1:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID1));
 | 
			
		||||
	printf("PHY ID 2:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID2));
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    return(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void init_tx_desc(void)
 | 
			
		||||
{
 | 
			
		||||
    u32_t i;
 | 
			
		||||
    uint32_t i;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    cur_tx_desc_ptr = fin_tx_desc_ptr = &tx_desc[0];
 | 
			
		||||
| 
						 | 
				
			
			@ -168,7 +158,7 @@ static void init_tx_desc(void)
 | 
			
		|||
 | 
			
		||||
static void init_rx_desc(void)
 | 
			
		||||
{
 | 
			
		||||
    u32_t i;
 | 
			
		||||
    uint32_t i;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    cur_rx_desc_ptr = &rx_desc[0];
 | 
			
		||||
| 
						 | 
				
			
			@ -183,7 +173,7 @@ static void init_rx_desc(void)
 | 
			
		|||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_mac_addr(u8_t *addr)
 | 
			
		||||
void numaker_set_mac_addr(uint8_t *addr)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    EMAC->CAM0M = (addr[0] << 24) |
 | 
			
		||||
| 
						 | 
				
			
			@ -237,9 +227,11 @@ static void __eth_clk_pin_init()
 | 
			
		|||
 | 
			
		||||
    /* Lock protected registers */
 | 
			
		||||
    SYS_LockReg();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ETH_init(u8_t *mac_addr)
 | 
			
		||||
void numaker_eth_init(uint8_t *mac_addr)
 | 
			
		||||
{
 | 
			
		||||
    
 | 
			
		||||
	// init CLK & pins
 | 
			
		||||
| 
						 | 
				
			
			@ -252,7 +244,7 @@ void ETH_init(u8_t *mac_addr)
 | 
			
		|||
    init_tx_desc();
 | 
			
		||||
    init_rx_desc();
 | 
			
		||||
 | 
			
		||||
    set_mac_addr(mac_addr);  // need to reconfigure hardware address 'cos we just RESET emc...
 | 
			
		||||
    numaker_set_mac_addr(mac_addr);  // need to reconfigure hardware address 'cos we just RESET emc...
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /* Configure the MAC interrupt enable register. */
 | 
			
		||||
| 
						 | 
				
			
			@ -279,6 +271,7 @@ void ETH_init(u8_t *mac_addr)
 | 
			
		|||
                    
 | 
			
		||||
    EMAC_ENABLE_RX();
 | 
			
		||||
    EMAC_ENABLE_TX();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -293,17 +286,18 @@ unsigned int m_status;
 | 
			
		|||
 | 
			
		||||
void EMAC_RX_IRQHandler(void)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//    NU_DEBUGF(("%s ... nu_eth_txrx_cb=0x%x\r\n", __FUNCTION__, nu_eth_txrx_cb));
 | 
			
		||||
    m_status = EMAC->INTSTS & 0xFFFF;
 | 
			
		||||
    EMAC->INTSTS = m_status;
 | 
			
		||||
    if (m_status & EMAC_INTSTS_RXBEIF_Msk) {
 | 
			
		||||
        // Shouldn't goes here, unless descriptor corrupted
 | 
			
		||||
		LWIP_DEBUGF(LWIP_DBG_LEVEL_SERIOUS|LWIP_DBG_ON, ("RX descriptor corrupted \r\n"));
 | 
			
		||||
		NU_DEBUGF(("RX descriptor corrupted \r\n"));
 | 
			
		||||
		//return;
 | 
			
		||||
    }
 | 
			
		||||
	ack_emac_rx_isr();
 | 
			
		||||
	if (nu_eth_txrx_cb != NULL) nu_eth_txrx_cb('R', nu_userData); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
void EMAC_RX_Action(void)
 | 
			
		||||
{
 | 
			
		||||
    unsigned int cur_entry, status;
 | 
			
		||||
| 
						 | 
				
			
			@ -311,7 +305,7 @@ void EMAC_RX_Action(void)
 | 
			
		|||
 | 
			
		||||
        cur_entry = EMAC->CRXDSA;
 | 
			
		||||
 | 
			
		||||
        if ((cur_entry == (u32_t)cur_rx_desc_ptr) && (!(m_status & EMAC_INTSTS_RDUIF_Msk)))  // cur_entry may equal to cur_rx_desc_ptr if RDU occures
 | 
			
		||||
        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
 | 
			
		||||
            break;
 | 
			
		||||
        status = cur_rx_desc_ptr->status1;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -320,7 +314,7 @@ void EMAC_RX_Action(void)
 | 
			
		|||
 | 
			
		||||
        if (status & RXFD_RXGD) {
 | 
			
		||||
			// Lwip will invoke osMutexWait for resource protection, so ethernetif_input can't be called in EMAC_RX_IRQHandler.
 | 
			
		||||
            ethernetif_input(status & 0xFFFF, cur_rx_desc_ptr->buf, cur_rx_desc_ptr->status2, (u32_t)cur_rx_desc_ptr->next);
 | 
			
		||||
            //ethernetif_input(status & 0xFFFF, cur_rx_desc_ptr->buf, cur_rx_desc_ptr->status2, (uint32_t)cur_rx_desc_ptr->next);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -330,8 +324,41 @@ void EMAC_RX_Action(void)
 | 
			
		|||
    } while (1);
 | 
			
		||||
 | 
			
		||||
    ETH_TRIGGER_RX();
 | 
			
		||||
 | 
			
		||||
//	eth_arch_tcpip_thread();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    }
 | 
			
		||||
//    cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC;
 | 
			
		||||
//    cur_rx_desc_ptr = cur_rx_desc_ptr->next;
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -346,14 +373,15 @@ void EMAC_TX_IRQHandler(void)
 | 
			
		|||
 | 
			
		||||
    cur_entry = EMAC->CTXDSA;
 | 
			
		||||
 | 
			
		||||
    while (cur_entry != (u32_t)fin_tx_desc_ptr) {
 | 
			
		||||
    while (cur_entry != (uint32_t)fin_tx_desc_ptr) {
 | 
			
		||||
 | 
			
		||||
        fin_tx_desc_ptr = fin_tx_desc_ptr->next;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    if (nu_eth_txrx_cb != NULL) nu_eth_txrx_cb('T', nu_userData);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u8_t *ETH_get_tx_buf(void)
 | 
			
		||||
uint8_t *numaker_eth_get_tx_buf(void)
 | 
			
		||||
{
 | 
			
		||||
    if(cur_tx_desc_ptr->status1 & OWNERSHIP_EMAC)
 | 
			
		||||
        return(NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -361,7 +389,7 @@ u8_t *ETH_get_tx_buf(void)
 | 
			
		|||
        return(cur_tx_desc_ptr->buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ETH_trigger_tx(u16_t length, struct pbuf *p)
 | 
			
		||||
void numaker_eth_trigger_tx(uint16_t length, void *p)
 | 
			
		||||
{
 | 
			
		||||
    struct eth_descriptor volatile *desc;
 | 
			
		||||
    cur_tx_desc_ptr->status2 = (unsigned int)length;
 | 
			
		||||
| 
						 | 
				
			
			@ -373,7 +401,7 @@ void ETH_trigger_tx(u16_t length, struct pbuf *p)
 | 
			
		|||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ETH_link_ok()
 | 
			
		||||
int numaker_eth_link_ok(void)
 | 
			
		||||
{
 | 
			
		||||
	/* first, a dummy read to latch */
 | 
			
		||||
	mdio_read(CONFIG_PHY_ADDR, MII_BMSR);
 | 
			
		||||
| 
						 | 
				
			
			@ -381,3 +409,63 @@ int ETH_link_ok()
 | 
			
		|||
		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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Override mbed_mac_address of mbed_interface.c to provide ethernet devices with a semi-unique MAC address
 | 
			
		||||
void mbed_mac_address(char *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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Nuvoton Technology Corp.
 | 
			
		||||
 * Copyright (c) 2018 Nuvoton Technology Corp.
 | 
			
		||||
 *
 | 
			
		||||
 * See file CREDITS for list of people who contributed to this
 | 
			
		||||
 * project.
 | 
			
		||||
| 
						 | 
				
			
			@ -21,8 +21,8 @@
 | 
			
		|||
 *
 | 
			
		||||
 * Description:   M480 EMAC driver header file
 | 
			
		||||
 */
 | 
			
		||||
#include "lwip/def.h"
 | 
			
		||||
#include "lwip/pbuf.h"
 | 
			
		||||
 | 
			
		||||
#include "numaker_emac_config.h"
 | 
			
		||||
#include "M480.h"
 | 
			
		||||
#ifndef  _M480_ETH_
 | 
			
		||||
#define  _M480_ETH_
 | 
			
		||||
| 
						 | 
				
			
			@ -87,10 +87,10 @@
 | 
			
		|||
#define ADVERTISE_LPACK         0x4000  /* Ack link partners response  */
 | 
			
		||||
#define ADVERTISE_NPAGE         0x8000  /* Next page bit               */
 | 
			
		||||
 | 
			
		||||
#define RX_DESCRIPTOR_NUM 4 //2    // 4: Max Number of Rx Frame Descriptors
 | 
			
		||||
#define TX_DESCRIPTOR_NUM 4 //2    // 4: Max number of Tx Frame Descriptors
 | 
			
		||||
#define RX_DESCRIPTOR_NUM       NU_RX_RING_LEN//4 //2    // 4: Max Number of Rx Frame Descriptors
 | 
			
		||||
#define TX_DESCRIPTOR_NUM       NU_TX_RING_LEN//4 //2    // 4: Max number of Tx Frame Descriptors
 | 
			
		||||
 | 
			
		||||
#define PACKET_BUFFER_SIZE  1520
 | 
			
		||||
#define PACKET_BUFFER_SIZE      NU_ETH_MAX_FLEN//1520
 | 
			
		||||
 | 
			
		||||
#define CONFIG_PHY_ADDR     1
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -119,15 +119,15 @@
 | 
			
		|||
// Tx/Rx buffer descriptor structure
 | 
			
		||||
struct eth_descriptor;
 | 
			
		||||
struct eth_descriptor {
 | 
			
		||||
    u32_t  status1;
 | 
			
		||||
    u8_t *buf;
 | 
			
		||||
    u32_t  status2;
 | 
			
		||||
    uint32_t  status1;
 | 
			
		||||
    uint8_t *buf;
 | 
			
		||||
    uint32_t  status2;
 | 
			
		||||
    struct eth_descriptor *next;
 | 
			
		||||
#ifdef TIME_STAMPING
 | 
			
		||||
    u32_t backup1;
 | 
			
		||||
    u32_t backup2;
 | 
			
		||||
    u32_t reserved1;
 | 
			
		||||
    u32_t reserved2;
 | 
			
		||||
    uint32_t backup1;
 | 
			
		||||
    uint32_t backup2;
 | 
			
		||||
    uint32_t reserved1;
 | 
			
		||||
    uint32_t reserved2;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -143,8 +143,4 @@ void ETH_setinc(void);
 | 
			
		|||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern void ETH_init(u8_t *mac_addr);
 | 
			
		||||
extern u8_t *ETH_get_tx_buf(void);
 | 
			
		||||
extern void ETH_trigger_tx(u16_t length, struct pbuf *p);
 | 
			
		||||
 | 
			
		||||
#endif  /* _M480_ETH_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2013 Nuvoton Technology Corp.
 | 
			
		||||
 * Copyright (c) 2018 Nuvoton Technology Corp.
 | 
			
		||||
 *
 | 
			
		||||
 * See file CREDITS for list of people who contributed to this
 | 
			
		||||
 * project.
 | 
			
		||||
| 
						 | 
				
			
			@ -23,6 +23,7 @@
 | 
			
		|||
 */
 | 
			
		||||
#include "nuc472_eth.h"
 | 
			
		||||
#include "mbed_toolchain.h"
 | 
			
		||||
#include "numaker_eth_hal.h"
 | 
			
		||||
 | 
			
		||||
#define ETH_TRIGGER_RX()    do{EMAC->RXST = 0;}while(0)
 | 
			
		||||
#define ETH_TRIGGER_TX()    do{EMAC->TXST = 0;}while(0)
 | 
			
		||||
| 
						 | 
				
			
			@ -30,32 +31,19 @@
 | 
			
		|||
#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)
 | 
			
		||||
 | 
			
		||||
#define NU_DEBUGF printf
 | 
			
		||||
    
 | 
			
		||||
/*
 | 
			
		||||
#ifdef __ICCARM__
 | 
			
		||||
#pragma data_alignment=4
 | 
			
		||||
struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM];
 | 
			
		||||
struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM];
 | 
			
		||||
#else
 | 
			
		||||
struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
 | 
			
		||||
struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] __attribute__ ((aligned(4)));
 | 
			
		||||
#endif
 | 
			
		||||
*/
 | 
			
		||||
struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] MBED_ALIGN(4);
 | 
			
		||||
struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] MBED_ALIGN(4);
 | 
			
		||||
 | 
			
		||||
MBED_ALIGN(4) struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM];
 | 
			
		||||
MBED_ALIGN(4) struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM];
 | 
			
		||||
 | 
			
		||||
struct eth_descriptor volatile *cur_tx_desc_ptr, *cur_rx_desc_ptr, *fin_tx_desc_ptr;
 | 
			
		||||
 | 
			
		||||
uint8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE]  MBED_ALIGN(4);
 | 
			
		||||
uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE]  MBED_ALIGN(4);
 | 
			
		||||
MBED_ALIGN(4) uint8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
 | 
			
		||||
MBED_ALIGN(4) uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
 | 
			
		||||
 | 
			
		||||
typedef void (* eth_callback_t) (char, void*);
 | 
			
		||||
eth_callback_t nu_eth_txrx_cb = NULL;
 | 
			
		||||
void *nu_userData = NULL;
 | 
			
		||||
 | 
			
		||||
//extern void ethernetif_input(uint16_t len, uint8_t *buf, uint32_t s, uint32_t ns);
 | 
			
		||||
extern void ack_emac_rx_isr(void);
 | 
			
		||||
 | 
			
		||||
// PTP source clock is 84MHz (Real chip using PLL). Each tick is 11.90ns
 | 
			
		||||
| 
						 | 
				
			
			@ -89,20 +77,20 @@ static int reset_phy(void)
 | 
			
		|||
{
 | 
			
		||||
 | 
			
		||||
    uint16_t reg;
 | 
			
		||||
    uint32_t delay;
 | 
			
		||||
    uint32_t delayCnt;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    mdio_write(CONFIG_PHY_ADDR, MII_BMCR, BMCR_RESET);
 | 
			
		||||
 | 
			
		||||
    delay = 2000;
 | 
			
		||||
    while(delay-- > 0) {
 | 
			
		||||
    delayCnt = 2000;
 | 
			
		||||
    while(delayCnt-- > 0) {
 | 
			
		||||
        if((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0)
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(delay == 0) {
 | 
			
		||||
        NU_DEBUGF("Reset phy failed\n");
 | 
			
		||||
    if(delayCnt == 0) {
 | 
			
		||||
        NU_DEBUGF(("Reset phy failed\n"));
 | 
			
		||||
        return(-1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -115,34 +103,36 @@ static int reset_phy(void)
 | 
			
		|||
    reg = mdio_read(CONFIG_PHY_ADDR, MII_BMCR);
 | 
			
		||||
    mdio_write(CONFIG_PHY_ADDR, MII_BMCR, reg | BMCR_ANRESTART);
 | 
			
		||||
 | 
			
		||||
    delay = 200000;
 | 
			
		||||
    while(delay-- > 0) {
 | 
			
		||||
    delayCnt = 200000;
 | 
			
		||||
    while(delayCnt-- > 0) {
 | 
			
		||||
        if((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
 | 
			
		||||
                == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(delay == 0) {
 | 
			
		||||
        NU_DEBUGF("AN failed. Set to 100 FULL\n");
 | 
			
		||||
    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");
 | 
			
		||||
            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");
 | 
			
		||||
            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");
 | 
			
		||||
            NU_DEBUGF(("10 full\n"));
 | 
			
		||||
            EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk;
 | 
			
		||||
        } else {
 | 
			
		||||
            NU_DEBUGF("10 half\n");
 | 
			
		||||
            NU_DEBUGF(("10 half\n"));
 | 
			
		||||
            EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
	printf("PHY ID 1:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID1));
 | 
			
		||||
	printf("PHY ID 2:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID2));
 | 
			
		||||
 | 
			
		||||
    return(0);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -269,17 +259,18 @@ unsigned int m_status;
 | 
			
		|||
 | 
			
		||||
void EMAC_RX_IRQHandler(void)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//    NU_DEBUGF(("%s ... nu_eth_txrx_cb=0x%x\r\n", __FUNCTION__, nu_eth_txrx_cb));
 | 
			
		||||
    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");
 | 
			
		||||
		NU_DEBUGF(("RX descriptor corrupted \r\n"));
 | 
			
		||||
		//return;
 | 
			
		||||
    }
 | 
			
		||||
	if (nu_eth_txrx_cb != NULL) nu_eth_txrx_cb('R', nu_userData); //ack_emac_rx_isr();
 | 
			
		||||
	if (nu_eth_txrx_cb != NULL) nu_eth_txrx_cb('R', nu_userData); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
void EMAC_RX_Action(void)
 | 
			
		||||
{
 | 
			
		||||
    unsigned int cur_entry, status;
 | 
			
		||||
| 
						 | 
				
			
			@ -308,6 +299,7 @@ void EMAC_RX_Action(void)
 | 
			
		|||
    ETH_TRIGGER_RX();
 | 
			
		||||
//	eth_arch_tcpip_thread();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void numaker_eth_trigger_rx(void)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -327,8 +319,8 @@ int numaker_eth_get_rx_buf(uint16_t *len, uint8_t **buf)
 | 
			
		|||
            return -1;
 | 
			
		||||
 | 
			
		||||
    if (status & RXFD_RXGD) {
 | 
			
		||||
        cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC;
 | 
			
		||||
        cur_rx_desc_ptr = cur_rx_desc_ptr->next;
 | 
			
		||||
        *buf = cur_rx_desc_ptr->buf;
 | 
			
		||||
        *len = status & 0xFFFF;
 | 
			
		||||
    }
 | 
			
		||||
    cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC;
 | 
			
		||||
    cur_rx_desc_ptr = cur_rx_desc_ptr->next;
 | 
			
		||||
| 
						 | 
				
			
			@ -430,5 +422,17 @@ void mbed_mac_address(char *mac)
 | 
			
		|||
    mac[4] = (word0 & 0x0000ff00) >> 8;
 | 
			
		||||
    mac[5] = (word0 & 0x000000ff);
 | 
			
		||||
    
 | 
			
		||||
    printf("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]);
 | 
			
		||||
}
 | 
			
		||||
    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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -142,8 +142,4 @@ void ETH_setinc(void);
 | 
			
		|||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern void numaker_eth_init(uint8_t *mac_addr);
 | 
			
		||||
extern uint8_t *numaker_eth_get_tx_buf(void);
 | 
			
		||||
extern void numaker_eth_trigger_tx(uint16_t length, void *p);
 | 
			
		||||
 | 
			
		||||
#endif  /* _NUC472_ETH_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,10 +34,11 @@
 | 
			
		|||
#include "netsocket/nsapi_types.h"
 | 
			
		||||
#include "mbed_shared_queues.h"
 | 
			
		||||
 | 
			
		||||
#define NU_TRACE
 | 
			
		||||
 | 
			
		||||
#include "numaker_emac_config.h"
 | 
			
		||||
#include "numaker_emac.h"
 | 
			
		||||
 | 
			
		||||
#include "numaker_eth_hal.h"
 | 
			
		||||
 | 
			
		||||
/********************************************************************************
 | 
			
		||||
 * 
 | 
			
		||||
| 
						 | 
				
			
			@ -47,18 +48,7 @@
 | 
			
		|||
#define PHY_UNLINKED_STATE      0
 | 
			
		||||
#define PACKET_BUFFER_SIZE      NU_ETH_MAX_FLEN
 | 
			
		||||
 | 
			
		||||
typedef void (* eth_callback_t) (char, void*);
 | 
			
		||||
extern "C" void numaker_init_eth_hardware(void);
 | 
			
		||||
extern "C" void mbed_mac_address(char *mac);
 | 
			
		||||
extern "C" void numaker_eth_init(uint8_t *mac_addr);
 | 
			
		||||
extern "C" void numaker_eth_trigger_rx(void);
 | 
			
		||||
extern "C" int numaker_eth_get_rx_buf(uint16_t *len, uint8_t **buf);
 | 
			
		||||
extern "C" uint8_t *numaker_eth_get_tx_buf(void);
 | 
			
		||||
extern "C" void numaker_eth_trigger_tx(uint16_t length, void *p);
 | 
			
		||||
extern "C" int numaker_eth_link_ok(void);
 | 
			
		||||
extern "C" void numaker_eth_set_cb(eth_callback_t eth_cb, void *userData);
 | 
			
		||||
extern "C" void numaker_set_mac_addr(uint8_t *addr);
 | 
			
		||||
 | 
			
		||||
extern "C" void numaker_eth_rx_next(void);
 | 
			
		||||
/* \brief Flags for worker thread */
 | 
			
		||||
#define FLAG_TX  1
 | 
			
		||||
#define FLAG_RX  2
 | 
			
		||||
| 
						 | 
				
			
			@ -126,7 +116,7 @@ bool NUMAKER_EMAC::low_level_init_successful()
 | 
			
		|||
    /* Init ETH */
 | 
			
		||||
 | 
			
		||||
    mbed_mac_address((char *)hwaddr);
 | 
			
		||||
 | 
			
		||||
    printf("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", hwaddr[0], hwaddr[1],hwaddr[2],hwaddr[3],hwaddr[4],hwaddr[5]);
 | 
			
		||||
    /* Enable clock & set EMAC configuration         */
 | 
			
		||||
    /* Enable MAC and DMA transmission and reception */
 | 
			
		||||
    numaker_eth_init(hwaddr);
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +137,7 @@ int NUMAKER_EMAC::low_level_input(emac_mem_buf_t **buf)
 | 
			
		|||
    uint32_t payloadoffset = 0;
 | 
			
		||||
 | 
			
		||||
    /* get received frame */
 | 
			
		||||
    if ( !numaker_eth_get_rx_buf(&len, &buffer)) {
 | 
			
		||||
    if ( numaker_eth_get_rx_buf(&len, &buffer) != 0) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -157,19 +147,19 @@ int NUMAKER_EMAC::low_level_input(emac_mem_buf_t **buf)
 | 
			
		|||
        /* Allocate a memory buffer chain from buffer pool */
 | 
			
		||||
        *buf = memory_manager->alloc_pool(len, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    NU_DEBUGF(("%s... length=%d, buf=0x%x\r\n", __FUNCTION__, len, *buf));
 | 
			
		||||
    if (*buf != NULL) {
 | 
			
		||||
        bufferoffset = 0;
 | 
			
		||||
        for (q = *buf; q != NULL; q = memory_manager->get_next(q)) {
 | 
			
		||||
            byteslefttocopy = memory_manager->get_len(q);
 | 
			
		||||
            payloadoffset = 0;
 | 
			
		||||
 | 
			
		||||
            NU_DEBUGF(("offset=[%d], bytes-to-copy[%d]\r\n",bufferoffset,byteslefttocopy));
 | 
			
		||||
            /* Copy data in pbuf */
 | 
			
		||||
            memcpy(static_cast<uint8_t *>(memory_manager->get_ptr(q)) + payloadoffset, static_cast<uint8_t *>(buffer) + bufferoffset, byteslefttocopy);
 | 
			
		||||
            bufferoffset = bufferoffset + byteslefttocopy;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    numaker_eth_rx_next();
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -208,8 +198,10 @@ void NUMAKER_EMAC::packet_rx()
 | 
			
		|||
          break;
 | 
			
		||||
      }
 | 
			
		||||
      if (p) {
 | 
			
		||||
          NU_DEBUGF(("%s ... p=0x%x\r\n",__FUNCTION__,p));
 | 
			
		||||
          emac_link_input_cb(p);
 | 
			
		||||
      }
 | 
			
		||||
//      numaker_eth_rx_next();
 | 
			
		||||
  }
 | 
			
		||||
  numaker_eth_trigger_rx();
 | 
			
		||||
  
 | 
			
		||||
| 
						 | 
				
			
			@ -242,14 +234,14 @@ bool NUMAKER_EMAC::link_out(emac_mem_buf_t *buf)
 | 
			
		|||
 | 
			
		||||
    /* Get exclusive access */
 | 
			
		||||
    TXLockMutex.lock();
 | 
			
		||||
 | 
			
		||||
    NU_DEBUGF(("%s ... buffer=0x%x\r\n",__FUNCTION__, buffer));
 | 
			
		||||
    /* copy frame from buf to driver buffers */
 | 
			
		||||
    for (q = buf; q != NULL; q = memory_manager->get_next(q)) {
 | 
			
		||||
 | 
			
		||||
        /* Get bytes in current lwIP buffer */
 | 
			
		||||
        byteslefttocopy = memory_manager->get_len(q);
 | 
			
		||||
        payloadoffset = 0;
 | 
			
		||||
 | 
			
		||||
        NU_DEBUGF(("offset=%d, bytes-to-copy=%d\r\n",bufferoffset, byteslefttocopy));
 | 
			
		||||
        /* Check if the length of data to copy is bigger than Tx buffer size*/
 | 
			
		||||
        while ((byteslefttocopy + bufferoffset) > PACKET_BUFFER_SIZE) {
 | 
			
		||||
            /* Copy data to Tx buffer*/
 | 
			
		||||
| 
						 | 
				
			
			@ -265,7 +257,7 @@ bool NUMAKER_EMAC::link_out(emac_mem_buf_t *buf)
 | 
			
		|||
            framelength = framelength + (PACKET_BUFFER_SIZE - bufferoffset);
 | 
			
		||||
            bufferoffset = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        /* Copy the remaining bytes */
 | 
			
		||||
        memcpy(static_cast<uint8_t *>(buffer) + bufferoffset, static_cast<uint8_t *>(memory_manager->get_ptr(q)) + payloadoffset, byteslefttocopy);
 | 
			
		||||
        bufferoffset = bufferoffset + byteslefttocopy;
 | 
			
		||||
| 
						 | 
				
			
			@ -297,10 +289,10 @@ void NUMAKER_EMAC::phy_task()
 | 
			
		|||
 | 
			
		||||
    
 | 
			
		||||
    if ((state & PHY_LINKED_STATE) && !(phy_state & PHY_LINKED_STATE)) {
 | 
			
		||||
        printf("Link Up\r\n");
 | 
			
		||||
        NU_DEBUGF(("Link Up\r\n"));
 | 
			
		||||
        if (emac_link_state_cb) emac_link_state_cb(true);
 | 
			
		||||
    } else if (!(state & PHY_LINKED_STATE) && (phy_state & PHY_LINKED_STATE)) {
 | 
			
		||||
        printf("Link Down\r\n");
 | 
			
		||||
        NU_DEBUGF(("Link Down\r\n"));
 | 
			
		||||
        if (emac_link_state_cb) emac_link_state_cb(false);
 | 
			
		||||
    }
 | 
			
		||||
    phy_state = state;        
 | 
			
		||||
| 
						 | 
				
			
			@ -323,7 +315,7 @@ bool NUMAKER_EMAC::power_up()
 | 
			
		|||
 | 
			
		||||
  /* Allow the PHY task to detect the initial link state and set up the proper flags */
 | 
			
		||||
  osDelay(10);
 | 
			
		||||
 | 
			
		||||
  numaker_eth_enable_interrupts();
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,60 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2018 Nuvoton Technology Corp.
 | 
			
		||||
 *
 | 
			
		||||
 * See file CREDITS for list of people who contributed to this
 | 
			
		||||
 * project.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 | 
			
		||||
 * MA 02111-1307 USA
 | 
			
		||||
 *
 | 
			
		||||
 * Description:   NUC472 EMAC driver header file
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef  NUMAKER_ETH_HAL_
 | 
			
		||||
#define  NUMAKER_ETH_HAL_
 | 
			
		||||
 
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#ifdef NU_TRACE
 | 
			
		||||
#define NU_DEBUGF(x) { printf x; }
 | 
			
		||||
#else
 | 
			
		||||
#define NU_DEBUGF(x)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef void (* eth_callback_t) (char, void*);
 | 
			
		||||
void mbed_mac_address(char *mac);
 | 
			
		||||
void numaker_eth_init(uint8_t *mac_addr);
 | 
			
		||||
void numaker_eth_trigger_rx(void);
 | 
			
		||||
int numaker_eth_get_rx_buf(uint16_t *len, uint8_t **buf);
 | 
			
		||||
uint8_t *numaker_eth_get_tx_buf(void);
 | 
			
		||||
void numaker_eth_trigger_tx(uint16_t length, void *p);
 | 
			
		||||
int numaker_eth_link_ok(void);
 | 
			
		||||
void numaker_eth_set_cb(eth_callback_t eth_cb, void *userData);
 | 
			
		||||
void numaker_set_mac_addr(uint8_t *addr);
 | 
			
		||||
void numaker_eth_enable_interrupts(void);
 | 
			
		||||
void numaker_eth_disable_interrupts(void);       
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* NUMAKER_ETH_HAL_ */
 | 
			
		||||
		Loading…
	
		Reference in New Issue