NXP LPC1768 Ethernet driver for lwip and CMSIS-RTOS

Dependents:   EthernetInterface EthernetInterface EthernetInterface_RSF EthernetInterface ... more

Legacy Networking Libraries

This is an mbed 2 networking library. For mbed 5, the networking libraries have been revised to better support additional network stacks and thread safety here.

This library is based on the code of the NXP LPC port of the Lightweight TCP/IP Stack

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.
Committer:
emilmont
Date:
Mon Jun 03 12:06:46 2013 +0100
Revision:
6:59b01b9349d5
Parent:
5:698d868a5285
Child:
7:5754e05385b8
De-allocate all queued TX pbufs

Who changed what in which revision?

UserRevisionLine numberNew contents of line
emilmont 4:d827a085afd9 1 /**********************************************************************
emilmont 5:698d868a5285 2 * $Id$ lpc17_emac.c 2011-11-20
emilmont 4:d827a085afd9 3 *//**
emilmont 5:698d868a5285 4 * @file lpc17_emac.c
emilmont 5:698d868a5285 5 * @brief LPC17 ethernet driver for LWIP
emilmont 5:698d868a5285 6 * @version 1.0
emilmont 5:698d868a5285 7 * @date 20. Nov. 2011
emilmont 5:698d868a5285 8 * @author NXP MCU SW Application Team
emilmont 4:d827a085afd9 9 *
emilmont 4:d827a085afd9 10 * Copyright(C) 2011, NXP Semiconductor
emilmont 4:d827a085afd9 11 * All rights reserved.
emilmont 4:d827a085afd9 12 *
emilmont 4:d827a085afd9 13 ***********************************************************************
emilmont 4:d827a085afd9 14 * Software that is described herein is for illustrative purposes only
emilmont 4:d827a085afd9 15 * which provides customers with programming information regarding the
emilmont 4:d827a085afd9 16 * products. This software is supplied "AS IS" without any warranties.
emilmont 4:d827a085afd9 17 * NXP Semiconductors assumes no responsibility or liability for the
emilmont 4:d827a085afd9 18 * use of the software, conveys no license or title under any patent,
emilmont 4:d827a085afd9 19 * copyright, or mask work right to the product. NXP Semiconductors
emilmont 4:d827a085afd9 20 * reserves the right to make changes in the software without
emilmont 4:d827a085afd9 21 * notification. NXP Semiconductors also make no representation or
emilmont 4:d827a085afd9 22 * warranty that such application will be suitable for the specified
emilmont 4:d827a085afd9 23 * use without further testing or modification.
emilmont 4:d827a085afd9 24 **********************************************************************/
emilmont 4:d827a085afd9 25
emilmont 4:d827a085afd9 26 #include "lwip/opt.h"
emilmont 4:d827a085afd9 27 #include "lwip/sys.h"
emilmont 4:d827a085afd9 28 #include "lwip/def.h"
emilmont 4:d827a085afd9 29 #include "lwip/mem.h"
emilmont 4:d827a085afd9 30 #include "lwip/pbuf.h"
emilmont 4:d827a085afd9 31 #include "lwip/stats.h"
emilmont 4:d827a085afd9 32 #include "lwip/snmp.h"
emilmont 4:d827a085afd9 33 #include "netif/etharp.h"
emilmont 4:d827a085afd9 34 #include "netif/ppp_oe.h"
emilmont 4:d827a085afd9 35
emilmont 4:d827a085afd9 36 #include "lpc17xx_emac.h"
emilmont 4:d827a085afd9 37 #include "lpc17_emac.h"
emilmont 4:d827a085afd9 38 #include "lpc_emac_config.h"
emilmont 4:d827a085afd9 39 #include "lpc_phy.h"
emilmont 4:d827a085afd9 40 #include "sys_arch.h"
emilmont 4:d827a085afd9 41
emilmont 4:d827a085afd9 42 #include "mbed_interface.h"
emilmont 4:d827a085afd9 43 #include <string.h>
emilmont 4:d827a085afd9 44
emilmont 4:d827a085afd9 45 #ifndef LPC_EMAC_RMII
emilmont 4:d827a085afd9 46 #error LPC_EMAC_RMII is not defined!
emilmont 4:d827a085afd9 47 #endif
emilmont 4:d827a085afd9 48
emilmont 4:d827a085afd9 49 #if LPC_NUM_BUFF_TXDESCS < 2
emilmont 4:d827a085afd9 50 #error LPC_NUM_BUFF_TXDESCS must be at least 2
emilmont 4:d827a085afd9 51 #endif
emilmont 4:d827a085afd9 52
emilmont 4:d827a085afd9 53 #if LPC_NUM_BUFF_RXDESCS < 3
emilmont 4:d827a085afd9 54 #error LPC_NUM_BUFF_RXDESCS must be at least 3
emilmont 4:d827a085afd9 55 #endif
emilmont 4:d827a085afd9 56
emilmont 5:698d868a5285 57 /** @defgroup lwip17xx_emac_DRIVER lpc17 EMAC driver for LWIP
emilmont 4:d827a085afd9 58 * @ingroup lwip_emac
emilmont 4:d827a085afd9 59 *
emilmont 4:d827a085afd9 60 * @{
emilmont 4:d827a085afd9 61 */
emilmont 4:d827a085afd9 62
emilmont 4:d827a085afd9 63 #if NO_SYS == 0
emilmont 4:d827a085afd9 64 /** \brief Driver transmit and receive thread priorities
emilmont 4:d827a085afd9 65 *
emilmont 4:d827a085afd9 66 * Thread priorities for receive thread and TX cleanup thread. Alter
emilmont 4:d827a085afd9 67 * to prioritize receive or transmit bandwidth. In a heavily loaded
emilmont 4:d827a085afd9 68 * system or with LEIP_DEBUG enabled, the priorities might be better
emilmont 4:d827a085afd9 69 * the same. */
emilmont 4:d827a085afd9 70 #define RX_PRIORITY (osPriorityNormal)
emilmont 4:d827a085afd9 71 #define TX_PRIORITY (osPriorityNormal)
emilmont 4:d827a085afd9 72
emilmont 4:d827a085afd9 73 /** \brief Debug output formatter lock define
emilmont 4:d827a085afd9 74 *
emilmont 4:d827a085afd9 75 * When using FreeRTOS and with LWIP_DEBUG enabled, enabling this
emilmont 4:d827a085afd9 76 * define will allow RX debug messages to not interleave with the
emilmont 4:d827a085afd9 77 * TX messages (so they are actually readable). Not enabling this
emilmont 4:d827a085afd9 78 * define when the system is under load will cause the output to
emilmont 4:d827a085afd9 79 * be unreadable. There is a small tradeoff in performance for this
emilmont 4:d827a085afd9 80 * so use it only for debug. */
emilmont 4:d827a085afd9 81 //#define LOCK_RX_THREAD
emilmont 4:d827a085afd9 82
emilmont 4:d827a085afd9 83 /** \brief Receive group interrupts
emilmont 4:d827a085afd9 84 */
emilmont 4:d827a085afd9 85 #define RXINTGROUP (EMAC_INT_RX_OVERRUN | EMAC_INT_RX_ERR | EMAC_INT_RX_DONE)
emilmont 4:d827a085afd9 86
emilmont 4:d827a085afd9 87 /** \brief Transmit group interrupts
emilmont 4:d827a085afd9 88 */
emilmont 4:d827a085afd9 89 #define TXINTGROUP (EMAC_INT_TX_UNDERRUN | EMAC_INT_TX_ERR | EMAC_INT_TX_DONE)
emilmont 4:d827a085afd9 90
emilmont 4:d827a085afd9 91 #else
emilmont 4:d827a085afd9 92 #define RXINTGROUP 0
emilmont 4:d827a085afd9 93 #define TXINTGROUP 0
emilmont 4:d827a085afd9 94 #endif
emilmont 4:d827a085afd9 95
emilmont 4:d827a085afd9 96 /** \brief Structure of a TX/RX descriptor
emilmont 4:d827a085afd9 97 */
emilmont 4:d827a085afd9 98 typedef struct
emilmont 4:d827a085afd9 99 {
emilmont 5:698d868a5285 100 volatile u32_t packet; /**< Pointer to buffer */
emilmont 5:698d868a5285 101 volatile u32_t control; /**< Control word */
emilmont 4:d827a085afd9 102 } LPC_TXRX_DESC_T;
emilmont 4:d827a085afd9 103
emilmont 4:d827a085afd9 104 /** \brief Structure of a RX status entry
emilmont 4:d827a085afd9 105 */
emilmont 4:d827a085afd9 106 typedef struct
emilmont 4:d827a085afd9 107 {
emilmont 5:698d868a5285 108 volatile u32_t statusinfo; /**< RX status word */
emilmont 5:698d868a5285 109 volatile u32_t statushashcrc; /**< RX hash CRC */
emilmont 4:d827a085afd9 110 } LPC_TXRX_STATUS_T;
emilmont 4:d827a085afd9 111
emilmont 4:d827a085afd9 112 /* LPC EMAC driver data structure */
emilmont 4:d827a085afd9 113 struct lpc_enetdata {
emilmont 4:d827a085afd9 114 /* prxs must be 8 byte aligned! */
emilmont 5:698d868a5285 115 LPC_TXRX_STATUS_T prxs[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX statuses */
emilmont 5:698d868a5285 116 struct netif *netif; /**< Reference back to LWIP parent netif */
emilmont 5:698d868a5285 117 LPC_TXRX_DESC_T ptxd[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX descriptor list */
emilmont 5:698d868a5285 118 LPC_TXRX_STATUS_T ptxs[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX statuses */
emilmont 5:698d868a5285 119 LPC_TXRX_DESC_T prxd[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX descriptor list */
emilmont 5:698d868a5285 120 struct pbuf *rxb[LPC_NUM_BUFF_RXDESCS]; /**< RX pbuf pointer list, zero-copy mode */
emilmont 5:698d868a5285 121 u32_t rx_fill_desc_index; /**< RX descriptor next available index */
emilmont 5:698d868a5285 122 volatile u32_t rx_free_descs; /**< Count of free RX descriptors */
emilmont 5:698d868a5285 123 struct pbuf *txb[LPC_NUM_BUFF_TXDESCS]; /**< TX pbuf pointer list, zero-copy mode */
emilmont 5:698d868a5285 124 u32_t lpc_last_tx_idx; /**< TX last descriptor index, zero-copy mode */
emilmont 4:d827a085afd9 125 #if NO_SYS == 0
emilmont 5:698d868a5285 126 sys_sem_t RxSem; /**< RX receive thread wakeup semaphore */
emilmont 5:698d868a5285 127 sys_sem_t TxCleanSem; /**< TX cleanup thread wakeup semaphore */
emilmont 5:698d868a5285 128 sys_mutex_t TXLockMutex; /**< TX critical section mutex */
emilmont 5:698d868a5285 129 sys_sem_t xTXDCountSem; /**< TX free buffer counting semaphore */
emilmont 4:d827a085afd9 130 #endif
emilmont 4:d827a085afd9 131 };
emilmont 4:d827a085afd9 132
emilmont 5:698d868a5285 133 #if defined(TARGET_LPC4088)
emilmont 5:698d868a5285 134 # if defined (__ICCARM__)
emilmont 5:698d868a5285 135 # define ETHMEM_SECTION
emilmont 5:698d868a5285 136 # elif defined(TOOLCHAIN_GCC_CR)
emilmont 5:698d868a5285 137 # define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32")))
emilmont 5:698d868a5285 138 # else
emilmont 5:698d868a5285 139 # define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned))
emilmont 5:698d868a5285 140 # endif
emilmont 5:698d868a5285 141 #else
emilmont 5:698d868a5285 142 # define ETHMEM_SECTION ALIGNED(8)
emilmont 5:698d868a5285 143 #endif
emilmont 5:698d868a5285 144
emilmont 4:d827a085afd9 145 /** \brief LPC EMAC driver work data
emilmont 4:d827a085afd9 146 */
emilmont 5:698d868a5285 147 ETHMEM_SECTION struct lpc_enetdata lpc_enetdata;
emilmont 4:d827a085afd9 148
emilmont 4:d827a085afd9 149 /* Write a value via the MII link (non-blocking) */
emilmont 4:d827a085afd9 150 void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value)
emilmont 4:d827a085afd9 151 {
emilmont 5:698d868a5285 152 /* Write value at PHY address and register */
emilmont 5:698d868a5285 153 LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg;
emilmont 5:698d868a5285 154 LPC_EMAC->MWTD = Value;
emilmont 4:d827a085afd9 155 }
emilmont 4:d827a085afd9 156
emilmont 4:d827a085afd9 157 /* Write a value via the MII link (blocking) */
emilmont 4:d827a085afd9 158 err_t lpc_mii_write(u32_t PhyReg, u32_t Value)
emilmont 4:d827a085afd9 159 {
emilmont 5:698d868a5285 160 u32_t mst = 250;
emilmont 5:698d868a5285 161 err_t sts = ERR_OK;
emilmont 4:d827a085afd9 162
emilmont 5:698d868a5285 163 /* Write value at PHY address and register */
emilmont 5:698d868a5285 164 lpc_mii_write_noblock(PhyReg, Value);
emilmont 4:d827a085afd9 165
emilmont 5:698d868a5285 166 /* Wait for unbusy status */
emilmont 5:698d868a5285 167 while (mst > 0) {
emilmont 5:698d868a5285 168 sts = LPC_EMAC->MIND;
emilmont 5:698d868a5285 169 if ((sts & EMAC_MIND_BUSY) == 0)
emilmont 5:698d868a5285 170 mst = 0;
emilmont 5:698d868a5285 171 else {
emilmont 5:698d868a5285 172 mst--;
emilmont 5:698d868a5285 173 osDelay(1);
emilmont 5:698d868a5285 174 }
emilmont 5:698d868a5285 175 }
emilmont 4:d827a085afd9 176
emilmont 5:698d868a5285 177 if (sts != 0)
emilmont 5:698d868a5285 178 sts = ERR_TIMEOUT;
emilmont 4:d827a085afd9 179
emilmont 5:698d868a5285 180 return sts;
emilmont 4:d827a085afd9 181 }
emilmont 4:d827a085afd9 182
emilmont 4:d827a085afd9 183 /* Reads current MII link busy status */
emilmont 4:d827a085afd9 184 u32_t lpc_mii_is_busy(void)
emilmont 4:d827a085afd9 185 {
emilmont 5:698d868a5285 186 return (u32_t) (LPC_EMAC->MIND & EMAC_MIND_BUSY);
emilmont 4:d827a085afd9 187 }
emilmont 4:d827a085afd9 188
emilmont 4:d827a085afd9 189 /* Starts a read operation via the MII link (non-blocking) */
emilmont 4:d827a085afd9 190 u32_t lpc_mii_read_data(void)
emilmont 4:d827a085afd9 191 {
emilmont 5:698d868a5285 192 u32_t data = LPC_EMAC->MRDD;
emilmont 5:698d868a5285 193 LPC_EMAC->MCMD = 0;
emilmont 4:d827a085afd9 194
emilmont 5:698d868a5285 195 return data;
emilmont 4:d827a085afd9 196 }
emilmont 4:d827a085afd9 197
emilmont 4:d827a085afd9 198 /* Starts a read operation via the MII link (non-blocking) */
emilmont 4:d827a085afd9 199 void lpc_mii_read_noblock(u32_t PhyReg)
emilmont 4:d827a085afd9 200 {
emilmont 5:698d868a5285 201 /* Read value at PHY address and register */
emilmont 5:698d868a5285 202 LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg;
emilmont 5:698d868a5285 203 LPC_EMAC->MCMD = EMAC_MCMD_READ;
emilmont 4:d827a085afd9 204 }
emilmont 4:d827a085afd9 205
emilmont 4:d827a085afd9 206 /* Read a value via the MII link (blocking) */
emilmont 4:d827a085afd9 207 err_t lpc_mii_read(u32_t PhyReg, u32_t *data)
emilmont 4:d827a085afd9 208 {
emilmont 5:698d868a5285 209 u32_t mst = 250;
emilmont 5:698d868a5285 210 err_t sts = ERR_OK;
emilmont 4:d827a085afd9 211
emilmont 5:698d868a5285 212 /* Read value at PHY address and register */
emilmont 5:698d868a5285 213 lpc_mii_read_noblock(PhyReg);
emilmont 4:d827a085afd9 214
emilmont 5:698d868a5285 215 /* Wait for unbusy status */
emilmont 5:698d868a5285 216 while (mst > 0) {
emilmont 5:698d868a5285 217 sts = LPC_EMAC->MIND & ~EMAC_MIND_MII_LINK_FAIL;
emilmont 5:698d868a5285 218 if ((sts & EMAC_MIND_BUSY) == 0) {
emilmont 5:698d868a5285 219 mst = 0;
emilmont 5:698d868a5285 220 *data = LPC_EMAC->MRDD;
emilmont 5:698d868a5285 221 } else {
emilmont 5:698d868a5285 222 mst--;
emilmont 5:698d868a5285 223 osDelay(1);
emilmont 5:698d868a5285 224 }
emilmont 5:698d868a5285 225 }
emilmont 4:d827a085afd9 226
emilmont 5:698d868a5285 227 LPC_EMAC->MCMD = 0;
emilmont 4:d827a085afd9 228
emilmont 5:698d868a5285 229 if (sts != 0)
emilmont 5:698d868a5285 230 sts = ERR_TIMEOUT;
emilmont 4:d827a085afd9 231
emilmont 5:698d868a5285 232 return sts;
emilmont 4:d827a085afd9 233 }
emilmont 4:d827a085afd9 234
emilmont 4:d827a085afd9 235 /** \brief Queues a pbuf into the RX descriptor list
emilmont 4:d827a085afd9 236 *
emilmont 4:d827a085afd9 237 * \param[in] lpc_enetif Pointer to the drvier data structure
emilmont 4:d827a085afd9 238 * \param[in] p Pointer to pbuf to queue
emilmont 4:d827a085afd9 239 */
emilmont 4:d827a085afd9 240 static void lpc_rxqueue_pbuf(struct lpc_enetdata *lpc_enetif, struct pbuf *p)
emilmont 4:d827a085afd9 241 {
emilmont 5:698d868a5285 242 u32_t idx;
emilmont 4:d827a085afd9 243
emilmont 5:698d868a5285 244 /* Get next free descriptor index */
emilmont 5:698d868a5285 245 idx = lpc_enetif->rx_fill_desc_index;
emilmont 4:d827a085afd9 246
emilmont 5:698d868a5285 247 /* Setup descriptor and clear statuses */
emilmont 5:698d868a5285 248 lpc_enetif->prxd[idx].control = EMAC_RCTRL_INT | ((u32_t) (p->len - 1));
emilmont 5:698d868a5285 249 lpc_enetif->prxd[idx].packet = (u32_t) p->payload;
emilmont 5:698d868a5285 250 lpc_enetif->prxs[idx].statusinfo = 0xFFFFFFFF;
emilmont 5:698d868a5285 251 lpc_enetif->prxs[idx].statushashcrc = 0xFFFFFFFF;
emilmont 4:d827a085afd9 252
emilmont 5:698d868a5285 253 /* Save pbuf pointer for push to network layer later */
emilmont 5:698d868a5285 254 lpc_enetif->rxb[idx] = p;
emilmont 4:d827a085afd9 255
emilmont 5:698d868a5285 256 /* Wrap at end of descriptor list */
emilmont 5:698d868a5285 257 idx++;
emilmont 5:698d868a5285 258 if (idx >= LPC_NUM_BUFF_RXDESCS)
emilmont 5:698d868a5285 259 idx = 0;
emilmont 4:d827a085afd9 260
emilmont 5:698d868a5285 261 /* Queue descriptor(s) */
emilmont 5:698d868a5285 262 lpc_enetif->rx_free_descs -= 1;
emilmont 5:698d868a5285 263 lpc_enetif->rx_fill_desc_index = idx;
emilmont 5:698d868a5285 264 LPC_EMAC->RxConsumeIndex = idx;
emilmont 4:d827a085afd9 265
emilmont 5:698d868a5285 266 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
emilmont 5:698d868a5285 267 ("lpc_rxqueue_pbuf: pbuf packet queued: %p (free desc=%d)\n", p,
emilmont 5:698d868a5285 268 lpc_enetif->rx_free_descs));
emilmont 4:d827a085afd9 269 }
emilmont 4:d827a085afd9 270
emilmont 4:d827a085afd9 271 /** \brief Attempt to allocate and requeue a new pbuf for RX
emilmont 4:d827a085afd9 272 *
emilmont 4:d827a085afd9 273 * \param[in] netif Pointer to the netif structure
emilmont 4:d827a085afd9 274 * \returns 1 if a packet was allocated and requeued, otherwise 0
emilmont 4:d827a085afd9 275 */
emilmont 4:d827a085afd9 276 s32_t lpc_rx_queue(struct netif *netif)
emilmont 4:d827a085afd9 277 {
emilmont 5:698d868a5285 278 struct lpc_enetdata *lpc_enetif = netif->state;
emilmont 5:698d868a5285 279 struct pbuf *p;
emilmont 5:698d868a5285 280 s32_t queued = 0;
emilmont 4:d827a085afd9 281
emilmont 5:698d868a5285 282 /* Attempt to requeue as many packets as possible */
emilmont 5:698d868a5285 283 while (lpc_enetif->rx_free_descs > 0) {
emilmont 5:698d868a5285 284 /* Allocate a pbuf from the pool. We need to allocate at the
emilmont 5:698d868a5285 285 maximum size as we don't know the size of the yet to be
emilmont 5:698d868a5285 286 received packet. */
emilmont 5:698d868a5285 287 p = pbuf_alloc(PBUF_RAW, (u16_t) EMAC_ETH_MAX_FLEN, PBUF_RAM);
emilmont 5:698d868a5285 288 if (p == NULL) {
emilmont 5:698d868a5285 289 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
emilmont 5:698d868a5285 290 ("lpc_rx_queue: could not allocate RX pbuf (free desc=%d)\n",
emilmont 5:698d868a5285 291 lpc_enetif->rx_free_descs));
emilmont 5:698d868a5285 292 return queued;
emilmont 5:698d868a5285 293 }
emilmont 4:d827a085afd9 294
emilmont 5:698d868a5285 295 /* pbufs allocated from the RAM pool should be non-chained. */
emilmont 5:698d868a5285 296 LWIP_ASSERT("lpc_rx_queue: pbuf is not contiguous (chained)",
emilmont 5:698d868a5285 297 pbuf_clen(p) <= 1);
emilmont 4:d827a085afd9 298
emilmont 5:698d868a5285 299 /* Queue packet */
emilmont 5:698d868a5285 300 lpc_rxqueue_pbuf(lpc_enetif, p);
emilmont 4:d827a085afd9 301
emilmont 5:698d868a5285 302 /* Update queued count */
emilmont 5:698d868a5285 303 queued++;
emilmont 5:698d868a5285 304 }
emilmont 4:d827a085afd9 305
emilmont 5:698d868a5285 306 return queued;
emilmont 4:d827a085afd9 307 }
emilmont 4:d827a085afd9 308
emilmont 4:d827a085afd9 309 /** \brief Sets up the RX descriptor ring buffers.
emilmont 4:d827a085afd9 310 *
emilmont 4:d827a085afd9 311 * This function sets up the descriptor list used for receive packets.
emilmont 4:d827a085afd9 312 *
emilmont 4:d827a085afd9 313 * \param[in] lpc_enetif Pointer to driver data structure
emilmont 4:d827a085afd9 314 * \returns Always returns ERR_OK
emilmont 4:d827a085afd9 315 */
emilmont 4:d827a085afd9 316 static err_t lpc_rx_setup(struct lpc_enetdata *lpc_enetif)
emilmont 4:d827a085afd9 317 {
emilmont 5:698d868a5285 318 /* Setup pointers to RX structures */
emilmont 5:698d868a5285 319 LPC_EMAC->RxDescriptor = (u32_t) &lpc_enetif->prxd[0];
emilmont 5:698d868a5285 320 LPC_EMAC->RxStatus = (u32_t) &lpc_enetif->prxs[0];
emilmont 5:698d868a5285 321 LPC_EMAC->RxDescriptorNumber = LPC_NUM_BUFF_RXDESCS - 1;
emilmont 4:d827a085afd9 322
emilmont 5:698d868a5285 323 lpc_enetif->rx_free_descs = LPC_NUM_BUFF_RXDESCS;
emilmont 5:698d868a5285 324 lpc_enetif->rx_fill_desc_index = 0;
emilmont 4:d827a085afd9 325
emilmont 5:698d868a5285 326 /* Build RX buffer and descriptors */
emilmont 5:698d868a5285 327 lpc_rx_queue(lpc_enetif->netif);
emilmont 4:d827a085afd9 328
emilmont 5:698d868a5285 329 return ERR_OK;
emilmont 4:d827a085afd9 330 }
emilmont 4:d827a085afd9 331
emilmont 4:d827a085afd9 332 /** \brief Allocates a pbuf and returns the data from the incoming packet.
emilmont 4:d827a085afd9 333 *
emilmont 4:d827a085afd9 334 * \param[in] netif the lwip network interface structure for this lpc_enetif
emilmont 4:d827a085afd9 335 * \return a pbuf filled with the received packet (including MAC header)
emilmont 4:d827a085afd9 336 * NULL on memory error
emilmont 4:d827a085afd9 337 */
emilmont 4:d827a085afd9 338 static struct pbuf *lpc_low_level_input(struct netif *netif)
emilmont 4:d827a085afd9 339 {
emilmont 5:698d868a5285 340 struct lpc_enetdata *lpc_enetif = netif->state;
emilmont 5:698d868a5285 341 struct pbuf *p = NULL;
emilmont 5:698d868a5285 342 u32_t idx, length;
emilmont 4:d827a085afd9 343
emilmont 4:d827a085afd9 344 #ifdef LOCK_RX_THREAD
emilmont 4:d827a085afd9 345 #if NO_SYS == 0
emilmont 5:698d868a5285 346 /* Get exclusive access */
emilmont 5:698d868a5285 347 sys_mutex_lock(&lpc_enetif->TXLockMutex);
emilmont 4:d827a085afd9 348 #endif
emilmont 4:d827a085afd9 349 #endif
emilmont 4:d827a085afd9 350
emilmont 5:698d868a5285 351 /* Monitor RX overrun status. This should never happen unless
emilmont 5:698d868a5285 352 (possibly) the internal bus is behing held up by something.
emilmont 5:698d868a5285 353 Unless your system is running at a very low clock speed or
emilmont 5:698d868a5285 354 there are possibilities that the internal buses may be held
emilmont 5:698d868a5285 355 up for a long time, this can probably safely be removed. */
emilmont 5:698d868a5285 356 if (LPC_EMAC->IntStatus & EMAC_INT_RX_OVERRUN) {
emilmont 5:698d868a5285 357 LINK_STATS_INC(link.err);
emilmont 5:698d868a5285 358 LINK_STATS_INC(link.drop);
emilmont 4:d827a085afd9 359
emilmont 5:698d868a5285 360 /* Temporarily disable RX */
emilmont 5:698d868a5285 361 LPC_EMAC->MAC1 &= ~EMAC_MAC1_REC_EN;
emilmont 4:d827a085afd9 362
emilmont 5:698d868a5285 363 /* Reset the RX side */
emilmont 5:698d868a5285 364 LPC_EMAC->MAC1 |= EMAC_MAC1_RES_RX;
emilmont 5:698d868a5285 365 LPC_EMAC->IntClear = EMAC_INT_RX_OVERRUN;
emilmont 4:d827a085afd9 366
emilmont 5:698d868a5285 367 /* De-allocate all queued RX pbufs */
emilmont 5:698d868a5285 368 for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) {
emilmont 5:698d868a5285 369 if (lpc_enetif->rxb[idx] != NULL) {
emilmont 5:698d868a5285 370 pbuf_free(lpc_enetif->rxb[idx]);
emilmont 5:698d868a5285 371 lpc_enetif->rxb[idx] = NULL;
emilmont 5:698d868a5285 372 }
emilmont 5:698d868a5285 373 }
emilmont 4:d827a085afd9 374
emilmont 5:698d868a5285 375 /* Start RX side again */
emilmont 5:698d868a5285 376 lpc_rx_setup(lpc_enetif);
emilmont 4:d827a085afd9 377
emilmont 5:698d868a5285 378 /* Re-enable RX */
emilmont 5:698d868a5285 379 LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
emilmont 4:d827a085afd9 380
emilmont 4:d827a085afd9 381 #ifdef LOCK_RX_THREAD
emilmont 4:d827a085afd9 382 #if NO_SYS == 0
emilmont 5:698d868a5285 383 sys_mutex_unlock(&lpc_enetif->TXLockMutex);
emilmont 4:d827a085afd9 384 #endif
emilmont 4:d827a085afd9 385 #endif
emilmont 4:d827a085afd9 386
emilmont 5:698d868a5285 387 return NULL;
emilmont 5:698d868a5285 388 }
emilmont 4:d827a085afd9 389
emilmont 5:698d868a5285 390 /* Determine if a frame has been received */
emilmont 5:698d868a5285 391 length = 0;
emilmont 5:698d868a5285 392 idx = LPC_EMAC->RxConsumeIndex;
emilmont 5:698d868a5285 393 if (LPC_EMAC->RxProduceIndex != idx) {
emilmont 5:698d868a5285 394 /* Handle errors */
emilmont 5:698d868a5285 395 if (lpc_enetif->prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR |
emilmont 5:698d868a5285 396 EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR | EMAC_RINFO_LEN_ERR)) {
emilmont 4:d827a085afd9 397 #if LINK_STATS
emilmont 5:698d868a5285 398 if (lpc_enetif->prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR |
emilmont 5:698d868a5285 399 EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR))
emilmont 5:698d868a5285 400 LINK_STATS_INC(link.chkerr);
emilmont 5:698d868a5285 401 if (lpc_enetif->prxs[idx].statusinfo & EMAC_RINFO_LEN_ERR)
emilmont 5:698d868a5285 402 LINK_STATS_INC(link.lenerr);
emilmont 4:d827a085afd9 403 #endif
emilmont 4:d827a085afd9 404
emilmont 5:698d868a5285 405 /* Drop the frame */
emilmont 5:698d868a5285 406 LINK_STATS_INC(link.drop);
emilmont 4:d827a085afd9 407
emilmont 5:698d868a5285 408 /* Re-queue the pbuf for receive */
emilmont 5:698d868a5285 409 lpc_enetif->rx_free_descs++;
emilmont 5:698d868a5285 410 p = lpc_enetif->rxb[idx];
emilmont 5:698d868a5285 411 lpc_enetif->rxb[idx] = NULL;
emilmont 5:698d868a5285 412 lpc_rxqueue_pbuf(lpc_enetif, p);
emilmont 4:d827a085afd9 413
emilmont 5:698d868a5285 414 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
emilmont 5:698d868a5285 415 ("lpc_low_level_input: Packet dropped with errors (0x%x)\n",
emilmont 5:698d868a5285 416 lpc_enetif->prxs[idx].statusinfo));
emilmont 5:698d868a5285 417
emilmont 5:698d868a5285 418 p = NULL;
emilmont 5:698d868a5285 419 } else {
emilmont 5:698d868a5285 420 /* A packet is waiting, get length */
emilmont 5:698d868a5285 421 length = (lpc_enetif->prxs[idx].statusinfo & 0x7FF) + 1;
emilmont 4:d827a085afd9 422
emilmont 5:698d868a5285 423 /* Zero-copy */
emilmont 5:698d868a5285 424 p = lpc_enetif->rxb[idx];
emilmont 5:698d868a5285 425 p->len = (u16_t) length;
emilmont 4:d827a085afd9 426
emilmont 5:698d868a5285 427 /* Free pbuf from desriptor */
emilmont 5:698d868a5285 428 lpc_enetif->rxb[idx] = NULL;
emilmont 5:698d868a5285 429 lpc_enetif->rx_free_descs++;
emilmont 4:d827a085afd9 430
emilmont 5:698d868a5285 431 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
emilmont 5:698d868a5285 432 ("lpc_low_level_input: Packet received: %p, size %d (index=%d)\n",
emilmont 5:698d868a5285 433 p, length, idx));
emilmont 4:d827a085afd9 434
emilmont 5:698d868a5285 435 /* Save size */
emilmont 5:698d868a5285 436 p->tot_len = (u16_t) length;
emilmont 5:698d868a5285 437 LINK_STATS_INC(link.recv);
emilmont 4:d827a085afd9 438
emilmont 5:698d868a5285 439 /* Queue new buffer(s) */
emilmont 5:698d868a5285 440 lpc_rx_queue(lpc_enetif->netif);
emilmont 5:698d868a5285 441 }
emilmont 5:698d868a5285 442 }
emilmont 4:d827a085afd9 443
emilmont 4:d827a085afd9 444 #ifdef LOCK_RX_THREAD
emilmont 4:d827a085afd9 445 #if NO_SYS == 0
emilmont 5:698d868a5285 446 sys_mutex_unlock(&lpc_enetif->TXLockMutex);
emilmont 4:d827a085afd9 447 #endif
emilmont 4:d827a085afd9 448 #endif
emilmont 4:d827a085afd9 449
emilmont 5:698d868a5285 450 return p;
emilmont 4:d827a085afd9 451 }
emilmont 4:d827a085afd9 452
emilmont 4:d827a085afd9 453 /** \brief Attempt to read a packet from the EMAC interface.
emilmont 4:d827a085afd9 454 *
emilmont 4:d827a085afd9 455 * \param[in] netif the lwip network interface structure for this lpc_enetif
emilmont 4:d827a085afd9 456 */
emilmont 4:d827a085afd9 457 void lpc_enetif_input(struct netif *netif)
emilmont 4:d827a085afd9 458 {
emilmont 5:698d868a5285 459 struct eth_hdr *ethhdr;
emilmont 5:698d868a5285 460 struct pbuf *p;
emilmont 4:d827a085afd9 461
emilmont 5:698d868a5285 462 /* move received packet into a new pbuf */
emilmont 5:698d868a5285 463 p = lpc_low_level_input(netif);
emilmont 5:698d868a5285 464 if (p == NULL)
emilmont 5:698d868a5285 465 return;
emilmont 4:d827a085afd9 466
emilmont 5:698d868a5285 467 /* points to packet payload, which starts with an Ethernet header */
emilmont 5:698d868a5285 468 ethhdr = p->payload;
emilmont 4:d827a085afd9 469
emilmont 5:698d868a5285 470 switch (htons(ethhdr->type)) {
emilmont 5:698d868a5285 471 case ETHTYPE_IP:
emilmont 5:698d868a5285 472 case ETHTYPE_ARP:
emilmont 4:d827a085afd9 473 #if PPPOE_SUPPORT
emilmont 5:698d868a5285 474 case ETHTYPE_PPPOEDISC:
emilmont 5:698d868a5285 475 case ETHTYPE_PPPOE:
emilmont 4:d827a085afd9 476 #endif /* PPPOE_SUPPORT */
emilmont 5:698d868a5285 477 /* full packet send to tcpip_thread to process */
emilmont 5:698d868a5285 478 if (netif->input(p, netif) != ERR_OK) {
emilmont 5:698d868a5285 479 LWIP_DEBUGF(NETIF_DEBUG, ("lpc_enetif_input: IP input error\n"));
emilmont 5:698d868a5285 480 /* Free buffer */
emilmont 5:698d868a5285 481 pbuf_free(p);
emilmont 5:698d868a5285 482 }
emilmont 5:698d868a5285 483 break;
emilmont 4:d827a085afd9 484
emilmont 5:698d868a5285 485 default:
emilmont 5:698d868a5285 486 /* Return buffer */
emilmont 5:698d868a5285 487 pbuf_free(p);
emilmont 5:698d868a5285 488 break;
emilmont 5:698d868a5285 489 }
emilmont 4:d827a085afd9 490 }
emilmont 4:d827a085afd9 491
emilmont 4:d827a085afd9 492 /** \brief Determine if the passed address is usable for the ethernet
emilmont 4:d827a085afd9 493 * DMA controller.
emilmont 4:d827a085afd9 494 *
emilmont 4:d827a085afd9 495 * \param[in] addr Address of packet to check for DMA safe operation
emilmont 4:d827a085afd9 496 * \return 1 if the packet address is not safe, otherwise 0
emilmont 4:d827a085afd9 497 */
emilmont 4:d827a085afd9 498 static s32_t lpc_packet_addr_notsafe(void *addr) {
emilmont 5:698d868a5285 499 /* Check for legal address ranges */
emilmont 5:698d868a5285 500 #if defined(TARGET_LPC1768)
emilmont 5:698d868a5285 501 if ((((u32_t) addr >= 0x2007C000) && ((u32_t) addr < 0x20083FFF))) {
emilmont 5:698d868a5285 502 #elif defined(TARGET_LPC4088)
emilmont 5:698d868a5285 503 if ((((u32_t) addr >= 0x20000000) && ((u32_t) addr < 0x20007FFF))) {
emilmont 5:698d868a5285 504 #endif
emilmont 5:698d868a5285 505 return 0;
emilmont 5:698d868a5285 506 }
emilmont 5:698d868a5285 507 return 1;
emilmont 4:d827a085afd9 508 }
emilmont 4:d827a085afd9 509
emilmont 4:d827a085afd9 510 /** \brief Sets up the TX descriptor ring buffers.
emilmont 4:d827a085afd9 511 *
emilmont 4:d827a085afd9 512 * This function sets up the descriptor list used for transmit packets.
emilmont 4:d827a085afd9 513 *
emilmont 4:d827a085afd9 514 * \param[in] lpc_enetif Pointer to driver data structure
emilmont 4:d827a085afd9 515 */
emilmont 4:d827a085afd9 516 static err_t lpc_tx_setup(struct lpc_enetdata *lpc_enetif)
emilmont 4:d827a085afd9 517 {
emilmont 5:698d868a5285 518 s32_t idx;
emilmont 4:d827a085afd9 519
emilmont 5:698d868a5285 520 /* Build TX descriptors for local buffers */
emilmont 5:698d868a5285 521 for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) {
emilmont 5:698d868a5285 522 lpc_enetif->ptxd[idx].control = 0;
emilmont 5:698d868a5285 523 lpc_enetif->ptxs[idx].statusinfo = 0xFFFFFFFF;
emilmont 5:698d868a5285 524 }
emilmont 4:d827a085afd9 525
emilmont 5:698d868a5285 526 /* Setup pointers to TX structures */
emilmont 5:698d868a5285 527 LPC_EMAC->TxDescriptor = (u32_t) &lpc_enetif->ptxd[0];
emilmont 5:698d868a5285 528 LPC_EMAC->TxStatus = (u32_t) &lpc_enetif->ptxs[0];
emilmont 5:698d868a5285 529 LPC_EMAC->TxDescriptorNumber = LPC_NUM_BUFF_TXDESCS - 1;
emilmont 4:d827a085afd9 530
emilmont 5:698d868a5285 531 lpc_enetif->lpc_last_tx_idx = 0;
emilmont 4:d827a085afd9 532
emilmont 5:698d868a5285 533 return ERR_OK;
emilmont 4:d827a085afd9 534 }
emilmont 4:d827a085afd9 535
emilmont 4:d827a085afd9 536 /** \brief Free TX buffers that are complete
emilmont 4:d827a085afd9 537 *
emilmont 4:d827a085afd9 538 * \param[in] lpc_enetif Pointer to driver data structure
emilmont 4:d827a085afd9 539 * \param[in] cidx EMAC current descriptor comsumer index
emilmont 4:d827a085afd9 540 */
emilmont 4:d827a085afd9 541 static void lpc_tx_reclaim_st(struct lpc_enetdata *lpc_enetif, u32_t cidx)
emilmont 4:d827a085afd9 542 {
emilmont 4:d827a085afd9 543 #if NO_SYS == 0
emilmont 5:698d868a5285 544 /* Get exclusive access */
emilmont 5:698d868a5285 545 sys_mutex_lock(&lpc_enetif->TXLockMutex);
emilmont 4:d827a085afd9 546 #endif
emilmont 4:d827a085afd9 547
emilmont 5:698d868a5285 548 while (cidx != lpc_enetif->lpc_last_tx_idx) {
emilmont 5:698d868a5285 549 if (lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] != NULL) {
emilmont 5:698d868a5285 550 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
emilmont 5:698d868a5285 551 ("lpc_tx_reclaim_st: Freeing packet %p (index %d)\n",
emilmont 5:698d868a5285 552 lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx],
emilmont 5:698d868a5285 553 lpc_enetif->lpc_last_tx_idx));
emilmont 5:698d868a5285 554 pbuf_free(lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx]);
emilmont 5:698d868a5285 555 lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] = NULL;
emilmont 5:698d868a5285 556 }
emilmont 4:d827a085afd9 557
emilmont 4:d827a085afd9 558 #if NO_SYS == 0
emilmont 5:698d868a5285 559 osSemaphoreRelease(lpc_enetif->xTXDCountSem.id);
emilmont 4:d827a085afd9 560 #endif
emilmont 5:698d868a5285 561 lpc_enetif->lpc_last_tx_idx++;
emilmont 5:698d868a5285 562 if (lpc_enetif->lpc_last_tx_idx >= LPC_NUM_BUFF_TXDESCS)
emilmont 5:698d868a5285 563 lpc_enetif->lpc_last_tx_idx = 0;
emilmont 5:698d868a5285 564 }
emilmont 4:d827a085afd9 565
emilmont 4:d827a085afd9 566 #if NO_SYS == 0
emilmont 5:698d868a5285 567 /* Restore access */
emilmont 5:698d868a5285 568 sys_mutex_unlock(&lpc_enetif->TXLockMutex);
emilmont 4:d827a085afd9 569 #endif
emilmont 4:d827a085afd9 570 }
emilmont 4:d827a085afd9 571
emilmont 4:d827a085afd9 572 /** \brief User call for freeingTX buffers that are complete
emilmont 4:d827a085afd9 573 *
emilmont 4:d827a085afd9 574 * \param[in] netif the lwip network interface structure for this lpc_enetif
emilmont 4:d827a085afd9 575 */
emilmont 4:d827a085afd9 576 void lpc_tx_reclaim(struct netif *netif)
emilmont 4:d827a085afd9 577 {
emilmont 5:698d868a5285 578 lpc_tx_reclaim_st((struct lpc_enetdata *) netif->state,
emilmont 5:698d868a5285 579 LPC_EMAC->TxConsumeIndex);
emilmont 4:d827a085afd9 580 }
emilmont 4:d827a085afd9 581
emilmont 4:d827a085afd9 582 /** \brief Polls if an available TX descriptor is ready. Can be used to
emilmont 4:d827a085afd9 583 * determine if the low level transmit function will block.
emilmont 4:d827a085afd9 584 *
emilmont 4:d827a085afd9 585 * \param[in] netif the lwip network interface structure for this lpc_enetif
emilmont 4:d827a085afd9 586 * \return 0 if no descriptors are read, or >0
emilmont 4:d827a085afd9 587 */
emilmont 4:d827a085afd9 588 s32_t lpc_tx_ready(struct netif *netif)
emilmont 4:d827a085afd9 589 {
emilmont 5:698d868a5285 590 s32_t fb;
emilmont 5:698d868a5285 591 u32_t idx, cidx;
emilmont 4:d827a085afd9 592
emilmont 5:698d868a5285 593 cidx = LPC_EMAC->TxConsumeIndex;
emilmont 5:698d868a5285 594 idx = LPC_EMAC->TxProduceIndex;
emilmont 4:d827a085afd9 595
emilmont 5:698d868a5285 596 /* Determine number of free buffers */
emilmont 5:698d868a5285 597 if (idx == cidx)
emilmont 5:698d868a5285 598 fb = LPC_NUM_BUFF_TXDESCS;
emilmont 5:698d868a5285 599 else if (cidx > idx)
emilmont 5:698d868a5285 600 fb = (LPC_NUM_BUFF_TXDESCS - 1) -
emilmont 5:698d868a5285 601 ((idx + LPC_NUM_BUFF_TXDESCS) - cidx);
emilmont 5:698d868a5285 602 else
emilmont 5:698d868a5285 603 fb = (LPC_NUM_BUFF_TXDESCS - 1) - (cidx - idx);
emilmont 4:d827a085afd9 604
emilmont 5:698d868a5285 605 return fb;
emilmont 4:d827a085afd9 606 }
emilmont 4:d827a085afd9 607
emilmont 4:d827a085afd9 608 /** \brief Low level output of a packet. Never call this from an
emilmont 4:d827a085afd9 609 * interrupt context, as it may block until TX descriptors
emilmont 4:d827a085afd9 610 * become available.
emilmont 4:d827a085afd9 611 *
emilmont 4:d827a085afd9 612 * \param[in] netif the lwip network interface structure for this lpc_enetif
emilmont 4:d827a085afd9 613 * \param[in] p the MAC packet to send (e.g. IP packet including MAC addresses and type)
emilmont 4:d827a085afd9 614 * \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent
emilmont 4:d827a085afd9 615 */
emilmont 4:d827a085afd9 616 static err_t lpc_low_level_output(struct netif *netif, struct pbuf *p)
emilmont 4:d827a085afd9 617 {
emilmont 5:698d868a5285 618 struct lpc_enetdata *lpc_enetif = netif->state;
emilmont 5:698d868a5285 619 struct pbuf *q;
emilmont 5:698d868a5285 620 u8_t *dst;
emilmont 4:d827a085afd9 621 u32_t idx;
emilmont 5:698d868a5285 622 struct pbuf *np;
emilmont 5:698d868a5285 623 u32_t dn, notdmasafe = 0;
emilmont 4:d827a085afd9 624
emilmont 5:698d868a5285 625 /* Zero-copy TX buffers may be fragmented across mutliple payload
emilmont 5:698d868a5285 626 chains. Determine the number of descriptors needed for the
emilmont 5:698d868a5285 627 transfer. The pbuf chaining can be a mess! */
emilmont 5:698d868a5285 628 dn = (u32_t) pbuf_clen(p);
emilmont 4:d827a085afd9 629
emilmont 5:698d868a5285 630 /* Test to make sure packet addresses are DMA safe. A DMA safe
emilmont 5:698d868a5285 631 address is once that uses external memory or periphheral RAM.
emilmont 5:698d868a5285 632 IRAM and FLASH are not safe! */
emilmont 5:698d868a5285 633 for (q = p; q != NULL; q = q->next)
emilmont 5:698d868a5285 634 notdmasafe += lpc_packet_addr_notsafe(q->payload);
emilmont 4:d827a085afd9 635
emilmont 4:d827a085afd9 636 #if LPC_TX_PBUF_BOUNCE_EN==1
emilmont 5:698d868a5285 637 /* If the pbuf is not DMA safe, a new bounce buffer (pbuf) will be
emilmont 5:698d868a5285 638 created that will be used instead. This requires an copy from the
emilmont 5:698d868a5285 639 non-safe DMA region to the new pbuf */
emilmont 5:698d868a5285 640 if (notdmasafe) {
emilmont 5:698d868a5285 641 /* Allocate a pbuf in DMA memory */
emilmont 5:698d868a5285 642 np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
emilmont 5:698d868a5285 643 if (np == NULL)
emilmont 5:698d868a5285 644 return ERR_MEM;
emilmont 4:d827a085afd9 645
emilmont 5:698d868a5285 646 /* This buffer better be contiguous! */
emilmont 5:698d868a5285 647 LWIP_ASSERT("lpc_low_level_output: New transmit pbuf is chained",
emilmont 5:698d868a5285 648 (pbuf_clen(np) == 1));
emilmont 4:d827a085afd9 649
emilmont 5:698d868a5285 650 /* Copy to DMA safe pbuf */
emilmont 5:698d868a5285 651 dst = (u8_t *) np->payload;
emilmont 5:698d868a5285 652 for(q = p; q != NULL; q = q->next) {
emilmont 5:698d868a5285 653 /* Copy the buffer to the descriptor's buffer */
emilmont 5:698d868a5285 654 MEMCPY(dst, (u8_t *) q->payload, q->len);
emilmont 5:698d868a5285 655 dst += q->len;
emilmont 5:698d868a5285 656 }
emilmont 5:698d868a5285 657 np->len = p->tot_len;
emilmont 4:d827a085afd9 658
emilmont 5:698d868a5285 659 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
emilmont 5:698d868a5285 660 ("lpc_low_level_output: Switched to DMA safe buffer, old=%p, new=%p\n",
emilmont 5:698d868a5285 661 q, np));
emilmont 4:d827a085afd9 662
emilmont 5:698d868a5285 663 /* use the new buffer for descrptor queueing. The original pbuf will
emilmont 5:698d868a5285 664 be de-allocated outsuide this driver. */
emilmont 5:698d868a5285 665 p = np;
emilmont 5:698d868a5285 666 dn = 1;
emilmont 5:698d868a5285 667 }
emilmont 4:d827a085afd9 668 #else
emilmont 5:698d868a5285 669 if (notdmasafe)
emilmont 5:698d868a5285 670 LWIP_ASSERT("lpc_low_level_output: Not a DMA safe pbuf",
emilmont 5:698d868a5285 671 (notdmasafe == 0));
emilmont 4:d827a085afd9 672 #endif
emilmont 4:d827a085afd9 673
emilmont 5:698d868a5285 674 /* Wait until enough descriptors are available for the transfer. */
emilmont 5:698d868a5285 675 /* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */
emilmont 5:698d868a5285 676 while (dn > lpc_tx_ready(netif))
emilmont 4:d827a085afd9 677 #if NO_SYS == 0
emilmont 5:698d868a5285 678 osSemaphoreWait(lpc_enetif->xTXDCountSem.id, osWaitForever);
emilmont 4:d827a085afd9 679 #else
emilmont 5:698d868a5285 680 osDelay(1);
emilmont 4:d827a085afd9 681 #endif
emilmont 4:d827a085afd9 682
emilmont 5:698d868a5285 683 /* Get free TX buffer index */
emilmont 5:698d868a5285 684 idx = LPC_EMAC->TxProduceIndex;
emilmont 4:d827a085afd9 685
emilmont 4:d827a085afd9 686 #if NO_SYS == 0
emilmont 5:698d868a5285 687 /* Get exclusive access */
emilmont 5:698d868a5285 688 sys_mutex_lock(&lpc_enetif->TXLockMutex);
emilmont 4:d827a085afd9 689 #endif
emilmont 4:d827a085afd9 690
emilmont 5:698d868a5285 691 /* Prevent LWIP from de-allocating this pbuf. The driver will
emilmont 5:698d868a5285 692 free it once it's been transmitted. */
emilmont 5:698d868a5285 693 if (!notdmasafe)
emilmont 5:698d868a5285 694 pbuf_ref(p);
emilmont 4:d827a085afd9 695
emilmont 5:698d868a5285 696 /* Setup transfers */
emilmont 5:698d868a5285 697 q = p;
emilmont 5:698d868a5285 698 while (dn > 0) {
emilmont 5:698d868a5285 699 dn--;
emilmont 4:d827a085afd9 700
emilmont 5:698d868a5285 701 /* Only save pointer to free on last descriptor */
emilmont 5:698d868a5285 702 if (dn == 0) {
emilmont 5:698d868a5285 703 /* Save size of packet and signal it's ready */
emilmont 5:698d868a5285 704 lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT |
emilmont 5:698d868a5285 705 EMAC_TCTRL_LAST;
emilmont 4:d827a085afd9 706 lpc_enetif->txb[idx] = p;
emilmont 5:698d868a5285 707 }
emilmont 5:698d868a5285 708 else {
emilmont 5:698d868a5285 709 /* Save size of packet, descriptor is not last */
emilmont 5:698d868a5285 710 lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT;
emilmont 5:698d868a5285 711 lpc_enetif->txb[idx] = NULL;
emilmont 5:698d868a5285 712 }
emilmont 4:d827a085afd9 713
emilmont 5:698d868a5285 714 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
emilmont 5:698d868a5285 715 ("lpc_low_level_output: pbuf packet(%p) sent, chain#=%d,"
emilmont 5:698d868a5285 716 " size = %d (index=%d)\n", q->payload, dn, q->len, idx));
emilmont 4:d827a085afd9 717
emilmont 5:698d868a5285 718 lpc_enetif->ptxd[idx].packet = (u32_t) q->payload;
emilmont 4:d827a085afd9 719
emilmont 5:698d868a5285 720 q = q->next;
emilmont 4:d827a085afd9 721
emilmont 5:698d868a5285 722 idx++;
emilmont 5:698d868a5285 723 if (idx >= LPC_NUM_BUFF_TXDESCS)
emilmont 5:698d868a5285 724 idx = 0;
emilmont 5:698d868a5285 725 }
emilmont 4:d827a085afd9 726
emilmont 5:698d868a5285 727 LPC_EMAC->TxProduceIndex = idx;
emilmont 4:d827a085afd9 728
emilmont 5:698d868a5285 729 LINK_STATS_INC(link.xmit);
emilmont 4:d827a085afd9 730
emilmont 4:d827a085afd9 731 #if NO_SYS == 0
emilmont 5:698d868a5285 732 /* Restore access */
emilmont 5:698d868a5285 733 sys_mutex_unlock(&lpc_enetif->TXLockMutex);
emilmont 4:d827a085afd9 734 #endif
emilmont 4:d827a085afd9 735
emilmont 5:698d868a5285 736 return ERR_OK;
emilmont 4:d827a085afd9 737 }
emilmont 4:d827a085afd9 738
emilmont 4:d827a085afd9 739 /** \brief LPC EMAC interrupt handler.
emilmont 4:d827a085afd9 740 *
emilmont 4:d827a085afd9 741 * This function handles the transmit, receive, and error interrupt of
emilmont 4:d827a085afd9 742 * the LPC177x_8x. This is meant to be used when NO_SYS=0.
emilmont 4:d827a085afd9 743 */
emilmont 4:d827a085afd9 744 void ENET_IRQHandler(void)
emilmont 4:d827a085afd9 745 {
emilmont 4:d827a085afd9 746 #if NO_SYS == 1
emilmont 5:698d868a5285 747 /* Interrupts are not used without an RTOS */
emilmont 4:d827a085afd9 748 NVIC_DisableIRQ(ENET_IRQn);
emilmont 4:d827a085afd9 749 #else
emilmont 5:698d868a5285 750 uint32_t ints;
emilmont 4:d827a085afd9 751
emilmont 5:698d868a5285 752 /* Interrupts are of 2 groups - transmit or receive. Based on the
emilmont 5:698d868a5285 753 interrupt, kick off the receive or transmit (cleanup) task */
emilmont 4:d827a085afd9 754
emilmont 5:698d868a5285 755 /* Get pending interrupts */
emilmont 5:698d868a5285 756 ints = LPC_EMAC->IntStatus;
emilmont 4:d827a085afd9 757
emilmont 5:698d868a5285 758 if (ints & RXINTGROUP) {
emilmont 4:d827a085afd9 759 /* RX group interrupt(s): Give semaphore to wakeup RX receive task.*/
emilmont 4:d827a085afd9 760 sys_sem_signal(&lpc_enetdata.RxSem);
emilmont 4:d827a085afd9 761 }
emilmont 4:d827a085afd9 762
emilmont 4:d827a085afd9 763 if (ints & TXINTGROUP) {
emilmont 4:d827a085afd9 764 /* TX group interrupt(s): Give semaphore to wakeup TX cleanup task. */
emilmont 4:d827a085afd9 765 sys_sem_signal(&lpc_enetdata.TxCleanSem);
emilmont 4:d827a085afd9 766 }
emilmont 4:d827a085afd9 767
emilmont 5:698d868a5285 768 /* Clear pending interrupts */
emilmont 5:698d868a5285 769 LPC_EMAC->IntClear = ints;
emilmont 4:d827a085afd9 770 #endif
emilmont 4:d827a085afd9 771 }
emilmont 4:d827a085afd9 772
emilmont 4:d827a085afd9 773 #if NO_SYS == 0
emilmont 4:d827a085afd9 774 /** \brief Packet reception task
emilmont 4:d827a085afd9 775 *
emilmont 4:d827a085afd9 776 * This task is called when a packet is received. It will
emilmont 4:d827a085afd9 777 * pass the packet to the LWIP core.
emilmont 4:d827a085afd9 778 *
emilmont 4:d827a085afd9 779 * \param[in] pvParameters Not used yet
emilmont 4:d827a085afd9 780 */
emilmont 4:d827a085afd9 781 static void packet_rx(void* pvParameters) {
emilmont 4:d827a085afd9 782 struct lpc_enetdata *lpc_enetif = pvParameters;
emilmont 4:d827a085afd9 783
emilmont 4:d827a085afd9 784 while (1) {
emilmont 4:d827a085afd9 785 /* Wait for receive task to wakeup */
emilmont 4:d827a085afd9 786 sys_arch_sem_wait(&lpc_enetif->RxSem, 0);
emilmont 4:d827a085afd9 787
emilmont 4:d827a085afd9 788 /* Process packets until all empty */
emilmont 4:d827a085afd9 789 while (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex)
emilmont 4:d827a085afd9 790 lpc_enetif_input(lpc_enetif->netif);
emilmont 4:d827a085afd9 791 }
emilmont 4:d827a085afd9 792 }
emilmont 4:d827a085afd9 793
emilmont 4:d827a085afd9 794 /** \brief Transmit cleanup task
emilmont 4:d827a085afd9 795 *
emilmont 4:d827a085afd9 796 * This task is called when a transmit interrupt occurs and
emilmont 4:d827a085afd9 797 * reclaims the pbuf and descriptor used for the packet once
emilmont 4:d827a085afd9 798 * the packet has been transferred.
emilmont 4:d827a085afd9 799 *
emilmont 4:d827a085afd9 800 * \param[in] pvParameters Not used yet
emilmont 4:d827a085afd9 801 */
emilmont 4:d827a085afd9 802 static void packet_tx(void* pvParameters) {
emilmont 4:d827a085afd9 803 struct lpc_enetdata *lpc_enetif = pvParameters;
emilmont 4:d827a085afd9 804 s32_t idx;
emilmont 4:d827a085afd9 805
emilmont 4:d827a085afd9 806 while (1) {
emilmont 4:d827a085afd9 807 /* Wait for transmit cleanup task to wakeup */
emilmont 4:d827a085afd9 808 sys_arch_sem_wait(&lpc_enetif->TxCleanSem, 0);
emilmont 4:d827a085afd9 809
emilmont 4:d827a085afd9 810 /* Error handling for TX underruns. This should never happen unless
emilmont 4:d827a085afd9 811 something is holding the bus or the clocks are going too slow. It
emilmont 4:d827a085afd9 812 can probably be safely removed. */
emilmont 4:d827a085afd9 813 if (LPC_EMAC->IntStatus & EMAC_INT_TX_UNDERRUN) {
emilmont 4:d827a085afd9 814 LINK_STATS_INC(link.err);
emilmont 4:d827a085afd9 815 LINK_STATS_INC(link.drop);
emilmont 4:d827a085afd9 816
emilmont 4:d827a085afd9 817 #if NO_SYS == 0
emilmont 4:d827a085afd9 818 /* Get exclusive access */
emilmont 4:d827a085afd9 819 sys_mutex_lock(&lpc_enetif->TXLockMutex);
emilmont 4:d827a085afd9 820 #endif
emilmont 4:d827a085afd9 821 /* Reset the TX side */
emilmont 4:d827a085afd9 822 LPC_EMAC->MAC1 |= EMAC_MAC1_RES_TX;
emilmont 4:d827a085afd9 823 LPC_EMAC->IntClear = EMAC_INT_TX_UNDERRUN;
emilmont 4:d827a085afd9 824
emilmont 4:d827a085afd9 825 /* De-allocate all queued TX pbufs */
emilmont 6:59b01b9349d5 826 for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) {
emilmont 4:d827a085afd9 827 if (lpc_enetif->txb[idx] != NULL) {
emilmont 4:d827a085afd9 828 pbuf_free(lpc_enetif->txb[idx]);
emilmont 4:d827a085afd9 829 lpc_enetif->txb[idx] = NULL;
emilmont 4:d827a085afd9 830 }
emilmont 4:d827a085afd9 831 }
emilmont 4:d827a085afd9 832
emilmont 4:d827a085afd9 833 #if NO_SYS == 0
emilmont 4:d827a085afd9 834 /* Restore access */
emilmont 4:d827a085afd9 835 sys_mutex_unlock(&lpc_enetif->TXLockMutex);
emilmont 4:d827a085afd9 836 #endif
emilmont 4:d827a085afd9 837 /* Start TX side again */
emilmont 4:d827a085afd9 838 lpc_tx_setup(lpc_enetif);
emilmont 4:d827a085afd9 839 } else {
emilmont 4:d827a085afd9 840 /* Free TX buffers that are done sending */
emilmont 4:d827a085afd9 841 lpc_tx_reclaim(lpc_enetdata.netif);
emilmont 4:d827a085afd9 842 }
emilmont 4:d827a085afd9 843 }
emilmont 4:d827a085afd9 844 }
emilmont 4:d827a085afd9 845 #endif
emilmont 4:d827a085afd9 846
emilmont 4:d827a085afd9 847 /** \brief Low level init of the MAC and PHY.
emilmont 4:d827a085afd9 848 *
emilmont 4:d827a085afd9 849 * \param[in] netif Pointer to LWIP netif structure
emilmont 4:d827a085afd9 850 */
emilmont 4:d827a085afd9 851 static err_t low_level_init(struct netif *netif)
emilmont 4:d827a085afd9 852 {
emilmont 5:698d868a5285 853 struct lpc_enetdata *lpc_enetif = netif->state;
emilmont 5:698d868a5285 854 err_t err = ERR_OK;
emilmont 4:d827a085afd9 855
emilmont 5:698d868a5285 856 /* Enable MII clocking */
emilmont 5:698d868a5285 857 LPC_SC->PCONP |= CLKPWR_PCONP_PCENET;
emilmont 5:698d868a5285 858
emilmont 5:698d868a5285 859 #if defined(TARGET_LPC1768)
emilmont 5:698d868a5285 860 LPC_PINCON->PINSEL2 = 0x50150105; /* Enable P1 Ethernet Pins. */
emilmont 5:698d868a5285 861 LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005;
emilmont 5:698d868a5285 862 #elif defined(TARGET_LPC4088)
emilmont 5:698d868a5285 863 LPC_IOCON->P1_0 &= ~0x07; /* ENET I/O config */
emilmont 5:698d868a5285 864 LPC_IOCON->P1_0 |= 0x01; /* ENET_TXD0 */
emilmont 5:698d868a5285 865 LPC_IOCON->P1_1 &= ~0x07;
emilmont 5:698d868a5285 866 LPC_IOCON->P1_1 |= 0x01; /* ENET_TXD1 */
emilmont 5:698d868a5285 867 LPC_IOCON->P1_4 &= ~0x07;
emilmont 5:698d868a5285 868 LPC_IOCON->P1_4 |= 0x01; /* ENET_TXEN */
emilmont 5:698d868a5285 869 LPC_IOCON->P1_8 &= ~0x07;
emilmont 5:698d868a5285 870 LPC_IOCON->P1_8 |= 0x01; /* ENET_CRS */
emilmont 5:698d868a5285 871 LPC_IOCON->P1_9 &= ~0x07;
emilmont 5:698d868a5285 872 LPC_IOCON->P1_9 |= 0x01; /* ENET_RXD0 */
emilmont 5:698d868a5285 873 LPC_IOCON->P1_10 &= ~0x07;
emilmont 5:698d868a5285 874 LPC_IOCON->P1_10 |= 0x01; /* ENET_RXD1 */
emilmont 5:698d868a5285 875 LPC_IOCON->P1_14 &= ~0x07;
emilmont 5:698d868a5285 876 LPC_IOCON->P1_14 |= 0x01; /* ENET_RX_ER */
emilmont 5:698d868a5285 877 LPC_IOCON->P1_15 &= ~0x07;
emilmont 5:698d868a5285 878 LPC_IOCON->P1_15 |= 0x01; /* ENET_REF_CLK */
emilmont 5:698d868a5285 879 LPC_IOCON->P1_16 &= ~0x07; /* ENET/PHY I/O config */
emilmont 5:698d868a5285 880 LPC_IOCON->P1_16 |= 0x01; /* ENET_MDC */
emilmont 5:698d868a5285 881 LPC_IOCON->P1_17 &= ~0x07;
emilmont 5:698d868a5285 882 LPC_IOCON->P1_17 |= 0x01; /* ENET_MDIO */
emilmont 5:698d868a5285 883 #endif
emilmont 5:698d868a5285 884
emilmont 5:698d868a5285 885 /* Reset all MAC logic */
emilmont 5:698d868a5285 886 LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX |
emilmont 5:698d868a5285 887 EMAC_MAC1_RES_RX | EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES |
emilmont 5:698d868a5285 888 EMAC_MAC1_SOFT_RES;
emilmont 5:698d868a5285 889 LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES |
emilmont 5:698d868a5285 890 EMAC_CR_PASS_RUNT_FRM;
emilmont 5:698d868a5285 891 osDelay(10);
emilmont 5:698d868a5285 892
emilmont 5:698d868a5285 893 /* Initial MAC initialization */
emilmont 5:698d868a5285 894 LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL;
emilmont 5:698d868a5285 895 LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN |
emilmont 5:698d868a5285 896 EMAC_MAC2_VLAN_PAD_EN;
emilmont 5:698d868a5285 897 LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN;
emilmont 4:d827a085afd9 898
emilmont 5:698d868a5285 899 /* Set RMII management clock rate to lowest speed */
emilmont 5:698d868a5285 900 LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(11) | EMAC_MCFG_RES_MII;
emilmont 5:698d868a5285 901 LPC_EMAC->MCFG &= ~EMAC_MCFG_RES_MII;
emilmont 4:d827a085afd9 902
emilmont 5:698d868a5285 903 /* Maximum number of retries, 0x37 collision window, gap */
emilmont 5:698d868a5285 904 LPC_EMAC->CLRT = EMAC_CLRT_DEF;
emilmont 5:698d868a5285 905 LPC_EMAC->IPGR = EMAC_IPGR_P1_DEF | EMAC_IPGR_P2_DEF;
emilmont 4:d827a085afd9 906
emilmont 4:d827a085afd9 907 #if LPC_EMAC_RMII
emilmont 5:698d868a5285 908 /* RMII setup */
emilmont 5:698d868a5285 909 LPC_EMAC->Command = EMAC_CR_PASS_RUNT_FRM | EMAC_CR_RMII;
emilmont 4:d827a085afd9 910 #else
emilmont 5:698d868a5285 911 /* MII setup */
emilmont 5:698d868a5285 912 LPC_EMAC->CR = EMAC_CR_PASS_RUNT_FRM;
emilmont 4:d827a085afd9 913 #endif
emilmont 4:d827a085afd9 914
emilmont 5:698d868a5285 915 /* Initialize the PHY and reset */
emilmont 4:d827a085afd9 916 err = lpc_phy_init(netif, LPC_EMAC_RMII);
emilmont 5:698d868a5285 917 if (err != ERR_OK)
emilmont 5:698d868a5285 918 return err;
emilmont 4:d827a085afd9 919
emilmont 5:698d868a5285 920 /* Save station address */
emilmont 5:698d868a5285 921 LPC_EMAC->SA2 = (u32_t) netif->hwaddr[0] |
emilmont 5:698d868a5285 922 (((u32_t) netif->hwaddr[1]) << 8);
emilmont 5:698d868a5285 923 LPC_EMAC->SA1 = (u32_t) netif->hwaddr[2] |
emilmont 5:698d868a5285 924 (((u32_t) netif->hwaddr[3]) << 8);
emilmont 5:698d868a5285 925 LPC_EMAC->SA0 = (u32_t) netif->hwaddr[4] |
emilmont 5:698d868a5285 926 (((u32_t) netif->hwaddr[5]) << 8);
emilmont 4:d827a085afd9 927
emilmont 5:698d868a5285 928 /* Setup transmit and receive descriptors */
emilmont 5:698d868a5285 929 if (lpc_tx_setup(lpc_enetif) != ERR_OK)
emilmont 5:698d868a5285 930 return ERR_BUF;
emilmont 5:698d868a5285 931 if (lpc_rx_setup(lpc_enetif) != ERR_OK)
emilmont 5:698d868a5285 932 return ERR_BUF;
emilmont 4:d827a085afd9 933
emilmont 5:698d868a5285 934 /* Enable packet reception */
emilmont 4:d827a085afd9 935 #if IP_SOF_BROADCAST_RECV
emilmont 5:698d868a5285 936 LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_MCAST_EN;
emilmont 4:d827a085afd9 937 #else
emilmont 5:698d868a5285 938 LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN;
emilmont 4:d827a085afd9 939 #endif
emilmont 4:d827a085afd9 940
emilmont 5:698d868a5285 941 /* Clear and enable rx/tx interrupts */
emilmont 5:698d868a5285 942 LPC_EMAC->IntClear = 0xFFFF;
emilmont 5:698d868a5285 943 LPC_EMAC->IntEnable = RXINTGROUP | TXINTGROUP;
emilmont 4:d827a085afd9 944
emilmont 5:698d868a5285 945 /* Enable RX and TX */
emilmont 5:698d868a5285 946 LPC_EMAC->Command |= EMAC_CR_RX_EN | EMAC_CR_TX_EN;
emilmont 5:698d868a5285 947 LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
emilmont 4:d827a085afd9 948
emilmont 5:698d868a5285 949 return err;
emilmont 4:d827a085afd9 950 }
emilmont 4:d827a085afd9 951
emilmont 4:d827a085afd9 952 /* This function provides a method for the PHY to setup the EMAC
emilmont 4:d827a085afd9 953 for the PHY negotiated duplex mode */
emilmont 4:d827a085afd9 954 void lpc_emac_set_duplex(int full_duplex)
emilmont 4:d827a085afd9 955 {
emilmont 5:698d868a5285 956 if (full_duplex) {
emilmont 5:698d868a5285 957 LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP;
emilmont 5:698d868a5285 958 LPC_EMAC->Command |= EMAC_CR_FULL_DUP;
emilmont 5:698d868a5285 959 LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP;
emilmont 5:698d868a5285 960 } else {
emilmont 5:698d868a5285 961 LPC_EMAC->MAC2 &= ~EMAC_MAC2_FULL_DUP;
emilmont 5:698d868a5285 962 LPC_EMAC->Command &= ~EMAC_CR_FULL_DUP;
emilmont 5:698d868a5285 963 LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP;
emilmont 5:698d868a5285 964 }
emilmont 4:d827a085afd9 965 }
emilmont 4:d827a085afd9 966
emilmont 4:d827a085afd9 967 /* This function provides a method for the PHY to setup the EMAC
emilmont 4:d827a085afd9 968 for the PHY negotiated bit rate */
emilmont 4:d827a085afd9 969 void lpc_emac_set_speed(int mbs_100)
emilmont 4:d827a085afd9 970 {
emilmont 5:698d868a5285 971 if (mbs_100)
emilmont 5:698d868a5285 972 LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
emilmont 5:698d868a5285 973 else
emilmont 5:698d868a5285 974 LPC_EMAC->SUPP = 0;
emilmont 4:d827a085afd9 975 }
emilmont 4:d827a085afd9 976
emilmont 4:d827a085afd9 977 /**
emilmont 4:d827a085afd9 978 * This function is the ethernet packet send function. It calls
emilmont 4:d827a085afd9 979 * etharp_output after checking link status.
emilmont 4:d827a085afd9 980 *
emilmont 4:d827a085afd9 981 * \param[in] netif the lwip network interface structure for this lpc_enetif
emilmont 4:d827a085afd9 982 * \param[in] q Pointer to pbug to send
emilmont 4:d827a085afd9 983 * \param[in] ipaddr IP address
emilmont 4:d827a085afd9 984 * \return ERR_OK or error code
emilmont 4:d827a085afd9 985 */
emilmont 4:d827a085afd9 986 err_t lpc_etharp_output(struct netif *netif, struct pbuf *q,
emilmont 5:698d868a5285 987 ip_addr_t *ipaddr)
emilmont 4:d827a085afd9 988 {
emilmont 5:698d868a5285 989 /* Only send packet is link is up */
emilmont 5:698d868a5285 990 if (netif->flags & NETIF_FLAG_LINK_UP)
emilmont 5:698d868a5285 991 return etharp_output(netif, q, ipaddr);
emilmont 4:d827a085afd9 992
emilmont 5:698d868a5285 993 return ERR_CONN;
emilmont 4:d827a085afd9 994 }
emilmont 4:d827a085afd9 995
emilmont 4:d827a085afd9 996 #if NO_SYS == 0
emilmont 4:d827a085afd9 997 /* periodic PHY status update */
emilmont 4:d827a085afd9 998 void phy_update(void const *nif) {
emilmont 4:d827a085afd9 999 lpc_phy_sts_sm((struct netif*)nif);
emilmont 4:d827a085afd9 1000 }
emilmont 4:d827a085afd9 1001 osTimerDef(phy_update, phy_update);
emilmont 4:d827a085afd9 1002 #endif
emilmont 4:d827a085afd9 1003
emilmont 4:d827a085afd9 1004 /**
emilmont 4:d827a085afd9 1005 * Should be called at the beginning of the program to set up the
emilmont 4:d827a085afd9 1006 * network interface.
emilmont 4:d827a085afd9 1007 *
emilmont 4:d827a085afd9 1008 * This function should be passed as a parameter to netif_add().
emilmont 4:d827a085afd9 1009 *
emilmont 4:d827a085afd9 1010 * @param[in] netif the lwip network interface structure for this lpc_enetif
emilmont 4:d827a085afd9 1011 * @return ERR_OK if the loopif is initialized
emilmont 4:d827a085afd9 1012 * ERR_MEM if private data couldn't be allocated
emilmont 4:d827a085afd9 1013 * any other err_t on error
emilmont 4:d827a085afd9 1014 */
emilmont 4:d827a085afd9 1015 err_t lpc_enetif_init(struct netif *netif)
emilmont 4:d827a085afd9 1016 {
emilmont 5:698d868a5285 1017 err_t err;
emilmont 4:d827a085afd9 1018
emilmont 5:698d868a5285 1019 LWIP_ASSERT("netif != NULL", (netif != NULL));
emilmont 4:d827a085afd9 1020
emilmont 5:698d868a5285 1021 lpc_enetdata.netif = netif;
emilmont 4:d827a085afd9 1022
emilmont 5:698d868a5285 1023 /* set MAC hardware address */
emilmont 5:698d868a5285 1024 mbed_mac_address((char *)netif->hwaddr);
emilmont 5:698d868a5285 1025 netif->hwaddr_len = ETHARP_HWADDR_LEN;
emilmont 4:d827a085afd9 1026
emilmont 5:698d868a5285 1027 /* maximum transfer unit */
emilmont 5:698d868a5285 1028 netif->mtu = 1500;
emilmont 4:d827a085afd9 1029
emilmont 5:698d868a5285 1030 /* device capabilities */
emilmont 5:698d868a5285 1031 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
emilmont 4:d827a085afd9 1032
emilmont 5:698d868a5285 1033 /* Initialize the hardware */
emilmont 5:698d868a5285 1034 netif->state = &lpc_enetdata;
emilmont 5:698d868a5285 1035 err = low_level_init(netif);
emilmont 5:698d868a5285 1036 if (err != ERR_OK)
emilmont 5:698d868a5285 1037 return err;
emilmont 4:d827a085afd9 1038
emilmont 4:d827a085afd9 1039 #if LWIP_NETIF_HOSTNAME
emilmont 5:698d868a5285 1040 /* Initialize interface hostname */
emilmont 5:698d868a5285 1041 netif->hostname = "lwiplpc";
emilmont 4:d827a085afd9 1042 #endif /* LWIP_NETIF_HOSTNAME */
emilmont 4:d827a085afd9 1043
emilmont 5:698d868a5285 1044 netif->name[0] = 'e';
emilmont 5:698d868a5285 1045 netif->name[1] = 'n';
emilmont 4:d827a085afd9 1046
emilmont 5:698d868a5285 1047 netif->output = lpc_etharp_output;
emilmont 5:698d868a5285 1048 netif->linkoutput = lpc_low_level_output;
emilmont 4:d827a085afd9 1049
emilmont 4:d827a085afd9 1050 /* CMSIS-RTOS, start tasks */
emilmont 4:d827a085afd9 1051 #if NO_SYS == 0
emilmont 4:d827a085afd9 1052 #ifdef CMSIS_OS_RTX
emilmont 4:d827a085afd9 1053 memset(lpc_enetdata.xTXDCountSem.data, 0, sizeof(lpc_enetdata.xTXDCountSem.data));
emilmont 4:d827a085afd9 1054 lpc_enetdata.xTXDCountSem.def.semaphore = lpc_enetdata.xTXDCountSem.data;
emilmont 4:d827a085afd9 1055 #endif
emilmont 4:d827a085afd9 1056 lpc_enetdata.xTXDCountSem.id = osSemaphoreCreate(&lpc_enetdata.xTXDCountSem.def, LPC_NUM_BUFF_TXDESCS);
emilmont 5:698d868a5285 1057 LWIP_ASSERT("xTXDCountSem creation error", (lpc_enetdata.xTXDCountSem.id != NULL));
emilmont 4:d827a085afd9 1058
emilmont 5:698d868a5285 1059 err = sys_mutex_new(&lpc_enetdata.TXLockMutex);
emilmont 5:698d868a5285 1060 LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK));
emilmont 4:d827a085afd9 1061
emilmont 5:698d868a5285 1062 /* Packet receive task */
emilmont 5:698d868a5285 1063 err = sys_sem_new(&lpc_enetdata.RxSem, 0);
emilmont 5:698d868a5285 1064 LWIP_ASSERT("RxSem creation error", (err == ERR_OK));
emilmont 5:698d868a5285 1065 sys_thread_new("receive_thread", packet_rx, netif->state, DEFAULT_THREAD_STACKSIZE, RX_PRIORITY);
emilmont 4:d827a085afd9 1066
emilmont 5:698d868a5285 1067 /* Transmit cleanup task */
emilmont 5:698d868a5285 1068 err = sys_sem_new(&lpc_enetdata.TxCleanSem, 0);
emilmont 5:698d868a5285 1069 LWIP_ASSERT("TxCleanSem creation error", (err == ERR_OK));
emilmont 5:698d868a5285 1070 sys_thread_new("txclean_thread", packet_tx, netif->state, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY);
emilmont 5:698d868a5285 1071
emilmont 5:698d868a5285 1072 /* periodic PHY status update */
emilmont 5:698d868a5285 1073 osTimerId phy_timer = osTimerCreate(osTimer(phy_update), osTimerPeriodic, (void *)netif);
emilmont 5:698d868a5285 1074 osTimerStart(phy_timer, 250);
emilmont 4:d827a085afd9 1075 #endif
emilmont 4:d827a085afd9 1076
emilmont 4:d827a085afd9 1077 return ERR_OK;
emilmont 4:d827a085afd9 1078 }
emilmont 4:d827a085afd9 1079
emilmont 4:d827a085afd9 1080 /**
emilmont 4:d827a085afd9 1081 * @}
emilmont 4:d827a085afd9 1082 */
emilmont 4:d827a085afd9 1083
emilmont 4:d827a085afd9 1084 /* --------------------------------- End Of File ------------------------------ */