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

This commit is contained in:
Gregory Nutt 2014-03-26 13:19:44 -06:00
parent 3f4593dda8
commit 135b6b0ca2
3 changed files with 109 additions and 35 deletions

View File

@ -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).

View File

@ -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;

View File

@ -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)
{
*rxptr++ = (uint8_t)data;
*rxptr8++ = (uint8_t)data;
}
else if (rxptr16)
{
*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