Changes to stm32_dmacapable interfaces from Mike Smith
This commit is contained in:
parent
973d11f625
commit
944e0fe81d
@ -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).
|
||||
|
@ -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
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -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.
|
||||
*/
|
||||
@ -2449,6 +2452,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
|
||||
*
|
||||
@ -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 */
|
||||
/* Initialize register sampling */
|
||||
|
||||
if (priv->widebus)
|
||||
{
|
||||
stm32_sampleinit();
|
||||
stm32_sample(priv, SAMPLENDX_BEFORE_SETUP);
|
||||
stm32_sampleinit();
|
||||
stm32_sample(priv, SAMPLENDX_BEFORE_SETUP);
|
||||
|
||||
/* Save the source buffer information for use by the interrupt handler */
|
||||
/* Save the source 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);
|
||||
dblocksize = stm32_log2(buflen) << SDIO_DCTRL_DBLOCKSIZE_SHIFT;
|
||||
stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, buflen, dblocksize);
|
||||
|
||||
/* Configure the TX DMA */
|
||||
/* Configure the TX DMA */
|
||||
|
||||
stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32_t)buffer,
|
||||
(buflen + 3) >> 2, SDIO_TXDMA32_CONFIG);
|
||||
stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32_t)buffer,
|
||||
(buflen + 3) >> 2, SDIO_TXDMA32_CONFIG);
|
||||
|
||||
stm32_sample(priv, SAMPLENDX_BEFORE_ENABLE);
|
||||
putreg32(1, SDIO_DCTRL_DMAEN_BB);
|
||||
stm32_sample(priv, SAMPLENDX_BEFORE_ENABLE);
|
||||
putreg32(1, SDIO_DCTRL_DMAEN_BB);
|
||||
|
||||
/* Start the DMA */
|
||||
/* Start the DMA */
|
||||
|
||||
stm32_dmastart(priv->dma, stm32_dmacallback, priv, false);
|
||||
stm32_sample(priv, SAMPLENDX_AFTER_SETUP);
|
||||
stm32_dmastart(priv->dma, stm32_dmacallback, priv, false);
|
||||
stm32_sample(priv, SAMPLENDX_AFTER_SETUP);
|
||||
|
||||
/* Enable TX interrrupts */
|
||||
/* Enable TX interrrupts */
|
||||
|
||||
stm32_configxfrints(priv, SDIO_DMASEND_MASK);
|
||||
stm32_configxfrints(priv, SDIO_DMASEND_MASK);
|
||||
|
||||
ret = OK;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user