arch/arm/src/stm32h7/stm32_sdmmc.c: SDMMC Fix system hang on card eject.

This commit is contained in:
Gregory Nutt
2019-10-29 09:44:00 -06:00
parent 24f646a417
commit 71b0065207
+45 -14
View File
@@ -725,14 +725,16 @@ static inline void stm32_setclkcr(struct stm32_dev_s *priv, uint32_t clkcr)
regval &= ~(STM32_SDMMC_CLKCR_CLKDIV_MASK | STM32_SDMMC_CLKCR_PWRSAV | regval &= ~(STM32_SDMMC_CLKCR_CLKDIV_MASK | STM32_SDMMC_CLKCR_PWRSAV |
STM32_SDMMC_CLKCR_WIDBUS_MASK | STM32_SDMMC_CLKCR_NEGEDGE | STM32_SDMMC_CLKCR_WIDBUS_MASK | STM32_SDMMC_CLKCR_NEGEDGE |
STM32_SDMMC_CLKCR_HWFC_EN | STM32_SDMMC_CLKCR_DDR | STM32_SDMMC_CLKCR_HWFC_EN | STM32_SDMMC_CLKCR_DDR |
STM32_SDMMC_CLKCR_BUS_SPEED | STM32_SDMMC_CLKCR_SELCLKRX_MASK); STM32_SDMMC_CLKCR_BUS_SPEED |
STM32_SDMMC_CLKCR_SELCLKRX_MASK);
/* Replace with user provided settings */ /* Replace with user provided settings */
clkcr &= (STM32_SDMMC_CLKCR_CLKDIV_MASK | STM32_SDMMC_CLKCR_PWRSAV | clkcr &= (STM32_SDMMC_CLKCR_CLKDIV_MASK | STM32_SDMMC_CLKCR_PWRSAV |
STM32_SDMMC_CLKCR_WIDBUS_MASK | STM32_SDMMC_CLKCR_NEGEDGE | STM32_SDMMC_CLKCR_WIDBUS_MASK | STM32_SDMMC_CLKCR_NEGEDGE |
STM32_SDMMC_CLKCR_HWFC_EN | STM32_SDMMC_CLKCR_DDR | STM32_SDMMC_CLKCR_HWFC_EN | STM32_SDMMC_CLKCR_DDR |
STM32_SDMMC_CLKCR_BUS_SPEED | STM32_SDMMC_CLKCR_SELCLKRX_MASK); STM32_SDMMC_CLKCR_BUS_SPEED |
STM32_SDMMC_CLKCR_SELCLKRX_MASK);
regval |= clkcr | STM32_SDMMC_CLKCR_HWFC_EN; regval |= clkcr | STM32_SDMMC_CLKCR_HWFC_EN;
@@ -1545,11 +1547,13 @@ static int stm32_sdmmc_interrupt(int irq, void *context, void *arg)
if (priv->remaining == 0) if (priv->remaining == 0)
{ {
sdmmc_putreg32(priv, ~STM32_SDMMC_MASK_TXFIFOHEIE & sdmmc_putreg32(priv, ~STM32_SDMMC_MASK_TXFIFOHEIE &
sdmmc_getreg32(priv, STM32_SDMMC_MASK_OFFSET), sdmmc_getreg32(priv,
STM32_SDMMC_MASK_OFFSET),
STM32_SDMMC_MASK_OFFSET); STM32_SDMMC_MASK_OFFSET);
} }
} }
#endif #endif
/* Handle data end events */ /* Handle data end events */
if ((pending & STM32_SDMMC_STA_DATAEND) != 0) if ((pending & STM32_SDMMC_STA_DATAEND) != 0)
@@ -1668,6 +1672,7 @@ static int stm32_sdmmc_interrupt(int irq, void *context, void *arg)
} }
} }
} }
#if defined(HAVE_SDMMC_SDIO_MODE) #if defined(HAVE_SDMMC_SDIO_MODE)
if (priv->sdiomode == true) if (priv->sdiomode == true)
{ {
@@ -1696,6 +1701,7 @@ static int stm32_sdmmc_interrupt(int irq, void *context, void *arg)
} }
#endif #endif
} }
return OK; return OK;
} }
@@ -1762,6 +1768,7 @@ static void stm32_reset(FAR struct sdio_dev_s *dev)
restval = RCC_AHB3RSTR_SDMMC1RST; restval = RCC_AHB3RSTR_SDMMC1RST;
} }
#endif #endif
#if defined CONFIG_STM32H7_SDMMC2 #if defined CONFIG_STM32H7_SDMMC2
if (priv->base == STM32_SDMMC2_BASE) if (priv->base == STM32_SDMMC2_BASE)
{ {
@@ -2102,8 +2109,8 @@ static int stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
* *
****************************************************************************/ ****************************************************************************/
static void stm32_blocksetup(FAR struct sdio_dev_s *dev, unsigned int blocksize, static void stm32_blocksetup(FAR struct sdio_dev_s *dev,
unsigned int nblocks) unsigned int blocksize, unsigned int nblocks)
{ {
struct stm32_dev_s *priv = (struct stm32_dev_s *)dev; struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
@@ -2160,7 +2167,8 @@ static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
/* Then set up the SDIO data path */ /* Then set up the SDIO data path */
dblksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; dblksize = stm32_log2(priv->blocksize) <<
STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT;
stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT * ((nbytes + 511) >> 9), stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT * ((nbytes + 511) >> 9),
nbytes, dblksize | STM32_SDMMC_DCTRL_DTDIR); nbytes, dblksize | STM32_SDMMC_DCTRL_DTDIR);
@@ -2235,7 +2243,8 @@ static int stm32_sendsetup(FAR struct sdio_dev_s *dev, FAR const
/* Then set up the SDIO data path */ /* Then set up the SDIO data path */
dblksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; dblksize = stm32_log2(priv->blocksize) <<
STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT;
stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT * ((nbytes + 511) >> 9), stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT * ((nbytes + 511) >> 9),
nbytes, dblksize); nbytes, dblksize);
@@ -2688,7 +2697,21 @@ static sdio_eventset_t stm32_eventwait(FAR struct sdio_dev_s *dev,
*/ */
flags = enter_critical_section(); flags = enter_critical_section();
#if defined(CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE)
/* A card ejected while in SDIOWAIT_WRCOMPLETE can lead to a
* condition where there is no waitevents set and no wkupevent
*/
if (priv->waitevents == 0 && priv->wkupevent == 0)
{
wkupevent = SDIOWAIT_ERROR;
goto erroutdisable;
}
#else
DEBUGASSERT(priv->waitevents != 0 || priv->wkupevent != 0); DEBUGASSERT(priv->waitevents != 0 || priv->wkupevent != 0);
#endif
/* Check if the timeout event is specified in the event set */ /* Check if the timeout event is specified in the event set */
@@ -2742,16 +2765,17 @@ static sdio_eventset_t stm32_eventwait(FAR struct sdio_dev_s *dev,
for (; ; ) for (; ; )
{ {
/* Wait for an event in event set to occur. If this the event has already /* Wait for an event in event set to occur. If this the event has
* occurred, then the semaphore will already have been incremented and * already occurred, then the semaphore will already have been
* there will be no wait. * incremented and there will be no wait.
*/ */
stm32_takesem(priv); stm32_takesem(priv);
wkupevent = priv->wkupevent; wkupevent = priv->wkupevent;
/* Check if the event has occurred. When the event has occurred, then /* 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. * evenset will be set to 0 and wkupevent will be set to a nonzero
* value.
*/ */
if (wkupevent != 0) if (wkupevent != 0)
@@ -2764,6 +2788,10 @@ static sdio_eventset_t stm32_eventwait(FAR struct sdio_dev_s *dev,
/* Disable event-related interrupts */ /* Disable event-related interrupts */
#if defined(CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE)
erroutdisable:
#endif
stm32_configwaitints(priv, 0, 0, 0); stm32_configwaitints(priv, 0, 0, 0);
errout: errout:
@@ -2882,7 +2910,8 @@ static int stm32_dmapreflight(FAR struct sdio_dev_s *dev,
(((uintptr_t)buffer & (ARMV7M_DCACHE_LINESIZE - 1)) != 0 || (((uintptr_t)buffer & (ARMV7M_DCACHE_LINESIZE - 1)) != 0 ||
((uintptr_t)(buffer + buflen) & (ARMV7M_DCACHE_LINESIZE - 1)) != 0)) ((uintptr_t)(buffer + buflen) & (ARMV7M_DCACHE_LINESIZE - 1)) != 0))
{ {
dmainfo("stm32_dmapreflight: dcache unaligned buffer:0x%08x end:0x%08x\n", dmainfo("stm32_dmapreflight: dcache unaligned "
"buffer:0x%08x end:0x%08x\n",
buffer, buffer + buflen - 1); buffer, buffer + buflen - 1);
return -EFAULT; return -EFAULT;
} }
@@ -2955,7 +2984,8 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
/* Then set up the SDIO data path */ /* Then set up the SDIO data path */
dblksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; dblksize = stm32_log2(priv->blocksize) <<
STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT;
stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT * ((buflen + 511) >> 9), stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT * ((buflen + 511) >> 9),
buflen, dblksize | STM32_SDMMC_DCTRL_DTDIR); buflen, dblksize | STM32_SDMMC_DCTRL_DTDIR);
@@ -3058,7 +3088,8 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
/* Then set up the SDIO data path */ /* Then set up the SDIO data path */
dblksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; dblksize = stm32_log2(priv->blocksize) <<
STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT;
stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT * ((buflen + 511) >> 9), stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT * ((buflen + 511) >> 9),
buflen, dblksize); buflen, dblksize);