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