mirror of
https://github.com/apache/nuttx.git
synced 2026-06-04 14:53:47 +08:00
arch/arm/src/stm32h7/stm32_sdmmc.c: SDMMC Fix system hang on card eject.
This commit is contained in:
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user