summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-10-18 08:06:23 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-10-18 08:06:23 -0600
commite1d399b339878b4106e02a2803558a1566e6dd6b (patch)
treed9b325992631455bd9a9a46df7b7cc29e6edaa94
parentb154fa5b1b08512616f34cbd9afb53b88ae19a94 (diff)
downloadnuttx-e1d399b339878b4106e02a2803558a1566e6dd6b.tar.gz
nuttx-e1d399b339878b4106e02a2803558a1566e6dd6b.tar.bz2
nuttx-e1d399b339878b4106e02a2803558a1566e6dd6b.zip
Changes to stm32_dmacapable interfaces from Mike Smith
-rw-r--r--nuttx/ChangeLog7
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_dma.h11
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_sdio.c174
-rw-r--r--nuttx/arch/arm/src/stm32/stm32f10xxx_dma.c50
-rw-r--r--nuttx/arch/arm/src/stm32/stm32f20xxx_dma.c87
-rw-r--r--nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c108
-rw-r--r--nuttx/drivers/mmcsd/Kconfig4
7 files changed, 361 insertions, 80 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 01b87931a..246b69341 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -5795,4 +5795,9 @@
UART8 DMA configs. From Mike Smit (2013-10-18).
* arch/arm/src/stm32/Kconfig: DMA priority corrections from Mike Smith
(2013-10-18).
-
+ * arch/arm/src/stm32/stm32*_dma.c, stm32_sdio.c, and stm32_dma.h:
+ Changes to the stm32_dmacapable API. In order to correctly verify that
+ a buffer can be transferred, the transfer count and the CCR value are
+ required. Implemented stm32_dmacapable for stm32f1xx devices. Enhanced
+ stm32_dmacapable for stm32f2xx and stm32f4xx devices to check for
+ additional conditions that will cause DMA to fail or lose data (2013-10-18).
diff --git a/nuttx/arch/arm/src/stm32/stm32_dma.h b/nuttx/arch/arm/src/stm32/stm32_dma.h
index 771754bf9..1d4baae4f 100644
--- a/nuttx/arch/arm/src/stm32/stm32_dma.h
+++ b/nuttx/arch/arm/src/stm32/stm32_dma.h
@@ -271,9 +271,10 @@ size_t stm32_dmaresidual(DMA_HANDLE handle);
*
* Description:
* Check if the DMA controller can transfer data to/from given memory
- * address. This depends on the internal connections in the ARM bus matrix
- * of the processor. Note that this only applies to memory addresses, it
- * will return false for any peripheral address.
+ * address with the given configuration. This depends on the internal
+ * connections in the ARM bus matrix of the processor. Note that this
+ * only applies to memory addresses, it will return false for any peripheral
+ * address.
*
* Returned value:
* True, if transfer is possible.
@@ -281,9 +282,9 @@ size_t stm32_dmaresidual(DMA_HANDLE handle);
****************************************************************************/
#ifdef CONFIG_STM32_DMACAPABLE
-bool stm32_dmacapable(uintptr_t maddr);
+bool stm32_dmacapable(uintptr_t maddr, uint32_t count, uint32_t ccr);
#else
-# define stm32_dmacapable(maddr) (true)
+# define stm32_dmacapable(maddr, count, ccr) (true)
#endif
/****************************************************************************
diff --git a/nuttx/arch/arm/src/stm32/stm32_sdio.c b/nuttx/arch/arm/src/stm32/stm32_sdio.c
index 6e94b16a1..ea06deade 100644
--- a/nuttx/arch/arm/src/stm32/stm32_sdio.c
+++ b/nuttx/arch/arm/src/stm32/stm32_sdio.c
@@ -292,7 +292,7 @@
struct stm32_dev_s
{
struct sdio_dev_s dev; /* Standard, base SDIO interface */
-
+
/* STM32-specific extensions */
/* Event support */
@@ -453,6 +453,8 @@ static int stm32_registercallback(FAR struct sdio_dev_s *dev,
#ifdef CONFIG_SDIO_DMA
static bool stm32_dmasupported(FAR struct sdio_dev_s *dev);
+static int stm32_dmapreflight(FAR struct sdio_dev_s *dev,
+ FAR uint8_t *buffer, size_t buflen);
static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev,
FAR uint8_t *buffer, size_t buflen);
static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
@@ -501,6 +503,7 @@ struct stm32_dev_s g_sdiodev =
.registercallback = stm32_registercallback,
#ifdef CONFIG_SDIO_DMA
.dmasupported = stm32_dmasupported,
+ .dmapreflight = stm32_dmapreflight,
.dmarecvsetup = stm32_dmarecvsetup,
.dmasendsetup = stm32_dmasendsetup,
#endif
@@ -570,7 +573,7 @@ static void stm32_takesem(struct stm32_dev_s *priv)
static inline void stm32_setclkcr(uint32_t clkcr)
{
uint32_t regval = getreg32(STM32_SDIO_CLKCR);
-
+
/* Clear CLKDIV, PWRSAV, BYPASS, WIDBUS, NEGEDGE, HWFC_EN bits */
regval &= ~(SDIO_CLKCR_CLKDIV_MASK|SDIO_CLKCR_PWRSAV|SDIO_CLKCR_BYPASS|
@@ -1024,7 +1027,7 @@ static void stm32_sendfifo(struct stm32_dev_s *priv)
{
data.b[i] = *ptr++;
}
-
+
/* Now the transfer is finished */
priv->remaining = 0;
@@ -1192,7 +1195,7 @@ static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupeven
stm32_configxfrints(priv, 0);
/* Clearing pending interrupt status on all transfer related interrupts */
-
+
putreg32(SDIO_XFRDONE_ICR, STM32_SDIO_ICR);
/* If this was a DMA transfer, make sure that DMA is stopped */
@@ -1452,7 +1455,7 @@ static int stm32_interrupt(int irq, void *context)
#ifdef CONFIG_SDIO_MUXBUS
static int stm32_lock(FAR struct sdio_dev_s *dev, bool lock)
-{
+{
/* Single SDIO instance so there is only one possibility. The multiplex
* bus is part of board support package.
*/
@@ -1598,7 +1601,7 @@ static void stm32_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate)
/* Enable in initial ID mode clocking (<400KHz) */
- case CLOCK_IDMODE:
+ case CLOCK_IDMODE:
clckr = (STM32_CLCKCR_INIT | SDIO_CLKCR_CLKEN);
break;
@@ -1731,7 +1734,7 @@ static int stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg)
cmdidx = (cmd & MMCSD_CMDIDX_MASK) >> MMCSD_CMDIDX_SHIFT;
regval |= cmdidx | SDIO_CMD_CPSMEN;
-
+
fvdbg("cmd: %08x arg: %08x regval: %08x\n", cmd, arg, regval);
/* Write the SDIO CMD */
@@ -1880,7 +1883,7 @@ static int stm32_cancel(FAR struct sdio_dev_s *dev)
/* Clearing pending interrupt status on all transfer- and event- related
* interrupts
*/
-
+
putreg32(SDIO_WAITALL_ICR, STM32_SDIO_ICR);
/* Cancel any watchdog timeout */
@@ -2119,7 +2122,7 @@ static int stm32_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t rlo
ret = -EIO;
}
}
-
+
/* Return the long response */
putreg32(SDIO_RESPDONE_ICR|SDIO_CMDDONE_ICR, STM32_SDIO_ICR);
@@ -2216,7 +2219,7 @@ static void stm32_waitenable(FAR struct sdio_dev_s *dev,
{
struct stm32_dev_s *priv = (struct stm32_dev_s*)dev;
uint32_t waitmask;
-
+
DEBUGASSERT(priv != NULL);
/* Disable event-related interrupts */
@@ -2330,7 +2333,7 @@ static sdio_eventset_t stm32_eventwait(FAR struct sdio_dev_s *dev,
stm32_takesem(priv);
wkupevent = priv->wkupevent;
-
+
/* Check if the event has occurred. When the event has occurred, then
* evenset will be set to 0 and wkupevent will be set to a nonzero value.
*/
@@ -2450,6 +2453,48 @@ static bool stm32_dmasupported(FAR struct sdio_dev_s *dev)
#endif
/****************************************************************************
+ * Name: stm32_dmapreflight
+ *
+ * Description:
+ * Preflight an SDIO DMA operation. If the buffer is not well-formed for
+ * SDIO DMA transfer (alignment, size, etc.) returns an error.
+ *
+ * Input Parameters:
+ * dev - An instance of the SDIO device interface
+ * buffer - The memory to DMA to/from
+ * buflen - The size of the DMA transfer in bytes
+ *
+ * Returned Value:
+ * OK on success; a negated errno on failure
+ ****************************************************************************/
+
+#ifdef CONFIG_SDIO_DMA
+static int stm32_dmapreflight(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
+ size_t buflen)
+{
+ struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+ DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
+
+ /* Wide bus operation is required for DMA */
+
+ if (!priv->widebus)
+ {
+ return -EINVAL;
+ }
+
+ /* DMA must be possible to the buffer */
+
+ if (!stm32_dmacapable((uintptr_t)buffer, (buflen + 3) >> 2, SDIO_RXDMA32_CONFIG))
+ {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+#endif
+
+/****************************************************************************
* Name: stm32_dmarecvsetup
*
* Description:
@@ -2474,50 +2519,45 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
{
struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
uint32_t dblocksize;
- int ret = -EINVAL;
DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
- DEBUGASSERT(((uint32_t)buffer & 3) == 0);
+ DEBUGASSERT(stm32_dmapreflight(dev, buffer, buflen) == 0);
/* Reset the DPSM configuration */
stm32_datadisable();
- /* Wide bus operation is required for DMA */
+ /* Initialize register sampling */
- if (priv->widebus)
- {
- stm32_sampleinit();
- stm32_sample(priv, SAMPLENDX_BEFORE_SETUP);
+ stm32_sampleinit();
+ stm32_sample(priv, SAMPLENDX_BEFORE_SETUP);
- /* Save the destination buffer information for use by the interrupt handler */
+ /* Save the destination buffer information for use by the interrupt handler */
- priv->buffer = (uint32_t*)buffer;
- priv->remaining = buflen;
- priv->dmamode = true;
+ priv->buffer = (uint32_t*)buffer;
+ priv->remaining = buflen;
+ priv->dmamode = true;
- /* Then set up the SDIO data path */
+ /* Then set up the SDIO data path */
- dblocksize = stm32_log2(buflen) << SDIO_DCTRL_DBLOCKSIZE_SHIFT;
- stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, buflen, dblocksize|SDIO_DCTRL_DTDIR);
+ dblocksize = stm32_log2(buflen) << SDIO_DCTRL_DBLOCKSIZE_SHIFT;
+ stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, buflen, dblocksize|SDIO_DCTRL_DTDIR);
- /* Configure the RX DMA */
+ /* Configure the RX DMA */
- stm32_configxfrints(priv, SDIO_DMARECV_MASK);
+ stm32_configxfrints(priv, SDIO_DMARECV_MASK);
- putreg32(1, SDIO_DCTRL_DMAEN_BB);
- stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32_t)buffer,
- (buflen + 3) >> 2, SDIO_RXDMA32_CONFIG);
-
- /* Start the DMA */
+ putreg32(1, SDIO_DCTRL_DMAEN_BB);
+ stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32_t)buffer,
+ (buflen + 3) >> 2, SDIO_RXDMA32_CONFIG);
- stm32_sample(priv, SAMPLENDX_BEFORE_ENABLE);
- stm32_dmastart(priv->dma, stm32_dmacallback, priv, false);
- stm32_sample(priv, SAMPLENDX_AFTER_SETUP);
- ret = OK;
- }
+ /* Start the DMA */
- return ret;
+ stm32_sample(priv, SAMPLENDX_BEFORE_ENABLE);
+ stm32_dmastart(priv->dma, stm32_dmacallback, priv, false);
+ stm32_sample(priv, SAMPLENDX_AFTER_SETUP);
+
+ return OK;
}
#endif
@@ -2546,54 +2586,48 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
{
struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
uint32_t dblocksize;
- int ret = -EINVAL;
DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
- DEBUGASSERT(((uint32_t)buffer & 3) == 0);
+ DEBUGASSERT(stm32_dmapreflight(dev, buffer, buflen) == 0);
/* Reset the DPSM configuration */
stm32_datadisable();
- /* Wide bus operation is required for DMA */
-
- if (priv->widebus)
- {
- stm32_sampleinit();
- stm32_sample(priv, SAMPLENDX_BEFORE_SETUP);
+ /* Initialize register sampling */
- /* Save the source buffer information for use by the interrupt handler */
+ stm32_sampleinit();
+ stm32_sample(priv, SAMPLENDX_BEFORE_SETUP);
- priv->buffer = (uint32_t*)buffer;
- priv->remaining = buflen;
- priv->dmamode = true;
+ /* Save the source buffer information for use by the interrupt handler */
- /* Then set up the SDIO data path */
+ priv->buffer = (uint32_t*)buffer;
+ priv->remaining = buflen;
+ priv->dmamode = true;
- dblocksize = stm32_log2(buflen) << SDIO_DCTRL_DBLOCKSIZE_SHIFT;
- stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, buflen, dblocksize);
+ /* Then set up the SDIO data path */
- /* Configure the TX DMA */
+ dblocksize = stm32_log2(buflen) << SDIO_DCTRL_DBLOCKSIZE_SHIFT;
+ stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, buflen, dblocksize);
- stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32_t)buffer,
- (buflen + 3) >> 2, SDIO_TXDMA32_CONFIG);
+ /* Configure the TX DMA */
- stm32_sample(priv, SAMPLENDX_BEFORE_ENABLE);
- putreg32(1, SDIO_DCTRL_DMAEN_BB);
+ stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32_t)buffer,
+ (buflen + 3) >> 2, SDIO_TXDMA32_CONFIG);
- /* Start the DMA */
+ stm32_sample(priv, SAMPLENDX_BEFORE_ENABLE);
+ putreg32(1, SDIO_DCTRL_DMAEN_BB);
- stm32_dmastart(priv->dma, stm32_dmacallback, priv, false);
- stm32_sample(priv, SAMPLENDX_AFTER_SETUP);
+ /* Start the DMA */
- /* Enable TX interrrupts */
+ stm32_dmastart(priv->dma, stm32_dmacallback, priv, false);
+ stm32_sample(priv, SAMPLENDX_AFTER_SETUP);
- stm32_configxfrints(priv, SDIO_DMASEND_MASK);
+ /* Enable TX interrrupts */
- ret = OK;
- }
+ stm32_configxfrints(priv, SDIO_DMASEND_MASK);
- return ret;
+ return OK;
}
#endif
@@ -2738,7 +2772,7 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno)
/* Configure GPIOs for 4-bit, wide-bus operation (the chip is capable of
* 8-bit wide bus operation but D4-D7 are not configured).
- *
+ *
* If bus is multiplexed then there is a custom bus configuration utility
* in the scope of the board support package.
*/
@@ -2772,7 +2806,7 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno)
*
* Input Parameters:
* dev - An instance of the SDIO driver device state structure.
- * cardinslot - true is a card has been detected in the slot; false if a
+ * cardinslot - true is a card has been detected in the slot; false if a
* card has been removed from the slot. Only transitions
* (inserted->removed or removed->inserted should be reported)
*
@@ -2799,6 +2833,9 @@ void sdio_mediachange(FAR struct sdio_dev_s *dev, bool cardinslot)
{
priv->cdstatus &= ~SDIO_STATUS_PRESENT;
}
+
+ irqrestore(flags);
+
fvdbg("cdstatus OLD: %02x NEW: %02x\n", cdstatus, priv->cdstatus);
/* Perform any requested callback if the status has changed */
@@ -2807,7 +2844,6 @@ void sdio_mediachange(FAR struct sdio_dev_s *dev, bool cardinslot)
{
stm32_callback(priv);
}
- irqrestore(flags);
}
/****************************************************************************
diff --git a/nuttx/arch/arm/src/stm32/stm32f10xxx_dma.c b/nuttx/arch/arm/src/stm32/stm32f10xxx_dma.c
index 616d2aa1a..01d697e87 100644
--- a/nuttx/arch/arm/src/stm32/stm32f10xxx_dma.c
+++ b/nuttx/arch/arm/src/stm32/stm32f10xxx_dma.c
@@ -611,8 +611,54 @@ size_t stm32_dmaresidual(DMA_HANDLE handle)
****************************************************************************/
#ifdef CONFIG_STM32_DMACAPABLE
-bool stm32_dmacapable(uint32_t maddr)
+bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
{
+ uint32_t transfer_size;
+ uint32_t mend;
+
+ /* Verify that the address conforms to the memory transfer size.
+ * Transfers to/from memory performed by the DMA controller are
+ * required to be aligned to their size.
+ *
+ * See ST RM0090 rev4, section 9.3.11
+ *
+ * Compute mend inline to avoid a possible non-constant integer
+ * multiply.
+ */
+
+ switch (ccr & STM32_DMA_SCR_MSIZE_MASK)
+ {
+ case DMA_SCR_MSIZE_8BITS:
+ transfer_size = 1;
+ mend = maddr + count - 1;
+ break;
+
+ case DMA_SCR_MSIZE_16BITS:
+ transfer_size = 2;
+ mend = maddr + (count << 1) - 1;
+ break;
+
+ case DMA_SCR_MSIZE_32BITS:
+ transfer_size = 4;
+ mend = maddr + (count << 2) - 1;
+ break;
+
+ default
+ return false;
+ }
+
+ if ((maddr & (transfer_size - 1)) != 0)
+ {
+ return false;
+ }
+
+ /* Verify that the transfer is to a memory region that supports DMA. */
+
+ if ((maddr & STM32_REGION_MASK) != (mend & STM32_REGION_MASK))
+ {
+ return false;
+ }
+
switch (maddr & STM32_REGION_MASK)
{
#if defined(CONFIG_STM32_STM32F10XX)
@@ -624,10 +670,12 @@ bool stm32_dmacapable(uint32_t maddr)
case STM32_SRAM_BASE:
case STM32_CODE_BASE:
/* All RAM and flash is supported */
+
return true;
default:
/* Everything else is unsupported by DMA */
+
return false;
}
}
diff --git a/nuttx/arch/arm/src/stm32/stm32f20xxx_dma.c b/nuttx/arch/arm/src/stm32/stm32f20xxx_dma.c
index 0186bec15..e6873e242 100644
--- a/nuttx/arch/arm/src/stm32/stm32f20xxx_dma.c
+++ b/nuttx/arch/arm/src/stm32/stm32f20xxx_dma.c
@@ -856,8 +856,91 @@ size_t stm32_dmaresidual(DMA_HANDLE handle)
****************************************************************************/
#ifdef CONFIG_STM32_DMACAPABLE
-bool stm32_dmacapable(uint32_t maddr)
+bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
{
+ uint32_t transfer_size, burst_length;
+ uint32_t mend;
+
+ /* Verify that the address conforms to the memory transfer size.
+ * Transfers to/from memory performed by the DMA controller are
+ * required to be aligned to their size.
+ *
+ * See ST RM0090 rev4, section 9.3.11
+ *
+ * Compute mend inline to avoid a possible non-constant integer
+ * multiply.
+ */
+
+ switch (ccr & STM32_DMA_SCR_MSIZE_MASK)
+ {
+ case DMA_SCR_MSIZE_8BITS:
+ transfer_size = 1;
+ mend = maddr + count - 1;
+ break;
+
+ case DMA_SCR_MSIZE_16BITS:
+ transfer_size = 2;
+ mend = maddr + (count << 1) - 1;
+ break;
+
+ case DMA_SCR_MSIZE_32BITS:
+ transfer_size = 4;
+ mend = maddr + (count << 2) - 1;
+ break;
+
+ default
+ return false;
+ }
+
+ if ((maddr & (transfer_size - 1)) != 0)
+ {
+ return false;
+ }
+
+ /* Verify that burst transfers do not cross a 1KiB boundary. */
+
+ if ((maddr / 1024) != (mend / 1024))
+ {
+ /* The transfer as a whole crosses a 1KiB boundary.
+ * Verify that no burst does by asserting that the address
+ * is aligned to the burst length.
+ */
+
+ switch (ccr & STM32_DMA_SCR_MBURST_MASK)
+ {
+ case DMA_SCR_MBURST_SINGLE:
+ burst_length = transfer_size;
+ break;
+
+ case DMA_SCR_MBURST_INCR4:
+ burst_length = transfer_size << 2;
+ break;
+
+ case DMA_SCR_MBURST_INCR8:
+ burst_length = transfer_size << 3;
+ break;
+
+ case DMA_SCR_MBURST_INCR16:
+ burst_length = transfer_size << 4;
+ break;
+
+ default:
+ return false;
+ }
+
+ if ((maddr & (burst_length - 1)) != 0)
+ {
+ return false;
+ }
+ }
+
+ /* Verify that the transfer is to a memory region that supports DMA. */
+
+ if ((maddr & STM32_REGION_MASK) != (mend & STM32_REGION_MASK))
+ {
+ return false;
+ }
+
switch (maddr & STM32_REGION_MASK)
{
case STM32_FSMC_BANK1:
@@ -867,10 +950,12 @@ bool stm32_dmacapable(uint32_t maddr)
case STM32_SRAM_BASE:
case STM32_CODE_BASE:
/* All RAM and flash is supported */
+
return true;
default:
/* Everything else is unsupported by DMA */
+
return false;
}
}
diff --git a/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c b/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c
index 235e40441..0a45ab965 100644
--- a/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c
+++ b/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c
@@ -607,6 +607,10 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
dmadbg("paddr: %08x maddr: %08x ntransfers: %d scr: %08x\n",
paddr, maddr, ntransfers, scr);
+#ifdef CONFIG_STM32_DMACAPABLE
+ DEBUGASSERT(stm32_dmacapable(maddr, ntransfers, scr))
+#endif
+
/* "If the stream is enabled, disable it by resetting the EN bit in the
* DMA_SxCR register, then read this bit in order to confirm that there is no
* ongoing stream operation. Writing this bit to 0 is not immediately
@@ -859,8 +863,98 @@ size_t stm32_dmaresidual(DMA_HANDLE handle)
****************************************************************************/
#ifdef CONFIG_STM32_DMACAPABLE
-bool stm32_dmacapable(uint32_t maddr)
+bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
{
+ uint32_t transfer_size, burst_length;
+ uint32_t mend;
+
+ dmavdbg("stm32_dmacapable: 0x%08x/%u 0x%08x\n", maddr, count, ccr);
+
+ /* Verify that the address conforms to the memory transfer size.
+ * Transfers to/from memory performed by the DMA controller are
+ * required to be aligned to their size.
+ *
+ * See ST RM0090 rev4, section 9.3.11
+ *
+ * Compute mend inline to avoid a possible non-constant integer
+ * multiply.
+ */
+
+ switch (ccr & DMA_SCR_MSIZE_MASK)
+ {
+ case DMA_SCR_MSIZE_8BITS:
+ transfer_size = 1;
+ mend = maddr + count - 1;
+ break;
+
+ case DMA_SCR_MSIZE_16BITS:
+ transfer_size = 2;
+ mend = maddr + (count << 1) - 1;
+ break;
+
+ case DMA_SCR_MSIZE_32BITS:
+ transfer_size = 4;
+ mend = maddr + (count << 2) - 1;
+ break;
+
+ default:
+ dmavdbg("stm32_dmacapable: bad transfer size in CCR\n");
+ return false;
+ }
+
+ if ((maddr & (transfer_size - 1)) != 0)
+ {
+ dmavdbg("stm32_dmacapable: transfer unaligned\n");
+ return false;
+ }
+
+ /* Verify that burst transfers do not cross a 1KiB boundary. */
+
+ if ((maddr / 1024) != (mend / 1024))
+ {
+ /* The transfer as a whole crosses a 1KiB boundary.
+ * Verify that no burst does by asserting that the address
+ * is aligned to the burst length.
+ */
+
+ switch (ccr & DMA_SCR_MBURST_MASK)
+ {
+ case DMA_SCR_MBURST_SINGLE:
+ burst_length = transfer_size;
+ break;
+
+ case DMA_SCR_MBURST_INCR4:
+ burst_length = transfer_size << 2;
+ break;
+
+ case DMA_SCR_MBURST_INCR8:
+ burst_length = transfer_size << 3;
+ break;
+
+ case DMA_SCR_MBURST_INCR16:
+ burst_length = transfer_size << 4;
+ break;
+
+ default:
+ dmavdbg("stm32_dmacapable: bad burst size in CCR\n");
+ return false;
+ }
+
+ if ((maddr & (burst_length - 1)) != 0)
+ {
+ dmavdbg("stm32_dmacapable: burst crosses 1KiB\n");
+ return false;
+ }
+ }
+
+ /* Verify that the transfer is to a memory region that supports DMA. */
+
+ if ((maddr & STM32_REGION_MASK) != (mend & STM32_REGION_MASK))
+ {
+ dmavdbg("stm32_dmacapable: transfer crosses memory region\n");
+ return false;
+ }
+
switch (maddr & STM32_REGION_MASK)
{
case STM32_FSMC_BANK1:
@@ -869,21 +963,29 @@ bool stm32_dmacapable(uint32_t maddr)
case STM32_FSMC_BANK4:
case STM32_SRAM_BASE:
/* All RAM is supported */
- return true;
+
+ break;
case STM32_CODE_BASE:
/* Everything except the CCM ram is supported */
+
if (maddr >= STM32_CCMRAM_BASE &&
(maddr - STM32_CCMRAM_BASE) < 65536)
{
+ dmavdbg("stm32_dmacapable: transfer targets CCMRAM\n");
return false;
}
- return true;
+ break;
default:
/* Everything else is unsupported by DMA */
+
+ dmavdbg("stm32_dmacapable: transfer targets unknown/unsupported region\n");
return false;
}
+
+ dmavdbg("stm32_dmacapable: transfer OK\n");
+ return true;
}
#endif
diff --git a/nuttx/drivers/mmcsd/Kconfig b/nuttx/drivers/mmcsd/Kconfig
index 84037707c..4949cee1f 100644
--- a/nuttx/drivers/mmcsd/Kconfig
+++ b/nuttx/drivers/mmcsd/Kconfig
@@ -78,6 +78,10 @@ config SDIO_DMA
---help---
SDIO driver supports DMA
+config SDIO_PREFLIGHT
+ bool
+ default n
+
config SDIO_MUXBUS
bool "SDIO bus share support"
default n