More Kinetis ENET logic

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3888 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2011-08-17 03:39:43 +00:00
parent ec3d3c66b1
commit 94a3c61edb
4 changed files with 175 additions and 133 deletions

View File

@ -190,6 +190,14 @@
# define CONFIG_ENET_NBUFFERS 8
#endif
#ifndef CONFIG_ENET_PHYADDR
# define CONFIG_ENET_PHYADDR 1
#endif
#ifndef CONFIG_ENET_NETHIFS
# define CONFIG_ENET_NETHIFS 1
#endif
/* EMAC Default Interrupt Priorities */
#ifndef CONFIG_KINETIS_EMACTMR_PRIO

View File

@ -50,6 +50,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/mii.h>
#include <net/uip/uip.h>
#include <net/uip/uip-arp.h>
@ -66,16 +67,12 @@
* Definitions
****************************************************************************/
/* CONFIG_KINETIS_NETHIFS determines the number of physical interfaces
/* CONFIG_ENET_NETHIFS determines the number of physical interfaces
* that will be supported.
*/
#ifndef CONFIG_KINETIS_NETHIFS
# define CONFIG_KINETIS_NETHIFS 1
#endif
#ifdef CONFIG_ENET_LEGACYDESC
# error "Legacy descriptor types are not supported"
#if CONFIG_ENET_NETHIFS != 1
# error "CONFIG_ENET_NETHIFS must be one for now"
#endif
/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per second */
@ -86,7 +83,17 @@
/* TX timeout = 1 minute */
#define KINETIS_TXTIMEOUT (60*CLK_TCK)
#define MII_TIMEOUT (0x1ffff)
#define MII_MAXPOLLS (0x1ffff)
#define LINK_WAITUS (500*1000)
/* PHY hardware specifics. This was copied from the FreeScale code examples.
* this is a vendor specific register and bit settings. I really should
* do the research and find out what this really is.
*/
#define PHY_STATUS (0x1f)
#define PHY_DUPLEX_STATUS (4 << 2)
#define PHY_SPEED_STATUS (1 << 2)
/* Estimate the hold time to use based on the peripheral (bus) clock.
* BUS_FREQ = 48Mhz, hold time clocks = (2*48)/5 + 1 = 19.
@ -141,7 +148,7 @@ struct kinetis_driver_s
* Private Data
****************************************************************************/
static struct kinetis_driver_s g_enet[CONFIG_KINETIS_NETHIFS];
static struct kinetis_driver_s g_enet[CONFIG_ENET_NETHIFS];
/****************************************************************************
* Private Function Prototypes
@ -166,12 +173,6 @@ static int kinetis_uiptxpoll(struct uip_driver_s *dev);
static void kinetis_receive(FAR struct kinetis_driver_s *priv);
static void kinetis_txdone(FAR struct kinetis_driver_s *priv);
static int kinetis_interrupt(int irq, FAR void *context);
#if 0
static int kinetis_tmrinterrupt(int irq, FAR void *context);
#endif
static int kinetis_txrinterrupt(int irq, FAR void *context);
static int kinetis_rxrinterrupt(int irq, FAR void *context);
static int kinetis_miscinterrupt(int irq, FAR void *context);
/* Watchdog timer expirations */
@ -424,40 +425,13 @@ static void kinetis_txdone(FAR struct kinetis_driver_s *priv)
}
/****************************************************************************
* Function: kinetis_tmrinterrupt
* Function: kinetis_interrupt
*
* Description:
* Ethernet MAC IEEE 1588 timer interrupt handler
*
* Parameters:
* irq - Number of the IRQ that generated the interrupt
* context - Interrupt register state save info (architecture-specific)
*
* Returned Value:
* OK on success
*
* Assumptions:
*
****************************************************************************/
#if 0
static int kinetis_tmrinterrupt(int irq, FAR void *context)
{
register FAR struct kinetis_driver_s *priv = &g_enet[0];
/* Get and clear interrupt status bits */
/* Handle interrupts according to status bit settings */
#warning "Missing logic"
return OK;
}
#endif
/****************************************************************************
* Function: kinetis_txinterrupt
*
* Description:
* Ethernet MAC transmit interrupt handler
* Three interrupt sources will vector this this function:
* 1. Ethernet MAC transmit interrupt handler
* 2. Ethernet MAC receive interrupt handler
* 3.
*
* Parameters:
* irq - Number of the IRQ that generated the interrupt
@ -470,82 +444,60 @@ static int kinetis_tmrinterrupt(int irq, FAR void *context)
*
****************************************************************************/
static int kinetis_txinterrupt(int irq, FAR void *context)
static int kinetis_interrupt(int irq, FAR void *context)
{
register FAR struct kinetis_driver_s *priv = &g_enet[0];
uint32_t pending;
/* Get and clear interrupt status bits */
/* Get the set of unmasked, pending interrupt. */
/* Handle interrupts according to status bit settings */
#warning "Missing logic"
pending = getreg32(KINETIS_ENET_EIR) & getreg32(KINETIS_ENET_EIMR);
/* Check if a packet transmission just completed. If so, call kinetis_txdone.
* This may disable further Tx interrupts if there are no pending
* tansmissions.
*/
/* Clear the pending interrupts */
kinetis_txdone(priv);
putreg32(pending, KINETIS_ENET_EIR);
return OK;
}
/* Check for the receipt of a packet */
/****************************************************************************
* Function: kinetis_rxinterrupt
*
* Description:
* Hardware interrupt handler
*
* Parameters:
* irq - Number of the IRQ that generated the interrupt
* context - Interrupt register state save info (architecture-specific)
*
* Returned Value:
* OK on success
*
* Assumptions:
*
****************************************************************************/
if ((pending & ENET_INT_RXF) != 0)
{
/* A packet has been received, call kinetis_receive() to handle the packet */
static int kinetis_rxinterrupt(int irq, FAR void *context)
{
register FAR struct kinetis_driver_s *priv = &g_enet[0];
kinetis_receive(priv);
}
/* Get and clear interrupt status bits */
/* Check if a packet transmission has completed */
/* Handle interrupts according to status bit settings */
#warning "Missing logic"
if ((pending & ENET_INT_TXF) != 0)
{
/* The Tx has completed. Mark the data pointer as NULL to indicate
* that the buffer is now free again.
*/
g_txdesc->data = NULL;
/* Check if we received an incoming packet, if so, call kinetis_receive() */
/* Call kinetis_txdone to handle the end of transfer even. NOTE that
* this may disable further Tx interrupts if there are no pending
* tansmissions.
*/
kinetis_receive(priv);
return OK;
}
kinetis_txdone(priv);
}
/****************************************************************************
* Function: kinetis_miscinterrupt
*
* Description:
* Ethernet MAC error and misc interrupt handler
*
* Parameters:
* irq - Number of the IRQ that generated the interrupt
* context - Interrupt register state save info (architecture-specific)
*
* Returned Value:
* OK on success
*
* Assumptions:
*
****************************************************************************/
/* Check for errors */
static int kinetis_miscinterrupt(int irq, FAR void *context)
{
register FAR struct kinetis_driver_s *priv = &g_enet[0];
if (pending &
(ENET_INT_UN | ENET_INT_RL | ENET_INT_LC | ENET_INT_EBERR |
ENET_INT_BABT | ENET_INT_BABR))
{
/* An error has occurred. Reinitialize all buffers. */
/* Get and clear interrupt status bits */
kinetis_initbuffers();
/* Indicate that there have been empty receive buffers produced */
/* Handle interrupts according to status bit settings */
#warning "Missing logic"
putreg32(ENET_RDAR, KINETIS_ENET_RDAR);
}
return OK;
}
@ -881,7 +833,7 @@ static int kinetis_writemii(struct kinetis_driver_s *priv, uint8_t phyaddr,
/* Wait for the transfer to complete */
for (timeout = 0; timeout < MII_TIMEOUT; timeout++)
for (timeout = 0; timeout < MII_MAXPOLLS; timeout++)
{
if ((getreg32(KINETIS_ENET_EIR) & ENET_INT_MII) != 0)
{
@ -891,7 +843,7 @@ static int kinetis_writemii(struct kinetis_driver_s *priv, uint8_t phyaddr,
/* Check for a timeout */
if(timeout == MII_TIMEOUT)
if(timeout == MII_MAXPOLLS)
{
return -ETIMEDOUT;
}
@ -939,7 +891,7 @@ static int kinetis_readmii(struct kinetis_driver_s *priv, uint8_t phyaddr,
/* Wait for the transfer to complete */
for (timeout = 0; timeout < MII_TIMEOUT; timeout++)
for (timeout = 0; timeout < MII_MAXPOLLS; timeout++)
{
if ((getreg32(KINETIS_ENET_EIR) & ENET_INT_MII) != 0)
{
@ -949,7 +901,7 @@ static int kinetis_readmii(struct kinetis_driver_s *priv, uint8_t phyaddr,
/* Check for a timeout */
if(timeout == MII_TIMEOUT)
if (timeout >= MII_MAXPOLLS)
{
return -ETIMEDOUT;
}
@ -982,7 +934,82 @@ static int kinetis_readmii(struct kinetis_driver_s *priv, uint8_t phyaddr,
static inline void kinetis_initphy(struct kinetis_driver_s *priv)
{
#warning "Missing logic"
uint32_t rcr;
uint32_t tcr;
uint16_t phydata;
/* Loop (potentially infinitely?) until we successfully communicate with
* the PHY.
*/
do
{
usleep(LINK_WAITUS);
phydata = 0xffff;
kinetis_readmii(priv, 0, CONFIG_ENET_PHYADDR, MII_PHYID1, &phydata);
}
while (phydata == 0xffff);
/* Start auto negotiation */
kinetis_writemii(priv, 0, CONFIG_ENET_PHYADDR, MII_MCR,
(MII_MCR_ANRESTART | MII_MCR_ANENABLE));
/* Wait (potentially forever) for auto negotiation to complete */
do
{
usleep(LINK_WAITUS);
kinetis_readmii(0, CONFIG_ENET_PHYADDR, MII_MSR, &phydata);
}
while ((phydata & MII_MSR_ANEGCOMPLETE) == 0);
/* When we get here we have a link - Find the negotiated speed and duplex. */
phydata = 0;
kinetis_readmii(0, CONFIG_ENET_PHYADDR, PHY_STATUS, &phydata);
/* Set up the transmit and receive contrel registers based on the
* configuration and the auto negotiation results.
*/
#if CONFIG_ENET_USEMII
rcr = ENET_RCR_MII_MODE | ENET_RCR_CRCFWD |
CONFIG_NET_BUFSIZE << ENET_RCR_MAX_FL_SHIFT;
#else
rcr = ENET_RCR_RMII_MODE | ENET_RCR_CRCFWD |
CONFIG_NET_BUFSIZE << ENET_RCR_MAX_FL_SHIFT;
#endif
tcr = 0
putreg32(rcr, KINETIS_ENET_RCR);
putreg32(tcr, KINETIS_ENET_TCR);
/* Setup half or full duplex */
if ((phydata & PHY_DUPLEX_STATUS) != 0)
{
/* Full duplex */
tcr |= ENET_TCR_FDEN;
}
else
{
/* Half duplex */
rcr |= ENET_RCR_DRT;
}
if ((phydata & PHY_SPEED_STATUS) != 0)
{
/* 10Mbps */
ENET_RCR |= ENET_RCR_RMII_10T;
}
putreg32(rcr, KINETIS_ENET_RCR);
putreg32(tcr, KINETIS_ENET_TCR);
}
/****************************************************************************
@ -1112,7 +1139,7 @@ int kinetis_initialize(int intf)
/* Get the interface structure associated with this interface number. */
DEBUGASSERT(inf < CONFIG_KINETIS_NETHIFS);
DEBUGASSERT(inf < CONFIG_ENET_NETHIFS);
priv = &g_enet[intf];
/* Enable the ENET clock */
@ -1192,7 +1219,7 @@ int kinetis_initialize(int intf)
/* Attach the Ethernet MAC transmit interrupt handler */
if (irq_attach(KINETIS_IRQ_EMACTX, kinetis_txinterrupt))
if (irq_attach(KINETIS_IRQ_EMACTX, kinetis_interrupt))
{
/* We could not attach the ISR to the interrupt */
@ -1201,7 +1228,7 @@ int kinetis_initialize(int intf)
/* Attach the Ethernet MAC receive interrupt handler */
if (irq_attach(KINETIS_IRQ_EMACRX, kinetis_rxinterrupt))
if (irq_attach(KINETIS_IRQ_EMACRX, kinetis_interrupt))
{
/* We could not attach the ISR to the interrupt */
@ -1210,13 +1237,20 @@ int kinetis_initialize(int intf)
/* Attach the Ethernet MAC error and misc interrupt handler */
if (irq_attach(KINETIS_IRQ_EMACMISC, kinetis_miscinterrupt))
if (irq_attach(KINETIS_IRQ_EMACMISC, kinetis_interrupt))
{
/* We could not attach the ISR to the interrupt */
return -EAGAIN;
}
/* Clear the Individual and Group Address Hash registers */
putreg32(0, KINETIS_ENET_IALR);
putreg32(0, KINETIS_ENET_IAUR);
putreg32(0, KINETIS_ENET_GALR);
putreg32(0, KINETIS_ENET_GAUR);
/* Configure the PHY */
kinetis_initphy(priv);

View File

@ -159,25 +159,24 @@
/* Register Bit Definitions *****************************************************************/
/* Interrupt Event Register, Interrupt Mask Register */
/* Bit 31: Reserved */
#define ENET_INT_BABR (1 << 30) /* Bit 30: Babbling Receive Error */
#define ENET_INT_BABT (1 << 29) /* Bit 29: Babbling Transmit Error */
#define ENET_INT_GRA (1 << 28) /* Bit 28: Graceful Stop Complete */
#define ENET_INT_TXF (1 << 27) /* Bit 27: Transmit Frame Interrupt */
#define ENET_INT_TXB (1 << 26) /* Bit 26: Transmit Buffer Interrupt */
#define ENET_INT_RXF (1 << 25) /* Bit 25: Receive Frame Interrupt */
#define ENET_INT_RXB (1 << 24) /* Bit 24: Receive Buffer Interrupt */
#define ENET_INT_MII (1 << 23) /* Bit 23: MII Interrupt */
#define ENET_INT_EBERR (1 << 22) /* Bit 22: Ethernet Bus Error */
#define ENET_INT_LC (1 << 21) /* Bit 21: Late Collision */
#define ENET_INT_RL (1 << 20) /* Bit 20: Collision Retry Limit */
#define ENET_INT_UN (1 << 19) /* Bit 19: Transmit FIFO underrun */
#define ENET_INT_PLR (1 << 18) /* Bit 18: Payload receive error */
#define ENET_INT_WAKEUP (1 << 17) /* Bit 17: Node wake-up request indication */
#define ENET_INT_TS_AVAIL (1 << 16) /* Bit 16: Transmit timestamp available */
#define ENET_INT_TS_TIMER (1 << 15) /* Bit 15: Timestamp timer */
/* Bits 0-14: Reserved */
#define ENET_INT_TS_TIMER (1 << 15) /* Bit 15: Timestamp timer */
#define ENET_INT_TS_AVAIL (1 << 16) /* Bit 16: Transmit timestamp available */
#define ENET_INT_WAKEUP (1 << 17) /* Bit 17: Node wake-up request indication */
#define ENET_INT_PLR (1 << 18) /* Bit 18: Payload receive error */
#define ENET_INT_UN (1 << 19) /* Bit 19: Transmit FIFO underrun */
#define ENET_INT_RL (1 << 20) /* Bit 20: Collision Retry Limit */
#define ENET_INT_LC (1 << 21) /* Bit 21: Late Collision */
#define ENET_INT_EBERR (1 << 22) /* Bit 22: Ethernet Bus Error */
#define ENET_INT_MII (1 << 23) /* Bit 23: MII Interrupt */
#define ENET_INT_RXB (1 << 24) /* Bit 24: Receive Buffer Interrupt */
#define ENET_INT_RXF (1 << 25) /* Bit 25: Receive Frame Interrupt */
#define ENET_INT_TXB (1 << 26) /* Bit 26: Transmit Buffer Interrupt */
#define ENET_INT_TXF (1 << 27) /* Bit 27: Transmit Frame Interrupt */
#define ENET_INT_GRA (1 << 28) /* Bit 28: Graceful Stop Complete */
#define ENET_INT_BABT (1 << 29) /* Bit 29: Babbling Transmit Error */
#define ENET_INT_BABR (1 << 30) /* Bit 30: Babbling Receive Error */
/* Bit 31: Reserved */
/* Receive Descriptor Active Register */
/* Bits 0-23: Reserved */
#define ENET_RDAR (1 << 24) /* Bit 24: Receive descriptor active */

View File

@ -560,6 +560,7 @@ TWR-K60N512-specific Configuration Options
CONFIG_ENET_NBUFFERS - Number of TX/RX buffers. The size of one
buffer is determined by CONFIG_NET_BUFSIZE. Default: 8
CONFIG_ENET_USEMII - Usee MII mode. Default: RMII mode.
CONFIG_ENET_PHYADDR - PHY address
Configurations
==============