diff --git a/arch/arm/src/stm32/stm32_sdio.c b/arch/arm/src/stm32/stm32_sdio.c index 3a128da10c803ad88d3eed817e84c673a51a5d06..c491395e5309b93cf456a02836535f34187860eb 100644 --- a/arch/arm/src/stm32/stm32_sdio.c +++ b/arch/arm/src/stm32/stm32_sdio.c @@ -39,12 +39,16 @@ #include <nuttx/config.h> #include <sys/types.h> - + +#include <semaphore.h> +#include <assert.h> #include <debug.h> #include <errno.h> #include <nuttx/sdio.h> -#include <nuttx/mmcsd.h> +#include <nuttx/mmcsd.h> +#include <nuttx/arch.h> +#include <arch/irq.h> #include "chip.h" #include "up_arch.h" @@ -65,8 +69,12 @@ # undef CONFIG_SDIO_DMA #endif +#ifndef CONFIG_SDIO_PRI +# define CONFIG_SDIO_PRI DMA_CCR_PRIMED +#endif + #ifndef CONFIG_SDIO_DMAPRIO -# define CONFIG_SDIO_DMAPRIO DMA_CCR_PRIMED +# define CONFIG_SDIO_DMAPRIO DMA_CCR_PRIMED #endif /* Friendly CLKCR bit re-definitions ****************************************/ @@ -83,22 +91,31 @@ /* HCLK=72 MHz, SDIOCLK=72MHz, SDIO_CK=HCLK/(1+2)=24 MHz */ #define SDIO_TRANSFER_CLKDIV (1 << SDIO_CLKCR_CLKDIV_SHIFT) -#define STM32_CLCKCR_TRANSFER \ - (SDIO_TRANSFER_CLKDIV|SDIO_CLKCR_RISINGEDGE|SDIO_CLKCR_WIDBUS_D1) -#define STM32_CLKCR_WIDETRANSFER \ - (SDIO_TRANSFER_CLKDIV|SDIO_CLKCR_RISINGEDGE|SDIO_CLKCR_WIDBUS_D4) +#define STM32_CLCKCR_TRANSFER (SDIO_TRANSFER_CLKDIV|SDIO_CLKCR_RISINGEDGE|\ + SDIO_CLKCR_WIDBUS_D1) +#define STM32_CLKCR_WIDETRANSFER (SDIO_TRANSFER_CLKDIV|SDIO_CLKCR_RISINGEDGE|\ + SDIO_CLKCR_WIDBUS_D4) /* Timing */ -#define SDIO_CMDTIMEOUT 100000 -#define SDIO_LONGTIMEOUT 0x7fffffff +#define SDIO_CMDTIMEOUT (100000) +#define SDIO_LONGTIMEOUT (0x7fffffff) + +/* Big DTIMER setting */ + +#define SDIO_DTIMER_DATATIMEOUT (0x000fffff) /* DMA CCR register settings */ -#define SDIO_RXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\ - DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC) -#define SDIO_TXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\ - DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC|DMA_CCR_DIR) +#define SDIO_RXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\ + DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC) +#define SDIO_TXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\ + DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC|DMA_CCR_DIR) + +/* FIFO sizes */ + +#define SDIO_HALFFIFO_WORDS (8) +#define SDIO_HALFFIFO_BYTES (8*4) /**************************************************************************** * Private Types @@ -108,20 +125,30 @@ struct stm32_dev_s { - struct sdio_dev_s dev; /* Standard, base MMC/SD interface */ + struct sdio_dev_s dev; /* Standard, base SDIO interface */ /* STM32-specific extensions */ - sem_t eventsem; /* Implements event waiting */ - sdio_event_t waitevents; /* Set of events to be waited for */ - volatile sdio_event_t wkupevents; /* Set of events that caused the wakeup */ - sdio_event_t cbevents; /* Set of events to be cause callbacks */ - sdio_mediachange_t callback; /* Registered callback function */ + sem_t waitsem; /* Implements event waiting */ + sdio_eventset_t waitevents; /* Set of events to be waited for */ + volatile sdio_eventset_t wkupevent; /* The event that caused the wakeup */ + sdio_eventset_t cbevents; /* Set of events to be cause callbacks */ + sdio_mediachange_t callback; /* Registered callback function */ + void *cbarg; /* Registered callback argument */ + + /* Interrupt mode data transfer support */ - /* DMA support */ + uint32 *buffer; /* Address of current R/W buffer */ + size_t remaining; /* Number of bytes remaining in the transfer */ + int result; /* Result of the transfer */ + boolean stopxfr; /* TRUE: Send STOP_TRANSMISSION */ + /* DMA data transfer support */ + + boolean widebus; /* Required for DMA support */ #ifdef CONFIG_SDIO_DMA - DMA_HANDLE dma; /* Handle for DMA channel */ + boolean dmamode; /* TRUE: DMA mode transfer */ + DMA_HANDLE dma; /* Handle for DMA channel */ #endif }; @@ -138,8 +165,8 @@ static inline void stm32_enableint(uint32 bitset); static inline void stm32_disableint(uint32 bitset); static void stm32_setpwrctrl(uint32 pwrctrl); static inline uint32 stm32_getpwrctrl(void); -static inline void stm32_clkenable(void) -static inline void stm32_clkdisable(void) +static inline void stm32_clkenable(void); +static inline void stm32_clkdisable(void); /* DMA Helpers **************************************************************/ @@ -151,7 +178,15 @@ static void stm32_dmacallback(DMA_HANDLE handle, ubyte isr, void *arg); static ubyte stm32_log2(uint16 value); static void stm32_dataconfig(uint32 timeout, uint32 dlen, uint32 dctrl); -static void stm32_datadisable(void); +static void stm32_datadisable(void); +static void stm32_sendfifo(struct stm32_dev_s *priv); +static void stm32_recvfifo(struct stm32_dev_s *priv); +static int stm32_stoptransmission(struct stm32_dev_s *priv); +static void stm32_endtransfer(struct stm32_dev_s *priv, int result); + +/* Interrupt Handling *******************************************************/ + +static int stm32_interrupt(int irq, void *context); /* SDIO interface methods ***************************************************/ @@ -166,40 +201,43 @@ static int stm32_attach(FAR struct sdio_dev_s *dev); /* Command/Status/Data Transfer */ -static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg); -static int stm32_sendsetup(FAR struct sdio_dev_s *dev, uint32 nbytes); -static int stm32_senddata(FAR struct sdio_dev_s *dev, - FAR const ubyte *buffer); - -static int stm32_waitresponseFAR struct sdio_dev_s *dev, uint32 cmd); -static int stm32_recvshortcrc(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rshort); -static int stm32_recvlong(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 rlong[4]); -static int stm32_recvshort(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rshort); -static int stm32_recvnotimpl(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rnotimpl); -static int stm32_recvsetup(FAR struct sdio_dev_s *dev, uint32 nbytes); -static int stm32_recvdata(FAR struct sdio_dev_s *dev, FAR ubyte *buffer); +static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd, + uint32 arg); +static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, + size_t nbytes); +static int stm32_sendsetup(FAR struct sdio_dev_s *dev, + FAR const ubyte *buffer, uint32 nbytes); + +static int stm32_waitresponse(FAR struct sdio_dev_s *dev, uint32 cmd); +static int stm32_recvshortcrc(FAR struct sdio_dev_s *dev, uint32 cmd, + uint32 *rshort); +static int stm32_recvlong(FAR struct sdio_dev_s *dev, uint32 cmd, + uint32 rlong[4]); +static int stm32_recvshort(FAR struct sdio_dev_s *dev, uint32 cmd, + uint32 *rshort); +static int stm32_recvnotimpl(FAR struct sdio_dev_s *dev, uint32 cmd, + uint32 *rnotimpl); /* EVENT handler */ -static void stm32_waitenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset, - boolean enable); +static void stm32_waitenable(FAR struct sdio_dev_s *dev, + sdio_eventset_t eventset); static ubyte stm32_eventwait(FAR struct sdio_dev_s *dev, uint32 timeout); static ubyte stm32_events(FAR struct sdio_dev_s *dev); -static void stm32_callbackenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset); +static void stm32_callbackenable(FAR struct sdio_dev_s *dev, + sdio_eventset_t eventset); static int stm32_registercallback(FAR struct sdio_dev_s *dev, - sdio_mediachange_t callback, void *arg) + sdio_mediachange_t callback, void *arg); /* DMA */ #ifdef CONFIG_SDIO_DMA static boolean stm32_dmasupported(FAR struct sdio_dev_s *dev); -static int stm32_dmareadsetup(FAR struct sdio_dev_s *dev, +static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, size_t buflen); -static int stm32_dmawritesetup(FAR struct sdio_dev_s *dev, +static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer, size_t buflen); -static int stm32_dmastart(FAR struct sdio_dev_s *dev); -static int stm32_dmastatus(FAR struct sdio_dev_s *dev, - size_t *remaining); +static int stm32_sdiodmastart(FAR struct sdio_dev_s *dev); #endif /* Initialization/uninitialization/reset ************************************/ @@ -211,7 +249,7 @@ static void stm32_default(void); * Private Data ****************************************************************************/ -struct stm32_dev_s g_mmcsd = +struct stm32_dev_s g_sdiodev = { .dev = { @@ -221,8 +259,8 @@ struct stm32_dev_s g_mmcsd = .clock = stm32_clock, .attach = stm32_attach, .sendcmd = stm32_sendcmd, + .recvsetup = stm32_recvsetup, .sendsetup = stm32_sendsetup, - .senddata = stm32_senddata, .waitresponse = stm32_waitresponse, .recvR1 = stm32_recvshortcrc, .recvR2 = stm32_recvlong, @@ -231,8 +269,6 @@ struct stm32_dev_s g_mmcsd = .recvR5 = stm32_recvnotimpl, .recvR6 = stm32_recvshortcrc, .recvR7 = stm32_recvshort, - .recvsetup = stm32_recvsetup, - .recvdata = stm32_recvdata, .waitenable = stm32_waitenable, .eventwait = stm32_eventwait, .events = stm32_events, @@ -240,10 +276,9 @@ struct stm32_dev_s g_mmcsd = .registercallback = stm32_registercallback, #ifdef CONFIG_SDIO_DMA .dmasupported = stm32_dmasupported, - .dmareadsetup = stm32_dmareadsetup, - .dmawritesetup = stm32_dmawritesetup, - .dmastart = stm32_dmastart, - .dmastatus = stm32_dmastatus, + .dmarecvsetup = stm32_dmarecvsetup, + .dmasendsetup = stm32_dmasendsetup, + .dmastart = stm32_sdiodmastart, #endif }, }; @@ -436,15 +471,9 @@ static void stm32_dmacallback(DMA_HANDLE handle, ubyte isr, void *arg) { FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg; - /* Is a data transfer complete event expected? */ - - if ((priv->waitevents & SDIOWAIT_TRANSFERDONE) != 0) - { - /* Yes, wake up the waiting thread */ - - priv->wkupevent = SDIOWAIT_TRANSFERDONE; - sdio_semgive(priv); - } + /* We don't really do anything at the completion of DMA. The termination + * of the transfer is driven by the SDIO interrupts. + */ } #endif @@ -506,7 +535,7 @@ static void stm32_dataconfig(uint32 timeout, uint32 dlen, uint32 dctrl) regval = getreg32(STM32_SDIO_DCTRL); regval &= ~(SDIO_DCTRL_DTDIR|SDIO_DCTRL_DTMODE|SDIO_DCTRL_DBLOCKSIZE_MASK); dctrl &= (SDIO_DCTRL_DTDIR|SDIO_DCTRL_DTMODE|SDIO_DCTRL_DBLOCKSIZE_MASK); - regval |= (dctrl|DIO_DCTRL_DTEN); + regval |= (dctrl|SDIO_DCTRL_DTEN); putreg32(regval, STM32_SDIO_DCTRL); } @@ -525,7 +554,7 @@ static void stm32_datadisable(void) /* Disable the data path */ - putreg32(SD_DATATIMEOUT, STM32_SDIO_DTIMER); /* Reset DTIMER */ + putreg32(SDIO_DTIMER_DATATIMEOUT, STM32_SDIO_DTIMER); /* Reset DTIMER */ putreg32(0, STM32_SDIO_DLEN); /* Reset DLEN */ /* Reset DCTRL DTEN, DTDIR, DTMODE, DMAEN, and DBLOCKSIZE fields */ @@ -536,6 +565,336 @@ static void stm32_datadisable(void) putreg32(regval, STM32_SDIO_DCTRL); } +/**************************************************************************** + * Name: stm32_sendfifo + * + * Description: + * Send SDIO data in interrupt mode + * + * Input Parameters: + * priv - An instance of the SDIO device interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void stm32_sendfifo(struct stm32_dev_s *priv) +{ + union + { + uint32 w; + ubyte b[2]; + } data; + + /* Loop while there is more data to be sent and the RX FIFO is not full */ + + while (priv->remaining > 0 && + (getreg32(STM32_SDIO_STA) & SDIO_STA_TXFIFOF) == 0) + { + /* Is there a full word remaining in the user buffer? */ + + if (priv->remaining >= sizeof(uint32)) + { + /* Yes, transfer the word to the TX FIFO */ + + data.w = *priv->buffer++; + priv->remaining -= sizeof(uint32); + } + else + { + /* No.. transfer just the bytes remaining in the user buffer, + * padding with zero as necessary to extend to a full word. + */ + + ubyte *ptr = (ubyte *)priv->remaining; + int i; + + data.w = 0; + for (i = 0; i < priv->remaining; i++) + { + data.b[i] = *ptr++; + } + + /* Now the transfer is finished */ + + priv->remaining = 0; + } + + /* Put the word in the FIFO */ + + putreg32(data.w, STM32_SDIO_FIFO); + } +} + +/**************************************************************************** + * Name: stm32_recvfifo + * + * Description: + * Receive SDIO data in interrupt mode + * + * Input Parameters: + * priv - An instance of the SDIO device interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void stm32_recvfifo(struct stm32_dev_s *priv) +{ + union + { + uint32 w; + ubyte b[2]; + } data; + + /* Loop while there is space to store the data and there is more + * data available in the RX FIFO. + */ + + while (priv->remaining > 0 && + (getreg32(STM32_SDIO_STA) & SDIO_STA_RXDAVL) == 0) + { + /* Read the next word from the RX FIFO */ + + data.w = getreg32(STM32_SDIO_FIFO); + if (priv->remaining >= sizeof(uint32)) + { + /* Transfer the whole word to the user buffer */ + + *priv->buffer++ = data.w; + priv->remaining -= sizeof(uint32); + } + else + { + /* Transfer any trailing fractional word */ + + ubyte *ptr = (ubyte*)priv->buffer; + int i; + + for (i = 0; i < priv->remaining; i++) + { + *ptr++ = data.b[i]; + } + + /* Now the transfer is finished */ + + priv->remaining = 0; + } + } +} + +/**************************************************************************** + * Name: stm32_stoptransmission + * + * Description: + * Send STOP_TRANSMISSION + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * + * Returned Value: + * OK on success; A negated errno on failure. + * + ****************************************************************************/ + +static int stm32_stoptransmission(struct stm32_dev_s *priv) +{ +# warning "Not implemented" + return -ENOSYS; +} + +/**************************************************************************** + * Name: stm32_endtransfer + * + * Description: + * Terminate a transfer with the provided status + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * result - The result status of the transfer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void stm32_endtransfer(struct stm32_dev_s *priv, int result) +{ + /* Disable interrupts */ + + stm32_disableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE| + SDIO_MASK_DATAENDIE|SDIO_MASK_TXFIFOHEIE| + SDIO_MASK_RXFIFOHFIE|SDIO_MASK_TXUNDERRIE| + SDIO_MASK_RXOVERRIE|SDIO_MASK_STBITERRIE); + + /* Mark the transfer finished with the provided status */ + + priv->remaining = 0; + priv->result = result; + + /* Is a data transfer complete event expected? */ + + if ((priv->waitevents & SDIOWAIT_TRANSFERDONE) != 0) + { + /* Yes, wake up the waiting thread */ + + priv->wkupevent = SDIOWAIT_TRANSFERDONE; + stm32_givesem(priv); + } +} + +/**************************************************************************** + * Interrrupt Handling + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_interrupt + * + * Description: + * SDIO interrupt handler + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int stm32_interrupt(int irq, void *context) +{ + struct stm32_dev_s *priv = &g_sdiodev; + uint32 sta; + + /* Loop while there are pending interrupts. Check the SDIO status + * register. Mask out all bits that don't correspond to enabled + * interrupts. (This depends on the fact that bits are ordered + * the same in both the STA and MASK register). If there are non-zero + * bits remaining, then we have work to do here. + */ + + while ((sta = getreg32(STM32_SDIO_STA) & getreg32(STM32_SDIO_MASK)) != 0) + { + /* Handle in progress, interrupt driven data transfers */ + +#ifdef CONFIG_SDIO_DMA + if (!priv->dmamode) +#endif + { + /* Is the RX FIFO half full or more? Is so then we must be + * processing a receive transaction. + */ + + if ((sta & SDIO_STA_RXFIFOHF) != 0) + { + /* Receive data from the RX FIFO */ + + stm32_recvfifo(priv); + } + + /* Otherwise, Is the transmit FIFO half empty or less? If so we must + * be processing a send transaction. NOTE: We can't be processing + * both! + */ + + else if ((sta & SDIO_STA_TXFIFOHE) != 0) + { + /* Send data via the TX FIFO */ + + stm32_sendfifo(priv); + } + } + + /* Handle data end events */ + + if ((sta & SDIO_STA_DATAEND) != 0) + { + int result; + + /* Handle any data remaining the RX FIFO. If the RX FIFO is + * less than half full at the end of the transfer, then no + * half-full interrupt will be received. + */ + +#ifdef CONFIG_SDIO_DMA + if (!priv->dmamode) +#endif + { + /* Receive data from the RX FIFO */ + + stm32_recvfifo(priv); + } + + /* Check if we are supposed to send STOP_TRANSMISSION now */ + + result = OK; + if (priv->stopxfr) + { + result = stm32_stoptransmission(priv); + } + + /* Then terminate the transfer */ + + putreg32(SDIO_ICR_DATAENDC, STM32_SDIO_ICR); + stm32_endtransfer(priv, result); + } + + /* Handler data block send/receive CRC failure */ + + else if ((sta & SDIO_STA_DCRCFAIL) != 0) + { + /* Terminate the transfer with an error */ + + putreg32(SDIO_ICR_DCRCFAILC, STM32_SDIO_ICR); + stm32_endtransfer(priv, -EIO); + } + + /* Handle data timeout error */ + + else if ((sta & SDIO_STA_DTIMEOUT) != 0) + { + /* Terminate the transfer with an error */ + + putreg32(SDIO_ICR_DTIMEOUTC, STM32_SDIO_ICR); + stm32_endtransfer(priv, -ETIMEDOUT); + } + + /* Handle RX FIFO overrun error */ + + else if ((sta & SDIO_STA_RXOVERR) != 0) + { + /* Terminate the transfer with an error */ + + putreg32(SDIO_ICR_RXOVERRC, STM32_SDIO_ICR); + stm32_endtransfer(priv, -EOVERFLOW); + } + + /* Handle TX FIFO underrun error */ + + else if ((sta & SDIO_STA_TXUNDERR) != 0) + { + /* Terminate the transfer with an error */ + + putreg32(SDIO_ICR_TXUNDERRC, STM32_SDIO_ICR); + stm32_endtransfer(priv, -EOVERFLOW); + } + + /* Handle start bit error */ + + else if ((sta & SDIO_STA_STBITERR) != 0) + { + /* Terminate the transfer with an error */ + + putreg32(SDIO_ICR_STBITERRC, STM32_SDIO_ICR); + stm32_endtransfer(priv, -EIO); + } + } + + return OK; +} + /**************************************************************************** * SDIO Interface Methods ****************************************************************************/ @@ -543,10 +902,10 @@ static void stm32_datadisable(void) * Name: stm32_reset * * Description: - * Reset the MMC/SD controller. Undo all setup and initialization. + * Reset the SDIO controller. Undo all setup and initialization. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * * Returned Value: * None @@ -561,7 +920,7 @@ static void stm32_reset(FAR struct sdio_dev_s *dev) * Name: stm32_status * * Description: - * Get MMC/SD status. + * Get SDIO status. * * Input Parameters: * dev - Device-specific state data @@ -585,7 +944,7 @@ static ubyte stm32_status(FAR struct sdio_dev_s *dev) * correctly in the new bus mode. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * wide - TRUE: wide bus (4-bit) bus mode enabled * * Returned Value: @@ -595,20 +954,18 @@ static ubyte stm32_status(FAR struct sdio_dev_s *dev) static void stm32_widebus(FAR struct sdio_dev_s *dev, boolean wide) { - if (wide) - { - priv->mode = MMCSDMODE_DMA; - } + struct stm32_dev_s *priv = (struct stm32_dev_s *)dev; + priv->widebus = wide; } /**************************************************************************** * Name: stm32_clock * * Description: - * Enable/disable MMC/SD clocking + * Enable/disable SDIO clocking * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * rate - Specifies the clocking to use (see enum sdio_clock_e) * * Returned Value: @@ -627,7 +984,7 @@ static void stm32_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate) * Attach and prepare interrupts * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * * Returned Value: * OK on success; A negated errno on failure. @@ -635,18 +992,44 @@ static void stm32_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate) ****************************************************************************/ static int stm32_attach(FAR struct sdio_dev_s *dev) -{ - return -ENOSYS; +{ + int ret; + + /* Attach the SDIO interrupt handler */ + + ret = irq_attach(STM32_IRQ_SDIO, stm32_interrupt); + if (ret == OK) + { + + /* Disable all interrupts at the SDIO controller and clear static + * interrupt flags + */ + + putreg32(SDIO_MASK_RESET, STM32_SDIO_MASK); + putreg32(SDIO_ICR_STATICFLAGS, STM32_SDIO_ICR); + + /* Enable SDIO interrupts at the NVIC. They can now be enabled at + * the SDIO controller as needed. + */ + + up_enable_irq(STM32_IRQ_SDIO); + + /* Set the interrrupt priority */ + + up_prioritize_irq(STM32_IRQ_SDIO, CONFIG_SDIO_PRI); + } + + return ret; } /**************************************************************************** * Name: stm32_sendcmd * * Description: - * Send the MMC/SD command + * Send the SDIO command * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * cmd - The command to send (32-bits, encoded) * arg - 32-bit argument required with some commands * @@ -703,6 +1086,58 @@ static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg) putreg32(regval, STM32_SDIO_CMD); } +/**************************************************************************** + * Name: stm32_recvsetup + * + * Description: + * Setup hardware in preparation for data trasfer from the card in non-DMA + * (interrupt driven mode). This method will do whatever controller setup + * is necessary. This would be called for SD memory just BEFORE sending + * CMD13 (SEND_STATUS), CMD17 (READ_SINGLE_BLOCK), CMD18 + * (READ_MULTIPLE_BLOCKS), ACMD51 (SEND_SCR), etc. Normally, SDIO_WAITEVENT + * will be called to receive the indication that the transfer is complete. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * buffer - Address of the buffer in which to receive the data + * nbytes - The number of bytes in the transfer + * + * Returned Value: + * Number of bytes sent on success; a negated errno on failure + * + ****************************************************************************/ + +static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, + size_t nbytes) +{ + struct stm32_dev_s *priv = (struct stm32_dev_s *)dev; + uint32 dblocksize; + + DEBUGASSERT(priv != NULL && buffer != NULL && nbytes > 0); + DEBUGASSERT(((uint32)buffer & 3) == 0); + + /* Save the destination buffer information for use by the interrupt handler */ + + priv->buffer = (uint32*)buffer; + priv->remaining = nbytes; + priv->result = -EBUSY; +#ifdef CONFIG_SDIO_DMA + priv->dmamode = FALSE; +#endif + + /* Then set up the SDIO data path */ + + dblocksize = stm32_log2(nbytes) << SDIO_DCTRL_DBLOCKSIZE_SHIFT; + stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, nbytes, dblocksize|SDIO_DCTRL_DTDIR); + + /* And enable interrupts */ + + stm32_enableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE| + SDIO_MASK_DATAENDIE|SDIO_MASK_RXOVERRIE| + SDIO_MASK_RXFIFOHFIE|SDIO_MASK_STBITERRIE); + return OK; +} + /**************************************************************************** * Name: stm32_sendsetup * @@ -713,7 +1148,8 @@ static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg) * (WRITE_MULTIPLE_BLOCK), ... and before SDIO_SENDDATA is called. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface + * buffer - Address of the buffer containing the data to send * nbytes - The number of bytes in the transfer * * Returned Value: @@ -721,33 +1157,37 @@ static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg) * ****************************************************************************/ -static int stm32_sendsetup(FAR struct sdio_dev_s *dev, uint32 nbytes) +static int stm32_sendsetup(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer, + size_t nbytes) { - uint32 dctrl = stm32_log2(nbytes) << SDIO_DCTRL_DBLOCKSIZE_SHIFT); - stm32_dataconfig(SD_DATATIMEOUT, nbytes, dctrl); + struct stm32_dev_s *priv = (struct stm32_dev_s *)dev; + uint32 dblocksize; + + DEBUGASSERT(priv != NULL && buffer != NULL && nbytes > 0); + DEBUGASSERT(((uint32)buffer & 3) == 0); + + /* Save the source buffer information for use by the interrupt handler */ + + priv->buffer = (uint32*)buffer; + priv->remaining = nbytes; + priv->result = -EBUSY; +#ifdef CONFIG_SDIO_DMA + priv->dmamode = FALSE; +#endif + + /* Then set up the SDIO data path */ + + dblocksize = stm32_log2(nbytes) << SDIO_DCTRL_DBLOCKSIZE_SHIFT; + stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, nbytes, dblocksize); + + /* Enable TX interrrupts */ + + stm32_enableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE| + SDIO_MASK_DATAENDIE|SDIO_MASK_TXUNDERRIE| + SDIO_MASK_TXFIFOHEIE|SDIO_MASK_STBITERRIE); return OK; } -/**************************************************************************** - * Name: stm32_senddata - * - * Description: - * Send more MMC/SD data - * - * Input Parameters: - * dev - An instance of the MMC/SD device interface - * data - Data to be sent - * - * Returned Value: - * Number of bytes sent on success; a negated errno on failure - * - ****************************************************************************/ - -static int stm32_senddata(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer) -{ - return -ENOSYS; -} - /**************************************************************************** * Name: stm32_waitresponse * @@ -755,7 +1195,7 @@ static int stm32_senddata(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer) * Poll-wait for the response to the last command to be ready. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * cmd - The command that was sent. See 32-bit command definitions above. * * Returned Value: @@ -763,7 +1203,7 @@ static int stm32_senddata(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer) * ****************************************************************************/ -static int stm32_waitresponseFAR struct sdio_dev_s *dev, uint32 cmd) +static int stm32_waitresponse(FAR struct sdio_dev_s *dev, uint32 cmd) { sint32 timeout = SDIO_LONGTIMEOUT; uint32 events; @@ -817,13 +1257,13 @@ static int stm32_waitresponseFAR struct sdio_dev_s *dev, uint32 cmd) * Name: stm32_recvRx * * Description: - * Receive response to MMC/SD command. Only the critical payload is + * Receive response to SDIO command. Only the critical payload is * returned -- that is 32 bits for 48 bit status and 128 bits for 136 bit * status. The driver implementation should verify the correctness of * the remaining, non-returned bits (CRCs, CMD index, etc.). * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * Rx - Buffer in which to receive the response * * Returned Value: @@ -876,7 +1316,7 @@ static int stm32_recvshortcrc(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rs if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1_RESPONSE && (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1B_RESPONSE && - cmd & MMCSD_RESPONSE_MASK |= MMCSD_R6_RESPONSE) + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R6_RESPONSE) { fdbg("ERROR: Wrong response CMD=%08x\n", cmd); return -EINVAL; @@ -994,7 +1434,7 @@ static int stm32_recvshort(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rshor #ifdef CONFIG_DEBUG if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R3_RESPONSE && - cmd & MMCSD_RESPONSE_MASK |= MMCSD_R7_RESPONSE) + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R7_RESPONSE) { fdbg("ERROR: Wrong response CMD=%08x\n", cmd); return -EINVAL; @@ -1030,57 +1470,11 @@ static int stm32_recvnotimpl(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rno return -ENOSYS; } -/**************************************************************************** - * Name: stm32_recvsetup - * - * Description: - * Setup hardware in preparation for data trasfer from the card. This method - * will do whatever controller setup is necessary. This would be called - * for SD memory just BEFORE sending CMD13 (SEND_STATUS), CMD17 - * (READ_SINGLE_BLOCK), CMD18 (READ_MULTIPLE_BLOCKS), ACMD51 (SEND_SCR), ... - * and before SDIO_RECVDATA is called. - * - * Input Parameters: - * dev - An instance of the MMC/SD device interface - * nbytes - The number of bytes in the transfer - * - * Returned Value: - * Number of bytes sent on success; a negated errno on failure - * - ****************************************************************************/ - -static int stm32_recvsetup(FAR struct sdio_dev_s *dev, uint32 nbytes) -{ - uint32 dctrl = (stm32_log2(nbytes) << SDIO_DCTRL_DBLOCKSIZE_SHIFT)) | SDIO_DCTRL_DTDIR; - stm32_dataconfig(SD_DATATIMEOUT, nbytes, dctrl); - return OK; -} - -/**************************************************************************** - * Name: stm32_recvdata - * - * Description: - * Receive data from MMC/SD - * - * Input Parameters: - * dev - An instance of the MMC/SD device interface - * buffer - Buffer in which to receive the data - * - * Returned Value: - * Number of bytes sent on success; a negated errno on failure - * - ****************************************************************************/ - -static int stm32_recvdata(FAR struct sdio_dev_s *dev, FAR ubyte *buffer) -{ - return -ENOSYS; -} - /**************************************************************************** * Name: stm32_waitenable * * Description: - * Enable/disable of a set of MMC/SD wait events. This is part of the + * Enable/disable of a set of SDIO wait events. This is part of the * the SDIO_WAITEVENT sequence. The set of to-be-waited-for events is * configured before calling stm32_waitevent. This is done in this way * to help the driver to eliminate race conditions between the command @@ -1091,7 +1485,7 @@ static int stm32_recvdata(FAR struct sdio_dev_s *dev, FAR ubyte *buffer) * returns. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * eventset - A bitset of events to enable or disable (see SDIOWAIT_* * definitions). 0=disable; 1=enable. * @@ -1100,7 +1494,8 @@ static int stm32_recvdata(FAR struct sdio_dev_s *dev, FAR ubyte *buffer) * ****************************************************************************/ -static void stm32_waitenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset) +static void stm32_waitenable(FAR struct sdio_dev_s *dev, + sdio_eventset_t eventset) { struct stm32_dev_s *priv = (struct stm32_dev_s*)dev; @@ -1108,7 +1503,7 @@ static void stm32_waitenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset) DEBUGASSERT(priv != NULL); priv->waitevents = 0; - priv->wkupevents = 0; + priv->wkupevent = 0; priv->waitevents = eventset; } @@ -1122,7 +1517,7 @@ static void stm32_waitenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset) * can be used again. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * timeout - Maximum time in milliseconds to wait. Zero means no timeout. * * Returned Value: @@ -1134,7 +1529,8 @@ static void stm32_waitenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset) static ubyte stm32_eventwait(FAR struct sdio_dev_s *dev, uint32 timeout) { - ubyte wkupevents = 0; + struct stm32_dev_s *priv = (struct stm32_dev_s*)dev; + ubyte wkupevent = 0; DEBUGASSERT(priv->waitevents != 0); @@ -1155,10 +1551,10 @@ static ubyte stm32_eventwait(FAR struct sdio_dev_s *dev, uint32 timeout) /* Check if the event has occurred. */ - wkupevents = (ubyte)(priv->wkupevents & priv->waitevents) - if (wkupevents != 0) + wkupevent = (ubyte)(priv->wkupevent & priv->waitevents); + if (wkupevent != 0) { - /* Yes... break out of the loop with wkupevents non-zero */ + /* Yes... break out of the loop with wkupevent non-zero */ break; } @@ -1167,19 +1563,19 @@ static ubyte stm32_eventwait(FAR struct sdio_dev_s *dev, uint32 timeout) /* Clear all enabled wait events before returning */ priv->waitevents = 0; - priv->wkupevents = 0; - return wkupevents; + priv->wkupevent = 0; + return wkupevent; } /**************************************************************************** * Name: stm32_events * * Description: - * Return the current event set. This supports polling for MMC/SD (vs. + * Return the current event set. This supports polling for SDIO (vs. * waiting). Only enabled events need be reported. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * * Returned Value: * Event set containing the current events (All pending events are cleared @@ -1196,7 +1592,7 @@ static ubyte stm32_events(FAR struct sdio_dev_s *dev) * Name: stm32_callbackenable * * Description: - * Enable/disable of a set of MMC/SD callback events. This is part of the + * Enable/disable of a set of SDIO callback events. This is part of the * the SDIO callback sequence. The set of events is configured to enabled * callbacks to the function provided in stm32_registercallback. * @@ -1205,7 +1601,7 @@ static ubyte stm32_events(FAR struct sdio_dev_s *dev) * calling this methos. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * eventset - A bitset of events to enable or disable (see SDIOMEDIA_* * definitions). 0=disable; 1=enable. * @@ -1214,7 +1610,8 @@ static ubyte stm32_events(FAR struct sdio_dev_s *dev) * ****************************************************************************/ -static void stm32_callbackenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset) +static void stm32_callbackenable(FAR struct sdio_dev_s *dev, + sdio_eventset_t eventset) { struct stm32_dev_s *priv = (struct stm32_dev_s*)dev; DEBUGASSERT(priv != NULL); @@ -1265,7 +1662,7 @@ static int stm32_registercallback(FAR struct sdio_dev_s *dev, * Return TRUE if the hardware can support DMA * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * * Returned Value: * TRUE if DMA is supported. @@ -1280,7 +1677,7 @@ static boolean stm32_dmasupported(FAR struct sdio_dev_s *dev) #endif /**************************************************************************** - * Name: stm32_dmareadsetup + * Name: stm32_dmarecvsetup * * Description: * Setup to perform a read DMA. If the processor supports a data cache, @@ -1289,7 +1686,7 @@ static boolean stm32_dmasupported(FAR struct sdio_dev_s *dev) * invalidating the data cache. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * buffer - The memory to DMA from * buflen - The size of the DMA transfer in bytes * @@ -1299,20 +1696,49 @@ static boolean stm32_dmasupported(FAR struct sdio_dev_s *dev) ****************************************************************************/ #ifdef CONFIG_SDIO_DMA -static int tm32_dmareadsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, size_t buflen) +static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, + size_t buflen) { - /* Configure the RX DMA */ + struct stm32_dev_s *priv = (struct stm32_dev_s *)dev; + uint32 dblocksize; + int ret = -EINVAL; + + DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); + DEBUGASSERT(((uint32)buffer & 3) == 0); - stm32_enableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE|SDIO_MASK_DATAENDIE| - SDIO_MASK_RXOVERRIE|SDIO_MASK_STBITERRIE); - putreg32(1, SDIO_DCTRL_DMAEN_BB) - stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer, - (buflen + 3) >> 2, SDIO_RXDMA16_CONFIG); + /* Wide bus operation is required for DMA */ + + if (priv->widebus) + { + /* Save the destination buffer information for use by the interrupt handler */ + + priv->buffer = (uint32*)buffer; + priv->remaining = buflen; + priv->result = -EBUSY; + priv->dmamode = TRUE; + + /* 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); + + /* Configure the RX DMA */ + + stm32_enableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE| + SDIO_MASK_DATAENDIE|SDIO_MASK_RXOVERRIE| + SDIO_MASK_STBITERRIE); + + putreg32(1, SDIO_DCTRL_DMAEN_BB); + stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer, + (buflen + 3) >> 2, SDIO_RXDMA16_CONFIG); + ret = OK; + } + return ret; } #endif /**************************************************************************** - * Name: stm32_dmawritesetup + * Name: stm32_dmasendsetup * * Description: * Setup to perform a write DMA. If the processor supports a data cache, @@ -1321,7 +1747,7 @@ static int tm32_dmareadsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, siz * flushing the data cache. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * buffer - The memory to DMA into * buflen - The size of the DMA transfer in bytes * @@ -1331,27 +1757,57 @@ static int tm32_dmareadsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, siz ****************************************************************************/ #ifdef CONFIG_SDIO_DMA -static int stm32_dmawritesetup(FAR struct sdio_dev_s *dev, +static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer, size_t buflen) { - /* Configure the TX DMA */ + struct stm32_dev_s *priv = (struct stm32_dev_s *)dev; + uint32 dblocksize; + int ret = -EINVAL; + + DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); + DEBUGASSERT(((uint32)buffer & 3) == 0); + + /* Wide bus operation is required for DMA */ - stm32_enableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE|SDIO_MASK_DATAENDIE| - SDIO_MASK_TXUNDERRIE|SDIO_MASK_STBITERRIE); - stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer, - (buflen + 3) >> 2, SDIO_TXDMA16_CONFIG); - putreg32(1, SDIO_DCTRL_DMAEN_BB) + if (priv->widebus) + { + /* Save the source buffer information for use by the interrupt handler */ + + priv->buffer = (uint32*)buffer; + priv->remaining = buflen; + priv->result = -EBUSY; + priv->dmamode = TRUE; + + /* Then set up the SDIO data path */ + + dblocksize = stm32_log2(buflen) << SDIO_DCTRL_DBLOCKSIZE_SHIFT; + stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, buflen, dblocksize); + + /* Enable TX interrrupts */ + + stm32_enableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE| + SDIO_MASK_DATAENDIE|SDIO_MASK_TXUNDERRIE| + SDIO_MASK_STBITERRIE); + + /* Configure the TX DMA */ + + stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer, + (buflen + 3) >> 2, SDIO_TXDMA16_CONFIG); + putreg32(1, SDIO_DCTRL_DMAEN_BB); + ret = OK; + } + return ret; } #endif /**************************************************************************** - * Name: stm32_dmastart + * Name: stm32_sdiodmastart * * Description: * Start the DMA * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * * Returned Value: * OK on success; a negated errno on failure @@ -1359,42 +1815,11 @@ static int stm32_dmawritesetup(FAR struct sdio_dev_s *dev, ****************************************************************************/ #ifdef CONFIG_SDIO_DMA -static int stm32_dmastart(FAR struct sdio_dev_s *dev) +static int stm32_sdiodmastart(FAR struct sdio_dev_s *dev) { - stm32_dmastart(priv->dma, sdio_dmacallback, priv, FALSE); -} -#endif - -/**************************************************************************** - * Name: stm32_dmastatus - * - * Description: - * Return the number of bytes remaining in the DMA transfer - * - * Input Parameters: - * dev - An instance of the MMC/SD device interface - * remaining - A pointer to location in which to return the number of bytes - * remaining in the transfer. - * - * Returned Value: - * OK on success; a negated errno on failure - * - ****************************************************************************/ - -#ifdef CONFIG_SDIO_DMA -static int stm32_dmastatus(FAR struct sdio_dev_s *dev, size_t *remaining) -{ -#ifdef CONFIG_DEBUG - if (remaining) - { - *remaining = getreg32(STM32_SDIO_DCOUNT); - return OK; - } - return -EINVAL; -#else - *remaining = getreg32(STM32_SDIO_DCOUNT); - return OK; -#endif + struct stm32_dev_s *priv = (struct stm32_dev_s *)dev; + stm32_dmastart(priv->dma, stm32_dmacallback, priv, FALSE); + return OK; } #endif @@ -1497,7 +1922,7 @@ static void stm32_default(void) * ****************************************************************************/ -FAR sdio_dev_s *mmcsd_slotinitialize(int slotno) +FAR struct sdio_dev_s *sdio_initialize(int slotno) { /* There is only one, slot */ @@ -1505,7 +1930,7 @@ FAR sdio_dev_s *mmcsd_slotinitialize(int slotno) /* Initialize the SDIO slot structure */ - sem_init(&priv->eventsem, 0, 0); + sem_init(&priv->waitsem, 0, 0); /* Allocate a DMA channel */ @@ -1532,7 +1957,7 @@ FAR sdio_dev_s *mmcsd_slotinitialize(int slotno) stm32_setclkcr(STM32_CLCKCR_INIT); stm32_setpwrctrl(SDIO_POWER_PWRCTRL_ON); - stm32_clkenable(ENABLE); + stm32_clkenable(); return &g_sdiodev.dev; } diff --git a/arch/arm/src/stm32/stm32_sdio.h b/arch/arm/src/stm32/stm32_sdio.h index d276be8cff04567f3c860e17c649b5b91f6164cd..977b428d5d669c70e68513d06cdaa07a92014e5d 100755 --- a/arch/arm/src/stm32/stm32_sdio.h +++ b/arch/arm/src/stm32/stm32_sdio.h @@ -224,8 +224,8 @@ #define SDIO_DATACOUNT_SHIFT (0) #define SDIO_DATACOUNT_MASK (0x01ffffff << SDIO_DATACOUNT_SHIFT) -#define SDIO_STA_CCRCFAIL (1 << 0) /* Bit 0: Command response received (CRC fail) */ -#define SDIO_STA_DCRCFAIL (1 << 1) /* Bit 1: Data block sent/received */ +#define SDIO_STA_CCRCFAIL (1 << 0) /* Bit 0: Command response CRC fail */ +#define SDIO_STA_DCRCFAIL (1 << 1) /* Bit 1: Data block CRC fail */ #define SDIO_STA_CTIMEOUT (1 << 2) /* Bit 2: Command response timeout */ #define SDIO_STA_DTIMEOUT (1 << 3) /* Bit 3: Data timeout */ #define SDIO_STA_TXUNDERR (1 << 4) /* Bit 4: Transmit FIFO underrun error */ diff --git a/drivers/mmcsd/mmcsd_sdio.c b/drivers/mmcsd/mmcsd_sdio.c index 76663c8c5b6cf3cbff567ac5ff932605246bb1a9..cd32e1dae579d7e6e2db2a63a8f4e88ef5477e4c 100644 --- a/drivers/mmcsd/mmcsd_sdio.c +++ b/drivers/mmcsd/mmcsd_sdio.c @@ -366,9 +366,9 @@ static int mmcsd_getSCR(struct mmcsd_state_s *priv, uint32 scr[2]) return ret; } - /* Setup up to receive data */ + /* Setup up to receive data with interrupt mode */ - SDIO_RECVSETUP(priv->dev, 8); + SDIO_RECVSETUP(priv->dev, (FAR ubyte*)scr, 8); /* Send ACMD51 SD_APP_SEND_SCR with argument as 0 to start data receipt */ @@ -381,21 +381,14 @@ static int mmcsd_getSCR(struct mmcsd_state_s *priv, uint32 scr[2]) return ret; } - /* Wait for data available */ + /* Wait for data to be transferred */ ret = SDIO_EVENTWAIT(priv->dev, MMCSD_SCR_DATADELAY); if (ret != OK) { fdbg("ERROR: WAITEVENT for READ DATA failed: %d\n", ret); - return ret; } - - /* Receive the SCR data from the SD card. Card data is sent big-endian; - * if we are running on a little-endian machine, then we need to swap - * some bytes (should this be a configuration option?) - */ - - return SDIO_RECVDATA(priv->dev, (FAR ubyte *)scr); + return ret; } /**************************************************************************** diff --git a/include/nuttx/sdio.h b/include/nuttx/sdio.h index cf347058578a35a8000b8719580d71de6dc57ace..490128180ad119e61c5dfddee9634ee56ae70e28 100755 --- a/include/nuttx/sdio.h +++ b/include/nuttx/sdio.h @@ -47,7 +47,7 @@ * Pre-Processor Definitions ****************************************************************************/ -/* MMC/SD events needed by the driver +/* SDIO events needed by the driver * * Wait events are used for event-waiting by SDIO_WAITENABLE and SDIO_EVENTWAIT */ @@ -290,10 +290,10 @@ * Name: SDIO_RESET * * Description: - * Reset the MMC/SD controller. Undo all setup and initialization. + * Reset the SDIO controller. Undo all setup and initialization. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * * Returned Value: * None @@ -306,7 +306,7 @@ * Name: SDIO_STATUS * * Description: - * Get MMC/SD status. + * Get SDIO status. * * Input Parameters: * dev - Device-specific state data @@ -318,10 +318,10 @@ #define SDIO_STATUS(dev) ((dev)->status(dev)) -/* MMC/SD status bits */ +/* SDIO status bits */ -#define SDIO_STATUS_PRESENT 0x01 /* Bit 0=1: MMC/SD card present */ -#define SDIO_STATUS_WRPROTECTED 0x02 /* Bit 1=1: MMC/SD card write protected */ +#define SDIO_STATUS_PRESENT 0x01 /* Bit 0=1: SDIO card present */ +#define SDIO_STATUS_WRPROTECTED 0x02 /* Bit 1=1: SDIO card write protected */ #define SDIO_PRESENT(dev) ((SDIO_STATUS(dev) & SDIO_STATUS_PRESENT) != 0) #define SDIO_WRPROTECTED(dev) ((SDIO_STATUS(dev) & SDIO_STATUS_WRPROTECTED) != 0) @@ -335,7 +335,7 @@ * correctly in the new bus mode. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * wide - TRUE: wide bus (4-bit) bus mode enabled * * Returned Value: @@ -349,10 +349,10 @@ * Name: SDIO_CLOCK * * Description: - * Enable/disable MMC/SD clocking + * Enable/disable SDIO clocking * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * rate - Specifies the clocking to use (see enum sdio_clock_e) * * Returned Value: @@ -369,7 +369,7 @@ * Attach and prepare interrupts * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * * Returned Value: * OK on success; A negated errno on failure. @@ -382,10 +382,10 @@ * Name: SDIO_SENDCMD * * Description: - * Send the MMC/SD command + * Send the SDIO command * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * cmd - The command to send. See 32-bit command definitions above. * arg - 32-bit argument required with some commands * data - A reference to data required with some commands @@ -398,16 +398,19 @@ #define SDIO_SENDCMD(dev,cmd,arg) ((dev)->sendcmd(dev,cmd,arg)) /**************************************************************************** - * Name: SDIO_SENDSETUP + * Name: SDIO_RECVSETUP * * Description: - * Setup hardware in preparation for data trasfer from the card. This method - * will do whatever controller setup is necessary. This would be called - * for SD memory just AFTER sending CMD24 (WRITE_BLOCK), CMD25 - * (WRITE_MULTIPLE_BLOCK), ... and before SDIO_SENDDATA is called. + * Setup hardware in preparation for data trasfer from the card in non-DMA + * (interrupt driven mode). This method will do whatever controller setup + * is necessary. This would be called for SD memory just BEFORE sending + * CMD13 (SEND_STATUS), CMD17 (READ_SINGLE_BLOCK), CMD18 + * (READ_MULTIPLE_BLOCKS), ACMD51 (SEND_SCR), etc. Normally, SDIO_WAITEVENT + * will be called to receive the indication that the transfer is complete. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface + * buffer - Address of the buffer in which to receive the data * nbytes - The number of bytes in the transfer * * Returned Value: @@ -415,24 +418,28 @@ * ****************************************************************************/ -#define SDIO_SENDSETUP(dev,nbytes) ((dev)->sendsetup(dev,nbytes)) +#define SDIO_RECVSETUP(dev,buffer,nbytes) ((dev)->recvsetup(dev,buffer,nbytes)) /**************************************************************************** - * Name: SDIO_SENDDATA + * Name: SDIO_SENDSETUP * * Description: - * Send more MMC/SD data + * Setup hardware in preparation for data trasfer from the card. This method + * will do whatever controller setup is necessary. This would be called + * for SD memory just AFTER sending CMD24 (WRITE_BLOCK), CMD25 + * (WRITE_MULTIPLE_BLOCK), ... and before SDIO_SENDDATA is called. * * Input Parameters: - * dev - An instance of the MMC/SD device interface - * data - Data to be sent + * dev - An instance of the SDIO device interface + * buffer - Address of the buffer containing the data to send + * nbytes - The number of bytes in the transfer * * Returned Value: * Number of bytes sent on success; a negated errno on failure * ****************************************************************************/ -#define SDIO_SENDDATA(dev,data) ((dev)->senddata(dev,data)) +#define SDIO_SENDSETUP(dev,buffer,nbytes) ((dev)->sendsetup(dev,buffer,nbytes)) /**************************************************************************** * Name: SDIO_WAITRESPONSE @@ -441,7 +448,7 @@ * Poll-wait for the response to the last command to be ready. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * cmd - The command that was sent. See 32-bit command definitions above. * * Returned Value: @@ -455,13 +462,13 @@ * Name: SDIO_RECVRx * * Description: - * Receive response to MMC/SD command. Only the critical payload is + * Receive response to SDIO command. Only the critical payload is * returned -- that is 32 bits for 48 bit status and 128 bits for 136 bit * status. The driver implementation should verify the correctness of * the remaining, non-returned bits (CRCs, CMD index, etc.). * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * Rx - Buffer in which to receive the response * * Returned Value: @@ -481,49 +488,11 @@ #define SDIO_RECVR6(dev,cmd,R6) ((dev)->recvR6(dev,cmd,R6)) /* 48-bit */ #define SDIO_RECVR7(dev,cmd,R7) ((dev)->recvR7(dev,cmd,R7)) /* 48-bit */ -/**************************************************************************** - * Name: SDIO_RECVSETUP - * - * Description: - * Setup hardware in preparation for data trasfer from the card. This method - * will do whatever controller setup is necessary. This would be called - * for SD memory just BEFORE sending CMD13 (SEND_STATUS), CMD17 - * (READ_SINGLE_BLOCK), CMD18 (READ_MULTIPLE_BLOCKS), ACMD51 (SEND_SCR), ... - * and before SDIO_RECVDATA is called. - * - * Input Parameters: - * dev - An instance of the MMC/SD device interface - * nbytes - The number of bytes in the transfer - * - * Returned Value: - * Number of bytes sent on success; a negated errno on failure - * - ****************************************************************************/ - -#define SDIO_RECVSETUP(dev,nbytes) ((dev)->recvsetup(dev,nbytes)) - -/**************************************************************************** - * Name: SDIO_RECVDATA - * - * Description: - * Receive data from MMC/SD - * - * Input Parameters: - * dev - An instance of the MMC/SD device interface - * buffer - Buffer in which to receive the data - * - * Returned Value: - * Number of bytes sent on success; a negated errno on failure - * - ****************************************************************************/ - -#define SDIO_RECVDATA(dev,buffer) ((dev)->recvdata(dev,buffer)) - /**************************************************************************** * Name: SDIO_WAITENABLE * * Description: - * Enable/disable of a set of MMC/SD wait events. This is part of the + * Enable/disable of a set of SDIO wait events. This is part of the * the SDIO_WAITEVENT sequence. The set of to-be-waited-for events is * configured before calling SDIO_EVENTWAIT. This is done in this way * to help the driver to eliminate race conditions between the command @@ -534,7 +503,7 @@ * returns. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * eventset - A bitset of events to enable or disable (see SDIOWAIT_* * definitions). 0=disable; 1=enable. * @@ -555,7 +524,7 @@ * can be used again. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * timeout - Maximum time in milliseconds to wait. Zero means no timeout. * * Returned Value: @@ -571,11 +540,11 @@ * Name: SDIO_EVENTS * * Description: - * Return the current event set. This supports polling for MMC/SD (vs. + * Return the current event set. This supports polling for SDIO (vs. * waiting). Only enabled events need be reported. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * * Returned Value: * Event set containing the current events (All pending events are cleared @@ -589,7 +558,7 @@ * Name: SDIO_CALLBACKENABLE * * Description: - * Enable/disable of a set of MMC/SD callback events. This is part of the + * Enable/disable of a set of SDIO callback events. This is part of the * the SDIO callback sequence. The set of events is configured to enabled * callbacks to the function provided in SDIO_REGISTERCALLBACK. * @@ -598,7 +567,7 @@ * calling this methos. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * eventset - A bitset of events to enable or disable (see SDIOMEDIA_* * definitions). 0=disable; 1=enable. * @@ -640,7 +609,7 @@ * Return TRUE if the hardware can support DMA * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * * Returned Value: * TRUE if DMA is supported. @@ -654,7 +623,7 @@ #endif /**************************************************************************** - * Name: SDIO_DMAREADSETUP + * Name: SDIO_DMARECVSETUP * * Description: * Setup to perform a read DMA. If the processor supports a data cache, @@ -663,7 +632,7 @@ * invalidating the data cache. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * buffer - The memory to DMA from * buflen - The size of the DMA transfer in bytes * @@ -673,13 +642,13 @@ ****************************************************************************/ #ifdef CONFIG_SDIO_DMA -# define SDIO_DMAREADSETUP(dev,buffer,len) ((dev)->dmareadsetup(dev,buffer,len)) +# define SDIO_DMARECVSETUP(dev,buffer,len) ((dev)->dmarecvsetup(dev,buffer,len)) #else -# define SDIO_DMAREADSETUP(dev,buffer,len) (-ENOSYS) +# define SDIO_DMARECVSETUP(dev,buffer,len) (-ENOSYS) #endif /**************************************************************************** - * Name: SDIO_DMAWRITESETUP + * Name: SDIO_DMASENDSETUP * * Description: * Setup to perform a write DMA. If the processor supports a data cache, @@ -688,7 +657,7 @@ * flushing the data cache. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * buffer - The memory to DMA into * buflen - The size of the DMA transfer in bytes * @@ -698,9 +667,9 @@ ****************************************************************************/ #ifdef CONFIG_SDIO_DMA -# define SDIO_DMAWRITESETUP(dev,buffer,len) ((dev)->dmawritesetup(dev,buffer,len)) +# define SDIO_DMASENDSETUP(dev,buffer,len) ((dev)->dmasendsetup(dev,buffer,len)) #else -# define SDIO_DMAWRITESETUP(dev,buffer,len) (-ENOSYS) +# define SDIO_DMASENDSETUP(dev,buffer,len) (-ENOSYS) #endif /**************************************************************************** @@ -710,7 +679,7 @@ * Start the DMA * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the SDIO device interface * * Returned Value: * OK on success; a negated errno on failure @@ -723,28 +692,6 @@ # define SDIO_DMASTART(dev) (-ENOSYS) #endif -/**************************************************************************** - * Name: SDIO_DMASTATUS - * - * Description: - * Return the number of bytes remaining in the DMA transfer - * - * Input Parameters: - * dev - An instance of the MMC/SD device interface - * remaining - A pointer to location in which to return the number of bytes - * remaining in the transfer. - * - * Returned Value: - * OK on success; a negated errno on failure - * - ****************************************************************************/ - -#ifdef CONFIG_SDIO_DMA -# define SDIO_DMASTATUS(dev,remaining) ((dev)->dmastatus(dev,remaining)) -#else -# define SDIO_DMASTATUS(dev,remaining) (-ENOSYS) -#endif - /**************************************************************************** * Public Types ****************************************************************************/ @@ -753,7 +700,7 @@ typedef void (*sdio_mediachange_t)(FAR void *arg); -/* Various clocking used by the MMC/SD driver */ +/* Various clocking used by the SDIO driver */ enum sdio_clock_e { @@ -770,11 +717,11 @@ enum sdio_clock_e typedef ubyte sdio_eventset_t; -/* This structure defines the interface between the NuttX MMC/SD - * driver and the chip- or board-specific MMC/SD interface. This +/* This structure defines the interface between the NuttX SDIO + * driver and the chip- or board-specific SDIO interface. This * interface is only used in architectures that support SDIO - * 1- or 4-bit data busses. For MMC/SD support this interface is - * registered with the NuttX MMC/SD driver by calling + * 1- or 4-bit data busses. For SDIO support this interface is + * registered with the NuttX SDIO driver by calling * sdio_slotinitialize(). */ @@ -795,8 +742,10 @@ struct sdio_dev_s /* Command/Status/Data Transfer */ void (*sendcmd)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg); - int (*sendsetup)(FAR struct sdio_dev_s *dev, uint32 nbytes); - int (*senddata)(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer); + int (*recvsetup)(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, + size_t nbytes); + int (*sendsetup)(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer, + size_t nbytes); int (*waitresponse)(FAR struct sdio_dev_s *dev, uint32 cmd); int (*recvR1)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *R1); @@ -806,26 +755,24 @@ struct sdio_dev_s int (*recvR5)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *R5); int (*recvR6)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *R6); int (*recvR7)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *R7); - int (*recvsetup)(FAR struct sdio_dev_s *dev, uint32 nbytes); - int (*recvdata)(FAR struct sdio_dev_s *dev, FAR ubyte *buffer); /* EVENT handler */ void (*waitenable)(FAR struct sdio_dev_s *dev, sdio_eventset_t eventset); ubyte (*eventwait)(FAR struct sdio_dev_s *dev, uint32 timeout); ubyte (*events)(FAR struct sdio_dev_s *dev); + void (*callbackenable)(FAR struct sdio_dev_s *dev, sdio_eventset_t eventset); int (*registercallback)(FAR struct sdio_dev_s *dev, sdio_mediachange_t callback, void *arg); /* DMA */ #ifdef CONFIG_SDIO_DMA boolean (*dmasupported)(FAR struct sdio_dev_s *dev); - int (*dmareadsetup)(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, + int (*dmarecvsetup)(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, size_t buflen); - int (*dmawritesetup)(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer, + int (*dmasendsetup)(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer, size_t buflen); int (*dmastart)(FAR struct sdio_dev_s *dev); - int (*dmastatus)(FAR struct sdio_dev_s *dev, size_t *remaining); #endif };