mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			
						commit
						8c6a664380
					
				
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -116,6 +116,12 @@
 | 
			
		|||
        "LPC4088_DM": {
 | 
			
		||||
            "mem-size": 15360
 | 
			
		||||
        },
 | 
			
		||||
        "UBLOX_C027": {
 | 
			
		||||
            "mem-size": 16362
 | 
			
		||||
        },
 | 
			
		||||
        "ARCH_PRO": {
 | 
			
		||||
            "mem-size": 16362
 | 
			
		||||
        },      
 | 
			
		||||
        "LPC546XX": {
 | 
			
		||||
            "mem-size": 36496
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,972 @@
 | 
			
		|||
/**********************************************************************
 | 
			
		||||
* $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 <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#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 */
 | 
			
		||||
    uint32_t lpc_reserved_tx_num; /**< Number of reserved TX descriptors, 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;
 | 
			
		||||
    lpc_enetdata.lpc_reserved_tx_num = 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();
 | 
			
		||||
 | 
			
		||||
    // If consume index not last freed index or all descriptors in use
 | 
			
		||||
    while (cidx != lpc_enetdata.lpc_last_tx_idx || lpc_enetdata.lpc_reserved_tx_num == LPC_NUM_BUFF_TXDESCS) {
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
        lpc_enetdata.lpc_reserved_tx_num--;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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_enetdata.lpc_reserved_tx_num++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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<LPC17_EMAC *>(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<LPC17_EMAC *>(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<LPC17_EMAC *>(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 ------------------------------ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,191 @@
 | 
			
		|||
/* Copyright (c) 2018 ARM Limited
 | 
			
		||||
 *
 | 
			
		||||
 * 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 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
 | 
			
		||||
| 
						 | 
				
			
			@ -654,6 +654,10 @@ typedef struct {
 | 
			
		|||
 | 
			
		||||
#endif /* LPC17XX_EMAC_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 ------------------------------ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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 ------------------------------ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @}
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -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",
 | 
			
		||||
| 
						 | 
				
			
			@ -276,7 +276,7 @@
 | 
			
		|||
        "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"],
 | 
			
		||||
        "config": {
 | 
			
		||||
            "modem_is_on_board": {
 | 
			
		||||
                "help": "Value: Tells the build system that the modem is on-board as oppose to a plug-in shield/module.",
 | 
			
		||||
| 
						 | 
				
			
			@ -291,7 +291,7 @@
 | 
			
		|||
        },
 | 
			
		||||
        "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": {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue