Misc ENC28J60 fixes

git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@5132 7fd9a85b-ad96-42d3-883c-3090e2eb8679
This commit is contained in:
patacongo 2012-09-12 00:12:18 +00:00
parent 7bb74973bd
commit 675f37494a
6 changed files with 157 additions and 81 deletions

View File

@ -3930,8 +3930,8 @@ build
<code>CONFIG_HEAP2_BASE</code> and <code>CONFIG_HEAP2_SIZE</code>:
Some architectures use these settings to specify the size of
a second heap region.
<li>
</li>
<li>
<code>CONFIG_GRAN</code>:
Enable granual allocator support. Allocations will be aligned to the
granule size; allocations will be in units of the granule size.
@ -3940,8 +3940,8 @@ build
NOTE: The current implementation also restricts the maximum
allocation size to 32 granaules. That restriction could be
eliminated with some additional coding effort.
<li>
</li>
<li>
<code>CONFIG_GRAN_SINGLE</code>:
Select if there is only one instance of the granule allocator (i.e.,
gran_initialize will be called only once. In this case, (1) there

View File

@ -183,6 +183,9 @@ struct enc_driver_s
uint8_t ifstate; /* Interface state: See ENCSTATE_* */
uint8_t bank; /* Currently selected bank */
#ifndef CONFIG_SPI_OWNBUS
uint8_t lockcount; /* Avoid recursive locks */
#endif
uint16_t nextpkt; /* Next packet address */
FAR const struct enc_lower_s *lower; /* Low-level MCU-specific support */
@ -191,7 +194,7 @@ struct enc_driver_s
WDOG_ID txpoll; /* TX poll timer */
WDOG_ID txtimeout; /* TX timeout timer */
/* We we don't own the SPI bus, then we cannot do SPI accesses from the
/* If we don't own the SPI bus, then we cannot do SPI accesses from the
* interrupt handler.
*/
@ -228,11 +231,11 @@ static struct enc_driver_s g_enc28j60[CONFIG_ENC28J60_NINTERFACES];
static inline void enc_configspi(FAR struct spi_dev_s *spi);
#ifdef CONFIG_SPI_OWNBUS
static inline void enc_select(FAR struct spi_dev_s *spi);
static inline void enc_deselect(FAR struct spi_dev_s *spi);
static inline void enc_select(FAR struct enc_driver_s *priv);
static inline void enc_deselect(FAR struct enc_driver_s *priv);
#else
static void enc_select(FAR struct spi_dev_s *spi);
static void enc_deselect(FAR struct spi_dev_s *spi);
static void enc_select(FAR struct enc_driver_s *priv);
static void enc_deselect(FAR struct enc_driver_s *priv);
#endif
/* SPI control register access */
@ -240,6 +243,7 @@ static void enc_deselect(FAR struct spi_dev_s *spi);
static uint8_t enc_rdgreg2(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 inline void enc_src(FAR struct enc_driver_s *priv);
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);
static void enc_wrbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg,
@ -351,30 +355,47 @@ static inline void enc_configspi(FAR struct spi_dev_s *spi)
****************************************************************************/
#ifdef CONFIG_SPI_OWNBUS
static inline void enc_select(FAR struct spi_dev_s *spi)
static inline void enc_select(FAR struct enc_driver_s *priv)
{
/* We own the SPI bus, so just select the chip */
SPI_SELECT(spi, SPIDEV_ETHERNET, true);
SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);
}
#else
static void enc_select(FAR struct spi_dev_s *spi)
static void enc_select(FAR struct enc_driver_s *priv)
{
/* Select ENC28J60 chip (locking the SPI bus in case there are multiple
* devices competing for the SPI bus
/* Lock the SPI bus in case there are multiple devices competing for the SPI
* bus. First check if we already hold the lock.
*/
SPI_LOCK(spi, true);
SPI_SELECT(spi, SPIDEV_ETHERNET, true);
if (priv->lockcount > 0)
{
/* Yes... just increment the lock count */
DEBUGASSERT(priv->lockcount < 255);
priv->lockcount++;
}
else
{
/* No... take the lock and set the lock count to 1 */
DEBUGASSERT(priv->lockcount == 0);
SPI_LOCK(priv->spi, true);
priv->lockcount = 1;
}
/* Select ENC28J60 chip. */
SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);
/* Now make sure that the SPI bus is configured for the ENC28J60 (it
* might have gotten configured for a different device while unlocked)
*/
SPI_SETMODE(spi, CONFIG_ENC28J60_SPIMODE);
SPI_SETBITS(spi, 8);
SPI_SETMODE(priv->spi, CONFIG_ENC28J60_SPIMODE);
SPI_SETBITS(priv->spi, 8);
#ifdef CONFIG_ENC28J60_FREQUENCY
SPI_SETFREQUENCY(spi, CONFIG_ENC28J60_FREQUENCY);
SPI_SETFREQUENCY(priv->spi, CONFIG_ENC28J60_FREQUENCY);
#endif
}
#endif
@ -396,19 +417,33 @@ static void enc_select(FAR struct spi_dev_s *spi)
****************************************************************************/
#ifdef CONFIG_SPI_OWNBUS
static inline void enc_deselect(FAR struct spi_dev_s *spi)
static inline void enc_deselect(FAR struct enc_driver_s *priv)
{
/* We own the SPI bus, so just de-select the chip */
SPI_SELECT(spi, SPIDEV_ETHERNET, false);
SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false);
}
#else
static void enc_deselect(FAR struct spi_dev_s *spi)
static void enc_deselect(FAR struct enc_driver_s *priv)
{
/* De-select ENC28J60 chip and relinquish the SPI bus. */
/* De-select ENC28J60 chip. */
SPI_SELECT(spi, SPIDEV_ETHERNET, false);
SPI_LOCK(spi, false);
SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false);
/* And relinquishthe lock on the bus. If the lock count is > 1 then we
* are in a nested lock and we only need to decrement the lock cound.
*/
if (priv->lockcount <= 1)
{
DEBUGASSERT(priv->lockcount == 1);
SPI_LOCK(priv->spi, false);
priv->lockcount = 0;
}
else
{
priv->lockcount--;
}
}
#endif
@ -432,26 +467,24 @@ static void enc_deselect(FAR struct spi_dev_s *spi)
static uint8_t enc_rdgreg2(FAR struct enc_driver_s *priv, uint8_t cmd)
{
FAR struct spi_dev_s *spi;
uint8_t rddata;
DEBUGASSERT(priv && priv->spi);
spi = priv->spi;
/* Select ENC28J60 chip */
enc_select(spi);
enc_select(priv);
/* Send the read command and collect the data. The sequence requires
* 16-clocks: 8 to clock out the cmd + 8 to clock in the data.
*/
(void)SPI_SEND(spi, cmd); /* Clock out the command */
rddata = SPI_SEND(spi, 0); /* Clock in the data */
(void)SPI_SEND(priv->spi, cmd); /* Clock out the command */
rddata = SPI_SEND(priv->spi, 0); /* Clock in the data */
/* De-select ENC28J60 chip */
enc_deselect(spi);
enc_deselect(priv);
return rddata;
}
@ -477,25 +510,75 @@ static uint8_t enc_rdgreg2(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;
DEBUGASSERT(priv && priv->spi);
spi = priv->spi;
/* Select ENC28J60 chip */
enc_select(spi);
enc_select(priv);
/* Send the write command and data. The sequence requires 16-clocks:
* 8 to clock out the cmd + 8 to clock out the data.
*/
(void)SPI_SEND(spi, cmd); /* Clock out the command */
(void)SPI_SEND(spi, wrdata); /* Clock out the data */
(void)SPI_SEND(priv->spi, cmd); /* Clock out the command */
(void)SPI_SEND(priv->spi, wrdata); /* Clock out the data */
/* De-select ENC28J60 chip. */
enc_deselect(spi);
enc_deselect(priv);
}
/****************************************************************************
* Function: enc_src
*
* Description:
* Send the single byte system reset command (SRC).
*
* "The System Reset Command (SRC) allows the host controller to issue a
* System Soft Reset command. Unlike other SPI commands, the SRC is
* only a single byte command and does not operate on any register. The
* command is started by pulling the CS pin low. The SRC opcode is the
* sent, followed by a 5-bit Soft Reset command constant of 1Fh. The
* SRC operation is terminated by raising the CS pin."
*
* Parameters:
* priv - Reference to the driver state structure
*
* Returned Value:
* None
*
* Assumptions:
*
****************************************************************************/
static inline void enc_src(FAR struct enc_driver_s *priv)
{
DEBUGASSERT(priv && priv->spi);
/* Select ENC28J60 chip */
enc_select(priv);
/* Send the system reset command. */
(void)SPI_SEND(priv->spi, 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.
*
* Also, "After a System Reset, all PHY registers should not be read or
* written to until at least 50 µs have passed since the Reset has ended.
* All registers will revert to their Reset default values. The dual
* port buffer memory will maintain state throughout the System Reset."
*/
up_mdelay(2);
/* while ((enc_rdgreg(priv, ENC_ESTAT) & ESTAT_CLKRDY) != 0); */
/* De-select ENC28J60 chip. */
enc_deselect(priv);
}
/****************************************************************************
@ -560,15 +643,13 @@ 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)
{
FAR struct spi_dev_s *spi;
uint8_t rddata;
DEBUGASSERT(priv && priv->spi);
spi = priv->spi;
/* Select ENC28J60 chip */
enc_select(spi);
enc_select(priv);
/* Set the bank */
@ -579,20 +660,21 @@ static uint8_t enc_rdbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg)
* 16-clocks: 8 to clock out the cmd and 8 to clock in the data.
*/
(void)SPI_SEND(spi, ENC_RCR | GETADDR(ctrlreg)); /* Clock out the command */
(void)SPI_SEND(priv->spi, ENC_RCR | GETADDR(ctrlreg)); /* Clock out the command */
if (ISPHYMAC(ctrlreg))
{
/* The PHY/MAC sequence requires 24-clocks: 8 to clock out the cmd,
* 8 dummy bits, and 8 to clock in the PHY/MAC data.
*/
(void)SPI_SEND(spi,0); /* Clock in the dummy byte */
(void)SPI_SEND(priv->spi, 0); /* Clock in the dummy byte */
}
rddata = SPI_SEND(spi, 0); /* Clock in the data */
rddata = SPI_SEND(priv->spi, 0); /* Clock in the data */
/* De-select ENC28J60 chip */
enc_deselect(spi);
enc_deselect(priv);
return rddata;
}
@ -619,14 +701,11 @@ static uint8_t enc_rdbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg)
static void enc_wrbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg,
uint8_t wrdata)
{
FAR struct spi_dev_s *spi;
DEBUGASSERT(priv && priv->spi);
spi = priv->spi;
/* Select ENC28J60 chip */
enc_select(spi);
enc_select(priv);
/* Set the bank */
@ -636,12 +715,12 @@ static void enc_wrbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg,
* 8 to clock out the cmd + 8 to clock out the data.
*/
(void)SPI_SEND(spi, ENC_WCR | GETADDR(ctrlreg)); /* Clock out the command */
(void)SPI_SEND(spi, wrdata); /* Clock out the data */
(void)SPI_SEND(priv->spi, ENC_WCR | GETADDR(ctrlreg)); /* Clock out the command */
(void)SPI_SEND(priv->spi, wrdata); /* Clock out the data */
/* De-select ENC28J60 chip. */
enc_deselect(spi);
enc_deselect(priv);
}
/****************************************************************************
@ -681,6 +760,7 @@ static int enc_waitbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg,
elapsed = clock_systimer() - start;
}
while ((rddata & bits) != value || elapsed > ENC_POLLTIMEOUT);
return (rddata & bits) == value ? -ETIMEDOUT : OK;
}
@ -706,26 +786,23 @@ static int enc_waitbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg,
static void enc_rdbuffer(FAR struct enc_driver_s *priv, FAR uint8_t *buffer,
size_t buflen)
{
FAR struct spi_dev_s *spi;
DEBUGASSERT(priv && priv->spi);
spi = priv->spi;
/* Select ENC28J60 chip */
enc_select(spi);
enc_select(priv);
/* Send the read buffer memory command (ignoring the response) */
(void)SPI_SEND(spi, ENC_RBM);
(void)SPI_SEND(priv->spi, ENC_RBM);
/* Then read the buffer data */
SPI_RECVBLOCK(spi, buffer, buflen);
SPI_RECVBLOCK(priv->spi, buffer, buflen);
/* De-select ENC28J60 chip. */
enc_deselect(spi);
enc_deselect(priv);
}
/****************************************************************************
@ -750,26 +827,23 @@ static void enc_rdbuffer(FAR struct enc_driver_s *priv, FAR uint8_t *buffer,
static void enc_wrbuffer(FAR struct enc_driver_s *priv,
FAR const uint8_t *buffer, size_t buflen)
{
FAR struct spi_dev_s *spi;
DEBUGASSERT(priv && priv->spi);
spi = priv->spi;
/* Select ENC28J60 chip */
enc_select(spi);
enc_select(priv);
/* Send the write buffer memory command (ignoring the response) */
(void)SPI_SEND(spi, ENC_WBM);
(void)SPI_SEND(priv->spi, ENC_WBM);
/* Then send the buffer */
SPI_SNDBLOCK(spi, buffer, buflen);
SPI_SNDBLOCK(priv->spi, buffer, buflen);
/* De-select ENC28J60 chip. */
enc_deselect(spi);
enc_deselect(priv);
}
/****************************************************************************
@ -811,6 +885,7 @@ static uint16_t enc_rdphy(FAR struct enc_driver_s *priv, uint8_t phyaddr)
data = (uint16_t)enc_rdbreg(priv, ENC_MIRDL);
data |= (uint16_t)enc_rdbreg(priv, ENC_MIRDH) << 8;
}
return data;
}
@ -1999,15 +2074,7 @@ static int enc_reset(FAR struct enc_driver_s *priv)
/* 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); */
enc_src(priv);
/* Initialize ECON1: Clear ECON1 */
@ -2053,6 +2120,7 @@ static int enc_reset(FAR struct enc_driver_s *priv)
nlldbg("Bad Rev ID: %02x\n", regval);
return -ENODEV;
}
nllvdbg("Rev ID: %02x\n", regval);
/* Set filter mode: unicast OR broadcast AND crc valid */

View File

@ -56,7 +56,7 @@
*/
#define ENC_RCR (0x00) /* Read Control Register
* 000 | aaaaa | (Registe value returned)) */
* 000 | aaaaa | (Register value returned)) */
#define ENC_RBM (0x3a) /* Read Buffer Memory
* 001 | 11010 | (Read buffer data follows) */
#define ENC_WCR (0x40) /* Write Control Register

View File

@ -90,7 +90,7 @@ extern "C" {
* losses of memory due to alignment and quantization waste.
*
* NOTE: The current implementation also restricts the maximum allocation
* size to 32 granaules. That restriction could be eliminated with some
* size to 32 granules. That restriction could be eliminated with some
* additional coding effort.
*
* Input Parameters:
@ -120,7 +120,7 @@ EXTERN GRAN_HANDLE gran_initialize(FAR void *heapstart, size_t heapsize,
* Allocate memory from the granule heap.
*
* NOTE: The current implementation also restricts the maximum allocation
* size to 32 granaules. That restriction could be eliminated with some
* size to 32 granules. That restriction could be eliminated with some
* additional coding effort.
*
* Input Parameters:

View File

@ -158,11 +158,19 @@ static inline FAR void *gran_common_alloc(FAR struct gran_s *priv, size_t size)
for (i = 0; i < priv->ngranules; i += 32)
{
/* Get the GAT index associated with the granule (i) */
/* Get the GAT index associated with the granule table entry [i] */
j = i >> 5;
curr = priv->gat[j];
/* Handle the case where there are no free granules in the entry */
if (curr == 0xffffffff)
{
alloc += (32 << priv->log2gran);
continue;
}
/* Get the next entry from the GAT to support a 64 bit shift */
if (i < priv->ngranules)
@ -228,7 +236,7 @@ static inline FAR void *gran_common_alloc(FAR struct gran_s *priv, size_t size)
* Allocate memory from the granule heap.
*
* NOTE: The current implementation also restricts the maximum allocation
* size to 32 granaules. That restriction could be eliminated with some
* size to 32 granules. That restriction could be eliminated with some
* additional coding effort.
*
* Input Parameters:

View File

@ -139,7 +139,7 @@ static inline FAR struct gran_s *gran_common_initialize(FAR void *heapstart,
* losses of memory due to alignment and quantization waste.
*
* NOTE: The current implementation also restricts the maximum allocation
* size to 32 granaules. That restriction could be eliminated with some
* size to 32 granules. That restriction could be eliminated with some
* additional coding effort.
*
* Input Parameters: