diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc17_emac.c b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc17_emac.c deleted file mode 100644 index c79083c943..0000000000 --- a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc17_emac.c +++ /dev/null @@ -1,1076 +0,0 @@ -/********************************************************************** -* $Id$ lpc17_emac.c 2011-11-20 -*//** -* @file lpc17_emac.c -* @brief LPC17 ethernet driver for LWIP -* @version 1.0 -* @date 20. Nov. 2011 -* @author NXP MCU SW Application Team -* -* Copyright(C) 2011, NXP Semiconductor -* All rights reserved. -* -*********************************************************************** -* Software that is described herein is for illustrative purposes only -* which provides customers with programming information regarding the -* products. This software is supplied "AS IS" without any warranties. -* NXP Semiconductors assumes no responsibility or liability for the -* use of the software, conveys no license or title under any patent, -* copyright, or mask work right to the product. NXP Semiconductors -* reserves the right to make changes in the software without -* notification. NXP Semiconductors also make no representation or -* warranty that such application will be suitable for the specified -* use without further testing or modification. -**********************************************************************/ - -#include "lwip/opt.h" -#include "lwip/sys.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/pbuf.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "netif/etharp.h" -#include "lwip/ethip6.h" -#include "netif/ppp/pppoe.h" - -#include "lpc17xx_emac.h" -#include "eth_arch.h" -#include "lpc_emac_config.h" -#include "lpc_phy.h" -#include "sys_arch.h" - -#include "mbed_interface.h" -#include - -#if LWIP_ARP || LWIP_ETHERNET - -#ifndef LPC_EMAC_RMII -#error LPC_EMAC_RMII is not defined! -#endif - -#if LPC_NUM_BUFF_TXDESCS < 2 -#error LPC_NUM_BUFF_TXDESCS must be at least 2 -#endif - -#if LPC_NUM_BUFF_RXDESCS < 3 -#error LPC_NUM_BUFF_RXDESCS must be at least 3 -#endif - -/** @defgroup lwip17xx_emac_DRIVER lpc17 EMAC driver for LWIP - * @ingroup lwip_emac - * - * @{ - */ - -#if defined(TARGET_LPC1768) || defined(TARGET_LPC1769) -/** \brief Group LPC17xx processors into one definition - */ -#define TARGET_LPC17XX -#endif - -#if NO_SYS == 0 -/** \brief Driver transmit and receive thread priorities - * - * Thread priorities for receive thread and TX cleanup thread. Alter - * to prioritize receive or transmit bandwidth. In a heavily loaded - * system or with LEIP_DEBUG enabled, the priorities might be better - * the same. */ -#define RX_PRIORITY (osPriorityNormal) -#define TX_PRIORITY (osPriorityNormal) -#define PHY_PRIORITY (osPriorityNormal) - -/** \brief Debug output formatter lock define - * - * When using FreeRTOS and with LWIP_DEBUG enabled, enabling this - * define will allow RX debug messages to not interleave with the - * TX messages (so they are actually readable). Not enabling this - * define when the system is under load will cause the output to - * be unreadable. There is a small tradeoff in performance for this - * so use it only for debug. */ -//#define LOCK_RX_THREAD - -/** \brief Receive group interrupts - */ -#define RXINTGROUP (EMAC_INT_RX_OVERRUN | EMAC_INT_RX_ERR | EMAC_INT_RX_DONE) - -/** \brief Transmit group interrupts - */ -#define TXINTGROUP (EMAC_INT_TX_UNDERRUN | EMAC_INT_TX_ERR | EMAC_INT_TX_DONE) - -/** \brief Signal used for ethernet ISR to signal packet_rx() thread. - */ -#define RX_SIGNAL 1 - -#else -#define RXINTGROUP 0 -#define TXINTGROUP 0 -#endif - - /** \brief Structure of a TX/RX descriptor - */ -typedef struct -{ - volatile u32_t packet; /**< Pointer to buffer */ - volatile u32_t control; /**< Control word */ -} LPC_TXRX_DESC_T; - -/** \brief Structure of a RX status entry - */ -typedef struct -{ - volatile u32_t statusinfo; /**< RX status word */ - volatile u32_t statushashcrc; /**< RX hash CRC */ -} LPC_TXRX_STATUS_T; - -/* LPC EMAC driver data structure */ -struct lpc_enetdata { - /* prxs must be 8 byte aligned! */ - LPC_TXRX_STATUS_T prxs[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX statuses */ - struct netif *netif; /**< Reference back to LWIP parent netif */ - LPC_TXRX_DESC_T ptxd[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX descriptor list */ - LPC_TXRX_STATUS_T ptxs[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX statuses */ - LPC_TXRX_DESC_T prxd[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX descriptor list */ - struct pbuf *rxb[LPC_NUM_BUFF_RXDESCS]; /**< RX pbuf pointer list, zero-copy mode */ - u32_t rx_fill_desc_index; /**< RX descriptor next available index */ - volatile u32_t rx_free_descs; /**< Count of free RX descriptors */ - struct pbuf *txb[LPC_NUM_BUFF_TXDESCS]; /**< TX pbuf pointer list, zero-copy mode */ - u32_t lpc_last_tx_idx; /**< TX last descriptor index, zero-copy mode */ -#if NO_SYS == 0 - sys_thread_t RxThread; /**< RX receive thread data object pointer */ - sys_sem_t TxCleanSem; /**< TX cleanup thread wakeup semaphore */ - sys_mutex_t TXLockMutex; /**< TX critical section mutex */ - sys_sem_t xTXDCountSem; /**< TX free buffer counting semaphore */ -#endif -}; - -#if defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) -# if defined (__ICCARM__) -# define ETHMEM_SECTION -# elif defined(TOOLCHAIN_GCC_CR) -# define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32"), aligned)) -# else -# define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned)) -# endif -#elif defined(TARGET_LPC17XX) -# if defined(TOOLCHAIN_GCC_ARM) || defined(TOOLCHAIN_ARM) -# define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned)) -# endif -#endif - -#ifndef ETHMEM_SECTION -#define ETHMEM_SECTION ALIGNED(8) -#endif - -/** \brief LPC EMAC driver work data - */ -ETHMEM_SECTION struct lpc_enetdata lpc_enetdata; - -/** \brief Queues a pbuf into the RX descriptor list - * - * \param[in] lpc_enetif Pointer to the drvier data structure - * \param[in] p Pointer to pbuf to queue - */ -static void lpc_rxqueue_pbuf(struct lpc_enetdata *lpc_enetif, struct pbuf *p) -{ - u32_t idx; - - /* Get next free descriptor index */ - idx = lpc_enetif->rx_fill_desc_index; - - /* Setup descriptor and clear statuses */ - lpc_enetif->prxd[idx].control = EMAC_RCTRL_INT | ((u32_t) (p->len - 1)); - lpc_enetif->prxd[idx].packet = (u32_t) p->payload; - lpc_enetif->prxs[idx].statusinfo = 0xFFFFFFFF; - lpc_enetif->prxs[idx].statushashcrc = 0xFFFFFFFF; - - /* Save pbuf pointer for push to network layer later */ - lpc_enetif->rxb[idx] = p; - - /* Wrap at end of descriptor list */ - idx++; - if (idx >= LPC_NUM_BUFF_RXDESCS) - idx = 0; - - /* Queue descriptor(s) */ - lpc_enetif->rx_free_descs -= 1; - lpc_enetif->rx_fill_desc_index = idx; - LPC_EMAC->RxConsumeIndex = idx; - - LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, - ("lpc_rxqueue_pbuf: pbuf packet queued: %p (free desc=%"U32_F")\n", p, - lpc_enetif->rx_free_descs)); -} - -/** \brief Attempt to allocate and requeue a new pbuf for RX - * - * \param[in] netif Pointer to the netif structure - * \returns 1 if a packet was allocated and requeued, otherwise 0 - */ -s32_t lpc_rx_queue(struct netif *netif) -{ - struct lpc_enetdata *lpc_enetif = netif->state; - struct pbuf *p; - s32_t queued = 0; - - /* Attempt to requeue as many packets as possible */ - while (lpc_enetif->rx_free_descs > 0) { - /* Allocate a pbuf from the pool. We need to allocate at the - maximum size as we don't know the size of the yet to be - received packet. */ - p = pbuf_alloc(PBUF_RAW, (u16_t) EMAC_ETH_MAX_FLEN, PBUF_RAM); - if (p == NULL) { - LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, - ("lpc_rx_queue: could not allocate RX pbuf (free desc=%"U32_F")\n", - lpc_enetif->rx_free_descs)); - return queued; - } - - /* pbufs allocated from the RAM pool should be non-chained. */ - LWIP_ASSERT("lpc_rx_queue: pbuf is not contiguous (chained)", - pbuf_clen(p) <= 1); - - /* Queue packet */ - lpc_rxqueue_pbuf(lpc_enetif, p); - - /* Update queued count */ - queued++; - } - - return queued; -} - -/** \brief Sets up the RX descriptor ring buffers. - * - * This function sets up the descriptor list used for receive packets. - * - * \param[in] lpc_enetif Pointer to driver data structure - * \returns Always returns ERR_OK - */ -static err_t lpc_rx_setup(struct lpc_enetdata *lpc_enetif) -{ - /* Setup pointers to RX structures */ - LPC_EMAC->RxDescriptor = (u32_t) &lpc_enetif->prxd[0]; - LPC_EMAC->RxStatus = (u32_t) &lpc_enetif->prxs[0]; - LPC_EMAC->RxDescriptorNumber = LPC_NUM_BUFF_RXDESCS - 1; - - lpc_enetif->rx_free_descs = LPC_NUM_BUFF_RXDESCS; - lpc_enetif->rx_fill_desc_index = 0; - - /* Build RX buffer and descriptors */ - lpc_rx_queue(lpc_enetif->netif); - - return ERR_OK; -} - -/** \brief Allocates a pbuf and returns the data from the incoming packet. - * - * \param[in] netif the lwip network interface structure for this lpc_enetif - * \return a pbuf filled with the received packet (including MAC header) - * NULL on memory error - */ -static struct pbuf *lpc_low_level_input(struct netif *netif) -{ - struct lpc_enetdata *lpc_enetif = netif->state; - struct pbuf *p = NULL; - u32_t idx, length; - u16_t origLength; - -#ifdef LOCK_RX_THREAD -#if NO_SYS == 0 - /* Get exclusive access */ - sys_mutex_lock(&lpc_enetif->TXLockMutex); -#endif -#endif - - /* Monitor RX overrun status. This should never happen unless - (possibly) the internal bus is behing held up by something. - Unless your system is running at a very low clock speed or - there are possibilities that the internal buses may be held - up for a long time, this can probably safely be removed. */ - if (LPC_EMAC->IntStatus & EMAC_INT_RX_OVERRUN) { - LINK_STATS_INC(link.err); - LINK_STATS_INC(link.drop); - - /* Temporarily disable RX */ - LPC_EMAC->MAC1 &= ~EMAC_MAC1_REC_EN; - - /* Reset the RX side */ - LPC_EMAC->MAC1 |= EMAC_MAC1_RES_RX; - LPC_EMAC->IntClear = EMAC_INT_RX_OVERRUN; - - /* De-allocate all queued RX pbufs */ - for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) { - if (lpc_enetif->rxb[idx] != NULL) { - pbuf_free(lpc_enetif->rxb[idx]); - lpc_enetif->rxb[idx] = NULL; - } - } - - /* Start RX side again */ - lpc_rx_setup(lpc_enetif); - - /* Re-enable RX */ - LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN; - -#ifdef LOCK_RX_THREAD -#if NO_SYS == 0 - sys_mutex_unlock(&lpc_enetif->TXLockMutex); -#endif -#endif - - return NULL; - } - - /* Determine if a frame has been received */ - length = 0; - idx = LPC_EMAC->RxConsumeIndex; - if (LPC_EMAC->RxProduceIndex != idx) { - /* Handle errors */ - if (lpc_enetif->prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR | - EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR | EMAC_RINFO_LEN_ERR)) { -#if LINK_STATS - if (lpc_enetif->prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR | - EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR)) - LINK_STATS_INC(link.chkerr); - if (lpc_enetif->prxs[idx].statusinfo & EMAC_RINFO_LEN_ERR) - LINK_STATS_INC(link.lenerr); -#endif - - /* Drop the frame */ - LINK_STATS_INC(link.drop); - - /* Re-queue the pbuf for receive */ - lpc_enetif->rx_free_descs++; - p = lpc_enetif->rxb[idx]; - lpc_enetif->rxb[idx] = NULL; - lpc_rxqueue_pbuf(lpc_enetif, p); - - LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, - ("lpc_low_level_input: Packet dropped with errors (%"X32_F")\n", - lpc_enetif->prxs[idx].statusinfo)); - - p = NULL; - } else { - /* A packet is waiting, get length */ - length = (lpc_enetif->prxs[idx].statusinfo & 0x7FF) + 1; - - /* Zero-copy */ - p = lpc_enetif->rxb[idx]; - origLength = p->len; - p->len = (u16_t) length; - - /* Free pbuf from descriptor */ - lpc_enetif->rxb[idx] = NULL; - lpc_enetif->rx_free_descs++; - - /* Attempt to queue new buffer(s) */ - if (lpc_rx_queue(lpc_enetif->netif) == 0) { - /* Drop the frame due to OOM. */ - LINK_STATS_INC(link.drop); - - /* Re-queue the pbuf for receive */ - p->len = origLength; - lpc_rxqueue_pbuf(lpc_enetif, p); - - LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, - ("lpc_low_level_input: Packet index %"U32_F" dropped for OOM\n", - idx)); - -#ifdef LOCK_RX_THREAD -#if NO_SYS == 0 - sys_mutex_unlock(&lpc_enetif->TXLockMutex); -#endif -#endif - - return NULL; - } - - LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, - ("lpc_low_level_input: Packet received: %p, size %"U32_F" (index=%"U32_F")\n", - p, length, idx)); - - /* Save size */ - p->tot_len = (u16_t) length; - LINK_STATS_INC(link.recv); - } - } - -#ifdef LOCK_RX_THREAD -#if NO_SYS == 0 - sys_mutex_unlock(&lpc_enetif->TXLockMutex); -#endif -#endif - - return p; -} - -/** \brief Attempt to read a packet from the EMAC interface. - * - * \param[in] netif the lwip network interface structure for this lpc_enetif - */ -void lpc_enetif_input(struct netif *netif) -{ - struct pbuf *p; - - /* move received packet into a new pbuf */ - p = lpc_low_level_input(netif); - if (p == NULL) - return; - - /* full packet send to tcpip_thread to process */ - if (netif->input(p, netif) != ERR_OK) { - LWIP_DEBUGF(NETIF_DEBUG, ("lpc_enetif_input: IP input error\n")); - /* Free buffer */ - pbuf_free(p); - } -} - -/** \brief Determine if the passed address is usable for the ethernet - * DMA controller. - * - * \param[in] addr Address of packet to check for DMA safe operation - * \return 1 if the packet address is not safe, otherwise 0 - */ -static s32_t lpc_packet_addr_notsafe(void *addr) { - /* Check for legal address ranges */ -#if defined(TARGET_LPC17XX) - if ((((u32_t) addr >= 0x2007C000) && ((u32_t) addr < 0x20083FFF))) { -#elif defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) - if ((((u32_t) addr >= 0x20000000) && ((u32_t) addr < 0x20007FFF))) { -#endif - return 0; - } - return 1; -} - -/** \brief Sets up the TX descriptor ring buffers. - * - * This function sets up the descriptor list used for transmit packets. - * - * \param[in] lpc_enetif Pointer to driver data structure - */ -static err_t lpc_tx_setup(struct lpc_enetdata *lpc_enetif) -{ - s32_t idx; - - /* Build TX descriptors for local buffers */ - for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) { - lpc_enetif->ptxd[idx].control = 0; - lpc_enetif->ptxs[idx].statusinfo = 0xFFFFFFFF; - } - - /* Setup pointers to TX structures */ - LPC_EMAC->TxDescriptor = (u32_t) &lpc_enetif->ptxd[0]; - LPC_EMAC->TxStatus = (u32_t) &lpc_enetif->ptxs[0]; - LPC_EMAC->TxDescriptorNumber = LPC_NUM_BUFF_TXDESCS - 1; - - lpc_enetif->lpc_last_tx_idx = 0; - - return ERR_OK; -} - -/** \brief Free TX buffers that are complete - * - * \param[in] lpc_enetif Pointer to driver data structure - * \param[in] cidx EMAC current descriptor comsumer index - */ -static void lpc_tx_reclaim_st(struct lpc_enetdata *lpc_enetif, u32_t cidx) -{ -#if NO_SYS == 0 - /* Get exclusive access */ - sys_mutex_lock(&lpc_enetif->TXLockMutex); -#endif - - while (cidx != lpc_enetif->lpc_last_tx_idx) { - if (lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] != NULL) { - LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, - ("lpc_tx_reclaim_st: Freeing packet %p (index %"U32_F")\n", - lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx], - lpc_enetif->lpc_last_tx_idx)); - pbuf_free(lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx]); - lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] = NULL; - } - -#if NO_SYS == 0 - osSemaphoreRelease(lpc_enetif->xTXDCountSem.id); -#endif - lpc_enetif->lpc_last_tx_idx++; - if (lpc_enetif->lpc_last_tx_idx >= LPC_NUM_BUFF_TXDESCS) - lpc_enetif->lpc_last_tx_idx = 0; - } - -#if NO_SYS == 0 - /* Restore access */ - sys_mutex_unlock(&lpc_enetif->TXLockMutex); -#endif -} - -/** \brief User call for freeingTX buffers that are complete - * - * \param[in] netif the lwip network interface structure for this lpc_enetif - */ -void lpc_tx_reclaim(struct netif *netif) -{ - lpc_tx_reclaim_st((struct lpc_enetdata *) netif->state, - LPC_EMAC->TxConsumeIndex); -} - - /** \brief Polls if an available TX descriptor is ready. Can be used to - * determine if the low level transmit function will block. - * - * \param[in] netif the lwip network interface structure for this lpc_enetif - * \return 0 if no descriptors are read, or >0 - */ -s32_t lpc_tx_ready(struct netif *netif) -{ - s32_t fb; - u32_t idx, cidx; - - cidx = LPC_EMAC->TxConsumeIndex; - idx = LPC_EMAC->TxProduceIndex; - - /* Determine number of free buffers */ - if (idx == cidx) - fb = LPC_NUM_BUFF_TXDESCS; - else if (cidx > idx) - fb = (LPC_NUM_BUFF_TXDESCS - 1) - - ((idx + LPC_NUM_BUFF_TXDESCS) - cidx); - else - fb = (LPC_NUM_BUFF_TXDESCS - 1) - (cidx - idx); - - return fb; -} - -/** \brief Low level output of a packet. Never call this from an - * interrupt context, as it may block until TX descriptors - * become available. - * - * \param[in] netif the lwip network interface structure for this lpc_enetif - * \param[in] p the MAC packet to send (e.g. IP packet including MAC addresses and type) - * \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent - */ -static err_t lpc_low_level_output(struct netif *netif, struct pbuf *p) -{ - struct lpc_enetdata *lpc_enetif = netif->state; - struct pbuf *q; - u8_t *dst; - u32_t idx, notdmasafe = 0; - struct pbuf *np; - s32_t dn; - - /* Zero-copy TX buffers may be fragmented across mutliple payload - chains. Determine the number of descriptors needed for the - transfer. The pbuf chaining can be a mess! */ - dn = (s32_t) pbuf_clen(p); - - /* Test to make sure packet addresses are DMA safe. A DMA safe - address is once that uses external memory or periphheral RAM. - IRAM and FLASH are not safe! */ - for (q = p; q != NULL; q = q->next) - notdmasafe += lpc_packet_addr_notsafe(q->payload); - -#if LPC_TX_PBUF_BOUNCE_EN==1 - /* If the pbuf is not DMA safe, a new bounce buffer (pbuf) will be - created that will be used instead. This requires an copy from the - non-safe DMA region to the new pbuf */ - if (notdmasafe) { - /* Allocate a pbuf in DMA memory */ - np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); - if (np == NULL) - return ERR_MEM; - - /* This buffer better be contiguous! */ - LWIP_ASSERT("lpc_low_level_output: New transmit pbuf is chained", - (pbuf_clen(np) == 1)); - - /* Copy to DMA safe pbuf */ - dst = (u8_t *) np->payload; - for(q = p; q != NULL; q = q->next) { - /* Copy the buffer to the descriptor's buffer */ - MEMCPY(dst, (u8_t *) q->payload, q->len); - dst += q->len; - } - np->len = p->tot_len; - - LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, - ("lpc_low_level_output: Switched to DMA safe buffer, old=%p, new=%p\n", - q, np)); - - /* use the new buffer for descrptor queueing. The original pbuf will - be de-allocated outsuide this driver. */ - p = np; - dn = 1; - } -#else - if (notdmasafe) - LWIP_ASSERT("lpc_low_level_output: Not a DMA safe pbuf", - (notdmasafe == 0)); -#endif - - /* Wait until enough descriptors are available for the transfer. */ - /* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */ -#if NO_SYS == 0 - for (s32_t count = 0; count < dn; count++) { - osSemaphoreAcquire(lpc_enetif->xTXDCountSem.id, osWaitForever); - } - MBED_ASSERT(dn <= lpc_tx_ready(netif)); -#else - while (dn > lpc_tx_ready(netif)) - osDelay(1); -#endif - - /* Get free TX buffer index */ - idx = LPC_EMAC->TxProduceIndex; - -#if NO_SYS == 0 - /* Get exclusive access */ - sys_mutex_lock(&lpc_enetif->TXLockMutex); -#endif - - /* Prevent LWIP from de-allocating this pbuf. The driver will - free it once it's been transmitted. */ - if (!notdmasafe) - pbuf_ref(p); - - /* Setup transfers */ - q = p; - while (dn > 0) { - dn--; - - /* Only save pointer to free on last descriptor */ - if (dn == 0) { - /* Save size of packet and signal it's ready */ - lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT | - EMAC_TCTRL_LAST; - lpc_enetif->txb[idx] = p; - } - else { - /* Save size of packet, descriptor is not last */ - lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT; - lpc_enetif->txb[idx] = NULL; - } - - LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, - ("lpc_low_level_output: pbuf packet(%p) sent, chain#=%"S32_F"," - " size = %d (index=%"U32_F")\n", q->payload, dn, q->len, idx)); - - lpc_enetif->ptxd[idx].packet = (u32_t) q->payload; - - q = q->next; - - idx++; - if (idx >= LPC_NUM_BUFF_TXDESCS) - idx = 0; - } - - LPC_EMAC->TxProduceIndex = idx; - - LINK_STATS_INC(link.xmit); - -#if NO_SYS == 0 - /* Restore access */ - sys_mutex_unlock(&lpc_enetif->TXLockMutex); -#endif - - return ERR_OK; -} - -/** \brief LPC EMAC interrupt handler. - * - * This function handles the transmit, receive, and error interrupt of - * the LPC177x_8x. This is meant to be used when NO_SYS=0. - */ -void LPC17xxEthernetHandler(void) -{ -#if NO_SYS == 1 - /* Interrupts are not used without an RTOS */ - NVIC_DisableIRQ(ENET_IRQn); -#else - uint32_t ints; - - /* Interrupts are of 2 groups - transmit or receive. Based on the - interrupt, kick off the receive or transmit (cleanup) task */ - - /* Get pending interrupts */ - ints = LPC_EMAC->IntStatus; - - if (ints & RXINTGROUP) { - /* RX group interrupt(s): Give signal to wakeup RX receive task.*/ - osThreadFlagsSet(lpc_enetdata.RxThread->id, RX_SIGNAL); - } - - if (ints & TXINTGROUP) { - /* TX group interrupt(s): Give semaphore to wakeup TX cleanup task. */ - sys_sem_signal(&lpc_enetdata.TxCleanSem); - } - - /* Clear pending interrupts */ - LPC_EMAC->IntClear = ints; -#endif -} - -#if NO_SYS == 0 -/** \brief Packet reception task - * - * This task is called when a packet is received. It will - * pass the packet to the LWIP core. - * - * \param[in] pvParameters Not used yet - */ -static void packet_rx(void* pvParameters) { - struct lpc_enetdata *lpc_enetif = pvParameters; - - while (1) { - /* Wait for receive task to wakeup */ - osThreadFlagsWait(RX_SIGNAL, 0, osWaitForever); - - /* Process packets until all empty */ - while (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex) - lpc_enetif_input(lpc_enetif->netif); - } -} - -/** \brief Transmit cleanup task - * - * This task is called when a transmit interrupt occurs and - * reclaims the pbuf and descriptor used for the packet once - * the packet has been transferred. - * - * \param[in] pvParameters Not used yet - */ -static void packet_tx(void* pvParameters) { - struct lpc_enetdata *lpc_enetif = pvParameters; - s32_t idx; - - while (1) { - /* Wait for transmit cleanup task to wakeup */ - sys_arch_sem_wait(&lpc_enetif->TxCleanSem, 0); - - /* Error handling for TX underruns. This should never happen unless - something is holding the bus or the clocks are going too slow. It - can probably be safely removed. */ - if (LPC_EMAC->IntStatus & EMAC_INT_TX_UNDERRUN) { - LINK_STATS_INC(link.err); - LINK_STATS_INC(link.drop); - -#if NO_SYS == 0 - /* Get exclusive access */ - sys_mutex_lock(&lpc_enetif->TXLockMutex); -#endif - /* Reset the TX side */ - LPC_EMAC->MAC1 |= EMAC_MAC1_RES_TX; - LPC_EMAC->IntClear = EMAC_INT_TX_UNDERRUN; - - /* De-allocate all queued TX pbufs */ - for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) { - if (lpc_enetif->txb[idx] != NULL) { - pbuf_free(lpc_enetif->txb[idx]); - lpc_enetif->txb[idx] = NULL; - } - } - -#if NO_SYS == 0 - /* Restore access */ - sys_mutex_unlock(&lpc_enetif->TXLockMutex); -#endif - /* Start TX side again */ - lpc_tx_setup(lpc_enetif); - } else { - /* Free TX buffers that are done sending */ - lpc_tx_reclaim(lpc_enetdata.netif); - } - } -} -#endif - -/** \brief Low level init of the MAC and PHY. - * - * \param[in] netif Pointer to LWIP netif structure - */ -static err_t low_level_init(struct netif *netif) -{ - struct lpc_enetdata *lpc_enetif = netif->state; - err_t err = ERR_OK; - - /* Enable MII clocking */ - LPC_SC->PCONP |= CLKPWR_PCONP_PCENET; - -#if defined(TARGET_LPC17XX) - LPC_PINCON->PINSEL2 = 0x50150105; /* Enable P1 Ethernet Pins. */ - LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005; -#elif defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) - LPC_IOCON->P1_0 &= ~0x07; /* ENET I/O config */ - LPC_IOCON->P1_0 |= 0x01; /* ENET_TXD0 */ - LPC_IOCON->P1_1 &= ~0x07; - LPC_IOCON->P1_1 |= 0x01; /* ENET_TXD1 */ - LPC_IOCON->P1_4 &= ~0x07; - LPC_IOCON->P1_4 |= 0x01; /* ENET_TXEN */ - LPC_IOCON->P1_8 &= ~0x07; - LPC_IOCON->P1_8 |= 0x01; /* ENET_CRS */ - LPC_IOCON->P1_9 &= ~0x07; - LPC_IOCON->P1_9 |= 0x01; /* ENET_RXD0 */ - LPC_IOCON->P1_10 &= ~0x07; - LPC_IOCON->P1_10 |= 0x01; /* ENET_RXD1 */ - LPC_IOCON->P1_14 &= ~0x07; - LPC_IOCON->P1_14 |= 0x01; /* ENET_RX_ER */ - LPC_IOCON->P1_15 &= ~0x07; - LPC_IOCON->P1_15 |= 0x01; /* ENET_REF_CLK */ - LPC_IOCON->P1_16 &= ~0x07; /* ENET/PHY I/O config */ - LPC_IOCON->P1_16 |= 0x01; /* ENET_MDC */ - LPC_IOCON->P1_17 &= ~0x07; - LPC_IOCON->P1_17 |= 0x01; /* ENET_MDIO */ -#endif - - /* Reset all MAC logic */ - LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | - EMAC_MAC1_RES_RX | EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | - EMAC_MAC1_SOFT_RES; - LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES | - EMAC_CR_PASS_RUNT_FRM; - osDelay(10); - - /* Initial MAC initialization */ - LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL; - LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN | - EMAC_MAC2_VLAN_PAD_EN; - LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN; - - /* Set RMII management clock rate to lowest speed */ - LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(11) | EMAC_MCFG_RES_MII; - LPC_EMAC->MCFG &= ~EMAC_MCFG_RES_MII; - - /* Maximum number of retries, 0x37 collision window, gap */ - LPC_EMAC->CLRT = EMAC_CLRT_DEF; - LPC_EMAC->IPGR = EMAC_IPGR_P1_DEF | EMAC_IPGR_P2_DEF; - -#if LPC_EMAC_RMII - /* RMII setup */ - LPC_EMAC->Command = EMAC_CR_PASS_RUNT_FRM | EMAC_CR_RMII; -#else - /* MII setup */ - LPC_EMAC->CR = EMAC_CR_PASS_RUNT_FRM; -#endif - - /* Initialize the PHY and reset */ - err = lpc_phy_init(netif, LPC_EMAC_RMII); - if (err != ERR_OK) - return err; - - /* Save station address */ - LPC_EMAC->SA2 = (u32_t) netif->hwaddr[0] | - (((u32_t) netif->hwaddr[1]) << 8); - LPC_EMAC->SA1 = (u32_t) netif->hwaddr[2] | - (((u32_t) netif->hwaddr[3]) << 8); - LPC_EMAC->SA0 = (u32_t) netif->hwaddr[4] | - (((u32_t) netif->hwaddr[5]) << 8); - - /* Setup transmit and receive descriptors */ - if (lpc_tx_setup(lpc_enetif) != ERR_OK) - return ERR_BUF; - if (lpc_rx_setup(lpc_enetif) != ERR_OK) - return ERR_BUF; - - /* Enable packet reception */ - LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_MCAST_EN; - - /* Clear and enable rx/tx interrupts */ - LPC_EMAC->IntClear = 0xFFFF; - LPC_EMAC->IntEnable = RXINTGROUP | TXINTGROUP; - - /* Enable RX and TX */ - LPC_EMAC->Command |= EMAC_CR_RX_EN | EMAC_CR_TX_EN; - LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN; - - return err; -} - -/* This function provides a method for the PHY to setup the EMAC - for the PHY negotiated duplex mode */ -void lpc_emac_set_duplex(int full_duplex) -{ - if (full_duplex) { - LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP; - LPC_EMAC->Command |= EMAC_CR_FULL_DUP; - LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP; - } else { - LPC_EMAC->MAC2 &= ~EMAC_MAC2_FULL_DUP; - LPC_EMAC->Command &= ~EMAC_CR_FULL_DUP; - LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP; - } -} - -/* This function provides a method for the PHY to setup the EMAC - for the PHY negotiated bit rate */ -void lpc_emac_set_speed(int mbs_100) -{ - if (mbs_100) - LPC_EMAC->SUPP = EMAC_SUPP_SPEED; - else - LPC_EMAC->SUPP = 0; -} - -/** - * This function is the ethernet IPv4 packet send function. It calls - * etharp_output after checking link status. - * - * \param[in] netif the lwip network interface structure for this lpc_enetif - * \param[in] q Pointer to pbug to send - * \param[in] ipaddr IP address - * \return ERR_OK or error code - */ -#if LWIP_IPV4 -err_t lpc_etharp_output_ipv4(struct netif *netif, struct pbuf *q, - const ip4_addr_t *ipaddr) -{ - /* Only send packet is link is up */ - if (netif->flags & NETIF_FLAG_LINK_UP) - return etharp_output(netif, q, ipaddr); - - return ERR_CONN; -} -#endif - -/** - * This function is the ethernet IPv6 packet send function. It calls - * etharp_output after checking link status. - * - * \param[in] netif the lwip network interface structure for this lpc_enetif - * \param[in] q Pointer to pbug to send - * \param[in] ipaddr IP address - * \return ERR_OK or error code - */ -#if LWIP_IPV6 -err_t lpc_etharp_output_ipv6(struct netif *netif, struct pbuf *q, - const ip6_addr_t *ipaddr) -{ - /* Only send packet is link is up */s - if (netif->flags & NETIF_FLAG_LINK_UP) - return ethip6_output(netif, q, ipaddr); - - return ERR_CONN; -} -#endif - -#if NO_SYS == 0 -/* periodic PHY status update */ -void phy_update(void *nif) { - while (true) { - lpc_phy_sts_sm((struct netif*)nif); - osDelay(250); - } -} - -#endif - -/** - * Should be called at the beginning of the program to set up the - * network interface. - * - * This function should be passed as a parameter to netif_add(). - * - * @param[in] netif the lwip network interface structure for this lpc_enetif - * @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; - - LWIP_ASSERT("netif != NULL", (netif != NULL)); - - lpc_enetdata.netif = netif; - - /* set MAC hardware 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 - netif->hwaddr_len = ETH_HWADDR_LEN; - - /* maximum transfer unit */ - netif->mtu = 1500; - - /* device capabilities */ - 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 - - /* Initialize the hardware */ - netif->state = &lpc_enetdata; - err = low_level_init(netif); - if (err != ERR_OK) - return err; - -#if LWIP_NETIF_HOSTNAME - /* Initialize interface hostname */ - netif->hostname = "lwiplpc"; -#endif /* LWIP_NETIF_HOSTNAME */ - - netif->name[0] = 'e'; - netif->name[1] = 'n'; - -#if LWIP_IPV4 - netif->output = lpc_etharp_output_ipv4; -#endif -#if LWIP_IPV6 - netif->output_ip6 = lpc_etharp_output_ipv6; -#endif - - netif->linkoutput = lpc_low_level_output; - - /* CMSIS-RTOS, start tasks */ -#if NO_SYS == 0 - memset(&lpc_enetdata.xTXDCountSem.data, 0, sizeof(lpc_enetdata.xTXDCountSem.data)); - lpc_enetdata.xTXDCountSem.attr.cb_mem = &lpc_enetdata.xTXDCountSem.data; - lpc_enetdata.xTXDCountSem.attr.cb_size = sizeof(lpc_enetdata.xTXDCountSem.data); - lpc_enetdata.xTXDCountSem.id = osSemaphoreNew(LPC_NUM_BUFF_TXDESCS, LPC_NUM_BUFF_TXDESCS, &lpc_enetdata.xTXDCountSem.attr); - LWIP_ASSERT("xTXDCountSem creation error", (lpc_enetdata.xTXDCountSem.id != NULL)); - - err = sys_mutex_new(&lpc_enetdata.TXLockMutex); - LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK)); - - /* Packet receive task */ - lpc_enetdata.RxThread = sys_thread_new("lpc17_emac_rx_thread", packet_rx, netif->state, DEFAULT_THREAD_STACKSIZE, RX_PRIORITY); - LWIP_ASSERT("RxThread creation error", (lpc_enetdata.RxThread)); - - /* Transmit cleanup task */ - err = sys_sem_new(&lpc_enetdata.TxCleanSem, 0); - LWIP_ASSERT("TxCleanSem creation error", (err == ERR_OK)); - sys_thread_new("lpc17_emac_txclean_thread", packet_tx, netif->state, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY); - - /* periodic PHY status update */ - sys_thread_new("lpc17_emac_phy_thread", phy_update, netif, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY); -#endif - - return ERR_OK; -} - -void eth_arch_enable_interrupts(void) { - NVIC_SetVector(ENET_IRQn, (uint32_t)LPC17xxEthernetHandler); - NVIC_SetPriority(ENET_IRQn, ((0x01 << 3) | 0x01)); - NVIC_EnableIRQ(ENET_IRQn); -} - -void eth_arch_disable_interrupts(void) { - NVIC_DisableIRQ(ENET_IRQn); -} - -/** - * @} - */ - -#endif /* LWIP_ARP || LWIP_ETHERNET */ - -/* --------------------------------- End Of File ------------------------------ */ diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lwipopts_conf.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lwipopts_conf.h deleted file mode 100644 index a117fa6c93..0000000000 --- a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lwipopts_conf.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef LWIPOPTS_CONF_H -#define LWIPOPTS_CONF_H - -#define LWIP_TRANSPORT_ETHERNET 1 - -#if defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) -#define MEM_SIZE 15360 -#elif defined(TARGET_LPC1768) -#define MEM_SIZE 16362 -#endif - -#endif diff --git a/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc17_emac.cpp b/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc17_emac.cpp new file mode 100644 index 0000000000..3c6e0e28cf --- /dev/null +++ b/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc17_emac.cpp @@ -0,0 +1,967 @@ +/********************************************************************** +* $Id$ lpc17_emac.c 2011-11-20 +*//** +* @file lpc17_emac.c +* @brief LPC17 ethernet driver for LWIP +* @version 1.0 +* @date 20. Nov. 2011 +* @author NXP MCU SW Application Team +* +* Copyright(C) 2011, NXP Semiconductor +* All rights reserved. +* +*********************************************************************** +* Software that is described herein is for illustrative purposes only +* which provides customers with programming information regarding the +* products. This software is supplied "AS IS" without any warranties. +* NXP Semiconductors assumes no responsibility or liability for the +* use of the software, conveys no license or title under any patent, +* copyright, or mask work right to the product. NXP Semiconductors +* reserves the right to make changes in the software without +* notification. NXP Semiconductors also make no representation or +* warranty that such application will be suitable for the specified +* use without further testing or modification. +**********************************************************************/ + +#include +#include + +#include "cmsis_os.h" + +#include "mbed_interface.h" +#include "mbed_assert.h" +#include "netsocket/nsapi_types.h" + +#include "lpc_emac_config.h" +#include "lpc17_emac.h" +#include "lpc17xx_emac.h" +#include "lpc_phy.h" +#include "mbed_interface.h" + +#ifndef LPC_EMAC_RMII +#error LPC_EMAC_RMII is not defined! +#endif + +#if LPC_NUM_BUFF_TXDESCS < 2 +#error LPC_NUM_BUFF_TXDESCS must be at least 2 +#endif + +#if LPC_NUM_BUFF_RXDESCS < 3 +#error LPC_NUM_BUFF_RXDESCS must be at least 3 +#endif + +/** @defgroup lwip17xx_emac_DRIVER lpc17 EMAC driver for LWIP + * @ingroup lwip_emac + * + * @{ + */ + +/** \brief Driver transmit and receive thread priorities + * + * Thread priorities for receive thread and TX cleanup thread. Alter + * to prioritize receive or transmit bandwidth. In a heavily loaded + * system or with LEIP_DEBUG enabled, the priorities might be better + * the same. */ +#define RX_PRIORITY (osPriorityNormal) +#define TX_PRIORITY (osPriorityNormal) +#define PHY_PRIORITY (osPriorityNormal) + +/** \brief Debug output formatter lock define + * + * When using FreeRTOS and with LWIP_DEBUG enabled, enabling this + * define will allow RX debug messages to not interleave with the + * TX messages (so they are actually readable). Not enabling this + * define when the system is under load will cause the output to + * be unreadable. There is a small tradeoff in performance for this + * so use it only for debug. */ +//#define LOCK_RX_THREAD + +/** \brief Receive group interrupts + */ +#define RXINTGROUP (EMAC_INT_RX_OVERRUN | EMAC_INT_RX_ERR | EMAC_INT_RX_DONE) + +/** \brief Transmit group interrupts + */ +#define TXINTGROUP (EMAC_INT_TX_UNDERRUN | EMAC_INT_TX_ERR | EMAC_INT_TX_DONE) + +/** \brief Signal used for ethernet ISR to signal packet_rx() thread. + */ +#define RX_SIGNAL 1 + + /** \brief Structure of a TX/RX descriptor + */ +typedef struct +{ + volatile uint32_t packet; /**< Pointer to buffer */ + volatile uint32_t control; /**< Control word */ +} LPC_TXRX_DESC_T; + +/** \brief Structure of a RX status entry + */ +typedef struct +{ + volatile uint32_t statusinfo; /**< RX status word */ + volatile uint32_t statushashcrc; /**< RX hash CRC */ +} LPC_TXRX_STATUS_T; + +/* LPC EMAC driver data structure */ +struct lpc_enetdata { + /* prxs must be 8 byte aligned! */ + LPC_TXRX_STATUS_T prxs[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX statuses */ + LPC_TXRX_DESC_T ptxd[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX descriptor list */ + LPC_TXRX_STATUS_T ptxs[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX statuses */ + LPC_TXRX_DESC_T prxd[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX descriptor list */ + emac_mem_buf_t *rxb[LPC_NUM_BUFF_RXDESCS]; /**< RX pbuf pointer list, zero-copy mode */ + uint32_t rx_fill_desc_index; /**< RX descriptor next available index */ + volatile uint32_t rx_free_descs; /**< Count of free RX descriptors */ + emac_mem_buf_t *txb[LPC_NUM_BUFF_TXDESCS]; /**< TX pbuf pointer list, zero-copy mode */ + uint32_t lpc_last_tx_idx; /**< TX last descriptor index, zero-copy mode */ +}; + +#if defined(TARGET_LPC1768) || defined(TARGET_LPC1769) +/** \brief Group LPC17xx processors into one definition + */ +#define TARGET_LPC17XX +#endif + +#if defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) +# if defined (__ICCARM__) +# define ETHMEM_SECTION +# elif defined(TOOLCHAIN_GCC_CR) +# define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32"), aligned)) +# else +# define ETHMEM_SECTION __attribute__((section("AHBSRAM0"),aligned)) +# endif +#elif defined(TARGET_LPC17XX) +# if defined(TOOLCHAIN_GCC_ARM) || defined(TOOLCHAIN_ARM) +# define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned)) +# endif +#endif + +#ifndef ETHMEM_SECTION +#define ETHMEM_SECTION +#endif + +/** \brief LPC EMAC driver work data + */ +#if defined (__ICCARM__) +#pragma location = ".ethusbram" +#pragma data_alignment = 8 +#endif +ETHMEM_SECTION struct lpc_enetdata lpc_enetdata; + +#if defined (__ICCARM__) +#pragma location = ".ethusbram" +#pragma data_alignment = 8 +#endif +ETHMEM_SECTION uint8_t rx_thread_stack[DEFAULT_THREAD_STACKSIZE]; + +#if defined (__ICCARM__) +#pragma location = ".ethusbram" +#pragma data_alignment = 8 +#endif +ETHMEM_SECTION uint8_t tx_clean_thread_stack[DEFAULT_THREAD_STACKSIZE]; + +#if defined (__ICCARM__) +#pragma location = ".ethusbram" +#pragma data_alignment = 8 +#endif +ETHMEM_SECTION uint8_t phy_thread_stack[DEFAULT_THREAD_STACKSIZE]; + +static osThreadId_t create_new_thread(const char *threadName, void (*thread)(void *arg), void *arg, void *stack_ptr, int stacksize, osPriority_t priority, os_thread_t *thread_cb) +{ + osThreadAttr_t attr = {0}; + attr.name = threadName; + attr.stack_mem = stack_ptr; + attr.cb_mem = thread_cb; + attr.stack_size = stacksize; + attr.cb_size = sizeof(os_thread_t); + attr.priority = priority; + return osThreadNew(thread, arg, &attr); +} + +/** \brief Queues a memory buffer into the RX descriptor list + * + * \param[in] p Pointer to buffer to queue + */ +void LPC17_EMAC::lpc_rxqueue_pbuf(emac_mem_buf_t *p) +{ + uint32_t idx; + + /* Get next free descriptor index */ + idx = lpc_enetdata.rx_fill_desc_index; + + /* Setup descriptor and clear statuses */ + lpc_enetdata.prxd[idx].control = EMAC_RCTRL_INT | ((uint32_t) (memory_manager->get_len(p) - 1)); + lpc_enetdata.prxd[idx].packet = (uint32_t) memory_manager->get_ptr(p); + lpc_enetdata.prxs[idx].statusinfo = 0xFFFFFFFF; + lpc_enetdata.prxs[idx].statushashcrc = 0xFFFFFFFF; + + /* Save pbuf pointer for push to network layer later */ + lpc_enetdata.rxb[idx] = p; + + /* Wrap at end of descriptor list */ + idx++; + if (idx >= LPC_NUM_BUFF_RXDESCS) { + idx = 0; + } + + /* Queue descriptor(s) */ + lpc_enetdata.rx_free_descs -= 1; + lpc_enetdata.rx_fill_desc_index = idx; + LPC_EMAC->RxConsumeIndex = idx; +} + +/** \brief Attempt to allocate and requeue a new memory buffer for RX + * + * \returns >= 1 if a packet or packets were allocated and requeued, otherwise 0 + */ +int32_t LPC17_EMAC::lpc_rx_queue() +{ + //struct lpc_enetdata *lpc_enetif = netif->state; + emac_mem_buf_t *p; + int32_t queued = 0; + + /* Attempt to requeue as many packets as possible */ + while (lpc_enetdata.rx_free_descs > 0) { + /* Allocate a pbuf from the pool. We need to allocate at the + maximum size as we don't know the size of the yet to be + received packet. */ + p = memory_manager->alloc_heap(EMAC_ETH_MAX_FLEN, 0); + if (p == NULL) { + return queued; + } + + /* Queue packet */ + lpc_rxqueue_pbuf(p); + + /* Update queued count */ + queued++; + } + + return queued; +} + +/** \brief Sets up the RX descriptor ring buffers. + * + * This function sets up the descriptor list used for receive packets. + * + * \returns Always returns ERR_OK + */ +bool LPC17_EMAC::lpc_rx_setup() +{ + /* Setup pointers to RX structures */ + LPC_EMAC->RxDescriptor = (uint32_t) &lpc_enetdata.prxd[0]; + LPC_EMAC->RxStatus = (uint32_t) &lpc_enetdata.prxs[0]; + LPC_EMAC->RxDescriptorNumber = LPC_NUM_BUFF_RXDESCS - 1; + + lpc_enetdata.rx_free_descs = LPC_NUM_BUFF_RXDESCS; + lpc_enetdata.rx_fill_desc_index = 0; + + /* Build RX buffer and descriptors */ + lpc_rx_queue(); + + return true; +} + +/** \brief Allocates a memory buffer and returns the data from the incoming packet. + * + * \return a buffer filled with the received packet (including MAC header) + * NULL on memory error + */ +emac_mem_buf_t *LPC17_EMAC::lpc_low_level_input() +{ + emac_mem_buf_t *p = NULL; + uint32_t idx, length; + uint16_t origLength; + +#ifdef LOCK_RX_THREAD + TXLockMutex.lock(); +#endif + + /* Monitor RX overrun status. This should never happen unless + (possibly) the internal bus is behing held up by something. + Unless your system is running at a very low clock speed or + there are possibilities that the internal buses may be held + up for a long time, this can probably safely be removed. */ + if (LPC_EMAC->IntStatus & EMAC_INT_RX_OVERRUN) { + + /* Temporarily disable RX */ + LPC_EMAC->MAC1 &= ~EMAC_MAC1_REC_EN; + + /* Reset the RX side */ + LPC_EMAC->MAC1 |= EMAC_MAC1_RES_RX; + LPC_EMAC->IntClear = EMAC_INT_RX_OVERRUN; + + /* De-allocate all queued RX pbufs */ + for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) { + if (lpc_enetdata.rxb[idx] != NULL) { + memory_manager->free(lpc_enetdata.rxb[idx]); + lpc_enetdata.rxb[idx] = NULL; + } + } + + /* Start RX side again */ + lpc_rx_setup(); + + /* Re-enable RX */ + LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN; + +#ifdef LOCK_RX_THREAD + TXLockMutex.unlock(); +#endif + return NULL; + } + + /* Determine if a frame has been received */ + length = 0; + idx = LPC_EMAC->RxConsumeIndex; + + if (LPC_EMAC->RxProduceIndex != idx) { + /* Handle errors */ + if (lpc_enetdata.prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR | + EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR | EMAC_RINFO_LEN_ERR)) { + + /* Re-queue the buffer for receive */ + lpc_enetdata.rx_free_descs++; + p = lpc_enetdata.rxb[idx]; + lpc_enetdata.rxb[idx] = NULL; + lpc_rxqueue_pbuf(p); + + p = NULL; + } else { + /* A packet is waiting, get length */ + length = (lpc_enetdata.prxs[idx].statusinfo & 0x7FF) + 1; + length -= 4; + + /* Zero-copy */ + p = lpc_enetdata.rxb[idx]; + origLength = memory_manager->get_len(p); + memory_manager->set_len(p, length); + + /* Free buffer from descriptor */ + lpc_enetdata.rxb[idx] = NULL; + lpc_enetdata.rx_free_descs++; + + /* Attempt to queue new buffer(s) */ + if (lpc_rx_queue() == 0) { + /* Re-queue the buffer for receive */ + memory_manager->set_len(p, origLength); + lpc_rxqueue_pbuf(p); + +#ifdef LOCK_RX_THREAD + TXLockMutex.unlock(); +#endif + return NULL; + } + } + } + +#ifdef LOCK_RX_THREAD + TXLockMutex.unlock(); +#endif + + return p; +} + +/** \brief Attempt to read a packet from the EMAC interface. + * + */ +void LPC17_EMAC::lpc_enetif_input() +{ + emac_mem_buf_t *p; + + /* move received packet into a new memory buffer */ + p = lpc_low_level_input(); + if (p == NULL) { + return; + } + + emac_link_input_cb(p); +} + +/** \brief Determine if the passed address is usable for the ethernet + * DMA controller. + * + * \param[in] addr Address of packet to check for DMA safe operation + * \return 1 if the packet address is not safe, otherwise 0 + */ +int32_t LPC17_EMAC::lpc_packet_addr_notsafe(void *addr) +{ + /* Check for legal address ranges */ +#if defined(TARGET_LPC17XX) + if ((((uint32_t) addr >= 0x2007C000) && ((uint32_t) addr < 0x20083FFF))) { +#elif defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) + if ((((uint32_t) addr >= 0x20000000) && ((uint32_t) addr < 0x20007FFF))) { +#endif + return 0; + } + return 1; +} + +/** \brief Sets up the TX descriptor ring buffers. + * + * This function sets up the descriptor list used for transmit packets. + */ +bool LPC17_EMAC::lpc_tx_setup() +{ + int32_t idx; + + /* Build TX descriptors for local buffers */ + for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) { + lpc_enetdata.ptxd[idx].control = 0; + lpc_enetdata.ptxs[idx].statusinfo = 0xFFFFFFFF; + } + + /* Setup pointers to TX structures */ + LPC_EMAC->TxDescriptor = (uint32_t) &lpc_enetdata.ptxd[0]; + LPC_EMAC->TxStatus = (uint32_t) &lpc_enetdata.ptxs[0]; + LPC_EMAC->TxDescriptorNumber = LPC_NUM_BUFF_TXDESCS - 1; + + lpc_enetdata.lpc_last_tx_idx = 0; + + return true; +} + +/** \brief Free TX buffers that are complete + * + * \param[in] cidx EMAC current descriptor comsumer index + */ +void LPC17_EMAC::lpc_tx_reclaim_st(uint32_t cidx) +{ + TXLockMutex.lock(); + + while (cidx != lpc_enetdata.lpc_last_tx_idx) { + if (lpc_enetdata.txb[lpc_enetdata.lpc_last_tx_idx] != NULL) { + memory_manager->free(lpc_enetdata.txb[lpc_enetdata.lpc_last_tx_idx]); + lpc_enetdata.txb[lpc_enetdata.lpc_last_tx_idx] = NULL; + } + + xTXDCountSem.release(); + + lpc_enetdata.lpc_last_tx_idx++; + if (lpc_enetdata.lpc_last_tx_idx >= LPC_NUM_BUFF_TXDESCS) { + lpc_enetdata.lpc_last_tx_idx = 0; + } + } + + TXLockMutex.unlock(); +} + +/** \brief User call for freeingTX buffers that are complete + * + */ +void LPC17_EMAC::lpc_tx_reclaim() +{ + lpc_tx_reclaim_st(LPC_EMAC->TxConsumeIndex); +} + + /** \brief Polls if an available TX descriptor is ready. Can be used to + * determine if the low level transmit function will block. + * + * \return 0 if no descriptors are read, or >0 + */ +int32_t LPC17_EMAC::lpc_tx_ready() +{ + int32_t fb; + uint32_t idx, cidx; + + cidx = LPC_EMAC->TxConsumeIndex; + idx = LPC_EMAC->TxProduceIndex; + + /* Determine number of free buffers */ + if (idx == cidx) { + fb = LPC_NUM_BUFF_TXDESCS; + } else if (cidx > idx) { + fb = (LPC_NUM_BUFF_TXDESCS - 1) - + ((idx + LPC_NUM_BUFF_TXDESCS) - cidx); + } else { + fb = (LPC_NUM_BUFF_TXDESCS - 1) - (cidx - idx); + } + + return fb; +} + +/** \brief Low level output of a packet. Never call this from an + * interrupt context, as it may block until TX descriptors + * become available. + * + * \param[in] p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent + */ +bool LPC17_EMAC::link_out(emac_mem_buf_t *p) +{ + emac_mem_buf_t *q; + uint32_t idx, notdmasafe = 0; + emac_mem_buf_t *np; + int32_t dn; + + /* Zero-copy TX buffers may be fragmented across a memory buffer chain. Determine + the number of descriptors needed for the transfer and make sure packet addresses + are DMA safe. + + A DMA safe address is once that uses external memory or periphheral RAM. + IRAM and FLASH are not safe! */ + dn = 0; + for (q = p; q != NULL; q = memory_manager->get_next(q)) { + ++dn; + void *ptr = memory_manager->get_ptr(q); + notdmasafe += lpc_packet_addr_notsafe(ptr); + } + +#if LPC_TX_PBUF_BOUNCE_EN==1 + /* If the buffer chain is not DMA safe, a new bounce buffer will be + created that will be used instead. This requires an copy from the + non-safe DMA region to the new buffer. */ + if (notdmasafe) { + /* Allocate a buffer in DMA memory. + MEMORY MANAGER HEAP MUST BE IN DMA SAFE MEMORY. */ + np = memory_manager->alloc_heap(memory_manager->get_total_len(p), 0); + if (np == NULL) { + memory_manager->free(p); + return false; + } + memory_manager->copy(np, p); + /* use the new buffer for descriptor queueing. The original buffer will + be de-allocated. */ + memory_manager->free(p); + p = np; + dn = 1; + } +#else + if (notdmasafe) { + MBED_ASSERT(0); + } +#endif + + /* Wait until enough descriptors are available for the transfer. */ + /* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */ + for (int32_t count = 0; count < dn; count++) { + xTXDCountSem.wait(); + } + + MBED_ASSERT(dn <= lpc_tx_ready()); + + TXLockMutex.lock(); + + /* Get free TX buffer index */ + idx = LPC_EMAC->TxProduceIndex; + + /* Setup transfers */ + q = p; + while (dn > 0) { + dn--; + + /* Only save pointer to free on last descriptor */ + if (dn == 0) { + /* Save size of packet and signal it's ready */ + lpc_enetdata.ptxd[idx].control = (memory_manager->get_len(q) - 1) | EMAC_TCTRL_INT | + EMAC_TCTRL_LAST; + lpc_enetdata.txb[idx] = p; + } + else { + /* Save size of packet, descriptor is not last */ + lpc_enetdata.ptxd[idx].control = (memory_manager->get_len(q) - 1) | EMAC_TCTRL_INT; + lpc_enetdata.txb[idx] = NULL; + } + + lpc_enetdata.ptxd[idx].packet = (uint32_t) memory_manager->get_ptr(q); + + q = memory_manager->get_next(q); + + idx++; + if (idx >= LPC_NUM_BUFF_TXDESCS) { + idx = 0; + } + } + + LPC_EMAC->TxProduceIndex = idx; + + TXLockMutex.unlock(); + + return true; +} + +/** \brief LPC EMAC interrupt handler. + * + * This function handles the transmit, receive, and error interrupt of + * the LPC177x_8x. This is meant to be used when NO_SYS=0. + */ +void LPC17xxEthernetHandler(void) +{ + LPC17_EMAC &emac = LPC17_EMAC::get_instance(); + + uint32_t ints; + + /* Interrupts are of 2 groups - transmit or receive. Based on the + interrupt, kick off the receive or transmit (cleanup) task */ + + /* Get pending interrupts */ + ints = LPC_EMAC->IntStatus; + + if (ints & RXINTGROUP) { + /* RX group interrupt(s): Give signal to wakeup RX receive task.*/ + osThreadFlagsSet(emac.RxThread, RX_SIGNAL); + } + + if (ints & TXINTGROUP) { + /* TX group interrupt(s): Give semaphore to wakeup TX cleanup task. */ + emac.TxCleanSem.release(); + } + + /* Clear pending interrupts */ + LPC_EMAC->IntClear = ints; +} + +/** \brief Packet reception task + * + * This task is called when a packet is received. It will + * pass the packet to the IP stacks core. + * + * \param[in] pvParameters Not used yet + */ +void LPC17_EMAC::packet_rx(void* pvParameters) +{ + LPC17_EMAC *lpc17_emac = static_cast(pvParameters); + + while (1) { + /* Wait for receive task to wakeup */ + osThreadFlagsWait(RX_SIGNAL, 0, osWaitForever); + + /* Process packets until all empty */ + while (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex) { + lpc17_emac->lpc_enetif_input(); + } + } +} + +/** \brief Transmit cleanup task + * + * This task is called when a transmit interrupt occurs and + * reclaims the memory buffer and descriptor used for the packet once + * the packet has been transferred. + * + * \param[in] pvParameters Not used yet + */ +void LPC17_EMAC::packet_tx(void* pvParameters) +{ + LPC17_EMAC *lpc17_emac = static_cast(pvParameters); + int32_t idx; + + while (1) { + /* Wait for transmit cleanup task to wakeup */ + lpc17_emac->TxCleanSem.wait(); + + /* Error handling for TX underruns. This should never happen unless + something is holding the bus or the clocks are going too slow. It + can probably be safely removed. */ + if (LPC_EMAC->IntStatus & EMAC_INT_TX_UNDERRUN) { + lpc17_emac->TXLockMutex.lock(); + + /* Reset the TX side */ + LPC_EMAC->MAC1 |= EMAC_MAC1_RES_TX; + LPC_EMAC->IntClear = EMAC_INT_TX_UNDERRUN; + + /* De-allocate all queued TX buffers */ + for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) { + if (lpc_enetdata.txb[idx] != NULL) { + lpc17_emac->memory_manager->free(lpc_enetdata.txb[idx]); + lpc_enetdata.txb[idx] = NULL; + } + } + + lpc17_emac->TXLockMutex.unlock(); + + /* Start TX side again */ + lpc17_emac->lpc_tx_setup(); + } else { + /* Free TX buffers that are done sending */ + lpc17_emac->lpc_tx_reclaim(); + } + } +} + +/** \brief Low level init of the MAC and PHY. + * + */ +bool LPC17_EMAC::low_level_init() +{ + bool err = true; + + /* Enable MII clocking */ + LPC_SC->PCONP |= CLKPWR_PCONP_PCENET; + +#if defined(TARGET_LPC17XX) + LPC_PINCON->PINSEL2 = 0x50150105; /* Enable P1 Ethernet Pins. */ + LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005; +#elif defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) + LPC_IOCON->P1_0 &= ~0x07; /* ENET I/O config */ + LPC_IOCON->P1_0 |= 0x01; /* ENET_TXD0 */ + LPC_IOCON->P1_1 &= ~0x07; + LPC_IOCON->P1_1 |= 0x01; /* ENET_TXD1 */ + LPC_IOCON->P1_4 &= ~0x07; + LPC_IOCON->P1_4 |= 0x01; /* ENET_TXEN */ + LPC_IOCON->P1_8 &= ~0x07; + LPC_IOCON->P1_8 |= 0x01; /* ENET_CRS */ + LPC_IOCON->P1_9 &= ~0x07; + LPC_IOCON->P1_9 |= 0x01; /* ENET_RXD0 */ + LPC_IOCON->P1_10 &= ~0x07; + LPC_IOCON->P1_10 |= 0x01; /* ENET_RXD1 */ + LPC_IOCON->P1_14 &= ~0x07; + LPC_IOCON->P1_14 |= 0x01; /* ENET_RX_ER */ + LPC_IOCON->P1_15 &= ~0x07; + LPC_IOCON->P1_15 |= 0x01; /* ENET_REF_CLK */ + LPC_IOCON->P1_16 &= ~0x07; /* ENET/PHY I/O config */ + LPC_IOCON->P1_16 |= 0x01; /* ENET_MDC */ + LPC_IOCON->P1_17 &= ~0x07; + LPC_IOCON->P1_17 |= 0x01; /* ENET_MDIO */ +#endif + + /* Reset all MAC logic */ + LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | + EMAC_MAC1_RES_RX | EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | + EMAC_MAC1_SOFT_RES; + LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES | + EMAC_CR_PASS_RUNT_FRM; + osDelay(10); + + /* Initial MAC initialization */ + LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL; + LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN | + EMAC_MAC2_VLAN_PAD_EN; + LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN; + + /* Set RMII management clock rate to lowest speed */ + LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(11) | EMAC_MCFG_RES_MII; + LPC_EMAC->MCFG &= ~EMAC_MCFG_RES_MII; + + /* Maximum number of retries, 0x37 collision window, gap */ + LPC_EMAC->CLRT = EMAC_CLRT_DEF; + LPC_EMAC->IPGR = EMAC_IPGR_P1_DEF | EMAC_IPGR_P2_DEF; + +#if LPC_EMAC_RMII + /* RMII setup */ + LPC_EMAC->Command = EMAC_CR_PASS_RUNT_FRM | EMAC_CR_RMII; +#else + /* MII setup */ + LPC_EMAC->CR = EMAC_CR_PASS_RUNT_FRM; +#endif + + /* Initialize the PHY and reset */ + err = lpc_phy_init(this, LPC_EMAC_RMII); + if (err == false) { + return false; + } + + /* Save station address */ + LPC_EMAC->SA2 = (uint32_t) hwaddr[0] | + (((uint32_t) hwaddr[1]) << 8); + LPC_EMAC->SA1 = (uint32_t) hwaddr[2] | + (((uint32_t) hwaddr[3]) << 8); + LPC_EMAC->SA0 = (uint32_t) hwaddr[4] | + (((uint32_t) hwaddr[5]) << 8); + + /* Setup transmit and receive descriptors */ + if (lpc_tx_setup() != true) { + return false; + } + if (lpc_rx_setup() != true) { + return false; + } + + /* Enable packet reception */ + LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_MCAST_EN; + + /* Clear and enable rx/tx interrupts */ + LPC_EMAC->IntClear = 0xFFFF; + LPC_EMAC->IntEnable = RXINTGROUP | TXINTGROUP; + + /* Enable RX and TX */ + LPC_EMAC->Command |= EMAC_CR_RX_EN | EMAC_CR_TX_EN; + LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN; + + return err; +} + +/* This function provides a method for the PHY to setup the EMAC + for the PHY negotiated duplex mode */ +void lpc_emac_set_duplex(int full_duplex) +{ + if (full_duplex) { + LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP; + LPC_EMAC->Command |= EMAC_CR_FULL_DUP; + LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP; + } else { + LPC_EMAC->MAC2 &= ~EMAC_MAC2_FULL_DUP; + LPC_EMAC->Command &= ~EMAC_CR_FULL_DUP; + LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP; + } +} + +/* This function provides a method for the PHY to setup the EMAC + for the PHY negotiated bit rate */ +void lpc_emac_set_speed(int mbs_100) +{ + if (mbs_100) { + LPC_EMAC->SUPP = EMAC_SUPP_SPEED; + } else { + LPC_EMAC->SUPP = 0; + } +} + +/* periodic PHY status update */ +void LPC17_EMAC::phy_update(void *nif) +{ + LPC17_EMAC *lpc17_emac = static_cast(nif); + + while (true) { + lpc_phy_sts_sm(lpc17_emac); + osDelay(250); + } +} + +void LPC17_EMAC::update_link_status(bool up) +{ + emac_link_state_cb(up); +} + +void LPC17_EMAC::eth_arch_enable_interrupts(void) { + NVIC_SetVector(ENET_IRQn, (uint32_t)LPC17xxEthernetHandler); + NVIC_SetPriority(ENET_IRQn, ((0x01 << 3) | 0x01)); + NVIC_EnableIRQ(ENET_IRQn); +} + +void LPC17_EMAC::eth_arch_disable_interrupts(void) { + NVIC_DisableIRQ(ENET_IRQn); +} + +/** + * Should be called at the beginning of the program to set up the + * network interface. + * + * This function should be passed as a parameter to netif_add(). + * + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +bool LPC17_EMAC::power_up() +{ + bool err = low_level_init(); + if (err != true) { + return false; + } + + RxThread = create_new_thread("lpc17_emac_rx_thread", LPC17_EMAC::packet_rx, this, rx_thread_stack, DEFAULT_THREAD_STACKSIZE, RX_PRIORITY, &RxThread_cb); + TxCleanThread = create_new_thread("lpc17_emac_txclean_thread", LPC17_EMAC::packet_tx, this, tx_clean_thread_stack, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY, &TxCleanThread_cb); + PhyThread = create_new_thread("lpc17_emac_phy_thread", LPC17_EMAC::phy_update, this, phy_thread_stack, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY, &PhyThread_cb); + + /* Allow the PHY task to detect the initial link state and set up the proper flags */ + osDelay(10); + + eth_arch_enable_interrupts(); + + return true; +} + +uint32_t LPC17_EMAC::get_mtu_size() const +{ + return 1500; +} + +uint32_t LPC17_EMAC::get_align_preference() const +{ + return 0; +} + +void LPC17_EMAC::get_ifname(char *name, uint8_t size) const +{ + memcpy(name, LPC17_ETH_IF_NAME, (size < sizeof(LPC17_ETH_IF_NAME)) ? size : sizeof(LPC17_ETH_IF_NAME)); +} + +uint8_t LPC17_EMAC::get_hwaddr_size() const +{ + return LPC17_ETH_HWADDR_SIZE; +} + +bool LPC17_EMAC::get_hwaddr(uint8_t *addr) const +{ + return false; +} + +void LPC17_EMAC::set_hwaddr(const uint8_t *addr) +{ + memcpy(hwaddr, addr, LPC17_ETH_HWADDR_SIZE); + + /* Save station address */ + LPC_EMAC->SA2 = (uint32_t) hwaddr[0] | + (((uint32_t) hwaddr[1]) << 8); + LPC_EMAC->SA1 = (uint32_t) hwaddr[2] | + (((uint32_t) hwaddr[3]) << 8); + LPC_EMAC->SA0 = (uint32_t) hwaddr[4] | + (((uint32_t) hwaddr[5]) << 8); +} + +void LPC17_EMAC::set_link_input_cb(emac_link_input_cb_t input_cb) +{ + emac_link_input_cb = input_cb; +} + +void LPC17_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb) +{ + emac_link_state_cb = state_cb; +} + +void LPC17_EMAC::add_multicast_group(const uint8_t *addr) +{ + /* No-op at this stage */ +} + +void LPC17_EMAC::remove_multicast_group(const uint8_t *address) +{ + /* No-op at this stage */ +} + +void LPC17_EMAC::set_all_multicast(bool all) +{ + /* No-op at this stage */ +} + +void LPC17_EMAC::power_down() +{ + /* No-op at this stage */ +} + +LPC17_EMAC::LPC17_EMAC() + : RxThread(), + RxThread_cb(), + TxCleanSem(), + hwaddr(), + TxCleanThread(), + TxCleanThread_cb(), + PhyThread(), + PhyThread_cb(), + TXLockMutex(), + xTXDCountSem(LPC_NUM_BUFF_TXDESCS), + emac_link_input_cb(0), + emac_link_state_cb(0), + memory_manager(0) +{ +} + +void LPC17_EMAC::set_memory_manager(EMACMemoryManager &mem_mngr) +{ + memory_manager = &mem_mngr; +} + +LPC17_EMAC &LPC17_EMAC::get_instance() { + static LPC17_EMAC emac; + return emac; +} + +// Weak so a module can override +MBED_WEAK EMAC &EMAC::get_default_instance() { + return LPC17_EMAC::get_instance(); +} + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc17_emac.h b/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc17_emac.h new file mode 100644 index 0000000000..1b8e9128fa --- /dev/null +++ b/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc17_emac.h @@ -0,0 +1,178 @@ + +#ifndef LPC17_EMAC_H_ +#define LPC17_EMAC_H_ + +#include "EMAC.h" +#include "rtos/Semaphore.h" +#include "rtos/Mutex.h" + +#include "lpc_emac_config.h" + +class LPC17_EMAC : public EMAC { +public: + LPC17_EMAC(); + + static LPC17_EMAC &get_instance(); + + /** + * Return maximum transmission unit + * + * @return MTU in bytes + */ + virtual uint32_t get_mtu_size() const; + + /** + * Gets memory buffer alignment preference + * + * Gets preferred memory buffer alignment of the Emac device. IP stack may or may not + * align link out memory buffer chains using the alignment. + * + * @return Memory alignment requirement in bytes + */ + virtual uint32_t get_align_preference() const; + + /** + * Return interface name + * + * @param name Pointer to where the name should be written + * @param size Maximum number of character to copy + */ + virtual void get_ifname(char *name, uint8_t size) const; + + /** + * Returns size of the underlying interface HW address size. + * + * @return HW address size in bytes + */ + virtual uint8_t get_hwaddr_size() const; + + /** + * Return interface-supplied HW address + * + * Copies HW address to provided memory, @param addr has to be of correct size see @a get_hwaddr_size + * + * HW address need not be provided if this interface does not have its own HW + * address configuration; stack will choose address from central system + * configuration if the function returns false and does not write to addr. + * + * @param addr HW address for underlying interface + * @return true if HW address is available + */ + virtual bool get_hwaddr(uint8_t *addr) const; + + /** + * Set HW address for interface + * + * Provided address has to be of correct size, see @a get_hwaddr_size + * + * Called to set the MAC address to actually use - if @a get_hwaddr is provided + * the stack would normally use that, but it could be overridden, eg for test + * purposes. + * + * @param addr Address to be set + */ + virtual void set_hwaddr(const uint8_t *addr); + + /** + * Sends the packet over the link + * + * That can not be called from an interrupt context. + * + * @param buf Packet to be send + * @return True if the packet was send successfully, False otherwise + */ + virtual bool link_out(emac_mem_buf_t *buf); + + /** + * Initializes the HW + * + * @return True on success, False in case of an error. + */ + virtual bool power_up(); + + /** + * Deinitializes the HW + * + */ + virtual void power_down(); + + /** + * Sets a callback that needs to be called for packets received for that interface + * + * @param input_cb Function to be register as a callback + */ + virtual void set_link_input_cb(emac_link_input_cb_t input_cb); + + /** + * Sets a callback that needs to be called on link status changes for given interface + * + * @param state_cb Function to be register as a callback + */ + virtual void set_link_state_cb(emac_link_state_change_cb_t state_cb); + + /** Add device to a multicast group + * + * @param address A multicast group hardware address + */ + virtual void add_multicast_group(const uint8_t *address); + + /** Remove device from a multicast group + * + * @param address A multicast group hardware address + */ + virtual void remove_multicast_group(const uint8_t *address); + + /** Request reception of all multicast packets + * + * @param all True to receive all multicasts + * False to receive only multicasts addressed to specified groups + */ + virtual void set_all_multicast(bool all); + + /** Sets memory manager that is used to handle memory buffers + * + * @param mem_mngr Pointer to memory manager + */ + virtual void set_memory_manager(EMACMemoryManager &mem_mngr); + + void update_link_status(bool up); + + osThreadId_t RxThread; + os_thread_t RxThread_cb; + rtos::Semaphore TxCleanSem; + +private: + void lpc_rxqueue_pbuf(emac_mem_buf_t *p); + int32_t lpc_rx_queue(); + bool lpc_rx_setup(); + emac_mem_buf_t *lpc_low_level_input(); + void lpc_enetif_input(); + int32_t lpc_packet_addr_notsafe(void *addr); + bool lpc_tx_setup(); + void lpc_tx_reclaim_st(uint32_t cidx); + void lpc_tx_reclaim(); + int32_t lpc_tx_ready(); + static void packet_rx(void* pvParameters); + static void packet_tx(void* pvParameters); + bool low_level_init(); + static void phy_update(void *nif); + bool eth_arch_enetif_init(); + void eth_arch_enable_interrupts(); + void eth_arch_disable_interrupts(); + + uint8_t hwaddr[6]; + + osThreadId_t TxCleanThread; + os_thread_t TxCleanThread_cb; + osThreadId_t PhyThread; + os_thread_t PhyThread_cb; + rtos::Mutex TXLockMutex; + rtos::Semaphore xTXDCountSem; + + emac_link_input_cb_t emac_link_input_cb; /**< Callback for incoming data */ + emac_link_state_change_cb_t emac_link_state_cb; /**< Link state change callback */ + + EMACMemoryManager *memory_manager; /**< Memory manager */ +}; + +#endif diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc17xx_emac.h b/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc17xx_emac.h similarity index 99% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc17xx_emac.h rename to features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc17xx_emac.h index 9979a2560c..13019d46e9 100644 --- a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc17xx_emac.h +++ b/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc17xx_emac.h @@ -654,6 +654,10 @@ typedef struct { #endif /* LPC17XX_EMAC_H_ */ +/** + * @} + */ + /** * @} */ diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_emac_config.h b/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc_emac_config.h similarity index 85% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_emac_config.h rename to features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc_emac_config.h index 831b3d76d0..43efb8a7fd 100644 --- a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_emac_config.h +++ b/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc_emac_config.h @@ -26,14 +26,12 @@ #ifndef __LPC_EMAC_CONFIG_H #define __LPC_EMAC_CONFIG_H -#include "lwip/opt.h" +#define LPC17_ETH_IF_NAME "lpc" +#define LPC17_ETH_HWADDR_SIZE 6 -#ifdef __cplusplus -extern "C" -{ -#endif +#define DEFAULT_THREAD_STACKSIZE 512 -/** @defgroup lwip_phy_config LWIP PHY configuration +/** @defgroup lwip_phy_config PHY configuration * @ingroup lwip_phy * * Configuration options for the PHY connected to the LPC EMAC. @@ -67,8 +65,7 @@ extern "C" * @} */ -/** @defgroup lwip_emac_config LWIP EMAC configuration - * @ingroup lwip_emac +/** @defgroup emac_config EMAC configuration * * Configuration options for the LPC EMAC. * @{ @@ -81,18 +78,18 @@ extern "C" /** \brief Defines the number of descriptors used for RX. This * must be a minimum value of 2. */ -#define LPC_NUM_BUFF_RXDESCS 3 +#define LPC_NUM_BUFF_RXDESCS 4 /** \brief Defines the number of descriptors used for TX. Must * be a minimum value of 2. */ -#define LPC_NUM_BUFF_TXDESCS (TCP_SND_QUEUELEN + 1) +#define LPC_NUM_BUFF_TXDESCS 9 -/** \brief Set this define to 1 to enable bounce buffers for transmit pbufs - * that cannot be sent via the zero-copy method. Some chained pbufs - * may have a payload address that links to an area of memory that +/** \brief Set this define to 1 to enable bounce buffers for transmit memory + * buffers that cannot be sent via the zero-copy method. Some chained + * buffers may have a payload address that links to an area of memory that * cannot be used for transmit DMA operations. If this define is - * set to 1, an extra check will be made with the pbufs. If a buffer + * set to 1, an extra check will be made with the buffers. If a buffer * is determined to be non-usable for zero-copy, a temporary bounce * buffer will be created and used instead. */ @@ -102,10 +99,6 @@ extern "C" * @} */ -#ifdef __cplusplus -} -#endif - #endif /* __LPC_EMAC_CONFIG_H */ /* --------------------------------- End Of File ------------------------------ */ diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_phy.h b/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc_phy.h similarity index 86% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_phy.h rename to features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc_phy.h index fa53656a77..5c2f314215 100644 --- a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_phy.h +++ b/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc_phy.h @@ -26,15 +26,6 @@ #ifndef __LPC_PHY_H_ #define __LPC_PHY_H_ -#include "lwip/opt.h" -#include "lwip/err.h" -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - /* These PHY functions are usually part of the EMAC driver */ /** \brief Phy status update state machine @@ -43,9 +34,10 @@ extern "C" * status without blocking. It must be occasionally called for the * PHY status to be maintained. * - * \param[in] netif NETIF structure + * \param[in] lpc17_emac LPC17 EMAC */ -s32_t lpc_phy_sts_sm(struct netif *netif); + +int32_t lpc_phy_sts_sm(LPC17_EMAC *lpc17_emac); /** \brief Initialize the PHY * @@ -54,11 +46,11 @@ s32_t lpc_phy_sts_sm(struct netif *netif); * initialization. Configuration of the PHY at startup is * controlled by setting up configuration defines in lpc_phy.h. * - * \param[in] netif NETIF structure + * \param[in] lpc17_emac LPC17 EMAC * \param[in] rmii If set, configures the PHY for RMII mode - * \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT + * \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT */ -err_t lpc_phy_init(struct netif *netif, int rmii); +bool lpc_phy_init(LPC17_EMAC *lpc17_emac, int rmii); /** \brief Write a value via the MII link (non-blocking) * @@ -70,7 +62,7 @@ err_t lpc_phy_init(struct netif *netif, int rmii); * \param[in] PhyReg PHY register to write to * \param[in] Value Value to write */ -void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value); +void lpc_mii_write_noblock(uint32_t PhyReg, uint32_t Value); /** \brief Write a value via the MII link (blocking) * @@ -81,7 +73,7 @@ void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value); * \param[in] Value Value to write * \returns 0 if the write was successful, otherwise !0 */ -err_t lpc_mii_write(u32_t PhyReg, u32_t Value); +bool lpc_mii_write(uint32_t PhyReg, uint32_t Value); /** \brief Reads current MII link busy status * @@ -91,7 +83,7 @@ err_t lpc_mii_write(u32_t PhyReg, u32_t Value); * * \returns !0 if the MII link is busy, otherwise 0 */ -u32_t lpc_mii_is_busy(void); +uint32_t lpc_mii_is_busy(void); /** \brief Starts a read operation via the MII link (non-blocking) * @@ -102,7 +94,7 @@ u32_t lpc_mii_is_busy(void); * * \returns The current value in the MII value register */ -u32_t lpc_mii_read_data(void); +uint32_t lpc_mii_read_data(void); /** \brief Starts a read operation via the MII link (non-blocking) * @@ -112,8 +104,11 @@ u32_t lpc_mii_read_data(void); * can be read. * * \param[in] PhyReg PHY register to read from + * \param[in] data Pointer to where to save data read via MII + * \returns 0 if the read was successful, otherwise !0 + * */ -err_t lpc_mii_read(u32_t PhyReg, u32_t *data); +bool lpc_mii_read(uint32_t PhyReg, uint32_t *data); /** \brief Read a value via the MII link (blocking) * @@ -121,10 +116,8 @@ err_t lpc_mii_read(u32_t PhyReg, u32_t *data); * or a connected device. The function will block until complete. * * \param[in] PhyReg PHY register to read from - * \param[in] data Pointer to where to save data read via MII - * \returns 0 if the read was successful, otherwise !0 */ -void lpc_mii_read_noblock(u32_t PhyReg); +void lpc_mii_read_noblock(uint32_t PhyReg); /** * This function provides a method for the PHY to setup the EMAC @@ -142,10 +135,6 @@ void lpc_emac_set_duplex(int full_duplex); */ void lpc_emac_set_speed(int mbs_100); -#ifdef __cplusplus -} -#endif - #endif /* __LPC_PHY_H_ */ /* --------------------------------- End Of File ------------------------------ */ diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_phy_dp83848.c b/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc_phy_dp83848.cpp similarity index 83% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_phy_dp83848.c rename to features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc_phy_dp83848.cpp index e44fa73c4c..fb59734b0d 100644 --- a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_phy_dp83848.c +++ b/features/netsocket/emac-drivers/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc_phy_dp83848.cpp @@ -23,15 +23,12 @@ * use without further testing or modification. **********************************************************************/ -#include "lwip/opt.h" -#include "lwip/err.h" -#include "lwip/tcpip.h" -#include "lwip/snmp.h" +#include "netsocket/nsapi_types.h" #include "lpc_emac_config.h" +#include "lpc17_emac.h" #include "lpc_phy.h" #include "lpc17xx_emac.h" -#if LWIP_ARP || LWIP_ETHERNET /** @defgroup dp83848_phy PHY status and control for the DP83848. * @ingroup lwip_phy @@ -110,12 +107,13 @@ #define DP83848C_ID 0x20005C90 /**< PHY Identifier - DP83848C */ #define LAN8720_ID 0x0007C0F0 /**< PHY Identifier - LAN8720 */ + /** \brief PHY status structure used to indicate current status of PHY. */ typedef struct { - u32_t phy_speed_100mbs:1; /**< 10/100 MBS connection speed flag. */ - u32_t phy_full_duplex:1; /**< Half/full duplex connection speed flag. */ - u32_t phy_link_active:1; /**< Phy link active flag. */ + unsigned int phy_speed_100mbs:1; /**< 10/100 MBS connection speed flag. */ + unsigned int phy_full_duplex:1; /**< Half/full duplex connection speed flag. */ + unsigned int phy_link_active:1; /**< Phy link active flag. */ } PHY_STATUS_TYPE; /** \brief PHY update flags */ @@ -125,16 +123,16 @@ static PHY_STATUS_TYPE physts; static PHY_STATUS_TYPE olddphysts; /** \brief PHY update counter for state machine */ -static s32_t phyustate; +static int32_t phyustate; /** \brief Holds the PHY ID */ -static u32_t phy_id; +static uint32_t phy_id; /** \brief Temporary holder of link status for LAN7420 */ -static u32_t phy_lan7420_sts_tmp; +static uint32_t phy_lan7420_sts_tmp; /* Write a value via the MII link (non-blocking) */ -void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value) +void lpc_mii_write_noblock(uint32_t PhyReg, uint32_t Value) { /* Write value at PHY address and register */ LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg; @@ -142,10 +140,10 @@ void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value) } /* Write a value via the MII link (blocking) */ -err_t lpc_mii_write(u32_t PhyReg, u32_t Value) +bool lpc_mii_write(uint32_t PhyReg, uint32_t Value) { - u32_t mst = 250; - err_t sts = ERR_OK; + uint32_t mst = 250; + int8_t sts = 0; /* Write value at PHY address and register */ lpc_mii_write_noblock(PhyReg, Value); @@ -162,28 +160,28 @@ err_t lpc_mii_write(u32_t PhyReg, u32_t Value) } if (sts != 0) - sts = ERR_TIMEOUT; + return false; - return sts; + return true; } /* Reads current MII link busy status */ -u32_t lpc_mii_is_busy(void) +uint32_t lpc_mii_is_busy(void) { - return (u32_t) (LPC_EMAC->MIND & EMAC_MIND_BUSY); + return (uint32_t) (LPC_EMAC->MIND & EMAC_MIND_BUSY); } /* Starts a read operation via the MII link (non-blocking) */ -u32_t lpc_mii_read_data(void) +uint32_t lpc_mii_read_data(void) { - u32_t data = LPC_EMAC->MRDD; + uint32_t data = LPC_EMAC->MRDD; LPC_EMAC->MCMD = 0; return data; } /* Starts a read operation via the MII link (non-blocking) */ -void lpc_mii_read_noblock(u32_t PhyReg) +void lpc_mii_read_noblock(uint32_t PhyReg) { /* Read value at PHY address and register */ LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg; @@ -191,10 +189,10 @@ void lpc_mii_read_noblock(u32_t PhyReg) } /* Read a value via the MII link (blocking) */ -err_t lpc_mii_read(u32_t PhyReg, u32_t *data) +bool lpc_mii_read(uint32_t PhyReg, uint32_t *data) { - u32_t mst = 250; - err_t sts = ERR_OK; + uint32_t mst = 250; + int8_t sts = 0; /* Read value at PHY address and register */ lpc_mii_read_noblock(PhyReg); @@ -214,26 +212,24 @@ err_t lpc_mii_read(u32_t PhyReg, u32_t *data) LPC_EMAC->MCMD = 0; if (sts != 0) - sts = ERR_TIMEOUT; + return false; - return sts; + return true; } - - /** \brief Update PHY status from passed value * * This function updates the current PHY status based on the * passed PHY status word. The PHY status indicate if the link * is active, the connection speed, and duplex. * - * \param[in] netif NETIF structure + * \param[in] lpc17_emac LPC17 EMAC * \param[in] linksts Status word from PHY - * \return 1 if the status has changed, otherwise 0 + * \return 1 if the status has changed, otherwise 0 */ -static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts) +static int32_t lpc_update_phy_sts(LPC17_EMAC *lpc17_emac, uint32_t linksts) { - s32_t changed = 0; + int32_t changed = 0; /* Update link active status */ if (linksts & LNK_STAT_VALID) @@ -258,14 +254,10 @@ static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts) if (physts.phy_speed_100mbs) { /* 100MBit mode. */ lpc_emac_set_speed(1); - - NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000); } else { /* 10MBit mode. */ lpc_emac_set_speed(0); - - NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000); } olddphysts.phy_speed_100mbs = physts.phy_speed_100mbs; @@ -283,19 +275,12 @@ static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts) if (physts.phy_link_active != olddphysts.phy_link_active) { changed = 1; -#if NO_SYS == 1 - if (physts.phy_link_active) - netif_set_link_up(netif); - else - netif_set_link_down(netif); -#else - if (physts.phy_link_active) - tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_up, - (void*) netif, 1); - else - tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_down, - (void*) netif, 1); -#endif + + if (physts.phy_link_active) { + lpc17_emac->update_link_status(true); + } else { + lpc17_emac->update_link_status(false); + } olddphysts.phy_link_active = physts.phy_link_active; } @@ -310,14 +295,14 @@ static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts) * initialization. Configuration of the PHY at startup is * controlled by setting up configuration defines in lpc_phy.h. * - * \param[in] netif NETIF structure - * \param[in] rmii If set, configures the PHY for RMII mode - * \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT + * \param[in] lpc17_emac LPC17 EMAC + * \param[in] rmii If set, configures the PHY for RMII mode + * \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT */ -err_t lpc_phy_init(struct netif *netif, int rmii) +bool lpc_phy_init(LPC17_EMAC *lpc17_emac, int rmii) { - u32_t tmp; - s32_t i; + uint32_t tmp; + int32_t i; physts.phy_speed_100mbs = olddphysts.phy_speed_100mbs = 0; physts.phy_full_duplex = olddphysts.phy_full_duplex = 0; @@ -326,13 +311,14 @@ err_t lpc_phy_init(struct netif *netif, int rmii) /* Only first read and write are checked for failure */ /* Put the DP83848C in reset mode and wait for completion */ - if (lpc_mii_write(DP8_BMCR_REG, DP8_RESET) != 0) - return ERR_TIMEOUT; + if (!lpc_mii_write(DP8_BMCR_REG, DP8_RESET)) { + return false; + } i = 400; while (i > 0) { osDelay(1); /* 1 ms */ - if (lpc_mii_read(DP8_BMCR_REG, &tmp) != 0) - return ERR_TIMEOUT; + if (!lpc_mii_read(DP8_BMCR_REG, &tmp)) + return false; if (!(tmp & (DP8_RESET | DP8_POWER_DOWN))) i = -1; @@ -341,7 +327,7 @@ err_t lpc_phy_init(struct netif *netif, int rmii) } /* Timeout? */ if (i == 0) - return ERR_TIMEOUT; + return false; // read PHY ID lpc_mii_read(DP8_IDR1_REG, &tmp); @@ -370,15 +356,19 @@ err_t lpc_phy_init(struct netif *netif, int rmii) /* The link is not set active at this point, but will be detected later */ - return ERR_OK; + return true; } -/* Phy status update state machine */ -s32_t lpc_phy_sts_sm(struct netif *netif) +/** \brief Phy status update state machine + * + * \param[in] lpc17_emac LPC17 EMAC + * \return 1 if the status has changed, otherwise 0 + */ +int32_t lpc_phy_sts_sm(LPC17_EMAC *lpc17_emac) { - s32_t changed = 0; - u32_t data = 0; - u32_t tmp; + int32_t changed = 0; + uint32_t data = 0; + uint32_t tmp; switch (phyustate) { default: @@ -424,7 +414,7 @@ s32_t lpc_phy_sts_sm(struct netif *netif) data = phy_lan7420_sts_tmp; } - changed = lpc_update_phy_sts(netif, data); + changed = lpc_update_phy_sts(lpc17_emac, data); phyustate = 0; } break; @@ -433,8 +423,6 @@ s32_t lpc_phy_sts_sm(struct netif *netif) return changed; } -#endif /* LWIP_ARP || LWIP_ETHERNET */ - /** * @} */ diff --git a/targets/targets.json b/targets/targets.json index 0025d90d9c..631fea1881 100755 --- a/targets/targets.json +++ b/targets/targets.json @@ -240,10 +240,10 @@ "LPC1768": { "inherits": ["LPCTarget"], "core": "Cortex-M3", - "extra_labels": ["NXP", "LPC176X", "MBED_LPC1768"], + "extra_labels": ["NXP", "LPC176X", "MBED_LPC1768", "NXP_EMAC"], "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "GCC_CR", "IAR"], "detect_code": ["1010"], - "device_has": ["USTICKER", "ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SEMIHOST", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "FLASH"], + "device_has": ["USTICKER", "ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "EMAC", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SEMIHOST", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "FLASH"], "release_versions": ["2", "5"], "features": ["LWIP"], "device_name": "LPC1768", @@ -260,10 +260,10 @@ "supported_form_factors": ["ARDUINO"], "core": "Cortex-M3", "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "GCC_CR", "IAR"], - "extra_labels": ["NXP", "LPC176X"], + "extra_labels": ["NXP", "LPC176X", "NXP_EMAC"], "macros": ["TARGET_LPC1768"], "inherits": ["LPCTarget"], - "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "FLASH"], + "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "EMAC", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "FLASH"], "release_versions": ["2", "5"], "features": ["LWIP"], "device_name": "LPC1768", @@ -362,13 +362,13 @@ "MCU_LPC4088": { "inherits": ["LPCTarget"], "core": "Cortex-M4F", - "extra_labels": ["NXP", "LPC408X"], + "extra_labels": ["NXP", "LPC408X", "NXP_EMAC"], "is_disk_virtual": true, "supported_toolchains": ["ARM", "GCC_CR", "GCC_ARM", "IAR"], "post_binary_hook": { "function": "LPC4088Code.binary_hook" }, - "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"], + "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "EMAC", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"], "features": ["LWIP"], "device_name": "LPC4088FBD144", "overrides": {