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:
Fri Jun 22 11:57:39 2012 +0000
Revision:
2:5208926bd863
Parent:
1:0c9d93e2f51c
Child:
3:dd8b8f5b449a
complete lpc_enetif initialization

Who changed what in which revision?

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