summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-08-08 13:15:52 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-08-08 13:15:52 -0600
commit051a567290d9bc9834ade25ff2b5465aa01e5f35 (patch)
treea376cc4b8bc39b3fa5b27022cf4c59bbb07afbc2
parentfbe106fa2101b4936aafd985ce4fe4e30bc93902 (diff)
downloadnuttx-051a567290d9bc9834ade25ff2b5465aa01e5f35.tar.gz
nuttx-051a567290d9bc9834ade25ff2b5465aa01e5f35.tar.bz2
nuttx-051a567290d9bc9834ade25ff2b5465aa01e5f35.zip
SAMA5 DMA: Need to flush caches; DMA channel depends upon direction of DMA; the maximum transfer size in bytes depends on the number of bytes per transfer
-rw-r--r--nuttx/arch/arm/src/sam34/sam3u_dmac.c52
-rw-r--r--nuttx/arch/arm/src/sama5/sam_dmac.c486
-rw-r--r--nuttx/arch/arm/src/sama5/sam_dmac.h2
-rw-r--r--nuttx/arch/arm/src/sama5/sam_hsmci.c14
4 files changed, 480 insertions, 74 deletions
diff --git a/nuttx/arch/arm/src/sam34/sam3u_dmac.c b/nuttx/arch/arm/src/sam34/sam3u_dmac.c
index 01585e91b..ef598d01b 100644
--- a/nuttx/arch/arm/src/sam34/sam3u_dmac.c
+++ b/nuttx/arch/arm/src/sam34/sam3u_dmac.c
@@ -424,7 +424,7 @@ static inline uint32_t sam_txctrla(struct sam_dma_s *dmach,
if ((dmach->flags & DMACH_FLAG_MEMCHUNKSIZE) == DMACH_FLAG_MEMCHUNKSIZE_4)
{
- dmasize >>= 2;
+ dmasize = (dmasize + 3) >> 2;
}
DEBUGASSERT(dmasize <= DMACHAN_CTRLA_BTSIZE_MAX);
@@ -516,7 +516,7 @@ static inline uint32_t sam_rxctrla(struct sam_dma_s *dmach,
if ((dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE) == DMACH_FLAG_PERIPHCHUNKSIZE_4)
{
- dmasize >>= 2;
+ dmasize = (dmasize + 3) >> 2;
}
DEBUGASSERT(dmasize <= DMACHAN_CTRLA_BTSIZE_MAX);
@@ -1311,6 +1311,7 @@ void sam_dmafree(DMA_HANDLE handle)
int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nbytes)
{
struct sam_dma_s *dmach = (struct sam_dma_s *)handle;
+ size_t maxtransfer;
int ret = OK;
dmavdbg("dmach: %p paddr: %08x maddr: %08x nbytes: %d\n",
@@ -1318,18 +1319,31 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
DEBUGASSERT(dmach);
dmavdbg("llhead: %p lltail: %p\n", dmach->llhead, dmach->lltail);
+ /* The maximum transfer size in bytes depends upon the maximum number of
+ * 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;
+ }
+
/* If this is a large transfer, break it up into smaller buffers */
- while (nbytes > DMACHAN_CTRLA_BTSIZE_MAX)
+ while (nbytes > maxtransfer)
{
/* Set up the maximum size transfer */
- ret = sam_txbuffer(dmach, paddr, maddr, DMACHAN_CTRLA_BTSIZE_MAX);
+ ret = sam_txbuffer(dmach, paddr, maddr, maxtransfer);
if (ret == OK);
{
/* Decrement the number of bytes left to transfer */
- nbytes -= DMACHAN_CTRLA_BTSIZE_MAX;
+ nbytes -= maxtransfer;
/* Increment the memory & peripheral address (if it is appropriate to
* do do).
@@ -1337,12 +1351,12 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
if ((dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
{
- paddr += DMACHAN_CTRLA_BTSIZE_MAX;
+ paddr += maxtransfer;
}
if ((dmach->flags & DMACH_FLAG_MEMINCREMENT) != 0)
{
- maddr += DMACHAN_CTRLA_BTSIZE_MAX;
+ maddr += maxtransfer;
}
}
}
@@ -1371,6 +1385,7 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nbytes)
{
struct sam_dma_s *dmach = (struct sam_dma_s *)handle;
+ size_t maxtransfer;
int ret = OK;
dmavdbg("dmach: %p paddr: %08x maddr: %08x nbytes: %d\n",
@@ -1378,18 +1393,31 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
DEBUGASSERT(dmach);
dmavdbg("llhead: %p lltail: %p\n", dmach->llhead, dmach->lltail);
+ /* The maximum transfer size in bytes depends upon the maximum number of
+ * 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;
+ }
+
/* If this is a large transfer, break it up into smaller buffers */
- while (nbytes > DMACHAN_CTRLA_BTSIZE_MAX)
+ while (nbytes > maxtransfer)
{
/* Set up the maximum size transfer */
- ret = sam_rxbuffer(dmach, paddr, maddr, DMACHAN_CTRLA_BTSIZE_MAX);
+ ret = sam_rxbuffer(dmach, paddr, maddr, maxtransfer);
if (ret == OK);
{
/* Decrement the number of bytes left to transfer */
- nbytes -= DMACHAN_CTRLA_BTSIZE_MAX;
+ nbytes -= maxtransfer;
/* Increment the memory & peripheral address (if it is appropriate to
* do do).
@@ -1397,12 +1425,12 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
if ((dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
{
- paddr += DMACHAN_CTRLA_BTSIZE_MAX;
+ paddr += maxtransfer;
}
if ((dmach->flags & DMACH_FLAG_MEMINCREMENT) != 0)
{
- maddr += DMACHAN_CTRLA_BTSIZE_MAX;
+ maddr += maxtransfer;
}
}
}
diff --git a/nuttx/arch/arm/src/sama5/sam_dmac.c b/nuttx/arch/arm/src/sama5/sam_dmac.c
index f26bab5de..90b6fee6f 100644
--- a/nuttx/arch/arm/src/sama5/sam_dmac.c
+++ b/nuttx/arch/arm/src/sama5/sam_dmac.c
@@ -51,6 +51,7 @@
#include <arch/irq.h>
#include "up_arch.h"
+#include "cache.h"
#include "up_internal.h"
#include "os_internal.h"
@@ -110,6 +111,13 @@
/****************************************************************************
* Private Types
****************************************************************************/
+/* This structure maps a peripheral ID to an DMA channel */
+
+struct sam_pidmap_s
+{
+ uint8_t pid; /* Peripheral identifier */
+ uint8_t pchan; /* DMA channel */
+};
/* This structure descibes one DMA channel */
@@ -177,6 +185,86 @@ static const uint32_t g_fifocfg[3] =
DMAC_CH_CFG_FIFOCFG_ASAP
};
+/* These tables map peripheral IDs to channels. A lookup is performed
+ * before each DMA transfer in order to map the peripheral IDs to the
+ * correct channel. This must be done because the channel can change with
+ * the direction of the transfer.
+ *
+ * DMA controller 0, RX DMA:
+ */
+
+static const struct sam_pidmap_s g_dmac0_rxchan[] =
+{
+ { SAM_PID_HSMCI0, DMAC0_CH_HSMCI0 }, /* HSMCI0 Receive/transmit */
+ { SAM_PID_SPI0, DMAC0_CH_SPI0_RX }, /* SPI0 Receive */
+ { SAM_PID_USART0, DMAC0_CH_USART0_RX }, /* USART0 Receive */
+ { SAM_PID_USART1, DMAC0_CH_USART1_RX }, /* USART1 Receive */
+ { SAM_PID_TWI0, DMAC0_CH_TWI0_RX }, /* TWI0 Receive */
+ { SAM_PID_TWI1, DMAC0_CH_TWI1_RX }, /* TWI1 Receive */
+ { SAM_PID_UART0, DMAC0_CH_UART0_RX }, /* UART0 Receive */
+ { SAM_PID_SSC0, DMAC0_CH_SSC0_RX }, /* SSC0 Receive */
+ { SAM_PID_SMD, DMAC0_CH_SMD_RX }, /* SMD Receive */
+};
+#define NDMAC0_RXCHANNELS (sizeof(g_dmac0_rxchan) / sizeof(struct sam_pidmap_s))
+
+#ifdef CONFIG_SAMA5_DMAC0
+/* DMA controller 0, TX DMA: */
+
+static const struct sam_pidmap_s g_dmac0_txchan[] =
+{
+ { SAM_PID_HSMCI0, DMAC0_CH_HSMCI0 }, /* HSMCI0 Receive/transmit */
+ { SAM_PID_SPI0, DMAC0_CH_SPI0_TX }, /* SPI0 Transmit */
+ { SAM_PID_USART0, DMAC0_CH_USART0_TX }, /* USART0 Transmit */
+ { SAM_PID_USART1, DMAC0_CH_USART1_TX }, /* USART1 Transmit */
+ { SAM_PID_TWI0, DMAC0_CH_TWI0_TX }, /* TWI0 Transmit */
+ { SAM_PID_TWI1, DMAC0_CH_TWI1_TX }, /* TWI1 Transmit */
+ { SAM_PID_UART0, DMAC0_CH_UART0_TX }, /* UART0 Transmit */
+ { SAM_PID_SSC0, DMAC0_CH_SSC0_TX }, /* SSC0 Transmit */
+ { SAM_PID_SMD, DMAC0_CH_SMD_TX }, /* SMD Transmit */
+};
+#define NDMAC0_TXCHANNELS (sizeof(g_dmac0_txchan) / sizeof(struct sam_pidmap_s))
+#endif
+
+#ifdef CONFIG_SAMA5_DMAC1
+/* DMA controller 1, RX DMA: */
+
+static const struct sam_pidmap_s g_dmac1_rxchan[] =
+{
+ { SAM_PID_HSMCI1, DMAC1_CH_HSMCI1 }, /* HSMCI1 Receive/transmit */
+ { SAM_PID_HSMCI2, DMAC1_CH_HSMCI2 }, /* HSMCI2 Receive/transmit */
+ { SAM_PID_ADC, DMAC1_CH_ADC_RX }, /* ADC Receive */
+ { SAM_PID_SSC1, DMAC1_CH_SSC1_RX }, /* SSC1 Receive */
+ { SAM_PID_UART1, DMAC1_CH_UART1_RX }, /* UART1 Receive */
+ { SAM_PID_USART2, DMAC1_CH_USART2_RX }, /* USART2 Receive */
+ { SAM_PID_USART3, DMAC1_CH_USART3_RX }, /* USART3 Receive */
+ { SAM_PID_TWI2, DMAC1_CH_TWI2_RX }, /* TWI2 Receive */
+ { SAM_PID_DBGU, DMAC1_CH_DBGU_RX }, /* DBGU Receive */
+ { SAM_PID_SPI1, DMAC1_CH_SPI1_RX }, /* SPI1 Receive */
+ { SAM_PID_AES, DMAC1_CH_AES_RX }, /* AES Receive */
+ { SAM_PID_TDES, DMAC1_CH_TDES_RX }, /* TDES Receive */
+};
+#define NDMAC1_RXCHANNELS (sizeof(g_dmac1_rxchan) / sizeof(struct sam_pidmap_s))
+
+/* DMA controller 1, TX DMA: */
+
+static const struct sam_pidmap_s g_dmac1_txchan[] =
+{
+ { SAM_PID_HSMCI1, DMAC1_CH_HSMCI1 }, /* HSMCI1 Receive/transmit */
+ { SAM_PID_HSMCI2, DMAC1_CH_HSMCI2 }, /* HSMCI2 Receive/transmit */
+ { SAM_PID_SSC1, DMAC1_CH_SSC1_TX }, /* SSC1 Transmit */
+ { SAM_PID_UART1, DMAC1_CH_UART1_TX }, /* UART1 Transmit */
+ { SAM_PID_USART2, DMAC1_CH_USART2_TX }, /* USART2 Transmit */
+ { SAM_PID_USART3, DMAC1_CH_USART3_TX }, /* USART3 Transmit */
+ { SAM_PID_TWI2, DMAC1_CH_TWI2_TX }, /* TWI2 Transmit */
+ { SAM_PID_DBGU, DMAC1_CH_DBGU_TX }, /* DBGU Transmit */
+ { SAM_PID_SPI1, DMAC1_CH_SPI1_TX }, /* SPI1 Transmit */
+ { SAM_PID_SHA, DMAC1_CH_SHA_TX }, /* SHA Transmit */
+ { SAM_PID_AES, DMAC1_CH_AES_TX }, /* AES Transmit */
+ { SAM_PID_TDES, DMAC1_CH_TDES_TX }, /* TDES Transmit */
+};
+#define NDMAC1_TXCHANNELS (sizeof(g_dmac1_txchan) / sizeof(struct sam_pidmap_s))
+#endif
+
#ifdef CONFIG_SAMA5_DMAC0
/* This array describes the available link list descriptors */
@@ -533,6 +621,126 @@ static inline uint32_t sam_fifocfg(struct sam_dmach_s *dmach)
return g_fifocfg[ndx];
}
+
+/****************************************************************************
+ * Name: sam_channel, sam_source_channel, and sam_sink_channel
+ *
+ * Description:
+ * Return the RX or TX channel associated with a PID. As a clarification:
+ *
+ * The source channel refers to the source of data for the DMA. This is,
+ * either (1) memory for a TX DMA or (2) a peripheral register for an RX
+ * DMA.
+ *
+ * The sink channel is the recipient of the DMA data. This is either
+ * (1) memory for an RX DMA, or (2) a peripheral register for a TX DMA.
+ *
+ ****************************************************************************/
+
+static uint8_t sam_channel(uint8_t pid, const struct sam_pidmap_s *table,
+ unsigned int nentries)
+{
+ int i;
+
+ /* Search until either the entry with the matching PID is found or until
+ * all of the table entries have been examined without finding the PID.
+ */
+
+ for (i = 0; i < nentries; i++, table++)
+ {
+ if (table->pid == pid)
+ {
+ return table->pchan;
+ }
+ }
+
+ fdbg("No channel found for pid %d\n", pid);
+ DEBUGPANIC();
+ return 0x3f;
+}
+
+static uint32_t sam_source_channel(struct sam_dmach_s *dmach, uint8_t pid,
+ bool isperiph)
+{
+ const struct sam_pidmap_s *table;
+ unsigned int nentries;
+
+ if (!isperiph)
+ {
+ /* The source is memory, not a peripheral. */
+
+ return 0x3f;
+ }
+ else
+
+#ifdef CONFIG_SAMA5_DMAC0
+#ifdef CONFIG_SAMA5_DMAC1
+ if (dmach->dmac == 0)
+#endif
+ {
+ /* Use the DMAC0 lookup table */
+
+ table = g_dmac0_rxchan;
+ nentries = NDMAC0_RXCHANNELS;
+ }
+#endif
+
+#ifdef CONFIG_SAMA5_DMAC1
+#ifdef CONFIG_SAMA5_DMAC0
+ else
+#endif
+ {
+ /* Use the DMAC1 lookup table */
+
+ table = g_dmac1_rxchan;
+ nentries = NDMAC1_RXCHANNELS;
+ }
+#endif
+
+ return (uint32_t)sam_channel(pid, table, nentries);
+}
+
+static uint32_t sam_sink_channel(struct sam_dmach_s *dmach, uint8_t pid,
+ bool isperiph)
+{
+ const struct sam_pidmap_s *table;
+ unsigned int nentries;
+
+ if (!isperiph)
+ {
+ /* The source is memory, not a peripheral. */
+
+ return 0x3f;
+ }
+ else
+
+#ifdef CONFIG_SAMA5_DMAC0
+#ifdef CONFIG_SAMA5_DMAC1
+ if (dmach->dmac == 0)
+#endif
+ {
+ /* Use the DMAC0 lookup table */
+
+ table = g_dmac0_txchan;
+ nentries = NDMAC0_TXCHANNELS;
+ }
+#endif
+
+#ifdef CONFIG_SAMA5_DMAC1
+#ifdef CONFIG_SAMA5_DMAC0
+ else
+#endif
+ {
+ /* Use the DMAC1 lookup table */
+
+ table = g_dmac1_txchan;
+ nentries = NDMAC1_TXCHANNELS;
+ }
+#endif
+
+ return (uint32_t)sam_channel(pid, table, nentries);
+}
+
/****************************************************************************
* Name: sam_txcfg
*
@@ -546,20 +754,28 @@ static inline uint32_t sam_txcfg(struct sam_dmach_s *dmach)
{
uint32_t regval;
unsigned int pid;
+ unsigned int pchan;
+ bool isperiph;
/* Set transfer (memory to peripheral) DMA channel configuration register */
- pid = (dmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT;
- regval = ((pid & 0x0f) << DMAC_CH_CFG_SRCPER_SHIFT);
- regval |= ((pid & 0x30) << (DMAC_CH_CFG_SRCPERMSB_SHIFT-4));
- regval |= (dmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ? DMAC_CH_CFG_SRCH2SEL : 0;
+ pid = (dmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT;
+ isperiph = ((dmach->flags & DMACH_FLAG_MEMISPERIPH) != 0);
+ pchan = sam_source_channel(dmach, pid, isperiph);
+
+ regval = ((pchan & 0x0f) << DMAC_CH_CFG_SRCPER_SHIFT);
+ regval |= ((pchan & 0x30) << (DMAC_CH_CFG_SRCPERMSB_SHIFT-4));
+ regval |= (dmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ? DMAC_CH_CFG_SRCH2SEL : 0;
- pid = (dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT;
- regval |= ((pid & 0x0f) << DMAC_CH_CFG_DSTPER_SHIFT);
- regval |= ((pid & 0x30) << (DMAC_CH_CFG_DSTPERMSB_SHIFT-4));
- regval |= (dmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ? DMAC_CH_CFG_DSTH2SEL : 0;
+ pid = (dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT;
+ isperiph = ((dmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0);
+ pchan = sam_sink_channel(dmach, pid, isperiph);
- regval |= sam_fifocfg(dmach);
+ regval |= ((pchan & 0x0f) << DMAC_CH_CFG_DSTPER_SHIFT);
+ regval |= ((pchan & 0x30) << (DMAC_CH_CFG_DSTPERMSB_SHIFT-4));
+ regval |= (dmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ? DMAC_CH_CFG_DSTH2SEL : 0;
+
+ regval |= sam_fifocfg(dmach);
return regval;
}
@@ -576,20 +792,28 @@ static inline uint32_t sam_rxcfg(struct sam_dmach_s *dmach)
{
uint32_t regval;
unsigned int pid;
+ unsigned int pchan;
+ bool isperiph;
/* Set received (peripheral to memory) DMA channel config */
- pid = (dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT;
- regval = ((pid & 0x0f) << DMAC_CH_CFG_SRCPER_SHIFT);
- regval |= ((pid & 0x30) << (DMAC_CH_CFG_SRCPERMSB_SHIFT-4));
- regval |= (dmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ? DMAC_CH_CFG_SRCH2SEL : 0;
+ pid = (dmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT;
+ isperiph = ((dmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0);
+ pchan = sam_source_channel(dmach, pid, isperiph);
+
+ regval = ((pchan & 0x0f) << DMAC_CH_CFG_SRCPER_SHIFT);
+ regval |= ((pchan & 0x30) << (DMAC_CH_CFG_SRCPERMSB_SHIFT-4));
+ regval |= (dmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ? DMAC_CH_CFG_SRCH2SEL : 0;
- pid = (dmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT;
- regval |= ((pid & 0x0f) << DMAC_CH_CFG_DSTPER_SHIFT);
- regval |= ((pid & 0x30) << (DMAC_CH_CFG_DSTPERMSB_SHIFT-4));
- regval |= (dmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ? DMAC_CH_CFG_DSTH2SEL : 0;
+ pid = (dmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT;
+ isperiph = ((dmach->flags & DMACH_FLAG_MEMISPERIPH) != 0);
+ pchan = sam_sink_channel(dmach, pid, isperiph);
- regval |= sam_fifocfg(dmach);
+ regval |= ((pchan & 0x0f) << DMAC_CH_CFG_DSTPER_SHIFT);
+ regval |= ((pchan & 0x30) << (DMAC_CH_CFG_DSTPERMSB_SHIFT-4));
+ regval |= (dmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ? DMAC_CH_CFG_DSTH2SEL : 0;
+
+ regval |= sam_fifocfg(dmach);
return regval;
}
@@ -644,28 +868,73 @@ static inline uint32_t sam_txctrlabits(struct sam_dmach_s *dmach)
}
/****************************************************************************
- * Name: sam_txctrla
+ * Name: sam_maxtxtransfer
*
* Description:
- * Or in the variable CTRLA bits
+ * Maximum number of bytes that can be sent in on transfer
*
****************************************************************************/
-static inline uint32_t sam_txctrla(struct sam_dmach_s *dmach,
- uint32_t dmasize, uint32_t ctrla)
+static size_t sam_maxtxtransfer(struct sam_dmach_s *dmach)
{
unsigned int chunksize;
+ size_t maxtransfer;
- /* 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). 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;
+
+ switch (chunksize)
+ {
+ default:
+ case 0: /* 1 byte */
+ maxtransfer = DMAC_CH_CTRLA_BTSIZE_MAX;
+ break;
+
+ case 1: /* 4 bytes */
+ maxtransfer = 4 * DMAC_CH_CTRLA_BTSIZE_MAX;
+ break;
+
+ case 2: /* 8 bytes */
+ maxtransfer = 8 * DMAC_CH_CTRLA_BTSIZE_MAX;
+ break;
+
+ case 3: /* 16 bytes */
+ maxtransfer = 16 * DMAC_CH_CTRLA_BTSIZE_MAX;
+ break;
+ }
+
+ return maxtransfer;
+}
+
+/****************************************************************************
+ * Name: sam_ntxtransfers
+ *
+ * Description:
+ * Number of TX transfers via DMA
+ *
+ ****************************************************************************/
+
+static uint32_t sam_ntxtransfers(struct sam_dmach_s *dmach, uint32_t dmasize)
+{
+ unsigned int chunksize;
+
/* Adjust the the source transfer size for the source chunk size (memory
- * chunk size)
+ * 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. ..."
*/
chunksize = (dmach->flags & DMACH_FLAG_MEMCHUNKSIZE_MASK)
>> DMACH_FLAG_MEMCHUNKSIZE_SHIFT;
+
switch (chunksize)
{
default:
@@ -673,21 +942,43 @@ static inline uint32_t sam_txctrla(struct sam_dmach_s *dmach,
break;
case 1: /* 4 bytes */
- dmasize >>= 2;
+ dmasize = (dmasize + 3) >> 2;
break;
case 2: /* 8 bytes */
- dmasize >>= 3;
+ dmasize = (dmasize + 7) >> 3;
break;
case 3: /* 16 bytes */
- dmasize >>= 4;
+ dmasize = (dmasize + 15) >> 4;
break;
}
- DEBUGASSERT(dmasize <= DMAC_CH_CTRLA_BTSIZE_MAX);
+ return dmasize;
+}
+
+/****************************************************************************
+ * Name: sam_txctrla
+ *
+ * Description:
+ * 'OR' in the variable CTRLA bits
+ *
+ ****************************************************************************/
+
+static inline uint32_t sam_txctrla(struct sam_dmach_s *dmach,
+ uint32_t dmasize, uint32_t ctrla)
+{
+ uint32_t ntransfers;
+
+ /* 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.
+ */
+
+ ntransfers = sam_ntxtransfers(dmach, dmasize);
+
+ DEBUGASSERT(ntransfers <= DMAC_CH_CTRLA_BTSIZE_MAX);
return (ctrla & ~DMAC_CH_CTRLA_BTSIZE_MASK) |
- (dmasize << DMAC_CH_CTRLA_BTSIZE_SHIFT);
+ (ntransfers << DMAC_CH_CTRLA_BTSIZE_SHIFT);
}
/****************************************************************************
@@ -745,28 +1036,73 @@ static inline uint32_t sam_rxctrlabits(struct sam_dmach_s *dmach)
}
/****************************************************************************
- * Name: sam_rxctrla
+ * Name: sam_maxrxtransfer
*
* Description:
- * 'OR' in the variable CTRLA bits
+ * Maximum number of bytes that can be sent in on transfer
*
****************************************************************************/
-static inline uint32_t sam_rxctrla(struct sam_dmach_s *dmach,
- uint32_t dmasize, uint32_t ctrla)
+static size_t sam_maxrxtransfer(struct sam_dmach_s *dmach)
{
unsigned int chunksize;
+ size_t maxtransfer;
- /* 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). 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;
+
+ switch (chunksize)
+ {
+ default:
+ case 0: /* 1 byte */
+ maxtransfer = DMAC_CH_CTRLA_BTSIZE_MAX;
+ break;
+
+ case 1: /* 4 bytes */
+ maxtransfer = 4 * DMAC_CH_CTRLA_BTSIZE_MAX;
+ break;
+
+ case 2: /* 8 bytes */
+ maxtransfer = 8 * DMAC_CH_CTRLA_BTSIZE_MAX;
+ break;
+
+ case 3: /* 16 bytes */
+ maxtransfer = 16 * DMAC_CH_CTRLA_BTSIZE_MAX;
+ break;
+ }
+
+ return maxtransfer;
+}
+
+/****************************************************************************
+ * Name: sam_nrxtransfers
+ *
+ * Description:
+ * Number of RX transfers via DMA
+ *
+ ****************************************************************************/
+
+static uint32_t sam_nrxtransfers(struct sam_dmach_s *dmach, uint32_t dmasize)
+{
+ unsigned int chunksize;
+
/* Adjust the the source transfer size for the source chunk size (peripheral
- * chunk size)
+ * 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. ..."
*/
chunksize = (dmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE_MASK)
>> DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT;
+
switch (chunksize)
{
default:
@@ -774,21 +1110,43 @@ static inline uint32_t sam_rxctrla(struct sam_dmach_s *dmach,
break;
case 1: /* 4 bytes */
- dmasize >>= 2;
+ dmasize = (dmasize + 3) >> 2;
break;
case 2: /* 8 bytes */
- dmasize >>= 3;
+ dmasize = (dmasize + 7) >> 3;
break;
case 3: /* 16 bytes */
- dmasize >>= 4;
+ dmasize = (dmasize + 15) >> 4;
break;
}
- DEBUGASSERT(dmasize <= DMAC_CH_CTRLA_BTSIZE_MAX);
+ return dmasize;
+}
+
+/****************************************************************************
+ * Name: sam_rxctrla
+ *
+ * Description:
+ * 'OR' in the variable CTRLA bits
+ *
+ ****************************************************************************/
+
+static inline uint32_t sam_rxctrla(struct sam_dmach_s *dmach,
+ uint32_t dmasize, uint32_t ctrla)
+{
+ uint32_t ntransfers;
+
+ /* 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.
+ */
+
+ ntransfers = sam_nrxtransfers(dmach, dmasize);
+
+ DEBUGASSERT(ntransfers <= DMAC_CH_CTRLA_BTSIZE_MAX);
return (ctrla & ~DMAC_CH_CTRLA_BTSIZE_MASK) |
- (dmasize << DMAC_CH_CTRLA_BTSIZE_SHIFT);
+ (ntransfers << DMAC_CH_CTRLA_BTSIZE_SHIFT);
}
/****************************************************************************
@@ -1166,6 +1524,7 @@ static int sam_txbuffer(struct sam_dmach_s *dmach, uint32_t paddr,
*/
dmach->cfg = sam_txcfg(dmach);
+
return OK;
}
@@ -1692,9 +2051,11 @@ void sam_dmafree(DMA_HANDLE handle)
*
****************************************************************************/
-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)
{
struct sam_dmach_s *dmach = (struct sam_dmach_s *)handle;
+ size_t maxtransfer;
int ret = OK;
dmavdbg("dmach: %p paddr: %08x maddr: %08x nbytes: %d\n",
@@ -1702,18 +2063,24 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
DEBUGASSERT(dmach);
dmavdbg("llhead: %p lltail: %p\n", dmach->llhead, dmach->lltail);
+ /* The maximum transfer size in bytes depends upon the maximum number of
+ * transfers and the number of bytes per transfer.
+ */
+
+ maxtransfer = sam_maxtxtransfer(dmach);
+
/* If this is a large transfer, break it up into smaller buffers */
- while (nbytes > DMAC_CH_CTRLA_BTSIZE_MAX)
+ while (nbytes > maxtransfer)
{
/* Set up the maximum size transfer */
- ret = sam_txbuffer(dmach, paddr, maddr, DMAC_CH_CTRLA_BTSIZE_MAX);
+ ret = sam_txbuffer(dmach, paddr, maddr, maxtransfer);
if (ret == OK);
{
/* Decrement the number of bytes left to transfer */
- nbytes -= DMAC_CH_CTRLA_BTSIZE_MAX;
+ nbytes -= maxtransfer;
/* Increment the memory & peripheral address (if it is appropriate to
* do do).
@@ -1721,12 +2088,12 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
if ((dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
{
- paddr += DMAC_CH_CTRLA_BTSIZE_MAX;
+ paddr += maxtransfer;
}
if ((dmach->flags & DMACH_FLAG_MEMINCREMENT) != 0)
{
- maddr += DMAC_CH_CTRLA_BTSIZE_MAX;
+ maddr += maxtransfer;
}
}
}
@@ -1738,6 +2105,9 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, size_t nby
ret = sam_txbuffer(dmach, paddr, maddr, nbytes);
}
+ /* Clean caches associated with the DMA memory */
+
+ cp15_coherent_dcache(maddr, maddr + nbytes);
return ret;
}
@@ -1756,6 +2126,7 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
size_t nbytes)
{
struct sam_dmach_s *dmach = (struct sam_dmach_s *)handle;
+ size_t maxtransfer;
int ret = OK;
dmavdbg("dmach: %p paddr: %08x maddr: %08x nbytes: %d\n",
@@ -1763,18 +2134,24 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
DEBUGASSERT(dmach);
dmavdbg("llhead: %p lltail: %p\n", dmach->llhead, dmach->lltail);
+ /* The maximum transfer size in bytes depends upon the maximum number of
+ * transfers and the number of bytes per transfer.
+ */
+
+ maxtransfer = sam_maxrxtransfer(dmach);
+
/* If this is a large transfer, break it up into smaller buffers */
- while (nbytes > DMAC_CH_CTRLA_BTSIZE_MAX)
+ while (nbytes > maxtransfer)
{
/* Set up the maximum size transfer */
- ret = sam_rxbuffer(dmach, paddr, maddr, DMAC_CH_CTRLA_BTSIZE_MAX);
+ ret = sam_rxbuffer(dmach, paddr, maddr, maxtransfer);
if (ret == OK);
{
/* Decrement the number of bytes left to transfer */
- nbytes -= DMAC_CH_CTRLA_BTSIZE_MAX;
+ nbytes -= maxtransfer;
/* Increment the memory & peripheral address (if it is appropriate to
* do do).
@@ -1782,12 +2159,12 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
if ((dmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0)
{
- paddr += DMAC_CH_CTRLA_BTSIZE_MAX;
+ paddr += maxtransfer;
}
if ((dmach->flags & DMACH_FLAG_MEMINCREMENT) != 0)
{
- maddr += DMAC_CH_CTRLA_BTSIZE_MAX;
+ maddr += maxtransfer;
}
}
}
@@ -1799,6 +2176,9 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
ret = sam_rxbuffer(dmach, paddr, maddr, nbytes);
}
+ /* Clean caches associated with the DMA memory */
+
+ cp15_coherent_dcache(maddr, maddr + nbytes);
return ret;
}
diff --git a/nuttx/arch/arm/src/sama5/sam_dmac.h b/nuttx/arch/arm/src/sama5/sam_dmac.h
index 138f41f64..3d4831b21 100644
--- a/nuttx/arch/arm/src/sama5/sam_dmac.h
+++ b/nuttx/arch/arm/src/sama5/sam_dmac.h
@@ -104,7 +104,7 @@
/* Memory endpoint characteristics */
#define DMACH_FLAG_MEMPID_SHIFT (17) /* Bits 17-22: Memory PID */
-#define DMACH_FLAG_MEMPID_MASK (63 << DMACH_FLAG_PERIPHPID_SHIFT)
+#define DMACH_FLAG_MEMPID_MASK (63 << DMACH_FLAG_MEMPID_SHIFT)
#define DMACH_FLAG_MEMH2SEL (1 << 23) /* Bits 23: HW handshaking */
#define DMACH_FLAG_MEMISPERIPH (1 << 24) /* Bits 24: 0=memory; 1=peripheral */
#define DMACH_FLAG_MEMAHB_SHIFT (25) /* Bits 25-26: Peripheral ABH layer number */
diff --git a/nuttx/arch/arm/src/sama5/sam_hsmci.c b/nuttx/arch/arm/src/sama5/sam_hsmci.c
index 8ad9a1b2a..42558048a 100644
--- a/nuttx/arch/arm/src/sama5/sam_hsmci.c
+++ b/nuttx/arch/arm/src/sama5/sam_hsmci.c
@@ -175,7 +175,7 @@
( HSMCI_INT_CSTOE | HSMCI_INT_RTOE | HSMCI_INT_RENDE | HSMCI_INT_RDIRE | \
HSMCI_INT_RINDE )
#define HSMCI_RESPONSE_TIMEOUT_ERRORS \
- ( HSMCI_INT_CSTOE | HSMCI_INT_RTOE )
+ ( HSMCI_INT_CSTOE | HSMCI_INT_RTOE )
/* Data transfer errors:
*
@@ -261,7 +261,6 @@
/****************************************************************************
* Private Types
****************************************************************************/
-
/* Register logging support */
#if defined(CONFIG_SAMA5_HSMCI_XFRDEBUG) || defined(CONFIG_SAMA5_HSMCI_CMDDEBUG)
@@ -432,7 +431,7 @@ static void sam_notransfer(struct sam_dev_s *priv);
/* Interrupt Handling *******************************************************/
-static int sam_hsmci_interrupt(struct sam_dev_s *priv);
+static int sam_hsmci_interrupt(struct sam_dev_s *priv);
#ifdef CONFIG_SAMA5_HSMCI0
static int sam_hsmci0_interrupt(int irq, void *context);
#endif
@@ -497,7 +496,6 @@ static void sam_callback(void *arg);
/****************************************************************************
* Private Data
****************************************************************************/
-
/* Callbacks */
static const struct sdio_dev_s g_callbacks =
@@ -2733,7 +2731,7 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno)
/* For DMA channel selection */
dmac = 0;
- pid = DMAC0_CH_HSMCI0;
+ pid = SAM_PID_HSMCI0;
}
else
#endif
@@ -2770,7 +2768,7 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno)
/* For DMA channel selection */
dmac = 1;
- pid = DMAC1_CH_HSMCI1;
+ pid = SAM_PID_HSMCI1;
}
else
#endif
@@ -2807,7 +2805,7 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno)
/* For DMA channel selection */
dmac = 1;
- pid = DMAC1_CH_HSMCI2;
+ pid = SAM_PID_HSMCI2;
}
else
#endif
@@ -2827,7 +2825,7 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno)
/* Initialize the callbacks */
- memcpy(&priv->dev, &g_callbacks, sizeof(struct sdio_dev_s ));
+ memcpy(&priv->dev, &g_callbacks, sizeof(struct sdio_dev_s));
/* Allocate a DMA channel */