Add initialization logic

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2638 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2010-04-30 01:43:46 +00:00
parent 5db45464f7
commit 338bbcd45a
2 changed files with 207 additions and 49 deletions

View File

@ -116,17 +116,25 @@
#define ENC_POLLTIMEOUT MSEC2TICK(50)
/* Packet Memory ************************************************************/
/* Packet memory layout */
#define PKTMEM_TX_START 0x0000 /* Start TX buffer at 0 */
#define PKTMEM_TX_ENDP1 0x0600 /* Allow TX buffer for one frame + */
#define PKTMEM_RX_START PKTMEM_TX_ENDP1 /* Followed by RX buffer */
#define PKTMEM_RX_END PKTMEM_END /* RX buffer goes to the end of SRAM */
/* Misc. Helper Macros ******************************************************/
#define enc_rdgreg(priv,ctrlreg) \
enc_rdgreg2(priv, ENC_RCR | GETADDR(ctrlreg))
#define enc_wdgreg(priv,ctrlreg,wrdata) \
enc_wdgreg2(priv, ENC_WCR | GETADDR(ctrlreg), wrdata)
#define enc_wrgreg(priv,ctrlreg,wrdata) \
enc_wrgreg2(priv, ENC_WCR | GETADDR(ctrlreg), wrdata)
#define enc_bfcgreg(priv,ctrlreg,clrbits) \
enc_wdgreg2(priv, ENC_BFC | GETADDR(ctrlreg), clrbits)
enc_wrgreg2(priv, ENC_BFC | GETADDR(ctrlreg), clrbits)
#define enc_bfsgreg(priv,ctrlreg,setbits) \
enc_wdgreg2(priv, ENC_BFS | GETADDR(ctrlreg), setbits)
enc_wrgreg2(priv, ENC_BFS | GETADDR(ctrlreg), setbits)
/* This is a helper pointer for accessing the contents of the Ethernet header */
@ -175,6 +183,7 @@ struct enc_driver_s
uint32_t txifs; /* TXIF completion events */
uint32_t txabrts; /* TXIF completions with ESTAT.TXABRT */
uint32_t txerifs; /* TXERIF error events */
uint32_t txtimeouts; /* S/W detected TX timeouts */
uint32_t rxerifs; /* RXERIF error evernts */
#endif
};
@ -203,7 +212,7 @@ static void enc_deselect(FAR struct spi_dev_s *spi);
/* SPI control register access */
static uint8_t enc_rdgreg2(FAR struct enc_driver_s *priv, uint8_t cmd);
static void enc_wdgreg2(FAR struct enc_driver_s *priv, uint8_t cmd,
static void enc_wrgreg2(FAR struct enc_driver_s *priv, uint8_t cmd,
uint8_t wrdata);
static void enc_setbank(FAR struct enc_driver_s *priv, uint8_t bank);
static uint8_t enc_rdbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg);
@ -257,7 +266,7 @@ static int enc_txavail(struct uip_driver_s *dev);
static void enc_pwrsave(FAR struct enc_driver_s *priv);
static void enc_pwrfull(FAR struct enc_driver_s *priv);
static void enc_setmacaddr(FAR struct enc_driver_s *priv);
static void enc_reset(FAR struct enc_driver_s *priv);
static int enc_reset(FAR struct enc_driver_s *priv);
/****************************************************************************
* Private Functions
@ -383,7 +392,7 @@ static uint8_t enc_rdgreg2(FAR struct enc_driver_s *priv, uint8_t cmd)
}
/****************************************************************************
* Function: enc_wdgreg2
* Function: enc_wrgreg2
*
* Description:
* Write to a global register (EIE, EIR, ESTAT, ECON2, or ECON1). The cmd
@ -391,7 +400,7 @@ static uint8_t enc_rdgreg2(FAR struct enc_driver_s *priv, uint8_t cmd)
*
****************************************************************************/
static void enc_wdgreg2(FAR struct enc_driver_s *priv, uint8_t cmd,
static void enc_wrgreg2(FAR struct enc_driver_s *priv, uint8_t cmd,
uint8_t wrdata)
{
FAR struct spi_dev_s *spi;
@ -706,6 +715,7 @@ static void enc_wrphy(FAR struct enc_driver_s *priv, uint8_t phyaddr,
static int enc_transmit(FAR struct enc_driver_s *priv)
{
/* Verify that the hardware is ready to send another packet */
#warning "Missing logic"
/* Increment statistics */
@ -758,6 +768,7 @@ static int enc_uiptxpoll(struct uip_driver_s *dev)
/* Check if there is room in the device to hold another packet. If not,
* return a non-zero value to terminate the poll.
*/
#warning "Missing logic"
}
/* If zero is returned, the polling will continue until all connections have
@ -1221,13 +1232,22 @@ static int enc_interrupt(int irq, FAR void *context)
static void enc_txtimeout(int argc, uint32_t arg, ...)
{
FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg;
int ret;
/* Increment statistics and dump debug info */
/* Then reset the hardware */
#ifdef CONFIG_ENC28J60_STATS
priv->txtimeouts++;
#endif
enc_reset(priv);
enc_setmacaddr(priv);
/* Then reset the hardware. Take the interface down, then bring it
* back up
*/
ret = enc_ifdown(&priv->dev);
DEBUGASSERT(ret == OK);
ret = enc_ifup(&priv->dev);
DEBUGASSERT(ret == OK);
/* Then poll uIP for new XMIT data */
@ -1286,6 +1306,7 @@ static void enc_polltimer(int argc, uint32_t arg, ...)
static int enc_ifup(struct uip_driver_s *dev)
{
FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private;
int ret;
ndbg("Bringing up: %d.%d.%d.%d\n",
dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff,
@ -1295,7 +1316,9 @@ static int enc_ifup(struct uip_driver_s *dev)
* the ENC28J80 is not in power save mode.
*/
enc_reset(priv);
ret = enc_reset(priv);
if (ret == OK)
{
enc_setmacaddr(priv);
enc_pwrfull(priv);
@ -1315,7 +1338,8 @@ static int enc_ifup(struct uip_driver_s *dev)
priv->bifup = true;
up_enable_irq(priv->irq);
return OK;
}
return ret;
}
/****************************************************************************
@ -1338,6 +1362,7 @@ static int enc_ifdown(struct uip_driver_s *dev)
{
FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private;
irqstate_t flags;
int ret;
/* Disable the Ethernet interrupt */
@ -1351,12 +1376,12 @@ static int enc_ifdown(struct uip_driver_s *dev)
/* Reset the device and leave in the power save state */
enc_reset(priv);
ret = enc_reset(priv);
enc_pwrsave(priv);
priv->bifup = false;
irqrestore(flags);
return OK;
return ret;
}
/****************************************************************************
@ -1445,8 +1470,7 @@ static void enc_pwrsave(FAR struct enc_driver_s *priv)
enc_waitbreg(priv, ENC_ECON1, ECON1_TXRTS, 0);
/* 4. Set ECON2.VRPS (if not already set). */
enc_bfsgreg(priv, ENC_ECON2, ECON2_VRPS);
/* enc_bfsgreg(priv, ENC_ECON2, ECON2_VRPS); <-- Set in enc_reset() */
/* 5. Enter Sleep by setting ECON2.PWRSV. */
@ -1543,9 +1567,129 @@ static void enc_setmacaddr(FAR struct enc_driver_s *priv)
*
****************************************************************************/
static void enc_reset(FAR struct enc_driver_s *priv)
static int enc_reset(FAR struct enc_driver_s *priv)
{
#warning "Missing logic"
uint8_t regval;
ndbg("Entry\n");
/* Configure SPI for the ENC28J60 */
enc_configspi(priv->spi);
/* Reset the ENC28J60 */
enc_wrgreg(priv, ENC_SRC, ENC_SRC);
/* Check CLKRDY bit to see when the reset is complete. There is an errata
* that says the CLKRDY may be invalid. We'll wait a couple of msec to
* workaround this condition.
*/
up_mdelay(2);
/* while ((enc_rdgreg(priv, ENC_ESTAT) & ESTAT_CLKRDY) != 0); */
/* Initialize ECON1: Clear ECON1 */
enc_wrgreg(priv, ENC_ECON1, 0x00);
/* Initialize ECON2: Enable address auto increment and voltage
* regulator powersave.
*/
enc_wrgreg(priv, ENC_ECON2, ECON2_AUTOINC | ECON2_VRPS);
/* Initialize receive buffer.
* First, set the receive buffer start address.
*/
priv->nextpkt = PKTMEM_RX_START;
enc_wrbreg(priv, ENC_ERXSTL, PKTMEM_RX_START & 0xff);
enc_wrbreg(priv, ENC_ERXSTH, PKTMEM_RX_START >> 8);
/* Set the receive data pointer */
enc_wrbreg(priv, ENC_ERXRDPTL, PKTMEM_RX_START & 0xff);
enc_wrbreg(priv, ENC_ERXRDPTH, PKTMEM_RX_START >> 8);
/* Set the receive buffer end. */
enc_wrbreg(priv, ENC_ERXNDL, PKTMEM_RX_END & 0xff);
enc_wrbreg(priv, ENC_ERXNDH, PKTMEM_RX_END >> 8);
/* Set transmit buffer start. */
enc_wrbreg(priv, ENC_ETXSTL, PKTMEM_TX_START & 0xff);
enc_wrbreg(priv, ENC_ETXSTH, PKTMEM_TX_START >> 8);
/* Check if we are actually communicating with the ENC28J60. If its
* 0x00 or 0xff, then we are probably not communicating correctly
* via SPI.
*/
regval = enc_rdbreg(priv, ENC_EREVID);
if (regval == 0x00 || regval == 0xff)
{
ndbg("Bad Rev ID: %0x\n", regval);
return -ENODEV;
}
nvdbg("Rev ID: %02x\n", regval);
/* Set filter mode: unicast OR broadcast AND crc valid */
enc_wrbreg(priv, ENC_ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_BCEN);
/* Enable MAC receive */
enc_wrbreg(priv, ENC_MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
/* Enable automatic padding and CRC operations */
#ifdef CONFIG_ENC28J60_HALFDUPLEX
enc_wrbreg(priv, ENC_MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
enc_wrbreg(priv, ENC_MACON4, MACON4_DEFER); /* Defer transmission enable */
/* Set Non-Back-to-Back Inter-Packet Gap */
enc_wrbreg(priv, ENC_MAIPGL, 0x12);
enc_wrbreg(priv, ENC_MAIPGH, 0x0c);
/* Set Back-to-Back Inter-Packet Gap */
enc_wrbreg(priv, ENC_MABBIPG, 0x12);
#else
/* Set filter mode: unicast OR broadcast AND crc valid AND Full Duplex */
enc_wrbreg(priv, ENC_MACON3,
MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX);
/* set Non-Back-to-Back Inter-Packet Gap */
enc_wrbreg(priv, ENC_MAIPGL, 0x12);
/* set ack-to-Back Inter-Packet Gap */
enc_wrbreg(priv, ENC_MABBIPG, 0x15);
#endif
/* Set the maximum packet size which the controller will accept */
enc_wrbreg(priv, ENC_MAMXFLL, MAX_FRAMELEN & 0xff);
enc_wrbreg(priv, ENC_MAMXFLH, MAX_FRAMELEN >> 8);
/* Configure LEDs (No, just use the defaults for now) */
/* enc_wrphy(priv, ENC_PHLCON, ??); */
/* Setup up PHCON1 & 2 */
#ifdef CONFIG_ENC28J60_HALFDUPLEX
enc_wrphy(priv, ENC_PHCON1, 0x00);
enc_wrphy(priv, ENC_PHCON2, PHCON2_HDLDIS);
#else
enc_wrphy(priv, ENC_PHCON1, PHCON1_PDPXMD);
enc_wrphy(priv, ENC_PHCON2, 0x00);
#endif
return OK;
}
/****************************************************************************
@ -1578,6 +1722,7 @@ static void enc_reset(FAR struct enc_driver_s *priv)
int enc_initialize(FAR struct spi_dev_s *spi, unsigned int devno, unsigned int irq)
{
FAR struct enc_driver_s *priv ;
int ret;
DEBUGASSERT(devno < CONFIG_ENC28J60_NINTERFACES);
priv = &g_enc28j60[devno];
@ -1602,22 +1747,23 @@ int enc_initialize(FAR struct spi_dev_s *spi, unsigned int devno, unsigned int i
* the MAC address before bringing the interface up.
*/
enc_ifdown(&priv->dev);
ret = enc_ifdown(&priv->dev);
if (ret == OK)
{
/* Attach the IRQ to the driver (but don't enable it yet) */
if (irq_attach(irq, enc_interrupt))
{
/* We could not attach the ISR to the interrupt */
return -EAGAIN;
ret = -EAGAIN;
}
/* Register the device with the OS so that socket IOCTLs can be performed */
(void)netdev_register(&priv->dev);
return OK;
}
return ret;
}
#endif /* CONFIG_NET && CONFIG_ENC28J60_NET */

View File

@ -355,7 +355,7 @@
#define ENC_PHCON2 (0x10) /* PHY Control Register 2 */
#define ENC_PHSTAT2 (0x11) /* PHY Status 2 */
#define ENC_PHIE (0x12) /* PHY Interrupt Enable Register */
#define ENC_PHIR (0x13)
#define ENC_PHIR (0x13) /* PHY Interrupt Request Register */
#define ENC_PHLCON (0x14)
/* PHY Control Register 1 Register Bit Definitions */
@ -413,6 +413,18 @@
#define PHLCON_LACFG2 (1 << 10) /* Bit 10: " " " " */
#define PHLCON_LACFG3 (1 << 11) /* Bit 11: " " " " */
/* Packet Memory ************************************************************/
/* 8-Kbyte Transmit/Receive Packet Dual Port SRAM */
#define PKTMEM_START 0x0000
#define PKTMEM_END 0x1fff
/* Ethernet frames are between 64 and 1518 bytes long */
#define MIN_FRAMELEN 64
#define MAX_FRAMELEN 1518
/* Packet Control Bits Definitions ******************************************/
#define PKTCTRL_POVERRIDE (1 << 0) /* Bit 0: Per Packet Override */