SAM3,4,A5 DMA fixes; SAMA5 SPI driver now supports DMA transfers

This commit is contained in:
Gregory Nutt
2013-08-09 13:12:16 -06:00
parent 417636e1de
commit 628f50ba61
12 changed files with 1098 additions and 205 deletions
+1 -1
View File
@@ -379,7 +379,7 @@
#define DMACHAN_CTRLB_SRCINCR_MASK (3 << DMACHAN_CTRLB_SRCINCR_SHIFT)
# define DMACHAN_CTRLB_SRCINCR_INCR (0 << DMACHAN_CTRLB_SRCINCR_SHIFT) /* Incrementing address */
# define DMACHAN_CTRLB_SRCINCR_FIXED (2 << DMACHAN_CTRLB_SRCINCR_SHIFT) /* Fixed address */
#define DMACHAN_CTRLB_DSTINCR_SHIFT (28) /* Bits 28-29 */
#define DMACHAN_CTRLB_DSTINCR_SHIFT (28) /* Bits 28-29 */
#define DMACHAN_CTRLB_DSTINCR_MASK (3 << DMACHAN_CTRLB_DSTINCR_SHIFT)
# define DMACHAN_CTRLB_DSTINCR_INCR (0 << DMACHAN_CTRLB_DSTINCR_SHIFT) /* Incrementing address */
# define DMACHAN_CTRLB_DSTINCR_FIXED (2 << DMACHAN_CTRLB_DSTINCR_SHIFT) /* Fixed address */
+166 -48
View File
@@ -252,14 +252,14 @@ static inline void sam_givedsem(void)
*
****************************************************************************/
static unsigned int sam_fifosize(uint8_t dmach_flags)
static unsigned int sam_fifosize(uint8_t chflags)
{
dmach_flags &= DMACH_FLAG_FIFOSIZE_MASK;
if (dmach_flags == DMACH_FLAG_FIFO_8BYTES)
chflags &= DMACH_FLAG_FIFOSIZE_MASK;
if (chflags == DMACH_FLAG_FIFO_8BYTES)
{
return 8;
}
else /* if (dmach_flags == DMACH_FLAG_FIFO_32BYTES) */
else /* if (chflags == DMACH_FLAG_FIFO_32BYTES) */
{
return 32;
}
@@ -273,9 +273,9 @@ static unsigned int sam_fifosize(uint8_t dmach_flags)
*
****************************************************************************/
static inline bool sam_flowcontrol(uint8_t dmach_flags)
static inline bool sam_flowcontrol(uint8_t chflags)
{
return ((dmach_flags & DMACH_FLAG_FLOWCONTROL) != 0);
return ((chflags & DMACH_FLAG_FLOWCONTROL) != 0);
}
/****************************************************************************
@@ -368,7 +368,7 @@ sam_txctrlabits(struct sam_dma_s *dmach)
DEBUGASSERT(ndx < 3);
regval = g_srcwidth[ndx];
/* Set the source chuck size (memory chunk size) */
/* Set the source chunk size (memory chunk size) */
if ((dmach->flags & DMACH_FLAG_MEMCHUNKSIZE) == DMACH_FLAG_MEMCHUNKSIZE_4)
{
@@ -389,7 +389,7 @@ sam_txctrlabits(struct sam_dma_s *dmach)
DEBUGASSERT(ndx < 3);
regval |= g_destwidth[ndx];
/* Set the destination chuck size (peripheral chunk size) */
/* Set the destination chunk size (peripheral chunk size) */
if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) == DMACH_FLAG_PERIPHCHUNKSIZE_4)
{
@@ -405,6 +405,48 @@ sam_txctrlabits(struct sam_dma_s *dmach)
return regval;
}
/****************************************************************************
* Name: sam_maxtxtransfer
*
* Description:
* Maximum number of bytes that can be sent in on transfer
*
****************************************************************************/
static size_t sam_maxtxtransfer(struct sam_dmach_s *dmach)
{
unsigned int srcwidth;
size_t maxtransfer;
/* Get the maximum transfer size in bytes. BTSIZE is "the number of
* transfers to be performed, that is, for writes it refers to the number
* of source width transfers to perform when DMAC is flow controller. For
* Reads, BTSIZE refers to the number of transfers completed on the Source
* Interface. ..."
*/
srcwidth = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK)
>> DMACH_FLAG_MEMWIDTH_SHIFT;
switch (srcwidth)
{
default:
case 0: /* 8 bits, 1 byte */
maxtransfer = DMACHAN_CTRLA_BTSIZE_MAX;
break;
case 1: /* 16 bits, 2 bytes */
maxtransfer = 2 * DMACHAN_CTRLA_BTSIZE_MAX;
break;
case 2: /* 32 bits 4 bytes */
maxtransfer = 4 * DMACHAN_CTRLA_BTSIZE_MAX;
break;
}
return maxtransfer;
}
/****************************************************************************
* Name: sam_txctrla
*
@@ -414,19 +456,30 @@ sam_txctrlabits(struct sam_dma_s *dmach)
****************************************************************************/
static inline uint32_t sam_txctrla(struct sam_dma_s *dmach,
uint32_t dmasize, uint32_t ctrla)
uint32_t ctrla, uint32_t dmasize)
{
unsigned int srcwidth;
/* Set the buffer transfer size field. This is the number of transfers to
* be performed, that is, the number of source width transfers to perform.
*/
/* Adjust the the source transfer size for the source chunk size (memory
* chunk size)
*/
srcwidth = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK)
>> DMACH_FLAG_MEMWIDTH_SHIFT;
if ((dmach->flags & DMACH_FLAG_MEMCHUNKSIZE) == DMACH_FLAG_MEMCHUNKSIZE_4)
switch (srcwidth)
{
dmasize = (dmasize + 3) >> 2;
default:
case 0: /* 8 bits, 1 byte */
break;
case 1: /* 16 bits, 2 bytes */
dmasize = (dmasize + 1) >> 1;
break;
case 2: /* 32 bits, 4 bytes */
dmasize = (dmasize + 3) >> 2;
break;
}
DEBUGASSERT(dmasize <= DMACHAN_CTRLA_BTSIZE_MAX);
@@ -460,7 +513,7 @@ static inline uint32_t sam_rxctrlabits(struct sam_dma_s *dmach)
DEBUGASSERT(ndx < 3);
regval = g_srcwidth[ndx];
/* Set the source chuck size (peripheral chunk size) */
/* Set the source chunk size (peripheral chunk size) */
if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) == DMACH_FLAG_PERIPHCHUNKSIZE_4)
{
@@ -481,7 +534,7 @@ static inline uint32_t sam_rxctrlabits(struct sam_dma_s *dmach)
DEBUGASSERT(ndx < 3);
regval |= g_destwidth[ndx];
/* Set the destination chuck size (memory chunk size) */
/* Set the destination chunk size (memory chunk size) */
if ((dmach->flags & DMACH_FLAG_MEMCHUNKSIZE) == DMACH_FLAG_MEMCHUNKSIZE_4)
{
@@ -497,6 +550,48 @@ static inline uint32_t sam_rxctrlabits(struct sam_dma_s *dmach)
return regval;
}
/****************************************************************************
* Name: sam_maxrxtransfer
*
* Description:
* Maximum number of bytes that can be sent in on transfer
*
****************************************************************************/
static size_t sam_maxrxtransfer(struct sam_dmach_s *dmach)
{
unsigned int srcwidth;
size_t maxtransfer;
/* Get the maximum transfer size in bytes. BTSIZE is "the number of
* transfers to be performed, that is, for writes it refers to the number
* of source width transfers to perform when DMAC is flow controller. For
* Reads, BTSIZE refers to the number of transfers completed on the Source
* Interface. ..."
*/
srcwidth = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK)
>> DMACH_FLAG_PERIPHWIDTH_SHIFT;
switch (srcwidth)
{
default:
case 0: /* 8 bits, 1 byte */
maxtransfer = DMACHAN_CTRLA_BTSIZE_MAX;
break;
case 1: /* 16 bits, 2 bytes */
maxtransfer = 2 * DMACHAN_CTRLA_BTSIZE_MAX;
break;
case 2: /* 32 bits, 4 bytes */
maxtransfer = 4 * DMACHAN_CTRLA_BTSIZE_MAX;
break;
}
return maxtransfer;
}
/****************************************************************************
* Name: sam_rxctrla
*
@@ -506,19 +601,30 @@ static inline uint32_t sam_rxctrlabits(struct sam_dma_s *dmach)
****************************************************************************/
static inline uint32_t sam_rxctrla(struct sam_dma_s *dmach,
uint32_t dmasize, uint32_t ctrla)
uint32_t ctrla, uint32_t dmasize)
{
unsigned int srcwidth;
/* Set the buffer transfer size field. This is the number of transfers to
* be performed, that is, the number of source width transfers to perform.
*/
/* Adjust the the source transfer size for the source chunk size (peripheral
* chunk size)
*/
srcwidth = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK)
>> DMACH_FLAG_PERIPHWIDTH_SHIFT;
if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) == DMACH_FLAG_PERIPHCHUNKSIZE_4)
switch (srcwidth)
{
dmasize = (dmasize + 3) >> 2;
default:
case 0: /* 8 bits, 1 byte */
break;
case 1: /* 16 bits, 2 bytes */
dmasize = (dmasize + 1) >> 1;
break;
case 2: /* 32 bits, 4 bytes */
dmasize = (dmasize + 3) >> 2;
break;
}
DEBUGASSERT(dmasize <= DMACHAN_CTRLA_BTSIZE_MAX);
@@ -907,7 +1013,7 @@ static int sam_rxbuffer(struct sam_dma_s *dmach, uint32_t paddr,
ctrlb = sam_rxctrlb(dmach);
}
ctrla = sam_rxctrla(dmach, nbytes, regval);
ctrla = sam_rxctrla(dmach, regval, nbytes);
/* Add the new link list entry */
@@ -1102,9 +1208,9 @@ static int sam_dmainterrupt(int irq, void *context)
regval = getreg32(SAM_DMAC_EBCISR) & getreg32(SAM_DMAC_EBCIMR);
/* Check if the any transfer has completed */
/* Check if the any transfer has completed or any errors have occurred */
if (regval & DMAC_EBC_BTC_MASK)
if (regval & DMAC_EBC_ALLINTS)
{
/* Yes.. Check each bit to see which channel has interrupted */
@@ -1219,15 +1325,15 @@ void weak_function up_dmainitialize(void)
*
****************************************************************************/
DMA_HANDLE sam_dmachannel(uint32_t dmach_flags)
DMA_HANDLE sam_dmachannel(uint32_t chflags)
{
struct sam_dma_s *dmach;
unsigned int chndx;
/* Get the search parameters */
bool flowcontrol = sam_flowcontrol(dmach_flags);
unsigned int fifosize = sam_fifosize(dmach_flags);
bool flowcontrol = sam_flowcontrol(chflags);
unsigned int fifosize = sam_fifosize(chflags);
/* Search for an available DMA channel with at least the requested FIFO
* size.
@@ -1241,7 +1347,7 @@ DMA_HANDLE sam_dmachannel(uint32_t dmach_flags)
struct sam_dma_s *candidate = &g_dma[chndx];
if (!candidate->inuse &&
(sam_fifosize(candidate->flags) >= fifosize) &&
(!flowcontrol || sam_flowcontrol(dmach_flags)))
(!flowcontrol || sam_flowcontrol(chflags)))
{
dmach = candidate;
dmach->inuse = true;
@@ -1258,23 +1364,49 @@ DMA_HANDLE sam_dmachannel(uint32_t dmach_flags)
putreg32(DMAC_CHDR_DIS(chndx), SAM_DMAC_CHDR);
/* See the DMA channel flags, retaining the fifo size and flow
/* Set the DMA channel flags, retaining the fifo size and flow
* control settings which are inherent properties of the FIFO
* and cannot be changed.
*/
dmach->flags &= (DMACH_FLAG_FLOWCONTROL | DMACH_FLAG_FIFOSIZE_MASK);
dmach->flags |= (dmach_flags & ~((DMACH_FLAG_FLOWCONTROL | DMACH_FLAG_FIFOSIZE_MASK)));
dmach->flags |= (chflags & ~((DMACH_FLAG_FLOWCONTROL | DMACH_FLAG_FIFOSIZE_MASK)));
break;
}
}
sam_givechsem();
dmavdbg("dmach_flags: %08x returning dmach: %p\n", (int)dmach_flags, dmach);
dmavdbg("chflags: %08x returning dmach: %p\n", (int)chflags, dmach);
return (DMA_HANDLE)dmach;
}
/************************************************************************************
* Name: sam_dmaconfig
*
* Description:
* There are two channel usage models: (1) The channel is allocated and configured
* in one step. This is the typical case where a DMA channel performs a constant
* role. The alternative is (2) where the DMA channel is reconfigured on the fly.
* In this case, the chflags provided to sam_dmachannel are not used and
* sam_dmaconfig() is called before each DMA to configure the DMA channel
* appropriately.
*
* Returned Value:
* None
*
************************************************************************************/
void sam_dmaconfig(DMA_HANDLE handle, uint32_t chflags)
{
struct sam_dmach_s *dmach = (struct sam_dmach_s *)handle;
/* Set the new DMA channel flags. */
dmavdbg("chflags: %08x\n", (int)chflags);
dmach->flags = chflags;
}
/****************************************************************************
* Name: sam_dmafree
*
@@ -1329,14 +1461,7 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
* transfers and the number of bytes per transfer.
*/
if ((dmach->flags & DMACH_FLAG_MEMCHUNKSIZE) == DMACH_FLAG_MEMCHUNKSIZE_4)
{
maxtransfer = 4 * DMACHAN_CTRLA_BTSIZE_MAX;
}
else
{
maxtransfer = DMACHAN_CTRLA_BTSIZE_MAX;
}
maxtransfer = sam_maxtxtransfer(dmach);
/* If this is a large transfer, break it up into smaller buffers */
@@ -1403,14 +1528,7 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
* transfers and the number of bytes per transfer.
*/
if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) == DMACH_FLAG_PERIPHCHUNKSIZE_4)
{
maxtransfer = 4 * DMACHAN_CTRLA_BTSIZE_MAX;
}
else
{
maxtransfer = DMACHAN_CTRLA_BTSIZE_MAX;
}
maxtransfer = sam_maxrxtransfer(dmach);
/* If this is a large transfer, break it up into smaller buffers */
+18
View File
@@ -194,6 +194,24 @@ extern "C"
DMA_HANDLE sam_dmachannel(uint32_t dmach_flags);
/****************************************************************************
* Name: sam_dmaconfig
*
* Description:
* There are two channel usage models: (1) The channel is allocated and
* configured in one step. This is the typical case where a DMA channel
* performs a constant role. The alternative is (2) where the DMA channel
* is reconfigured on the fly. In this case, the chflags provided to
* sam_dmachannel are not used and sam_dmaconfig() is called before each
* DMA to configure the DMA channel appropriately.
*
* Returned Value:
* None
*
****************************************************************************/
void sam_dmaconfig(DMA_HANDLE handle, uint32_t chflags);
/****************************************************************************
* Name: sam_dmafree
*
+26
View File
@@ -245,6 +245,32 @@ if SAMA5_SPI0 || SAMA5_SPI1
menu "SPI device driver options"
config SAMA5_SPI_DMA
bool "SPI DMA"
default n
depends on (SAMA5_DMAC0 && SAMA5_SPI0) || (SAMA5_DMAC1 && SAMA5_SPI1)
---help---
Use DMA to improve SPI transfer performance.
config SAMA5_SPI_DMATHRESHOLD
int "SPI DMA threshold"
default 4
depends on SAMA5_SPI_DMA
---help---
When SPI DMA is enabled, small DMA transfers will still be performed
by polling logic. But we need a threshold value to determine what
is small. That value is provided by CONFIG_SAMA5_SPI_DMATHRESHOLD.
config SAMA5_SPI_DMADEBUG
bool "SPI DMA transfer debug"
depends on SAMA5_SPI_DMA && DEBUG && DEBUG_DMA
default n
---help---
Enable special debug instrumentation analyze SPI DMA data transfers.
This logic is as non-invasive as possible: It samples DMA
registers at key points in the data transfer and then dumps all of
the registers at the end of the transfer.
config SAMA5_SPI_REGDEBUG
bool "SPI Register level debug"
depends on DEBUG
+3 -4
View File
@@ -509,11 +509,10 @@
# define DMAC_EBC_DICERR6 (1 << (DMAC_EBC_DICERR_SHIFT+6))
# define DMAC_EBC_DICERR7 (1 << (DMAC_EBC_DICERR_SHIFT+7))
#define DMAC_EBC_BTCINTS(n) (0x00010001 << (n)) /* BTC+ERR interrupts */
#define DMAC_EBC_CBTCINTS(n) (0x00010100 << (n)) /* CBT+ERR interrupts */
#define DMAC_EBC_CHANINTS(n) (0x00010101 << (n)) /* BTC+CBT+ERR interrupts */
#define DMAC_EBC_ALLCHANINTS(n) (0x01010101 << (n)) /* All channel interrupts */
#define DMAC_EBC_ALLINTS (0xffffffff) /* All interrupts */
#define DMAC_EBC_ALLCHANINTS (0x00ffffff) /* All BTC+CBT+ERR interrupts */
#define DMAC_EBC_ALLINTS (0xffffffff) /* All channel interrupts */
/* DMAC Channel Handler Enable Register */
@@ -695,7 +694,7 @@
# define DMAC_CH_CTRLB_SRCINCR_INCR (0 << DMAC_CH_CTRLB_SRCINCR_SHIFT) /* Incrementing address */
# define DMAC_CH_CTRLB_SRCINCR_DECR (1 << DMAC_CH_CTRLB_SRCINCR_SHIFT) /* Decrementing address */
# define DMAC_CH_CTRLB_SRCINCR_FIXED (2 << DMAC_CH_CTRLB_SRCINCR_SHIFT) /* Fixed address */
#define DMAC_CH_CTRLB_DSTINCR_SHIFT (28) /* Bits 28-29 */
#define DMAC_CH_CTRLB_DSTINCR_SHIFT (28) /* Bits 28-29 */
#define DMAC_CH_CTRLB_DSTINCR_MASK (3 << DMAC_CH_CTRLB_DSTINCR_SHIFT)
# define DMAC_CH_CTRLB_DSTINCR_INCR (0 << DMAC_CH_CTRLB_DSTINCR_SHIFT) /* Incrementing address */
# define DMAC_CH_CTRLB_DSTINCR_DECR (1 << DMAC_CH_CTRLB_DSTINCR_SHIFT) /* Decrementing address */
+129 -82
View File
@@ -848,7 +848,7 @@ static inline uint32_t sam_txctrlabits(struct sam_dmach_s *dmach)
DEBUGASSERT(ndx < 4);
regval = g_srcwidth[ndx];
/* Set the source chuck size (memory chunk size) */
/* Set the source chunk size (memory chunk size) */
chunksize = (dmach->flags & DMACH_FLAG_MEMCHUNKSIZE_MASK)
>> DMACH_FLAG_MEMCHUNKSIZE_SHIFT;
@@ -862,7 +862,7 @@ static inline uint32_t sam_txctrlabits(struct sam_dmach_s *dmach)
DEBUGASSERT(ndx < 4);
regval |= g_destwidth[ndx];
/* Set the destination chuck size (peripheral chunk size) */
/* Set the destination chunk size (peripheral chunk size) */
chunksize = (dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE_MASK)
>> DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT;
@@ -881,37 +881,37 @@ static inline uint32_t sam_txctrlabits(struct sam_dmach_s *dmach)
static size_t sam_maxtxtransfer(struct sam_dmach_s *dmach)
{
unsigned int chunksize;
unsigned int srcwidth;
size_t maxtransfer;
/* Adjust the the source transfer size for the source chunk size (peripheral
* chunk size). BTSIZE is "the number of transfers to be performed, that
* is, for writes it refers to the number of source width transfers
* to perform when DMAC is flow controller. For Reads, BTSIZE refers to
* the number of transfers completed on the Source Interface. ..."
/* Get the maximum transfer size in bytes. BTSIZE is "the number of
* transfers to be performed, that is, for writes it refers to the number
* of source width transfers to perform when DMAC is flow controller. For
* Reads, BTSIZE refers to the number of transfers completed on the Source
* Interface. ..."
*/
chunksize = (dmach->flags & DMACH_FLAG_MEMCHUNKSIZE_MASK)
>> DMACH_FLAG_MEMCHUNKSIZE_SHIFT;
srcwidth = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK)
>> DMACH_FLAG_MEMWIDTH_SHIFT;
switch (chunksize)
switch (srcwidth)
{
default:
case 0: /* 1 byte */
case 0: /* 8 bits, 1 byte */
maxtransfer = DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 1: /* 4 bytes */
case 1: /* 16 bits, 2 bytes */
maxtransfer = 2 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 2: /* 32 bits 4 bytes */
maxtransfer = 4 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 2: /* 8 bytes */
case 3: /* 64 bits, 8 bytes */
maxtransfer = 8 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 3: /* 16 bytes */
maxtransfer = 16 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
}
return maxtransfer;
@@ -927,7 +927,7 @@ static size_t sam_maxtxtransfer(struct sam_dmach_s *dmach)
static uint32_t sam_ntxtransfers(struct sam_dmach_s *dmach, uint32_t dmasize)
{
unsigned int chunksize;
unsigned int srcwidth;
/* Adjust the the source transfer size for the source chunk size (memory
* chunk size). BTSIZE is "the number of transfers to be performed, that
@@ -936,26 +936,26 @@ static uint32_t sam_ntxtransfers(struct sam_dmach_s *dmach, uint32_t dmasize)
* the number of transfers completed on the Source Interface. ..."
*/
chunksize = (dmach->flags & DMACH_FLAG_MEMCHUNKSIZE_MASK)
>> DMACH_FLAG_MEMCHUNKSIZE_SHIFT;
srcwidth = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK)
>> DMACH_FLAG_MEMWIDTH_SHIFT;
switch (chunksize)
switch (srcwidth)
{
default:
case 0: /* 1 byte */
case 0: /* 8 bits, 1 byte */
break;
case 1: /* 4 bytes */
case 1: /* 16 bits, 2 bytes */
dmasize = (dmasize + 1) >> 1;
break;
case 2: /* 32 bits, 4 bytes */
dmasize = (dmasize + 3) >> 2;
break;
case 2: /* 8 bytes */
case 3: /* 64 bits, 8 bytes */
dmasize = (dmasize + 7) >> 3;
break;
case 3: /* 16 bytes */
dmasize = (dmasize + 15) >> 4;
break;
}
return dmasize;
@@ -970,7 +970,7 @@ static uint32_t sam_ntxtransfers(struct sam_dmach_s *dmach, uint32_t dmasize)
****************************************************************************/
static inline uint32_t sam_txctrla(struct sam_dmach_s *dmach,
uint32_t dmasize, uint32_t ctrla)
uint32_t ctrla, uint32_t dmasize)
{
uint32_t ntransfers;
@@ -1014,7 +1014,7 @@ static inline uint32_t sam_rxctrlabits(struct sam_dmach_s *dmach)
DEBUGASSERT(ndx < 4);
regval = g_srcwidth[ndx];
/* Set the source chuck size (peripheral chunk size) */
/* Set the source chunk size (peripheral chunk size) */
chunksize = (dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE_MASK)
>> DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT;
@@ -1030,7 +1030,7 @@ static inline uint32_t sam_rxctrlabits(struct sam_dmach_s *dmach)
DEBUGASSERT(ndx < 4);
regval |= g_destwidth[ndx];
/* Set the destination chuck size (memory chunk size) */
/* Set the destination chunk size (memory chunk size) */
chunksize = (dmach->flags & DMACH_FLAG_MEMCHUNKSIZE_MASK)
>> DMACH_FLAG_MEMCHUNKSIZE_SHIFT;
@@ -1049,37 +1049,37 @@ static inline uint32_t sam_rxctrlabits(struct sam_dmach_s *dmach)
static size_t sam_maxrxtransfer(struct sam_dmach_s *dmach)
{
unsigned int chunksize;
unsigned int srcwidth;
size_t maxtransfer;
/* Adjust the the source transfer size for the source chunk size (peripheral
* chunk size). BTSIZE is "the number of transfers to be performed, that
* is, for writes it refers to the number of source width transfers
* to perform when DMAC is flow controller. For Reads, BTSIZE refers to
* the number of transfers completed on the Source Interface. ..."
/* Get the maximum transfer size in bytes. BTSIZE is "the number of
* transfers to be performed, that is, for writes it refers to the number
* of source width transfers to perform when DMAC is flow controller. For
* Reads, BTSIZE refers to the number of transfers completed on the Source
* Interface. ..."
*/
chunksize = (dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE_MASK)
>> DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT;
srcwidth = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK)
>> DMACH_FLAG_PERIPHWIDTH_SHIFT;
switch (chunksize)
switch (srcwidth)
{
default:
case 0: /* 1 byte */
case 0: /* 8 bits, 1 byte */
maxtransfer = DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 1: /* 4 bytes */
case 1: /* 16 bits, 2 bytes */
maxtransfer = 2 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 2: /* 32 bits, 4 bytes */
maxtransfer = 4 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 2: /* 8 bytes */
case 3: /* 64 bits, 8 bytes */
maxtransfer = 8 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
case 3: /* 16 bytes */
maxtransfer = 16 * DMAC_CH_CTRLA_BTSIZE_MAX;
break;
}
return maxtransfer;
@@ -1095,7 +1095,7 @@ static size_t sam_maxrxtransfer(struct sam_dmach_s *dmach)
static uint32_t sam_nrxtransfers(struct sam_dmach_s *dmach, uint32_t dmasize)
{
unsigned int chunksize;
unsigned int srcwidth;
/* Adjust the the source transfer size for the source chunk size (peripheral
* chunk size). BTSIZE is "the number of transfers to be performed, that
@@ -1104,26 +1104,26 @@ static uint32_t sam_nrxtransfers(struct sam_dmach_s *dmach, uint32_t dmasize)
* the number of transfers completed on the Source Interface. ..."
*/
chunksize = (dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE_MASK)
>> DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT;
srcwidth = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK)
>> DMACH_FLAG_PERIPHWIDTH_SHIFT;
switch (chunksize)
switch (srcwidth)
{
default:
case 0: /* 1 byte */
case 0: /* 8 bits, 1 byte */
break;
case 1: /* 4 bytes */
case 1: /* 16 bits, 2 bytes */
dmasize = (dmasize + 1) >> 1;
break;
case 2: /* 32 bits, 4 bytes */
dmasize = (dmasize + 3) >> 2;
break;
case 2: /* 8 bytes */
case 3: /* 64 bits, 8 bytes */
dmasize = (dmasize + 7) >> 3;
break;
case 3: /* 16 bytes */
dmasize = (dmasize + 15) >> 4;
break;
}
return dmasize;
@@ -1138,7 +1138,7 @@ static uint32_t sam_nrxtransfers(struct sam_dmach_s *dmach, uint32_t dmasize)
****************************************************************************/
static inline uint32_t sam_rxctrla(struct sam_dmach_s *dmach,
uint32_t dmasize, uint32_t ctrla)
uint32_t ctrla, uint32_t dmasize)
{
uint32_t ntransfers;
@@ -1564,7 +1564,7 @@ static int sam_rxbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
ctrlb = sam_rxctrlb(dmach);
}
ctrla = sam_rxctrla(dmach, nbytes, regval);
ctrla = sam_rxctrla(dmach, regval, nbytes);
/* Add the new link list entry */
@@ -1769,9 +1769,9 @@ static int sam_dmac_interrupt(struct sam_dmac_s *dmac)
regval = sam_getdmac(dmac, SAM_DMAC_EBCISR_OFFSET) &
sam_getdmac(dmac, SAM_DMAC_EBCIMR_OFFSET);
/* Check if the any transfer has completed */
/* Check if the any transfer has completed or any errors have ocurred. */
if (regval & DMAC_EBC_BTC_MASK)
if (regval & DMAC_EBC_ALLCHANINTS)
{
/* Yes.. Check each bit to see which channel has interrupted */
@@ -1933,10 +1933,8 @@ void weak_function up_dmainitialize(void)
/****************************************************************************
* Name: sam_dmachannel
*
* Description:
* Allocate a DMA channel. This function sets aside a DMA channel with
* the required FIFO size and flow control capabilities (determined by
* dma_flags) then gives the caller exclusive access to the DMA channel.
* Allocate a DMA channel. This function sets aside a DMA channel then
* gives the caller exclusive access to the DMA channel.
*
* The naming convention in all of the DMA interfaces is that one side is
* the 'peripheral' and the other is 'memory'. Howerver, the interface
@@ -1944,9 +1942,8 @@ void weak_function up_dmainitialize(void)
* the naming would be awkward.
*
* Returned Value:
* If a DMA channel if the required FIFO size is available, this function
* returns a non-NULL, void* DMA channel handle. NULL is returned on any
* failure.
* If a DMA channel is available, this function returns a non-NULL, void*
* DMA channel handle. NULL is returned on any failure.
*
****************************************************************************/
@@ -1975,7 +1972,7 @@ DMA_HANDLE sam_dmachannel(uint8_t dmacno, uint32_t chflags)
#endif
{
dmadbg("Bad DMAC number: %d\n", dmacno);
dmadbg("ERROR: Bad DMAC number: %d\n", dmacno);
DEBUGPANIC();
return (DMA_HANDLE)NULL;
}
@@ -2006,7 +2003,7 @@ DMA_HANDLE sam_dmachannel(uint8_t dmacno, uint32_t chflags)
sam_putdmac(dmac,DMAC_CHDR_DIS(chndx), SAM_DMAC_CHDR_OFFSET);
/* See the DMA channel flags. */
/* Set the DMA channel flags. */
dmach->flags = chflags;
break;
@@ -2015,11 +2012,57 @@ DMA_HANDLE sam_dmachannel(uint8_t dmacno, uint32_t chflags)
sam_givechsem(dmac);
dmavdbg("dmacno: %d chflags: %08x returning dmach: %p\n",
(int)dmacno, (int)chflags, dmach);
/* Show the result of the allocation */
if (dmach)
{
dmavdbg("DMAC%d CH%d: chflags: %08x returning dmach: %p\n",
(int)dmacno, dmach->chan, (int)chflags, dmach);
}
else
{
dmadbg("ERROR: Failed allocate DMAC%d channel\n", (int)dmacno);
}
return (DMA_HANDLE)dmach;
}
/************************************************************************************
* Name: sam_dmaconfig
*
* Description:
* There are two channel usage models: (1) The channel is allocated and configured
* in one step. This is the typical case where a DMA channel performs a constant
* role. The alternative is (2) where the DMA channel is reconfigured on the fly.
* In this case, the chflags provided to sam_dmachannel are not used and
* sam_dmaconfig() is called before each DMA to configure the DMA channel
* appropriately.
*
* Returned Value:
* None
*
************************************************************************************/
void sam_dmaconfig(DMA_HANDLE handle, uint32_t chflags)
{
struct sam_dmach_s *dmach = (struct sam_dmach_s *)handle;
/* Set the new DMA channel flags. */
dmach->flags = chflags;
#if defined(CONFIG_SAMA5_DMAC0) && defined(CONFIG_SAMA5_DMAC1)
dmavdbg("DMAC%d CH%d: chflags: %08x\n",
dmach->dmac, dmach->chan, (int)chflags);
#elif defined(CONFIG_SAMA5_DMAC0)
dmavdbg("DMAC0 CH%d: chflags: %08x\n",
dmach->chan, (int)chflags);
#else
dmavdbg("DMAC1 CH%d: chflags: %08x\n",
dmach->chan, (int)chflags);
#endif
}
/****************************************************************************
* Name: sam_dmafree
*
@@ -2064,6 +2107,7 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
{
struct sam_dmach_s *dmach = (struct sam_dmach_s *)handle;
size_t maxtransfer;
size_t remaining;
int ret = OK;
dmavdbg("dmach: %p paddr: %08x maddr: %08x nbytes: %d\n",
@@ -2076,10 +2120,11 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
*/
maxtransfer = sam_maxtxtransfer(dmach);
remaining = nbytes;
/* If this is a large transfer, break it up into smaller buffers */
while (nbytes > maxtransfer)
while (remaining > maxtransfer)
{
/* Set up the maximum size transfer */
@@ -2088,7 +2133,7 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
{
/* Decrement the number of bytes left to transfer */
nbytes -= maxtransfer;
remaining -= maxtransfer;
/* Increment the memory & peripheral address (if it is appropriate to
* do do).
@@ -2108,9 +2153,9 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
/* Then set up the final buffer transfer */
if (ret == OK && nbytes > 0)
if (ret == OK && remaining > 0)
{
ret = sam_txbuffer(dmach, paddr, maddr, nbytes);
ret = sam_txbuffer(dmach, paddr, maddr, remaining);
}
/* Clean caches associated with the DMA memory */
@@ -2135,6 +2180,7 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
{
struct sam_dmach_s *dmach = (struct sam_dmach_s *)handle;
size_t maxtransfer;
size_t remaining;
int ret = OK;
dmavdbg("dmach: %p paddr: %08x maddr: %08x nbytes: %d\n",
@@ -2147,10 +2193,11 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
*/
maxtransfer = sam_maxrxtransfer(dmach);
remaining = nbytes;
/* If this is a large transfer, break it up into smaller buffers */
while (nbytes > maxtransfer)
while (remaining > maxtransfer)
{
/* Set up the maximum size transfer */
@@ -2159,7 +2206,7 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
{
/* Decrement the number of bytes left to transfer */
nbytes -= maxtransfer;
remaining -= maxtransfer;
/* Increment the memory & peripheral address (if it is appropriate to
* do do).
@@ -2179,9 +2226,9 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
/* Then set up the final buffer transfer */
if (ret == OK && nbytes > 0)
if (ret == OK && remaining > 0)
{
ret = sam_rxbuffer(dmach, paddr, maddr, nbytes);
ret = sam_rxbuffer(dmach, paddr, maddr, remaining);
}
/* Clean caches associated with the DMA memory */
+59 -48
View File
@@ -187,100 +187,112 @@ extern "C"
* Public Function Prototypes
************************************************************************************/
/****************************************************************************
/************************************************************************************
* Name: sam_dmachannel
*
* Description:
* Allocate a DMA channel. This function sets aside a DMA channel with
* the required FIFO size and flow control capabilities (determined by
* dma_flags) then gives the caller exclusive access to the DMA channel.
* Allocate a DMA channel. This function sets aside a DMA channel then gives the
* caller exclusive access to the DMA channel.
*
* The naming convention in all of the DMA interfaces is that one side is
* the 'peripheral' and the other is 'memory'. Howerver, the interface
* could still be used if, for example, both sides were memory although
* the naming would be awkward.
* The naming convention in all of the DMA interfaces is that one side is the
* 'peripheral' and the other is 'memory'. Howerver, the interface could still
* be used if, for example, both sides were memory although the naming would be
* awkward.
*
* Returned Value:
* If a DMA channel if the required FIFO size is available, this function
* returns a non-NULL, void* DMA channel handle. NULL is returned on any
* failure.
* If a DMA channel is available, this function returns a non-NULL, void* DMA
* channel handle. NULL is returned on any failure.
*
****************************************************************************/
************************************************************************************/
DMA_HANDLE sam_dmachannel(uint8_t dmacno, uint32_t dmach_flags);
DMA_HANDLE sam_dmachannel(uint8_t dmacno, uint32_t chflags);
/****************************************************************************
* Name: sam_dmafree
/************************************************************************************
* Name: sam_dmaconfig
*
* Description:
* Release a DMA channel. NOTE: The 'handle' used in this argument must
* NEVER be used again until sam_dmachannel() is called again to re-gain
* a valid handle.
* There are two channel usage models: (1) The channel is allocated and configured
* in one step. This is the typical case where a DMA channel performs a constant
* role. The alternative is (2) where the DMA channel is reconfigured on the fly.
* In this case, the chflags provided to sam_dmachannel are not used and
* sam_dmaconfig() is called before each DMA to configure the DMA channel
* appropriately.
*
* Returned Value:
* None
*
****************************************************************************/
************************************************************************************/
void sam_dmaconfig(DMA_HANDLE handle, uint32_t chflags);
/************************************************************************************
* Name: sam_dmafree
*
* Description:
* Release a DMA channel. NOTE: The 'handle' used in this argument must NEVER be
* used again until sam_dmachannel() is called again to re-gain a valid handle.
*
* Returned Value:
* None
*
************************************************************************************/
void sam_dmafree(DMA_HANDLE handle);
/****************************************************************************
/************************************************************************************
* Name: sam_dmatxsetup
*
* Description:
* Configure DMA for transmit of one buffer (memory to peripheral). This
* function may be called multiple times to handle large and/or dis-
* continuous transfers. Calls to sam_dmatxsetup() and sam_dmarxsetup()
* must not be intermixed on the same transfer, however.
* Configure DMA for transmit of one buffer (memory to peripheral). This function
* may be called multiple times to handle large and/or discontinuous transfers.
* Calls to sam_dmatxsetup() and sam_dmarxsetup() must not be intermixed on the
* same transfer, however.
*
****************************************************************************/
************************************************************************************/
int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
size_t nbytes);
int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nbytes);
/****************************************************************************
/************************************************************************************
* Name: sam_dmarxsetup
*
* Description:
* Configure DMA for receipt of one buffer (peripheral to memory). This
* function may be called multiple times to handle large and/or dis-
* continuous transfers. Calls to sam_dmatxsetup() and sam_dmarxsetup()
* must not be intermixed on the same transfer, however.
* Configure DMA for receipt of one buffer (peripheral to memory). This function
* may be called multiple times to handle large and/or discontinuous transfers.
* Calls to sam_dmatxsetup() and sam_dmarxsetup() must not be intermixed on the
* same transfer, however.
*
****************************************************************************/
************************************************************************************/
int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
size_t nbytes);
int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nbytes);
/****************************************************************************
/************************************************************************************
* Name: sam_dmastart
*
* Description:
* Start the DMA transfer
*
****************************************************************************/
************************************************************************************/
int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg);
/****************************************************************************
/************************************************************************************
* Name: sam_dmastop
*
* Description:
* Cancel the DMA. After sam_dmastop() is called, the DMA channel is
* reset and sam_dmarx/txsetup() must be called before sam_dmastart() can be
* called again
* Cancel the DMA. After sam_dmastop() is called, the DMA channel is reset and
* sam_dmarx/txsetup() must be called before sam_dmastart() can be called again
*
****************************************************************************/
************************************************************************************/
void sam_dmastop(DMA_HANDLE handle);
/****************************************************************************
/************************************************************************************
* Name: sam_dmasample
*
* Description:
* Sample DMA register contents
*
****************************************************************************/
************************************************************************************/
#ifdef CONFIG_DEBUG_DMA
void sam_dmasample(DMA_HANDLE handle, struct sam_dmaregs_s *regs);
@@ -288,17 +300,16 @@ void sam_dmasample(DMA_HANDLE handle, struct sam_dmaregs_s *regs);
# define sam_dmasample(handle,regs)
#endif
/****************************************************************************
/************************************************************************************
* Name: sam_dmadump
*
* Description:
* Dump previously sampled DMA register contents
*
****************************************************************************/
************************************************************************************/
#ifdef CONFIG_DEBUG_DMA
void sam_dmadump(DMA_HANDLE handle, const struct sam_dmaregs_s *regs,
const char *msg);
void sam_dmadump(DMA_HANDLE handle, const struct sam_dmaregs_s *regs, const char *msg);
#else
# define sam_dmadump(handle,regs,msg)
#endif
+14 -14
View File
@@ -420,7 +420,7 @@ static void sam_cmddump(struct sam_dev_s *priv);
/* DMA Helpers **************************************************************/
static void sam_dmacallback(DMA_HANDLE handle, void *arg, int result);
static uint32_t sam_dmaregister(struct sam_dev_s *priv, unsigned int offset);
static uint32_t sam_physregaddr(struct sam_dev_s *priv, unsigned int offset);
/* Data Transfer Helpers ****************************************************/
@@ -1074,50 +1074,50 @@ static void sam_dmacallback(DMA_HANDLE handle, void *arg, int result)
}
/****************************************************************************
* Name: sam_dmaregister
* Name: sam_physregaddr
*
* Description:
* Return the physical address of an HSMCI register
*
****************************************************************************/
static uint32_t sam_dmaregister(struct sam_dev_s *priv, unsigned int offset)
static uint32_t sam_physregaddr(struct sam_dev_s *priv, unsigned int offset)
{
/* Get the offset into the 1MB section containing the HSMCI registers */
uint32_t pbase = priv->base & 0xfff00000;
uint32_t pbase = priv->base & 0x000fffff;
#ifdef CONFIG_HSMCI_HSMCI0
#ifdef CONFIG_SAMA5_HSMCI0
/* Add in the physical base for HSMCI0
*
* We only have to check if this is HSMCI0 if either HSMCI1 or HSMCI2 are
* enabled.
*/
#if defined(CONFIG_HSMCI_HSMCI1) || defined(CONFIG_HSMCI_HSMCI2)
#if defined(CONFIG_SAMA5_HSMCI1) || defined(CONFIG_SAMA5_HSMCI2)
if (priv->hsmci == 0)
#endif
{
pbase |= SAM_PERIPHA_PSECTION;
}
#if defined(CONFIG_HSMCI_HSMCI1) || defined(CONFIG_HSMCI_HSMCI2)
#if defined(CONFIG_SAMA5_HSMCI1) || defined(CONFIG_SAMA5_HSMCI2)
else
#endif
#endif
#ifdef CONFIG_HSMCI_HSMCI1
#ifdef CONFIG_SAMA5_HSMCI1
/* Add in the physical base for HSMCI1
*
* We only have to check if this is HSCMCi1 if HSMCI2 is enabled.
*/
#ifdef CONFIG_HSMCI_HSMCI2
#ifdef CONFIG_SAMA5_HSMCI2
if (priv->hsmci == 1)
#endif
{
pbase |= SAM_PERIPHB_PSECTION;
}
#ifdef CONFIG_HSMCI_HSMCI2
#ifdef CONFIG_SAMA5_HSMCI2
else
#endif
#endif
@@ -1127,7 +1127,7 @@ static uint32_t sam_dmaregister(struct sam_dev_s *priv, unsigned int offset)
* If we get here, we con't have to check.
*/
#ifdef CONFIG_HSMCI_HSMCI2
#ifdef CONFIG_SAMA5_HSMCI2
{
pbase |= SAM_PERIPHB_PSECTION;
}
@@ -2351,7 +2351,7 @@ static sdio_eventset_t sam_eventwait(FAR struct sdio_dev_s *dev,
if (ret != OK)
{
fdbg("ERROR: wd_start failed: %d\n", ret);
}
}
}
/* Loop until the event (or the timeout occurs). Race conditions are avoided
@@ -2512,7 +2512,7 @@ static int sam_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
/* Physical address of the HSCMI RDR registr */
rdr = sam_dmaregister(priv, SAM_HSMCI_RDR_OFFSET);
rdr = sam_physregaddr(priv, SAM_HSMCI_RDR_OFFSET);
/* Setup register sampling */
@@ -2566,7 +2566,7 @@ static int sam_dmasendsetup(FAR struct sdio_dev_s *dev,
/* Physical address of the HSCMI TDR registr */
tdr = sam_dmaregister(priv, SAM_HSMCI_TDR_OFFSET);
tdr = sam_physregaddr(priv, SAM_HSMCI_TDR_OFFSET);
/* Setup register sampling */
File diff suppressed because it is too large Load Diff
+10
View File
@@ -987,6 +987,16 @@ Configurations
CONFIG_SAMA5_AT25_AUTOMOUNT=y : Mounts AT25 for NSH
CONFIG_SAMA5_AT25_FTL=y : Create block driver for FAT
The SPI driver can be built to do polled or DMA SPI data transfers.
The following additional changes will enable SPI DMA:
System Type -> SAMA5 Peripheral Support
CONFIG_SAMA5_DMAC0=y : Enable DMA controller 0
System Type -> SPI device driver options
CONFIG_SAMA5_SPI_DMA=y : Use DMA for SPI transfers
CONFIG_SAMA5_SPI_DMATHRESHOLD=4 : Don't DMA for small transfers
NOTE that you must close JP1 on the Embest/Ronetix board in
order to enable the AT25 FLASH chip select.
+1
View File
@@ -114,6 +114,7 @@ int nsh_archinitialize(void)
{
fdbg("ERROR: sam_at25_initialize failed: %d\n", ret);
return ret;
}
#endif
#ifdef HAVE_HSMCI_MTD
-1
View File
@@ -205,7 +205,6 @@ static inline int at25_readid(struct at25_dev_s *priv)
{
uint16_t manufacturer;
uint16_t memory;
uint16_t version;
fvdbg("priv: %p\n", priv);