mirror of
https://github.com/apache/nuttx.git
synced 2026-06-04 14:53:47 +08:00
arch/arm/src/stm32/stm32_sdio.c: SDIO Fix system hang on card eject.
This commit is contained in:
committed by
Gregory Nutt
parent
77bf9b09a1
commit
5d095e00b3
+113
-55
@@ -1,7 +1,8 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* arch/arm/src/stm32/stm32_sdio.c
|
* arch/arm/src/stm32/stm32_sdio.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009, 2011-2014, 2016-2018 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2009, 2011-2014, 2016-2019 Gregory Nutt. All rights
|
||||||
|
* reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -72,6 +73,7 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* Configuration ************************************************************/
|
/* Configuration ************************************************************/
|
||||||
|
|
||||||
/* Required system configuration options:
|
/* Required system configuration options:
|
||||||
*
|
*
|
||||||
* CONFIG_ARCH_DMA - Enable architecture-specific DMA subsystem
|
* CONFIG_ARCH_DMA - Enable architecture-specific DMA subsystem
|
||||||
@@ -315,6 +317,7 @@ struct stm32_dev_s
|
|||||||
struct sdio_dev_s dev; /* Standard, base SDIO interface */
|
struct sdio_dev_s dev; /* Standard, base SDIO interface */
|
||||||
|
|
||||||
/* STM32-specific extensions */
|
/* STM32-specific extensions */
|
||||||
|
|
||||||
/* Event support */
|
/* Event support */
|
||||||
|
|
||||||
sem_t waitsem; /* Implements event waiting */
|
sem_t waitsem; /* Implements event waiting */
|
||||||
@@ -424,13 +427,16 @@ static void stm32_dmacallback(DMA_HANDLE handle, uint8_t status, void *arg);
|
|||||||
/* Data Transfer Helpers ****************************************************/
|
/* Data Transfer Helpers ****************************************************/
|
||||||
|
|
||||||
static uint8_t stm32_log2(uint16_t value);
|
static uint8_t stm32_log2(uint16_t value);
|
||||||
static void stm32_dataconfig(uint32_t timeout, uint32_t dlen, uint32_t dctrl);
|
static void stm32_dataconfig(uint32_t timeout, uint32_t dlen,
|
||||||
|
uint32_t dctrl);
|
||||||
static void stm32_datadisable(void);
|
static void stm32_datadisable(void);
|
||||||
static void stm32_sendfifo(struct stm32_dev_s *priv);
|
static void stm32_sendfifo(struct stm32_dev_s *priv);
|
||||||
static void stm32_recvfifo(struct stm32_dev_s *priv);
|
static void stm32_recvfifo(struct stm32_dev_s *priv);
|
||||||
static void stm32_eventtimeout(int argc, uint32_t arg);
|
static void stm32_eventtimeout(int argc, uint32_t arg);
|
||||||
static void stm32_endwait(struct stm32_dev_s *priv, sdio_eventset_t wkupevent);
|
static void stm32_endwait(struct stm32_dev_s *priv,
|
||||||
static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupevent);
|
sdio_eventset_t wkupevent);
|
||||||
|
static void stm32_endtransfer(struct stm32_dev_s *priv,
|
||||||
|
sdio_eventset_t wkupevent);
|
||||||
|
|
||||||
/* Interrupt Handling *******************************************************/
|
/* Interrupt Handling *******************************************************/
|
||||||
|
|
||||||
@@ -633,14 +639,16 @@ static inline void stm32_setclkcr(uint32_t clkcr)
|
|||||||
|
|
||||||
/* Clear CLKDIV, PWRSAV, BYPASS, WIDBUS, NEGEDGE, HWFC_EN bits */
|
/* Clear CLKDIV, PWRSAV, BYPASS, WIDBUS, NEGEDGE, HWFC_EN bits */
|
||||||
|
|
||||||
regval &= ~(SDIO_CLKCR_CLKDIV_MASK | SDIO_CLKCR_PWRSAV | SDIO_CLKCR_BYPASS |
|
regval &= ~(SDIO_CLKCR_CLKDIV_MASK | SDIO_CLKCR_PWRSAV |
|
||||||
SDIO_CLKCR_WIDBUS_MASK | SDIO_CLKCR_NEGEDGE | SDIO_CLKCR_HWFC_EN |
|
SDIO_CLKCR_BYPASS | SDIO_CLKCR_WIDBUS_MASK |
|
||||||
|
SDIO_CLKCR_NEGEDGE | SDIO_CLKCR_HWFC_EN |
|
||||||
SDIO_CLKCR_CLKEN);
|
SDIO_CLKCR_CLKEN);
|
||||||
|
|
||||||
/* Replace with user provided settings */
|
/* Replace with user provided settings */
|
||||||
|
|
||||||
clkcr &= (SDIO_CLKCR_CLKDIV_MASK | SDIO_CLKCR_PWRSAV | SDIO_CLKCR_BYPASS |
|
clkcr &= (SDIO_CLKCR_CLKDIV_MASK | SDIO_CLKCR_PWRSAV |
|
||||||
SDIO_CLKCR_WIDBUS_MASK | SDIO_CLKCR_NEGEDGE | SDIO_CLKCR_HWFC_EN |
|
SDIO_CLKCR_BYPASS | SDIO_CLKCR_WIDBUS_MASK |
|
||||||
|
SDIO_CLKCR_NEGEDGE | SDIO_CLKCR_HWFC_EN |
|
||||||
SDIO_CLKCR_CLKEN);
|
SDIO_CLKCR_CLKEN);
|
||||||
|
|
||||||
regval |= clkcr;
|
regval |= clkcr;
|
||||||
@@ -686,7 +694,7 @@ static void stm32_configwaitints(struct stm32_dev_s *priv, uint32_t waitmask,
|
|||||||
{
|
{
|
||||||
/* Do not use this in STM32_SDIO_MASK register */
|
/* Do not use this in STM32_SDIO_MASK register */
|
||||||
|
|
||||||
waitmask &= !SDIOWAIT_WRCOMPLETE;
|
waitmask &= ~SDIOWAIT_WRCOMPLETE;
|
||||||
|
|
||||||
pinset = GPIO_SDIO_D0 & (GPIO_PORT_MASK | GPIO_PIN_MASK);
|
pinset = GPIO_SDIO_D0 & (GPIO_PORT_MASK | GPIO_PIN_MASK);
|
||||||
pinset |= (GPIO_INPUT | GPIO_FLOAT | GPIO_EXTI);
|
pinset |= (GPIO_INPUT | GPIO_FLOAT | GPIO_EXTI);
|
||||||
@@ -815,7 +823,8 @@ static inline uint32_t stm32_getpwrctrl(void)
|
|||||||
#ifdef CONFIG_SDIO_XFRDEBUG
|
#ifdef CONFIG_SDIO_XFRDEBUG
|
||||||
static void stm32_sampleinit(void)
|
static void stm32_sampleinit(void)
|
||||||
{
|
{
|
||||||
memset(g_sampleregs, 0xff, DEBUG_NSAMPLES * sizeof(struct stm32_sampleregs_s));
|
memset(g_sampleregs, 0xff,
|
||||||
|
DEBUG_NSAMPLES * sizeof(struct stm32_sampleregs_s));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -924,22 +933,27 @@ static void stm32_dumpsample(struct stm32_dev_s *priv,
|
|||||||
#ifdef CONFIG_SDIO_XFRDEBUG
|
#ifdef CONFIG_SDIO_XFRDEBUG
|
||||||
static void stm32_dumpsamples(struct stm32_dev_s *priv)
|
static void stm32_dumpsamples(struct stm32_dev_s *priv)
|
||||||
{
|
{
|
||||||
stm32_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_SETUP], "Before setup");
|
stm32_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_SETUP],
|
||||||
|
"Before setup");
|
||||||
|
|
||||||
#if defined(CONFIG_DEBUG_DMA_INFO) && defined(CONFIG_STM32_SDIO_DMA)
|
#if defined(CONFIG_DEBUG_DMA_INFO) && defined(CONFIG_STM32_SDIO_DMA)
|
||||||
if (priv->dmamode)
|
if (priv->dmamode)
|
||||||
{
|
{
|
||||||
stm32_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_ENABLE], "Before DMA enable");
|
stm32_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_ENABLE],
|
||||||
|
"Before DMA enable");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
stm32_dumpsample(priv, &g_sampleregs[SAMPLENDX_AFTER_SETUP], "After setup");
|
stm32_dumpsample(priv, &g_sampleregs[SAMPLENDX_AFTER_SETUP],
|
||||||
stm32_dumpsample(priv, &g_sampleregs[SAMPLENDX_END_TRANSFER], "End of transfer");
|
"After setup");
|
||||||
|
stm32_dumpsample(priv, &g_sampleregs[SAMPLENDX_END_TRANSFER],
|
||||||
|
"End of transfer");
|
||||||
|
|
||||||
#if defined(CONFIG_DEBUG_DMA_INFO) && defined(CONFIG_STM32_SDIO_DMA)
|
#if defined(CONFIG_DEBUG_DMA_INFO) && defined(CONFIG_STM32_SDIO_DMA)
|
||||||
if (priv->dmamode)
|
if (priv->dmamode)
|
||||||
{
|
{
|
||||||
stm32_dumpsample(priv, &g_sampleregs[SAMPLENDX_DMA_CALLBACK], "DMA Callback");
|
stm32_dumpsample(priv, &g_sampleregs[SAMPLENDX_DMA_CALLBACK],
|
||||||
|
"DMA Callback");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -972,7 +986,8 @@ static void stm32_dmacallback(DMA_HANDLE handle, uint8_t status, void *arg)
|
|||||||
|
|
||||||
if ((status & DMA_STATUS_ERROR) != 0)
|
if ((status & DMA_STATUS_ERROR) != 0)
|
||||||
{
|
{
|
||||||
mcerr("ERROR: DMA error %02x, remaining: %d\n", status, priv->remaining);
|
mcerr("ERROR: DMA error %02x, remaining: %d\n",
|
||||||
|
status, priv->remaining);
|
||||||
result = SDIOWAIT_ERROR;
|
result = SDIOWAIT_ERROR;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1051,8 +1066,10 @@ static void stm32_dataconfig(uint32_t timeout, uint32_t dlen, uint32_t dctrl)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
regval = getreg32(STM32_SDIO_DCTRL);
|
regval = getreg32(STM32_SDIO_DCTRL);
|
||||||
regval &= ~(SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTMODE | SDIO_DCTRL_DBLOCKSIZE_MASK);
|
regval &= ~(SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTMODE |
|
||||||
dctrl &= (SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTMODE | SDIO_DCTRL_DBLOCKSIZE_MASK);
|
SDIO_DCTRL_DBLOCKSIZE_MASK);
|
||||||
|
dctrl &= (SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTMODE |
|
||||||
|
SDIO_DCTRL_DBLOCKSIZE_MASK);
|
||||||
regval |= (dctrl | SDIO_DCTRL_DTEN | SDIO_DCTRL_SDIOEN);
|
regval |= (dctrl | SDIO_DCTRL_DTEN | SDIO_DCTRL_SDIOEN);
|
||||||
putreg32(regval, STM32_SDIO_DCTRL);
|
putreg32(regval, STM32_SDIO_DCTRL);
|
||||||
}
|
}
|
||||||
@@ -1228,7 +1245,8 @@ static void stm32_eventtimeout(int argc, uint32_t arg)
|
|||||||
|
|
||||||
/* There is always race conditions with timer expirations. */
|
/* There is always race conditions with timer expirations. */
|
||||||
|
|
||||||
DEBUGASSERT((priv->waitevents & SDIOWAIT_TIMEOUT) != 0 || priv->wkupevent != 0);
|
DEBUGASSERT((priv->waitevents & SDIOWAIT_TIMEOUT) != 0 ||
|
||||||
|
priv->wkupevent != 0);
|
||||||
|
|
||||||
/* Is a data transfer complete event expected? */
|
/* Is a data transfer complete event expected? */
|
||||||
|
|
||||||
@@ -1294,7 +1312,8 @@ static void stm32_endwait(struct stm32_dev_s *priv, sdio_eventset_t wkupevent)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupevent)
|
static void stm32_endtransfer(struct stm32_dev_s *priv,
|
||||||
|
sdio_eventset_t wkupevent)
|
||||||
{
|
{
|
||||||
/* Disable all transfer related interrupts */
|
/* Disable all transfer related interrupts */
|
||||||
|
|
||||||
@@ -1412,9 +1431,9 @@ static int stm32_interrupt(int irq, void *context, FAR void *arg)
|
|||||||
stm32_recvfifo(priv);
|
stm32_recvfifo(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise, Is the transmit FIFO half empty or less? If so we must
|
/* Otherwise, Is the transmit FIFO half empty or less? If so
|
||||||
* be processing a send transaction. NOTE: We can't be processing
|
* we must be processing a send transaction. NOTE: We can't
|
||||||
* both!
|
* be processing both!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
else if ((pending & SDIO_STA_TXFIFOHE) != 0)
|
else if ((pending & SDIO_STA_TXFIFOHE) != 0)
|
||||||
@@ -1477,8 +1496,10 @@ static int stm32_interrupt(int irq, void *context, FAR void *arg)
|
|||||||
{
|
{
|
||||||
/* Terminate the transfer with an error */
|
/* Terminate the transfer with an error */
|
||||||
|
|
||||||
mcerr("ERROR: Data block CRC failure, remaining: %d\n", priv->remaining);
|
mcerr("ERROR: Data block CRC failure, remaining: %d\n",
|
||||||
stm32_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR);
|
priv->remaining);
|
||||||
|
stm32_endtransfer(priv,
|
||||||
|
SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle data timeout error */
|
/* Handle data timeout error */
|
||||||
@@ -1487,8 +1508,10 @@ static int stm32_interrupt(int irq, void *context, FAR void *arg)
|
|||||||
{
|
{
|
||||||
/* Terminate the transfer with an error */
|
/* Terminate the transfer with an error */
|
||||||
|
|
||||||
mcerr("ERROR: Data timeout, remaining: %d\n", priv->remaining);
|
mcerr("ERROR: Data timeout, remaining: %d\n",
|
||||||
stm32_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_TIMEOUT);
|
priv->remaining);
|
||||||
|
stm32_endtransfer(priv,
|
||||||
|
SDIOWAIT_TRANSFERDONE | SDIOWAIT_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle RX FIFO overrun error */
|
/* Handle RX FIFO overrun error */
|
||||||
@@ -1497,8 +1520,10 @@ static int stm32_interrupt(int irq, void *context, FAR void *arg)
|
|||||||
{
|
{
|
||||||
/* Terminate the transfer with an error */
|
/* Terminate the transfer with an error */
|
||||||
|
|
||||||
mcerr("ERROR: RX FIFO overrun, remaining: %d\n", priv->remaining);
|
mcerr("ERROR: RX FIFO overrun, remaining: %d\n",
|
||||||
stm32_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR);
|
priv->remaining);
|
||||||
|
stm32_endtransfer(priv,
|
||||||
|
SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle TX FIFO underrun error */
|
/* Handle TX FIFO underrun error */
|
||||||
@@ -1507,8 +1532,10 @@ static int stm32_interrupt(int irq, void *context, FAR void *arg)
|
|||||||
{
|
{
|
||||||
/* Terminate the transfer with an error */
|
/* Terminate the transfer with an error */
|
||||||
|
|
||||||
mcerr("ERROR: TX FIFO underrun, remaining: %d\n", priv->remaining);
|
mcerr("ERROR: TX FIFO underrun, remaining: %d\n",
|
||||||
stm32_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR);
|
priv->remaining);
|
||||||
|
stm32_endtransfer(priv,
|
||||||
|
SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle start bit error */
|
/* Handle start bit error */
|
||||||
@@ -1517,8 +1544,10 @@ static int stm32_interrupt(int irq, void *context, FAR void *arg)
|
|||||||
{
|
{
|
||||||
/* Terminate the transfer with an error */
|
/* Terminate the transfer with an error */
|
||||||
|
|
||||||
mcerr("ERROR: Start bit, remaining: %d\n", priv->remaining);
|
mcerr("ERROR: Start bit, remaining: %d\n",
|
||||||
stm32_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR);
|
priv->remaining);
|
||||||
|
stm32_endtransfer(priv,
|
||||||
|
SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1537,7 +1566,8 @@ static int stm32_interrupt(int irq, void *context, FAR void *arg)
|
|||||||
{
|
{
|
||||||
/* Yes.. wake the thread up */
|
/* Yes.. wake the thread up */
|
||||||
|
|
||||||
putreg32(SDIO_RESPDONE_ICR | SDIO_CMDDONE_ICR, STM32_SDIO_ICR);
|
putreg32(SDIO_RESPDONE_ICR | SDIO_CMDDONE_ICR,
|
||||||
|
STM32_SDIO_ICR);
|
||||||
stm32_endwait(priv, SDIOWAIT_RESPONSEDONE);
|
stm32_endwait(priv, SDIOWAIT_RESPONSEDONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1832,7 +1862,6 @@ static int stm32_attach(FAR struct sdio_dev_s *dev)
|
|||||||
ret = irq_attach(STM32_IRQ_SDIO, stm32_interrupt, NULL);
|
ret = irq_attach(STM32_IRQ_SDIO, stm32_interrupt, NULL);
|
||||||
if (ret == OK)
|
if (ret == OK)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Disable all interrupts at the SDIO controller and clear static
|
/* Disable all interrupts at the SDIO controller and clear static
|
||||||
* interrupt flags
|
* interrupt flags
|
||||||
*/
|
*/
|
||||||
@@ -1866,7 +1895,8 @@ static int stm32_attach(FAR struct sdio_dev_s *dev)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg)
|
static int stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
|
||||||
|
uint32_t arg)
|
||||||
{
|
{
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
uint32_t cmdidx;
|
uint32_t cmdidx;
|
||||||
@@ -2003,7 +2033,8 @@ static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
|
|||||||
dblocksize = stm32_log2(nbytes) << SDIO_DCTRL_DBLOCKSIZE_SHIFT;
|
dblocksize = stm32_log2(nbytes) << SDIO_DCTRL_DBLOCKSIZE_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, nbytes, dblocksize | SDIO_DCTRL_DTDIR);
|
stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, nbytes,
|
||||||
|
dblocksize | SDIO_DCTRL_DTDIR);
|
||||||
|
|
||||||
/* And enable interrupts */
|
/* And enable interrupts */
|
||||||
|
|
||||||
@@ -2016,9 +2047,9 @@ static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
|
|||||||
* Name: stm32_sendsetup
|
* Name: stm32_sendsetup
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Setup hardware in preparation for data transfer from the card. This method
|
* Setup hardware in preparation for data transfer from the card. This
|
||||||
* will do whatever controller setup is necessary. This would be called
|
* method will do whatever controller setup is necessary. This would be
|
||||||
* for SD memory just AFTER sending CMD24 (WRITE_BLOCK), CMD25
|
* called for SD memory just AFTER sending CMD24 (WRITE_BLOCK), CMD25
|
||||||
* (WRITE_MULTIPLE_BLOCK), ... and before SDIO_SENDDATA is called.
|
* (WRITE_MULTIPLE_BLOCK), ... and before SDIO_SENDDATA is called.
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
@@ -2031,8 +2062,8 @@ static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int stm32_sendsetup(FAR struct sdio_dev_s *dev, FAR const uint8_t *buffer,
|
static int stm32_sendsetup(FAR struct sdio_dev_s *dev,
|
||||||
size_t nbytes)
|
FAR const uint8_t *buffer, size_t nbytes)
|
||||||
{
|
{
|
||||||
struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
|
struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
|
||||||
uint32_t dblocksize;
|
uint32_t dblocksize;
|
||||||
@@ -2218,7 +2249,8 @@ static int stm32_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int stm32_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rshort)
|
static int stm32_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd,
|
||||||
|
uint32_t *rshort)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_DEBUG_MEMCARD_INFO
|
#ifdef CONFIG_DEBUG_MEMCARD_INFO
|
||||||
uint32_t respcmd;
|
uint32_t respcmd;
|
||||||
@@ -2248,7 +2280,6 @@ static int stm32_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t
|
|||||||
* 0 1 End bit
|
* 0 1 End bit
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_MEMCARD_INFO
|
#ifdef CONFIG_DEBUG_MEMCARD_INFO
|
||||||
if (!rshort)
|
if (!rshort)
|
||||||
{
|
{
|
||||||
@@ -2304,7 +2335,8 @@ static int stm32_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stm32_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t rlong[4])
|
static int stm32_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd,
|
||||||
|
uint32_t rlong[4])
|
||||||
{
|
{
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
@@ -2358,7 +2390,8 @@ static int stm32_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t rlo
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stm32_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rshort)
|
static int stm32_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd,
|
||||||
|
uint32_t *rshort)
|
||||||
{
|
{
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
@@ -2513,7 +2546,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 */
|
||||||
|
|
||||||
@@ -2567,16 +2614,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)
|
||||||
@@ -2589,6 +2637,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);
|
||||||
#ifdef CONFIG_STM32_SDIO_DMA
|
#ifdef CONFIG_STM32_SDIO_DMA
|
||||||
priv->xfrflags = 0;
|
priv->xfrflags = 0;
|
||||||
@@ -2707,7 +2759,8 @@ static int stm32_dmapreflight(FAR struct sdio_dev_s *dev,
|
|||||||
|
|
||||||
/* DMA must be possible to the buffer */
|
/* DMA must be possible to the buffer */
|
||||||
|
|
||||||
if (!stm32_dmacapable((uintptr_t)buffer, (buflen + 3) >> 2, SDIO_RXDMA32_CONFIG))
|
if (!stm32_dmacapable((uintptr_t)buffer, (buflen + 3) >> 2,
|
||||||
|
SDIO_RXDMA32_CONFIG))
|
||||||
{
|
{
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
@@ -2775,7 +2828,8 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
|
|||||||
dblocksize = stm32_log2(buflen) << SDIO_DCTRL_DBLOCKSIZE_SHIFT;
|
dblocksize = stm32_log2(buflen) << SDIO_DCTRL_DBLOCKSIZE_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, buflen, dblocksize | SDIO_DCTRL_DTDIR);
|
stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, buflen,
|
||||||
|
dblocksize | SDIO_DCTRL_DTDIR);
|
||||||
|
|
||||||
/* Configure the RX DMA */
|
/* Configure the RX DMA */
|
||||||
|
|
||||||
@@ -2945,8 +2999,10 @@ static void stm32_callback(void *arg)
|
|||||||
{
|
{
|
||||||
/* Yes.. queue it */
|
/* Yes.. queue it */
|
||||||
|
|
||||||
mcinfo("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg);
|
mcinfo("Queuing callback to %p(%p)\n",
|
||||||
(void)work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0);
|
priv->callback, priv->cbarg);
|
||||||
|
(void)work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback,
|
||||||
|
priv->cbarg, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2993,7 +3049,8 @@ static void stm32_default(void)
|
|||||||
* slotno - Not used.
|
* slotno - Not used.
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* A reference to an SDIO interface structure. NULL is returned on failures.
|
* A reference to an SDIO interface structure. NULL is returned on
|
||||||
|
* failures.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
@@ -3004,6 +3061,7 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno)
|
|||||||
struct stm32_dev_s *priv = &g_sdiodev;
|
struct stm32_dev_s *priv = &g_sdiodev;
|
||||||
|
|
||||||
/* Initialize the SDIO slot structure */
|
/* Initialize the SDIO slot structure */
|
||||||
|
|
||||||
/* Initialize semaphores */
|
/* Initialize semaphores */
|
||||||
|
|
||||||
nxsem_init(&priv->waitsem, 0, 0);
|
nxsem_init(&priv->waitsem, 0, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user