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:17:21 2012 +0000
Revision:
1:0c9d93e2f51c
Parent:
0:f4db29eb9e47
Child:
2:5208926bd863
Adapt NXP lwip Ethernet driver to CMSIS-RTOS and LPC1768

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 */
mbed_official 0:f4db29eb9e47 485 if ((((u32_t) addr >= 0x20000000) && ((u32_t) addr < 0x20008000)) ||
mbed_official 0:f4db29eb9e47 486 (((u32_t) addr >= 0x80000000) && ((u32_t) addr < 0xF0000000)))
mbed_official 0:f4db29eb9e47 487 return 0;
mbed_official 0:f4db29eb9e47 488
mbed_official 0:f4db29eb9e47 489 return 1;
mbed_official 0:f4db29eb9e47 490 }
mbed_official 0:f4db29eb9e47 491
mbed_official 0:f4db29eb9e47 492 /** \brief Sets up the TX descriptor ring buffers.
mbed_official 0:f4db29eb9e47 493 *
mbed_official 0:f4db29eb9e47 494 * This function sets up the descriptor list used for transmit packets.
mbed_official 0:f4db29eb9e47 495 *
mbed_official 0:f4db29eb9e47 496 * \param[in] lpc_enetif Pointer to driver data structure
mbed_official 0:f4db29eb9e47 497 */
mbed_official 0:f4db29eb9e47 498 static err_t lpc_tx_setup(struct lpc_enetdata *lpc_enetif)
mbed_official 0:f4db29eb9e47 499 {
mbed_official 0:f4db29eb9e47 500 s32_t idx;
mbed_official 0:f4db29eb9e47 501
mbed_official 0:f4db29eb9e47 502 /* Build TX descriptors for local buffers */
mbed_official 0:f4db29eb9e47 503 for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) {
mbed_official 0:f4db29eb9e47 504 lpc_enetif->ptxd[idx].control = 0;
mbed_official 0:f4db29eb9e47 505 lpc_enetif->ptxs[idx].statusinfo = 0xFFFFFFFF;
mbed_official 0:f4db29eb9e47 506 }
mbed_official 0:f4db29eb9e47 507
mbed_official 0:f4db29eb9e47 508 /* Setup pointers to TX structures */
mbed_official 0:f4db29eb9e47 509 LPC_EMAC->TxDescriptor = (u32_t) &lpc_enetif->ptxd[0];
mbed_official 0:f4db29eb9e47 510 LPC_EMAC->TxStatus = (u32_t) &lpc_enetif->ptxs[0];
mbed_official 0:f4db29eb9e47 511 LPC_EMAC->TxDescriptorNumber = LPC_NUM_BUFF_TXDESCS - 1;
mbed_official 0:f4db29eb9e47 512
mbed_official 0:f4db29eb9e47 513 lpc_enetif->lpc_last_tx_idx = 0;
mbed_official 0:f4db29eb9e47 514
mbed_official 0:f4db29eb9e47 515 return ERR_OK;
mbed_official 0:f4db29eb9e47 516 }
mbed_official 0:f4db29eb9e47 517
mbed_official 0:f4db29eb9e47 518 /** \brief Free TX buffers that are complete
mbed_official 0:f4db29eb9e47 519 *
mbed_official 0:f4db29eb9e47 520 * \param[in] lpc_enetif Pointer to driver data structure
emilmont 1:0c9d93e2f51c 521 * \param[in] cidx EMAC current descriptor comsumer index
mbed_official 0:f4db29eb9e47 522 */
mbed_official 0:f4db29eb9e47 523 static void lpc_tx_reclaim_st(struct lpc_enetdata *lpc_enetif, u32_t cidx)
mbed_official 0:f4db29eb9e47 524 {
mbed_official 0:f4db29eb9e47 525 #if NO_SYS == 0
mbed_official 0:f4db29eb9e47 526 /* Get exclusive access */
mbed_official 0:f4db29eb9e47 527 sys_mutex_lock(&lpc_enetif->TXLockMutex);
mbed_official 0:f4db29eb9e47 528 #endif
mbed_official 0:f4db29eb9e47 529
mbed_official 0:f4db29eb9e47 530 while (cidx != lpc_enetif->lpc_last_tx_idx) {
mbed_official 0:f4db29eb9e47 531 if (lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] != NULL) {
mbed_official 0:f4db29eb9e47 532 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
mbed_official 0:f4db29eb9e47 533 ("lpc_tx_reclaim_st: Freeing packet %p (index %d)\n",
mbed_official 0:f4db29eb9e47 534 lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx],
mbed_official 0:f4db29eb9e47 535 lpc_enetif->lpc_last_tx_idx));
mbed_official 0:f4db29eb9e47 536 pbuf_free(lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx]);
mbed_official 0:f4db29eb9e47 537 lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] = NULL;
mbed_official 0:f4db29eb9e47 538 }
mbed_official 0:f4db29eb9e47 539
mbed_official 0:f4db29eb9e47 540 #if NO_SYS == 0
emilmont 1:0c9d93e2f51c 541 osSemaphoreRelease(lpc_enetif->xTXDCountSem.id);
mbed_official 0:f4db29eb9e47 542 #endif
mbed_official 0:f4db29eb9e47 543 lpc_enetif->lpc_last_tx_idx++;
mbed_official 0:f4db29eb9e47 544 if (lpc_enetif->lpc_last_tx_idx >= LPC_NUM_BUFF_TXDESCS)
mbed_official 0:f4db29eb9e47 545 lpc_enetif->lpc_last_tx_idx = 0;
mbed_official 0:f4db29eb9e47 546 }
mbed_official 0:f4db29eb9e47 547
mbed_official 0:f4db29eb9e47 548 #if NO_SYS == 0
mbed_official 0:f4db29eb9e47 549 /* Restore access */
mbed_official 0:f4db29eb9e47 550 sys_mutex_unlock(&lpc_enetif->TXLockMutex);
mbed_official 0:f4db29eb9e47 551 #endif
mbed_official 0:f4db29eb9e47 552 }
mbed_official 0:f4db29eb9e47 553
mbed_official 0:f4db29eb9e47 554 /** \brief User call for freeingTX buffers that are complete
mbed_official 0:f4db29eb9e47 555 *
emilmont 1:0c9d93e2f51c 556 * \param[in] netif the lwip network interface structure for this lpc_enetif
mbed_official 0:f4db29eb9e47 557 */
mbed_official 0:f4db29eb9e47 558 void lpc_tx_reclaim(struct netif *netif)
mbed_official 0:f4db29eb9e47 559 {
mbed_official 0:f4db29eb9e47 560 lpc_tx_reclaim_st((struct lpc_enetdata *) netif->state,
mbed_official 0:f4db29eb9e47 561 LPC_EMAC->TxConsumeIndex);
mbed_official 0:f4db29eb9e47 562 }
mbed_official 0:f4db29eb9e47 563
mbed_official 0:f4db29eb9e47 564 /** \brief Polls if an available TX descriptor is ready. Can be used to
mbed_official 0:f4db29eb9e47 565 * determine if the low level transmit function will block.
mbed_official 0:f4db29eb9e47 566 *
emilmont 1:0c9d93e2f51c 567 * \param[in] netif the lwip network interface structure for this lpc_enetif
emilmont 1:0c9d93e2f51c 568 * \return 0 if no descriptors are read, or >0
mbed_official 0:f4db29eb9e47 569 */
mbed_official 0:f4db29eb9e47 570 s32_t lpc_tx_ready(struct netif *netif)
mbed_official 0:f4db29eb9e47 571 {
mbed_official 0:f4db29eb9e47 572 s32_t fb;
mbed_official 0:f4db29eb9e47 573 u32_t idx, cidx;
emilmont 1:0c9d93e2f51c 574
mbed_official 0:f4db29eb9e47 575 cidx = LPC_EMAC->TxConsumeIndex;
mbed_official 0:f4db29eb9e47 576 idx = LPC_EMAC->TxProduceIndex;
mbed_official 0:f4db29eb9e47 577
mbed_official 0:f4db29eb9e47 578 /* Determine number of free buffers */
mbed_official 0:f4db29eb9e47 579 if (idx == cidx)
mbed_official 0:f4db29eb9e47 580 fb = LPC_NUM_BUFF_TXDESCS;
mbed_official 0:f4db29eb9e47 581 else if (cidx > idx)
mbed_official 0:f4db29eb9e47 582 fb = (LPC_NUM_BUFF_TXDESCS - 1) -
mbed_official 0:f4db29eb9e47 583 ((idx + LPC_NUM_BUFF_TXDESCS) - cidx);
mbed_official 0:f4db29eb9e47 584 else
mbed_official 0:f4db29eb9e47 585 fb = (LPC_NUM_BUFF_TXDESCS - 1) - (cidx - idx);
mbed_official 0:f4db29eb9e47 586
mbed_official 0:f4db29eb9e47 587 return fb;
mbed_official 0:f4db29eb9e47 588 }
mbed_official 0:f4db29eb9e47 589
mbed_official 0:f4db29eb9e47 590 /** \brief Low level output of a packet. Never call this from an
mbed_official 0:f4db29eb9e47 591 * interrupt context, as it may block until TX descriptors
mbed_official 0:f4db29eb9e47 592 * become available.
mbed_official 0:f4db29eb9e47 593 *
emilmont 1:0c9d93e2f51c 594 * \param[in] netif the lwip network interface structure for this lpc_enetif
emilmont 1:0c9d93e2f51c 595 * \param[in] p the MAC packet to send (e.g. IP packet including MAC addresses and type)
emilmont 1:0c9d93e2f51c 596 * \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 597 */
emilmont 1:0c9d93e2f51c 598 static err_t lpc_low_level_output(struct netif *netif, struct pbuf *p)
mbed_official 0:f4db29eb9e47 599 {
mbed_official 0:f4db29eb9e47 600 struct lpc_enetdata *lpc_enetif = netif->state;
mbed_official 0:f4db29eb9e47 601 struct pbuf *q;
mbed_official 0:f4db29eb9e47 602 u8_t *dst;
emilmont 1:0c9d93e2f51c 603 u32_t idx;
mbed_official 0:f4db29eb9e47 604 struct pbuf *np;
mbed_official 0:f4db29eb9e47 605 u32_t dn, notdmasafe = 0;
mbed_official 0:f4db29eb9e47 606
mbed_official 0:f4db29eb9e47 607 /* Zero-copy TX buffers may be fragmented across mutliple payload
mbed_official 0:f4db29eb9e47 608 chains. Determine the number of descriptors needed for the
mbed_official 0:f4db29eb9e47 609 transfer. The pbuf chaining can be a mess! */
mbed_official 0:f4db29eb9e47 610 dn = (u32_t) pbuf_clen(p);
mbed_official 0:f4db29eb9e47 611
mbed_official 0:f4db29eb9e47 612 /* Test to make sure packet addresses are DMA safe. A DMA safe
mbed_official 0:f4db29eb9e47 613 address is once that uses external memory or periphheral RAM.
mbed_official 0:f4db29eb9e47 614 IRAM and FLASH are not safe! */
mbed_official 0:f4db29eb9e47 615 for (q = p; q != NULL; q = q->next)
mbed_official 0:f4db29eb9e47 616 notdmasafe += lpc_packet_addr_notsafe(q->payload);
mbed_official 0:f4db29eb9e47 617
mbed_official 0:f4db29eb9e47 618 #if LPC_TX_PBUF_BOUNCE_EN==1
mbed_official 0:f4db29eb9e47 619 /* If the pbuf is not DMA safe, a new bounce buffer (pbuf) will be
mbed_official 0:f4db29eb9e47 620 created that will be used instead. This requires an copy from the
mbed_official 0:f4db29eb9e47 621 non-safe DMA region to the new pbuf */
mbed_official 0:f4db29eb9e47 622 if (notdmasafe) {
mbed_official 0:f4db29eb9e47 623 /* Allocate a pbuf in DMA memory */
mbed_official 0:f4db29eb9e47 624 np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
mbed_official 0:f4db29eb9e47 625 if (np == NULL)
mbed_official 0:f4db29eb9e47 626 return ERR_MEM;
mbed_official 0:f4db29eb9e47 627
mbed_official 0:f4db29eb9e47 628 /* This buffer better be contiguous! */
mbed_official 0:f4db29eb9e47 629 LWIP_ASSERT("lpc_low_level_output: New transmit pbuf is chained",
mbed_official 0:f4db29eb9e47 630 (pbuf_clen(np) == 1));
emilmont 1:0c9d93e2f51c 631
mbed_official 0:f4db29eb9e47 632 /* Copy to DMA safe pbuf */
mbed_official 0:f4db29eb9e47 633 dst = (u8_t *) np->payload;
emilmont 1:0c9d93e2f51c 634 for(q = p; q != NULL; q = q->next) {
mbed_official 0:f4db29eb9e47 635 /* Copy the buffer to the descriptor's buffer */
mbed_official 0:f4db29eb9e47 636 MEMCPY(dst, (u8_t *) q->payload, q->len);
mbed_official 0:f4db29eb9e47 637 dst += q->len;
mbed_official 0:f4db29eb9e47 638 }
mbed_official 0:f4db29eb9e47 639 np->len = p->tot_len;
mbed_official 0:f4db29eb9e47 640
mbed_official 0:f4db29eb9e47 641 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
mbed_official 0:f4db29eb9e47 642 ("lpc_low_level_output: Switched to DMA safe buffer, old=%p, new=%p\n",
mbed_official 0:f4db29eb9e47 643 q, np));
mbed_official 0:f4db29eb9e47 644
mbed_official 0:f4db29eb9e47 645 /* use the new buffer for descrptor queueing. The original pbuf will
mbed_official 0:f4db29eb9e47 646 be de-allocated outsuide this driver. */
mbed_official 0:f4db29eb9e47 647 p = np;
mbed_official 0:f4db29eb9e47 648 dn = 1;
mbed_official 0:f4db29eb9e47 649 }
mbed_official 0:f4db29eb9e47 650 #else
mbed_official 0:f4db29eb9e47 651 if (notdmasafe)
mbed_official 0:f4db29eb9e47 652 LWIP_ASSERT("lpc_low_level_output: Not a DMA safe pbuf",
emilmont 1:0c9d93e2f51c 653 (notdmasafe == 0));
mbed_official 0:f4db29eb9e47 654 #endif
mbed_official 0:f4db29eb9e47 655
mbed_official 0:f4db29eb9e47 656 /* Wait until enough descriptors are available for the transfer. */
mbed_official 0:f4db29eb9e47 657 /* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */
mbed_official 0:f4db29eb9e47 658 while (dn > lpc_tx_ready(netif))
mbed_official 0:f4db29eb9e47 659 #if NO_SYS == 0
emilmont 1:0c9d93e2f51c 660 osSemaphoreWait(lpc_enetif->xTXDCountSem.id, osWaitForever);
mbed_official 0:f4db29eb9e47 661 #else
emilmont 1:0c9d93e2f51c 662 osDelay(1);
mbed_official 0:f4db29eb9e47 663 #endif
mbed_official 0:f4db29eb9e47 664
mbed_official 0:f4db29eb9e47 665 /* Get free TX buffer index */
mbed_official 0:f4db29eb9e47 666 idx = LPC_EMAC->TxProduceIndex;
mbed_official 0:f4db29eb9e47 667
mbed_official 0:f4db29eb9e47 668 #if NO_SYS == 0
mbed_official 0:f4db29eb9e47 669 /* Get exclusive access */
mbed_official 0:f4db29eb9e47 670 sys_mutex_lock(&lpc_enetif->TXLockMutex);
mbed_official 0:f4db29eb9e47 671 #endif
mbed_official 0:f4db29eb9e47 672
mbed_official 0:f4db29eb9e47 673 /* Prevent LWIP from de-allocating this pbuf. The driver will
mbed_official 0:f4db29eb9e47 674 free it once it's been transmitted. */
mbed_official 0:f4db29eb9e47 675 if (!notdmasafe)
mbed_official 0:f4db29eb9e47 676 pbuf_ref(p);
mbed_official 0:f4db29eb9e47 677
mbed_official 0:f4db29eb9e47 678 /* Setup transfers */
mbed_official 0:f4db29eb9e47 679 q = p;
mbed_official 0:f4db29eb9e47 680 while (dn > 0) {
mbed_official 0:f4db29eb9e47 681 dn--;
mbed_official 0:f4db29eb9e47 682
mbed_official 0:f4db29eb9e47 683 /* Only save pointer to free on last descriptor */
mbed_official 0:f4db29eb9e47 684 if (dn == 0) {
mbed_official 0:f4db29eb9e47 685 /* Save size of packet and signal it's ready */
mbed_official 0:f4db29eb9e47 686 lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT |
mbed_official 0:f4db29eb9e47 687 EMAC_TCTRL_LAST;
mbed_official 0:f4db29eb9e47 688 lpc_enetif->txb[idx] = p;
mbed_official 0:f4db29eb9e47 689 }
mbed_official 0:f4db29eb9e47 690 else {
mbed_official 0:f4db29eb9e47 691 /* Save size of packet, descriptor is not last */
mbed_official 0:f4db29eb9e47 692 lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT;
mbed_official 0:f4db29eb9e47 693 lpc_enetif->txb[idx] = NULL;
mbed_official 0:f4db29eb9e47 694 }
mbed_official 0:f4db29eb9e47 695
mbed_official 0:f4db29eb9e47 696 LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
mbed_official 0:f4db29eb9e47 697 ("lpc_low_level_output: pbuf packet(%p) sent, chain#=%d,"
mbed_official 0:f4db29eb9e47 698 " size = %d (index=%d)\n", q->payload, dn, q->len, idx));
mbed_official 0:f4db29eb9e47 699
mbed_official 0:f4db29eb9e47 700 lpc_enetif->ptxd[idx].packet = (u32_t) q->payload;
mbed_official 0:f4db29eb9e47 701
mbed_official 0:f4db29eb9e47 702 q = q->next;
mbed_official 0:f4db29eb9e47 703
mbed_official 0:f4db29eb9e47 704 idx++;
mbed_official 0:f4db29eb9e47 705 if (idx >= LPC_NUM_BUFF_TXDESCS)
mbed_official 0:f4db29eb9e47 706 idx = 0;
mbed_official 0:f4db29eb9e47 707 }
mbed_official 0:f4db29eb9e47 708
mbed_official 0:f4db29eb9e47 709 LPC_EMAC->TxProduceIndex = idx;
mbed_official 0:f4db29eb9e47 710
mbed_official 0:f4db29eb9e47 711 LINK_STATS_INC(link.xmit);
mbed_official 0:f4db29eb9e47 712
mbed_official 0:f4db29eb9e47 713 #if NO_SYS == 0
mbed_official 0:f4db29eb9e47 714 /* Restore access */
mbed_official 0:f4db29eb9e47 715 sys_mutex_unlock(&lpc_enetif->TXLockMutex);
mbed_official 0:f4db29eb9e47 716 #endif
emilmont 1:0c9d93e2f51c 717
emilmont 1:0c9d93e2f51c 718 return ERR_OK;
mbed_official 0:f4db29eb9e47 719 }
mbed_official 0:f4db29eb9e47 720
mbed_official 0:f4db29eb9e47 721 /** \brief LPC EMAC interrupt handler.
mbed_official 0:f4db29eb9e47 722 *
mbed_official 0:f4db29eb9e47 723 * This function handles the transmit, receive, and error interrupt of
mbed_official 0:f4db29eb9e47 724 * the LPC177x_8x. This is meant to be used when NO_SYS=0.
mbed_official 0:f4db29eb9e47 725 */
mbed_official 0:f4db29eb9e47 726 void ENET_IRQHandler(void)
mbed_official 0:f4db29eb9e47 727 {
mbed_official 0:f4db29eb9e47 728 #if NO_SYS == 1
mbed_official 0:f4db29eb9e47 729 /* Interrupts are not used without an RTOS */
mbed_official 0:f4db29eb9e47 730 NVIC_DisableIRQ(ENET_IRQn);
mbed_official 0:f4db29eb9e47 731 #else
mbed_official 0:f4db29eb9e47 732 uint32_t ints;
mbed_official 0:f4db29eb9e47 733
mbed_official 0:f4db29eb9e47 734 /* Interrupts are of 2 groups - transmit or receive. Based on the
mbed_official 0:f4db29eb9e47 735 interrupt, kick off the receive or transmit (cleanup) task */
mbed_official 0:f4db29eb9e47 736
mbed_official 0:f4db29eb9e47 737 /* Get pending interrupts */
mbed_official 0:f4db29eb9e47 738 ints = LPC_EMAC->IntStatus;
mbed_official 0:f4db29eb9e47 739
mbed_official 0:f4db29eb9e47 740 if (ints & RXINTGROUP) {
emilmont 1:0c9d93e2f51c 741 /* RX group interrupt(s): Give semaphore to wakeup RX receive task.*/
emilmont 1:0c9d93e2f51c 742 sys_sem_signal(&lpc_enetdata.RxSem);
mbed_official 0:f4db29eb9e47 743 }
mbed_official 0:f4db29eb9e47 744
mbed_official 0:f4db29eb9e47 745 if (ints & TXINTGROUP) {
emilmont 1:0c9d93e2f51c 746 /* TX group interrupt(s): Give semaphore to wakeup TX cleanup task. */
emilmont 1:0c9d93e2f51c 747 sys_sem_signal(&lpc_enetdata.TxCleanSem);
mbed_official 0:f4db29eb9e47 748 }
mbed_official 0:f4db29eb9e47 749
mbed_official 0:f4db29eb9e47 750 /* Clear pending interrupts */
mbed_official 0:f4db29eb9e47 751 LPC_EMAC->IntClear = ints;
mbed_official 0:f4db29eb9e47 752 #endif
mbed_official 0:f4db29eb9e47 753 }
mbed_official 0:f4db29eb9e47 754
mbed_official 0:f4db29eb9e47 755 #if NO_SYS == 0
mbed_official 0:f4db29eb9e47 756 /** \brief Packet reception task
mbed_official 0:f4db29eb9e47 757 *
mbed_official 0:f4db29eb9e47 758 * This task is called when a packet is received. It will
mbed_official 0:f4db29eb9e47 759 * pass the packet to the LWIP core.
emilmont 1:0c9d93e2f51c 760 *
emilmont 1:0c9d93e2f51c 761 * \param[in] pvParameters Not used yet
mbed_official 0:f4db29eb9e47 762 */
emilmont 1:0c9d93e2f51c 763 static void packet_rx(void* pvParameters) {
mbed_official 0:f4db29eb9e47 764 struct lpc_enetdata *lpc_enetif = pvParameters;
mbed_official 0:f4db29eb9e47 765
mbed_official 0:f4db29eb9e47 766 while (1) {
mbed_official 0:f4db29eb9e47 767 /* Wait for receive task to wakeup */
mbed_official 0:f4db29eb9e47 768 sys_arch_sem_wait(&lpc_enetif->RxSem, 0);
mbed_official 0:f4db29eb9e47 769
mbed_official 0:f4db29eb9e47 770 /* Process packets until all empty */
mbed_official 0:f4db29eb9e47 771 while (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex)
mbed_official 0:f4db29eb9e47 772 lpc_enetif_input(lpc_enetif->netif);
mbed_official 0:f4db29eb9e47 773 }
mbed_official 0:f4db29eb9e47 774 }
mbed_official 0:f4db29eb9e47 775
mbed_official 0:f4db29eb9e47 776 /** \brief Transmit cleanup task
mbed_official 0:f4db29eb9e47 777 *
mbed_official 0:f4db29eb9e47 778 * This task is called when a transmit interrupt occurs and
mbed_official 0:f4db29eb9e47 779 * reclaims the pbuf and descriptor used for the packet once
mbed_official 0:f4db29eb9e47 780 * the packet has been transferred.
emilmont 1:0c9d93e2f51c 781 *
emilmont 1:0c9d93e2f51c 782 * \param[in] pvParameters Not used yet
mbed_official 0:f4db29eb9e47 783 */
emilmont 1:0c9d93e2f51c 784 static void packet_tx(void* pvParameters) {
mbed_official 0:f4db29eb9e47 785 struct lpc_enetdata *lpc_enetif = pvParameters;
mbed_official 0:f4db29eb9e47 786 s32_t idx;
mbed_official 0:f4db29eb9e47 787
mbed_official 0:f4db29eb9e47 788 while (1) {
mbed_official 0:f4db29eb9e47 789 /* Wait for transmit cleanup task to wakeup */
mbed_official 0:f4db29eb9e47 790 sys_arch_sem_wait(&lpc_enetif->TxCleanSem, 0);
mbed_official 0:f4db29eb9e47 791
mbed_official 0:f4db29eb9e47 792 /* Error handling for TX underruns. This should never happen unless
mbed_official 0:f4db29eb9e47 793 something is holding the bus or the clocks are going too slow. It
mbed_official 0:f4db29eb9e47 794 can probably be safely removed. */
mbed_official 0:f4db29eb9e47 795 if (LPC_EMAC->IntStatus & EMAC_INT_TX_UNDERRUN) {
emilmont 1:0c9d93e2f51c 796 LINK_STATS_INC(link.err);
mbed_official 0:f4db29eb9e47 797 LINK_STATS_INC(link.drop);
mbed_official 0:f4db29eb9e47 798
mbed_official 0:f4db29eb9e47 799 #if NO_SYS == 0
mbed_official 0:f4db29eb9e47 800 /* Get exclusive access */
mbed_official 0:f4db29eb9e47 801 sys_mutex_lock(&lpc_enetif->TXLockMutex);
mbed_official 0:f4db29eb9e47 802 #endif
mbed_official 0:f4db29eb9e47 803 /* Reset the TX side */
mbed_official 0:f4db29eb9e47 804 LPC_EMAC->MAC1 |= EMAC_MAC1_RES_TX;
mbed_official 0:f4db29eb9e47 805 LPC_EMAC->IntClear = EMAC_INT_TX_UNDERRUN;
mbed_official 0:f4db29eb9e47 806
mbed_official 0:f4db29eb9e47 807 /* De-allocate all queued TX pbufs */
mbed_official 0:f4db29eb9e47 808 for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) {
mbed_official 0:f4db29eb9e47 809 if (lpc_enetif->txb[idx] != NULL) {
mbed_official 0:f4db29eb9e47 810 pbuf_free(lpc_enetif->txb[idx]);
mbed_official 0:f4db29eb9e47 811 lpc_enetif->txb[idx] = NULL;
mbed_official 0:f4db29eb9e47 812 }
mbed_official 0:f4db29eb9e47 813 }
mbed_official 0:f4db29eb9e47 814
mbed_official 0:f4db29eb9e47 815 #if NO_SYS == 0
mbed_official 0:f4db29eb9e47 816 /* Restore access */
mbed_official 0:f4db29eb9e47 817 sys_mutex_unlock(&lpc_enetif->TXLockMutex);
mbed_official 0:f4db29eb9e47 818 #endif
mbed_official 0:f4db29eb9e47 819 /* Start TX side again */
mbed_official 0:f4db29eb9e47 820 lpc_tx_setup(lpc_enetif);
mbed_official 0:f4db29eb9e47 821 } else {
mbed_official 0:f4db29eb9e47 822 /* Free TX buffers that are done sending */
mbed_official 0:f4db29eb9e47 823 lpc_tx_reclaim(lpc_enetdata.netif);
mbed_official 0:f4db29eb9e47 824 }
mbed_official 0:f4db29eb9e47 825 }
mbed_official 0:f4db29eb9e47 826 }
mbed_official 0:f4db29eb9e47 827 #endif
mbed_official 0:f4db29eb9e47 828
mbed_official 0:f4db29eb9e47 829 /** \brief Low level init of the MAC and PHY.
mbed_official 0:f4db29eb9e47 830 *
mbed_official 0:f4db29eb9e47 831 * \param[in] netif Pointer to LWIP netif structure
mbed_official 0:f4db29eb9e47 832 */
emilmont 1:0c9d93e2f51c 833 static err_t low_level_init(struct netif *netif)
emilmont 1:0c9d93e2f51c 834 {
mbed_official 0:f4db29eb9e47 835 struct lpc_enetdata *lpc_enetif = netif->state;
emilmont 1:0c9d93e2f51c 836 err_t err = ERR_OK;
emilmont 1:0c9d93e2f51c 837
mbed_official 0:f4db29eb9e47 838 /* Enable MII clocking */
emilmont 1:0c9d93e2f51c 839 LPC_SC->PCONP |= CLKPWR_PCONP_PCENET;
emilmont 1:0c9d93e2f51c 840
emilmont 1:0c9d93e2f51c 841 LPC_PINCON->PINSEL2 = 0x50150105; /* Enable P1 Ethernet Pins. */
emilmont 1:0c9d93e2f51c 842 LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005;
mbed_official 0:f4db29eb9e47 843
mbed_official 0:f4db29eb9e47 844 /* Reset all MAC logic */
mbed_official 0:f4db29eb9e47 845 LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX |
mbed_official 0:f4db29eb9e47 846 EMAC_MAC1_RES_RX | EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES |
mbed_official 0:f4db29eb9e47 847 EMAC_MAC1_SOFT_RES;
mbed_official 0:f4db29eb9e47 848 LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES |
mbed_official 0:f4db29eb9e47 849 EMAC_CR_PASS_RUNT_FRM;
emilmont 1:0c9d93e2f51c 850 osDelay(10);
mbed_official 0:f4db29eb9e47 851
mbed_official 0:f4db29eb9e47 852 /* Initial MAC initialization */
mbed_official 0:f4db29eb9e47 853 LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL;
mbed_official 0:f4db29eb9e47 854 LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN |
mbed_official 0:f4db29eb9e47 855 EMAC_MAC2_VLAN_PAD_EN;
mbed_official 0:f4db29eb9e47 856 LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN;
mbed_official 0:f4db29eb9e47 857
mbed_official 0:f4db29eb9e47 858 /* Set RMII management clock rate to lowest speed */
mbed_official 0:f4db29eb9e47 859 LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(11) | EMAC_MCFG_RES_MII;
mbed_official 0:f4db29eb9e47 860 LPC_EMAC->MCFG &= ~EMAC_MCFG_RES_MII;
mbed_official 0:f4db29eb9e47 861
mbed_official 0:f4db29eb9e47 862 /* Maximum number of retries, 0x37 collision window, gap */
mbed_official 0:f4db29eb9e47 863 LPC_EMAC->CLRT = EMAC_CLRT_DEF;
mbed_official 0:f4db29eb9e47 864 LPC_EMAC->IPGR = EMAC_IPGR_P1_DEF | EMAC_IPGR_P2_DEF;
mbed_official 0:f4db29eb9e47 865
mbed_official 0:f4db29eb9e47 866 #if LPC_EMAC_RMII
mbed_official 0:f4db29eb9e47 867 /* RMII setup */
mbed_official 0:f4db29eb9e47 868 LPC_EMAC->Command = EMAC_CR_PASS_RUNT_FRM | EMAC_CR_RMII;
mbed_official 0:f4db29eb9e47 869 #else
mbed_official 0:f4db29eb9e47 870 /* MII setup */
mbed_official 0:f4db29eb9e47 871 LPC_EMAC->CR = EMAC_CR_PASS_RUNT_FRM;
mbed_official 0:f4db29eb9e47 872 #endif
mbed_official 0:f4db29eb9e47 873
mbed_official 0:f4db29eb9e47 874 /* Initialize the PHY and reset */
mbed_official 0:f4db29eb9e47 875 err = lpc_phy_init(netif, LPC_EMAC_RMII);
mbed_official 0:f4db29eb9e47 876 if (err != ERR_OK)
mbed_official 0:f4db29eb9e47 877 return err;
mbed_official 0:f4db29eb9e47 878
mbed_official 0:f4db29eb9e47 879 /* Save station address */
mbed_official 0:f4db29eb9e47 880 LPC_EMAC->SA2 = (u32_t) netif->hwaddr[0] |
mbed_official 0:f4db29eb9e47 881 (((u32_t) netif->hwaddr[1]) << 8);
mbed_official 0:f4db29eb9e47 882 LPC_EMAC->SA1 = (u32_t) netif->hwaddr[2] |
mbed_official 0:f4db29eb9e47 883 (((u32_t) netif->hwaddr[3]) << 8);
mbed_official 0:f4db29eb9e47 884 LPC_EMAC->SA0 = (u32_t) netif->hwaddr[4] |
mbed_official 0:f4db29eb9e47 885 (((u32_t) netif->hwaddr[5]) << 8);
mbed_official 0:f4db29eb9e47 886
mbed_official 0:f4db29eb9e47 887 /* Setup transmit and receive descriptors */
mbed_official 0:f4db29eb9e47 888 if (lpc_tx_setup(lpc_enetif) != ERR_OK)
mbed_official 0:f4db29eb9e47 889 return ERR_BUF;
mbed_official 0:f4db29eb9e47 890 if (lpc_rx_setup(lpc_enetif) != ERR_OK)
mbed_official 0:f4db29eb9e47 891 return ERR_BUF;
mbed_official 0:f4db29eb9e47 892
mbed_official 0:f4db29eb9e47 893 /* Enable packet reception */
mbed_official 0:f4db29eb9e47 894 #if IP_SOF_BROADCAST_RECV
mbed_official 0:f4db29eb9e47 895 LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN | EMAC_RFC_BCAST_EN;
mbed_official 0:f4db29eb9e47 896 #else
mbed_official 0:f4db29eb9e47 897 LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN;
mbed_official 0:f4db29eb9e47 898 #endif
mbed_official 0:f4db29eb9e47 899
mbed_official 0:f4db29eb9e47 900 /* Clear and enable rx/tx interrupts */
mbed_official 0:f4db29eb9e47 901 LPC_EMAC->IntClear = 0xFFFF;
mbed_official 0:f4db29eb9e47 902 LPC_EMAC->IntEnable = RXINTGROUP | TXINTGROUP;
mbed_official 0:f4db29eb9e47 903
mbed_official 0:f4db29eb9e47 904 /* Enable RX and TX */
mbed_official 0:f4db29eb9e47 905 LPC_EMAC->Command |= EMAC_CR_RX_EN | EMAC_CR_TX_EN;
mbed_official 0:f4db29eb9e47 906 LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
mbed_official 0:f4db29eb9e47 907
mbed_official 0:f4db29eb9e47 908 return err;
mbed_official 0:f4db29eb9e47 909 }
emilmont 1:0c9d93e2f51c 910
emilmont 1:0c9d93e2f51c 911 /* This function provides a method for the PHY to setup the EMAC
emilmont 1:0c9d93e2f51c 912 for the PHY negotiated duplex mode */
emilmont 1:0c9d93e2f51c 913 void lpc_emac_set_duplex(int full_duplex)
emilmont 1:0c9d93e2f51c 914 {
emilmont 1:0c9d93e2f51c 915 if (full_duplex) {
emilmont 1:0c9d93e2f51c 916 LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP;
emilmont 1:0c9d93e2f51c 917 LPC_EMAC->Command |= EMAC_CR_FULL_DUP;
emilmont 1:0c9d93e2f51c 918 LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP;
emilmont 1:0c9d93e2f51c 919 } else {
emilmont 1:0c9d93e2f51c 920 LPC_EMAC->MAC2 &= ~EMAC_MAC2_FULL_DUP;
emilmont 1:0c9d93e2f51c 921 LPC_EMAC->Command &= ~EMAC_CR_FULL_DUP;
emilmont 1:0c9d93e2f51c 922 LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP;
emilmont 1:0c9d93e2f51c 923 }
mbed_official 0:f4db29eb9e47 924 }
emilmont 1:0c9d93e2f51c 925
emilmont 1:0c9d93e2f51c 926 /* This function provides a method for the PHY to setup the EMAC
emilmont 1:0c9d93e2f51c 927 for the PHY negotiated bit rate */
emilmont 1:0c9d93e2f51c 928 void lpc_emac_set_speed(int mbs_100)
emilmont 1:0c9d93e2f51c 929 {
emilmont 1:0c9d93e2f51c 930 if (mbs_100)
emilmont 1:0c9d93e2f51c 931 LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
emilmont 1:0c9d93e2f51c 932 else
emilmont 1:0c9d93e2f51c 933 LPC_EMAC->SUPP = 0;
emilmont 1:0c9d93e2f51c 934 }
emilmont 1:0c9d93e2f51c 935
emilmont 1:0c9d93e2f51c 936 /**
mbed_official 0:f4db29eb9e47 937 * This function is the ethernet packet send function. It calls
emilmont 1:0c9d93e2f51c 938 * etharp_output after checking link status.
emilmont 1:0c9d93e2f51c 939 *
emilmont 1:0c9d93e2f51c 940 * \param[in] netif the lwip network interface structure for this lpc_enetif
emilmont 1:0c9d93e2f51c 941 * \param[in] q Pointer to pbug to send
emilmont 1:0c9d93e2f51c 942 * \param[in] ipaddr IP address
mbed_official 0:f4db29eb9e47 943 * \return ERR_OK or error code
emilmont 1:0c9d93e2f51c 944 */
mbed_official 0:f4db29eb9e47 945 err_t lpc_etharp_output(struct netif *netif, struct pbuf *q,
mbed_official 0:f4db29eb9e47 946 ip_addr_t *ipaddr)
mbed_official 0:f4db29eb9e47 947 {
mbed_official 0:f4db29eb9e47 948 /* Only send packet is link is up */
mbed_official 0:f4db29eb9e47 949 if (netif->flags & NETIF_FLAG_LINK_UP)
mbed_official 0:f4db29eb9e47 950 return etharp_output(netif, q, ipaddr);
mbed_official 0:f4db29eb9e47 951
mbed_official 0:f4db29eb9e47 952 return ERR_CONN;
emilmont 1:0c9d93e2f51c 953 }
emilmont 1:0c9d93e2f51c 954
emilmont 1:0c9d93e2f51c 955 #if NO_SYS == 0
emilmont 1:0c9d93e2f51c 956 /* periodic PHY status update */
emilmont 1:0c9d93e2f51c 957 void phy_update(void const *nif) {
emilmont 1:0c9d93e2f51c 958 lpc_phy_sts_sm((struct netif*)nif);
emilmont 1:0c9d93e2f51c 959 }
emilmont 1:0c9d93e2f51c 960 osTimerDef(phy_update, phy_update);
emilmont 1:0c9d93e2f51c 961 #endif
emilmont 1:0c9d93e2f51c 962
emilmont 1:0c9d93e2f51c 963 /**
emilmont 1:0c9d93e2f51c 964 * Should be called at the beginning of the program to set up the
emilmont 1:0c9d93e2f51c 965 * network interface.
emilmont 1:0c9d93e2f51c 966 *
emilmont 1:0c9d93e2f51c 967 * This function should be passed as a parameter to netif_add().
emilmont 1:0c9d93e2f51c 968 *
emilmont 1:0c9d93e2f51c 969 * @param[in] netif the lwip network interface structure for this lpc_enetif
emilmont 1:0c9d93e2f51c 970 * @return ERR_OK if the loopif is initialized
emilmont 1:0c9d93e2f51c 971 * ERR_MEM if private data couldn't be allocated
emilmont 1:0c9d93e2f51c 972 * any other err_t on error
emilmont 1:0c9d93e2f51c 973 */
emilmont 1:0c9d93e2f51c 974 err_t lpc_enetif_init(struct netif *netif)
emilmont 1:0c9d93e2f51c 975 {
emilmont 1:0c9d93e2f51c 976 err_t err;
emilmont 1:0c9d93e2f51c 977
emilmont 1:0c9d93e2f51c 978 LWIP_ASSERT("netif != NULL", (netif != NULL));
emilmont 1:0c9d93e2f51c 979
mbed_official 0:f4db29eb9e47 980 lpc_enetdata.netif = netif;
mbed_official 0:f4db29eb9e47 981
mbed_official 0:f4db29eb9e47 982 /* set MAC hardware address */
emilmont 1:0c9d93e2f51c 983 mbed_mac_address((char *)netif->hwaddr);
emilmont 1:0c9d93e2f51c 984 netif->hwaddr_len = ETHARP_HWADDR_LEN;
emilmont 1:0c9d93e2f51c 985
emilmont 1:0c9d93e2f51c 986 /* maximum transfer unit */
emilmont 1:0c9d93e2f51c 987 netif->mtu = 1500;
emilmont 1:0c9d93e2f51c 988
emilmont 1:0c9d93e2f51c 989 /* device capabilities */
emilmont 1:0c9d93e2f51c 990 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
emilmont 1:0c9d93e2f51c 991
mbed_official 0:f4db29eb9e47 992 /* Initialize the hardware */
mbed_official 0:f4db29eb9e47 993 netif->state = &lpc_enetdata;
emilmont 1:0c9d93e2f51c 994 err = low_level_init(netif);
mbed_official 0:f4db29eb9e47 995 if (err != ERR_OK)
mbed_official 0:f4db29eb9e47 996 return err;
mbed_official 0:f4db29eb9e47 997
emilmont 1:0c9d93e2f51c 998 #if LWIP_NETIF_HOSTNAME
emilmont 1:0c9d93e2f51c 999 /* Initialize interface hostname */
emilmont 1:0c9d93e2f51c 1000 netif->hostname = "lwiplpc";
mbed_official 0:f4db29eb9e47 1001 #endif /* LWIP_NETIF_HOSTNAME */
mbed_official 0:f4db29eb9e47 1002
emilmont 1:0c9d93e2f51c 1003 netif->name[0] = 'e';
mbed_official 0:f4db29eb9e47 1004 netif->name[1] = 'n';
mbed_official 0:f4db29eb9e47 1005
emilmont 1:0c9d93e2f51c 1006 netif->output = lpc_etharp_output;
mbed_official 0:f4db29eb9e47 1007 netif->linkoutput = lpc_low_level_output;
mbed_official 0:f4db29eb9e47 1008
emilmont 1:0c9d93e2f51c 1009 /* CMSIS-RTOS, start tasks */
mbed_official 0:f4db29eb9e47 1010 #if NO_SYS == 0
emilmont 1:0c9d93e2f51c 1011 #ifdef CMSIS_OS_RTX
emilmont 1:0c9d93e2f51c 1012 memset(lpc_enetdata.xTXDCountSem.data, 0, sizeof(lpc_enetdata.xTXDCountSem.data));
emilmont 1:0c9d93e2f51c 1013 lpc_enetdata.xTXDCountSem.def.semaphore = lpc_enetdata.xTXDCountSem.data;
emilmont 1:0c9d93e2f51c 1014 #endif
emilmont 1:0c9d93e2f51c 1015 lpc_enetdata.xTXDCountSem.id = osSemaphoreCreate(&lpc_enetdata.xTXDCountSem.def, LPC_NUM_BUFF_TXDESCS);
emilmont 1:0c9d93e2f51c 1016 LWIP_ASSERT("xTXDCountSem creation error", (lpc_enetdata.xTXDCountSem.id != NULL));
emilmont 1:0c9d93e2f51c 1017
emilmont 1:0c9d93e2f51c 1018 err = sys_mutex_new(&lpc_enetdata.TXLockMutex);
mbed_official 0:f4db29eb9e47 1019 LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK));
emilmont 1:0c9d93e2f51c 1020
mbed_official 0:f4db29eb9e47 1021 /* Packet receive task */
mbed_official 0:f4db29eb9e47 1022 err = sys_sem_new(&lpc_enetdata.RxSem, 0);
emilmont 1:0c9d93e2f51c 1023 LWIP_ASSERT("RxSem creation error", (err == ERR_OK));
emilmont 1:0c9d93e2f51c 1024 sys_thread_new("receive_thread", packet_rx, netif->state, DEFAULT_THREAD_STACKSIZE, RX_PRIORITY);
emilmont 1:0c9d93e2f51c 1025
mbed_official 0:f4db29eb9e47 1026 /* Transmit cleanup task */
emilmont 1:0c9d93e2f51c 1027 sys_thread_new("txclean_thread", packet_tx, netif->state, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY);
emilmont 1:0c9d93e2f51c 1028
emilmont 1:0c9d93e2f51c 1029 /* periodic PHY status update */
emilmont 1:0c9d93e2f51c 1030 osTimerId phy_timer = osTimerCreate(osTimer(phy_update), osTimerPeriodic, (void *)netif);
emilmont 1:0c9d93e2f51c 1031 osTimerStart(phy_timer, 250);
mbed_official 0:f4db29eb9e47 1032 #endif
emilmont 1:0c9d93e2f51c 1033
emilmont 1:0c9d93e2f51c 1034 return ERR_OK;
mbed_official 0:f4db29eb9e47 1035 }
mbed_official 0:f4db29eb9e47 1036
emilmont 1:0c9d93e2f51c 1037 /**
emilmont 1:0c9d93e2f51c 1038 * @}
mbed_official 0:f4db29eb9e47 1039 */
mbed_official 0:f4db29eb9e47 1040
emilmont 1:0c9d93e2f51c 1041 /* --------------------------------- End Of File ------------------------------ */