diff --git a/bsp/lm4f232/rtconfig.h b/bsp/lm4f232/rtconfig.h index 723077dd508ec3ef6e2d7e8a015830362ee653e9..586b4adac2c92f7137a9cf79baf6983d38df2eb4 100644 --- a/bsp/lm4f232/rtconfig.h +++ b/bsp/lm4f232/rtconfig.h @@ -93,7 +93,7 @@ #define DFS_FD_MAX 4 /* SECTION: lwip, a lighwight TCP/IP protocol stack */ -/* #define RT_USING_LWIP */ +#define RT_USING_LWIP /* LwIP uses RT-Thread Memory Management */ #define RT_LWIP_USING_RT_MEM /* Enable ICMP protocol*/ diff --git a/bsp/tm4c129x/applications/application.c b/bsp/tm4c129x/applications/application.c index 80f58b6ed8a0c48e3ab90c6beeb798f4cc9a4537..984e6221573a44d23904baa9377c1cdc3ea32284 100644 --- a/bsp/tm4c129x/applications/application.c +++ b/bsp/tm4c129x/applications/application.c @@ -16,6 +16,9 @@ #include #include +#ifdef RT_USING_LWIP +#include "drv_eth.h" +#endif /* thread phase init */ void rt_init_thread_entry(void *parameter) { @@ -24,6 +27,9 @@ void rt_init_thread_entry(void *parameter) #ifdef RT_USING_FINSH finsh_set_device(RT_CONSOLE_DEVICE_NAME); #endif +#ifdef RT_USING_LWIP + rt_hw_tiva_eth_init(); +#endif } int rt_application_init(void) diff --git a/bsp/tm4c129x/applications/board.c b/bsp/tm4c129x/applications/board.c index c638369a5ad28aa6520faa73b5dacf68eea2c83c..2953e76c58dae162a6e033d67c7a72c4b330f539 100644 --- a/bsp/tm4c129x/applications/board.c +++ b/bsp/tm4c129x/applications/board.c @@ -92,7 +92,7 @@ void rt_hw_board_init() /*init uart device*/ rt_hw_uart_init(); - //redirect RTT stdio to CONSOLE device + //redirect RTT stdio to CONSOLE device rt_console_set_device(RT_CONSOLE_DEVICE_NAME); // // Enable interrupts to the processor. diff --git a/bsp/tm4c129x/drivers/drv_eth.c b/bsp/tm4c129x/drivers/drv_eth.c new file mode 100644 index 0000000000000000000000000000000000000000..ea4813be00c36da94f3ca296df8015aba0d115f6 --- /dev/null +++ b/bsp/tm4c129x/drivers/drv_eth.c @@ -0,0 +1,1446 @@ +/* + * File : drv_eth.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2009-2013 RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2014-07-25 ArdaFu Port to TM4C129X + */ + +/** + * @file - tivaif.c + * lwIP Ethernet interface for Stellaris LM4F Devices + * + */ + +/** + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICui32AR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/** + * Copyright (c) 2008-2012 Texas Instruments Incorporated + * + * This file is derived from the ``ethernetif.c'' skeleton Ethernet network + * interface driver for lwIP. + * + */ + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include +#include +#include "lwip/tcpip.h" +#include "netif/etharp.h" +#include "netif/ppp_oe.h" + + +/** + * Sanity Check: This interface driver will NOT work if the following defines + * are incorrect. + * + */ +#if (PBUF_LINK_HLEN != 16) +#error "PBUF_LINK_HLEN must be 16 for this interface driver!" +#endif +#if (ETH_PAD_SIZE != 0) +#error "ETH_PAD_SIZE must be 0 for this interface driver!" +#endif +#if (!SYS_LIGHTWEIGHT_PROT) +#error "SYS_LIGHTWEIGHT_PROT must be enabled for this interface driver!" +#endif + +/** + * Set the physical address of the PHY we will be using if this is not + * specified in lwipopts.h. We assume 0 for the internal PHY. + */ +#ifndef PHY_PHYS_ADDR +#define PHY_PHYS_ADDR 0 +#endif + +#if 0 +#ifndef EMAC_PHY_CONFIG +#define EMAC_PHY_CONFIG (EMAC_PHY_TYPE_INTERNAL | EMAC_PHY_INT_MDIX_EN | \ + EMAC_PHY_AN_100B_T_FULL_DUPLEX) +#endif +#endif + +/** + * If necessary, set the defaui32t number of transmit and receive DMA descriptors + * used by the Ethernet MAC. + * + */ +#ifndef NUM_RX_DESCRIPTORS +#define NUM_RX_DESCRIPTORS 4 +#endif + +#ifndef NUM_TX_DESCRIPTORS +#define NUM_TX_DESCRIPTORS 8 +#endif + +/** + * Setup processing for PTP (IEEE-1588). + * + */ +#if LWIP_PTPD +extern uint32_t g_ui32SysClk; +extern uint32_t g_ui32PTPTickRate; +extern void lwIPHostGetTime(u32_t *time_s, u32_t *time_ns); +#endif + +/** + * Stellaris DriverLib Header Files required for this interface driver. + * + */ +#include +#include +#include "inc/hw_emac.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_types.h" + +#include "driverlib/emac.h" +#include "driverlib/interrupt.h" +#include "driverlib/sysctl.h" +#include "driverlib/flash.h" +#include "driverlib/interrupt.h" + +#include "driverlib/pin_map.h" +#include "driverlib/rom_map.h" +#include "driverlib/gpio.h" + +#include +#include "lwipopts.h" +#include "drv_eth.h" + +/** + * A structure used to keep track of driver state and error counts. + */ +typedef struct { + uint32_t ui32TXCount; + uint32_t ui32TXCopyCount; + uint32_t ui32TXCopyFailCount; + uint32_t ui32TXNoDescCount; + uint32_t ui32TXBufQueuedCount; + uint32_t ui32TXBufFreedCount; + uint32_t ui32RXBufReadCount; + uint32_t ui32RXPacketReadCount; + uint32_t ui32RXPacketErrCount; + uint32_t ui32RXPacketCBErrCount; + uint32_t ui32RXNoBufCount; +} +tDriverStats; + +tDriverStats g_sDriverStats; + +#ifdef DEBUG +/** + * Note: This rather weird construction where we invoke the macro with the + * name of the field minus its Hungarian prefix is a workaround for a problem + * experienced with GCC which does not like concatenating tokens after an + * operator, specifically '.' or '->', in a macro. + */ +#define DRIVER_STATS_INC(x) do{ g_sDriverStats.ui32##x++; } while(0) +#define DRIVER_STATS_DEC(x) do{ g_sDriverStats.ui32##x--; } while(0) +#define DRIVER_STATS_ADD(x, inc) do{ g_sDriverStats.ui32##x += (inc); } while(0) +#define DRIVER_STATS_SUB(x, dec) do{ g_sDriverStats.ui32##x -= (dec); } while(0) +#else +#define DRIVER_STATS_INC(x) +#define DRIVER_STATS_DEC(x) +#define DRIVER_STATS_ADD(x, inc) +#define DRIVER_STATS_SUB(x, dec) +#endif + +/** + * Helper struct holding a DMA descriptor and the pbuf it currently refers + * to. + */ +typedef struct { + tEMACDMADescriptor Desc; + struct pbuf *pBuf; +} tDescriptor; + +typedef struct { + tDescriptor *pDescriptors; + uint32_t ui32NumDescs; + uint32_t ui32Read; + uint32_t ui32Write; +} tDescriptorList; + +/** + * Helper struct to hold private data used to operate your ethernet interface. + * Keeping the ethernet address of the MAC in this struct is not necessary + * as it is already kept in the struct netif. + * But this is only an example, anyway... + */ +typedef struct { + struct eth_addr *ethaddr; + /* Add whatever per-interface state that is needed here. */ + tDescriptorList *pTxDescList; + tDescriptorList *pRxDescList; +} tStellarisIF; + +/** + * Global variable for this interface's private data. Needed to allow + * the interrupt handlers access to this information outside of the + * context of the lwIP netif. + * + */ +tDescriptor g_pTxDescriptors[NUM_TX_DESCRIPTORS]; +tDescriptor g_pRxDescriptors[NUM_RX_DESCRIPTORS]; +tDescriptorList g_TxDescList = { + g_pTxDescriptors, NUM_TX_DESCRIPTORS, 0, 0 +}; +tDescriptorList g_RxDescList = { + g_pRxDescriptors, NUM_RX_DESCRIPTORS, 0, 0 +}; +static tStellarisIF g_StellarisIFData = { + 0, &g_TxDescList, &g_RxDescList +}; + +/** + * Interrupt counters (for debug purposes). + */ +volatile uint32_t g_ui32NormalInts; +volatile uint32_t g_ui32AbnormalInts; + +/** + * A macro which determines whether a pointer is within the SRAM address + * space and, hence, points to a buffer that the Ethernet MAC can directly + * DMA from. + */ +#define PTR_SAFE_FOR_EMAC_DMA(ptr) (((uint32_t)(ptr) >= 0x2000000) && \ + ((uint32_t)(ptr) < 0x20070000)) + + +typedef struct +{ + /* inherit from ethernet device */ + struct eth_device parent; + tStellarisIF* dma_if; + /* for rx_thread async get pbuf */ + rt_mailbox_t rx_pbuf_mb; +} net_device; +typedef net_device* net_device_t; + +static char rx_pbuf_mb_pool[8*4]; +static struct rt_mailbox eth_rx_pbuf_mb; +static net_device eth_dev_entry; +static net_device_t eth_dev = ð_dev_entry; + +/** + * Initialize the transmit and receive DMA descriptor lists. + */ +void +InitDMADescriptors(void) +{ + uint32_t ui32Loop; + + /* Transmit list - mark all descriptors as not owned by the hardware */ + for(ui32Loop = 0; ui32Loop < NUM_TX_DESCRIPTORS; ui32Loop++) + { + g_pTxDescriptors[ui32Loop].pBuf = (struct pbuf *)0; + g_pTxDescriptors[ui32Loop].Desc.ui32Count = 0; + g_pTxDescriptors[ui32Loop].Desc.pvBuffer1 = 0; + g_pTxDescriptors[ui32Loop].Desc.DES3.pLink = + ((ui32Loop == (NUM_TX_DESCRIPTORS - 1)) ? + &g_pTxDescriptors[0].Desc : &g_pTxDescriptors[ui32Loop + 1].Desc); + g_pTxDescriptors[ui32Loop].Desc.ui32CtrlStatus = DES0_TX_CTRL_INTERRUPT | + DES0_TX_CTRL_CHAINED | DES0_TX_CTRL_IP_ALL_CKHSUMS; + + } + + g_TxDescList.ui32Read = 0; + g_TxDescList.ui32Write = 0; + + + /* Receive list - tag each descriptor with a pbuf and set all fields to + * allow packets to be received. + */ + for(ui32Loop = 0; ui32Loop < NUM_RX_DESCRIPTORS; ui32Loop++) + { + g_pRxDescriptors[ui32Loop].pBuf = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, + PBUF_POOL); + g_pRxDescriptors[ui32Loop].Desc.ui32Count = DES1_RX_CTRL_CHAINED; + if(g_pRxDescriptors[ui32Loop].pBuf) + { + /* Set the DMA to write directly into the pbuf payload. */ + g_pRxDescriptors[ui32Loop].Desc.pvBuffer1 = + g_pRxDescriptors[ui32Loop].pBuf->payload; + g_pRxDescriptors[ui32Loop].Desc.ui32Count |= + (g_pRxDescriptors[ui32Loop].pBuf->len << DES1_RX_CTRL_BUFF1_SIZE_S); + g_pRxDescriptors[ui32Loop].Desc.ui32CtrlStatus = DES0_RX_CTRL_OWN; + } + else + { + LWIP_DEBUGF(NETIF_DEBUG, ("tivaif_init: pbuf_alloc error\n")); + + /* No pbuf available so leave the buffer pointer empty. */ + g_pRxDescriptors[ui32Loop].Desc.pvBuffer1 = 0; + g_pRxDescriptors[ui32Loop].Desc.ui32CtrlStatus = 0; + } + g_pRxDescriptors[ui32Loop].Desc.DES3.pLink = + ((ui32Loop == (NUM_RX_DESCRIPTORS - 1)) ? + &g_pRxDescriptors[0].Desc : &g_pRxDescriptors[ui32Loop + 1].Desc); + } + + g_TxDescList.ui32Read = 0; + g_TxDescList.ui32Write = 0; + + // + // Set the descriptor pointers in the hardware. + // + EMACRxDMADescriptorListSet(EMAC0_BASE, &g_pRxDescriptors[0].Desc); + EMACTxDMADescriptorListSet(EMAC0_BASE, &g_pTxDescriptors[0].Desc); +} + +/** + * In this function, the hardware should be initialized. + * Called from tivaif_init(). + * + * @param netif the already initialized lwip network interface structure + * for this ethernetif + */ +static void +tivaif_hwinit(struct netif *psNetif) +{ + uint16_t ui16Val; + + /* Initialize the DMA descriptors. */ + InitDMADescriptors(); + + /* Clear any stray PHY interrupts that may be set. */ + ui16Val = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1); + ui16Val = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR2); + + /* Configure and enable the link status change interrupt in the PHY. */ + ui16Val = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_SCR); + ui16Val |= (EPHY_SCR_INTEN_EXT | EPHY_SCR_INTOE_EXT); + EMACPHYWrite(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_SCR, ui16Val); + EMACPHYWrite(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1, (EPHY_MISR1_LINKSTATEN | + EPHY_MISR1_SPEEDEN | EPHY_MISR1_DUPLEXMEN | EPHY_MISR1_ANCEN)); + + /* Read the PHY interrupt status to clear any stray events. */ + ui16Val = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1); + + /** + * Set MAC filtering options. We receive all broadcast and mui32ticast + * packets along with those addressed specifically for us. + */ + EMACFrameFilterSet(EMAC0_BASE, (EMAC_FRMFILTER_HASH_AND_PERFECT | + EMAC_FRMFILTER_PASS_MULTICAST)); + +#if LWIP_PTPD + // + // Enable timestamping on all received packets. + // + // We set the fine clock adjustment mode and configure the subsecond + // increment to half the 25MHz PTPD clock. This will give us maximum control + // over the clock rate adjustment and keep the arithmetic easy later. It + // should be possible to synchronize with higher accuracy than this with + // appropriate juggling of the subsecond increment count and the addend + // register value, though. + // + EMACTimestampConfigSet(EMAC0_BASE, (EMAC_TS_ALL_RX_FRAMES | + EMAC_TS_DIGITAL_ROLLOVER | + EMAC_TS_PROCESS_IPV4_UDP | EMAC_TS_ALL | + EMAC_TS_PTP_VERSION_1 | EMAC_TS_UPDATE_FINE), + (1000000000 / (25000000 / 2))); + EMACTimestampAddendSet(EMAC0_BASE, 0x80000000); + EMACTimestampEnable(EMAC0_BASE); +#endif + + /* Clear any pending MAC interrupts. */ + EMACIntClear(EMAC0_BASE, EMACIntStatus(EMAC0_BASE, false)); + + /* Enable the Ethernet MAC transmitter and receiver. */ + EMACTxEnable(EMAC0_BASE); + EMACRxEnable(EMAC0_BASE); + + /* Enable the Ethernet RX and TX interrupt source. */ + EMACIntEnable(EMAC0_BASE, (EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT | + EMAC_INT_TX_STOPPED | EMAC_INT_RX_NO_BUFFER | + EMAC_INT_RX_STOPPED | EMAC_INT_PHY)); + + /* Enable the Ethernet interrupt. */ + IntEnable(INT_EMAC0); + + /* Enable all processor interrupts. */ + IntMasterEnable(); + + /* Tell the PHY to start an auto-negotiation cycle. */ + EMACPHYWrite(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_BMCR, (EPHY_BMCR_ANEN | + EPHY_BMCR_RESTARTAN)); +} + +#ifdef DEBUG +/** + * Dump the chain of pbuf pointers to the debug output. + */ +void +tivaif_trace_pbuf(const char *pcTitle, struct pbuf *p) +{ + LWIP_DEBUGF(NETIF_DEBUG, ("%s %08x (%d, %d)", pcTitle, p, p->tot_len, + p->len)); + + do + { + p = p->next; + if(p) + { + LWIP_DEBUGF(NETIF_DEBUG, ("->%08x(%d)", p, p->len)); + } + else + { + LWIP_DEBUGF(NETIF_DEBUG, ("->%08x", p)); + } + + } while((p != NULL) && (p->tot_len != p->len)); + + LWIP_DEBUGF(NETIF_DEBUG, ("\n")); +} +#endif + +/** + * This function is used to check whether a passed pbuf contains only buffers + * resident in regions of memory that the Ethernet MAC can access. If any + * buffers in the chain are outside a directly-DMAable section of memory, + * the pbuf is copied to SRAM and a different pointer returned. If all + * buffers are safe, the pbuf reference count is incremented and the original + * pointer returned. + */ +static struct pbuf * +tivaif_check_pbuf(struct pbuf *p) +{ + struct pbuf *pBuf; + rt_err_t Err; + + pBuf = p; + +#ifdef DEBUG + tivaif_trace_pbuf("Original:", p); +#endif + + /* Walk the list of buffers in the pbuf checking each. */ + do + { + /* Does this pbuf's payload reside in memory that the Ethernet DMA + * can access? + */ + if(!PTR_SAFE_FOR_EMAC_DMA(pBuf->payload)) + { + /* This buffer is outside the DMA-able memory space so we need + * to copy the pbuf. + */ + pBuf = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_POOL); + + /* If we got a new pbuf... */ + if(pBuf) + { + /* ...copy the old pbuf into the new one. */ + Err = pbuf_copy(pBuf, p); + + /* If we failed to copy the pbuf, free the newly allocated one + * and make sure we return a NULL to show a problem. + */ + if(Err != RT_EOK) + { + DRIVER_STATS_INC(TXCopyFailCount); + pbuf_free(pBuf); + pBuf = NULL; + } + else + { +#ifdef DEBUG + tivaif_trace_pbuf("Copied:", pBuf); +#endif + DRIVER_STATS_INC(TXCopyCount); + + /* Reduce the reference count on the original pbuf since + * we're not going to hold on to it after returning from + * tivaif_transmit. Note that we already bumped + * the reference count at the top of tivaif_transmit. + */ + pbuf_free(p); + } + } + + /* Send back the new pbuf pointer or NULL if an error occurred. */ + return(pBuf); + } + + /* Move on to the next buffer in the queue */ + pBuf = pBuf->next; + } + while(pBuf); + + /** + * If we get here, the passed pbuf can be safely used without needing to + * be copied. + */ + return(p); +} + +/** + * 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 psNetif 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 RT_EOK if the packet coui32d be sent + * an err_t value if the packet coui32dn't be sent + */ +static rt_err_t +tivaif_transmit(net_device_t dev, struct pbuf *p) +{ + tStellarisIF *pIF; + tDescriptor *pDesc; + struct pbuf *pBuf; + uint32_t ui32NumChained, ui32NumDescs; + bool bFirst; + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_DEBUGF(NETIF_DEBUG, ("tivaif_transmit 0x%08x, len %d\n", p, + p->tot_len)); + + /** + * This entire function must run within a "critical section" to preserve + * the integrity of the transmit pbuf queue. + */ + SYS_ARCH_PROTECT(lev); + + /* Update our transmit attempt counter. */ + DRIVER_STATS_INC(TXCount); + + /** + * Increase the reference count on the packet provided so that we can + * hold on to it until we are finished transmitting its content. + */ + pbuf_ref(p); + + /** + * Determine whether all buffers passed are within SRAM and, if not, copy + * the pbuf into SRAM-resident buffers so that the Ethernet DMA can access + * the data. + */ + p = tivaif_check_pbuf(p); + + /* Make sure we still have a valid buffer (it may have been copied) */ + if(!p) + { + LINK_STATS_INC(link.memerr); + SYS_ARCH_UNPROTECT(lev); + return(-RT_ENOMEM); + } + + /* Get our state data from the netif structure we were passed. */ + //pIF = (tStellarisIF *)psNetif->state; + pIF = dev->dma_if; + + /* Make sure that the transmit descriptors are not all in use */ + pDesc = &(pIF->pTxDescList->pDescriptors[pIF->pTxDescList->ui32Write]); + if(pDesc->pBuf) + { + /** + * The current write descriptor has a pbuf attached to it so this + * implies that the ring is fui32l. Reject this transmit request with a + * memory error since we can't satisfy it just now. + */ + pbuf_free(p); + LINK_STATS_INC(link.memerr); + DRIVER_STATS_INC(TXNoDescCount); + SYS_ARCH_UNPROTECT(lev); + return (-RT_ENOMEM); + } + + /* How many pbufs are in the chain passed? */ + ui32NumChained = (uint32_t)pbuf_clen(p); + + /* How many free transmit descriptors do we have? */ + ui32NumDescs = (pIF->pTxDescList->ui32Read > pIF->pTxDescList->ui32Write) ? + (pIF->pTxDescList->ui32Read - pIF->pTxDescList->ui32Write) : + ((NUM_TX_DESCRIPTORS - pIF->pTxDescList->ui32Write) + + pIF->pTxDescList->ui32Read); + + /* Do we have enough free descriptors to send the whole packet? */ + if(ui32NumDescs < ui32NumChained) + { + /* No - we can't transmit this whole packet so return an error. */ + pbuf_free(p); + LINK_STATS_INC(link.memerr); + DRIVER_STATS_INC(TXNoDescCount); + SYS_ARCH_UNPROTECT(lev); + return (-RT_ENOMEM); + } + + /* Tag the first descriptor as the start of the packet. */ + bFirst = true; + pDesc->Desc.ui32CtrlStatus = DES0_TX_CTRL_FIRST_SEG; + + /* Here, we know we can send the packet so write it to the descriptors */ + pBuf = p; + + while(ui32NumChained) + { + /* Get a pointer to the descriptor we will write next. */ + pDesc = &(pIF->pTxDescList->pDescriptors[pIF->pTxDescList->ui32Write]); + + /* Fill in the buffer pointer and length */ + pDesc->Desc.ui32Count = (uint32_t)pBuf->len; + pDesc->Desc.pvBuffer1 = pBuf->payload; + + /* Tag the first descriptor as the start of the packet. */ + if(bFirst) + { + bFirst = false; + pDesc->Desc.ui32CtrlStatus = DES0_TX_CTRL_FIRST_SEG; + } + else + { + pDesc->Desc.ui32CtrlStatus = 0; + } + + pDesc->Desc.ui32CtrlStatus |= (DES0_TX_CTRL_IP_ALL_CKHSUMS | + DES0_TX_CTRL_CHAINED); + + /* Decrement our descriptor counter, move on to the next buffer in the + * pbuf chain. */ + ui32NumChained--; + pBuf = pBuf->next; + + /* Update the descriptor list write index. */ + pIF->pTxDescList->ui32Write++; + if(pIF->pTxDescList->ui32Write == NUM_TX_DESCRIPTORS) + { + pIF->pTxDescList->ui32Write = 0; + } + + /* If this is the last descriptor, mark it as the end of the packet. */ + if(!ui32NumChained) + { + pDesc->Desc.ui32CtrlStatus |= (DES0_TX_CTRL_LAST_SEG | + DES0_TX_CTRL_INTERRUPT); + + /* Tag the descriptor with the original pbuf pointer. */ + pDesc->pBuf = p; + } + else + { + /* Set the lsb of the pbuf pointer. We use this as a signal that + * we should not free the pbuf when we are walking the descriptor + * list while processing the transmit interrupt. We only free the + * pbuf when processing the last descriptor used to transmit its + * chain. + */ + pDesc->pBuf = (struct pbuf *)((uint32_t)p + 1); + } + + DRIVER_STATS_INC(TXBufQueuedCount); + + /* Hand the descriptor over to the hardware. */ + pDesc->Desc.ui32CtrlStatus |= DES0_TX_CTRL_OWN; + } + + /* Tell the transmitter to start (in case it had stopped). */ + EMACTxDMAPollDemand(EMAC0_BASE); + + /* Update lwIP statistics */ + LINK_STATS_INC(link.xmit); + + SYS_ARCH_UNPROTECT(lev); + + return(RT_EOK); +} + +/** + * This function will process all transmit descriptors and free pbufs attached + * to any that have been transmitted since we last checked. + * + * This function is called only from the Ethernet interrupt handler. + * + * @param netif the lwip network interface structure for this ethernetif + * @return None. + */ +static void +tivaif_process_transmit(tStellarisIF *pIF) +{ + tDescriptorList *pDescList; + uint32_t ui32NumDescs; + + /* Get a pointer to the transmit descriptor list. */ + pDescList = pIF->pTxDescList; + + /* Walk the list until we have checked all descriptors or we reach the + * write pointer or find a descriptor that the hardware is still working + * on. + */ + for(ui32NumDescs = 0; ui32NumDescs < pDescList->ui32NumDescs; ui32NumDescs++) + { + /* Has the buffer attached to this descriptor been transmitted? */ + if(pDescList->pDescriptors[pDescList->ui32Read].Desc.ui32CtrlStatus & + DES0_TX_CTRL_OWN) + { + /* No - we're finished. */ + break; + } + + /* Does this descriptor have a buffer attached to it? */ + if(pDescList->pDescriptors[pDescList->ui32Read].pBuf) + { + /* Yes - free it if it's not marked as an intermediate pbuf */ + if(!((uint32_t)(pDescList->pDescriptors[pDescList->ui32Read].pBuf) & 1)) + { + pbuf_free(pDescList->pDescriptors[pDescList->ui32Read].pBuf); + DRIVER_STATS_INC(TXBufFreedCount); + } + pDescList->pDescriptors[pDescList->ui32Read].pBuf = NULL; + } + else + { + /* If the descriptor has no buffer, we are finished. */ + break; + } + + /* Move on to the next descriptor. */ + pDescList->ui32Read++; + if(pDescList->ui32Read == pDescList->ui32NumDescs) + { + pDescList->ui32Read = 0; + } + } +} + +/** + * This function will process all receive descriptors that contain newly read + * data and pass complete frames up the lwIP stack as they are found. The + * timestamp of the packet will be placed into the pbuf structure if PTPD is + * enabled. + * + * This function is called only from the Ethernet interrupt handler. + * + * @param psNetif the lwip network interface structure for this ethernetif + * @return None. + */ +static void +tivaif_receive(net_device_t dev) +{ + tDescriptorList *pDescList; + tStellarisIF *pIF; + struct pbuf *pBuf; + uint32_t ui32DescEnd; + + /* Get a pointer to our state data */ + pIF = dev->dma_if; + + /* Get a pointer to the receive descriptor list. */ + pDescList = pIF->pRxDescList; + + /* Start with a NULL pbuf so that we don't try to link chain the first + * time round. + */ + pBuf = NULL; + + /* Determine where we start and end our walk of the descriptor list */ + ui32DescEnd = pDescList->ui32Read ? (pDescList->ui32Read - 1) : (pDescList->ui32NumDescs - 1); + + /* Step through the descriptors that are marked for CPU attention. */ + while(pDescList->ui32Read != ui32DescEnd) + { + /* Does the current descriptor have a buffer attached to it? */ + if(pDescList->pDescriptors[pDescList->ui32Read].pBuf) + { + /* Yes - determine if the host has filled it yet. */ + if(pDescList->pDescriptors[pDescList->ui32Read].Desc.ui32CtrlStatus & + DES0_RX_CTRL_OWN) + { + /* The DMA engine still owns the descriptor so we are finished */ + break; + } + + DRIVER_STATS_INC(RXBufReadCount); + + /* If this descriptor contains the end of the packet, fix up the + * buffer size accordingly. + */ + if(pDescList->pDescriptors[pDescList->ui32Read].Desc.ui32CtrlStatus & + DES0_RX_STAT_LAST_DESC) + { + /* This is the last descriptor for the frame so fix up the + * length. It is safe for us to modify the internal fields + * directly here (rather than calling pbuf_realloc) since we + * know each of these pbufs is never chained. + */ + pDescList->pDescriptors[pDescList->ui32Read].pBuf->len = + (pDescList->pDescriptors[pDescList->ui32Read].Desc.ui32CtrlStatus & + DES0_RX_STAT_FRAME_LENGTH_M) >> + DES0_RX_STAT_FRAME_LENGTH_S; + pDescList->pDescriptors[pDescList->ui32Read].pBuf->tot_len = + pDescList->pDescriptors[pDescList->ui32Read].pBuf->len; + } + + if(pBuf) + { + /* Link this pbuf to the last one we looked at since this buffer + * is a continuation of an existing frame (split across mui32tiple + * pbufs). Note that we use pbuf_cat() here rather than + * pbuf_chain() since we don't want to increase the reference + * count of either pbuf - we only want to link them together. + */ + pbuf_cat(pBuf, pDescList->pDescriptors[pDescList->ui32Read].pBuf); + pDescList->pDescriptors[pDescList->ui32Read].pBuf = pBuf; + } + + /* Remember the buffer associated with this descriptor. */ + pBuf = pDescList->pDescriptors[pDescList->ui32Read].pBuf; + + /* Is this the last descriptor for the current frame? */ + if(pDescList->pDescriptors[pDescList->ui32Read].Desc.ui32CtrlStatus & + DES0_RX_STAT_LAST_DESC) + { + /* Yes - does the frame contain errors? */ + if(pDescList->pDescriptors[pDescList->ui32Read].Desc.ui32CtrlStatus & + DES0_RX_STAT_ERR) + { + /* This is a bad frame so discard it and update the relevant + * statistics. + */ + LWIP_DEBUGF(NETIF_DEBUG, ("tivaif_receive: packet error\n")); + pbuf_free(pBuf); + LINK_STATS_INC(link.drop); + DRIVER_STATS_INC(RXPacketErrCount); + } + else + { + /* This is a good frame so pass it up the stack. */ + LINK_STATS_INC(link.recv); + DRIVER_STATS_INC(RXPacketReadCount); + +#if LWIP_PTPD + /* Place the timestamp in the PBUF if PTPD is enabled */ + pBuf->time_s = + pDescList->pDescriptors[pDescList->ui32Read].Desc.ui32IEEE1588TimeHi; + pBuf->time_ns = + pDescList->pDescriptors[pDescList->ui32Read].Desc.ui32IEEE1588TimeLo; +#endif + +#if NO_SYS + if(ethernet_input(pBuf, psNetif) != RT_EOK) + { +#else + //if(tcpip_input(pBuf, psNetif) != RT_EOK) + if((rt_mb_send(dev->rx_pbuf_mb, (rt_uint32_t)pBuf) != RT_EOK) || + (eth_device_ready(&(dev->parent)) != RT_EOK)) + { +#endif + /* drop the packet */ + LWIP_DEBUGF(NETIF_DEBUG, ("tivaif_input: input error\n")); + pbuf_free(pBuf); + + /* Adjust the link statistics */ + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + DRIVER_STATS_INC(RXPacketCBErrCount); + } + + /* We're finished with this packet so make sure we don't try + * to link the next buffer to it. + */ + pBuf = NULL; + } + } + } + + /* Allocate a new buffer for this descriptor */ + pDescList->pDescriptors[pDescList->ui32Read].pBuf = pbuf_alloc(PBUF_RAW, + PBUF_POOL_BUFSIZE, + PBUF_POOL); + pDescList->pDescriptors[pDescList->ui32Read].Desc.ui32Count = + DES1_RX_CTRL_CHAINED; + if(pDescList->pDescriptors[pDescList->ui32Read].pBuf) + { + /* We got a buffer so fill in the payload pointer and size. */ + pDescList->pDescriptors[pDescList->ui32Read].Desc.pvBuffer1 = + pDescList->pDescriptors[pDescList->ui32Read].pBuf->payload; + pDescList->pDescriptors[pDescList->ui32Read].Desc.ui32Count |= + (pDescList->pDescriptors[pDescList->ui32Read].pBuf->len << + DES1_RX_CTRL_BUFF1_SIZE_S); + + /* Give this descriptor back to the hardware */ + pDescList->pDescriptors[pDescList->ui32Read].Desc.ui32CtrlStatus = + DES0_RX_CTRL_OWN; + } + else + { + LWIP_DEBUGF(NETIF_DEBUG, ("tivaif_receive: pbuf_alloc error\n")); + + pDescList->pDescriptors[pDescList->ui32Read].Desc.pvBuffer1 = 0; + + /* Update the stats to show we coui32dn't allocate a pbuf. */ + DRIVER_STATS_INC(RXNoBufCount); + LINK_STATS_INC(link.memerr); + + /* Stop parsing here since we can't leave a broken descriptor in + * the chain. + */ + break; + } + + /* Move on to the next descriptor in the chain, taking care to wrap. */ + pDescList->ui32Read++; + if(pDescList->ui32Read == pDescList->ui32NumDescs) + { + pDescList->ui32Read = 0; + } + } +} + +/** + * Process interrupts from the PHY. + * + * should be called from the Stellaris Ethernet Interrupt Handler. This + * function will read packets from the Stellaris Ethernet fifo and place them + * into a pbuf queue. If the transmitter is idle and there is at least one packet + * on the transmit queue, it will place it in the transmit fifo and start the + * transmitter. + * + */ +void +tivaif_process_phy_interrupt(net_device_t dev) +{ + uint16_t ui16Val, ui16Status; + uint32_t ui32Config, ui32Mode, ui32RxMaxFrameSize; + + /* Read the PHY interrupt status. This clears all interrupt sources. + * Note that we are only enabling sources in EPHY_MISR1 so we don't + * read EPHY_MISR2. + */ + ui16Val = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1); + + /* + * Dummy read PHY REG EPHY_BMSR, it will force update the EPHY_STS register + */ + EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_BMSR); + /* Read the current PHY status. */ + ui16Status = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_STS); + + /* Has the link status changed? */ + if(ui16Val & EPHY_MISR1_LINKSTAT) + { + /* Is link up or down now? */ + if(ui16Status & EPHY_STS_LINK) + { + /* Tell lwIP the link is up. */ +#if NO_SYS + netif_set_link_up(psNetif); +#else + //tcpip_callback((tcpip_callback_fn)netif_set_link_up, psNetif); + eth_device_linkchange(&(dev->parent), RT_TRUE); +#endif + + /* In this case we drop through since we may need to reconfigure + * the MAC depending upon the speed and half/fui32l-duplex settings. + */ + } + else + { + /* Tell lwIP the link is down */ +#if NO_SYS + netif_set_link_down(psNetif); +#else + //tcpip_callback((tcpip_callback_fn)netif_set_link_down, psNetif); + eth_device_linkchange(&(dev->parent), RT_FALSE); +#endif + } + } + + /* Has the speed or duplex status changed? */ + if(ui16Val & (EPHY_MISR1_SPEED | EPHY_MISR1_SPEED | EPHY_MISR1_ANC)) + { + /* Get the current MAC configuration. */ + EMACConfigGet(EMAC0_BASE, &ui32Config, &ui32Mode, + &ui32RxMaxFrameSize); + + /* What speed is the interface running at now? + */ + if(ui16Status & EPHY_STS_SPEED) + { + /* 10Mbps is selected */ + ui32Config &= ~EMAC_CONFIG_100MBPS; + } + else + { + /* 100Mbps is selected */ + ui32Config |= EMAC_CONFIG_100MBPS; + } + + /* Are we in fui32l- or half-duplex mode? */ + if(ui16Status & EPHY_STS_DUPLEX) + { + /* Fui32l duplex. */ + ui32Config |= EMAC_CONFIG_FULL_DUPLEX; + } + else + { + /* Half duplex. */ + ui32Config &= ~EMAC_CONFIG_FULL_DUPLEX; + } + + /* Reconfigure the MAC */ + EMACConfigSet(EMAC0_BASE, ui32Config, ui32Mode, ui32RxMaxFrameSize); + } +} + +/** + * Process tx and rx packets at the low-level interrupt. + * + * should be called from the Stellaris Ethernet Interrupt Handler. This + * function will read packets from the Stellaris Ethernet fifo and place them + * into a pbuf queue. If the transmitter is idle and there is at least one packet + * on the transmit queue, it will place it in the transmit fifo and start the + * transmitter. + * + */ +void +tivaif_interrupt(net_device_t dev, uint32_t ui32Status) +{ + + /* Update our debug interrupt counters. */ + if(ui32Status & EMAC_INT_NORMAL_INT) + { + g_ui32NormalInts++; + } + + if(ui32Status & EMAC_INT_ABNORMAL_INT) + { + g_ui32AbnormalInts++; + } + + /* Is this an interrupt from the PHY? */ + if(ui32Status & EMAC_INT_PHY) + { + tivaif_process_phy_interrupt(dev); + } + + /* Process the transmit DMA list, freeing any buffers that have been + * transmitted since our last interrupt. + */ + if(ui32Status & EMAC_INT_TRANSMIT) + { + tivaif_process_transmit(dev->dma_if); + } + + /** + * Process the receive DMA list and pass all successfui32ly received packets + * up the stack. We also call this function in cases where the receiver has + * stalled due to missing buffers since the receive function will attempt to + * allocate new pbufs for descriptor entries which have none. + */ + if(ui32Status & (EMAC_INT_RECEIVE | EMAC_INT_RX_NO_BUFFER | + EMAC_INT_RX_STOPPED)) + { + tivaif_receive(dev); + } +} + +#if NETIF_DEBUG +/* Print an IP header by using LWIP_DEBUGF + * @param p an IP packet, p->payload pointing to the IP header + */ +void +tivaif_debug_print(struct pbuf *p) +{ + struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; + u16_t *plen = (u16_t *)p->payload; + + LWIP_DEBUGF(NETIF_DEBUG, ("ETH header:\n")); + LWIP_DEBUGF(NETIF_DEBUG, ("Packet Length:%5"U16_F" \n",*plen)); + LWIP_DEBUGF(NETIF_DEBUG, ("Destination: %02"X8_F"-%02"X8_F"-%02"X8_F"-%02"X8_F"-%02"X8_F"-%02"X8_F"\n", + ethhdr->dest.addr[0], + ethhdr->dest.addr[1], + ethhdr->dest.addr[2], + ethhdr->dest.addr[3], + ethhdr->dest.addr[4], + ethhdr->dest.addr[5])); + LWIP_DEBUGF(NETIF_DEBUG, ("Source: %02"X8_F"-%02"X8_F"-%02"X8_F"-%02"X8_F"-%02"X8_F"-%02"X8_F"\n", + ethhdr->src.addr[0], + ethhdr->src.addr[1], + ethhdr->src.addr[2], + ethhdr->src.addr[3], + ethhdr->src.addr[4], + ethhdr->src.addr[5])); + LWIP_DEBUGF(NETIF_DEBUG, ("Packet Type:0x%04"U16_F" \n", ethhdr->type)); +} +#endif /* NETIF_DEBUG */ + +void lwIPEthernetIntHandler(void) +{ + uint32_t ui32Status; +#ifdef DEF_INT_TEMPSTAMP + uint32_t ui32TimerStatus; +#endif + // + // Read and Clear the interrupt. + // + ui32Status = MAP_EMACIntStatus(EMAC0_BASE, true); + + // + // If the interrupt really came from the Ethernet and not our + // timer, clear it. + // + if(ui32Status) + { + MAP_EMACIntClear(EMAC0_BASE, ui32Status); + } +#ifdef DEF_INT_TEMPSTAMP + // + // Check to see whether a hardware timer interrupt has been reported. + // + if(ui32Status & EMAC_INT_TIMESTAMP) + { + // + // Yes - read and clear the timestamp interrupt status. + // + ui32TimerStatus = EMACTimestampIntStatus(EMAC0_BASE); + + // + // If a timer interrupt handler has been registered, call it. + // + if(g_pfnTimerHandler) + { + g_pfnTimerHandler(EMAC0_BASE, ui32TimerStatus); + } + } +#endif + // + // The handling of the interrupt is different based on the use of a RTOS. + // + + // + // No RTOS is being used. If a transmit/receive interrupt was active, + // run the low-level interrupt handler. + // + if(ui32Status) + { + tivaif_interrupt(eth_dev, ui32Status); + } + + // + // Service the lwIP timers. + // + //lwIPServiceTimers(); +} + + +// OUI:00-12-37 (hex) Texas Instruments, only for test +static int tiva_eth_mac_addr_init(void) +{ + int retVal =0; + uint32_t ulUser[2]; + uint8_t mac_addr[6]; + + MAP_FlashUserGet(&ulUser[0], &ulUser[1]); + if((ulUser[0] == 0xffffffff) || (ulUser[1] == 0xffffffff)) + { + rt_kprintf("Fail to get mac address from eeprom.\n"); + rt_kprintf("Using default mac address\n"); + // OUI:00-12-37 (hex) Texas Instruments, only for test + // Configure the hardware MAC address + ulUser[0] = 0x00371200; + ulUser[1] = 0x00563412; + //FlashUserSet(ulUser0, ulUser1); + retVal =-1; + } + + + //Convert the 24/24 split MAC address from NV ram into a 32/16 split MAC + //address needed to program the hardware registers, then program the MAC + //address into the Ethernet Controller registers. + + mac_addr[0] = ((ulUser[0] >> 0) & 0xff); + mac_addr[1] = ((ulUser[0] >> 8) & 0xff); + mac_addr[2] = ((ulUser[0] >> 16) & 0xff); + mac_addr[3] = ((ulUser[1] >> 0) & 0xff); + mac_addr[4] = ((ulUser[1] >> 8) & 0xff); + mac_addr[5] = ((ulUser[1] >> 16) & 0xff); + + // + // Program the hardware with its MAC address (for filtering). + // + MAP_EMACAddrSet(EMAC0_BASE, 0, mac_addr); + return retVal; +} + +#ifndef EMAC_PHY_CONFIG +#define EMAC_PHY_CONFIG (EMAC_PHY_TYPE_INTERNAL | \ + EMAC_PHY_INT_MDIX_EN | \ + EMAC_PHY_AN_100B_T_FULL_DUPLEX) +#endif + + void tiva_eth_lowlevel_init(void) +{ + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); + // + // PF1/PK4/PK6 are used for Ethernet LEDs. + // + MAP_GPIOPinConfigure(GPIO_PF0_EN0LED0); + MAP_GPIOPinConfigure(GPIO_PF4_EN0LED1); + GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_0); + GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_4); + + // + // Enable the ethernet peripheral. + // + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0); + MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0); + // + // Enable the internal PHY if it's present and we're being + // asked to use it. + // + if((EMAC_PHY_CONFIG & EMAC_PHY_TYPE_MASK) == EMAC_PHY_TYPE_INTERNAL) + { + // + // We've been asked to configure for use with the internal + // PHY. Is it present? + // + if(SysCtlPeripheralPresent(SYSCTL_PERIPH_EPHY0)) + { + // + // Yes - enable and reset it. + // + MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0); + MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0); + } + else + { + // + // Internal PHY is not present on this part so hang here. + // + rt_kprintf("Internal PHY is not present on this part.\n"); + while(1) + { + } + } + } + + // + // Wait for the MAC to come out of reset. + // + while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0)) + { + } + + // + // Configure for use with whichever PHY the user requires. + // + MAP_EMACPHYConfigSet(EMAC0_BASE, EMAC_PHY_CONFIG); + + // + // Initialize the MAC and set the DMA mode. + // + MAP_EMACInit(EMAC0_BASE, 120000000, //system clock = 120MHz + EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED, + 4, 4, 0); + + // + // Set MAC configuration options. + // + MAP_EMACConfigSet(EMAC0_BASE, (EMAC_CONFIG_FULL_DUPLEX | + EMAC_CONFIG_CHECKSUM_OFFLOAD | + EMAC_CONFIG_7BYTE_PREAMBLE | + EMAC_CONFIG_IF_GAP_96BITS | + EMAC_CONFIG_USE_MACADDR0 | + EMAC_CONFIG_SA_FROM_DESCRIPTOR | + EMAC_CONFIG_BO_LIMIT_1024), + (EMAC_MODE_RX_STORE_FORWARD | + EMAC_MODE_TX_STORE_FORWARD | + EMAC_MODE_TX_THRESHOLD_64_BYTES | + EMAC_MODE_RX_THRESHOLD_64_BYTES), 0); + + EMACIntRegister(EMAC0_BASE, lwIPEthernetIntHandler); + +} + +static rt_err_t eth_dev_init(rt_device_t device) +{ + net_device_t net_dev = (net_device_t)device; + struct netif *psNetif = (net_dev->parent.netif); + + LWIP_ASSERT("psNetif != NULL", (psNetif != NULL)); + +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + psNetif->hostname = "t4mc"; +#endif /* LWIP_NETIF_HOSTNAME */ + + /* + * Initialize the snmp variables and counters inside the struct netif. + * The last argument should be replaced with your link speed, in units + * of bits per second. + */ + //NETIF_INIT_SNMP(psNetif, snmp_ifType_ethernet_csmacd, 1000000); + + net_dev->dma_if = &g_StellarisIFData; + + /* Remember our MAC address. */ + g_StellarisIFData.ethaddr = (struct eth_addr *)&(psNetif->hwaddr[0]); + + /* Initialize the hardware */ + tivaif_hwinit(psNetif); + return RT_EOK; +} + +/* control the interface */ +static rt_err_t eth_dev_control(rt_device_t dev, rt_uint8_t cmd, void *args) +{ + switch(cmd) + { + case NIOCTL_GADDR: + /* get mac address */ + if(args) + MAP_EMACAddrGet(EMAC0_BASE, 0, (uint8_t*)args); + else + return -RT_ERROR; + break; + + default : + break; + } + + return RT_EOK; +} + +/* Open the interface */ +static rt_err_t eth_dev_open(rt_device_t dev, rt_uint16_t oflag) +{ + return RT_EOK; +} + +/* Close the interface */ +static rt_err_t eth_dev_close(rt_device_t dev) +{ + return RT_EOK; +} + +/* Read */ +static rt_size_t eth_dev_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + rt_set_errno(-RT_ENOSYS); + return 0; +} + +/* Write */ +static rt_size_t eth_dev_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) +{ + rt_set_errno(-RT_ENOSYS); + return 0; +} + +static rt_err_t eth_dev_tx(rt_device_t dev, struct pbuf *p) +{ + return tivaif_transmit((net_device_t)dev, p); +} + +static struct pbuf* eth_dev_rx(rt_device_t dev) +{ + rt_err_t result; + rt_uint32_t temp =0; + net_device_t net_dev = (net_device_t)dev; + result = rt_mb_recv(net_dev->rx_pbuf_mb, &temp, RT_WAITING_NO); + + return (result == RT_EOK)? (struct pbuf*)temp : RT_NULL; +} + +rt_err_t rt_hw_tiva_eth_init(void) +{ + rt_err_t result; + + /* Clock GPIO and etc */ + tiva_eth_lowlevel_init(); + tiva_eth_mac_addr_init(); + + /* init rt-thread device interface */ + eth_dev->parent.parent.init = eth_dev_init; + eth_dev->parent.parent.open = eth_dev_open; + eth_dev->parent.parent.close = eth_dev_close; + eth_dev->parent.parent.read = eth_dev_read; + eth_dev->parent.parent.write = eth_dev_write; + eth_dev->parent.parent.control = eth_dev_control; + eth_dev->parent.eth_rx = eth_dev_rx; + eth_dev->parent.eth_tx = eth_dev_tx; + + result = rt_mb_init(ð_rx_pbuf_mb, "epbuf", + &rx_pbuf_mb_pool[0], sizeof(rx_pbuf_mb_pool)/4, + RT_IPC_FLAG_FIFO); + RT_ASSERT(result == RT_EOK); + eth_dev->rx_pbuf_mb = ð_rx_pbuf_mb; + + + result = eth_device_init(&(eth_dev->parent), "e0"); + return result; +} + +#ifdef RT_USING_FINSH +#include "finsh.h" +void PHY_Read(uint8_t addr) +{ + uint16_t data = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, addr); + rt_kprintf("R PHY_REG[0x%02X] = 0x%04X\n", addr, data); +} +FINSH_FUNCTION_EXPORT(PHY_Read, (add)); + +void PHY_Write(uint8_t addr , uint16_t data) +{ + EMACPHYWrite(EMAC0_BASE, PHY_PHYS_ADDR, addr, data); + rt_kprintf("W PHY_REG[0x%02X] = 0x%04X\n", addr, data); +} +FINSH_FUNCTION_EXPORT(PHY_Write, (add, data)); + +void PHY_SetAdd(uint8_t addr0, uint8_t addr1, uint8_t addr2, + uint8_t addr3, uint8_t addr4, uint8_t addr5) +{ + uint32_t ulUser[2]; + ulUser[0] = (((addr2<<8)|addr1)<<8)|addr0; + ulUser[1] = (((addr5<<8)|addr4)<<8)|addr3; + + MAP_FlashUserSet(ulUser[0], ulUser[1]); + MAP_FlashUserSave(); + rt_kprintf("Save to EEPROM. please reboot."); +} +FINSH_FUNCTION_EXPORT(PHY_SetAdd, (add0-add5)); +#endif //RT_USING_FINSH diff --git a/bsp/tm4c129x/drivers/drv_eth.h b/bsp/tm4c129x/drivers/drv_eth.h new file mode 100644 index 0000000000000000000000000000000000000000..5f27139d5f6fcb483d4056b391d076e1ce0c3e8a --- /dev/null +++ b/bsp/tm4c129x/drivers/drv_eth.h @@ -0,0 +1,20 @@ +/* + * File : drv_eth.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2009-2013 RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2014-07-25 ArdaFu Port to TM4C129X + */ + +#ifndef __TIVA_ETH_H__ +#define __TIVA_ETH_H__ + +rt_err_t rt_hw_tiva_eth_init(void); + +#endif diff --git a/bsp/tm4c129x/libraries/driverlib/emac.c b/bsp/tm4c129x/libraries/driverlib/emac.c index dcedfdf657d4c10d109304dbc8ac7bcd24f460e5..a9e5d14a65c6a17a14f9aacce4bb07bdadf95e41 100644 --- a/bsp/tm4c129x/libraries/driverlib/emac.c +++ b/bsp/tm4c129x/libraries/driverlib/emac.c @@ -2917,6 +2917,7 @@ EMACPHYRead(uint32_t ui32Base, uint8_t ui8PhyAddr, uint8_t ui8RegAddr) // HWREG(ui32Base + EMAC_O_MIIADDR) = ((HWREG(ui32Base + EMAC_O_MIIADDR) & EMAC_MIIADDR_CR_M) | + EMAC_MIIADDR_CR_100_150 | (ui8RegAddr << EMAC_MIIADDR_MII_S) | (ui8PhyAddr << EMAC_MIIADDR_PLA_S) | EMAC_MIIADDR_MIIB);