diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-03-26 13:19:44 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-03-26 13:19:44 -0600 |
commit | 263351a8fc11b1645e66f8c3e710428d0f873b08 (patch) | |
tree | 9c0bedf987c38b49887b726d16a1fc9bd54e60d7 | |
parent | 18002b4005bb0d70a1bea9d1d2aea3bd3adb7781 (diff) | |
download | px4-nuttx-263351a8fc11b1645e66f8c3e710428d0f873b08.tar.gz px4-nuttx-263351a8fc11b1645e66f8c3e710428d0f873b08.tar.bz2 px4-nuttx-263351a8fc11b1645e66f8c3e710428d0f873b08.zip |
SAM3/4: SPI and HSCMI drivers with now use the CMCC is available; The SPI driver will now handle word sizes greater than 8-bits
-rw-r--r-- | nuttx/ChangeLog | 4 | ||||
-rw-r--r-- | nuttx/arch/arm/src/sam34/sam_hsmci.c | 9 | ||||
-rw-r--r-- | nuttx/arch/arm/src/sam34/sam_spi.c | 131 |
3 files changed, 109 insertions, 35 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index ee63937ca..45ca8e8b7 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -7046,3 +7046,7 @@ startup (2014-3-25). * tools/astyle.sh: A code formatting tool from Lorenz Meier. This tool should do a better job than the old tools/indent.sh tool. + * arch/arm/src/sam_hsmci.c and sam_spi.c: Add support to invalidate + cached memory if the CMCC is enabled (not yet tested, 2014-3-26). + * arch/arm/src/sam_spi.c: Add logic to handle SPI word widths > 8 + (also untested on initial checkin, 2014-3-26). diff --git a/nuttx/arch/arm/src/sam34/sam_hsmci.c b/nuttx/arch/arm/src/sam34/sam_hsmci.c index 081bdce3d..488ccdc95 100644 --- a/nuttx/arch/arm/src/sam34/sam_hsmci.c +++ b/nuttx/arch/arm/src/sam34/sam_hsmci.c @@ -62,6 +62,7 @@ #include "sam_gpio.h" #include "sam_dmac.h" +#include "sam_cmcc.h" #include "sam_hsmci.h" #include "sam_periphclks.h" #include "chip/sam_dmac.h" @@ -2343,6 +2344,12 @@ static int sam_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, sam_dmarxsetup(priv->dma, SAM_HSMCI_RDR, (uint32_t)buffer, buflen); + /* Invalidate the buffer memory to force re-fetching from RAM when the DMA + * completes + */ + + sam_cmcc_invalidate((uintptr_t)buffer, (uintptr_t)buffer + buflen); + #if defined(CONFIG_ARCH_CHIP_SAM3U) /* Enable DMA handshaking */ @@ -2385,7 +2392,7 @@ static int sam_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, ****************************************************************************/ static int sam_dmasendsetup(FAR struct sdio_dev_s *dev, - FAR const uint8_t *buffer, size_t buflen) + FAR const uint8_t *buffer, size_t buflen) { struct sam_dev_s *priv = (struct sam_dev_s *)dev; diff --git a/nuttx/arch/arm/src/sam34/sam_spi.c b/nuttx/arch/arm/src/sam34/sam_spi.c index 859983451..ab67e1480 100644 --- a/nuttx/arch/arm/src/sam34/sam_spi.c +++ b/nuttx/arch/arm/src/sam34/sam_spi.c @@ -62,6 +62,7 @@ #include "chip.h" #include "sam_gpio.h" #include "sam_dmac.h" +#include "sam_cmcc.h" #include "sam_periphclks.h" #include "sam_spi.h" #include "chip/sam_pmc.h" @@ -177,9 +178,9 @@ struct sam_spics_s #ifndef CONFIG_SPI_OWNBUS uint32_t frequency; /* Requested clock frequency */ uint32_t actual; /* Actual clock frequency */ - uint8_t nbits; /* Width of word in bits (8 to 16) */ uint8_t mode; /* Mode 0,1,2,3 */ #endif + uint8_t nbits; /* Width of word in bits (8 to 16) */ #if defined(CONFIG_SAM34_SPI0) || defined(CONFIG_SAM34_SPI1) uint8_t spino; /* SPI controller number (0 or 1) */ @@ -1190,19 +1191,12 @@ static void spi_setbits(struct spi_dev_s *dev, int nbits) spivdbg("cs=%d nbits=%d\n", spics->cs, nbits); DEBUGASSERT(spics && nbits > 7 && nbits < 17); - /* NOTE: The logic in spi_send and in spi_exchange only handles 8-bit - * data at the present time. So the following extra assertion is a - * reminder that we have to fix that someday. - */ - - DEBUGASSERT(nbits == 8); /* Temporary -- FIX ME */ - /* Has the number of bits changed? */ #ifndef CONFIG_SPI_OWNBUS if (nbits != spics->nbits) - { #endif + { /* Yes... Set number of bits appropriately */ offset = (unsigned int)g_csroffset[spics->cs]; @@ -1215,10 +1209,8 @@ static void spi_setbits(struct spi_dev_s *dev, int nbits) /* Save the selection so the subsequence re-configurations will be faster */ -#ifndef CONFIG_SPI_OWNBUS spics->nbits = nbits; } -#endif } /**************************************************************************** @@ -1284,18 +1276,20 @@ static uint16_t spi_send(struct spi_dev_s *dev, uint16_t wd) #ifdef CONFIG_SAM34_SPI_DMA static void spi_exchange_nodma(struct spi_dev_s *dev, const void *txbuffer, - void *rxbuffer, size_t nwords) + void *rxbuffer, size_t nwords) #else static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, - void *rxbuffer, size_t nwords) + void *rxbuffer, size_t nwords) #endif { struct sam_spics_s *spics = (struct sam_spics_s *)dev; struct sam_spidev_s *spi = spi_device(spics); - uint8_t *rxptr = (uint8_t*)rxbuffer; - uint8_t *txptr = (uint8_t*)txbuffer; uint32_t pcs; uint32_t data; + uint16_t *rxptr16; + uint16_t *txptr16; + uint8_t *rxptr8; + uint8_t *txptr8; spivdbg("txbuffer=%p rxbuffer=%p nwords=%d\n", txbuffer, rxbuffer, nwords); @@ -1303,6 +1297,23 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, pcs = spi_cs2pcs(spics) << SPI_TDR_PCS_SHIFT; + /* Set up working pointers */ + + if (spics->nbits > 8) + { + rxptr16 = (uint16_t*)rxbuffer; + txptr16 = (uint16_t*)txbuffer; + rxptr8 = NULL; + txptr8 = NULL; + } + else + { + rxptr16 = NULL; + txptr16 = NULL; + rxptr8 = (uint8_t*)rxbuffer; + txptr8 = (uint8_t*)txbuffer; + } + /* Make sure that any previous transfer is flushed from the hardware */ spi_flush(spi); @@ -1340,11 +1351,15 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, for ( ; nwords > 0; nwords--) { - /* Get the data to send (0xff if there is no data source) */ + /* Get the data to send (0xff if there is no data source). */ - if (txptr) + if (txptr8) { - data = (uint32_t)*txptr++; + data = (uint32_t)*txptr8++; + } + else if (txptr16) + { + data = (uint32_t)*txptr16++; } else { @@ -1381,14 +1396,16 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, while ((spi_getreg(spi, SAM_SPI_SR_OFFSET) & SPI_INT_RDRF) == 0); - /* Read the received data from the SPI Data Register.. - * TODO: The following only works if nbits <= 8. - */ + /* Read the received data from the SPI Data Register. */ data = spi_getreg(spi, SAM_SPI_RDR_OFFSET); - if (rxptr) + if (rxptr8) + { + *rxptr8++ = (uint8_t)data; + } + else if (rxptr16) { - *rxptr++ = (uint8_t)data; + *rxptr16++ = (uint16_t)data; } } } @@ -1405,13 +1422,19 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, uint32_t rxdummy; uint32_t regaddr; uint32_t memaddr; + uint32_t width; + size_t nbytes; int ret; + /* Convert the number of word to a number of bytes */ + + nbytes = (spics->nbits > 8) ? nwords << 1 : nwords; + /* If we cannot do DMA -OR- if this is a small SPI transfer, then let * spi_exchange_nodma() do the work. */ - if (!spics->candma || nwords <= CONFIG_SAM34_SPI_DMATHRESHOLD) + if (!spics->candma || nbytes <= CONFIG_SAM34_SPI_DMATHRESHOLD) { spi_exchange_nodma(dev, txbuffer, rxbuffer, nwords); return; @@ -1431,6 +1454,17 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, spi_dma_sampleinit(spics); + /* Select the source and destination width bits */ + + if (spics->nbits > 8) + { + width = (DMACH_FLAG_PERIPHWIDTH_16BITS | DMACH_FLAG_MEMWIDTH_16BITS); + } + else + { + width = (DMACH_FLAG_PERIPHWIDTH_8BITS | DMACH_FLAG_MEMWIDTH_8BITS); + } + /* Configure the DMA channels. There are four different cases: * * 1) A true exchange with the memory address incrementing on both @@ -1445,12 +1479,20 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, * provided on the SPI bus. */ + /* Configure the RX DMA channel */ + rxflags = DMACH_FLAG_FIFOCFG_LARGEST | ((uint32_t)spi->rxintf << DMACH_FLAG_PERIPHPID_SHIFT) | DMACH_FLAG_PERIPHH2SEL | DMACH_FLAG_PERIPHISPERIPH | - DMACH_FLAG_PERIPHWIDTH_8BITS | DMACH_FLAG_PERIPHCHUNKSIZE_1 | + DMACH_FLAG_PERIPHCHUNKSIZE_1 | ((uint32_t)(15) << DMACH_FLAG_MEMPID_SHIFT) | - DMACH_FLAG_MEMWIDTH_8BITS | DMACH_FLAG_MEMCHUNKSIZE_1; + DMACH_FLAG_MEMCHUNKSIZE_1; + + /* Set the source and destination width bits */ + + rxflags |= width; + + /* Handle the case where there is no sink buffer */ if (!rxbuffer) { @@ -1462,21 +1504,37 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, } else { - /* A receive buffer is available. Use normal TX memory incrementing. */ + /* A receive buffer is available. + * + * Invalidate the RX buffer memory to force re-fetching from RAM when + * the DMA completes + */ + + sam_cmcc_invalidate((uintptr_t)rxbuffer, (uintptr_t)rxbuffer + nbytes); + + /* Use normal RX memory incrementing. */ rxflags |= DMACH_FLAG_MEMINCREMENT; } + /* Configure the TX DMA channel */ + txflags = DMACH_FLAG_FIFOCFG_LARGEST | ((uint32_t)spi->txintf << DMACH_FLAG_PERIPHPID_SHIFT) | DMACH_FLAG_PERIPHH2SEL | DMACH_FLAG_PERIPHISPERIPH | - DMACH_FLAG_PERIPHWIDTH_8BITS | DMACH_FLAG_PERIPHCHUNKSIZE_1 | + DMACH_FLAG_PERIPHCHUNKSIZE_1 | ((uint32_t)(15) << DMACH_FLAG_MEMPID_SHIFT) | - DMACH_FLAG_MEMWIDTH_8BITS | DMACH_FLAG_MEMCHUNKSIZE_1; + DMACH_FLAG_MEMCHUNKSIZE_1; + + /* Set the source and destination width bits */ + + txflags |= width; + + /* Handle the case where there is no source buffer */ if (!txbuffer) { - /* No source data buffer. Point to our dummy buffer and configure + /* No source data buffer. Point to our dummy buffer and leave * the txflags so that no address increment is performed. */ @@ -1495,7 +1553,7 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, sam_dmaconfig(spics->rxdma, rxflags); sam_dmaconfig(spics->txdma, txflags); - /* Configure the exchange transfers */ + /* Configure the RX side of the exchange transfer */ regaddr = spi_regaddr(spics, SAM_SPI_RDR_OFFSET); memaddr = (uintptr_t)rxbuffer; @@ -1509,6 +1567,8 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, spi_rxdma_sample(spics, DMA_AFTER_SETUP); + /* Configure the TX side of the exchange transfer */ + regaddr = spi_regaddr(spics, SAM_SPI_TDR_OFFSET); memaddr = (uintptr_t)txbuffer; @@ -1626,7 +1686,8 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, * nwords - the length of data to send from the buffer in number of words. * The wordsize is determined by the number of bits-per-word * selected for the SPI interface. If nbits <= 8, the data is - * packed into uint8_t's; if nbits >8, the data is packed into uint16_t's + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's * * Returned Value: * None @@ -1634,7 +1695,8 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer, ****************************************************************************/ #ifndef CONFIG_SPI_EXCHANGE -static void spi_sndblock(struct spi_dev_s *dev, const void *buffer, size_t nwords) +static void spi_sndblock(struct spi_dev_s *dev, const void *buffer, + size_t nwords) { /* spi_exchange can do this. */ @@ -1654,7 +1716,8 @@ static void spi_sndblock(struct spi_dev_s *dev, const void *buffer, size_t nword * nwords - the length of data that can be received in the buffer in number * of words. The wordsize is determined by the number of bits-per-word * selected for the SPI interface. If nbits <= 8, the data is - * packed into uint8_t's; if nbits >8, the data is packed into uint16_t's + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's * * Returned Value: * None |