mirror of
https://github.com/apache/nuttx.git
synced 2026-09-20 21:06:58 +08:00
SAM3,4,A5 DMA fixes; SAMA5 SPI driver now supports DMA transfers
This commit is contained in:
@@ -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
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
|
||||
@@ -114,6 +114,7 @@ int nsh_archinitialize(void)
|
||||
{
|
||||
fdbg("ERROR: sam_at25_initialize failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_HSMCI_MTD
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user