1
0
Fork 0

Squashed 'tmk_core/' changes from 7967731..b9e0ea0

b9e0ea0 Merge commit '7fa9d8bdea3773d1195b04d98fcf27cf48ddd81d' as 'tool/mbed/mbed-sdk'
7fa9d8b Squashed 'tool/mbed/mbed-sdk/' content from commit 7c21ce5

git-subtree-dir: tmk_core
git-subtree-split: b9e0ea08cb940de20b3610ecdda18e9d8cd7c552
This commit is contained in:
Jun Wako 2015-04-24 16:26:14 +09:00
parent a20ef7052c
commit 1fe4406f37
4198 changed files with 2016457 additions and 0 deletions

View file

@ -0,0 +1,156 @@
/* EthernetInterface.cpp */
/* 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.
*/
#include "EthernetInterface.h"
#include "lwip/inet.h"
#include "lwip/netif.h"
#include "netif/etharp.h"
#include "lwip/dhcp.h"
#include "eth_arch.h"
#include "lwip/tcpip.h"
#include "mbed.h"
/* TCP/IP and Network Interface Initialisation */
static struct netif netif;
static char mac_addr[19];
static char ip_addr[17] = "\0";
static char gateway[17] = "\0";
static char networkmask[17] = "\0";
static bool use_dhcp = false;
static Semaphore tcpip_inited(0);
static Semaphore netif_linked(0);
static Semaphore netif_up(0);
static void tcpip_init_done(void *arg) {
tcpip_inited.release();
}
static void netif_link_callback(struct netif *netif) {
if (netif_is_link_up(netif)) {
netif_linked.release();
}
}
static void netif_status_callback(struct netif *netif) {
if (netif_is_up(netif)) {
strcpy(ip_addr, inet_ntoa(netif->ip_addr));
strcpy(gateway, inet_ntoa(netif->gw));
strcpy(networkmask, inet_ntoa(netif->netmask));
netif_up.release();
}
}
static void init_netif(ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw) {
tcpip_init(tcpip_init_done, NULL);
tcpip_inited.wait();
memset((void*) &netif, 0, sizeof(netif));
netif_add(&netif, ipaddr, netmask, gw, NULL, eth_arch_enetif_init, tcpip_input);
netif_set_default(&netif);
netif_set_link_callback (&netif, netif_link_callback);
netif_set_status_callback(&netif, netif_status_callback);
}
static void set_mac_address(void) {
#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
snprintf(mac_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", MBED_MAC_ADDR_0, MBED_MAC_ADDR_1, MBED_MAC_ADDR_2,
MBED_MAC_ADDR_3, MBED_MAC_ADDR_4, MBED_MAC_ADDR_5);
#else
char mac[6];
mbed_mac_address(mac);
snprintf(mac_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
#endif
}
int EthernetInterface::init() {
use_dhcp = true;
set_mac_address();
init_netif(NULL, NULL, NULL);
return 0;
}
int EthernetInterface::init(const char* ip, const char* mask, const char* gateway) {
use_dhcp = false;
set_mac_address();
strcpy(ip_addr, ip);
ip_addr_t ip_n, mask_n, gateway_n;
inet_aton(ip, &ip_n);
inet_aton(mask, &mask_n);
inet_aton(gateway, &gateway_n);
init_netif(&ip_n, &mask_n, &gateway_n);
return 0;
}
int EthernetInterface::connect(unsigned int timeout_ms) {
eth_arch_enable_interrupts();
int inited;
if (use_dhcp) {
dhcp_start(&netif);
// Wait for an IP Address
// -1: error, 0: timeout
inited = netif_up.wait(timeout_ms);
} else {
netif_set_up(&netif);
// Wait for the link up
inited = netif_linked.wait(timeout_ms);
}
return (inited > 0) ? (0) : (-1);
}
int EthernetInterface::disconnect() {
if (use_dhcp) {
dhcp_release(&netif);
dhcp_stop(&netif);
} else {
netif_set_down(&netif);
}
eth_arch_disable_interrupts();
return 0;
}
char* EthernetInterface::getMACAddress() {
return mac_addr;
}
char* EthernetInterface::getIPAddress() {
return ip_addr;
}
char* EthernetInterface::getGateway() {
return gateway;
}
char* EthernetInterface::getNetworkMask() {
return networkmask;
}

View file

@ -0,0 +1,90 @@
/* EthernetInterface.h */
/* 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 ETHERNETINTERFACE_H_
#define ETHERNETINTERFACE_H_
#if !defined(TARGET_LPC1768) && !defined(TARGET_LPC4088) && !defined(TARGET_LPC4088_DM) && !defined(TARGET_K64F) && !defined(TARGET_RZ_A1H) && !defined(TARGET_STM32F4)
#error The Ethernet Interface library is not supported on this target
#endif
#include "rtos.h"
#include "lwip/netif.h"
/** Interface using Ethernet to connect to an IP-based network
*
*/
class EthernetInterface {
public:
/** Initialize the interface with DHCP.
* Initialize the interface and configure it to use DHCP (no connection at this point).
* \return 0 on success, a negative number on failure
*/
static int init(); //With DHCP
/** Initialize the interface with a static IP address.
* Initialize the interface and configure it with the following static configuration (no connection at this point).
* \param ip the IP address to use
* \param mask the IP address mask
* \param gateway the gateway to use
* \return 0 on success, a negative number on failure
*/
static int init(const char* ip, const char* mask, const char* gateway);
/** Connect
* Bring the interface up, start DHCP if needed.
* \param timeout_ms timeout in ms (default: (15)s).
* \return 0 on success, a negative number on failure
*/
static int connect(unsigned int timeout_ms=15000);
/** Disconnect
* Bring the interface down
* \return 0 on success, a negative number on failure
*/
static int disconnect();
/** Get the MAC address of your Ethernet interface
* \return a pointer to a string containing the MAC address
*/
static char* getMACAddress();
/** Get the IP address of your Ethernet interface
* \return a pointer to a string containing the IP address
*/
static char* getIPAddress();
/** Get the Gateway address of your Ethernet interface
* \return a pointer to a string containing the Gateway address
*/
static char* getGateway();
/** Get the Network mask of your Ethernet interface
* \return a pointer to a string containing the Network mask
*/
static char* getNetworkMask();
};
#include "TCPSocketConnection.h"
#include "TCPSocketServer.h"
#include "Endpoint.h"
#include "UDPSocket.h"
#endif /* ETHERNETINTERFACE_H_ */

View file

@ -0,0 +1,41 @@
/* EthernetInterface.h */
/* 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.
*/
// Architecture specific Ethernet interface
// Must be implemented by each target
#ifndef ETHARCH_H_
#define ETHARCH_H_
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
void eth_arch_enable_interrupts(void);
void eth_arch_disable_interrupts(void);
err_t eth_arch_enetif_init(struct netif *netif);
#ifdef __cplusplus
}
#endif
#endif // #ifndef ETHARCHINTERFACE_H_

View file

@ -0,0 +1,469 @@
/*
* Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc.
* All rights reserved.
*
* 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 Freescale Semiconductor, Inc. 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.
*/
/* Modified by mbed for the lwIP port */
#include "fsl_enet_driver.h"
#include "fsl_enet_hal.h"
#include "fsl_clock_manager.h"
#include "fsl_interrupt_manager.h"
#include <string.h>
#include "sys_arch.h"
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief Define ENET's IRQ list */
void *enetIfHandle;
/*! @brief Define MAC driver API structure and for application of stack adaptor layer*/
const enet_mac_api_t g_enetMacApi =
{
enet_mac_init,
NULL, // enet_mac_deinit,
NULL, // enet_mac_send,
#if !ENET_RECEIVE_ALL_INTERRUPT
NULL, // enet_mac_receive,
#endif
enet_mii_read,
enet_mii_write,
NULL, // enet_mac_add_multicast_group,
NULL, //enet_mac_leave_multicast_group,
};
/*******************************************************************************
* Code
******************************************************************************/
// NOTE: we need these functions to be non-blocking fpr the PHY task, hence the
// osDelay() below
/*FUNCTION****************************************************************
*
* Function Name: enet_mii_read
* Return Value: The execution status.
* Description: Read function.
* This interface read data over the (R)MII bus from the specified PHY register,
* This function is called by all PHY interfaces.
*END*********************************************************************/
uint32_t enet_mii_read(uint32_t instance, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr)
{
uint32_t counter;
/* Check the input parameters*/
if (!dataPtr)
{
return kStatus_ENET_InvalidInput;
}
/* Check if the mii is enabled*/
if (!enet_hal_is_mii_enabled(instance))
{
return kStatus_ENET_Miiuninitialized;
}
/* Clear the MII interrupt event*/
enet_hal_clear_interrupt(instance, kEnetMiiInterrupt);
/* Read command operation*/
enet_hal_set_mii_command(instance, phyAddr, phyReg, kEnetReadValidFrame, 0);
/* Poll for MII complete*/
for (counter = 0; counter < kEnetMaxTimeout; counter++)
{
if (enet_hal_get_interrupt_status(instance, kEnetMiiInterrupt))
{
break;
}
osDelay(1);
}
/* Check for timeout*/
if (counter == kEnetMaxTimeout)
{
return kStatus_ENET_TimeOut;
}
/* Get data from mii register*/
*dataPtr = enet_hal_get_mii_data(instance);
/* Clear MII interrupt event*/
enet_hal_clear_interrupt(instance, kEnetMiiInterrupt);
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mii_write
* Return Value: The execution status.
* Description: Write function.
* This interface write data over the (R)MII bus to the specified PHY register.
* This function is called by all PHY interfaces.
*END*********************************************************************/
uint32_t enet_mii_write(uint32_t instance, uint32_t phyAddr, uint32_t phyReg, uint32_t data)
{
uint32_t counter;
/* Check if the mii is enabled*/
if (!enet_hal_is_mii_enabled(instance))
{
return kStatus_ENET_Miiuninitialized;
}
/* Clear the MII interrupt event*/
enet_hal_clear_interrupt(instance, kEnetMiiInterrupt);
/* Read command operation*/
enet_hal_set_mii_command(instance, phyAddr, phyReg, kEnetWriteValidFrame, data);
/* Poll for MII complete*/
for (counter = 0; counter < kEnetMaxTimeout; counter++)
{
if (enet_hal_get_interrupt_status(instance, kEnetMiiInterrupt))
{
break;
}
osDelay(1);
}
/* Check for timeout*/
if (counter == kEnetMaxTimeout)
{
return kStatus_ENET_TimeOut;
}
/* Clear MII intrrupt event*/
enet_hal_clear_interrupt(instance, kEnetMiiInterrupt);
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mac_mii_init
* Return Value: The execution status.
* Description:Initialize the ENET Mac mii(mdc/mdio)interface.
*END*********************************************************************/
uint32_t enet_mac_mii_init(enet_dev_if_t * enetIfPtr)
{
uint32_t frequency;
/* Check the input parameters*/
if (enetIfPtr == NULL)
{
return kStatus_ENET_InvalidInput;
}
/* Configure mii speed*/
CLOCK_SYS_GetFreq(kSystemClock, &frequency);
enet_hal_config_mii(enetIfPtr->deviceNumber, (frequency/(2 * enetIfPtr->macCfgPtr->miiClock) + 1),
kEnetMdioHoldOneClkCycle, false);
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mac_rxbd_init
* Return Value: The execution status.
* Description:Initialize the ENET receive buffer descriptors.
* Note: If you do receive on receive interrupt handler the receive
* data buffer number can be the same as the receive descriptor numbers.
* But if you are polling receive frames please make sure the receive data
* buffers are more than buffer descriptors to guarantee a good performance.
*END*********************************************************************/
uint32_t enet_mac_rxbd_init(enet_dev_if_t * enetIfPtr, enet_rxbd_config_t *rxbdCfg)
{
/* Check the input parameters*/
if ((!enetIfPtr) || (!rxbdCfg))
{
return kStatus_ENET_InvalidInput;
}
enetIfPtr->macContextPtr->bufferdescSize = enet_hal_get_bd_size();
/* Initialize the bd status*/
enetIfPtr->macContextPtr->isRxFull = false;
/* Initialize receive bd base address and current address*/
enetIfPtr->macContextPtr->rxBdBasePtr = rxbdCfg->rxBdPtrAlign;
enetIfPtr->macContextPtr->rxBdCurPtr = enetIfPtr->macContextPtr->rxBdBasePtr;
enetIfPtr->macContextPtr->rxBdDirtyPtr = enetIfPtr->macContextPtr->rxBdBasePtr;
enet_hal_set_rxbd_address(enetIfPtr->deviceNumber, (uint32_t)(enetIfPtr->macContextPtr->rxBdBasePtr));
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mac_txbd_init
* Return Value: The execution status.
* Description:Initialize the ENET transmit buffer descriptors.
* This function prepare all of the transmit buffer descriptors.
*END*********************************************************************/
uint32_t enet_mac_txbd_init(enet_dev_if_t * enetIfPtr, enet_txbd_config_t *txbdCfg)
{
/* Check the input parameters*/
if ((!enetIfPtr) || (!txbdCfg))
{
return kStatus_ENET_InvalidInput;
}
/* Initialize the bd status*/
enetIfPtr->macContextPtr->isTxFull = false;
/* Initialize transmit bd base address and current address*/
enetIfPtr->macContextPtr->txBdBasePtr = txbdCfg->txBdPtrAlign;
enetIfPtr->macContextPtr->txBdCurPtr = enetIfPtr->macContextPtr->txBdBasePtr;
enetIfPtr->macContextPtr->txBdDirtyPtr = enetIfPtr->macContextPtr->txBdBasePtr;
enet_hal_set_txbd_address(enetIfPtr->deviceNumber, (uint32_t)(enetIfPtr->macContextPtr->txBdBasePtr));
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mac_configure_fifo_accel
* Return Value: The execution status.
* Description: Configure the ENET FIFO and Accelerator.
*END*********************************************************************/
uint32_t enet_mac_configure_fifo_accel(enet_dev_if_t * enetIfPtr)
{
enet_config_rx_fifo_t rxFifo;
enet_config_tx_fifo_t txFifo;
/* Check the input parameters*/
if (!enetIfPtr)
{
return kStatus_ENET_InvalidInput;
}
/* Initialize values that will not be initialized later on */
rxFifo.rxEmpty = 0;
rxFifo.rxFull = 0;
txFifo.isStoreForwardEnabled = 0;
txFifo.txFifoWrite = 0;
txFifo.txEmpty = 0;
/* Configure tx/rx accelerator*/
if (enetIfPtr->macCfgPtr->isRxAccelEnabled)
{
enet_hal_config_rx_accelerator(enetIfPtr->deviceNumber,
(enet_config_rx_accelerator_t *)&(enetIfPtr->macCfgPtr->rxAcceler));
if ((enetIfPtr->macCfgPtr->rxAcceler.isIpcheckEnabled) || (enetIfPtr->macCfgPtr->rxAcceler.isProtocolCheckEnabled))
{
rxFifo.rxFull = 0;
}
}
if (enetIfPtr->macCfgPtr->isTxAccelEnabled)
{
enet_hal_config_tx_accelerator(enetIfPtr->deviceNumber,
(enet_config_tx_accelerator_t *)&(enetIfPtr->macCfgPtr->txAcceler));
if ((enetIfPtr->macCfgPtr->txAcceler.isIpCheckEnabled) || (enetIfPtr->macCfgPtr->txAcceler.isProtocolCheckEnabled))
{
txFifo.isStoreForwardEnabled = 1;
}
}
if (enetIfPtr->macCfgPtr->isStoreAndFwEnabled)
{
rxFifo.rxFull = 0;
txFifo.isStoreForwardEnabled = 1;
}
/* Set TFWR value if STRFWD is not being used */
if (txFifo.isStoreForwardEnabled == 1)
txFifo.txFifoWrite = 0;
else
/* TFWR value is a trade-off between transmit latency and risk of transmit FIFO underrun due to contention for the system bus
TFWR = 15 means transmission will begin once 960 bytes has been written to the Tx FIFO (for frames larger than 960 bytes)
See Section 45.4.18 - Transmit FIFO Watermark Register of the K64F Reference Manual for details */
txFifo.txFifoWrite = 15;
/* Configure tx/rx FIFO with default value*/
rxFifo.rxAlmostEmpty = 4;
rxFifo.rxAlmostFull = 4;
txFifo.txAlmostEmpty = 4;
txFifo.txAlmostFull = 8;
enet_hal_config_rx_fifo(enetIfPtr->deviceNumber, &rxFifo);
enet_hal_config_tx_fifo(enetIfPtr->deviceNumber, &txFifo);
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mac_configure_controller
* Return Value: The execution status.
* Description: Configure the ENET controller with the basic configuration.
*END*********************************************************************/
uint32_t enet_mac_configure_controller(enet_dev_if_t * enetIfPtr)
{
uint32_t macCtlCfg;
/* Check the input parameters*/
if (enetIfPtr == NULL)
{
return kStatus_ENET_InvalidInput;
}
macCtlCfg = enetIfPtr->macCfgPtr->macCtlConfigure;
/* Configure rmii/mii interface*/
enet_hal_config_rmii(enetIfPtr->deviceNumber, enetIfPtr->macCfgPtr->rmiiCfgMode,
enetIfPtr->macCfgPtr->speed, enetIfPtr->macCfgPtr->duplex, false,
(macCtlCfg & kEnetRxMiiLoopback));
/* Configure receive buffer size*/
if (enetIfPtr->macCfgPtr->isVlanEnabled)
{
enetIfPtr->maxFrameSize = kEnetMaxFrameVlanSize;
enet_hal_set_rx_max_size(enetIfPtr->deviceNumber,
enetIfPtr->macContextPtr->rxBufferSizeAligned, kEnetMaxFrameVlanSize);
}
else
{
enetIfPtr->maxFrameSize = kEnetMaxFrameSize;
enet_hal_set_rx_max_size(enetIfPtr->deviceNumber,
enetIfPtr->macContextPtr->rxBufferSizeAligned, kEnetMaxFrameSize);
}
/* Set receive controller promiscuous */
enet_hal_config_promiscuous(enetIfPtr->deviceNumber, macCtlCfg & kEnetRxPromiscuousEnable);
/* Set receive flow control*/
enet_hal_enable_flowcontrol(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxFlowControlEnable));
/* Set received PAUSE frames are forwarded/terminated*/
enet_hal_enable_pauseforward(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxPauseFwdEnable));
/* Set receive broadcast frame reject*/
enet_hal_enable_broadcastreject(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxBcRejectEnable));
/* Set padding is removed from the received frame*/
enet_hal_enable_padremove(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxPadRemoveEnable));
/* Set the crc of the received frame is stripped from the frame*/
enet_hal_enable_rxcrcforward(enetIfPtr->deviceNumber, (macCtlCfg & kEnetRxCrcFwdEnable));
/* Set receive payload length check*/
enet_hal_enable_payloadcheck(enetIfPtr->deviceNumber, (macCtlCfg & kEnetPayloadlenCheckEnable));
/* Set control sleep mode*/
enet_hal_enable_sleep(enetIfPtr->deviceNumber, (macCtlCfg & kEnetSleepModeEnable));
return kStatus_ENET_Success;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_mac_init
* Return Value: The execution status.
* Description:Initialize the ENET device with the basic configuration
* When ENET is used, this function need to be called by the NET initialize
* interface.
*END*********************************************************************/
uint32_t enet_mac_init(enet_dev_if_t * enetIfPtr, enet_rxbd_config_t *rxbdCfg,
enet_txbd_config_t *txbdCfg)
{
uint32_t timeOut = 0;
uint32_t devNumber, result = 0;
/* Check the input parameters*/
if (enetIfPtr == NULL)
{
return kStatus_ENET_InvalidInput;
}
/* Get device number and check the parameter*/
devNumber = enetIfPtr->deviceNumber;
/* Store the global ENET structure for ISR input parameters */
enetIfHandle = enetIfPtr;
/* Turn on ENET module clock gate */
CLOCK_SYS_EnableEnetClock(0U);
/* Reset ENET mac*/
enet_hal_reset_ethernet(devNumber);
while ((!enet_hal_is_reset_completed(devNumber)) && (timeOut < kEnetMaxTimeout))
{
time_delay(1);
timeOut++;
}
/* Check out if timeout*/
if (timeOut == kEnetMaxTimeout)
{
return kStatus_ENET_TimeOut;
}
/* Disable all ENET mac interrupt and Clear all interrupt events*/
enet_hal_config_interrupt(devNumber, kEnetAllInterrupt, false);
enet_hal_clear_interrupt(devNumber, kEnetAllInterrupt);
/* Program this station's physical address*/
enet_hal_set_mac_address(devNumber, enetIfPtr->macCfgPtr->macAddr);
/* Clear group and individual hash register*/
enet_hal_set_group_hashtable(devNumber, 0, kEnetSpecialAddressInit);
enet_hal_set_individual_hashtable(devNumber, 0, kEnetSpecialAddressInit);
/* Configure mac controller*/
result = enet_mac_configure_controller(enetIfPtr);
if(result != kStatus_ENET_Success)
{
return result;
}
/* Clear mib zero counters*/
enet_hal_clear_mib(devNumber, true);
/* Initialize FIFO and accelerator*/
result = enet_mac_configure_fifo_accel(enetIfPtr);
if(result != kStatus_ENET_Success)
{
return result;
}
/* Initialize receive buffer descriptors*/
result = enet_mac_rxbd_init(enetIfPtr, rxbdCfg);
if(result != kStatus_ENET_Success)
{
return result;
}
/* Initialize transmit buffer descriptors*/
result = enet_mac_txbd_init(enetIfPtr, txbdCfg);
if(result != kStatus_ENET_Success)
{
return result;
}
/* Initialize rmii/mii interface*/
result = enet_mac_mii_init(enetIfPtr);
if (result != kStatus_ENET_Success)
{
return result;
}
return kStatus_ENET_Success;
}
/*******************************************************************************
* EOF
******************************************************************************/

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc.
* All rights reserved.
*
* 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 Freescale Semiconductor, Inc. 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_port_hal.h"
#include "fsl_clock_manager.h"
#include "fsl_device_registers.h"
#include "fsl_sim_hal.h"
/*******************************************************************************
* Code
******************************************************************************/
void k64f_init_eth_hardware(void)
{
uint8_t count;
/* Disable the mpu*/
BW_MPU_CESR_VLD(MPU_BASE, 0);
/* Open POTR clock gate*/
for (count = 0; count < HW_PORT_INSTANCE_COUNT; count++)
{
CLOCK_SYS_EnablePortClock(count);
}
/* Configure gpio*/
PORT_HAL_SetMuxMode(PORTA_BASE, 12, kPortMuxAlt4); /*!< ENET RMII0_RXD1/MII0_RXD1*/
PORT_HAL_SetMuxMode(PORTA_BASE, 13, kPortMuxAlt4); /*!< ENET RMII0_RXD0/MII0_RXD0*/
PORT_HAL_SetMuxMode(PORTA_BASE, 14, kPortMuxAlt4); /*!< ENET RMII0_CRS_DV/MII0_RXDV*/
PORT_HAL_SetMuxMode(PORTA_BASE, 15, kPortMuxAlt4); /*!< ENET RMII0_TXEN/MII0_TXEN*/
PORT_HAL_SetMuxMode(PORTA_BASE, 16, kPortMuxAlt4); /*!< ENET RMII0_TXD0/MII0_TXD0*/
PORT_HAL_SetMuxMode(PORTA_BASE, 17, kPortMuxAlt4); /*!< ENET RMII0_TXD01/MII0_TXD1*/
PORT_HAL_SetMuxMode(PORTB_BASE, 0, kPortMuxAlt4); /*!< ENET RMII0_MDIO/MII0_MDIO*/
PORT_HAL_SetOpenDrainCmd(PORTB_BASE,0, true); /*!< ENET RMII0_MDC/MII0_MDC*/
// Added for FRDM-K64F
PORT_HAL_SetPullMode(PORTB_BASE, 0, kPortPullUp);
PORT_HAL_SetPullCmd(PORTB_BASE, 0, true);
PORT_HAL_SetMuxMode(PORTB_BASE, 1, kPortMuxAlt4);
/* Configure GPIO for MII interface */
PORT_HAL_SetMuxMode(PORTA_BASE, 9, kPortMuxAlt4); /*!< ENET MII0_RXD3*/
PORT_HAL_SetMuxMode(PORTA_BASE, 10, kPortMuxAlt4); /*!< ENET MII0_RXD2*/
PORT_HAL_SetMuxMode(PORTA_BASE, 11, kPortMuxAlt4); /*!< ENET MII0_RXCLK*/
PORT_HAL_SetMuxMode(PORTA_BASE, 24, kPortMuxAlt4); /*!< ENET MII0_TXD2*/
PORT_HAL_SetMuxMode(PORTA_BASE, 25, kPortMuxAlt4); /*!< ENET MII0_TXCLK*/
PORT_HAL_SetMuxMode(PORTA_BASE, 26, kPortMuxAlt4); /*!< ENET MII0_TXD3*/
PORT_HAL_SetMuxMode(PORTA_BASE, 27, kPortMuxAlt4); /*!< ENET MII0_CRS*/
PORT_HAL_SetMuxMode(PORTA_BASE, 28, kPortMuxAlt4); /*!< ENET MII0_TXER*/
PORT_HAL_SetMuxMode(PORTA_BASE, 29, kPortMuxAlt4); /*!< ENET MII0_COL*/
#if FSL_FEATURE_ENET_SUPPORT_PTP
PORT_HAL_SetMuxMode(PORTC_BASE, (16 + ENET_TIMER_CHANNEL_NUM), kPortMuxAlt4); /* ENET ENET0_1588_TMR0*/
PORT_HAL_SetDriveStrengthMode(PORTC_BASE, (16 + ENET_TIMER_CHANNEL_NUM), kPortHighDriveStrength);
#endif
/* Open ENET clock gate*/
CLOCK_SYS_EnableEnetClock( 0U);
/* Select the ptp timer outclk*/
CLOCK_HAL_SetSource(g_simBaseAddr[0], kClockTimeSrc, 2);
}
/*******************************************************************************
* EOF
******************************************************************************/

View file

@ -0,0 +1,885 @@
#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 "netif/etharp.h"
#include "netif/ppp_oe.h"
#include "eth_arch.h"
#include "sys_arch.h"
#include "fsl_enet_driver.h"
#include "fsl_enet_hal.h"
#include "fsl_device_registers.h"
#include "fsl_phy_driver.h"
#include "fsl_interrupt_manager.h"
#include "k64f_emac_config.h"
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mbed_interface.h"
extern IRQn_Type enet_irq_ids[HW_ENET_INSTANCE_COUNT][FSL_FEATURE_ENET_INTERRUPT_COUNT];
extern uint8_t enetIntMap[kEnetIntNum];
extern void *enetIfHandle;
/********************************************************************************
* Internal data
********************************************************************************/
extern void k64f_init_eth_hardware(void);
/* K64F EMAC driver data structure */
struct k64f_enetdata {
struct netif *netif; /**< Reference back to LWIP parent netif */
sys_sem_t RxReadySem; /**< RX packet ready semaphore */
sys_sem_t TxCleanSem; /**< TX cleanup thread wakeup semaphore */
sys_mutex_t TXLockMutex; /**< TX critical section mutex */
sys_sem_t xTXDCountSem; /**< TX free buffer counting semaphore */
volatile u32_t rx_free_descs; /**< Count of free RX descriptors */
struct pbuf *rxb[ENET_RX_RING_LEN]; /**< RX pbuf pointer list, zero-copy mode */
uint8_t *rx_desc_start_addr; /**< RX descriptor start address */
uint8_t *tx_desc_start_addr; /**< TX descriptor start address */
uint8_t tx_consume_index, tx_produce_index; /**< TX buffers ring */
uint8_t rx_fill_index; /**< RX ring fill index */
struct pbuf *txb[ENET_TX_RING_LEN]; /**< TX pbuf pointer list, zero-copy mode */
void *txb_aligned[ENET_TX_RING_LEN]; /**< TX aligned buffers (if needed) */
};
static struct k64f_enetdata k64f_enetdata;
static enet_dev_if_t enetDevIf[HW_ENET_INSTANCE_COUNT];
static enet_mac_config_t g_enetMacCfg[HW_ENET_INSTANCE_COUNT] =
{
{
ENET_ETH_MAX_FLEN , /*!< enet receive buffer size*/
ENET_RX_LARGE_BUFFER_NUM, /*!< enet large receive buffer number*/
ENET_RX_RING_LEN, /*!< enet receive bd number*/
ENET_TX_RING_LEN, /*!< enet transmit bd number*/
{0}, /*!< enet mac address*/
kEnetCfgRmii, /*!< enet rmii interface*/
kEnetCfgSpeed100M, /*!< enet rmii 100M*/
kEnetCfgFullDuplex, /*!< enet rmii Full- duplex*/
/*!< enet mac control flag recommended to use enet_mac_control_flag_t
we send frame with crc so receive crc forward for data length check test*/
kEnetRxCrcFwdEnable | kEnetRxFlowControlEnable,
true, /*!< enet txaccelerator enabled*/
true, /*!< enet rxaccelerator enabled*/
false, /*!< enet store and forward*/
{false, false, true, false, true}, /*!< enet rxaccelerator config*/
{false, false, true}, /*!< enet txaccelerator config*/
true, /*!< vlan frame support*/
true, /*!< phy auto discover*/
ENET_MII_CLOCK, /*!< enet MDC clock*/
},
};
static enet_phy_config_t g_enetPhyCfg[HW_ENET_INSTANCE_COUNT] =
{
{0, false}
};
/** \brief Driver transmit and receive thread priorities
*
* Thread priorities for receive thread and TX cleanup thread. Alter
* to prioritize receive or transmit bandwidth. In a heavily loaded
* system or with LEIP_DEBUG enabled, the priorities might be better
* the same. */
#define RX_PRIORITY (osPriorityNormal)
#define TX_PRIORITY (osPriorityNormal)
#define PHY_PRIORITY (osPriorityNormal)
/** \brief Debug output formatter lock define
*
* When using FreeRTOS and with LWIP_DEBUG enabled, enabling this
* define will allow RX debug messages to not interleave with the
* TX messages (so they are actually readable). Not enabling this
* define when the system is under load will cause the output to
* be unreadable. There is a small tradeoff in performance for this
* so use it only for debug. */
//#define LOCK_RX_THREAD
/** \brief Signal used for ethernet ISR to signal packet_rx() thread.
*/
#define RX_SIGNAL 1
// K64F-specific macros
#define RX_PBUF_AUTO_INDEX (-1)
/********************************************************************************
* Buffer management
********************************************************************************/
/** \brief Queues a pbuf into the RX descriptor list
*
* \param[in] k64f_enet Pointer to the drvier data structure
* \param[in] p Pointer to pbuf to queue
* \param[in] bidx Index to queue into
*/
static void k64f_rxqueue_pbuf(struct k64f_enetdata *k64f_enet, struct pbuf *p, int bidx)
{
enet_bd_struct_t *start = (enet_bd_struct_t *)k64f_enet->rx_desc_start_addr;
int idx;
/* Get next free descriptor index */
if (bidx == RX_PBUF_AUTO_INDEX)
idx = k64f_enet->rx_fill_index;
else
idx = bidx;
/* Setup descriptor and clear statuses */
enet_hal_init_rxbds(start + idx, (uint8_t*)p->payload, idx == ENET_RX_RING_LEN - 1);
/* Save pbuf pointer for push to network layer later */
k64f_enet->rxb[idx] = p;
/* Wrap at end of descriptor list */
idx = (idx + 1) % ENET_RX_RING_LEN;
/* Queue descriptor(s) */
k64f_enet->rx_free_descs -= 1;
if (bidx == RX_PBUF_AUTO_INDEX)
k64f_enet->rx_fill_index = idx;
enet_hal_active_rxbd(BOARD_DEBUG_ENET_INSTANCE_ADDR);
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
("k64f_rxqueue_pbuf: pbuf packet queued: %p (free desc=%d)\n", p,
k64f_enet->rx_free_descs));
}
/** \brief Attempt to allocate and requeue a new pbuf for RX
*
* \param[in] netif Pointer to the netif structure
* \returns number of queued packets
*/
s32_t k64f_rx_queue(struct netif *netif, int idx)
{
struct k64f_enetdata *k64f_enet = netif->state;
enet_dev_if_t *enetIfPtr = (enet_dev_if_t *)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
struct pbuf *p;
int queued = 0;
/* Attempt to requeue as many packets as possible */
while (k64f_enet->rx_free_descs > 0) {
/* Allocate a pbuf from the pool. We need to allocate at the
maximum size as we don't know the size of the yet to be
received packet. */
p = pbuf_alloc(PBUF_RAW, enetIfPtr->macCfgPtr->rxBufferSize + RX_BUF_ALIGNMENT, PBUF_RAM);
if (p == NULL) {
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
("k64_rx_queue: could not allocate RX pbuf (free desc=%d)\n",
k64f_enet->rx_free_descs));
return queued;
}
/* K64F note: the next line ensures that the RX buffer is properly aligned for the K64F
RX descriptors (16 bytes alignment). However, by doing so, we're effectively changing
a data structure which is internal to lwIP. This might not prove to be a good idea
in the long run, but a better fix would probably involve modifying lwIP itself */
p->payload = (void*)ENET_ALIGN((uint32_t)p->payload, RX_BUF_ALIGNMENT);
/* pbufs allocated from the RAM pool should be non-chained. */
LWIP_ASSERT("k64f_rx_queue: pbuf is not contiguous (chained)", pbuf_clen(p) <= 1);
/* Queue packet */
k64f_rxqueue_pbuf(k64f_enet, p, idx);
queued++;
}
return queued;
}
/** \brief Sets up the RX descriptor ring buffers.
*
* This function sets up the descriptor list used for receive packets.
*
* \param[in] netif Pointer to driver data structure
* \returns ERR_MEM if out of memory, ERR_OK otherwise
*/
static err_t k64f_rx_setup(struct netif *netif, enet_rxbd_config_t *rxbdCfg) {
struct k64f_enetdata *k64f_enet = netif->state;
enet_dev_if_t *enetIfPtr = (enet_dev_if_t *)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
uint8_t *rxBdPtr;
uint32_t rxBufferSizeAligned;
// Allocate RX descriptors
rxBdPtr = (uint8_t *)calloc(1, enet_hal_get_bd_size() * enetIfPtr->macCfgPtr->rxBdNumber + ENET_BD_ALIGNMENT);
if(!rxBdPtr)
return ERR_MEM;
k64f_enet->rx_desc_start_addr = (uint8_t *)ENET_ALIGN((uint32_t)rxBdPtr, ENET_BD_ALIGNMENT);
k64f_enet->rx_free_descs = enetIfPtr->macCfgPtr->rxBdNumber;
k64f_enet->rx_fill_index = 0;
rxBufferSizeAligned = ENET_ALIGN(enetIfPtr->macCfgPtr->rxBufferSize, ENET_RX_BUFFER_ALIGNMENT);
enetIfPtr->macContextPtr->rxBufferSizeAligned = rxBufferSizeAligned;
rxbdCfg->rxBdPtrAlign = k64f_enet->rx_desc_start_addr;
rxbdCfg->rxBdNum = enetIfPtr->macCfgPtr->rxBdNumber;
rxbdCfg->rxBufferNum = enetIfPtr->macCfgPtr->rxBdNumber;
k64f_rx_queue(netif, RX_PBUF_AUTO_INDEX);
return ERR_OK;
}
/** \brief Sets up the TX descriptor ring buffers.
*
* This function sets up the descriptor list used for transmit packets.
*
* \param[in] netif Pointer to driver data structure
* \returns ERR_MEM if out of memory, ERR_OK otherwise
*/
static err_t k64f_tx_setup(struct netif *netif, enet_txbd_config_t *txbdCfg) {
struct k64f_enetdata *k64f_enet = netif->state;
enet_dev_if_t *enetIfPtr = (enet_dev_if_t *)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
uint8_t *txBdPtr;
// Allocate TX descriptors
txBdPtr = (uint8_t *)calloc(1, enet_hal_get_bd_size() * enetIfPtr->macCfgPtr->txBdNumber + ENET_BD_ALIGNMENT);
if(!txBdPtr)
return ERR_MEM;
k64f_enet->tx_desc_start_addr = (uint8_t *)ENET_ALIGN((uint32_t)txBdPtr, ENET_BD_ALIGNMENT);
k64f_enet->tx_consume_index = k64f_enet->tx_produce_index = 0;
txbdCfg->txBdPtrAlign = k64f_enet->tx_desc_start_addr;
txbdCfg->txBufferNum = enetIfPtr->macCfgPtr->txBdNumber;
txbdCfg->txBufferSizeAlign = ENET_ALIGN(enetIfPtr->maxFrameSize, ENET_TX_BUFFER_ALIGNMENT);
// Make the TX descriptor ring circular
enet_hal_init_txbds(k64f_enet->tx_desc_start_addr + enet_hal_get_bd_size() * (ENET_TX_RING_LEN - 1), 1);
return ERR_OK;
}
/** \brief Free TX buffers that are complete
*
* \param[in] k64f_enet Pointer to driver data structure
*/
static void k64f_tx_reclaim(struct k64f_enetdata *k64f_enet)
{
uint8_t i;
volatile enet_bd_struct_t * bdPtr = (enet_bd_struct_t *)k64f_enet->tx_desc_start_addr;
/* Get exclusive access */
sys_mutex_lock(&k64f_enet->TXLockMutex);
// Traverse all descriptors, looking for the ones modified by the uDMA
i = k64f_enet->tx_consume_index;
while(i != k64f_enet->tx_produce_index && !(bdPtr[i].control & kEnetTxBdReady)) {
if (k64f_enet->txb_aligned[i]) {
free(k64f_enet->txb_aligned[i]);
k64f_enet->txb_aligned[i] = NULL;
} else if (k64f_enet->txb[i]) {
pbuf_free(k64f_enet->txb[i]);
k64f_enet->txb[i] = NULL;
}
osSemaphoreRelease(k64f_enet->xTXDCountSem.id);
bdPtr[i].controlExtend2 &= ~TX_DESC_UPDATED_MASK;
i = (i + 1) % ENET_TX_RING_LEN;
}
k64f_enet->tx_consume_index = i;
/* Restore access */
sys_mutex_unlock(&k64f_enet->TXLockMutex);
}
/** \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)
{
enet_dev_if_t * enetIfPtr;
uint32_t device = BOARD_DEBUG_ENET_INSTANCE_ADDR;
enet_rxbd_config_t rxbdCfg;
enet_txbd_config_t txbdCfg;
enet_phy_speed_t phy_speed;
enet_phy_duplex_t phy_duplex;
k64f_init_eth_hardware();
/* Initialize device*/
enetIfPtr = (enet_dev_if_t *)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
enetIfPtr->deviceNumber = device;
enetIfPtr->macCfgPtr = &g_enetMacCfg[BOARD_DEBUG_ENET_INSTANCE];
enetIfPtr->phyCfgPtr = &g_enetPhyCfg[BOARD_DEBUG_ENET_INSTANCE];
enetIfPtr->macApiPtr = &g_enetMacApi;
enetIfPtr->phyApiPtr = (void *)&g_enetPhyApi;
memcpy(enetIfPtr->macCfgPtr->macAddr, (char*)netif->hwaddr, kEnetMacAddrLen);
/* Allocate buffer for ENET mac context*/
enetIfPtr->macContextPtr = (enet_mac_context_t *)calloc(1, sizeof(enet_mac_context_t));
if (!enetIfPtr->macContextPtr) {
return ERR_BUF;
}
/* Initialize enet buffers*/
if(k64f_rx_setup(netif, &rxbdCfg) != ERR_OK) {
return ERR_BUF;
}
/* Initialize enet buffers*/
if(k64f_tx_setup(netif, &txbdCfg) != ERR_OK) {
return ERR_BUF;
}
/* Initialize enet module*/
if (enet_mac_init(enetIfPtr, &rxbdCfg, &txbdCfg) == kStatus_ENET_Success)
{
/* Initialize PHY*/
if (enetIfPtr->macCfgPtr->isPhyAutoDiscover) {
if (((enet_phy_api_t *)(enetIfPtr->phyApiPtr))->phy_auto_discover(enetIfPtr) != kStatus_PHY_Success)
return ERR_IF;
}
if (((enet_phy_api_t *)(enetIfPtr->phyApiPtr))->phy_init(enetIfPtr) != kStatus_PHY_Success)
return ERR_IF;
enetIfPtr->isInitialized = true;
}
else
{
// TODOETH: cleanup memory
return ERR_IF;
}
/* Get link information from PHY */
phy_get_link_speed(enetIfPtr, &phy_speed);
phy_get_link_duplex(enetIfPtr, &phy_duplex);
BW_ENET_RCR_RMII_10T(enetIfPtr->deviceNumber, phy_speed == kEnetSpeed10M ? kEnetCfgSpeed10M : kEnetCfgSpeed100M);
BW_ENET_TCR_FDEN(enetIfPtr->deviceNumber, phy_duplex == kEnetFullDuplex ? kEnetCfgFullDuplex : kEnetCfgHalfDuplex);
/* Enable Ethernet module*/
enet_hal_config_ethernet(BOARD_DEBUG_ENET_INSTANCE_ADDR, true, true);
/* Active Receive buffer descriptor must be done after module enable*/
enet_hal_active_rxbd(enetIfPtr->deviceNumber);
return ERR_OK;
}
/********************************************************************************
* LWIP port
********************************************************************************/
/** \brief Ethernet receive interrupt handler
*
* This function handles the receive interrupt of K64F.
*/
void enet_mac_rx_isr(void *enetIfPtr)
{
/* Clear interrupt */
enet_hal_clear_interrupt(((enet_dev_if_t *)enetIfPtr)->deviceNumber, kEnetRxFrameInterrupt);
sys_sem_signal(&k64f_enetdata.RxReadySem);
}
void enet_mac_tx_isr(void *enetIfPtr)
{
/*Clear interrupt*/
enet_hal_clear_interrupt(((enet_dev_if_t *)enetIfPtr)->deviceNumber, kEnetTxFrameInterrupt);
sys_sem_signal(&k64f_enetdata.TxCleanSem);
}
/**
* This function is the ethernet packet send function. It calls
* etharp_output after checking link status.
*
* \param[in] netif the lwip network interface structure for this enetif
* \param[in] q Pointer to pbug to send
* \param[in] ipaddr IP address
* \return ERR_OK or error code
*/
err_t k64f_etharp_output(struct netif *netif, struct pbuf *q, ip_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;
}
/** \brief Allocates a pbuf and returns the data from the incoming packet.
*
* \param[in] netif the lwip network interface structure
* \param[in] idx index of packet to be read
* \return a pbuf filled with the received packet (including MAC header)
*/
static struct pbuf *k64f_low_level_input(struct netif *netif, int idx)
{
struct k64f_enetdata *k64f_enet = netif->state;
enet_bd_struct_t * bdPtr = (enet_bd_struct_t*)k64f_enet->rx_desc_start_addr;
struct pbuf *p = NULL;
u32_t length = 0, orig_length;
const u16_t err_mask = kEnetRxBdTrunc | kEnetRxBdCrc | kEnetRxBdNoOctet | kEnetRxBdLengthViolation;
#ifdef LOCK_RX_THREAD
/* Get exclusive access */
sys_mutex_lock(&k64f_enet->TXLockMutex);
#endif
/* Determine if a frame has been received */
if ((bdPtr[idx].control & err_mask) != 0) {
#if LINK_STATS
if ((bdPtr[idx].control & kEnetRxBdLengthViolation) != 0)
LINK_STATS_INC(link.lenerr);
else
LINK_STATS_INC(link.chkerr);
#endif
LINK_STATS_INC(link.drop);
/* Re-queue the same buffer */
k64f_enet->rx_free_descs++;
p = k64f_enet->rxb[idx];
k64f_enet->rxb[idx] = NULL;
k64f_rxqueue_pbuf(k64f_enet, p, idx);
p = NULL;
} else {
/* A packet is waiting, get length */
length = enet_hal_get_bd_length(bdPtr + idx);
/* Zero-copy */
p = k64f_enet->rxb[idx];
orig_length = p->len;
p->len = (u16_t) length;
/* Free pbuf from descriptor */
k64f_enet->rxb[idx] = NULL;
k64f_enet->rx_free_descs++;
/* Attempt to queue new buffer */
if (k64f_rx_queue(netif, idx) == 0) {
/* Drop frame (out of memory) */
LINK_STATS_INC(link.drop);
/* Re-queue the same buffer */
p->len = orig_length;
k64f_rxqueue_pbuf(k64f_enet, p, idx);
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
("k64f_low_level_input: Packet index %d dropped for OOM\n",
idx));
#ifdef LOCK_RX_THREAD
sys_mutex_unlock(&k64f_enet->TXLockMutex);
#endif
return NULL;
}
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
("k64f_low_level_input: Packet received: %p, size %d (index=%d)\n",
p, length, idx));
/* Save size */
p->tot_len = (u16_t) length;
LINK_STATS_INC(link.recv);
}
#ifdef LOCK_RX_THREAD
sys_mutex_unlock(&k64f_enet->TXLockMutex);
#endif
return p;
}
/** \brief Attempt to read a packet from the EMAC interface.
*
* \param[in] netif the lwip network interface structure
* \param[in] idx index of packet to be read
*/
void k64f_enetif_input(struct netif *netif, int idx)
{
struct eth_hdr *ethhdr;
struct pbuf *p;
/* move received packet into a new pbuf */
p = k64f_low_level_input(netif, idx);
if (p == NULL)
return;
/* points to packet payload, which starts with an Ethernet header */
ethhdr = (struct eth_hdr*)p->payload;
switch (htons(ethhdr->type)) {
case ETHTYPE_IP:
case ETHTYPE_ARP:
#if PPPOE_SUPPORT
case ETHTYPE_PPPOEDISC:
case ETHTYPE_PPPOE:
#endif /* PPPOE_SUPPORT */
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("k64f_enetif_input: IP input error\n"));
/* Free buffer */
pbuf_free(p);
}
break;
default:
/* Return buffer */
pbuf_free(p);
break;
}
}
/** \brief Packet reception task
*
* This task is called when a packet is received. It will
* pass the packet to the LWIP core.
*
* \param[in] pvParameters pointer to the interface data
*/
static void packet_rx(void* pvParameters) {
struct k64f_enetdata *k64f_enet = pvParameters;
volatile enet_bd_struct_t * bdPtr = (enet_bd_struct_t*)k64f_enet->rx_desc_start_addr;
int idx = 0;
while (1) {
/* Wait for receive task to wakeup */
sys_arch_sem_wait(&k64f_enet->RxReadySem, 0);
if ((bdPtr[idx].control & kEnetRxBdEmpty) == 0) {
k64f_enetif_input(k64f_enet->netif, idx);
idx = (idx + 1) % ENET_RX_RING_LEN;
}
}
}
/** \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] pvParameters pointer to the interface data
*/
static void packet_tx(void* pvParameters) {
struct k64f_enetdata *k64f_enet = pvParameters;
while (1) {
/* Wait for transmit cleanup task to wakeup */
sys_arch_sem_wait(&k64f_enet->TxCleanSem, 0);
// TODOETH: handle TX underrun?
k64f_tx_reclaim(k64f_enet);
}
}
/** \brief Polls if an available TX descriptor is ready. Can be used to
* determine if the low level transmit function will block.
*
* \param[in] netif the lwip network interface structure
* \return 0 if no descriptors are read, or >0
*/
s32_t k64f_tx_ready(struct netif *netif)
{
struct k64f_enetdata *k64f_enet = netif->state;
s32_t fb;
u32_t idx, cidx;
cidx = k64f_enet->tx_consume_index;
idx = k64f_enet->tx_produce_index;
/* Determine number of free buffers */
if (idx == cidx)
fb = ENET_TX_RING_LEN;
else if (cidx > idx)
fb = (ENET_TX_RING_LEN - 1) -
((idx + ENET_TX_RING_LEN) - cidx);
else
fb = (ENET_TX_RING_LEN - 1) - (cidx - idx);
return fb;
}
/*FUNCTION****************************************************************
*
* Function Name: enet_hal_update_txbds
* Description: Update ENET transmit buffer descriptors.
*END*********************************************************************/
void k64f_update_txbds(struct k64f_enetdata *k64f_enet, int idx, uint8_t *buffer, uint16_t length, bool isLast)
{
volatile enet_bd_struct_t * bdPtr = (enet_bd_struct_t *)(k64f_enet->tx_desc_start_addr + idx * enet_hal_get_bd_size());
bdPtr->length = HTONS(length); /* Set data length*/
bdPtr->buffer = (uint8_t *)HTONL((uint32_t)buffer); /* Set data buffer*/
if (isLast)
bdPtr->control |= kEnetTxBdLast;
else
bdPtr->control &= ~kEnetTxBdLast;
bdPtr->controlExtend1 |= kEnetTxBdTxInterrupt;
bdPtr->controlExtend2 &= ~TX_DESC_UPDATED_MASK; // descriptor not updated by DMA
bdPtr->control |= kEnetTxBdTransmitCrc | kEnetTxBdReady;
}
/** \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 netif
* \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 k64f_low_level_output(struct netif *netif, struct pbuf *p)
{
struct k64f_enetdata *k64f_enet = netif->state;
struct pbuf *q;
u32_t idx;
s32_t dn;
uint8_t *psend = NULL, *dst;
/* Get free TX buffer index */
idx = k64f_enet->tx_produce_index;
/* Check the pbuf chain for payloads that are not 8-byte aligned.
If found, a new properly aligned buffer needs to be allocated
and the data copied there */
for (q = p; q != NULL; q = q->next)
if (((u32_t)q->payload & (TX_BUF_ALIGNMENT - 1)) != 0)
break;
if (q != NULL) {
// Allocate properly aligned buffer
psend = (uint8_t*)malloc(p->tot_len);
if (NULL == psend)
return ERR_MEM;
LWIP_ASSERT("k64f_low_level_output: buffer not properly aligned", ((u32_t)psend & (TX_BUF_ALIGNMENT - 1)) == 0);
for (q = p, dst = psend; q != NULL; q = q->next) {
MEMCPY(dst, q->payload, q->len);
dst += q->len;
}
k64f_enet->txb_aligned[idx] = psend;
dn = 1;
} else {
k64f_enet->txb_aligned[idx] = NULL;
dn = (s32_t) pbuf_clen(p);
pbuf_ref(p);
}
/* Wait until enough descriptors are available for the transfer. */
/* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */
while (dn > k64f_tx_ready(netif))
osSemaphoreWait(k64f_enet->xTXDCountSem.id, osWaitForever);
/* Get exclusive access */
sys_mutex_lock(&k64f_enet->TXLockMutex);
/* Setup transfers */
q = p;
while (dn > 0) {
dn--;
if (psend != NULL) {
k64f_update_txbds(k64f_enet, idx, psend, p->tot_len, 1);
k64f_enet->txb[idx] = NULL;
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
("k64f_low_level_output: aligned packet(%p) sent"
" size = %d (index=%d)\n", psend, p->tot_len, idx));
} else {
LWIP_ASSERT("k64f_low_level_output: buffer not properly aligned", ((u32_t)q->payload & 0x07) == 0);
/* Only save pointer to free on last descriptor */
if (dn == 0) {
/* Save size of packet and signal it's ready */
k64f_update_txbds(k64f_enet, idx, q->payload, q->len, 1);
k64f_enet->txb[idx] = p;
}
else {
/* Save size of packet, descriptor is not last */
k64f_update_txbds(k64f_enet, idx, q->payload, q->len, 0);
k64f_enet->txb[idx] = NULL;
}
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
("k64f_low_level_output: pbuf packet(%p) sent, chain#=%d,"
" size = %d (index=%d)\n", q->payload, dn, q->len, idx));
}
q = q->next;
idx = (idx + 1) % ENET_TX_RING_LEN;
}
k64f_enet->tx_produce_index = idx;
enet_hal_active_txbd(BOARD_DEBUG_ENET_INSTANCE_ADDR);
LINK_STATS_INC(link.xmit);
/* Restore access */
sys_mutex_unlock(&k64f_enet->TXLockMutex);
return ERR_OK;
}
/*******************************************************************************
* PHY task: monitor link
*******************************************************************************/
#define PHY_TASK_PERIOD_MS 200
#define STATE_UNKNOWN (-1)
typedef struct {
int connected;
enet_phy_speed_t speed;
enet_phy_duplex_t duplex;
} PHY_STATE;
int phy_link_status() {
bool connection_status;
enet_dev_if_t * enetIfPtr = (enet_dev_if_t*)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
phy_get_link_status(enetIfPtr, &connection_status);
return (int)connection_status;
}
static void k64f_phy_task(void *data) {
struct netif *netif = (struct netif*)data;
bool connection_status;
enet_dev_if_t * enetIfPtr = (enet_dev_if_t*)&enetDevIf[BOARD_DEBUG_ENET_INSTANCE];
PHY_STATE crt_state = {STATE_UNKNOWN, (enet_phy_speed_t)STATE_UNKNOWN, (enet_phy_duplex_t)STATE_UNKNOWN};
PHY_STATE prev_state;
prev_state = crt_state;
while (true) {
// Get current status
phy_get_link_status(enetIfPtr, &connection_status);
crt_state.connected = connection_status ? 1 : 0;
phy_get_link_speed(enetIfPtr, &crt_state.speed);
phy_get_link_duplex(enetIfPtr, &crt_state.duplex);
// Compare with previous state
if (crt_state.connected != prev_state.connected) {
if (crt_state.connected)
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1);
else
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
}
if (crt_state.speed != prev_state.speed)
BW_ENET_RCR_RMII_10T(enetIfPtr->deviceNumber, crt_state.speed == kEnetSpeed10M ? kEnetCfgSpeed10M : kEnetCfgSpeed100M);
// TODO: duplex change requires disable/enable of Ethernet interface, to be implemented
prev_state = crt_state;
osDelay(PHY_TASK_PERIOD_MS);
}
}
/**
* 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 netif
* @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));
k64f_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 = ETHARP_HWADDR_LEN;
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
// TODOETH: check if the flags are correct below
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
/* Initialize the hardware */
netif->state = &k64f_enetdata;
err = low_level_init(netif);
if (err != ERR_OK)
return err;
#if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
netif->hostname = "lwipk64f";
#endif /* LWIP_NETIF_HOSTNAME */
netif->name[0] = 'e';
netif->name[1] = 'n';
netif->output = k64f_etharp_output;
netif->linkoutput = k64f_low_level_output;
/* CMSIS-RTOS, start tasks */
#ifdef CMSIS_OS_RTX
memset(k64f_enetdata.xTXDCountSem.data, 0, sizeof(k64f_enetdata.xTXDCountSem.data));
k64f_enetdata.xTXDCountSem.def.semaphore = k64f_enetdata.xTXDCountSem.data;
#endif
k64f_enetdata.xTXDCountSem.id = osSemaphoreCreate(&k64f_enetdata.xTXDCountSem.def, ENET_TX_RING_LEN);
LWIP_ASSERT("xTXDCountSem creation error", (k64f_enetdata.xTXDCountSem.id != NULL));
err = sys_mutex_new(&k64f_enetdata.TXLockMutex);
LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK));
/* Packet receive task */
err = sys_sem_new(&k64f_enetdata.RxReadySem, 0);
LWIP_ASSERT("RxReadySem creation error", (err == ERR_OK));
sys_thread_new("receive_thread", packet_rx, netif->state, DEFAULT_THREAD_STACKSIZE, RX_PRIORITY);
/* Transmit cleanup task */
err = sys_sem_new(&k64f_enetdata.TxCleanSem, 0);
LWIP_ASSERT("TxCleanSem creation error", (err == ERR_OK));
sys_thread_new("txclean_thread", packet_tx, netif->state, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY);
/* PHY monitoring task */
sys_thread_new("phy_thread", k64f_phy_task, netif, DEFAULT_THREAD_STACKSIZE, PHY_PRIORITY);
/* Allow the PHY task to detect the initial link state and set up the proper flags */
osDelay(10);
return ERR_OK;
}
void eth_arch_enable_interrupts(void) {
enet_hal_config_interrupt(BOARD_DEBUG_ENET_INSTANCE_ADDR, (kEnetTxFrameInterrupt | kEnetRxFrameInterrupt), true);
INT_SYS_EnableIRQ(enet_irq_ids[BOARD_DEBUG_ENET_INSTANCE][enetIntMap[kEnetRxfInt]]);
INT_SYS_EnableIRQ(enet_irq_ids[BOARD_DEBUG_ENET_INSTANCE][enetIntMap[kEnetTxfInt]]);
}
void eth_arch_disable_interrupts(void) {
INT_SYS_DisableIRQ(enet_irq_ids[BOARD_DEBUG_ENET_INSTANCE][enetIntMap[kEnetRxfInt]]);
INT_SYS_DisableIRQ(enet_irq_ids[BOARD_DEBUG_ENET_INSTANCE][enetIntMap[kEnetTxfInt]]);
}
void ENET_Transmit_IRQHandler(void)
{
enet_mac_tx_isr(enetIfHandle);
}
void ENET_Receive_IRQHandler(void)
{
enet_mac_rx_isr(enetIfHandle);
}
#if FSL_FEATURE_ENET_SUPPORT_PTP
void ENET_1588_Timer_IRQHandler(void)
{
enet_mac_ts_isr(enetIfHandle);
}
#endif
/**
* @}
*/
/* --------------------------------- End Of File ------------------------------ */

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc.
* All rights reserved.
*
* 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 Freescale Semiconductor, Inc. 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 K64F_EMAC_CONFIG_H__
#define K64F_EMAC_CONFIG_H__
#define ENET_RX_RING_LEN (16)
#define ENET_TX_RING_LEN (8)
#define ENET_RX_LARGE_BUFFER_NUM (0)
#define ENET_RX_BUFFER_ALIGNMENT (16)
#define ENET_TX_BUFFER_ALIGNMENT (16)
#define ENET_BD_ALIGNMENT (16)
#define ENET_MII_CLOCK (2500000L)
#define RX_BUF_ALIGNMENT (16)
#define TX_BUF_ALIGNMENT (8)
#define BOARD_DEBUG_ENET_INSTANCE (0)
#define BOARD_DEBUG_ENET_INSTANCE_ADDR (ENET_BASE)
#define ENET_ETH_MAX_FLEN (1522) // recommended size for a VLAN frame
#if defined(__cplusplus)
extern "C" {
#endif
int phy_link_status(void);
#if defined(__cplusplus)
}
#endif
#endif // #define K64F_EMAC_CONFIG_H__

View file

@ -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 "k64f_emac_config.h"
#define LWIP_TRANSPORT_ETHERNET 1
#define ETH_PAD_SIZE 2
#define MEM_SIZE (ENET_RX_RING_LEN * (ENET_ETH_MAX_FLEN + RX_BUF_ALIGNMENT) + ENET_TX_RING_LEN * ENET_ETH_MAX_FLEN)
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,661 @@
/**********************************************************************
* $Id$ lpc17xx_emac.h 2010-05-21
*//**
* @file lpc17xx_emac.h
* @brief Contains all macro definitions and function prototypes
* support for Ethernet MAC firmware library on LPC17xx
* @version 2.0
* @date 21. May. 2010
* @author NXP MCU SW Application Team
*
* Copyright(C) 2010, 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.
**********************************************************************/
/* Peripheral group ----------------------------------------------------------- */
/** @defgroup EMAC EMAC (Ethernet Media Access Controller)
* @ingroup LPC1700CMSIS_FwLib_Drivers
* @{
*/
#ifndef LPC17XX_EMAC_H_
#define LPC17XX_EMAC_H_
/* Includes ------------------------------------------------------------------- */
#include "cmsis.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define MCB_LPC_1768
//#define IAR_LPC_1768
/* Public Macros -------------------------------------------------------------- */
/** @defgroup EMAC_Public_Macros EMAC Public Macros
* @{
*/
/* EMAC PHY status type definitions */
#define EMAC_PHY_STAT_LINK (0) /**< Link Status */
#define EMAC_PHY_STAT_SPEED (1) /**< Speed Status */
#define EMAC_PHY_STAT_DUP (2) /**< Duplex Status */
/* EMAC PHY device Speed definitions */
#define EMAC_MODE_AUTO (0) /**< Auto-negotiation mode */
#define EMAC_MODE_10M_FULL (1) /**< 10Mbps FullDuplex mode */
#define EMAC_MODE_10M_HALF (2) /**< 10Mbps HalfDuplex mode */
#define EMAC_MODE_100M_FULL (3) /**< 100Mbps FullDuplex mode */
#define EMAC_MODE_100M_HALF (4) /**< 100Mbps HalfDuplex mode */
/**
* @}
*/
/* Private Macros ------------------------------------------------------------- */
/** @defgroup EMAC_Private_Macros EMAC Private Macros
* @{
*/
/* EMAC Memory Buffer configuration for 16K Ethernet RAM */
#define EMAC_NUM_RX_FRAG 4 /**< Num.of RX Fragments 4*1536= 6.0kB */
#define EMAC_NUM_TX_FRAG 3 /**< Num.of TX Fragments 3*1536= 4.6kB */
#define EMAC_ETH_MAX_FLEN 1536 /**< Max. Ethernet Frame Size */
#define EMAC_TX_FRAME_TOUT 0x00100000 /**< Frame Transmit timeout count */
/* --------------------- BIT DEFINITIONS -------------------------------------- */
/*********************************************************************//**
* Macro defines for MAC Configuration Register 1
**********************************************************************/
#define EMAC_MAC1_REC_EN 0x00000001 /**< Receive Enable */
#define EMAC_MAC1_PASS_ALL 0x00000002 /**< Pass All Receive Frames */
#define EMAC_MAC1_RX_FLOWC 0x00000004 /**< RX Flow Control */
#define EMAC_MAC1_TX_FLOWC 0x00000008 /**< TX Flow Control */
#define EMAC_MAC1_LOOPB 0x00000010 /**< Loop Back Mode */
#define EMAC_MAC1_RES_TX 0x00000100 /**< Reset TX Logic */
#define EMAC_MAC1_RES_MCS_TX 0x00000200 /**< Reset MAC TX Control Sublayer */
#define EMAC_MAC1_RES_RX 0x00000400 /**< Reset RX Logic */
#define EMAC_MAC1_RES_MCS_RX 0x00000800 /**< Reset MAC RX Control Sublayer */
#define EMAC_MAC1_SIM_RES 0x00004000 /**< Simulation Reset */
#define EMAC_MAC1_SOFT_RES 0x00008000 /**< Soft Reset MAC */
/*********************************************************************//**
* Macro defines for MAC Configuration Register 2
**********************************************************************/
#define EMAC_MAC2_FULL_DUP 0x00000001 /**< Full-Duplex Mode */
#define EMAC_MAC2_FRM_LEN_CHK 0x00000002 /**< Frame Length Checking */
#define EMAC_MAC2_HUGE_FRM_EN 0x00000004 /**< Huge Frame Enable */
#define EMAC_MAC2_DLY_CRC 0x00000008 /**< Delayed CRC Mode */
#define EMAC_MAC2_CRC_EN 0x00000010 /**< Append CRC to every Frame */
#define EMAC_MAC2_PAD_EN 0x00000020 /**< Pad all Short Frames */
#define EMAC_MAC2_VLAN_PAD_EN 0x00000040 /**< VLAN Pad Enable */
#define EMAC_MAC2_ADET_PAD_EN 0x00000080 /**< Auto Detect Pad Enable */
#define EMAC_MAC2_PPREAM_ENF 0x00000100 /**< Pure Preamble Enforcement */
#define EMAC_MAC2_LPREAM_ENF 0x00000200 /**< Long Preamble Enforcement */
#define EMAC_MAC2_NO_BACKOFF 0x00001000 /**< No Backoff Algorithm */
#define EMAC_MAC2_BACK_PRESSURE 0x00002000 /**< Backoff Presurre / No Backoff */
#define EMAC_MAC2_EXCESS_DEF 0x00004000 /**< Excess Defer */
/*********************************************************************//**
* Macro defines for Back-to-Back Inter-Packet-Gap Register
**********************************************************************/
/** Programmable field representing the nibble time offset of the minimum possible period
* between the end of any transmitted packet to the beginning of the next */
#define EMAC_IPGT_BBIPG(n) (n&0x7F)
/** Recommended value for Full Duplex of Programmable field representing the nibble time
* offset of the minimum possible period between the end of any transmitted packet to the
* beginning of the next */
#define EMAC_IPGT_FULL_DUP (EMAC_IPGT_BBIPG(0x15))
/** Recommended value for Half Duplex of Programmable field representing the nibble time
* offset of the minimum possible period between the end of any transmitted packet to the
* beginning of the next */
#define EMAC_IPGT_HALF_DUP (EMAC_IPGT_BBIPG(0x12))
/*********************************************************************//**
* Macro defines for Non Back-to-Back Inter-Packet-Gap Register
**********************************************************************/
/** Programmable field representing the Non-Back-to-Back Inter-Packet-Gap */
#define EMAC_IPGR_NBBIPG_P2(n) (n&0x7F)
/** Recommended value for Programmable field representing the Non-Back-to-Back Inter-Packet-Gap Part 1 */
#define EMAC_IPGR_P2_DEF (EMAC_IPGR_NBBIPG_P2(0x12))
/** Programmable field representing the optional carrierSense window referenced in
* IEEE 802.3/4.2.3.2.1 'Carrier Deference' */
#define EMAC_IPGR_NBBIPG_P1(n) ((n&0x7F)<<8)
/** Recommended value for Programmable field representing the Non-Back-to-Back Inter-Packet-Gap Part 2 */
#define EMAC_IPGR_P1_DEF EMAC_IPGR_NBBIPG_P1(0x0C)
/*********************************************************************//**
* Macro defines for Collision Window/Retry Register
**********************************************************************/
/** Programmable field specifying the number of retransmission attempts following a collision before
* aborting the packet due to excessive collisions */
#define EMAC_CLRT_MAX_RETX(n) (n&0x0F)
/** Programmable field representing the slot time or collision window during which collisions occur
* in properly configured networks */
#define EMAC_CLRT_COLL(n) ((n&0x3F)<<8)
/** Default value for Collision Window / Retry register */
#define EMAC_CLRT_DEF ((EMAC_CLRT_MAX_RETX(0x0F))|(EMAC_CLRT_COLL(0x37)))
/*********************************************************************//**
* Macro defines for Maximum Frame Register
**********************************************************************/
/** Represents a maximum receive frame of 1536 octets */
#define EMAC_MAXF_MAXFRMLEN(n) (n&0xFFFF)
/*********************************************************************//**
* Macro defines for PHY Support Register
**********************************************************************/
#define EMAC_SUPP_SPEED 0x00000100 /**< Reduced MII Logic Current Speed */
#define EMAC_SUPP_RES_RMII 0x00000800 /**< Reset Reduced MII Logic */
/*********************************************************************//**
* Macro defines for Test Register
**********************************************************************/
#define EMAC_TEST_SHCUT_PQUANTA 0x00000001 /**< Shortcut Pause Quanta */
#define EMAC_TEST_TST_PAUSE 0x00000002 /**< Test Pause */
#define EMAC_TEST_TST_BACKP 0x00000004 /**< Test Back Pressure */
/*********************************************************************//**
* Macro defines for MII Management Configuration Register
**********************************************************************/
#define EMAC_MCFG_SCAN_INC 0x00000001 /**< Scan Increment PHY Address */
#define EMAC_MCFG_SUPP_PREAM 0x00000002 /**< Suppress Preamble */
#define EMAC_MCFG_CLK_SEL(n) ((n&0x0F)<<2) /**< Clock Select Field */
#define EMAC_MCFG_RES_MII 0x00008000 /**< Reset MII Management Hardware */
#define EMAC_MCFG_MII_MAXCLK 2500000UL /**< MII Clock max */
/*********************************************************************//**
* Macro defines for MII Management Command Register
**********************************************************************/
#define EMAC_MCMD_READ 0x00000001 /**< MII Read */
#define EMAC_MCMD_SCAN 0x00000002 /**< MII Scan continuously */
#define EMAC_MII_WR_TOUT 0x00050000 /**< MII Write timeout count */
#define EMAC_MII_RD_TOUT 0x00050000 /**< MII Read timeout count */
/*********************************************************************//**
* Macro defines for MII Management Address Register
**********************************************************************/
#define EMAC_MADR_REG_ADR(n) (n&0x1F) /**< MII Register Address field */
#define EMAC_MADR_PHY_ADR(n) ((n&0x1F)<<8) /**< PHY Address Field */
/*********************************************************************//**
* Macro defines for MII Management Write Data Register
**********************************************************************/
#define EMAC_MWTD_DATA(n) (n&0xFFFF) /**< Data field for MMI Management Write Data register */
/*********************************************************************//**
* Macro defines for MII Management Read Data Register
**********************************************************************/
#define EMAC_MRDD_DATA(n) (n&0xFFFF) /**< Data field for MMI Management Read Data register */
/*********************************************************************//**
* Macro defines for MII Management Indicators Register
**********************************************************************/
#define EMAC_MIND_BUSY 0x00000001 /**< MII is Busy */
#define EMAC_MIND_SCAN 0x00000002 /**< MII Scanning in Progress */
#define EMAC_MIND_NOT_VAL 0x00000004 /**< MII Read Data not valid */
#define EMAC_MIND_MII_LINK_FAIL 0x00000008 /**< MII Link Failed */
/* Station Address 0 Register */
/* Station Address 1 Register */
/* Station Address 2 Register */
/* Control register definitions --------------------------------------------------------------------------- */
/*********************************************************************//**
* Macro defines for Command Register
**********************************************************************/
#define EMAC_CR_RX_EN 0x00000001 /**< Enable Receive */
#define EMAC_CR_TX_EN 0x00000002 /**< Enable Transmit */
#define EMAC_CR_REG_RES 0x00000008 /**< Reset Host Registers */
#define EMAC_CR_TX_RES 0x00000010 /**< Reset Transmit Datapath */
#define EMAC_CR_RX_RES 0x00000020 /**< Reset Receive Datapath */
#define EMAC_CR_PASS_RUNT_FRM 0x00000040 /**< Pass Runt Frames */
#define EMAC_CR_PASS_RX_FILT 0x00000080 /**< Pass RX Filter */
#define EMAC_CR_TX_FLOW_CTRL 0x00000100 /**< TX Flow Control */
#define EMAC_CR_RMII 0x00000200 /**< Reduced MII Interface */
#define EMAC_CR_FULL_DUP 0x00000400 /**< Full Duplex */
/*********************************************************************//**
* Macro defines for Status Register
**********************************************************************/
#define EMAC_SR_RX_EN 0x00000001 /**< Enable Receive */
#define EMAC_SR_TX_EN 0x00000002 /**< Enable Transmit */
/*********************************************************************//**
* Macro defines for Transmit Status Vector 0 Register
**********************************************************************/
#define EMAC_TSV0_CRC_ERR 0x00000001 /**< CRC error */
#define EMAC_TSV0_LEN_CHKERR 0x00000002 /**< Length Check Error */
#define EMAC_TSV0_LEN_OUTRNG 0x00000004 /**< Length Out of Range */
#define EMAC_TSV0_DONE 0x00000008 /**< Tramsmission Completed */
#define EMAC_TSV0_MCAST 0x00000010 /**< Multicast Destination */
#define EMAC_TSV0_BCAST 0x00000020 /**< Broadcast Destination */
#define EMAC_TSV0_PKT_DEFER 0x00000040 /**< Packet Deferred */
#define EMAC_TSV0_EXC_DEFER 0x00000080 /**< Excessive Packet Deferral */
#define EMAC_TSV0_EXC_COLL 0x00000100 /**< Excessive Collision */
#define EMAC_TSV0_LATE_COLL 0x00000200 /**< Late Collision Occured */
#define EMAC_TSV0_GIANT 0x00000400 /**< Giant Frame */
#define EMAC_TSV0_UNDERRUN 0x00000800 /**< Buffer Underrun */
#define EMAC_TSV0_BYTES 0x0FFFF000 /**< Total Bytes Transferred */
#define EMAC_TSV0_CTRL_FRAME 0x10000000 /**< Control Frame */
#define EMAC_TSV0_PAUSE 0x20000000 /**< Pause Frame */
#define EMAC_TSV0_BACK_PRESS 0x40000000 /**< Backpressure Method Applied */
#define EMAC_TSV0_VLAN 0x80000000 /**< VLAN Frame */
/*********************************************************************//**
* Macro defines for Transmit Status Vector 1 Register
**********************************************************************/
#define EMAC_TSV1_BYTE_CNT 0x0000FFFF /**< Transmit Byte Count */
#define EMAC_TSV1_COLL_CNT 0x000F0000 /**< Transmit Collision Count */
/*********************************************************************//**
* Macro defines for Receive Status Vector Register
**********************************************************************/
#define EMAC_RSV_BYTE_CNT 0x0000FFFF /**< Receive Byte Count */
#define EMAC_RSV_PKT_IGNORED 0x00010000 /**< Packet Previously Ignored */
#define EMAC_RSV_RXDV_SEEN 0x00020000 /**< RXDV Event Previously Seen */
#define EMAC_RSV_CARR_SEEN 0x00040000 /**< Carrier Event Previously Seen */
#define EMAC_RSV_REC_CODEV 0x00080000 /**< Receive Code Violation */
#define EMAC_RSV_CRC_ERR 0x00100000 /**< CRC Error */
#define EMAC_RSV_LEN_CHKERR 0x00200000 /**< Length Check Error */
#define EMAC_RSV_LEN_OUTRNG 0x00400000 /**< Length Out of Range */
#define EMAC_RSV_REC_OK 0x00800000 /**< Frame Received OK */
#define EMAC_RSV_MCAST 0x01000000 /**< Multicast Frame */
#define EMAC_RSV_BCAST 0x02000000 /**< Broadcast Frame */
#define EMAC_RSV_DRIB_NIBB 0x04000000 /**< Dribble Nibble */
#define EMAC_RSV_CTRL_FRAME 0x08000000 /**< Control Frame */
#define EMAC_RSV_PAUSE 0x10000000 /**< Pause Frame */
#define EMAC_RSV_UNSUPP_OPC 0x20000000 /**< Unsupported Opcode */
#define EMAC_RSV_VLAN 0x40000000 /**< VLAN Frame */
/*********************************************************************//**
* Macro defines for Flow Control Counter Register
**********************************************************************/
#define EMAC_FCC_MIRR_CNT(n) (n&0xFFFF) /**< Mirror Counter */
#define EMAC_FCC_PAUSE_TIM(n) ((n&0xFFFF)<<16) /**< Pause Timer */
/*********************************************************************//**
* Macro defines for Flow Control Status Register
**********************************************************************/
#define EMAC_FCS_MIRR_CNT(n) (n&0xFFFF) /**< Mirror Counter Current */
/* Receive filter register definitions -------------------------------------------------------- */
/*********************************************************************//**
* Macro defines for Receive Filter Control Register
**********************************************************************/
#define EMAC_RFC_UCAST_EN 0x00000001 /**< Accept Unicast Frames Enable */
#define EMAC_RFC_BCAST_EN 0x00000002 /**< Accept Broadcast Frames Enable */
#define EMAC_RFC_MCAST_EN 0x00000004 /**< Accept Multicast Frames Enable */
#define EMAC_RFC_UCAST_HASH_EN 0x00000008 /**< Accept Unicast Hash Filter Frames */
#define EMAC_RFC_MCAST_HASH_EN 0x00000010 /**< Accept Multicast Hash Filter Fram.*/
#define EMAC_RFC_PERFECT_EN 0x00000020 /**< Accept Perfect Match Enable */
#define EMAC_RFC_MAGP_WOL_EN 0x00001000 /**< Magic Packet Filter WoL Enable */
#define EMAC_RFC_PFILT_WOL_EN 0x00002000 /**< Perfect Filter WoL Enable */
/*********************************************************************//**
* Macro defines for Receive Filter WoL Status/Clear Registers
**********************************************************************/
#define EMAC_WOL_UCAST 0x00000001 /**< Unicast Frame caused WoL */
#define EMAC_WOL_BCAST 0x00000002 /**< Broadcast Frame caused WoL */
#define EMAC_WOL_MCAST 0x00000004 /**< Multicast Frame caused WoL */
#define EMAC_WOL_UCAST_HASH 0x00000008 /**< Unicast Hash Filter Frame WoL */
#define EMAC_WOL_MCAST_HASH 0x00000010 /**< Multicast Hash Filter Frame WoL */
#define EMAC_WOL_PERFECT 0x00000020 /**< Perfect Filter WoL */
#define EMAC_WOL_RX_FILTER 0x00000080 /**< RX Filter caused WoL */
#define EMAC_WOL_MAG_PACKET 0x00000100 /**< Magic Packet Filter caused WoL */
#define EMAC_WOL_BITMASK 0x01BF /**< Receive Filter WoL Status/Clear bitmasl value */
/* Module control register definitions ---------------------------------------------------- */
/*********************************************************************//**
* Macro defines for Interrupt Status/Enable/Clear/Set Registers
**********************************************************************/
#define EMAC_INT_RX_OVERRUN 0x00000001 /**< Overrun Error in RX Queue */
#define EMAC_INT_RX_ERR 0x00000002 /**< Receive Error */
#define EMAC_INT_RX_FIN 0x00000004 /**< RX Finished Process Descriptors */
#define EMAC_INT_RX_DONE 0x00000008 /**< Receive Done */
#define EMAC_INT_TX_UNDERRUN 0x00000010 /**< Transmit Underrun */
#define EMAC_INT_TX_ERR 0x00000020 /**< Transmit Error */
#define EMAC_INT_TX_FIN 0x00000040 /**< TX Finished Process Descriptors */
#define EMAC_INT_TX_DONE 0x00000080 /**< Transmit Done */
#define EMAC_INT_SOFT_INT 0x00001000 /**< Software Triggered Interrupt */
#define EMAC_INT_WAKEUP 0x00002000 /**< Wakeup Event Interrupt */
/*********************************************************************//**
* Macro defines for Power Down Register
**********************************************************************/
#define EMAC_PD_POWER_DOWN 0x80000000 /**< Power Down MAC */
/* Descriptor and status formats ---------------------------------------------------- */
/*********************************************************************//**
* Macro defines for RX Descriptor Control Word
**********************************************************************/
#define EMAC_RCTRL_SIZE(n) (n&0x7FF) /**< Buffer size field */
#define EMAC_RCTRL_INT 0x80000000 /**< Generate RxDone Interrupt */
/*********************************************************************//**
* Macro defines for RX Status Hash CRC Word
**********************************************************************/
#define EMAC_RHASH_SA 0x000001FF /**< Hash CRC for Source Address */
#define EMAC_RHASH_DA 0x001FF000 /**< Hash CRC for Destination Address */
/*********************************************************************//**
* Macro defines for RX Status Information Word
**********************************************************************/
#define EMAC_RINFO_SIZE 0x000007FF /**< Data size in bytes */
#define EMAC_RINFO_CTRL_FRAME 0x00040000 /**< Control Frame */
#define EMAC_RINFO_VLAN 0x00080000 /**< VLAN Frame */
#define EMAC_RINFO_FAIL_FILT 0x00100000 /**< RX Filter Failed */
#define EMAC_RINFO_MCAST 0x00200000 /**< Multicast Frame */
#define EMAC_RINFO_BCAST 0x00400000 /**< Broadcast Frame */
#define EMAC_RINFO_CRC_ERR 0x00800000 /**< CRC Error in Frame */
#define EMAC_RINFO_SYM_ERR 0x01000000 /**< Symbol Error from PHY */
#define EMAC_RINFO_LEN_ERR 0x02000000 /**< Length Error */
#define EMAC_RINFO_RANGE_ERR 0x04000000 /**< Range Error (exceeded max. size) */
#define EMAC_RINFO_ALIGN_ERR 0x08000000 /**< Alignment Error */
#define EMAC_RINFO_OVERRUN 0x10000000 /**< Receive overrun */
#define EMAC_RINFO_NO_DESCR 0x20000000 /**< No new Descriptor available */
#define EMAC_RINFO_LAST_FLAG 0x40000000 /**< Last Fragment in Frame */
#define EMAC_RINFO_ERR 0x80000000 /**< Error Occured (OR of all errors) */
#define EMAC_RINFO_ERR_MASK (EMAC_RINFO_FAIL_FILT | EMAC_RINFO_CRC_ERR | EMAC_RINFO_SYM_ERR | \
EMAC_RINFO_LEN_ERR | EMAC_RINFO_ALIGN_ERR | EMAC_RINFO_OVERRUN)
/*********************************************************************//**
* Macro defines for TX Descriptor Control Word
**********************************************************************/
#define EMAC_TCTRL_SIZE 0x000007FF /**< Size of data buffer in bytes */
#define EMAC_TCTRL_OVERRIDE 0x04000000 /**< Override Default MAC Registers */
#define EMAC_TCTRL_HUGE 0x08000000 /**< Enable Huge Frame */
#define EMAC_TCTRL_PAD 0x10000000 /**< Pad short Frames to 64 bytes */
#define EMAC_TCTRL_CRC 0x20000000 /**< Append a hardware CRC to Frame */
#define EMAC_TCTRL_LAST 0x40000000 /**< Last Descriptor for TX Frame */
#define EMAC_TCTRL_INT 0x80000000 /**< Generate TxDone Interrupt */
/*********************************************************************//**
* Macro defines for TX Status Information Word
**********************************************************************/
#define EMAC_TINFO_COL_CNT 0x01E00000 /**< Collision Count */
#define EMAC_TINFO_DEFER 0x02000000 /**< Packet Deferred (not an error) */
#define EMAC_TINFO_EXCESS_DEF 0x04000000 /**< Excessive Deferral */
#define EMAC_TINFO_EXCESS_COL 0x08000000 /**< Excessive Collision */
#define EMAC_TINFO_LATE_COL 0x10000000 /**< Late Collision Occured */
#define EMAC_TINFO_UNDERRUN 0x20000000 /**< Transmit Underrun */
#define EMAC_TINFO_NO_DESCR 0x40000000 /**< No new Descriptor available */
#define EMAC_TINFO_ERR 0x80000000 /**< Error Occured (OR of all errors) */
#ifdef MCB_LPC_1768
/* DP83848C PHY definition ------------------------------------------------------------ */
/** PHY device reset time out definition */
#define EMAC_PHY_RESP_TOUT 0x100000UL
/* ENET Device Revision ID */
#define EMAC_OLD_EMAC_MODULE_ID 0x39022000 /**< Rev. ID for first rev '-' */
/*********************************************************************//**
* Macro defines for DP83848C PHY Registers
**********************************************************************/
#define EMAC_PHY_REG_BMCR 0x00 /**< Basic Mode Control Register */
#define EMAC_PHY_REG_BMSR 0x01 /**< Basic Mode Status Register */
#define EMAC_PHY_REG_IDR1 0x02 /**< PHY Identifier 1 */
#define EMAC_PHY_REG_IDR2 0x03 /**< PHY Identifier 2 */
#define EMAC_PHY_REG_ANAR 0x04 /**< Auto-Negotiation Advertisement */
#define EMAC_PHY_REG_ANLPAR 0x05 /**< Auto-Neg. Link Partner Abitily */
#define EMAC_PHY_REG_ANER 0x06 /**< Auto-Neg. Expansion Register */
#define EMAC_PHY_REG_ANNPTR 0x07 /**< Auto-Neg. Next Page TX */
#define EMAC_PHY_REG_LPNPA 0x08
/*********************************************************************//**
* Macro defines for PHY Extended Registers
**********************************************************************/
#define EMAC_PHY_REG_STS 0x10 /**< Status Register */
#define EMAC_PHY_REG_MICR 0x11 /**< MII Interrupt Control Register */
#define EMAC_PHY_REG_MISR 0x12 /**< MII Interrupt Status Register */
#define EMAC_PHY_REG_FCSCR 0x14 /**< False Carrier Sense Counter */
#define EMAC_PHY_REG_RECR 0x15 /**< Receive Error Counter */
#define EMAC_PHY_REG_PCSR 0x16 /**< PCS Sublayer Config. and Status */
#define EMAC_PHY_REG_RBR 0x17 /**< RMII and Bypass Register */
#define EMAC_PHY_REG_LEDCR 0x18 /**< LED Direct Control Register */
#define EMAC_PHY_REG_PHYCR 0x19 /**< PHY Control Register */
#define EMAC_PHY_REG_10BTSCR 0x1A /**< 10Base-T Status/Control Register */
#define EMAC_PHY_REG_CDCTRL1 0x1B /**< CD Test Control and BIST Extens. */
#define EMAC_PHY_REG_EDCR 0x1D /**< Energy Detect Control Register */
/*********************************************************************//**
* Macro defines for PHY Basic Mode Control Register
**********************************************************************/
#define EMAC_PHY_BMCR_RESET (1<<15) /**< Reset bit */
#define EMAC_PHY_BMCR_LOOPBACK (1<<14) /**< Loop back */
#define EMAC_PHY_BMCR_SPEED_SEL (1<<13) /**< Speed selection */
#define EMAC_PHY_BMCR_AN (1<<12) /**< Auto Negotiation */
#define EMAC_PHY_BMCR_POWERDOWN (1<<11) /**< Power down mode */
#define EMAC_PHY_BMCR_ISOLATE (1<<10) /**< Isolate */
#define EMAC_PHY_BMCR_RE_AN (1<<9) /**< Restart auto negotiation */
#define EMAC_PHY_BMCR_DUPLEX (1<<8) /**< Duplex mode */
/*********************************************************************//**
* Macro defines for PHY Basic Mode Status Status Register
**********************************************************************/
#define EMAC_PHY_BMSR_100BE_T4 (1<<15) /**< 100 base T4 */
#define EMAC_PHY_BMSR_100TX_FULL (1<<14) /**< 100 base full duplex */
#define EMAC_PHY_BMSR_100TX_HALF (1<<13) /**< 100 base half duplex */
#define EMAC_PHY_BMSR_10BE_FULL (1<<12) /**< 10 base T full duplex */
#define EMAC_PHY_BMSR_10BE_HALF (1<<11) /**< 10 base T half duplex */
#define EMAC_PHY_BMSR_NOPREAM (1<<6) /**< MF Preamable Supress */
#define EMAC_PHY_BMSR_AUTO_DONE (1<<5) /**< Auto negotiation complete */
#define EMAC_PHY_BMSR_REMOTE_FAULT (1<<4) /**< Remote fault */
#define EMAC_PHY_BMSR_NO_AUTO (1<<3) /**< Auto Negotiation ability */
#define EMAC_PHY_BMSR_LINK_ESTABLISHED (1<<2) /**< Link status */
/*********************************************************************//**
* Macro defines for PHY Status Register
**********************************************************************/
#define EMAC_PHY_SR_REMOTE_FAULT (1<<6) /**< Remote Fault */
#define EMAC_PHY_SR_JABBER (1<<5) /**< Jabber detect */
#define EMAC_PHY_SR_AUTO_DONE (1<<4) /**< Auto Negotiation complete */
#define EMAC_PHY_SR_LOOPBACK (1<<3) /**< Loop back status */
#define EMAC_PHY_SR_DUP (1<<2) /**< Duplex status */
#define EMAC_PHY_SR_SPEED (1<<1) /**< Speed status */
#define EMAC_PHY_SR_LINK (1<<0) /**< Link Status */
#define EMAC_PHY_FULLD_100M 0x2100 /**< Full Duplex 100Mbit */
#define EMAC_PHY_HALFD_100M 0x2000 /**< Half Duplex 100Mbit */
#define EMAC_PHY_FULLD_10M 0x0100 /**< Full Duplex 10Mbit */
#define EMAC_PHY_HALFD_10M 0x0000 /**< Half Duplex 10MBit */
#define EMAC_PHY_AUTO_NEG 0x3000 /**< Select Auto Negotiation */
#define EMAC_DEF_ADR 0x0100 /**< Default PHY device address */
#define EMAC_DP83848C_ID 0x20005C90 /**< PHY Identifier */
#define EMAC_PHY_SR_100_SPEED ((1<<14)|(1<<13))
#define EMAC_PHY_SR_FULL_DUP ((1<<14)|(1<<12))
#define EMAC_PHY_BMSR_LINK_STATUS (1<<2) /**< Link status */
#elif defined(IAR_LPC_1768)
/* KSZ8721BL PHY definition ------------------------------------------------------------ */
/** PHY device reset time out definition */
#define EMAC_PHY_RESP_TOUT 0x100000UL
/* ENET Device Revision ID */
#define EMAC_OLD_EMAC_MODULE_ID 0x39022000 /**< Rev. ID for first rev '-' */
/*********************************************************************//**
* Macro defines for KSZ8721BL PHY Registers
**********************************************************************/
#define EMAC_PHY_REG_BMCR 0x00 /**< Basic Mode Control Register */
#define EMAC_PHY_REG_BMSR 0x01 /**< Basic Mode Status Register */
#define EMAC_PHY_REG_IDR1 0x02 /**< PHY Identifier 1 */
#define EMAC_PHY_REG_IDR2 0x03 /**< PHY Identifier 2 */
#define EMAC_PHY_REG_ANAR 0x04 /**< Auto-Negotiation Advertisement */
#define EMAC_PHY_REG_ANLPAR 0x05 /**< Auto-Neg. Link Partner Abitily */
#define EMAC_PHY_REG_ANER 0x06 /**< Auto-Neg. Expansion Register */
#define EMAC_PHY_REG_ANNPTR 0x07 /**< Auto-Neg. Next Page TX */
#define EMAC_PHY_REG_LPNPA 0x08 /**< Link Partner Next Page Ability */
#define EMAC_PHY_REG_REC 0x15 /**< RXError Counter Register */
#define EMAC_PHY_REG_ISC 0x1b /**< Interrupt Control/Status Register */
#define EMAC_PHY_REG_100BASE 0x1f /**< 100BASE-TX PHY Control Register */
/*********************************************************************//**
* Macro defines for PHY Basic Mode Control Register
**********************************************************************/
#define EMAC_PHY_BMCR_RESET (1<<15) /**< Reset bit */
#define EMAC_PHY_BMCR_LOOPBACK (1<<14) /**< Loop back */
#define EMAC_PHY_BMCR_SPEED_SEL (1<<13) /**< Speed selection */
#define EMAC_PHY_BMCR_AN (1<<12) /**< Auto Negotiation */
#define EMAC_PHY_BMCR_POWERDOWN (1<<11) /**< Power down mode */
#define EMAC_PHY_BMCR_ISOLATE (1<<10) /**< Isolate */
#define EMAC_PHY_BMCR_RE_AN (1<<9) /**< Restart auto negotiation */
#define EMAC_PHY_BMCR_DUPLEX (1<<8) /**< Duplex mode */
#define EMAC_PHY_BMCR_COLLISION (1<<7) /**< Collision test */
#define EMAC_PHY_BMCR_TXDIS (1<<0) /**< Disable transmit */
/*********************************************************************//**
* Macro defines for PHY Basic Mode Status Register
**********************************************************************/
#define EMAC_PHY_BMSR_100BE_T4 (1<<15) /**< 100 base T4 */
#define EMAC_PHY_BMSR_100TX_FULL (1<<14) /**< 100 base full duplex */
#define EMAC_PHY_BMSR_100TX_HALF (1<<13) /**< 100 base half duplex */
#define EMAC_PHY_BMSR_10BE_FULL (1<<12) /**< 10 base T full duplex */
#define EMAC_PHY_BMSR_10BE_HALF (1<<11) /**< 10 base T half duplex */
#define EMAC_PHY_BMSR_NOPREAM (1<<6) /**< MF Preamable Supress */
#define EMAC_PHY_BMSR_AUTO_DONE (1<<5) /**< Auto negotiation complete */
#define EMAC_PHY_BMSR_REMOTE_FAULT (1<<4) /**< Remote fault */
#define EMAC_PHY_BMSR_NO_AUTO (1<<3) /**< Auto Negotiation ability */
#define EMAC_PHY_BMSR_LINK_STATUS (1<<2) /**< Link status */
#define EMAC_PHY_BMSR_JABBER_DETECT (1<<1) /**< Jabber detect */
#define EMAC_PHY_BMSR_EXTEND (1<<0) /**< Extended support */
/*********************************************************************//**
* Macro defines for PHY Identifier
**********************************************************************/
/* PHY Identifier 1 bitmap definitions */
#define EMAC_PHY_IDR1(n) (n & 0xFFFF) /**< PHY ID1 Number */
/* PHY Identifier 2 bitmap definitions */
#define EMAC_PHY_IDR2(n) (n & 0xFFFF) /**< PHY ID2 Number */
/*********************************************************************//**
* Macro defines for Auto-Negotiation Advertisement
**********************************************************************/
#define EMAC_PHY_AN_NEXTPAGE (1<<15) /**< Next page capable */
#define EMAC_PHY_AN_REMOTE_FAULT (1<<13) /**< Remote Fault support */
#define EMAC_PHY_AN_PAUSE (1<<10) /**< Pause support */
#define EMAC_PHY_AN_100BASE_T4 (1<<9) /**< T4 capable */
#define EMAC_PHY_AN_100BASE_TX_FD (1<<8) /**< TX with Full-duplex capable */
#define EMAC_PHY_AN_100BASE_TX (1<<7) /**< TX capable */
#define EMAC_PHY_AN_10BASE_T_FD (1<<6) /**< 10Mbps with full-duplex capable */
#define EMAC_PHY_AN_10BASE_T (1<<5) /**< 10Mbps capable */
#define EMAC_PHY_AN_FIELD(n) (n & 0x1F) /**< Selector Field */
#define EMAC_PHY_FULLD_100M 0x2100 /**< Full Duplex 100Mbit */
#define EMAC_PHY_HALFD_100M 0x2000 /**< Half Duplex 100Mbit */
#define EMAC_PHY_FULLD_10M 0x0100 /**< Full Duplex 10Mbit */
#define EMAC_PHY_HALFD_10M 0x0000 /**< Half Duplex 10MBit */
#define EMAC_PHY_AUTO_NEG 0x3000 /**< Select Auto Negotiation */
#define EMAC_PHY_SR_100_SPEED ((1<<14)|(1<<13))
#define EMAC_PHY_SR_FULL_DUP ((1<<14)|(1<<12))
#define EMAC_DEF_ADR (0x01<<8) /**< Default PHY device address */
#define EMAC_KSZ8721BL_ID ((0x22 << 16) | 0x1619 ) /**< PHY Identifier */
#endif
/**
* @}
*/
/* Public Types --------------------------------------------------------------- */
/** @defgroup EMAC_Public_Types EMAC Public Types
* @{
*/
/* Descriptor and status formats ---------------------------------------------- */
/**
* @brief RX Descriptor structure type definition
*/
typedef struct {
uint32_t Packet; /**< Receive Packet Descriptor */
uint32_t Ctrl; /**< Receive Control Descriptor */
} RX_Desc;
/**
* @brief RX Status structure type definition
*/
typedef struct {
uint32_t Info; /**< Receive Information Status */
uint32_t HashCRC; /**< Receive Hash CRC Status */
} RX_Stat;
/**
* @brief TX Descriptor structure type definition
*/
typedef struct {
uint32_t Packet; /**< Transmit Packet Descriptor */
uint32_t Ctrl; /**< Transmit Control Descriptor */
} TX_Desc;
/**
* @brief TX Status structure type definition
*/
typedef struct {
uint32_t Info; /**< Transmit Information Status */
} TX_Stat;
/**
* @brief TX Data Buffer structure definition
*/
typedef struct {
uint32_t ulDataLen; /**< Data length */
uint32_t *pbDataBuf; /**< A word-align data pointer to data buffer */
} EMAC_PACKETBUF_Type;
/**
* @brief EMAC configuration structure definition
*/
typedef struct {
uint32_t Mode; /**< Supported EMAC PHY device speed, should be one of the following:
- EMAC_MODE_AUTO
- EMAC_MODE_10M_FULL
- EMAC_MODE_10M_HALF
- EMAC_MODE_100M_FULL
- EMAC_MODE_100M_HALF
*/
uint8_t *pbEMAC_Addr; /**< Pointer to EMAC Station address that contains 6-bytes
of MAC address, it must be sorted in order (bEMAC_Addr[0]..[5])
*/
} EMAC_CFG_Type;
/** Ethernet block power/clock control bit*/
#define CLKPWR_PCONP_PCENET ((uint32_t)(1<<30))
#ifdef __cplusplus
}
#endif
#endif /* LPC17XX_EMAC_H_ */
/**
* @}
*/
/* --------------------------------- End Of File ------------------------------ */

View file

@ -0,0 +1,111 @@
/**********************************************************************
* $Id$ lpc_emac_config.h 2011-11-20
*//**
* @file lpc_emac_config.h
* @brief PHY and EMAC configuration file
* @version 1.0
* @date 20 Nov. 2011
* @author NXP MCU SW Application Team
*
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
**********************************************************************/
#ifndef __LPC_EMAC_CONFIG_H
#define __LPC_EMAC_CONFIG_H
#include "lwip/opt.h"
#ifdef __cplusplus
extern "C"
{
#endif
/** @defgroup lwip_phy_config LWIP PHY configuration
* @ingroup lwip_phy
*
* Configuration options for the PHY connected to the LPC EMAC.
* @{
*/
/** \brief The PHY address connected the to MII/RMII
*/
#define LPC_PHYDEF_PHYADDR 1 /**< The PHY address on the PHY device. */
/** \brief Enable autonegotiation mode.
* If this is enabled, the PHY will attempt to auto-negotiate the
* best link mode if the PHY supports it. If this is not enabled,
* the PHY_USE_FULL_DUPLEX and PHY_USE_100MBS defines will be
* used to select the link mode. Note that auto-negotiation may
* take a few seconds to complete.
*/
#define PHY_USE_AUTONEG 1 /**< Enables auto-negotiation mode. */
/** \brief Sets up the PHY interface to either full duplex operation or
* half duplex operation if PHY_USE_AUTONEG is not enabled.
*/
#define PHY_USE_FULL_DUPLEX 1 /**< Sets duplex mode to full. */
/** \brief Sets up the PHY interface to either 100MBS operation or 10MBS
* operation if PHY_USE_AUTONEG is not enabled.
*/
#define PHY_USE_100MBS 1 /**< Sets data rate to 100Mbps. */
/**
* @}
*/
/** @defgroup lwip_emac_config LWIP EMAC configuration
* @ingroup lwip_emac
*
* Configuration options for the LPC EMAC.
* @{
*/
/** \brief Selects RMII or MII connection type in the EMAC peripheral
*/
#define LPC_EMAC_RMII 1 /**< Use the RMII or MII driver variant .*/
/** \brief Defines the number of descriptors used for RX. This
* must be a minimum value of 2.
*/
#define LPC_NUM_BUFF_RXDESCS 3
/** \brief Defines the number of descriptors used for TX. Must
* be a minimum value of 2.
*/
#define LPC_NUM_BUFF_TXDESCS (TCP_SND_QUEUELEN + 1)
/** \brief Set this define to 1 to enable bounce buffers for transmit pbufs
* that cannot be sent via the zero-copy method. Some chained pbufs
* may have a payload address that links to an area of memory that
* cannot be used for transmit DMA operations. If this define is
* set to 1, an extra check will be made with the pbufs. If a buffer
* is determined to be non-usable for zero-copy, a temporary bounce
* buffer will be created and used instead.
*/
#define LPC_TX_PBUF_BOUNCE_EN 1
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __LPC_EMAC_CONFIG_H */
/* --------------------------------- End Of File ------------------------------ */

View file

@ -0,0 +1,151 @@
/**********************************************************************
* $Id$ lpc_phy.h 2011-11-20
*//**
* @file lpc_phy.h
* @brief Common PHY definitions used with all PHYs
* @version 1.0
* @date 20 Nov. 2011
* @author NXP MCU SW Application Team
*
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
**********************************************************************/
#ifndef __LPC_PHY_H_
#define __LPC_PHY_H_
#include "lwip/opt.h"
#include "lwip/err.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C"
{
#endif
/* These PHY functions are usually part of the EMAC driver */
/** \brief Phy status update state machine
*
* This function provides a state machine for maintaining the PHY
* status without blocking. It must be occasionally called for the
* PHY status to be maintained.
*
* \param[in] netif NETIF structure
*/
s32_t lpc_phy_sts_sm(struct netif *netif);
/** \brief Initialize the PHY
*
* This function initializes the PHY. It will block until complete.
* This function is called as part of the EMAC driver
* initialization. Configuration of the PHY at startup is
* controlled by setting up configuration defines in lpc_phy.h.
*
* \param[in] netif NETIF structure
* \param[in] rmii If set, configures the PHY for RMII mode
* \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT
*/
err_t lpc_phy_init(struct netif *netif, int rmii);
/** \brief Write a value via the MII link (non-blocking)
*
* This function will write a value on the MII link interface to a PHY
* or a connected device. The function will return immediately without
* a status. Status needs to be polled later to determine if the write
* was successful.
*
* \param[in] PhyReg PHY register to write to
* \param[in] Value Value to write
*/
void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value);
/** \brief Write a value via the MII link (blocking)
*
* This function will write a value on the MII link interface to a PHY
* or a connected device. The function will block until complete.
*
* \param[in] PhyReg PHY register to write to
* \param[in] Value Value to write
* \returns 0 if the write was successful, otherwise !0
*/
err_t lpc_mii_write(u32_t PhyReg, u32_t Value);
/** \brief Reads current MII link busy status
*
* This function will return the current MII link busy status and is meant to
* be used with non-blocking functions for monitor PHY status such as
* connection state.
*
* \returns !0 if the MII link is busy, otherwise 0
*/
u32_t lpc_mii_is_busy(void);
/** \brief Starts a read operation via the MII link (non-blocking)
*
* This function returns the current value in the MII data register. It is
* meant to be used with the non-blocking oeprations. This value should
* only be read after a non-block read command has been issued and the
* MII status has been determined to be good.
*
* \returns The current value in the MII value register
*/
u32_t lpc_mii_read_data(void);
/** \brief Starts a read operation via the MII link (non-blocking)
*
* This function will start a read operation on the MII link interface
* from a PHY or a connected device. The function will not block and
* the status mist be polled until complete. Once complete, the data
* can be read.
*
* \param[in] PhyReg PHY register to read from
*/
err_t lpc_mii_read(u32_t PhyReg, u32_t *data);
/** \brief Read a value via the MII link (blocking)
*
* This function will read a value on the MII link interface from a PHY
* or a connected device. The function will block until complete.
*
* \param[in] PhyReg PHY register to read from
* \param[in] data Pointer to where to save data read via MII
* \returns 0 if the read was successful, otherwise !0
*/
void lpc_mii_read_noblock(u32_t PhyReg);
/**
* This function provides a method for the PHY to setup the EMAC
* for the PHY negotiated duplex mode.
*
* @param[in] full_duplex 0 = half duplex, 1 = full duplex
*/
void lpc_emac_set_duplex(int full_duplex);
/**
* This function provides a method for the PHY to setup the EMAC
* for the PHY negotiated bit rate.
*
* @param[in] mbs_100 0 = 10mbs mode, 1 = 100mbs mode
*/
void lpc_emac_set_speed(int mbs_100);
#ifdef __cplusplus
}
#endif
#endif /* __LPC_PHY_H_ */
/* --------------------------------- End Of File ------------------------------ */

View file

@ -0,0 +1,438 @@
/**********************************************************************
* $Id$ lpc_phy_dp83848.c 2011-11-20
*//**
* @file lpc_phy_dp83848.c
* @brief DP83848C PHY status and control.
* @version 1.0
* @date 20 Nov. 2011
* @author NXP MCU SW Application Team
*
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
**********************************************************************/
#include "lwip/opt.h"
#include "lwip/err.h"
#include "lwip/tcpip.h"
#include "lwip/snmp.h"
#include "lpc_emac_config.h"
#include "lpc_phy.h"
#include "lpc17xx_emac.h"
/** @defgroup dp83848_phy PHY status and control for the DP83848.
* @ingroup lwip_phy
*
* Various functions for controlling and monitoring the status of the
* DP83848 PHY. In polled (standalone) systems, the PHY state must be
* monitored as part of the application. In a threaded (RTOS) system,
* the PHY state is monitored by the PHY handler thread. The MAC
* driver will not transmit unless the PHY link is active.
* @{
*/
/** \brief DP83848 PHY register offsets */
#define DP8_BMCR_REG 0x0 /**< Basic Mode Control Register */
#define DP8_BMSR_REG 0x1 /**< Basic Mode Status Reg */
#define DP8_IDR1_REG 0x2 /**< Basic Mode Status Reg */
#define DP8_IDR2_REG 0x3 /**< Basic Mode Status Reg */
#define DP8_ANADV_REG 0x4 /**< Auto_Neg Advt Reg */
#define DP8_ANLPA_REG 0x5 /**< Auto_neg Link Partner Ability Reg */
#define DP8_ANEEXP_REG 0x6 /**< Auto-neg Expansion Reg */
#define DP8_PHY_STAT_REG 0x10 /**< PHY Status Register */
#define DP8_PHY_INT_CTL_REG 0x11 /**< PHY Interrupt Control Register */
#define DP8_PHY_RBR_REG 0x17 /**< PHY RMII and Bypass Register */
#define DP8_PHY_STS_REG 0x19 /**< PHY Status Register */
#define DP8_PHY_SCSR_REG 0x1f /**< PHY Special Control/Status Register (LAN8720) */
/** \brief DP83848 Control register definitions */
#define DP8_RESET (1 << 15) /**< 1= S/W Reset */
#define DP8_LOOPBACK (1 << 14) /**< 1=loopback Enabled */
#define DP8_SPEED_SELECT (1 << 13) /**< 1=Select 100MBps */
#define DP8_AUTONEG (1 << 12) /**< 1=Enable auto-negotiation */
#define DP8_POWER_DOWN (1 << 11) /**< 1=Power down PHY */
#define DP8_ISOLATE (1 << 10) /**< 1=Isolate PHY */
#define DP8_RESTART_AUTONEG (1 << 9) /**< 1=Restart auto-negoatiation */
#define DP8_DUPLEX_MODE (1 << 8) /**< 1=Full duplex mode */
#define DP8_COLLISION_TEST (1 << 7) /**< 1=Perform collsion test */
/** \brief DP83848 Status register definitions */
#define DP8_100BASE_T4 (1 << 15) /**< T4 mode */
#define DP8_100BASE_TX_FD (1 << 14) /**< 100MBps full duplex */
#define DP8_100BASE_TX_HD (1 << 13) /**< 100MBps half duplex */
#define DP8_10BASE_T_FD (1 << 12) /**< 100Bps full duplex */
#define DP8_10BASE_T_HD (1 << 11) /**< 10MBps half duplex */
#define DP8_MF_PREAMB_SUPPR (1 << 6) /**< Preamble suppress */
#define DP8_AUTONEG_COMP (1 << 5) /**< Auto-negotation complete */
#define DP8_RMT_FAULT (1 << 4) /**< Fault */
#define DP8_AUTONEG_ABILITY (1 << 3) /**< Auto-negotation supported */
#define DP8_LINK_STATUS (1 << 2) /**< 1=Link active */
#define DP8_JABBER_DETECT (1 << 1) /**< Jabber detect */
#define DP8_EXTEND_CAPAB (1 << 0) /**< Supports extended capabilities */
/** \brief DP83848 PHY RBR MII dode definitions */
#define DP8_RBR_RMII_MODE (1 << 5) /**< Use RMII mode */
/** \brief DP83848 PHY status definitions */
#define DP8_REMOTEFAULT (1 << 6) /**< Remote fault */
#define DP8_FULLDUPLEX (1 << 2) /**< 1=full duplex */
#define DP8_SPEED10MBPS (1 << 1) /**< 1=10MBps speed */
#define DP8_VALID_LINK (1 << 0) /**< 1=Link active */
/** \brief DP83848 PHY ID register definitions */
#define DP8_PHYID1_OUI 0x2000 /**< Expected PHY ID1 */
#define DP8_PHYID2_OUI 0x5c90 /**< Expected PHY ID2 */
/** \brief LAN8720 PHY Special Control/Status Register */
#define PHY_SCSR_100MBIT 0x0008 /**< Speed: 1=100 MBit, 0=10Mbit */
#define PHY_SCSR_DUPLEX 0x0010 /**< PHY Duplex Mask */
/** \brief Link status bits */
#define LNK_STAT_VALID 0x01
#define LNK_STAT_FULLDUPLEX 0x02
#define LNK_STAT_SPEED10MPS 0x04
/** \brief PHY ID definitions */
#define DP83848C_ID 0x20005C90 /**< PHY Identifier - DP83848C */
#define LAN8720_ID 0x0007C0F0 /**< PHY Identifier - LAN8720 */
/** \brief PHY status structure used to indicate current status of PHY.
*/
typedef struct {
u32_t phy_speed_100mbs:1; /**< 10/100 MBS connection speed flag. */
u32_t phy_full_duplex:1; /**< Half/full duplex connection speed flag. */
u32_t phy_link_active:1; /**< Phy link active flag. */
} PHY_STATUS_TYPE;
/** \brief PHY update flags */
static PHY_STATUS_TYPE physts;
/** \brief Last PHY update flags, used for determing if something has changed */
static PHY_STATUS_TYPE olddphysts;
/** \brief PHY update counter for state machine */
static s32_t phyustate;
/** \brief Holds the PHY ID */
static u32_t phy_id;
/** \brief Temporary holder of link status for LAN7420 */
static u32_t phy_lan7420_sts_tmp;
/* Write a value via the MII link (non-blocking) */
void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value)
{
/* Write value at PHY address and register */
LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg;
LPC_EMAC->MWTD = Value;
}
/* Write a value via the MII link (blocking) */
err_t lpc_mii_write(u32_t PhyReg, u32_t Value)
{
u32_t mst = 250;
err_t sts = ERR_OK;
/* Write value at PHY address and register */
lpc_mii_write_noblock(PhyReg, Value);
/* Wait for unbusy status */
while (mst > 0) {
sts = LPC_EMAC->MIND;
if ((sts & EMAC_MIND_BUSY) == 0)
mst = 0;
else {
mst--;
osDelay(1);
}
}
if (sts != 0)
sts = ERR_TIMEOUT;
return sts;
}
/* Reads current MII link busy status */
u32_t lpc_mii_is_busy(void)
{
return (u32_t) (LPC_EMAC->MIND & EMAC_MIND_BUSY);
}
/* Starts a read operation via the MII link (non-blocking) */
u32_t lpc_mii_read_data(void)
{
u32_t data = LPC_EMAC->MRDD;
LPC_EMAC->MCMD = 0;
return data;
}
/* Starts a read operation via the MII link (non-blocking) */
void lpc_mii_read_noblock(u32_t PhyReg)
{
/* Read value at PHY address and register */
LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg;
LPC_EMAC->MCMD = EMAC_MCMD_READ;
}
/* Read a value via the MII link (blocking) */
err_t lpc_mii_read(u32_t PhyReg, u32_t *data)
{
u32_t mst = 250;
err_t sts = ERR_OK;
/* Read value at PHY address and register */
lpc_mii_read_noblock(PhyReg);
/* Wait for unbusy status */
while (mst > 0) {
sts = LPC_EMAC->MIND & ~EMAC_MIND_MII_LINK_FAIL;
if ((sts & EMAC_MIND_BUSY) == 0) {
mst = 0;
*data = LPC_EMAC->MRDD;
} else {
mst--;
osDelay(1);
}
}
LPC_EMAC->MCMD = 0;
if (sts != 0)
sts = ERR_TIMEOUT;
return sts;
}
/** \brief Update PHY status from passed value
*
* This function updates the current PHY status based on the
* passed PHY status word. The PHY status indicate if the link
* is active, the connection speed, and duplex.
*
* \param[in] netif NETIF structure
* \param[in] linksts Status word from PHY
* \return 1 if the status has changed, otherwise 0
*/
static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts)
{
s32_t changed = 0;
/* Update link active status */
if (linksts & LNK_STAT_VALID)
physts.phy_link_active = 1;
else
physts.phy_link_active = 0;
/* Full or half duplex */
if (linksts & LNK_STAT_FULLDUPLEX)
physts.phy_full_duplex = 1;
else
physts.phy_full_duplex = 0;
/* Configure 100MBit/10MBit mode. */
if (linksts & LNK_STAT_SPEED10MPS)
physts.phy_speed_100mbs = 0;
else
physts.phy_speed_100mbs = 1;
if (physts.phy_speed_100mbs != olddphysts.phy_speed_100mbs) {
changed = 1;
if (physts.phy_speed_100mbs) {
/* 100MBit mode. */
lpc_emac_set_speed(1);
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);
}
else {
/* 10MBit mode. */
lpc_emac_set_speed(0);
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
}
olddphysts.phy_speed_100mbs = physts.phy_speed_100mbs;
}
if (physts.phy_full_duplex != olddphysts.phy_full_duplex) {
changed = 1;
if (physts.phy_full_duplex)
lpc_emac_set_duplex(1);
else
lpc_emac_set_duplex(0);
olddphysts.phy_full_duplex = physts.phy_full_duplex;
}
if (physts.phy_link_active != olddphysts.phy_link_active) {
changed = 1;
#if NO_SYS == 1
if (physts.phy_link_active)
netif_set_link_up(netif);
else
netif_set_link_down(netif);
#else
if (physts.phy_link_active)
tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_up,
(void*) netif, 1);
else
tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_down,
(void*) netif, 1);
#endif
olddphysts.phy_link_active = physts.phy_link_active;
}
return changed;
}
/** \brief Initialize the DP83848 PHY.
*
* This function initializes the DP83848 PHY. It will block until
* complete. This function is called as part of the EMAC driver
* initialization. Configuration of the PHY at startup is
* controlled by setting up configuration defines in lpc_phy.h.
*
* \param[in] netif NETIF structure
* \param[in] rmii If set, configures the PHY for RMII mode
* \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT
*/
err_t lpc_phy_init(struct netif *netif, int rmii)
{
u32_t tmp;
s32_t i;
physts.phy_speed_100mbs = olddphysts.phy_speed_100mbs = 0;
physts.phy_full_duplex = olddphysts.phy_full_duplex = 0;
physts.phy_link_active = olddphysts.phy_link_active = 0;
phyustate = 0;
/* Only first read and write are checked for failure */
/* Put the DP83848C in reset mode and wait for completion */
if (lpc_mii_write(DP8_BMCR_REG, DP8_RESET) != 0)
return ERR_TIMEOUT;
i = 400;
while (i > 0) {
osDelay(1); /* 1 ms */
if (lpc_mii_read(DP8_BMCR_REG, &tmp) != 0)
return ERR_TIMEOUT;
if (!(tmp & (DP8_RESET | DP8_POWER_DOWN)))
i = -1;
else
i--;
}
/* Timeout? */
if (i == 0)
return ERR_TIMEOUT;
// read PHY ID
lpc_mii_read(DP8_IDR1_REG, &tmp);
phy_id = (tmp << 16);
lpc_mii_read(DP8_IDR2_REG, &tmp);
phy_id |= (tmp & 0XFFF0);
/* Setup link based on configuration options */
#if PHY_USE_AUTONEG==1
tmp = DP8_AUTONEG;
#else
tmp = 0;
#endif
#if PHY_USE_100MBS==1
tmp |= DP8_SPEED_SELECT;
#endif
#if PHY_USE_FULL_DUPLEX==1
tmp |= DP8_DUPLEX_MODE;
#endif
lpc_mii_write(DP8_BMCR_REG, tmp);
/* Enable RMII mode for PHY */
if (rmii)
lpc_mii_write(DP8_PHY_RBR_REG, DP8_RBR_RMII_MODE);
/* The link is not set active at this point, but will be detected
later */
return ERR_OK;
}
/* Phy status update state machine */
s32_t lpc_phy_sts_sm(struct netif *netif)
{
s32_t changed = 0;
u32_t data = 0;
u32_t tmp;
switch (phyustate) {
default:
case 0:
if (phy_id == DP83848C_ID) {
lpc_mii_read_noblock(DP8_PHY_STAT_REG);
phyustate = 2;
}
else if (phy_id == LAN8720_ID) {
lpc_mii_read_noblock(DP8_PHY_SCSR_REG);
phyustate = 1;
}
break;
case 1:
if (phy_id == LAN8720_ID) {
tmp = lpc_mii_read_data();
// we get speed and duplex here.
phy_lan7420_sts_tmp = (tmp & PHY_SCSR_DUPLEX) ? LNK_STAT_FULLDUPLEX : 0;
phy_lan7420_sts_tmp |= (tmp & PHY_SCSR_100MBIT) ? 0 : LNK_STAT_SPEED10MPS;
//read the status register to get link status
lpc_mii_read_noblock(DP8_BMSR_REG);
phyustate = 2;
}
break;
case 2:
/* Wait for read status state */
if (!lpc_mii_is_busy()) {
/* Update PHY status */
tmp = lpc_mii_read_data();
if (phy_id == DP83848C_ID) {
// STS register contains all needed status bits
data = (tmp & DP8_VALID_LINK) ? LNK_STAT_VALID : 0;
data |= (tmp & DP8_FULLDUPLEX) ? LNK_STAT_FULLDUPLEX : 0;
data |= (tmp & DP8_SPEED10MBPS) ? LNK_STAT_SPEED10MPS : 0;
}
else if (phy_id == LAN8720_ID) {
// we only get the link status here.
phy_lan7420_sts_tmp |= (tmp & DP8_LINK_STATUS) ? LNK_STAT_VALID : 0;
data = phy_lan7420_sts_tmp;
}
changed = lpc_update_phy_sts(netif, data);
phyustate = 0;
}
break;
}
return changed;
}
/**
* @}
*/
/* --------------------------------- End Of File ------------------------------ */

View file

@ -0,0 +1,30 @@
/* Copyright (C) 2012 mbed.org, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef LWIPOPTS_CONF_H
#define LWIPOPTS_CONF_H
#define LWIP_TRANSPORT_ETHERNET 1
#if defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM)
#define MEM_SIZE 15360
#elif defined(TARGET_LPC1768)
#define MEM_SIZE 16362
#endif
#endif

View file

@ -0,0 +1,26 @@
/* Copyright (C) 2012 mbed.org, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef LWIPOPTS_CONF_H
#define LWIPOPTS_CONF_H
#define LWIP_TRANSPORT_ETHERNET 1
#define MEM_SIZE (1600 * 16)
#endif

View file

@ -0,0 +1,192 @@
#include "lwip/opt.h"
#include "lwip/tcpip.h"
#include "netif/etharp.h"
#include "mbed_interface.h"
#include "ethernet_api.h"
#include "ethernetext_api.h"
#define RECV_TASK_PRI (osPriorityNormal)
#define PHY_TASK_PRI (osPriorityNormal)
#define PHY_TASK_WAIT (200)
/* memory */
static sys_sem_t recv_ready_sem; /* receive ready semaphore */
/* function */
static void rza1_recv_task(void *arg);
static void rza1_phy_task(void *arg);
static err_t rza1_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr);
static err_t rza1_low_level_output(struct netif *netif, struct pbuf *p);
static void rza1_recv_callback(void);
static void rza1_recv_task(void *arg) {
struct netif *netif = (struct netif*)arg;
struct eth_hdr *ethhdr;
u16_t recv_size;
struct pbuf *p;
struct pbuf *q;
while (1) {
sys_arch_sem_wait(&recv_ready_sem, 0);
recv_size = ethernet_receive();
if (recv_size != 0) {
p = pbuf_alloc(PBUF_RAW, recv_size, PBUF_POOL);
if (p != NULL) {
for (q = p; q != NULL; q = q->next) {
(void)ethernet_read((char *)q->payload, q->len);
}
ethhdr = p->payload;
switch (htons(ethhdr->type)) {
case ETHTYPE_IP:
case ETHTYPE_ARP:
#if PPPOE_SUPPORT
case ETHTYPE_PPPOEDISC:
case ETHTYPE_PPPOE:
#endif /* PPPOE_SUPPORT */
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
/* Free buffer */
pbuf_free(p);
}
break;
default:
/* Return buffer */
pbuf_free(p);
break;
}
}
}
}
}
static void rza1_phy_task(void *arg) {
struct netif *netif = (struct netif*)arg;
s32_t connect_sts = 0; /* 0: disconnect, 1:connect */
s32_t link_sts;
s32_t link_mode_new = NEGO_FAIL;
s32_t link_mode_old = NEGO_FAIL;
while (1) {
link_sts = ethernet_link();
if (link_sts == 1) {
link_mode_new = ethernetext_chk_link_mode();
if (link_mode_new != link_mode_old) {
if (connect_sts == 1) {
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
}
if (link_mode_new != NEGO_FAIL) {
ethernetext_set_link_mode(link_mode_new);
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1);
connect_sts = 1;
}
}
} else {
if (connect_sts != 0) {
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
link_mode_new = NEGO_FAIL;
connect_sts = 0;
}
}
link_mode_old = link_mode_new;
osDelay(PHY_TASK_WAIT);
}
}
static err_t rza1_etharp_output(struct netif *netif, struct pbuf *q, ip_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;
}
static err_t rza1_low_level_output(struct netif *netif, struct pbuf *p) {
struct pbuf *q;
s32_t cnt;
err_t err = ERR_MEM;
s32_t write_size = 0;
if ((p->payload != NULL) && (p->len != 0)) {
/* If the first data can't be written, transmit descriptor is full. */
for (cnt = 0; cnt < 100; cnt++) {
write_size = ethernet_write((char *)p->payload, p->len);
if (write_size != 0) {
break;
}
osDelay(1);
}
if (write_size != 0) {
for (q = p->next; q != NULL; q = q->next) {
(void)ethernet_write((char *)q->payload, q->len);
}
if (ethernet_send() == 1) {
err = ERR_OK;
}
}
}
return err;
}
static void rza1_recv_callback(void) {
sys_sem_signal(&recv_ready_sem);
}
err_t eth_arch_enetif_init(struct netif *netif)
{
ethernet_cfg_t ethcfg;
/* 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 = ETHARP_HWADDR_LEN;
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
#if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
netif->hostname = "lwiprza1";
#endif /* LWIP_NETIF_HOSTNAME */
netif->name[0] = 'e';
netif->name[1] = 'n';
netif->output = rza1_etharp_output;
netif->linkoutput = rza1_low_level_output;
/* Initialize the hardware */
ethcfg.int_priority = 6;
ethcfg.recv_cb = &rza1_recv_callback;
ethcfg.ether_mac = (char *)netif->hwaddr;
ethernetext_init(&ethcfg);
/* semaphore */
sys_sem_new(&recv_ready_sem, 0);
/* task */
sys_thread_new("rza1_recv_task", rza1_recv_task, netif, DEFAULT_THREAD_STACKSIZE, RECV_TASK_PRI);
sys_thread_new("rza1_phy_task", rza1_phy_task, netif, DEFAULT_THREAD_STACKSIZE, PHY_TASK_PRI);
return ERR_OK;
}
void eth_arch_enable_interrupts(void) {
ethernetext_start_stop(1);
}
void eth_arch_disable_interrupts(void) {
ethernetext_start_stop(0);
}

View file

@ -0,0 +1,26 @@
/* Copyright (C) 2015 mbed.org, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef LWIPOPTS_CONF_H
#define LWIPOPTS_CONF_H
#define LWIP_TRANSPORT_ETHERNET 1
#define MEM_SIZE (1600 * 16)
#endif

View file

@ -0,0 +1,560 @@
#include "stm32f4xx_hal.h"
#include "lwip/opt.h"
#include "lwip/timers.h"
#include "netif/etharp.h"
#include "lwip/tcpip.h"
#include <string.h>
#include "cmsis_os.h"
#include "mbed_interface.h"
/** @defgroup lwipstm32f4xx_emac_DRIVER stm32f4 EMAC driver for LWIP
* @ingroup lwip_emac
*
* @{
*/
#define RECV_TASK_PRI (osPriorityHigh)
#define PHY_TASK_PRI (osPriorityLow)
#define PHY_TASK_WAIT (200)
#if defined (__ICCARM__) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
__ALIGN_BEGIN ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB] __ALIGN_END; /* Ethernet Rx MA Descriptor */
#if defined (__ICCARM__) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
__ALIGN_BEGIN ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB] __ALIGN_END; /* Ethernet Tx DMA Descriptor */
#if defined (__ICCARM__) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
__ALIGN_BEGIN uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __ALIGN_END; /* Ethernet Receive Buffer */
#if defined (__ICCARM__) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
__ALIGN_BEGIN uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __ALIGN_END; /* Ethernet Transmit Buffer */
ETH_HandleTypeDef heth;
static sys_sem_t rx_ready_sem; /* receive ready semaphore */
static sys_mutex_t tx_lock_mutex;
/* function */
static void stm32f4_rx_task(void *arg);
static void stm32f4_phy_task(void *arg);
static err_t stm32f4_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr);
static err_t stm32f4_low_level_output(struct netif *netif, struct pbuf *p);
/**
* Override HAL Eth Init function
*/
void HAL_ETH_MspInit(ETH_HandleTypeDef* heth)
{
GPIO_InitTypeDef GPIO_InitStruct;
if (heth->Instance == ETH) {
/* Peripheral clock enable */
__ETH_CLK_ENABLE();
__GPIOA_CLK_ENABLE();
__GPIOB_CLK_ENABLE();
__GPIOC_CLK_ENABLE();
/**ETH GPIO Configuration
PC1 ------> ETH_MDC
PA1 ------> ETH_REF_CLK
PA2 ------> ETH_MDIO
PA7 ------> ETH_CRS_DV
PC4 ------> ETH_RXD0
PC5 ------> ETH_RXD1
PB11 ------> ETH_TX_EN
PB12 ------> ETH_TXD0
PB13 ------> ETH_TXD1
*/
GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral interrupt init*/
/* Sets the priority grouping field */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
HAL_NVIC_SetPriority(ETH_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(ETH_IRQn);
}
}
/**
* Override HAL Eth DeInit function
*/
void HAL_ETH_MspDeInit(ETH_HandleTypeDef* heth)
{
if (heth->Instance == ETH) {
/* Peripheral clock disable */
__ETH_CLK_DISABLE();
/**ETH GPIO Configuration
PC1 ------> ETH_MDC
PA1 ------> ETH_REF_CLK
PA2 ------> ETH_MDIO
PA7 ------> ETH_CRS_DV
PC4 ------> ETH_RXD0
PC5 ------> ETH_RXD1
PB11 ------> ETH_TX_EN
PB12 ------> ETH_TXD0
PB13 ------> ETH_TXD1
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5);
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7);
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13);
/* Peripheral interrupt Deinit*/
HAL_NVIC_DisableIRQ(ETH_IRQn);
}
}
/**
* Ethernet Rx Transfer completed callback
*
* @param heth: ETH handle
* @retval None
*/
void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
{
sys_sem_signal(&rx_ready_sem);
}
/**
* Ethernet IRQ Handler
*
* @param None
* @retval None
*/
void ETH_IRQHandler(void)
{
HAL_ETH_IRQHandler(&heth);
}
/**
* In this function, the hardware should be initialized.
* Called from eth_arch_enetif_init().
*
* @param netif the already initialized lwip network interface structure
* for this ethernetif
*/
static void stm32f4_low_level_init(struct netif *netif)
{
uint32_t regvalue = 0;
HAL_StatusTypeDef hal_eth_init_status;
/* Init ETH */
uint8_t MACAddr[6];
heth.Instance = ETH;
heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
heth.Init.Speed = ETH_SPEED_10M;
heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
heth.Init.PhyAddress = 1;
#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
MACAddr[0] = MBED_MAC_ADDR_0;
MACAddr[1] = MBED_MAC_ADDR_1;
MACAddr[2] = MBED_MAC_ADDR_2;
MACAddr[3] = MBED_MAC_ADDR_3;
MACAddr[4] = MBED_MAC_ADDR_4;
MACAddr[5] = MBED_MAC_ADDR_5;
#else
mbed_mac_address((char *)MACAddr);
#endif
heth.Init.MACAddr = &MACAddr[0];
heth.Init.RxMode = ETH_RXINTERRUPT_MODE;
heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
hal_eth_init_status = HAL_ETH_Init(&heth);
if (hal_eth_init_status == HAL_OK) {
/* Set netif link flag */
netif->flags |= NETIF_FLAG_LINK_UP;
}
/* Initialize Tx Descriptors list: Chain Mode */
HAL_ETH_DMATxDescListInit(&heth, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
/* Initialize Rx Descriptors list: Chain Mode */
HAL_ETH_DMARxDescListInit(&heth, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
#if LWIP_ARP || LWIP_ETHERNET
/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* set MAC hardware address */
netif->hwaddr[0] = heth.Init.MACAddr[0];
netif->hwaddr[1] = heth.Init.MACAddr[1];
netif->hwaddr[2] = heth.Init.MACAddr[2];
netif->hwaddr[3] = heth.Init.MACAddr[3];
netif->hwaddr[4] = heth.Init.MACAddr[4];
netif->hwaddr[5] = heth.Init.MACAddr[5];
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
/* Enable MAC and DMA transmission and reception */
HAL_ETH_Start(&heth);
/**** Configure PHY to generate an interrupt when Eth Link state changes ****/
/* Read Register Configuration */
HAL_ETH_ReadPHYRegister(&heth, PHY_MICR, &regvalue);
regvalue |= (PHY_MICR_INT_EN | PHY_MICR_INT_OE);
/* Enable Interrupts */
HAL_ETH_WritePHYRegister(&heth, PHY_MICR, regvalue);
/* Read Register Configuration */
HAL_ETH_ReadPHYRegister(&heth, PHY_MISR, &regvalue);
regvalue |= PHY_MISR_LINK_INT_EN;
/* Enable Interrupt on change of link status */
HAL_ETH_WritePHYRegister(&heth, PHY_MISR, regvalue);
#endif
}
/**
* This function should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
* @param netif the lwip network interface structure for this ethernetif
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
* @return ERR_OK if the packet could be sent
* an err_t value if the packet couldn't be sent
*
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
* strange results. You might consider waiting for space in the DMA queue
* to become availale since the stack doesn't retry to send a packet
* dropped because of memory failure (except for the TCP timers).
*/
static err_t stm32f4_low_level_output(struct netif *netif, struct pbuf *p)
{
err_t errval;
struct pbuf *q;
uint8_t *buffer = (uint8_t*)(heth.TxDesc->Buffer1Addr);
__IO ETH_DMADescTypeDef *DmaTxDesc;
uint32_t framelength = 0;
uint32_t bufferoffset = 0;
uint32_t byteslefttocopy = 0;
uint32_t payloadoffset = 0;
DmaTxDesc = heth.TxDesc;
bufferoffset = 0;
sys_mutex_lock(&tx_lock_mutex);
/* copy frame from pbufs to driver buffers */
for (q = p; q != NULL; q = q->next) {
/* Is this buffer available? If not, goto error */
if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET) {
errval = ERR_USE;
goto error;
}
/* Get bytes in current lwIP buffer */
byteslefttocopy = q->len;
payloadoffset = 0;
/* Check if the length of data to copy is bigger than Tx buffer size*/
while ((byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE) {
/* Copy data to Tx buffer*/
memcpy((uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset));
/* Point to next descriptor */
DmaTxDesc = (ETH_DMADescTypeDef*)(DmaTxDesc->Buffer2NextDescAddr);
/* Check if the buffer is available */
if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET) {
errval = ERR_USE;
goto error;
}
buffer = (uint8_t*)(DmaTxDesc->Buffer1Addr);
byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);
payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);
framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);
bufferoffset = 0;
}
/* Copy the remaining bytes */
memcpy((uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), byteslefttocopy);
bufferoffset = bufferoffset + byteslefttocopy;
framelength = framelength + byteslefttocopy;
}
/* Prepare transmit descriptors to give to DMA */
HAL_ETH_TransmitFrame(&heth, framelength);
errval = ERR_OK;
error:
/* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */
if ((heth.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET) {
/* Clear TUS ETHERNET DMA flag */
heth.Instance->DMASR = ETH_DMASR_TUS;
/* Resume DMA transmission*/
heth.Instance->DMATPDR = 0;
}
sys_mutex_unlock(&tx_lock_mutex);
return errval;
}
/**
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
* @param netif the lwip network interface structure for this ethernetif
* @return a pbuf filled with the received packet (including MAC header)
* NULL on memory error
*/
static struct pbuf * stm32f4_low_level_input(struct netif *netif)
{
struct pbuf *p = NULL;
struct pbuf *q;
uint16_t len = 0;
uint8_t *buffer;
__IO ETH_DMADescTypeDef *dmarxdesc;
uint32_t bufferoffset = 0;
uint32_t payloadoffset = 0;
uint32_t byteslefttocopy = 0;
uint32_t i = 0;
/* get received frame */
if (HAL_ETH_GetReceivedFrame(&heth) != HAL_OK)
return NULL;
/* Obtain the size of the packet and put it into the "len" variable. */
len = heth.RxFrameInfos.length;
buffer = (uint8_t*)heth.RxFrameInfos.buffer;
if (len > 0) {
/* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
}
if (p != NULL) {
dmarxdesc = heth.RxFrameInfos.FSRxDesc;
bufferoffset = 0;
for (q = p; q != NULL; q = q->next) {
byteslefttocopy = q->len;
payloadoffset = 0;
/* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/
while ((byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE) {
/* Copy data to pbuf */
memcpy((uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));
/* Point to next descriptor */
dmarxdesc = (ETH_DMADescTypeDef*)(dmarxdesc->Buffer2NextDescAddr);
buffer = (uint8_t*)(dmarxdesc->Buffer1Addr);
byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
bufferoffset = 0;
}
/* Copy remaining data in pbuf */
memcpy((uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), byteslefttocopy);
bufferoffset = bufferoffset + byteslefttocopy;
}
/* Release descriptors to DMA */
/* Point to first descriptor */
dmarxdesc = heth.RxFrameInfos.FSRxDesc;
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
for (i = 0; i < heth.RxFrameInfos.SegCount; i++) {
dmarxdesc->Status |= ETH_DMARXDESC_OWN;
dmarxdesc = (ETH_DMADescTypeDef*)(dmarxdesc->Buffer2NextDescAddr);
}
/* Clear Segment_Count */
heth.RxFrameInfos.SegCount = 0;
}
/* When Rx Buffer unavailable flag is set: clear it and resume reception */
if ((heth.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET) {
/* Clear RBUS ETHERNET DMA flag */
heth.Instance->DMASR = ETH_DMASR_RBUS;
/* Resume DMA reception */
heth.Instance->DMARPDR = 0;
}
return p;
}
/**
* This task receives input data
*
* \param[in] netif the lwip network interface structure
*/
static void stm32f4_rx_task(void *arg)
{
struct netif *netif = (struct netif*)arg;
struct pbuf *p;
while (1) {
sys_arch_sem_wait(&rx_ready_sem, 0);
p = stm32f4_low_level_input(netif);
if (p != NULL) {
if (netif->input(p, netif) != ERR_OK) {
pbuf_free(p);
p = NULL;
}
}
}
}
/**
* This task checks phy link status and updates net status
*
* \param[in] netif the lwip network interface structure
*/
static void stm32f4_phy_task(void *arg)
{
struct netif *netif = (struct netif*)arg;
uint32_t phy_status = 0;
while (1) {
uint32_t status;
if (HAL_ETH_ReadPHYRegister(&heth, PHY_SR, &status) == HAL_OK) {
if ((status & PHY_LINK_STATUS) && !(phy_status & PHY_LINK_STATUS)) {
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1);
} else if (!(status & PHY_LINK_STATUS) && (phy_status & PHY_LINK_STATUS)) {
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
}
phy_status = status;
}
osDelay(PHY_TASK_WAIT);
}
}
/**
* This function is the ethernet 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
*/
static err_t stm32f4_etharp_output(struct netif *netif, struct pbuf *q, ip_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;
}
/**
* 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)
{
/* set MAC hardware address */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
#if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
netif->hostname = "lwipstm32f4";
#endif /* LWIP_NETIF_HOSTNAME */
netif->name[0] = 'e';
netif->name[1] = 'n';
netif->output = stm32f4_etharp_output;
netif->linkoutput = stm32f4_low_level_output;
/* semaphore */
sys_sem_new(&rx_ready_sem, 0);
sys_mutex_new(&tx_lock_mutex);
/* task */
sys_thread_new("stm32f4_recv_task", stm32f4_rx_task, netif, DEFAULT_THREAD_STACKSIZE, RECV_TASK_PRI);
sys_thread_new("stm32f4_phy_task", stm32f4_phy_task, netif, DEFAULT_THREAD_STACKSIZE, PHY_TASK_PRI);
/* initialize the hardware */
stm32f4_low_level_init(netif);
return ERR_OK;
}
void eth_arch_enable_interrupts(void)
{
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
HAL_NVIC_SetPriority(ETH_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(ETH_IRQn);
}
void eth_arch_disable_interrupts(void)
{
NVIC_DisableIRQ(ETH_IRQn);
}
/**
* @}
*/
/* --------------------------------- End Of File ------------------------------ */