From 0c12ae82a5256ba40fef3e48b82d8adacee9ccf2 Mon Sep 17 00:00:00 2001
From: patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>
Date: Tue, 30 Mar 2010 01:39:30 +0000
Subject: [PATCH] More DMA logic

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2567 42af7a65-404d-4744-a932-0658087f49c3
---
 arch/arm/src/sam3u/sam3u_dmac.c     | 145 +++++++++++++++++++++++++---
 arch/arm/src/sam3u/sam3u_dmac.h     |   4 +
 arch/arm/src/sam3u/sam3u_hsmci.c    |   9 +-
 arch/arm/src/sam3u/sam3u_internal.h |  18 ++--
 4 files changed, 152 insertions(+), 24 deletions(-)

diff --git a/arch/arm/src/sam3u/sam3u_dmac.c b/arch/arm/src/sam3u/sam3u_dmac.c
index 7680f93db7..b5ed3e8878 100755
--- a/arch/arm/src/sam3u/sam3u_dmac.c
+++ b/arch/arm/src/sam3u/sam3u_dmac.c
@@ -207,70 +207,185 @@ static inline boolean sam3u_flowcontrol(uint8_t dmach_flags)
 }
 
 /************************************************************************************
- * Name: sam3u_settxctrla
+ * Name: sam3u_txctrlabits
  *
  * Description:
  *  Decode the the flags to get the correct CTRLA register bit settings for a transmit
- *  (memory to peripheral) transfer.
+ *  (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 void
-sam3u_settxctrla(struct sam3u_dma_s *dmach, uint32_t dmasize, uint32_t otherbits)
+static inline uint32_t
+sam3u_txctrlabits(struct sam3u_dma_s *dmach, uint32_t otherbits)
 {
   uint32_t regval;
   unsigned int ndx;
 
-  DEBUGASSERT(dmach && dmasize <= DMACHAN_CTRLA_BTSIZE_MAX);
-  regval = (dmasize << DMACHAN_CTRLA_BTSIZE_SHIFT) | otherbits;
+  DEBUGASSERT(dmach);
+  regval = otherbits;
 
-  /* Since this is a transmit, the source is described by the memeory selections */
+  /* Since this is a transmit, the source is described by the memory selections.
+   * Set the source width (memory width).
+   */
 
   ndx = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >> DMACH_FLAG_MEMWIDTH_SHIFT;
   DEBUGASSERT(ndx < 3);
   regval |= g_srcwidth[ndx];
-  return regval;
 
-  /* Since this is a transmit, the destination is described by the peripheral selections */
+  /* Set the source chuck size (memory chunk size) */
+
+  if ((dmach->flags & DMACH_FLAG_MEMCHUNKSIZE) == DMACH_FLAG_MEMCHUNKSIZE_4)
+    {
+      regval |= DMACHAN_CTRLA_SCSIZE_4;
+    }
+#if 0 /* DMACHAN_CTRLA_SCSIZE_1 is zero */
+  else
+    {
+      regval |= DMACHAN_CTRLA_SCSIZE_1;
+    }
+#endif
+
+  /* Since this is a transmit, the destination is described by the peripheral selections.
+   * Set the destination width (peripheral width).
+   */
 
   ndx = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> DMACH_FLAG_PERIPHWIDTH_SHIFT;
   DEBUGASSERT(ndx < 3);
   regval |= g_destwidth[ndx];
+
+  /* Set the destination chuck size (peripheral chunk size) */
+
+  if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) == DMACH_FLAG_PERIPHCHUNKSIZE_4)
+    {
+      regval |= DMACHAN_CTRLA_DCSIZE_4;
+    }
+#if 0 /* DMACHAN_CTRLA_DCSIZE_1 is zero */
+  else
+    {
+      regval |= DMACHAN_CTRLA_DCSIZE_1;
+    }
+#endif
+
   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.
+   */
+
+  /* Adjust the the source transfer size for the source chunk size (memory chunk size) */
+
+  if ((dmach->flags & DMACH_FLAG_MEMCHUNKSIZE) == DMACH_FLAG_MEMCHUNKSIZE_4)
+    {
+      dmasize >>= 2;
+    }
+ 
+  DEBUGASSERT(dmasize <= DMACHAN_CTRLA_BTSIZE_MAX);
+  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.
+ *  (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 void
-sam3u_setrxctrla(struct sam3u_dma_s *dmach, uint32_t dmasize, uint32_t otherbits)
+static inline uint32_t
+sam3u_setrxctrla(struct sam3u_dma_s *dmach, uint32_t otherbits)
 {
   uint32_t     regval;
   unsigned int ndx;
 
   DEBUGASSERT(dmach && dmasize <= DMACHAN_CTRLA_BTSIZE_MAX);
-  regval = (dmasize << DMACHAN_CTRLA_BTSIZE_SHIFT) | otherbits;
+  regval = otherbits;
 
-  /* Since this is a receive, the source is described by the peripheral selections */
+  /* 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];
 
-  /* Since this is a receive, the destination is described by the memory selections */
+  /* Set the source chuck size (peripheral chunk size) */
+
+  if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) == DMACH_FLAG_PERIPHCHUNKSIZE_4)
+    {
+      regval |= DMACHAN_CTRLA_SCSIZE_4;
+    }
+#if 0 /* DMACHAN_CTRLA_SCSIZE_1 is zero */
+  else
+    {
+      regval |= DMACHAN_CTRLA_SCSIZE_1;
+    }
+#endif
+
+  /* Since this is a receive, the destination is described by the memory selections.
+   * Set the destination width (memory width).
+   */
 
   ndx = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >> DMACH_FLAG_MEMWIDTH_SHIFT;
   DEBUGASSERT(ndx < 3);
   regval |= g_destwidth[ndx];
+
+  /* Set the destination chuck size (memory chunk size) */
+
+  if ((dmach->flags & DMACH_FLAG_MEMCHUNKSIZE) == DMACH_FLAG_MEMCHUNKSIZE_4)
+    {
+      regval |= DMACHAN_CTRLA_DCSIZE_4;
+    }
+#if 0 /* DMACHAN_CTRLA_DCSIZE_1 is zero */
+  else
+    {
+      regval |= DMACHAN_CTRLA_DCSIZE_1;
+    }
+#endif
+
   return regval;
 }
 
+/************************************************************************************
+ * Name: sam3u_rxctrla
+ *
+ * Description:
+ *  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.
+   */
+
+  /* Adjust the the source transfer size for the source chunk size (peripheral chunk size) */
+
+  if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) == DMACH_FLAG_PERIPHCHUNKSIZE_4)
+    {
+      dmasize >>= 2;
+    }
+ 
+  DEBUGASSERT(dmasize <= DMACHAN_CTRLA_BTSIZE_MAX);
+  return (txctrlabits & ~DMACHAN_CTRLA_BTSIZE_MASK) | (dmasize << DMACHAN_CTRLA_BTSIZE_SHIFT);
+}
+
 /************************************************************************************
  * Name: sam3u_srcctrlb
  *
diff --git a/arch/arm/src/sam3u/sam3u_dmac.h b/arch/arm/src/sam3u/sam3u_dmac.h
index c92c45edf3..736e689b0d 100755
--- a/arch/arm/src/sam3u/sam3u_dmac.h
+++ b/arch/arm/src/sam3u/sam3u_dmac.h
@@ -345,7 +345,11 @@
 #define DMACHAN_CTRLA_BTSIZE_SHIFT     (0)       /* Bits 0-11: Buffer Transfer Size */
 #define DMACHAN_CTRLA_BTSIZE_MASK      (DMACHAN_CTRLA_BTSIZE_MAX << DMACHAN_CTRLA_BTSIZE_SHIFT)
 #define DMACHAN_CTRLA_SCSIZE           (1 << 16) /* Bit 16: Source Chunk Transfer Size */
+#  define DMACHAN_CTRLA_SCSIZE_1       (0)
+#  define DMACHAN_CTRLA_SCSIZE_4       DMACHAN_CTRLA_SCSIZE
 #define DMACHAN_CTRLA_DCSIZE           (1 << 20) /* Bit 20:  Destination Chunk Transfer size */
+#  define DMACHAN_CTRLA_DCSIZE_1       (0)
+#  define DMACHAN_CTRLA_DCSIZE_4       DMACHAN_CTRLA_DCSIZE
 #define DMACHAN_CTRLA_SRCWIDTH_SHIFT   (24)      /* Bits 24-25 */
 #define DMACHAN_CTRLA_SRCWIDTH_MASK    (3 << DMACHAN_CTRLA_SRCWIDTH_SHIFT)
 #  define DMACHAN_CTRLA_SRCWIDTH_BYTE  (0 << DMACHAN_CTRLA_SRCWIDTH_SHIFT)
diff --git a/arch/arm/src/sam3u/sam3u_hsmci.c b/arch/arm/src/sam3u/sam3u_hsmci.c
index 795cac9542..552d554c75 100755
--- a/arch/arm/src/sam3u/sam3u_hsmci.c
+++ b/arch/arm/src/sam3u/sam3u_hsmci.c
@@ -120,9 +120,12 @@
 /* DMA configuration flags */
 
 #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_PERIPHWIDTH_32BITS | \
-   DMACH_FLAG_MEMLLIMODE | DMACH_FLAG_MEMWIDTH_32BITS | DMACH_FLAG_MEMINCREMENT)
+  (DMACH_FLAG_FIFO_8BYTES | DMACH_FLAG_FIFOCFG_LARGEST | \
+  (DMACHAN_PID_MCI0 << DMACH_FLAG_PERIPHPID_SHIFT) | \
+   DMACH_FLAG_PERIPHH2SEL | DMACH_FLAG_PERIPHLLIMODE | \
+   DMACH_FLAG_PERIPHWIDTH_32BITS | DMACH_FLAG_PERIPHCHUNKSIZE_1 | \
+   DMACH_FLAG_MEMLLIMODE | DMACH_FLAG_MEMWIDTH_32BITS | \
+   DMACH_FLAG_MEMINCREMENT | DMACH_FLAG_MEMCHUNKSIZE_4)
 
 /* FIFO sizes */
 
diff --git a/arch/arm/src/sam3u/sam3u_internal.h b/arch/arm/src/sam3u/sam3u_internal.h
index a6ff75ba62..91cfc7fa15 100755
--- a/arch/arm/src/sam3u/sam3u_internal.h
+++ b/arch/arm/src/sam3u/sam3u_internal.h
@@ -313,7 +313,7 @@
 
 #define DMACH_FLAG_FIFOCFG_SHIFT              (2)       /* Bits 2-3: FIFO configuration */
 #define DMACH_FLAG_FIFOCFG_MASK               (3 << DMACH_FLAG_FIFOCFG_SHIFT)
-#  define DMACH_FLAG_FIFOCFG_LARGEST          (DMACH_FLAG_BURST_LARGEST << DMACH_FLAG_FIFOCFG_SHIFT
+#  define DMACH_FLAG_FIFOCFG_LARGEST          (DMACH_FLAG_BURST_LARGEST << DMACH_FLAG_FIFOCFG_SHIFT)
 #  define DMACH_FLAG_FIFOCFG_HALF             (DMACH_FLAG_BURST_HALF << DMACH_FLAG_FIFOCFG_SHIFT)
 #  define DMACH_FLAG_FIFOCFG_SINGLE           (DMACH_FLAG_BURST_SINGLE << DMACH_FLAG_FIFOCFG_SHIFT)
 
@@ -329,19 +329,25 @@
 #  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_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 */
 
 /* Memory endpoint characteristics */
 
-#define DMACH_FLAG_MEMPID_SHIFT               (13)      /* Bits 13-16: Memory PID */
+#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 << 17) /* Bits 17: HW handshaking */
-#define DMACH_FLAG_MEMWIDTH_SHIFT             (18)      /* Bits 18-19: Memory width */
+#define DMACH_FLAG_MEMH2SEL                   (1 << 18) /* Bits 18: HW handshaking */
+#define DMACH_FLAG_MEMWIDTH_SHIFT             (19)      /* Bits 19-20: 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 << 20) /* Bit 20: Autoincrement memory address */
-#define DMACH_FLAG_MEMLLIMODE                 (1 << 21) /* Bit 21: Use link list descriptors */
+#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_MEMCHUNKSIZE_1           (0)                     /* Memory chunksize = 1 */
+#  define DMACH_FLAG_MEMCHUNKSIZE_4           DMACH_FLAG_MEMCHUNKSIZE /* Memory chunksize = 4 */
 
 /************************************************************************************
  * Public Types
-- 
GitLab