diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPC546XX/harware_init_LPC546XX.c b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPC546XX/harware_init_LPC546XX.c new file mode 100644 index 00000000000..22836f980a2 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPC546XX/harware_init_LPC546XX.c @@ -0,0 +1,261 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fsl_iocon.h" + +#define IOCON_PIO_DIGITAL_EN 0x0100u /*!<@brief Enables digital function */ +#define IOCON_PIO_FUNC0 0x00u /*!<@brief Selects pin function 0 */ +#define IOCON_PIO_FUNC1 0x01u /*!<@brief Selects pin function 1 */ +#define IOCON_PIO_FUNC6 0x06u /*!<@brief Selects pin function 6 */ +#define IOCON_PIO_FUNC7 0x07u /*!<@brief Selects pin function 7 */ +#define IOCON_PIO_INPFILT_OFF 0x0200u /*!<@brief Input filter disabled */ +#define IOCON_PIO_INV_DI 0x00u /*!<@brief Input function is not inverted */ +#define IOCON_PIO_MODE_INACT 0x00u /*!<@brief No addition pin function */ +#define IOCON_PIO_MODE_PULLUP 0x20u /*!<@brief Selects pull-up function */ +#define IOCON_PIO_OPENDRAIN_DI 0x00u /*!<@brief Open drain is disabled */ +#define IOCON_PIO_SLEW_FAST 0x0400u /*!<@brief Fast mode, slew rate control is disabled */ +#define IOCON_PIO_SLEW_STANDARD 0x00u /*!<@brief Standard mode, output slew rate control is enabled */ + +/******************************************************************************* + * Code + ******************************************************************************/ +void lpc546xx_init_eth_hardware(void) +{ + CLOCK_EnableClock(kCLOCK_InputMux); + + /* Enables the clock for the IOCON block. 0 = Disable; 1 = Enable.: 0x01u */ + CLOCK_EnableClock(kCLOCK_Iocon); + + const uint32_t port0_pin10_config = (/* Pin is configured as SWO */ + IOCON_PIO_FUNC6 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Input filter disabled */ + IOCON_PIO_INPFILT_OFF | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT0 PIN10 (coords: P2) is configured as SWO */ + IOCON_PinMuxSet(IOCON, 0U, 10U, port0_pin10_config); + + const uint32_t port0_pin17_config = (/* Pin is configured as ENET_TXD1 */ + IOCON_PIO_FUNC7 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Input filter disabled */ + IOCON_PIO_INPFILT_OFF | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT0 PIN17 (coords: E14) is configured as ENET_TXD1 */ + IOCON_PinMuxSet(IOCON, 0U, 17U, port0_pin17_config); + + const uint32_t port0_pin29_config = (/* Pin is configured as FC0_RXD_SDA_MOSI */ + IOCON_PIO_FUNC1 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Input filter disabled */ + IOCON_PIO_INPFILT_OFF | + /* Fast mode, slew rate control is disabled */ + IOCON_PIO_SLEW_FAST | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT0 PIN29 (coords: B13) is configured as FC0_RXD_SDA_MOSI */ + IOCON_PinMuxSet(IOCON, 0U, 29U, port0_pin29_config); + + const uint32_t port0_pin30_config = (/* Pin is configured as FC0_TXD_SCL_MISO */ + IOCON_PIO_FUNC1 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Input filter disabled */ + IOCON_PIO_INPFILT_OFF | + /* Fast mode, slew rate control is disabled */ + IOCON_PIO_SLEW_FAST | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT0 PIN30 (coords: A2) is configured as FC0_TXD_SCL_MISO */ + IOCON_PinMuxSet(IOCON, 0U, 30U, port0_pin30_config); + + const uint32_t port2_pin26_config = (/* Pin is configured as PIO2_26 */ + IOCON_PIO_FUNC0 | + /* Selects pull-up function */ + IOCON_PIO_MODE_PULLUP | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Input filter disabled */ + IOCON_PIO_INPFILT_OFF | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT2 PIN26 (coords: H11) is configured as PIO2_26 */ + IOCON_PinMuxSet(IOCON, 2U, 26U, port2_pin26_config); + + const uint32_t port4_pin10_config = (/* Pin is configured as ENET_RX_DV */ + IOCON_PIO_FUNC1 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Input filter disabled */ + IOCON_PIO_INPFILT_OFF | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT4 PIN10 (coords: B9) is configured as ENET_RX_DV */ + IOCON_PinMuxSet(IOCON, 4U, 10U, port4_pin10_config); + + const uint32_t port4_pin11_config = (/* Pin is configured as ENET_RXD0 */ + IOCON_PIO_FUNC1 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Input filter disabled */ + IOCON_PIO_INPFILT_OFF | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT4 PIN11 (coords: A9) is configured as ENET_RXD0 */ + IOCON_PinMuxSet(IOCON, 4U, 11U, port4_pin11_config); + + const uint32_t port4_pin12_config = (/* Pin is configured as ENET_RXD1 */ + IOCON_PIO_FUNC1 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Input filter disabled */ + IOCON_PIO_INPFILT_OFF | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT4 PIN12 (coords: A6) is configured as ENET_RXD1 */ + IOCON_PinMuxSet(IOCON, 4U, 12U, port4_pin12_config); + + const uint32_t port4_pin13_config = (/* Pin is configured as ENET_TX_EN */ + IOCON_PIO_FUNC1 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Input filter disabled */ + IOCON_PIO_INPFILT_OFF | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT4 PIN13 (coords: B6) is configured as ENET_TX_EN */ + IOCON_PinMuxSet(IOCON, 4U, 13U, port4_pin13_config); + + const uint32_t port4_pin14_config = (/* Pin is configured as ENET_RX_CLK */ + IOCON_PIO_FUNC1 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Input filter disabled */ + IOCON_PIO_INPFILT_OFF | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT4 PIN14 (coords: B5) is configured as ENET_RX_CLK */ + IOCON_PinMuxSet(IOCON, 4U, 14U, port4_pin14_config); + + const uint32_t port4_pin15_config = (/* Pin is configured as ENET_MDC */ + IOCON_PIO_FUNC1 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Input filter disabled */ + IOCON_PIO_INPFILT_OFF | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT4 PIN15 (coords: A4) is configured as ENET_MDC */ + IOCON_PinMuxSet(IOCON, 4U, 15U, port4_pin15_config); + + const uint32_t port4_pin16_config = (/* Pin is configured as ENET_MDIO */ + IOCON_PIO_FUNC1 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Input filter disabled */ + IOCON_PIO_INPFILT_OFF | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT4 PIN16 (coords: C4) is configured as ENET_MDIO */ + IOCON_PinMuxSet(IOCON, 4U, 16U, port4_pin16_config); + + const uint32_t port4_pin8_config = (/* Pin is configured as ENET_TXD0 */ + IOCON_PIO_FUNC1 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Input filter disabled */ + IOCON_PIO_INPFILT_OFF | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT4 PIN8 (coords: B14) is configured as ENET_TXD0 */ + IOCON_PinMuxSet(IOCON, 4U, 8U, port4_pin8_config); +} + diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPC546XX/lpc546xx_emac.c b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPC546XX/lpc546xx_emac.c new file mode 100644 index 00000000000..242699adae0 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPC546XX/lpc546xx_emac.c @@ -0,0 +1,692 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lwip/opt.h" +#include "lwip/sys.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/tcpip.h" +#include "lwip/ethip6.h" +#include "netif/etharp.h" +#include "netif/ppp/pppoe.h" + +#include "eth_arch.h" +#include "sys_arch.h" + +#include "fsl_phy.h" +#include "lpc546xx_emac_config.h" +#include + +#include "mbed_interface.h" + +#if LWIP_ARP || LWIP_ETHERNET + +enet_handle_t g_handle; +// RX packet buffer pointers +struct pbuf *rx_buff[ENET_RX_RING_LEN]; +// TX packet buffer pointers +uint8_t *tx_buff[ENET_TX_RING_LEN]; +// RX packet payload pointers +uint32_t rx_ptr[ENET_RX_RING_LEN]; + +/** \brief Debug output formatter lock define + * + * When using FreeRTOS and with LWIP_DEBUG enabled, enabling this + * define will allow RX debug messages to not interleave with the + * TX messages (so they are actually readable). Not enabling this + * define when the system is under load will cause the output to + * be unreadable. There is a small tradeoff in performance for this + * so use it only for debug. */ +//#define LOCK_RX_THREAD + +/* LPC546XX EMAC driver data structure */ +struct lpc_enetdata { + struct netif *netif; /**< Reference back to LWIP parent netif */ + osThreadId_t thread; /**< Processing thread */ + sys_mutex_t TXLockMutex; /**< TX critical section mutex */ + sys_sem_t xTXDCountSem; /**< TX free buffer counting semaphore */ +}; + +static struct lpc_enetdata lpc_enetdata; + +/* \brief Flags for worker thread */ +#define FLAG_TX 1 +#define FLAG_RX 2 + +/** \brief Driver thread priority */ +#define THREAD_PRIORITY (osPriorityNormal) + +#ifdef LWIP_DEBUG +#define THREAD_STACKSIZE (DEFAULT_THREAD_STACKSIZE * 5) +#else +#define THREAD_STACKSIZE DEFAULT_THREAD_STACKSIZE +#endif + +static void lpc546xx_phy_task(void *data); +static void lpc546xx_packet_rx(struct lpc_enetdata *lpc_enet); +static void lpc546xx_packet_tx(struct lpc_enetdata *lpc_enet); + +#define PHY_TASK_PERIOD_MS 200 + +/******************************************************************************** + * Buffer management + ********************************************************************************/ +/* + * This function will queue a new receive buffer + */ +static void update_read_buffer(enet_rx_bd_struct_t *rxDesc, uint8_t *buf) +{ + enet_rx_bd_ring_t *rxBdRing = (enet_rx_bd_ring_t *)&g_handle.rxBdRing[0]; + uint32_t control = ENET_RXDESCRIP_RD_OWN_MASK | ENET_RXDESCRIP_RD_BUFF1VALID_MASK | ENET_RXDESCRIP_RD_IOC_MASK; + uint32_t index = rxBdRing->rxGenIdx; + /* Increase the index. */ + index++; + if (index >= ENET_RX_RING_LEN) { + index = 0; + } + + rxBdRing->rxGenIdx = index; + if (buf != NULL) { + rxDesc->buff1Addr = (uint32_t)buf; + } + + rxDesc->buff2Addr = 0; + rxDesc->reserved = 0; + rxDesc->control = control; +} + +/** \brief Free TX buffers that are complete + * + * \param[in] lpc_enet Pointer to driver data structure + */ +static void lpc546xx_tx_reclaim(struct lpc_enetdata *lpc_enet) +{ + static uint8_t consume_index = 0; + enet_tx_bd_ring_t *txBdRing = (enet_tx_bd_ring_t *)&g_handle.txBdRing[0]; + + while (consume_index != txBdRing->txConsumIdx) { + /* Free the transmit buffer */ + free(tx_buff[consume_index]); + tx_buff[consume_index] = NULL; + + osSemaphoreRelease(lpc_enetdata.xTXDCountSem.id); + + consume_index++; + if (consume_index >= ENET_TX_RING_LEN) { + consume_index = 0; + } + } +} + +/******************************************************************************** + * Internal data + ********************************************************************************/ +#define ENET_BuffSizeAlign(n) ENET_ALIGN(n, ENET_BUFF_ALIGNMENT) +#define ENET_ALIGN(x,align) ((unsigned int)((x) + ((align)-1)) & (unsigned int)(~(unsigned int)((align)- 1))) +extern void lpc546xx_init_eth_hardware(void); + +/** \brief Allocates a pbuf and returns the data from the incoming packet. + * + * \param[in] netif the lwip network interface structure for this lpc_enetif + * \return a pbuf filled with the received packet (including MAC header) + * NULL on memory error + */ +static struct pbuf *lpc546xx_low_level_input(struct netif *netif) +{ + enet_rx_bd_ring_t *rxBdRing = (enet_rx_bd_ring_t *)&g_handle.rxBdRing[0]; + enet_rx_bd_struct_t *bdPtr = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; +#ifdef LOCK_RX_THREAD + struct lpc_enetdata *lpc_enet = netif->state; +#endif + struct pbuf *p = NULL; + struct pbuf *temp_rxbuf = NULL; + u32_t length = 0; + + /* Determine if a frame has been received */ + if ((bdPtr->control & ENET_RXDESCRIP_WR_OWN_MASK) != 0) { + return p; + } + +#ifdef LOCK_RX_THREAD + /* Get exclusive access */ + sys_mutex_lock(&lpc_enet->TXLockMutex); +#endif + + /* Determine if the received frame has an error */ + if ((bdPtr->control & ENET_RXDESCRIP_WR_ERRSUM_MASK) != 0) { + LINK_STATS_INC(link.err); + LINK_STATS_INC(link.drop); + /* Re-use the same buffer in case of error */ + update_read_buffer(bdPtr, NULL); + } else { + if (bdPtr->control & ENET_RXDESCRIP_WR_LD_MASK) { + length = (bdPtr->control & ENET_RXDESCRIP_WR_PACKETLEN_MASK); + } else { + length = rxBdRing->rxBuffSizeAlign; + } + + /* Zero-copy */ + p = rx_buff[rxBdRing->rxGenIdx]; + p->len = length; + + /* Attempt to queue new buffer */ + temp_rxbuf = pbuf_alloc(PBUF_RAW, ENET_ALIGN(ENET_ETH_MAX_FLEN, ENET_BUFF_ALIGNMENT), PBUF_RAM); + if (NULL == temp_rxbuf) { + /* Drop frame (out of memory) */ + LINK_STATS_INC(link.drop); + + LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, + ("lpc546xx_low_level_input: Packet index %d dropped for OOM\n", rxBdRing->rxGenIdx)); + + /* Re-queue the same buffer */ + update_read_buffer(bdPtr, NULL); + +#ifdef LOCK_RX_THREAD + sys_mutex_unlock(&lpc_enet->TXLockMutex); +#endif + + return NULL; + } + + rx_buff[rxBdRing->rxGenIdx] = temp_rxbuf; + rx_ptr[rxBdRing->rxGenIdx] = (uint32_t)rx_buff[rxBdRing->rxGenIdx]->payload; + + LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, + ("lpc_low_level_input: Packet received: %p, size %"PRIu32" (index=%d)\n", p, length, rxBdRing->rxGenIdx)); + + update_read_buffer(bdPtr, rx_buff[rxBdRing->rxGenIdx]->payload); + + /* Save size */ + p->tot_len = (u16_t)length; + LINK_STATS_INC(link.recv); + } + +#ifdef LOCK_RX_THREAD + sys_mutex_unlock(&lpc_enet->TXLockMutex); +#endif + + return p; +} + +/** \brief Attempt to read a packet from the EMAC interface. + * + * \param[in] netif the lwip network interface structure + */ +void lpc546xx_enetif_input(struct netif *netif) +{ + struct pbuf *p; + + /* move received packet into a new pbuf */ + p = lpc546xx_low_level_input(netif); + if (p == NULL) + return; + + /* pass all packets to ethernet_input, which decides what packets it supports */ + if (netif->input(p, netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("lpc546xx_enetif_input: input error\n")); + /* Free buffer */ + pbuf_free(p); + } +} + +/** \brief Worker thread. + * + * Woken by thread flags to receive packets or clean up transmit + * + * \param[in] pvParameters pointer to the interface data + */ +static void lpc546xx_emac_thread(void* pvParameters) +{ + struct lpc_enetdata *lpc_enet = pvParameters; + + for (;;) { + uint32_t flags = osThreadFlagsWait(FLAG_RX | FLAG_TX, osFlagsWaitAny, PHY_TASK_PERIOD_MS); + if (flags == osFlagsErrorTimeout) { + // Rather than calling strictly every period, we call when idle + // for that period - hopefully good enough. We run this task + // from lwIP's thread rather than our RX/TX thread, as PHY reads can + // be slow, and we don't want them to interfere with data pumping. + // This is analogous to the way the PHY polling works in the Nanostack + // version of the driver + tcpip_callback_with_block(lpc546xx_phy_task, lpc_enet->netif, 0); + continue; + } + + LWIP_ASSERT("osThreadFlagsWait error", !(flags & osFlagsError)); + if (flags & FLAG_RX) { + lpc546xx_packet_rx(lpc_enet); + } + + if (flags & FLAG_TX) { + lpc546xx_packet_tx(lpc_enet); + } + } +} + +/** \brief Low level output of a packet. Never call this from an + * interrupt context, as it may block until TX descriptors + * become available. + * + * \param[in] netif the lwip network interface structure for this lpc_enetif + * \param[in] p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent + */ +static err_t lpc546xx_low_level_output(struct netif *netif, struct pbuf *p) +{ + struct lpc_enetdata *lpc_enet = netif->state; + struct pbuf *q; + uint8_t *psend = NULL, *dst; + enet_tx_bd_ring_t *txBdRing = (enet_tx_bd_ring_t *)&g_handle.txBdRing[0]; + uint32_t index = txBdRing->txGenIdx; + + psend = (uint8_t *)calloc(1, ENET_ALIGN(p->tot_len, ENET_BUFF_ALIGNMENT)); + if (NULL == psend) + return ERR_MEM; + + if (p->len == p->tot_len) { + MEMCPY(psend, p->payload, p->len); + } else { + for (q = p, dst = psend; q != NULL; q = q->next) { + MEMCPY(dst, q->payload, q->len); + dst += q->len; + } + } + /* Check if a descriptor is available for the transfer. */ + osStatus_t stat = osSemaphoreAcquire(lpc_enet->xTXDCountSem.id, 0); + if (stat != osOK) + return ERR_BUF; + + /* Save the buffer so that it can be freed when transmit is done */ + tx_buff[index] = psend; + + if (ENET_SendFrame(ENET, &g_handle, psend, p->tot_len) != kStatus_Success) { + free(psend); + tx_buff[index] = NULL; + return ERR_IF; + } + + LINK_STATS_INC(link.xmit); + + return ERR_OK; +} + +/** \brief Ethernet receive interrupt handler + * + * This function handles the receive interrupt of LPC546XX. + */ +void enet_mac_rx_isr() +{ + osThreadFlagsSet(lpc_enetdata.thread, FLAG_RX); +} + +void enet_mac_tx_isr() +{ + osThreadFlagsSet(lpc_enetdata.thread, FLAG_TX); +} + +void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, uint8_t channel, void *param) +{ + switch (event) + { + case kENET_RxIntEvent: + enet_mac_rx_isr(); + break; + case kENET_TxIntEvent: + enet_mac_tx_isr(); + break; + default: + break; + } +} + +#if NO_SYS == 0 + +/** \brief Packet reception task + * + * This task is called when a packet is received. It will + * pass the packet to the LWIP core. + * + * \param[in] lpc_enet pointer to the interface data + */ +static void lpc546xx_packet_rx(struct lpc_enetdata *lpc_enet) +{ + enet_rx_bd_ring_t *rxBdRing = (enet_rx_bd_ring_t *)&g_handle.rxBdRing[0]; + enet_rx_bd_struct_t *bdPtr = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + bool suspend = false; + + /* Suspend and command for rx. */ + if (ENET->DMA_CH[0].DMA_CHX_STAT & ENET_DMA_CH_DMA_CHX_STAT_RBU_MASK) { + suspend = true; + } + + while ((bdPtr->control & ENET_RXDESCRIP_WR_OWN_MASK) == 0) { + lpc546xx_enetif_input(lpc_enet->netif); + /* rxGenIdx gets updated, gets the next receive buffer descriptor */ + bdPtr = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + } + + /* Set command for rx when it is suspend. */ + if (suspend) + { + ENET->DMA_CH[0].DMA_CHX_RXDESC_TAIL_PTR = ENET->DMA_CH[0].DMA_CHX_RXDESC_TAIL_PTR; + } +} + +/** \brief Transmit cleanup task + * + * This task is called when a transmit interrupt occurs and + * reclaims the pbuf and descriptor used for the packet once + * the packet has been transferred. + * + * \param[in] lpc_enet pointer to the interface data + */ +static void lpc546xx_packet_tx(struct lpc_enetdata *lpc_enet) +{ + lpc546xx_tx_reclaim(lpc_enet); +} + +#endif + +/** \brief Low level init of the MAC and PHY. + * + * \param[in] netif Pointer to LWIP netif structure + */ +static err_t low_level_init(struct netif *netif) +{ + status_t status; + uint8_t i; + uint32_t refClock; + phy_speed_t phy_speed; + phy_duplex_t phy_duplex; + uint32_t phyAddr = 0; + bool link = false; + enet_config_t config; + uint32_t timeout = 0xFFFU; + + lpc546xx_init_eth_hardware(); + + refClock = CLOCK_GetFreq(kCLOCK_CoreSysClk); + + status = PHY_Init(ENET, phyAddr, refClock); + if (status != kStatus_Success) { + return ERR_IF; + } + + ENET_GetDefaultConfig(&config); + config.multiqueueCfg = NULL; + + while ((!link) && timeout) { + PHY_GetLinkStatus(ENET, phyAddr, &link); + if (link) { + /* Get link information from PHY */ + PHY_GetLinkSpeedDuplex(ENET, phyAddr, &phy_speed, &phy_duplex); + + /* Change the MII speed and duplex for actual link status. */ + config.miiSpeed = (enet_mii_speed_t)phy_speed; + config.miiDuplex = (enet_mii_duplex_t)phy_duplex; + } + timeout--; + } + + if (!link) { + return ERR_CONN; + } + + AT_NONCACHEABLE_SECTION_ALIGN(static enet_rx_bd_struct_t rx_desc_start_addr[ENET_RX_RING_LEN], ENET_BUFF_ALIGNMENT); + AT_NONCACHEABLE_SECTION_ALIGN(static enet_tx_bd_struct_t tx_desc_start_addr[ENET_TX_RING_LEN], ENET_BUFF_ALIGNMENT); + + /* Create buffers for each receive BD */ + for (i = 0; i < ENET_RX_RING_LEN; i++) { + rx_buff[i] = pbuf_alloc(PBUF_RAW, ENET_ALIGN(ENET_ETH_MAX_FLEN, ENET_BUFF_ALIGNMENT), PBUF_RAM); + if (NULL == rx_buff[i]) + return ERR_MEM; + + rx_ptr[i] = (uint32_t)rx_buff[i]->payload; + } + + /* prepare the buffer configuration. */ + enet_buffer_config_t buffCfg = { + ENET_RX_RING_LEN, + ENET_TX_RING_LEN, + &tx_desc_start_addr[0], + &tx_desc_start_addr[0], + &rx_desc_start_addr[0], + &rx_desc_start_addr[ENET_RX_RING_LEN], + rx_ptr, + ENET_ALIGN(ENET_ETH_MAX_FLEN, ENET_BUFF_ALIGNMENT), + }; + + ENET_Init(ENET, &config, netif->hwaddr, refClock); + + /* Enable the tx & rx interrupt. */ + ENET_EnableInterrupts(ENET, kENET_DmaTx | kENET_DmaRx); + + /* Create the handler. */ + ENET_CreateHandler(ENET, &g_handle, &config, &buffCfg, ethernet_callback, netif); + + /* Initialize Descriptor. */ + ENET_DescriptorInit(ENET, &config, &buffCfg); + + return ERR_OK; +} + +/** + * This function is the ethernet IPv4 packet send function. It calls + * etharp_output after checking link status. + * + * \param[in] netif the lwip network interface structure for this lpc_enetif + * \param[in] q Pointer to pbug to send + * \param[in] ipaddr IP address + * \return ERR_OK or error code + */ +#if LWIP_IPV4 +err_t lpc546xx_etharp_output_ipv4(struct netif *netif, struct pbuf *q, + const ip4_addr_t *ipaddr) +{ + /* Only send packet is link is up */ + if (netif->flags & NETIF_FLAG_LINK_UP) + return etharp_output(netif, q, ipaddr); + + return ERR_CONN; +} +#endif + +/** + * This function is the ethernet IPv6 packet send function. It calls + * etharp_output after checking link status. + * + * \param[in] netif the lwip network interface structure for this lpc_enetif + * \param[in] q Pointer to pbug to send + * \param[in] ipaddr IP address + * \return ERR_OK or error code + */ +#if LWIP_IPV6 +err_t lpc546xx_etharp_output_ipv6(struct netif *netif, struct pbuf *q, + const ip6_addr_t *ipaddr) +{ + /* Only send packet is link is up */s + if (netif->flags & NETIF_FLAG_LINK_UP) + return ethip6_output(netif, q, ipaddr); + + return ERR_CONN; +} +#endif + +/******************************************************************************* + * PHY task: monitor link +*******************************************************************************/ + +#define STATE_UNKNOWN (-1) + +typedef struct { + int connected; + phy_speed_t speed; + phy_duplex_t duplex; +} PHY_STATE; + +int phy_link_status(void) { + bool connection_status; + uint32_t phyAddr = 0; + + PHY_GetLinkStatus(ENET, phyAddr, &connection_status); + return (int)connection_status; +} + +static void lpc546xx_phy_task(void *data) { + struct netif *netif = (struct netif*)data; + static PHY_STATE prev_state = {STATE_UNKNOWN, (phy_speed_t)STATE_UNKNOWN, (phy_duplex_t)STATE_UNKNOWN}; + uint32_t phyAddr = 0; + // Get current status + PHY_STATE crt_state; + bool connection_status; + + PHY_GetLinkStatus(ENET, phyAddr, &connection_status); + crt_state.connected = connection_status; + // Get the actual PHY link speed + PHY_GetLinkSpeedDuplex(ENET, phyAddr, &crt_state.speed, &crt_state.duplex); + + // Compare with previous state + if (crt_state.connected != prev_state.connected) { + // We're called from lwIP's tcpip thread, so can call link functions directly + if (crt_state.connected) { + netif_set_link_up(netif); + } else { + netif_set_link_down(netif); + } + } + + if (crt_state.speed != prev_state.speed) { + uint32_t fes = ENET->MAC_CONFIG; + fes &= ~ENET_MAC_CONFIG_FES_MASK; + if (prev_state.speed != (phy_speed_t)STATE_UNKNOWN) { + fes |= ENET_MAC_CONFIG_FES(!crt_state.speed); + } else { + fes |= ENET_MAC_CONFIG_FES(crt_state.speed); + } + + ENET->MAC_CONFIG = fes; + } + + prev_state = crt_state; +} + +/** + * Should be called at the beginning of the program to set up the + * network interface. + * + * This function should be passed as a parameter to netif_add(). + * + * @param[in] netif the lwip network interface structure for this lpc_enetif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +err_t eth_arch_enetif_init(struct netif *netif) +{ + err_t err; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + + lpc_enetdata.netif = netif; + + /* set MAC hardware address */ +#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE) + netif->hwaddr[0] = MBED_MAC_ADDR_0; + netif->hwaddr[1] = MBED_MAC_ADDR_1; + netif->hwaddr[2] = MBED_MAC_ADDR_2; + netif->hwaddr[3] = MBED_MAC_ADDR_3; + netif->hwaddr[4] = MBED_MAC_ADDR_4; + netif->hwaddr[5] = MBED_MAC_ADDR_5; +#else + mbed_mac_address((char *)netif->hwaddr); +#endif + + netif->hwaddr_len = ETH_HWADDR_LEN; + + /* maximum transfer unit */ + netif->mtu = 1500; + + /* device capabilities */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET; +#ifdef LWIP_IGMP + netif->flags |= NETIF_FLAG_IGMP; +#endif +#if LWIP_IPV6_MLD + netif->flags |= NETIF_FLAG_MLD6; +#endif + + /* Initialize the hardware */ + netif->state = &lpc_enetdata; + err = low_level_init(netif); + if (err != ERR_OK) + return err; + +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + netif->hostname = "lwiplpc546xx"; +#endif /* LWIP_NETIF_HOSTNAME */ + + netif->name[0] = 'e'; + netif->name[1] = 'n'; + +#if LWIP_IPV4 + netif->output = lpc546xx_etharp_output_ipv4; +#endif +#if LWIP_IPV6 + netif->output_ip6 = lpc546xx_etharp_output_ipv6; +#endif + + netif->linkoutput = lpc546xx_low_level_output; + + /* CMSIS-RTOS, start tasks */ +#if NO_SYS == 0 + memset(&lpc_enetdata.xTXDCountSem.data, 0, sizeof(lpc_enetdata.xTXDCountSem.data)); + lpc_enetdata.xTXDCountSem.attr.cb_mem = &lpc_enetdata.xTXDCountSem.data; + lpc_enetdata.xTXDCountSem.attr.cb_size = sizeof(lpc_enetdata.xTXDCountSem.data); + lpc_enetdata.xTXDCountSem.id = osSemaphoreNew(ENET_TX_RING_LEN, ENET_TX_RING_LEN, &lpc_enetdata.xTXDCountSem.attr); + + LWIP_ASSERT("xTXDCountSem creation error", (lpc_enetdata.xTXDCountSem.id != NULL)); + + err = sys_mutex_new(&lpc_enetdata.TXLockMutex); + LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK)); + + /* Allow the PHY task to detect the initial link state and set up the proper flags */ + tcpip_callback_with_block(lpc546xx_phy_task, netif, 1); + osDelay(10); + + /* Worker thread */ + lpc_enetdata.thread = sys_thread_new("lpc546xx_emac_thread", lpc546xx_emac_thread, netif->state, THREAD_STACKSIZE, THREAD_PRIORITY)->id; +#endif + + /* Active TX/RX. */ + ENET_StartRxTx(ENET, 1, 1); + + return ERR_OK; +} + +void eth_arch_enable_interrupts(void) { + +} + +void eth_arch_disable_interrupts(void) { + +} + +#endif /* LWIP_ARP || LWIP_ETHERNET */ + diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPC546XX/lpc546xx_emac_config.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPC546XX/lpc546xx_emac_config.h new file mode 100644 index 00000000000..d4d7bde7a86 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPC546XX/lpc546xx_emac_config.h @@ -0,0 +1,37 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef LPC546XX_EMAC_CONFIG_H__ +#define LPC546XX_EMAC_CONFIG_H__ + +#include "fsl_enet.h" + +#define ENET_RX_RING_LEN (16) +#define ENET_TX_RING_LEN (8) + +#define ENET_ETH_MAX_FLEN (ENET_FRAME_MAX_FRAMELEN) + +#if defined(__cplusplus) +extern "C" { +#endif + +int phy_link_status(void); + +#if defined(__cplusplus) +} +#endif + +#endif // #define LPC546XX_EMAC_CONFIG_H__ + diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPC546XX/lwipopts_conf.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPC546XX/lwipopts_conf.h new file mode 100644 index 00000000000..37e7e525939 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPC546XX/lwipopts_conf.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2012 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef LWIPOPTS_CONF_H +#define LWIPOPTS_CONF_H + +#include "lpc546xx_emac_config.h" + +#define LWIP_TRANSPORT_ETHERNET 1 +#define ETH_PAD_SIZE 0 + +#define MEM_SIZE (ENET_RX_RING_LEN * (ENET_ETH_MAX_FLEN + ENET_BUFF_ALIGNMENT) + ENET_TX_RING_LEN * ENET_ETH_MAX_FLEN) + +#endif diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/lpc17_emac.c b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc17_emac.c similarity index 100% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/lpc17_emac.c rename to features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc17_emac.c diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/lpc17xx_emac.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc17xx_emac.h similarity index 100% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/lpc17xx_emac.h rename to features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc17xx_emac.h diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/lpc_emac_config.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_emac_config.h similarity index 100% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/lpc_emac_config.h rename to features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_emac_config.h diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/lpc_phy.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_phy.h similarity index 100% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/lpc_phy.h rename to features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_phy.h diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/lpc_phy_dp83848.c b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_phy_dp83848.c similarity index 100% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/lpc_phy_dp83848.c rename to features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lpc_phy_dp83848.c diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/lwipopts_conf.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lwipopts_conf.h similarity index 100% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/lwipopts_conf.h rename to features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NXP/TARGET_LPCTarget/lwipopts_conf.h diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/crc.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/crc.c new file mode 100644 index 00000000000..7e2d7e7c516 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/crc.c @@ -0,0 +1,234 @@ +/********************************************************************** + * + * Filename: crc.c + * + * Description: Slow and fast implementations of the CRC standards. + * + * Notes: The parameters for each supported CRC standard are + * defined in the header file crc.h. The implementations + * here should stand up to further additions to that list. + * + * + * Copyright (c) 2000 by Michael Barr. This software is placed into + * the public domain and may be used for any purpose. However, this + * notice must not be changed or removed and no warranty is either + * expressed or implied by its publication or distribution. + **********************************************************************/ + +#include "crc.h" + + +/* + * Derive parameters from the standard-specific parameters in crc.h. + */ +#define WIDTH (8 * sizeof(crc)) +#define TOPBIT (1 << (WIDTH - 1)) + +#if (REFLECT_DATA == TRUE) +#undef REFLECT_DATA +#define REFLECT_DATA(X) ((unsigned char) reflect((X), 8)) +#else +#undef REFLECT_DATA +#define REFLECT_DATA(X) (X) +#endif + +#if (REFLECT_REMAINDER == TRUE) +#undef REFLECT_REMAINDER +#define REFLECT_REMAINDER(X) ((crc) reflect((X), WIDTH)) +#else +#undef REFLECT_REMAINDER +#define REFLECT_REMAINDER(X) (X) +#endif + + +/********************************************************************* + * + * Function: reflect() + * + * Description: Reorder the bits of a binary sequence, by reflecting + * them about the middle position. + * + * Notes: No checking is done that nBits <= 32. + * + * Returns: The reflection of the original data. + * + *********************************************************************/ +static unsigned long +reflect(unsigned long data, unsigned char nBits) +{ + unsigned long reflection = 0x00000000; + unsigned char bit; + + /* + * Reflect the data about the center bit. + */ + for (bit = 0; bit < nBits; ++bit) + { + /* + * If the LSB bit is set, set the reflection of it. + */ + if (data & 0x01) + { + reflection |= (1 << ((nBits - 1) - bit)); + } + + data = (data >> 1); + } + + return (reflection); + +} /* reflect() */ + + +/********************************************************************* + * + * Function: crcSlow() + * + * Description: Compute the CRC of a given message. + * + * Notes: + * + * Returns: The CRC of the message. + * + *********************************************************************/ +crc +crcSlow(unsigned char const message[], int nBytes) +{ + crc remainder = INITIAL_REMAINDER; + int byte; + unsigned char bit; + + + /* + * Perform modulo-2 division, a byte at a time. + */ + for (byte = 0; byte < nBytes; ++byte) + { + /* + * Bring the next byte into the remainder. + */ + remainder ^= (REFLECT_DATA(message[byte]) << (WIDTH - 8)); + + /* + * Perform modulo-2 division, a bit at a time. + */ + for (bit = 8; bit > 0; --bit) + { + /* + * Try to divide the current data bit. + */ + if (remainder & TOPBIT) + { + remainder = (remainder << 1) ^ POLYNOMIAL; + } + else + { + remainder = (remainder << 1); + } + } + } + + /* + * The final remainder is the CRC result. + */ + return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE); + +} /* crcSlow() */ + + +crc crcTable[256]; + + +/********************************************************************* + * + * Function: crcInit() + * + * Description: Populate the partial CRC lookup table. + * + * Notes: This function must be rerun any time the CRC standard + * is changed. If desired, it can be run "offline" and + * the table results stored in an embedded system's ROM. + * + * Returns: None defined. + * + *********************************************************************/ +void +crcInit(void) +{ + crc remainder; + int dividend; + unsigned char bit; + + + /* + * Compute the remainder of each possible dividend. + */ + for (dividend = 0; dividend < 256; ++dividend) + { + /* + * Start with the dividend followed by zeros. + */ + remainder = dividend << (WIDTH - 8); + + /* + * Perform modulo-2 division, a bit at a time. + */ + for (bit = 8; bit > 0; --bit) + { + /* + * Try to divide the current data bit. + */ + if (remainder & TOPBIT) + { + remainder = (remainder << 1) ^ POLYNOMIAL; + } + else + { + remainder = (remainder << 1); + } + } + + /* + * Store the result into the table. + */ + crcTable[dividend] = remainder; + } + +} /* crcInit() */ + + +/********************************************************************* + * + * Function: crcFast() + * + * Description: Compute the CRC of a given message. + * + * Notes: crcInit() must be called first. + * + * Returns: The CRC of the message. + * + *********************************************************************/ +crc +crcFast(unsigned char const message[], int nBytes) +{ + crc remainder = INITIAL_REMAINDER; + unsigned char data; + int byte; + + + /* + * Divide the message by the polynomial, a byte at a time. + */ + for (byte = 0; byte < nBytes; ++byte) + { + data = REFLECT_DATA(message[byte]) ^ (remainder >> (WIDTH - 8)); + remainder = crcTable[data] ^ (remainder << 8); + } + + /* + * The final remainder is the CRC. + */ + return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE); + +} /* crcFast() */ + diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/crc.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/crc.h new file mode 100644 index 00000000000..fae66ae4bcc --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/crc.h @@ -0,0 +1,77 @@ +/********************************************************************** + * + * Filename: crc.h + * + * Description: A header file describing the various CRC standards. + * + * Notes: + * + * + * Copyright (c) 2000 by Michael Barr. This software is placed into + * the public domain and may be used for any purpose. However, this + * notice must not be changed or removed and no warranty is either + * expressed or implied by its publication or distribution. + **********************************************************************/ + +#ifndef _crc_h +#define _crc_h + + +#define FALSE 0 +#define TRUE !FALSE + +/* + * Select the CRC standard from the list that follows. + */ +#define CRC16 + + +#if defined(CRC_CCITT) + +typedef unsigned short crc; + +#define CRC_NAME "CRC-CCITT" +#define POLYNOMIAL 0x1021 +#define INITIAL_REMAINDER 0xFFFF +#define FINAL_XOR_VALUE 0x0000 +#define REFLECT_DATA FALSE +#define REFLECT_REMAINDER FALSE +#define CHECK_VALUE 0x29B1 + +#elif defined(CRC16) + +typedef unsigned short crc; + +#define CRC_NAME "CRC-16" +#define POLYNOMIAL 0x8005 +#define INITIAL_REMAINDER 0x0000 +#define FINAL_XOR_VALUE 0x0000 +#define REFLECT_DATA TRUE +#define REFLECT_REMAINDER TRUE +#define CHECK_VALUE 0xBB3D + +#elif defined(CRC32) + +typedef unsigned long crc; + +#define CRC_NAME "CRC-32" +#define POLYNOMIAL 0x04C11DB7 +#define INITIAL_REMAINDER 0xFFFFFFFF +#define FINAL_XOR_VALUE 0xFFFFFFFF +#define REFLECT_DATA TRUE +#define REFLECT_REMAINDER TRUE +#define CHECK_VALUE 0xCBF43926 + +#else + +#error "One of CRC_CCITT, CRC16, or CRC32 must be #define'd." + +#endif + + +void crcInit(void); +crc crcSlow(unsigned char const message[], int nBytes); +crc crcFast(unsigned char const message[], int nBytes); + + +#endif /* _crc_h */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/fsl_phy.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/fsl_phy.c new file mode 100644 index 00000000000..98578cb5907 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/fsl_phy.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsl_phy.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines the timeout macro. */ +#define PHY_TIMEOUT_COUNT 0xFFFFFFU + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief Get the ENET instance from peripheral base address. + * + * @param base ENET peripheral base address. + * @return ENET instance. + */ +extern uint32_t ENET_GetInstance(ENET_Type *base); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to enet clocks for each instance. */ +#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) +extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT]; +#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) +extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_LPC_ENET_COUNT]; +#endif +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz) +{ + uint32_t reg; + uint32_t idReg = 0; + uint32_t delay = PHY_TIMEOUT_COUNT; + uint32_t instance = ENET_GetInstance(base); + bool status = false; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Set SMI first. */ + CLOCK_EnableClock(s_enetClock[instance]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) + ENET_SetSMI(base, srcClock_Hz, false); +#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) + ENET_SetSMI(base); +#endif + /* Initialization after PHY stars to work. */ + while ((idReg != PHY_CONTROL_ID1) && (delay != 0)) + { + PHY_Read(base, phyAddr, PHY_ID1_REG, &idReg); + delay --; + } + + if (!delay) + { + return kStatus_Fail; + } + delay = PHY_TIMEOUT_COUNT; + + /* Reset PHY and wait until completion. */ + PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); + do + { + PHY_Read(base, phyAddr, PHY_BASICCONTROL_REG, ®); + } while (delay-- && reg & PHY_BCTL_RESET_MASK); + + if (!delay) + { + return kStatus_Fail; + } + + /* Set the ability. */ + PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG, (PHY_ALL_CAPABLE_MASK | 0x1U)); + + /* Start Auto negotiation and wait until auto negotiation completion */ + PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); + delay = PHY_TIMEOUT_COUNT; + do + { + PHY_Read(base, phyAddr, PHY_SEPCIAL_CONTROL_REG, ®); + delay --; + } while (delay && ((reg & PHY_SPECIALCTL_AUTONEGDONE_MASK) == 0)); + + if (!delay) + { + return kStatus_Fail; + } + + /* Waiting a moment for phy stable. */ + for (delay = 0; delay < PHY_TIMEOUT_COUNT; delay++) + { + __ASM("nop"); + PHY_GetLinkStatus(base, phyAddr, &status); + if (status) + { + break; + } + } + + return kStatus_Success; +} + +status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data) +{ +#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) + uint32_t counter; + + /* Clear the SMI interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + /* Starts a SMI write command. */ + ENET_StartSMIWrite(base, phyAddr, phyReg, kENET_MiiWriteValidFrame, data); + + /* Wait for SMI complete. */ + for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--) + { + if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) + { + break; + } + } + + /* Check for timeout. */ + if (!counter) + { + return kStatus_PHY_SMIVisitTimeout; + } + + /* Clear MII interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + +#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) + ENET_StartSMIWrite(base, phyAddr, phyReg, data); + while (ENET_IsSMIBusy(base)) + ; +#endif + return kStatus_Success; +} + +status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr) +{ +#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) + assert(dataPtr); + + uint32_t counter; + + /* Clear the MII interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + /* Starts a SMI read command operation. */ + ENET_StartSMIRead(base, phyAddr, phyReg, kENET_MiiReadValidFrame); + + /* Wait for MII complete. */ + for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--) + { + if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) + { + break; + } + } + + /* Check for timeout. */ + if (!counter) + { + return kStatus_PHY_SMIVisitTimeout; + } + + /* Get data from MII register. */ + *dataPtr = ENET_ReadSMIData(base); + + /* Clear MII interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); +#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) + ENET_StartSMIRead(base, phyAddr, phyReg); + while (ENET_IsSMIBusy(base)) + ; + *dataPtr = ENET_ReadSMIData(base); +#endif + return kStatus_Success; +} + +status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status) +{ + uint32_t reg; + status_t result = kStatus_Success; + + /* Read the basic status register. */ + result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, ®); + if (result == kStatus_Success) + { + if (reg & PHY_BSTATUS_LINKSTATUS_MASK) + { + /* link up. */ + *status = true; + } + else + { + *status = false; + } + } + return result; +} + +status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex) +{ + assert(duplex); + assert(speed); + + uint32_t reg; + status_t result = kStatus_Success; + + /* Read the control two register. */ + result = PHY_Read(base, phyAddr, PHY_SEPCIAL_CONTROL_REG, ®); + if (result == kStatus_Success) + { + if (reg & PHY_SPECIALCTL_DUPLEX_MASK) + { + /* Full duplex. */ + *duplex = kPHY_FullDuplex; + } + else + { + /* Half duplex. */ + *duplex = kPHY_HalfDuplex; + } + + if (reg & PHY_SPECIALCTL_100SPEED_MASK) + { + /* 100M speed. */ + *speed = kPHY_Speed100M; + } + else + { /* 10M speed. */ + *speed = kPHY_Speed10M; + } + } + return result; +} diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/fsl_phy.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/fsl_phy.h new file mode 100644 index 00000000000..22866c65b55 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/fsl_phy.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _FSL_PHY_H_ +#define _FSL_PHY_H_ + +#include "fsl_enet.h" + +/*! + * @addtogroup phy_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief PHY driver version */ +#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) /*!< Version 2.0.0. */ + +/*! @brief Defines the PHY registers. */ +#define PHY_BASICCONTROL_REG 0x00U /*!< The PHY basic control register. */ +#define PHY_BASICSTATUS_REG 0x01U /*!< The PHY basic status register. */ +#define PHY_ID1_REG 0x02U /*!< The PHY ID one register. */ +#define PHY_ID2_REG 0x03U /*!< The PHY ID two register. */ +#define PHY_AUTONEG_ADVERTISE_REG 0x04U /*!< The PHY auto-negotiate advertise register. */ +#define PHY_SEPCIAL_CONTROL_REG 0x1FU /*!< The PHY control two register. */ + +#define PHY_CONTROL_ID1 0x07U /*!< The PHY ID1*/ + +/*! @brief Defines the mask flag in basic control register. */ +#define PHY_BCTL_DUPLEX_MASK 0x0100U /*!< The PHY duplex bit mask. */ +#define PHY_BCTL_RESTART_AUTONEG_MASK 0x0200U /*!< The PHY restart auto negotiation mask. */ +#define PHY_BCTL_AUTONEG_MASK 0x1000U /*!< The PHY auto negotiation bit mask. */ +#define PHY_BCTL_SPEED_MASK 0x2000U /*!< The PHY speed bit mask. */ +#define PHY_BCTL_LOOP_MASK 0x4000U /*!< The PHY loop bit mask. */ +#define PHY_BCTL_RESET_MASK 0x8000U /*!< The PHY reset bit mask. */ + +/*!@brief Defines the mask flag of operation mode in special control register*/ +#define PHY_SPECIALCTL_AUTONEGDONE_MASK 0x1000U /*!< The PHY auto-negotiation complete mask. */ +#define PHY_SPECIALCTL_DUPLEX_MASK 0x0010U /*!< The PHY duplex mask. */ +#define PHY_SPECIALCTL_100SPEED_MASK 0x0008U /*!< The PHY speed mask. */ +#define PHY_SPECIALCTL_10SPEED_MASK 0x0004U /*!< The PHY speed mask. */ +#define PHY_SPECIALCTL_SPEEDUPLX_MASK 0x001cU /*!< The PHY speed and duplex mask. */ + +/*! @brief Defines the mask flag in basic status register. */ +#define PHY_BSTATUS_LINKSTATUS_MASK 0x0004U /*!< The PHY link status mask. */ + +/*! @brief Defines the mask flag in PHY auto-negotiation advertise register. */ +#define PHY_ALL_CAPABLE_MASK 0x1e0U + +/*! @brief Defines the PHY status. */ +enum _phy_status +{ + kStatus_PHY_SMIVisitTimeout = MAKE_STATUS(kStatusGroup_PHY, 0), /*!< ENET PHY SMI visit timeout. */ +}; + +/*! @brief Defines the PHY link speed. This is align with the speed for ENET MAC. */ +typedef enum _phy_speed { + kPHY_Speed10M = 0U, /*!< ENET PHY 10M speed. */ + kPHY_Speed100M /*!< ENET PHY 100M speed. */ +} phy_speed_t; + +/*! @brief Defines the PHY link duplex. */ +typedef enum _phy_duplex { + kPHY_HalfDuplex = 0U, /*!< ENET PHY half duplex. */ + kPHY_FullDuplex /*!< ENET PHY full duplex. */ +} phy_duplex_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name PHY Driver + * @{ + */ + +/*! + * @brief Initializes PHY. + * + * This function initialize the SMI interface and initialize PHY. + * The SMI is the MII management interface between PHY and MAC, which should be + * firstly initialized before any other operation for PHY. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param srcClock_Hz The module clock frequency - system clock for MII management interface - SMI. + * @retval kStatus_Success PHY initialize success + * @retval kStatus_Fail PHY initialize fail + */ +status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz); + +/*! + * @brief PHY Write function. This function write data over the SMI to + * the specified PHY register. This function is called by all PHY interfaces. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param phyReg The PHY register. + * @param data The data written to the PHY register. + * @retval kStatus_Success PHY write success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data); + +/*! + * @brief PHY Read function. This interface read data over the SMI from the + * specified PHY register. This function is called by all PHY interfaces. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param phyReg The PHY register. + * @param dataPtr The address to store the data read from the PHY register. + * @retval kStatus_Success PHY read success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr); + +/*! + * @brief Gets the PHY link status. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param status The link up or down status of the PHY. + * - true the link is up. + * - false the link is down. + * @retval kStatus_Success PHY get link status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status); + +/*! + * @brief Gets the PHY link speed and duplex. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param speed The address of PHY link speed. + * @param duplex The link duplex of PHY. + * @retval kStatus_Success PHY get link speed and duplex success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_PHY_H_ */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/mbed_overrides.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/mbed_overrides.c index b727924a6a7..39418e8eabd 100644 --- a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/mbed_overrides.c +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/TARGET_LPCXpresso/mbed_overrides.c @@ -17,6 +17,10 @@ #include "clock_config.h" #include "fsl_emc.h" #include "fsl_power.h" +#include "fsl_flashiap.h" + +#define CRC16 +#include "crc.h" /******************************************************************************* * Definitions @@ -37,6 +41,18 @@ #define SDRAM_MODEREG_VALUE (0x23u) #define SDRAM_DEV_MEMORYMAP (0x09u) /* 128Mbits (8M*16, 4banks, 12 rows, 9 columns)*/ +uint32_t FLASHIAP_ReadUid(uint32_t *addr) +{ + uint32_t command[5], result[5]; + + command[0] = kIapCmd_FLASHIAP_ReadUid; + iap_entry(command, result); + + memcpy(addr, &result[1], (sizeof(uint32_t) * 4)); + + return result[0]; +} + // called before main void mbed_sdk_init() { @@ -59,6 +75,38 @@ void rtc_setup_oscillator(void) SYSCON->RTCOSCCTRL |= SYSCON_RTCOSCCTRL_EN_MASK; } +// Provide ethernet devices with a semi-unique MAC address from the UUID +void mbed_mac_address(char *mac) +{ + uint16_t MAC[3]; // 3 16 bits words for the MAC + uint32_t UID[4]; + + // get UID via ISP commands + FLASHIAP_ReadUid(UID); + + // generate three CRC16's using different slices of the UUID + MAC[0] = crcSlow((const uint8_t *)UID, 8); // most significant half-word + MAC[1] = crcSlow((const uint8_t *)UID, 12); + MAC[2] = crcSlow((const uint8_t *)UID, 16); // least significant half word + + // The network stack expects an array of 6 bytes + // so we copy, and shift and copy from the half-word array to the byte array + mac[0] = MAC[0] >> 8; + mac[1] = MAC[0]; + mac[2] = MAC[1] >> 8; + mac[3] = MAC[1]; + mac[4] = MAC[2] >> 8; + mac[5] = MAC[2]; + + // We want to force bits [1:0] of the most significant byte [0] + // to be "10" + // http://en.wikipedia.org/wiki/MAC_address + + mac[0] |= 0x02; // force bit 1 to a "1" = "Locally Administered" + mac[0] &= 0xFE; // force bit 0 to a "0" = Unicast + +} + void ADC_ClockPower_Configuration(void) { /* SYSCON power. */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/drivers/fsl_common.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/drivers/fsl_common.h index f20c09027e9..ead53ac46ff 100644 --- a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/drivers/fsl_common.h +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC546XX/drivers/fsl_common.h @@ -194,6 +194,123 @@ typedef int32_t status_t; #define COUNT_TO_MSEC(count, clockFreqInHz) (uint64_t)((uint64_t)count * 1000U / clockFreqInHz) /* @} */ +/*! @name Alignment variable definition macros */ +/* @{ */ +#if (defined(__ICCARM__)) +/** + * Workaround to disable MISRA C message suppress warnings for IAR compiler. + * http://supp.iar.com/Support/?note=24725 + */ +_Pragma("diag_suppress=Pm120") +#define SDK_PRAGMA(x) _Pragma(#x) + _Pragma("diag_error=Pm120") +/*! Macro to define a variable with alignbytes alignment */ +#define SDK_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var +/*! Macro to define a variable with L1 d-cache line size alignment */ +#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) +#define SDK_L1DCACHE_ALIGN(var) SDK_PRAGMA(data_alignment = FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) var +#endif +/*! Macro to define a variable with L2 cache line size alignment */ +#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) +#define SDK_L2CACHE_ALIGN(var) SDK_PRAGMA(data_alignment = FSL_FEATURE_L2CACHE_LINESIZE_BYTE) var +#endif +#elif defined(__ARMCC_VERSION) +/*! Macro to define a variable with alignbytes alignment */ +#define SDK_ALIGN(var, alignbytes) __align(alignbytes) var +/*! Macro to define a variable with L1 d-cache line size alignment */ +#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) +#define SDK_L1DCACHE_ALIGN(var) __align(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) var +#endif +/*! Macro to define a variable with L2 cache line size alignment */ +#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) +#define SDK_L2CACHE_ALIGN(var) __align(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) var +#endif +#elif defined(__GNUC__) +/*! Macro to define a variable with alignbytes alignment */ +#define SDK_ALIGN(var, alignbytes) var __attribute__((aligned(alignbytes))) +/*! Macro to define a variable with L1 d-cache line size alignment */ +#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) +#define SDK_L1DCACHE_ALIGN(var) var __attribute__((aligned(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE))) +#endif +/*! Macro to define a variable with L2 cache line size alignment */ +#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) +#define SDK_L2CACHE_ALIGN(var) var __attribute__((aligned(FSL_FEATURE_L2CACHE_LINESIZE_BYTE))) +#endif +#else +#error Toolchain not supported +#define SDK_ALIGN(var, alignbytes) var +#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) +#define SDK_L1DCACHE_ALIGN(var) var +#endif +#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) +#define SDK_L2CACHE_ALIGN(var) var +#endif +#endif + +/*! Macro to change a value to a given size aligned value */ +#define SDK_SIZEALIGN(var, alignbytes) \ + ((unsigned int)((var) + ((alignbytes)-1)) & (unsigned int)(~(unsigned int)((alignbytes)-1))) +/* @} */ + +/*! @name Non-cacheable region definition macros */ +/* For initialized non-zero non-cacheable variables, please using "AT_NONCACHEABLE_SECTION_INIT(var) ={xx};" or + * "AT_NONCACHEABLE_SECTION_ALIGN_INIT(var) ={xx};" in your projects to define them, for zero-inited non-cacheable variables, + * please using "AT_NONCACHEABLE_SECTION(var);" or "AT_NONCACHEABLE_SECTION_ALIGN(var);" to define them, these zero-inited variables + * will be initialized to zero in system startup. + */ +/* @{ */ +#if (defined(__ICCARM__)) +#if defined(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE) +#define AT_NONCACHEABLE_SECTION(var) var @"NonCacheable" +#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"NonCacheable" +#define AT_NONCACHEABLE_SECTION_INIT(var) var @"NonCacheable.init" +#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"NonCacheable.init" +#else +#define AT_NONCACHEABLE_SECTION(var) var +#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var +#define AT_NONCACHEABLE_SECTION_INIT(var) var +#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var +#endif +#elif(defined(__ARMCC_VERSION)) +#if defined(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE) +#define AT_NONCACHEABLE_SECTION(var) __attribute__((section("NonCacheable"), zero_init)) var +#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \ + __attribute__((section("NonCacheable"), zero_init)) __align(alignbytes) var +#define AT_NONCACHEABLE_SECTION_INIT(var) __attribute__((section("NonCacheable.init"))) var +#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \ + __attribute__((section("NonCacheable.init"))) __align(alignbytes) var +#else +#define AT_NONCACHEABLE_SECTION(var) var +#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) __align(alignbytes) var +#define AT_NONCACHEABLE_SECTION_INIT(var) var +#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) __align(alignbytes) var +#endif +#elif(defined(__GNUC__)) +/* For GCC, when the non-cacheable section is required, please define "__STARTUP_INITIALIZE_NONCACHEDATA" + * in your projects to make sure the non-cacheable section variables will be initialized in system startup. + */ +#if defined(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE) +#define AT_NONCACHEABLE_SECTION_INIT(var) __attribute__((section("NonCacheable.init"))) var +#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \ + __attribute__((section("NonCacheable.init"))) var __attribute__((aligned(alignbytes))) +#define AT_NONCACHEABLE_SECTION(var) __attribute__((section("NonCacheable,\"aw\",%nobits @"))) var +#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \ + __attribute__((section("NonCacheable,\"aw\",%nobits @"))) var __attribute__((aligned(alignbytes))) +#else +#define AT_NONCACHEABLE_SECTION(var) var +#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) var __attribute__((aligned(alignbytes))) +#define AT_NONCACHEABLE_SECTION_INIT(var) var +#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) var __attribute__((aligned(alignbytes))) +#endif +#else +#error Toolchain not supported. +#define AT_NONCACHEABLE_SECTION(var) var +#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) var +#define AT_NONCACHEABLE_SECTION_INIT(var) var +#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) var +#endif +/* @} */ + /******************************************************************************* * API ******************************************************************************/ diff --git a/targets/targets.json b/targets/targets.json index f51a92d6f2c..bac724d29ef 100755 --- a/targets/targets.json +++ b/targets/targets.json @@ -731,12 +731,14 @@ "inherits": ["Target"], "detect_code": ["1056"], "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"], + "features": ["LWIP"], "release_versions": ["2", "5"], "device_name" : "LPC54618J512ET180" }, "FF_LPC546XX": { "inherits": ["LPC546XX"], "extra_labels_remove" : ["LPCXpresso"], + "features_remove": ["LWIP"], "supported_form_factors": [""], "detect_code": ["8081"] },