summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2010-04-02 00:45:28 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2010-04-02 00:45:28 +0000
commitcb55abfbb0ad9ce15b3b1863f05ba209356ad69c (patch)
tree59b11f3d2a7d863ed0f6803a65aaaa9e0c5ff263
parente7c943a501d80d81c967815466f286285443353d (diff)
downloadnuttx-cb55abfbb0ad9ce15b3b1863f05ba209356ad69c.tar.gz
nuttx-cb55abfbb0ad9ce15b3b1863f05ba209356ad69c.tar.bz2
nuttx-cb55abfbb0ad9ce15b3b1863f05ba209356ad69c.zip
DMA updates
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2568 42af7a65-404d-4744-a932-0658087f49c3
-rwxr-xr-xnuttx/arch/arm/src/sam3u/sam3u_dmac.c909
-rwxr-xr-xnuttx/arch/arm/src/sam3u/sam3u_dmac.h12
-rwxr-xr-xnuttx/arch/arm/src/sam3u/sam3u_hsmci.c13
-rwxr-xr-xnuttx/arch/arm/src/sam3u/sam3u_internal.h33
4 files changed, 820 insertions, 147 deletions
diff --git a/nuttx/arch/arm/src/sam3u/sam3u_dmac.c b/nuttx/arch/arm/src/sam3u/sam3u_dmac.c
index b5ed3e887..2a5253c8f 100755
--- a/nuttx/arch/arm/src/sam3u/sam3u_dmac.c
+++ b/nuttx/arch/arm/src/sam3u/sam3u_dmac.c
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/sam3u-ek/sam3u_dmac.c
*
- * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2010 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Redistribution and use in source and binary forms, with or without
@@ -60,6 +60,31 @@
* Pre-processor Definitions
****************************************************************************/
+/* Configuration ************************************************************/
+
+/* Condition out the whole file unless DMA is selected in the configuration */
+
+#ifdef CONFIG_SAM3U_DMA
+
+/* Check the number of link list descriptors to allocate */
+
+#ifndef CONFIG_SAM3U_NLLDESC
+# define CONFIG_SAM3U_NLLDESC CONFIG_SAM3U_NDMACHAN
+#endif
+
+#if CONFIG_SAM3U_NLLDESC < CONFIG_SAM3U_NDMACHAN
+# warning "At least CONFIG_SAM3U_NDMACHAN descriptors must be allocated */
+
+# undef CONFIG_SAM3U_NLLDESC
+# define CONFIG_SAM3U_NLLDESC CONFIG_SAM3U_NDMACHAN
+#endif
+
+/* Register values **********************************************************/
+
+#define DMACHAN_CTRLB_BOTHDSCR \
+ (DMACHAN_CTRLB_SRCDSCR | DMACHAN_CTRLB_DSTDSCR)
+
+
/****************************************************************************
* Private Types
****************************************************************************/
@@ -68,24 +93,27 @@
struct sam3u_dma_s
{
- uint8_t chan; /* DMA channel number (0-6) */
- bool inuse; /* TRUE: The DMA channel is in use */
- uint32_t flags; /* DMA channel flags */
- uint32_t base; /* DMA register channel base address */
- dma_callback_t callback; /* Callback invoked when the DMA completes */
- void *arg; /* Argument passed to callback function */
- uint16_t bufsize; /* Transfer buffer size in bytes */
- volatile uint16_t remaining; /* Total number of bytes remaining to be transferred */
- int result; /* Transfer result (OK or negated errno) */
+ uint8_t chan; /* DMA channel number (0-6) */
+ bool inuse; /* TRUE: The DMA channel is in use */
+ uint32_t flags; /* DMA channel flags */
+ uint32_t base; /* DMA register channel base address */
+ dma_callback_t callback; /* Callback invoked when the DMA completes */
+ void *arg; /* Argument passed to callback function */
+ uint16_t bufsize; /* Transfer buffer size in bytes */
+ struct dma_linklist_s *llhead; /* DMA link list head */
+ struct dma_linklist_s *lltail; /* DMA link list head */
+ volatile uint16_t remaining; /* Total number of bytes remaining to be transferred */
+ int result; /* Transfer result (OK or negated errno) */
};
/****************************************************************************
* Private Data
****************************************************************************/
-/* This semaphore protects the DMA channel table */
+/* These semaphores protect the DMA channel and descriptor tables */
-static sem_t g_dmasem;
+static sem_t g_chsem;
+static sem_t g_dsem;
/* CTRLA field lookups */
@@ -103,6 +131,17 @@ static const uint32_t g_destwidth[3] =
DMACHAN_CTRLA_DSTWIDTH_WORD
};
+static const uint32_t g_fifocfg[3] =
+{
+ DMACHAN_CFG_FIFOCFG_LARGEST,
+ DMACHAN_CFG_FIFOCFG_HALF,
+ DMACHAN_CFG_FIFOCFG_SINGLE
+};
+
+/* This array describes the available link list descriptors */
+
+static struct dma_linklist_s g_linklist[CONFIG_SAM3U_NLLDESC];
+
/* This array describes the state of each DMA */
static struct sam3u_dma_s g_dma[CONFIG_SAM3U_NDMACHAN] =
@@ -145,40 +184,67 @@ static struct sam3u_dma_s g_dma[CONFIG_SAM3U_NDMACHAN] =
* Private Functions
****************************************************************************/
-/************************************************************************************
- * Name: sam3u_dmatake() and sam3u_dmagive()
+/****************************************************************************
+ * Name: sam3u_takechsem() and sam3u_givechsem()
*
* Description:
- * Used to get exclusive access to a DMA channel.
+ * Used to get exclusive access to the DMA channel table
*
- ************************************************************************************/
+ ****************************************************************************/
-static void sam3u_dmatake(void)
+static void sam3u_takechsem(void)
{
/* Take the semaphore (perhaps waiting) */
- while (sem_wait(&g_dmasem) != 0)
+ while (sem_wait(&g_chsem) != 0)
{
- /* The only case that an error should occur here is if the wait was awakened
- * by a signal.
+ /* The only case that an error should occur here is if the wait was
+ * awakened by a signal.
*/
ASSERT(errno == EINTR);
}
}
-static inline void sam3u_dmagive(void)
+static inline void sam3u_givechsem(void)
{
- (void)sem_post(&g_dmasem);
+ (void)sem_post(&g_chsem);
}
-/************************************************************************************
+****************************************************************************
+ * Name: sam3u_takedsem() and sam3u_givedsem()
+ *
+ * Description:
+ * Used to wait for availability of descriptors in the descriptor table.
+ *
+ ****************************************************************************/
+
+static void sam3u_takedsem(void)
+{
+ /* Take the semaphore (perhaps waiting) */
+
+ while (sem_wait(&g_dsem) != 0)
+ {
+ /* The only case that an error should occur here is if the wait was
+ * awakened by a signal.
+ */
+
+ ASSERT(errno == EINTR);
+ }
+}
+
+static inline void sam3u_givedsem(void)
+{
+ (void)sem_post(&g_dsem);
+}
+
+/****************************************************************************
* Name: sam3u_fifosize
*
* Description:
* Decode the FIFO size from the flags
*
- ************************************************************************************/
+ ****************************************************************************/
static unsigned int sam3u_fifosize(uint8_t dmach_flags)
{
@@ -193,38 +259,52 @@ static unsigned int sam3u_fifosize(uint8_t dmach_flags)
}
}
-/************************************************************************************
+/****************************************************************************
* Name: sam3u_flowcontrol
*
* Description:
* Decode the FIFO flow control from the flags
*
- ************************************************************************************/
+ ****************************************************************************/
static inline boolean sam3u_flowcontrol(uint8_t dmach_flags)
{
return ((dmach_flags & DMACH_FLAG_FLOWCONTROL) != 0);
}
-/************************************************************************************
+/****************************************************************************
+ * Name: sam3u_flowcontrol
+ *
+ * Description:
+ * Decode the FIFO config from the flags
+ *
+ ****************************************************************************/
+
+static uint32_t sam3u_fifocfg(struct sam3u_dma_s *dmach)
+{
+ unsigned int ndx = (dmach->flags & DMACH_FLAG_FIFOCFG_MASK) >> DMACH_FLAG_FIFOCFG_SHIFT;
+ DEBUGASSERT(ndx < 3);
+ return sam3u_fifocfg[ndx];
+}
+
+/****************************************************************************
* Name: sam3u_txctrlabits
*
* Description:
- * Decode the the flags to get the correct CTRLA register bit settings for a transmit
- * (memory to peripheral) transfer. These are only the "fixed" CTRLA values and
- * need to be updated with the actual transfer size before being written to CTRLA
- * sam3u_txctrla).
+ * Decode the the flags to get the correct CTRLA register bit settings for
+ * a transmit (memory to peripheral) transfer. These are only the "fixed"
+ * CTRLA values and need to be updated with the actual transfer size before
+ * being written to CTRLA sam3u_txctrla).
*
- ************************************************************************************/
+ ****************************************************************************/
static inline uint32_t
-sam3u_txctrlabits(struct sam3u_dma_s *dmach, uint32_t otherbits)
+sam3u_txctrlabits(struct sam3u_dma_s *dmach)
{
uint32_t regval;
unsigned int ndx;
DEBUGASSERT(dmach);
- regval = otherbits;
/* Since this is a transmit, the source is described by the memory selections.
* Set the source width (memory width).
@@ -232,7 +312,7 @@ sam3u_txctrlabits(struct sam3u_dma_s *dmach, uint32_t otherbits)
ndx = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >> DMACH_FLAG_MEMWIDTH_SHIFT;
DEBUGASSERT(ndx < 3);
- regval |= g_srcwidth[ndx];
+ regval = g_srcwidth[ndx];
/* Set the source chuck size (memory chunk size) */
@@ -271,21 +351,23 @@ sam3u_txctrlabits(struct sam3u_dma_s *dmach, uint32_t otherbits)
return regval;
}
-/************************************************************************************
+/****************************************************************************
* Name: sam3u_txctrla
*
* Description:
* Or in the variable CTRLA bits
*
- ************************************************************************************/
+ ****************************************************************************/
static inline uint32_t sam3u_txctrla(uint32_t dmasize, uint32_t txctrlabits)
{
- /* 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.
+ /* 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) */
+ /* Adjust the the source transfer size for the source chunk size (memory
+ * chunk size)
+ */
if ((dmach->flags & DMACH_FLAG_MEMCHUNKSIZE) == DMACH_FLAG_MEMCHUNKSIZE_4)
{
@@ -296,33 +378,32 @@ static inline uint32_t sam3u_txctrla(uint32_t dmasize, uint32_t txctrlabits)
return (txctrlabits & ~DMACHAN_CTRLA_BTSIZE_MASK) | (dmasize << DMACHAN_CTRLA_BTSIZE_SHIFT);
}
-/************************************************************************************
+/****************************************************************************
* Name: sam3u_setrxctrla
*
* Description:
- * Decode the the flags to get the correct CTRLA register bit settings for a read
- * (peripheral to memory) transfer. These are only the "fixed" CTRLA values and
- * need to be updated with the actual transfer size before being written to CTRLA
- * sam3u_rxctrla).
+ * Decode the the flags to get the correct CTRLA register bit settings for
+ * a read (peripheral to memory) transfer. These are only the "fixed" CTRLA
+ * values and need to be updated with the actual transfer size before being
+ * written to CTRLA sam3u_rxctrla).
*
- ************************************************************************************/
+ ****************************************************************************/
static inline uint32_t
-sam3u_setrxctrla(struct sam3u_dma_s *dmach, uint32_t otherbits)
+sam3u_setrxctrla(struct sam3u_dma_s *dmach)
{
uint32_t regval;
unsigned int ndx;
DEBUGASSERT(dmach && dmasize <= DMACHAN_CTRLA_BTSIZE_MAX);
- regval = otherbits;
- /* Since this is a receive, the source is described by the peripheral selections.
- * Set the source width (peripheral width).
+ /* Since this is a receive, the source is described by the peripheral
+ * selections. Set the source width (peripheral width).
*/
ndx = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> DMACH_FLAG_PERIPHWIDTH_SHIFT;
DEBUGASSERT(ndx < 3);
- regval |= g_srcwidth[ndx];
+ regval = g_srcwidth[ndx];
/* Set the source chuck size (peripheral chunk size) */
@@ -361,21 +442,23 @@ sam3u_setrxctrla(struct sam3u_dma_s *dmach, uint32_t otherbits)
return regval;
}
-/************************************************************************************
+/****************************************************************************
* Name: sam3u_rxctrla
*
* Description:
- * Or in the variable CTRLA bits
+ * 'OR' in the variable CTRLA bits
*
- ************************************************************************************/
+ ****************************************************************************/
static inline uint32_t sam3u_rxctrla(uint32_t dmasize, uint32_t txctrlabits)
{
- /* 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.
+ /* 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) */
+ /* Adjust the the source transfer size for the source chunk size (peripheral
+ * chunk size)
+ */
if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) == DMACH_FLAG_PERIPHCHUNKSIZE_4)
{
@@ -386,79 +469,171 @@ static inline uint32_t sam3u_rxctrla(uint32_t dmasize, uint32_t txctrlabits)
return (txctrlabits & ~DMACHAN_CTRLA_BTSIZE_MASK) | (dmasize << DMACHAN_CTRLA_BTSIZE_SHIFT);
}
-/************************************************************************************
- * Name: sam3u_srcctrlb
+/****************************************************************************
+ * Name: sam3u_txctrlb
*
* Description:
- * Set source related CTRLB fields
+ * Decode the the flags to get the correct CTRLB register bit settings for
+ * a transmit (memory to peripheral) transfer.
*
- ************************************************************************************/
+ ****************************************************************************/
-static void sam3u_srcctrlb(struct sam3u_dma_s *dmach, bool lli, bool autoincr)
+static inline void sam3u_txctrlb(struct sam3u_dma_s *dmach)
{
uint32_t regval;
+
+ /* Assume that we will not be using the link list and disable the source
+ * and destination descriptors. The default will be single transfer mode.
+ */
- /* Fetch CTRLB and clear the configurable bits */
+ regval = DMACHAN_CTRLB_BOTHDSCR;
- regval = getreg32(dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET);
- regval &= ~ (DMACHAN_CTRLB_SRCDSCR | DMACHAN_CTRLB_SRCINCR_MASK | 1<<31);
+ /* Select flow control (even if the channel doesn't support it). The
+ * naming convention from TX is memory to peripheral, but that is really be
+ * determined by bits in the DMA flags.
+ */
+
+ /* Is the memory source really a peripheral? */
+
+ if ((dmach->flags & DMACH_FLAG_MEMISPERIPH) != 0)
+ {
+ /* Yes.. is the peripheral destination also a peripheral? */
- /* Disable the source descriptor if we are not using the LLI transfer mode */
+ if ((dmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0)
+ {
+ /* Yes.. Use peripheral-to-peripheral flow control */
- if (lli)
+ regval |= DMACHAN_CTRLB_FC_P2P;
+ }
+ else
+ {
+ /* No.. Use peripheral-to-memory flow control */
+
+ regval |= DMACHAN_CTRLB_FC_P2M;
+ }
+ }
+ else
{
- regval |= DMACHAN_CTRLB_SRCDSCR;
+ /* No, the source is memory. Is the peripheral destination a
+ * peripheral
+ */
+
+ if ((dmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0)
+ {
+ /* Yes.. Use memory-to-peripheral flow control */
+
+ regval |= DMACHAN_CTRLB_FC_M2P;
+ }
+ else
+ {
+ /* No.. Use memory-to-memory flow control */
+
+ regval |= DMACHAN_CTRLB_FC_M2M;
+ }
}
- /* Select address incrementing */
+ /* Select source address incrementing */
- regval |= autoincr ? DMACHAN_CTRLB_SRCINCR_INCR ? DMACHAN_CTRLB_SRCINCR_FIXED;
+ if ((dmach->flags & DMACH_FLAG_MEMINCREMENT) == 0)
+ {
+ regval |= DMACHAN_CTRLB_SRCINCR_FIXED;
+ }
- /* Save the updated CTRLB value */
+ /* Select destination address incrementing */
- putreg32(regval, dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET)
+ if ((dmach->flags & DMACH_FLAG_PERIPHINCREMENT) == 0)
+ {
+ regval |= DMACHAN_CTRLB_DESTINCR_FIXED;
+ }
+ return regval;
}
-/************************************************************************************
- * Name: sam3u_destctrlb
+/****************************************************************************
+ * Name: sam3u_rxctrlb
*
* Description:
- * Set destination related CTRLB fields
+ * Decode the the flags to get the correct CTRLB register bit settings for
+ * a receive (peripheral to memory) transfer.
*
- ************************************************************************************/
+ ****************************************************************************/
-static void sam3u_destctrlb(struct sam3u_dma_s *dmach, bool lli, bool autoincr)
+static inline void sam3u_rxctrlb(struct sam3u_dma_s *dmach)
{
uint32_t regval;
+
+ /* Assume that we will not be using the link list and disable the source and
+ * destination descriptors. The default will be single transfer mode.
+ */
- /* Fetch CTRLB and clear the configurable bits */
+ regval = DMACHAN_CTRLB_BOTHDSCR;
- regval = getreg32(dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET);
- regval &= ~ (DMACHAN_CTRLB_DSTDSCR | DMACHAN_CTRLB_DSTINCR_MASK);
+ /* Select flow control (even if the channel doesn't support it). The
+ * naming convention from RX is peripheral to memory, but that is really be
+ * determined by bits in the DMA flags.
+ */
- /* Disable the source descriptor if we are not using the LLI transfer mode */
+ /* Is the peripheral source really a peripheral? */
- if (lli)
+ if ((dmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0)
{
- regval |= DMACHAN_CTRLB_DSTDSCR;
+ /* Yes.. is the memory destination also a peripheral? */
+
+ if ((dmach->flags & DMACH_FLAG_MEMISPERIPH) != 0)
+ {
+ /* Yes.. Use peripheral-to-peripheral flow control */
+
+ regval |= DMACHAN_CTRLB_FC_P2P;
+ }
+ else
+ {
+ /* No.. Use peripheral-to-memory flow control */
+
+ regval |= DMACHAN_CTRLB_FC_P2M;
+ }
}
+ else
+ {
+ /* No, the peripheral source is memory. Is the memory destination
+ * a peripheral
+ */
- /* Select address incrementing */
+ if ((dmach->flags & DMACH_FLAG_MEMISPERIPH) != 0)
+ {
+ /* Yes.. Use memory-to-peripheral flow control */
- regval |= autoincr ? DMACHAN_CTRLB_DESTINCR_INCR ? DMACHAN_CTRLB_DESTINCR_FIXED;
-
- /* Save the updated CTRLB value */
+ regval |= DMACHAN_CTRLB_FC_M2P;
+ }
+ else
+ {
+ /* No.. Use memory-to-memory flow control */
- putreg32(regval, dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET)
+ regval |= DMACHAN_CTRLB_FC_M2M;
+ }
+ }
+
+ /* Select source address incrementing */
+
+ if (dmach->flags & DMACH_FLAG_PERIPHINCREMENT) == 0)
+ {
+ regval |= DMACHAN_CTRLB_SRCINCR_FIXED;
+ }
+
+ /* Select address incrementing */
+
+ if (dmach->flags & DMACH_FLAG_MEMINCREMENT) 0= 0)
+ {
+ regval |= DMACHAN_CTRLB_DESTINCR_FIXED;
+ }
+ return regval;
}
-/************************************************************************************
+/****************************************************************************
* Name: sam3u_flowcontrol
*
* Description:
* Select flow control
*
- ************************************************************************************/
+ ****************************************************************************/
static inline void sam3u_flowcontrol(struct sam3u_dma_s *dmach, uint32_t setting)
{
@@ -470,13 +645,396 @@ static inline void sam3u_flowcontrol(struct sam3u_dma_s *dmach, uint32_t setting
putreg(regval, dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET);
}
-/************************************************************************************
+/****************************************************************************
+ * Name: sam3u_allocdesc
+ *
+ * Description:
+ * Allocate and add one descriptor to the DMA channel's link list.
+ *
+ * NOTE: link list entries are freed by the DMA interrupt handler. However,
+ * since the setting/clearing of the 'in use' indication is atomic, no
+ * special actions need be performed. It would be a good thing to add logic
+ * to handle the case where all of the entries are exhausted and we could
+ * wait for some to be freed by the interrupt handler.
+ *
+ ****************************************************************************/
+
+static struct dma_linklist_s *
+sam3u_allocdesc(struct sam3u_dma_s *dmach, struct dma_linklist_s *prev,
+ uint23_t src, uint32_t dest, uint32_t ctrla, uint32_t ctrlb)
+{
+ struct dma_linklist_s *desc = NULL;
+ int i;
+
+ /* Sanity check -- src == 0 is the indication that the link is unused.
+ * Obviously setting it to zero would break that usage.
+ */
+
+#ifdef CONFIG_DEBUG
+ if (src != 0)
+#endif
+ {
+ /* Table a descriptor table semaphore count. When we get one, then there
+ * is at least one free descriptor in the table and it is ours.
+ */
+
+ sam3u_takedsem();
+
+ /* Examine each link list entry to find an available one -- i.e., one
+ * with src == 0. That src field is set to zero by the DMA transfer
+ * complete interrupt handler. The following should be safe because
+ * that is an atomic operation.
+ */
+
+ sam3u_takechsem();
+ for (i = 0; i < CONFIG_SAM3U_NLLDESC; i++)
+ {
+ if (g_linklist[i].src == 0)
+ {
+ /* We have it. Initialize the new link list entry */
+
+ desc = &g_linklist[i];
+ desc->src = src; /* Source address */
+ desc->dest = dest; /* Destination address */
+ desc->ctrla = ctrla; /* Control A value */
+ desc->ctrlb = ctrlb; /* Control B value */
+ desc->desc = 0; /* Descriptor address */
+
+ /* And then hook it at the tail of the link list */
+
+ if (!prev)
+ {
+ /* There is no previous link. This is the new head of
+ * the list
+ */
+
+ DEBUGASSERT(dmach->llhead == NULL && dmach->lltail == NULL);
+ dmach->llhead = desc;
+ }
+ else
+ {
+ DEBUGASSERT(dmach->llhead != NULL && dmach->tail == prev);
+
+ /* When the second link is added to the list, that is the
+ * cue that we are going to do the link list transfer.
+ *
+ * Enable the source and destination descriptor in the link
+ * list entry just before this one. We assume that both
+ * source and destination buffers are non-continuous, but
+ * this should work even if that is not the case.
+ */
+
+ prev->ctrlb &= ~DMACHAN_CTRLB_BOTHDSCR;
+
+ /* Link the previous tail to the new tail */
+
+ prev->next = (uint32_t)desc;
+ }
+
+ /* In any event, this is the new tail of the list. The source
+ * and destination descriptors must be disabled for the last entry
+ * in the link list. */
+
+ desc->ctrlb |= DMACHAN_CTRLB_BOTHDSCR;
+ dmach->lltail = desc;
+
+ /* Increment the total number of bytes to be transferred */
+
+ dmach->bufsize += nbytes;
+ break;
+ }
+ }
+
+ /* Because we hold a count from the counting semaphore, the above
+ * search loop should always be successful.
+ */
+
+ sam3u_givechsem();
+ DEBUGASSERT(desc != NULL);
+ }
+ return desc;
+}
+
+/****************************************************************************
+ * Name: sam3u_freelinklist
+ *
+ * Description:
+ * Free all descriptors in the DMA channel's link list.
+ *
+ * NOTE: Called from the DMA interrupt handler.
+ *
+ ****************************************************************************/
+
+static void sam3u_freelinklist(struct sam3u_dma_s *dmach)
+{
+ struct dma_linklist_s *desc;
+ struct dma_linklist_s *next;
+
+ /* Get the head of the link list and detach the link list from the DMA
+ * channel
+ */
+
+ desc = dmach->llhead
+ dmach->llhead = NULL;
+ dmach->lltail = NULL;
+
+ /* No transfer in progress */
+
+ dmach->remaining = 0;
+ dmach->bufsize = 0;
+
+ /* Reset each descriptor in the link list (thereby freeing them) */
+
+ while (desc != NULL)
+ {
+ next = (struct dma_linklist_s *)desc->next;
+ DEBUGASSERT(desc->src != 0);
+ memset(desc, 0, sizeof(struct dma_linklist_s));
+ sam3u_givedsem();
+ desc = next;
+ }
+}
+
+/****************************************************************************
+ * Name: sam3u_txbuffer
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+static int sam3u_txbuffer(struct sam3u_dma_s *dmach, uint32_t paddr,
+ uint32_t maddr, size_t nbytes)
+{
+ uint32_t regval;
+ uint32_t ctrla;
+ uint32_t ctrlb;
+
+ /* If we are appending a buffer to a linklist, then re-use the CTRLA/B
+ * values. Otherwise, create them from the properties of the transfer.
+ */
+
+ if (dmach->llhead)
+ {
+ regval = dmach->llhead.ctrla;
+ ctrlb = dmach->llhead.ctrlb;
+ }
+ else
+ {
+ regval = sam3u_txctrlabits(dmach);
+ ctrla = sam3u_txctrlb(dmach);
+ }
+ ctrla = sam3u_txctrla(regval, nbytes);
+
+ /* Add the new link list entry */
+
+ if (!sam3u_allocdesc(dmach, dmach->lltail, maddr, paddr, ctrla, ctrlb))
+ {
+ return -ENOMEM;
+ }
+ return OK;
+}
+
+/****************************************************************************
+ * Name: sam3u_rxbuffer
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+static int sam3u_rxbuffer(struct sam3u_dma_s *dmach, uint32_t paddr,
+ uint32_t maddr, size_t nbytes)
+{
+ uint32_t regval;
+ uint32_t ctrla;
+ uint32_t ctrlb;
+
+ /* If we are appending a buffer to a linklist, then re-use the CTRLA/B
+ * values. Otherwise, create them from the properties of the transfer.
+ */
+
+ if (dmach->llhead)
+ {
+ regval = dmach->llhead.ctrla;
+ ctrlb = dmach->llhead.ctrlb;
+ }
+ else
+ {
+ regval = sam3u_rxctrlabits(dmach);
+ ctrlb = sam3u_rxctrlb(dmach);
+ }
+ ctrla = sam3u_rxctrla(regval, nbytes);
+
+ /* Add the new link list entry */
+
+ if (!sam3u_allocdesc(dmach, dmach->lltail, maddr, paddr, ctrla, ctrlb))
+ {
+ return -ENOMEM;
+ }
+ return OK;
+}
+
+/****************************************************************************
+ * Name: sam3u_single
+ *
+ * Description:
+ * Start a single buffer DMA.
+ *
+ ****************************************************************************/
+
+static inline int sam3u_single(struct sam3u_dma_s *dmach)
+{
+
+Transfer Type AUTO SRC_REP DST_REP SRC_DSCR DST_DSCR BTSIZE SADDR DADDR Other
+ 1) Single Buffer or Last 0 – – 1 1 USR USR USR USR
+buffer of a multiple buffer
+transfer
+
+ struct dma_linklist_s *llhead = dmach->llhead;
+
+ /* Clear any pending interrupts from any previous DMAC transfer by reading
+ * the interrupt status register.
+ */
+
+ (void)getreg32(SAM3U_DMAC_EBCISR);
+
+ /* Write the starting source address in the SADDR register */
+
+ DEBUGASSERT(llhead != NULL && llhead->src != 0);
+ putreg32(llhead->src, dmach->base + SAM3U_DMACHAN_SADDR_OFFSET);
+
+ /* Write the starting destination address in the DADDR register */
+
+ putreg32(llhead->dest, dmach->base + SAM3U_DMACHAN_DADDR_OFFSET);
+
+ /* Set up the CTRLA register */
+
+ putreg32(llhead->ctrla, dmach->base + SAM3U_DMACHAN_CTRLA_OFFSET);
+
+ /* Set up the CTRLB register */
+
+ putreg32(llhead->ctrlb, dmach->base + SAM3U_DMACHAN_CTRLA_OFFSET);
+
+ /* Both the DST and SRC DSCR bits should be '1' in CTRLB */
+
+ DEBUGASSERT((llhead->ctrlb & DMACHAN_CTRLB_BOTHDSCR) == DMACHAN_CTRLB_BOTHDSCR);
+
+ /* Set up the CFG register */
+ #error missing logic
+ /* Enable the channel by writing a ‘1’ to the CHER enable bit */
+ #error missing logic
+
+ /* Make sure that bit 0 of the EN register is enabled */
+
+5. Source and destination request single and chunk DMAC transactions to transfer the
+ buffer of data (assuming non-memory peripherals). The DMAC acknowledges at the
+ completion of every transaction (chunk and single) in the buffer and carry out the buffer
+ transfer.
+6. Once the transfer completes, hardware sets the interrupts and disables the channel. At
+ this time you can either respond to the buffer Complete or Transfer Complete interrupts,
+ or poll for the Channel Handler Status Register (DMAC_CHSR.ENABLE[n]) bit until it is
+ cleared by hardware, to detect when the transfer is complete.
+}
+
+
+/****************************************************************************
+ * Name: sam3u_multiple
+ *
+ * Description:
+ * Start a multiple buffer DMA.
+ *
+ ****************************************************************************/
+
+static inline int sam3u_multiple(struct sam3u_dma_s *dmach)
+{
+Transfer Type AUTO SRC_REP DST_REP SRC_DSCR DST_DSCR BTSIZE SADDR DADDR Other
+ 1) Single Buffer or Last 0 – – 1 1 USR USR USR USR
+buffer of a multiple buffer
+transfer
+ 4) Multi Buffer transfer 0 – – 0 0 LLI LLI LLI LLI
+with LLI support
+
+ struct dma_linklist_s *llhead = dmach->llhead;
+
+ DEBUGASSERT(llhead != NULL && llhead->src != 0);
+
+ /* Check the first and last CTRLB values */
+
+ DEBUGASSERT((llhead->ctrlb & DMACHAN_CTRLB_BOTHDSCR) == 0);
+ DEBUGASSERT((lltail->ctrlb & DMACHAN_CTRLB_BOTHDSCR) == DMACHAN_CTRLB_BOTHDSCR);
+
+ /* Write the channel configuration information into the CFG register */
+
+#error missing logic
+
+ /* Clear any pending interrupts from any previous DMAC transfer by reading the
+ * status register
+ */
+
+ (void)getreg32(SAM3U_DMAC_EBCISR);
+
+ /* Set up the initial CTRLB register (to enable descriptors) */
+
+ putreg32(llhead->ctrlb, dmach->base + SAM3U_DMACHAN_CTRLA_OFFSET);
+
+/* Program the DMAC_CTRLBx, DMAC_CFGx registers according to Row 4 as shown in
+ Table 40-1 on page 1060. */
+ #error missing logic
+
+ /* Program the DSCR register with the pointer to the firstlink list entry. */
+
+ putreg32((uint32_t)dmach->llhead, dmac->base + SAM3U_DMACHAN_DSCR_OFFSET);
+
+ #error missing logic
+
+/* Finally, enable the channel by writing a ‘1’ to the CHER enable */
+ #error missing logic
+
+14. The DMAC fetches the first LLI from the location pointed to by DMAC_DSCRx(0).
+ Note: The LLI.DMAC_SADDRx, LLI. DMAC_DADDRx, LLI.DMAC_DSCRx, LLI.DMAC_CTRLAx and
+ LLI.DMAC_CTRLBx registers are fetched. The DMAC automatically reprograms the
+ DMAC_SADDRx, DMAC_DADDRx, DMAC_DSCRx, DMAC_CTRLBx and DMAC_CTRLAx channel
+ registers from the DMAC_DSCRx(0).
+
+15. Source and destination request single and chunk DMAC transactions to transfer the
+ buffer of data (assuming non-memory peripheral). The DMAC acknowledges at the
+ completion of every transaction (chunk and single) in the buffer and carry out the buffer
+ transfer.
+
+16. Once the buffer of data is transferred, the DMAC_CTRLAx register is written out to system
+ memory at the same location and on the same layer where it was originally
+ fetched, that is, the location of the DMAC_CTRLAx register of the linked list item
+ fetched prior to the start of the buffer transfer. Only DMAC_CTRLAx register is written
+ out because only the DMAC_CTRLAx.BTSIZE and DMAC_CTRLAX.DONE bits have
+ been updated by DMAC hardware. Additionally, the DMAC_CTRLAx.DONE bit is
+ asserted when the buffer transfer has completed.
+ Note: Do not poll the DMAC_CTRLAx.DONE bit in the DMAC memory map. Instead, poll the
+ LLI.DMAC_CTRLAx.DONE bit in the LLI for that buffer. If the poll LLI.DMAC_CTRLAx.DONE bit is
+ asserted, then this buffer transfer has completed. This LLI.DMAC_CTRLAx.DONE bit was cleared
+ at the start of the transfer.
+17. The DMAC does not wait for the buffer interrupt to be cleared, but continues fetching
+ the next LLI from the memory location pointed to by current DMAC_DSCRx register
+ and automatically reprograms the DMAC_SADDRx, DMAC_DADDRx, DMAC_DSCRx,
+ DMAC_CTRLAx and DMAC_CTRLBx channel registers. The DMAC transfer continues
+ until the DMAC determines that the DMAC_CTRLBx and DMAC_DSCRx registers at
+ the end of a buffer transfer match described in Row 1 of Table 40-1 on page 1060. The
+ DMAC then knows that the previous buffer transferred was the last buffer in the DMAC
+ transfer. The DMAC transfer might look like that shown in Figure 40-5 on page 1064
+
+}
+
+/****************************************************************************
* Name: sam3u_dmainterrupt
*
* Description:
* DMA interrupt handler
*
- ************************************************************************************/
+ ****************************************************************************/
static int sam3u_dmainterrupt(int irq, void *context)
{
@@ -502,7 +1060,7 @@ static int sam3u_dmainterrupt(int irq, void *context)
{
/* Subtract the number of bytes transferred so far */
- dmach->remaining -= dmach->bufsize;
+ dmach->remaining -= dmach->bufsize ???????;
/* Is the transfer finished? */
@@ -517,11 +1075,15 @@ static int sam3u_dmainterrupt(int irq, void *context)
putreg32(DMAC_CHDR_DIS(dmach->chan), SAM3U_DMAC_CHDR);
+ /* Free the linklist */
+
+ sam3u_freelinklist(dmach);
+
/* Perform the DMA complete callback */
if (dmach->callback)
{
- dmach->callback(dmach->arg);
+ dmach->callback(dmach->arg, dmach->result);
}
}
else
@@ -575,7 +1137,12 @@ void weak_function up_dmainitialize(void)
/* Enable the DMA controller */
- putreg32(DMAC_EN_ENABLE, SAM3U_DMAC_EN);
+ putreg32(DMAC_EN_ENABLE, SAM3U_DMAC_EN);
+
+ /* Initialize semaphores */
+
+ sem_init(g_chsem, 0, 1);
+ sem_init(g_chsem, 0, CONFIG_SAM3U_NDMACHAN);
}
/****************************************************************************
@@ -614,7 +1181,7 @@ DMA_HANDLE sam3u_dmachannel(uint16_t dmach_flags)
*/
dmach = NULL;
- sam3u_dmatake();
+ sam3u_takechsem();
for (chndx = 0; chndx < CONFIG_SAM3U_NDMACHAN; chndx++)
{
struct sam3u_dma_s *candidate = &g_dma[chndx];
@@ -625,16 +1192,21 @@ DMA_HANDLE sam3u_dmachannel(uint16_t dmach_flags)
dmach = candidate;
dmach->inuse = true;
- /* Read the status register to clear any pending interrupts on the channel */
+ /* Read the status register to clear any pending interrupts on the
+ * channel
+ */
(void)getreg32(SAM3U_DMAC_EBCISR);
- /* Disable the channel by writing one to the write-only channel disable register */
+ /* Disable the channel by writing one to the write-only channel
+ * disable register
+ */
putreg32(DMAC_CHDR_DIS(chndx), SAM3U_DMAC_CHDR);
- /* See the DMA channel flags, retaining the fifo size and flow control
- * settings which are inherent properties of the FIFO and cannot be changed.
+ /* See 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);
@@ -646,7 +1218,7 @@ DMA_HANDLE sam3u_dmachannel(uint16_t dmach_flags)
break;
}
}
- sam3u_dmagive();
+ sam3u_givechsem();
return (DMA_HANDLE)dmach;
}
@@ -680,30 +1252,113 @@ void sam3u_dmafree(DMA_HANDLE handle)
* Name: sam3u_dmatxsetup
*
* Description:
- * Configure DMA for transmit (memory to peripheral) before using
+ * 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 sam3u_dmatxsetup() and sam3u_dmatxsetup()
+ * must not be intermixed on the same transfer, however.
*
****************************************************************************/
-void sam3u_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nbytes)
+int sam3u_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nbytes)
{
struct sam3u_dma_s *dmach = (struct sam3u_dma_s *)handle;
uint32_t regval;
-# warning "Missing logic"
+ int ret = OK;
+
+ DEBUGASSERT(dmach && dmach->llhead != NULL && dmach->lltail != 0);
+ DEBUGASSERT(dmach->remaining == 0);
+
+ /* If this is a large transfer, break it up into smaller buffers */
+
+ while (nbytes > DMACHAN_CTRLA_BTSIZE_MAX)
+ {
+ /* Set up the maximum size transfer */
+
+ ret = sam3u_txbuffer(dmach, paddr, maddr, DMACHAN_CTRLA_BTSIZE_MAX);
+ if (ret == OK);
+ {
+ /* Decrement the number of bytes left to transfer */
+
+ nbytes -= DMACHAN_CTRLA_BTSIZE_MAX;
+
+ /* Increment the memory & peripheral address (if it is appropriate to
+ * do do).
+ */
+
+ if (dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
+ {
+ paddr += DMACHAN_CTRLA_BTSIZE_MAX;
+ }
+
+ if (dmach->flags & DMACH_FLAG_MEMINCREMENT) != 0)
+ {
+ maddr += DMACHAN_CTRLA_BTSIZE_MAX;
+ }
+ }
+ }
+
+ /* Then set up the final buffer transfer */
+
+ if (ret == OK && nbytes > 0)
+ {
+ ret = sam3u_txbuffer(dmach, paddr, maddr, nbytes);
+ }
}
/****************************************************************************
* Name: sam3u_dmarxsetup
*
* Description:
- * Configure DMA for receuve (peripheral to memory) before using
+ * 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 sam3u_dmatxsetup() and sam3u_dmatxsetup()
+ * must not be intermixed on the same transfer, however.
*
****************************************************************************/
-void sam3u_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nbytes)
+int sam3u_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nbytes)
{
struct sam3u_dma_s *dmach = (struct sam3u_dma_s *)handle;
uint32_t regval;
-# warning "Missing logic"
+ int ret = OK;
+
+ DEBUGASSERT(dmach && dmach->llhead != NULL && dmach->lltail != 0);
+
+ /* If this is a large transfer, break it up into smaller buffers */
+
+ while (nbytes > DMACHAN_CTRLA_BTSIZE_MAX)
+ {
+ /* Set up the maximum size transfer */
+
+ ret = sam3u_rxbuffer(dmach, paddr, maddr, DMACHAN_CTRLA_BTSIZE_MAX);
+ if (ret == OK);
+ {
+ /* Decrement the number of bytes left to transfer */
+
+ nbytes -= DMACHAN_CTRLA_BTSIZE_MAX;
+
+ /* Increment the memory & peripheral address (if it is appropriate to
+ * do do).
+ */
+
+ if (dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
+ {
+ paddr += DMACHAN_CTRLA_BTSIZE_MAX;
+ }
+
+ if (dmach->flags & DMACH_FLAG_MEMINCREMENT) != 0)
+ {
+ maddr += DMACHAN_CTRLA_BTSIZE_MAX;
+ }
+ }
+ }
+
+ /* Then set up the final buffer transfer */
+
+ if (ret == OK && nbytes > 0)
+ {
+ ret = sam3u_rxbuffer(dmach, paddr, maddr, nbytes);
+ }
}
/****************************************************************************
@@ -712,23 +1367,37 @@ void sam3u_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t
* Description:
* Start the DMA transfer
*
- * Assumptions:
- * - DMA handle allocated by sam3u_dmachannel()
- * - No DMA in progress
- *
****************************************************************************/
-void sam3u_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, bool half)
+int sam3u_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
{
struct sam3u_dma_s *dmach = (struct sam3u_dma_s *)handle;
+ int ret = -EINVAL;
+
+ /* Verify that the DMA has been setup (i.e., at least one entry in the
+ * link list).
+ */
- DEBUGASSERT(handle != NULL);
+ DEBUGASSERT(dmach != NULL);
+ if (dmach->llhead)
+ {
+ /* Save the callback info. This will be invoked whent the DMA commpletes */
+
+ dmach->callback = callback;
+ dmach->arg = arg;
- /* Save the callback info. This will be invoked whent the DMA commpletes */
+ /* Is this a single block transfer? Or a multiple block tranfer? */
- dmach->callback = callback;
- dmach->arg = arg;
-# warning "Missing logic"
+ if (dmach->llhead == dmach->lltail)
+ {
+ ret = sam3u_single(dmach);
+ }
+ else
+ {
+ ret = sam3u_multiple(dmach);
+ }
+ }
+ return ret;
}
/****************************************************************************
@@ -797,7 +1466,7 @@ void sam3u_dmasample(DMA_HANDLE handle, struct sam3u_dmaregs_s *regs)
regs->cfg = getreg32(dmach->base + SAM3U_DMACHAN_CFG_OFFSET);
irqrestore(flags);
}
-#endif
+#endif /* CONFIG_DEBUG_DMA */
/****************************************************************************
* Name: sam3u_dmadump
@@ -834,5 +1503,5 @@ void sam3u_dmadump(DMA_HANDLE handle, const struct sam3u_dmaregs_s *regs,
dmadbg(" CTRLB[%08x]: %08x\n", dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET, regs->ctrlb);
dmadbg(" CFG[%08x]: %08x\n", dmach->base + SAM3U_DMACHAN_CFG_OFFSET, regs->cfg);
}
-#endif
-
+#endif /* CONFIG_DEBUG_DMA */
+#endif /* CONFIG_SAM3U_DMA */ \ No newline at end of file
diff --git a/nuttx/arch/arm/src/sam3u/sam3u_dmac.h b/nuttx/arch/arm/src/sam3u/sam3u_dmac.h
index 736e689b0..8a8758481 100755
--- a/nuttx/arch/arm/src/sam3u/sam3u_dmac.h
+++ b/nuttx/arch/arm/src/sam3u/sam3u_dmac.h
@@ -374,12 +374,12 @@
# define DMACHAN_CTRLB_FC_P2P (3 << DMACHAN_CTRLB_FC_SHIFT) /* Peripheral-to-Peripheral */
#define DMACHAN_CTRLB_SRCINCR_SHIFT (24) /* Bits 24-25 */
#define DMACHAN_CTRLB_SRCINCR_MASK (3 << DMACHAN_CTRLB_SRCINCR_SHIFT)
-# define DMACHAN_CTRLB_SRCINCR_INCR (0 << DMACHAN_CTRLB_SRCINCR_SHIFT) /* INCREMENTING */
-# define DMACHAN_CTRLB_SRCINCR_FIXED (2 << DMACHAN_CTRLB_SRCINCR_SHIFT) /* FIXED */
+# 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_MASK (3 << DMACHAN_CTRLB_DSTINCR_SHIFT)
-# define DMACHAN_CTRLB_DSTINCR_INCR (0 << DMACHAN_CTRLB_DSTINCR_SHIFT) /* INCREMENTING */
-# define DMACHAN_CTRLB_DSTINCR_FIXED (2 << DMACHAN_CTRLB_DSTINCR_SHIFT) /* FIXED */
+# define DMACHAN_CTRLB_DSTINCR_INCR (0 << DMACHAN_CTRLB_DSTINCR_SHIFT) /* Incrementing address */
+# define DMACHAN_CTRLB_DSTINCR_FIXED (2 << DMACHAN_CTRLB_DSTINCR_SHIFT) /* Fixed address */
#define DMACHAN_CTRLB_IEN (1 << 30) /* Bit 30: Clear sets BTC[n] flag in EBCISR */
/* DMAC Channel n [n = 0..3] Configuration Register */
@@ -422,8 +422,8 @@ struct dma_linklist_s
uint32_t src; /* Source address */
uint32_t dest; /* Destination address */
uint32_t ctrla; /* Control A value */
- uint32_t ctrlb; /* Congtrol B value */
- uint32_t desc; /* Descriptor address */
+ uint32_t ctrlb; /* Control B value */
+ uint32_t next; /* Next descriptor address */
};
/****************************************************************************************
diff --git a/nuttx/arch/arm/src/sam3u/sam3u_hsmci.c b/nuttx/arch/arm/src/sam3u/sam3u_hsmci.c
index 552d554c7..f0b26169d 100755
--- a/nuttx/arch/arm/src/sam3u/sam3u_hsmci.c
+++ b/nuttx/arch/arm/src/sam3u/sam3u_hsmci.c
@@ -122,10 +122,9 @@
#define DMA_FLAGS \
(DMACH_FLAG_FIFO_8BYTES | DMACH_FLAG_FIFOCFG_LARGEST | \
(DMACHAN_PID_MCI0 << DMACH_FLAG_PERIPHPID_SHIFT) | \
- DMACH_FLAG_PERIPHH2SEL | DMACH_FLAG_PERIPHLLIMODE | \
+ DMACH_FLAG_PERIPHH2SEL | DMACH_FLAG_PERIPHISPERIPH | \
DMACH_FLAG_PERIPHWIDTH_32BITS | DMACH_FLAG_PERIPHCHUNKSIZE_1 | \
- DMACH_FLAG_MEMLLIMODE | DMACH_FLAG_MEMWIDTH_32BITS | \
- DMACH_FLAG_MEMINCREMENT | DMACH_FLAG_MEMCHUNKSIZE_4)
+ DMACH_FLAG_MEMWIDTH_32BITS | DMACH_FLAG_MEMINCREMENT | DMACH_FLAG_MEMCHUNKSIZE_4)
/* FIFO sizes */
@@ -328,7 +327,7 @@ static void sam3u_dumpsamples(struct sam3u_dev_s *priv);
# define sam3u_dumpsamples(priv)
#endif
-static void sam3u_dmacallback(DMA_HANDLE handle, uint8_t isr, void *arg);
+static void sam3u_dmacallback(DMA_HANDLE handle, void *arg, int result);
/* Data Transfer Helpers ****************************************************/
@@ -791,7 +790,7 @@ static void sam3u_dumpsamples(struct sam3u_dev_s *priv)
*
****************************************************************************/
-static void sam3u_dmacallback(DMA_HANDLE handle, uint8_t isr, void *arg)
+static void sam3u_dmacallback(DMA_HANDLE handle, void *arg, int result)
{
/* FAR struct sam3u_spidev_s *priv = (FAR struct sam3u_spidev_s *)arg; */
@@ -2354,7 +2353,7 @@ static int sam3u_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
/* Start the DMA */
sam3u_sample(priv, SAMPLENDX_BEFORE_ENABLE);
- sam3u_dmastart(priv->dma, sam3u_dmacallback, priv, false);
+ sam3u_dmastart(priv->dma, sam3u_dmacallback, priv);
sam3u_sample(priv, SAMPLENDX_AFTER_SETUP);
ret = OK;
}
@@ -2421,7 +2420,7 @@ static int sam3u_dmasendsetup(FAR struct sdio_dev_s *dev,
/* Start the DMA */
- sam3u_dmastart(priv->dma, sam3u_dmacallback, priv, false);
+ sam3u_dmastart(priv->dma, sam3u_dmacallback, priv);
sam3u_sample(priv, SAMPLENDX_AFTER_SETUP);
/* Enable TX interrrupts */
diff --git a/nuttx/arch/arm/src/sam3u/sam3u_internal.h b/nuttx/arch/arm/src/sam3u/sam3u_internal.h
index 91cfc7fa1..67c1bafca 100755
--- a/nuttx/arch/arm/src/sam3u/sam3u_internal.h
+++ b/nuttx/arch/arm/src/sam3u/sam3u_internal.h
@@ -322,13 +322,13 @@
#define DMACH_FLAG_PERIPHPID_SHIFT (4) /* Bits 4-7: Peripheral PID */
#define DMACH_FLAG_PERIPHPID_MASK (15 << DMACH_FLAG_PERIPHPID_SHIFT)
#define DMACH_FLAG_PERIPHH2SEL (1 << 8) /* Bits 8: HW handshaking */
-#define DMACH_FLAG_PERIPHWIDTH_SHIFT (9) /* Bits 9-10: Peripheral width */
+#define DMACH_FLAG_PERIPHISPERIPH (1 << 9) /* Bits 9: 0=memory; 1=peripheral */
+#define DMACH_FLAG_PERIPHWIDTH_SHIFT (10) /* Bits 10-11: Peripheral width */
#define DMACH_FLAG_PERIPHWIDTH_MASK (3 << DMACH_FLAG_PERIPHWIDTH_SHIFT)
# define DMACH_FLAG_PERIPHWIDTH_8BITS (0 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 8 bits */
# define DMACH_FLAG_PERIPHWIDTH_16BITS (1 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 16 bits */
# define DMACH_FLAG_PERIPHWIDTH_32BITS (2 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 32 bits */
-#define DMACH_FLAG_PERIPHINCREMENT (1 << 11) /* Bit 11: Autoincrement peripheral address */
-#define DMACH_FLAG_PERIPHLLIMODE (1 << 12) /* Bit 12: Use link list descriptors */
+#define DMACH_FLAG_PERIPHINCREMENT (1 << 12) /* Bit 12: Autoincrement peripheral address */
#define DMACH_FLAG_PERIPHCHUNKSIZE (1 << 13) /* Bit 13: Peripheral chunk size */
# define DMACH_FLAG_PERIPHCHUNKSIZE_1 (0) /* Peripheral chunksize = 1 */
# define DMACH_FLAG_PERIPHCHUNKSIZE_4 DMACH_FLAG_PERIPHCHUNKSIZE /* Peripheral chunksize = 4 */
@@ -338,14 +338,14 @@
#define DMACH_FLAG_MEMPID_SHIFT (14) /* Bits 14-17: Memory PID */
#define DMACH_FLAG_MEMPID_MASK (15 << DMACH_FLAG_PERIPHPID_SHIFT)
#define DMACH_FLAG_MEMH2SEL (1 << 18) /* Bits 18: HW handshaking */
-#define DMACH_FLAG_MEMWIDTH_SHIFT (19) /* Bits 19-20: Memory width */
+#define DMACH_FLAG_MEMISPERIPH (1 << 19) /* Bits 19: 0=memory; 1=peripheral */
+#define DMACH_FLAG_MEMWIDTH_SHIFT (20) /* Bits 20-21: Memory width */
#define DMACH_FLAG_MEMWIDTH_MASK (3 << DMACH_FLAG_MEMWIDTH_SHIFT)
# define DMACH_FLAG_MEMWIDTH_8BITS (0 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 8 bits */
# define DMACH_FLAG_MEMWIDTH_16BITS (1 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 16 bits */
# define DMACH_FLAG_MEMWIDTH_32BITS (2 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 32 bits */
-#define DMACH_FLAG_MEMINCREMENT (1 << 21) /* Bit 21: Autoincrement memory address */
-#define DMACH_FLAG_MEMLLIMODE (1 << 22) /* Bit 22: Use link list descriptors */
-#define DMACH_FLAG_MEMCHUNKSIZE (1 << 23) /* Bit 23: Memory chunk size */
+#define DMACH_FLAG_MEMINCREMENT (1 << 22) /* Bit 22: Autoincrement memory address */
+#define DMACH_FLAG_MEMCHUNKSIZE (1 << 22) /* Bit 23: Memory chunk size */
# define DMACH_FLAG_MEMCHUNKSIZE_1 (0) /* Memory chunksize = 1 */
# define DMACH_FLAG_MEMCHUNKSIZE_4 DMACH_FLAG_MEMCHUNKSIZE /* Memory chunksize = 4 */
@@ -354,7 +354,7 @@
************************************************************************************/
typedef FAR void *DMA_HANDLE;
-typedef void (*dma_callback_t)(DMA_HANDLE handle, uint8_t isr, void *arg);
+typedef void (*dma_callback_t)(DMA_HANDLE handle, void *arg, int result);
/* The following is used for sampling DMA registers when CONFIG DEBUG_DMA is selected */
@@ -559,7 +559,10 @@ EXTERN void sam3u_dmafree(DMA_HANDLE handle);
* Name: sam3u_dmatxsetup
*
* Description:
- * Configure DMA for transmit (memory to periphal).
+ * 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 sam3u_dmatxsetup() and sam3u_dmatxsetup()
+ * must not be intermixed on the same transfer, however.
*
****************************************************************************/
@@ -570,12 +573,15 @@ EXTERN void sam3u_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
* Name: sam3u_dmarxsetup
*
* Description:
- * Configure DMA for receive (peripheral to memory).
+ * 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 sam3u_dmatxsetup() and sam3u_dmatxsetup()
+ * must not be intermixed on the same transfer, however.
*
****************************************************************************/
-EXTERN void sam3u_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
- size_t nbytes);
+EXTERN int sam3u_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
+ size_t nbytes);
/****************************************************************************
* Name: sam3u_dmastart
@@ -585,8 +591,7 @@ EXTERN void sam3u_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
*
****************************************************************************/
-EXTERN void sam3u_dmastart(DMA_HANDLE handle, dma_callback_t callback,
- void *arg, bool half);
+EXTERN int sam3u_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg);
/****************************************************************************
* Name: sam3u_dmastop