From 675f37494ad7f096e0b4c42189fe224c54e4fdb1 Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 12 Sep 2012 00:12:18 +0000 Subject: [PATCH] Misc ENC28J60 fixes git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@5132 7fd9a85b-ad96-42d3-883c-3090e2eb8679 --- nuttx/Documentation/NuttxPortingGuide.html | 4 +- nuttx/drivers/net/enc28j60.c | 212 ++++++++++++++------- nuttx/drivers/net/enc28j60.h | 2 +- nuttx/include/nuttx/gran.h | 4 +- nuttx/mm/mm_granalloc.c | 14 +- nuttx/mm/mm_graninit.c | 2 +- 6 files changed, 157 insertions(+), 81 deletions(-) diff --git a/nuttx/Documentation/NuttxPortingGuide.html b/nuttx/Documentation/NuttxPortingGuide.html index f2c89dcbe9..d44bae4abd 100644 --- a/nuttx/Documentation/NuttxPortingGuide.html +++ b/nuttx/Documentation/NuttxPortingGuide.html @@ -3930,8 +3930,8 @@ build CONFIG_HEAP2_BASE and CONFIG_HEAP2_SIZE: Some architectures use these settings to specify the size of a second heap region. -
  • +
  • CONFIG_GRAN: 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. -
  • +
  • CONFIG_GRAN_SINGLE: 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 diff --git a/nuttx/drivers/net/enc28j60.c b/nuttx/drivers/net/enc28j60.c index a2f3d58715..b9d614cd9d 100644 --- a/nuttx/drivers/net/enc28j60.c +++ b/nuttx/drivers/net/enc28j60.c @@ -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,11 +243,12 @@ 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, uint8_t wrdata); -static int enc_waitbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg, +static int enc_waitbreg(FAR struct enc_driver_s *priv, uint8_t ctrlreg, uint8_t bits, uint8_t value); /* SPI buffer transfers */ @@ -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 */ diff --git a/nuttx/drivers/net/enc28j60.h b/nuttx/drivers/net/enc28j60.h index 408224b22d..6ca1a524d1 100644 --- a/nuttx/drivers/net/enc28j60.h +++ b/nuttx/drivers/net/enc28j60.h @@ -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 diff --git a/nuttx/include/nuttx/gran.h b/nuttx/include/nuttx/gran.h index 1176735cf1..8e009ab810 100644 --- a/nuttx/include/nuttx/gran.h +++ b/nuttx/include/nuttx/gran.h @@ -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: diff --git a/nuttx/mm/mm_granalloc.c b/nuttx/mm/mm_granalloc.c index 0e94d464b0..62fbc0870a 100644 --- a/nuttx/mm/mm_granalloc.c +++ b/nuttx/mm/mm_granalloc.c @@ -158,10 +158,18 @@ 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]; + 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 */ @@ -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: diff --git a/nuttx/mm/mm_graninit.c b/nuttx/mm/mm_graninit.c index bc2c6f2a1a..d3144b2aa6 100644 --- a/nuttx/mm/mm_graninit.c +++ b/nuttx/mm/mm_graninit.c @@ -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: