diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2013-10-18 08:06:23 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2013-10-18 08:06:23 -0600 |
commit | e1d399b339878b4106e02a2803558a1566e6dd6b (patch) | |
tree | d9b325992631455bd9a9a46df7b7cc29e6edaa94 | |
parent | b154fa5b1b08512616f34cbd9afb53b88ae19a94 (diff) | |
download | px4-nuttx-e1d399b339878b4106e02a2803558a1566e6dd6b.tar.gz px4-nuttx-e1d399b339878b4106e02a2803558a1566e6dd6b.tar.bz2 px4-nuttx-e1d399b339878b4106e02a2803558a1566e6dd6b.zip |
Changes to stm32_dmacapable interfaces from Mike Smith
-rw-r--r-- | nuttx/ChangeLog | 7 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_dma.h | 11 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_sdio.c | 174 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32f10xxx_dma.c | 50 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32f20xxx_dma.c | 87 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c | 108 | ||||
-rw-r--r-- | nuttx/drivers/mmcsd/Kconfig | 4 |
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 |