diff --git a/arch/arm/src/stm32/stm32_sdio.c b/arch/arm/src/stm32/stm32_sdio.c index 102127e57d..a7fe28c7d4 100644 --- a/arch/arm/src/stm32/stm32_sdio.c +++ b/arch/arm/src/stm32/stm32_sdio.c @@ -123,6 +123,7 @@ static inline void stm32_dmaenable(void); /* Data Transfer Helpers ****************************************************/ +static ubyte stm32_log2(uint16 value); static void stm32_dataconfig(uint32 timeout, uint32 dlen, uint32 dctrl); static void stm32_datadisable(void); @@ -135,13 +136,12 @@ static ubyte stm32_status(FAR struct sdio_dev_s *dev); static void stm32_widebus(FAR struct sdio_dev_s *dev, boolean enable); static void stm32_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate); -static int stm32_setblocklen(FAR struct sdio_dev_s *dev, int blocklen, - int nblocks); 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 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); @@ -150,11 +150,12 @@ static int stm32_recvshortcrc(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 * 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); /* EVENT handler */ -static void stm32_eventenable(FAR struct sdio_dev_s *dev, ubyte eventset, +static void stm32_eventenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset, boolean enable); static ubyte stm32_eventwait(FAR struct sdio_dev_s *dev, uint32 timeout); static ubyte stm32_events(FAR struct sdio_dev_s *dev); @@ -194,9 +195,9 @@ struct stm32_dev_s g_mmcsd = .status = stm32_status, .widebus = stm32_widebus, .clock = stm32_clock, - .setblocklen = stm32_setblocklen, .attach = stm32_attach, - .sendcmd = stm32_sendcmd, + .sendcmd = stm32_sendcmd, + .sendsetup = stm32_sendsetup, .senddata = stm32_senddata, .waitresponse = stm32_waitresponse, .recvR1 = stm32_recvshortcrc, @@ -205,7 +206,8 @@ struct stm32_dev_s g_mmcsd = .recvR4 = stm32_recvnotimpl, .recvR5 = stm32_recvnotimpl, .recvR6 = stm32_recvshortcrc, - .recvR7 = stm32_recvshort, + .recvR7 = stm32_recvshort, + .recvsetup = stm32_recvsetup, .recvdata = stm32_recvdata, .eventenable = stm32_eventenable, .eventwait = stm32_eventwait, @@ -378,6 +380,37 @@ static inline void stm32_dmaenable(void) /**************************************************************************** * Data Transfer Helpers ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_log2 + * + * Description: + * Take (approximate) log base 2 of the provided number (Only works if the + * provided number is a power of 2). + * + ****************************************************************************/ + +static ubyte stm32_log2(uint16 value) +{ + ubyte log2 = 0; + + /* 0000 0000 0000 0001 -> return 0, + * 0000 0000 0000 001x -> return 1, + * 0000 0000 0000 01xx -> return 2, + * 0000 0000 0000 1xxx -> return 3, + * ... + * 1xxx xxxx xxxx xxxx -> return 15, + */ + + DEBUGASSERT(value > 0); + while (value != 1) + { + value >>= 1; + log2++; + } + return log2; +} + /**************************************************************************** * Name: stm32_dataconfig * @@ -490,7 +523,11 @@ 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; + } } /**************************************************************************** @@ -512,27 +549,6 @@ static void stm32_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate) { } -/**************************************************************************** - * Name: stm32_setblocklen - * - * Description: - * Set the MMC/SD block length and block count - * - * Input Parameters: - * dev - An instance of the MMC/SD device interface - * blocklen - The block length - * nblocks - The block count - * - * Returned Value: - * OK on success; negated errno on failure - * - ****************************************************************************/ - -static int stm32_setblocklen(FAR struct sdio_dev_s *dev, int blocklen, int nblocks) -{ - return -ENOSYS; -} - /**************************************************************************** * Name: stm32_attach * @@ -616,6 +632,31 @@ static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg) putreg32(regval, STM32_SDIO_CMD); } +/**************************************************************************** + * Name: stm32_sendsetup + * + * 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. + * + * 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_sendsetup(FAR struct sdio_dev_s *dev, uint32 nbytes) +{ + uint32 dctrl = stm32_log2(nbytes) << SDIO_DCTRL_DBLOCKSIZE_SHIFT); + stm32_dataconfig(SD_DATATIMEOUT, nbytes, dctrl); + return OK; +} + /**************************************************************************** * Name: stm32_senddata * @@ -627,7 +668,7 @@ static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg) * data - Data to be sent * * Returned Value: - * Number of bytes sent on succes; a negated errno on failure + * Number of bytes sent on success; a negated errno on failure * ****************************************************************************/ @@ -918,6 +959,32 @@ 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 * @@ -929,7 +996,7 @@ static int stm32_recvnotimpl(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rno * buffer - Buffer in which to receive the data * * Returned Value: - * Number of bytes sent on succes; a negated errno on failure + * Number of bytes sent on success; a negated errno on failure * ****************************************************************************/ @@ -947,16 +1014,14 @@ static int stm32_recvdata(FAR struct sdio_dev_s *dev, FAR ubyte *buffer) * Input Parameters: * dev - An instance of the MMC/SD device interface * eventset - A bitset of events to enable or disable (see MMCSDEVENT_* - * definitions - * enable - TRUE: enable event; FALSE: disable events + * definitions). 0=disable; 1=enable. * * Returned Value: * None * ****************************************************************************/ -static void stm32_eventenable(FAR struct sdio_dev_s *dev, ubyte eventset, - boolean enable) +static void stm32_eventenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset) { } @@ -972,7 +1037,8 @@ static void stm32_eventenable(FAR struct sdio_dev_s *dev, ubyte eventset, * * Returned Value: * Event set containing the event(s) that ended the wait. If no events the - * returned event set is zero, then the wait was terminated by the timeout. + * returned event set is zero, then the wait was terminated by the timeout. + * All events are cleared disabled after the wait concludes. * ****************************************************************************/ @@ -986,13 +1052,14 @@ static ubyte stm32_eventwait(FAR struct sdio_dev_s *dev, uint32 timeout) * * Description: * Return the current event set. This supports polling for MMC/SD (vs. - * waiting). + * waiting). Only enabled events need be reported. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the MMC/SD device interface * * Returned Value: - * Event set containing the current events (cleared after reading). + * Event set containing the current events (All pending events are cleared + * after reading). * ****************************************************************************/ @@ -1062,7 +1129,7 @@ static void stm32_coherent(FAR struct sdio_dev_s *dev, FAR void *addr, * buffer - The memory to DMA from * * Returned Value: - * OK on succes; a negated errno on failure + * OK on success; a negated errno on failure * ****************************************************************************/ @@ -1084,7 +1151,7 @@ static int tm32_dmareadsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer) * buffer - The memory to DMA into * * Returned Value: - * OK on succes; a negated errno on failure + * OK on success; a negated errno on failure * ****************************************************************************/ @@ -1106,7 +1173,7 @@ static int stm32_dmawritesetup(FAR struct sdio_dev_s *dev, * dev - An instance of the MMC/SD device interface * * Returned Value: - * OK on succes; a negated errno on failure + * OK on success; a negated errno on failure * ****************************************************************************/ @@ -1127,7 +1194,7 @@ static int stm32_dmastart(FAR struct sdio_dev_s *dev) * dev - An instance of the MMC/SD device interface * * Returned Value: - * OK on succes; a negated errno on failure + * OK on success; a negated errno on failure * ****************************************************************************/ @@ -1150,7 +1217,7 @@ static int stm32_dmastop(FAR struct sdio_dev_s *dev) * remaining in the transfer. * * Returned Value: - * OK on succes; a negated errno on failure + * OK on success; a negated errno on failure * ****************************************************************************/ diff --git a/drivers/mmcsd/mmcsd_sdio.c b/drivers/mmcsd/mmcsd_sdio.c index 6a60ab3c0f..65abe645f5 100644 --- a/drivers/mmcsd/mmcsd_sdio.c +++ b/drivers/mmcsd/mmcsd_sdio.c @@ -76,6 +76,10 @@ #define MMCSD_DSR_DELAY (100*1000) /* Time to wait after setting DSR */ #define MMCSD_CLK_DELAY (500*1000) /* Delay after changing clock speeds */ +/* Event delays (all in units of milliseconds) */ + +#define MMCSD_SCR_DATADELAY (100) /* Wait up to 100MS to get SCR */ + #define IS_EMPTY(priv) (priv->type == MMCSD_CARDTYPE_UNKNOWN) /* Transfer mode */ @@ -109,6 +113,7 @@ struct mmcsd_state_s ubyte mode:2; /* (See MMCSDMODE_* definitions) */ ubyte type:4; /* Card type (See MMCSD_CARDTYPE_* definitions) */ + ubyte buswidth:4; /* Bus widthes supported (SD only) */ uint16 selblocklen; /* The currently selected block length */ uint16 rca; /* Relative Card Address (RCS) register */ @@ -131,17 +136,21 @@ struct mmcsd_state_s /* Command/response helpers *************************************************/ -static int mmcsd_sendcmdpoll(struct mmcsd_state_s *priv, uint32 cmd, uint32 arg); - +static int mmcsd_sendcmdpoll(struct mmcsd_state_s *priv, uint32 cmd, + uint32 arg); static int mmcsd_recvR1(struct mmcsd_state_s *priv, uint32 cmd); -static void mmcsd_decodecsd(struct mmcsd_state_s *priv, uint32 csd[4]); +static int mmcsd_getSCR(struct mmcsd_state_s *priv, uint32 scr[2]); + +static void mmcsd_decodeCSD(struct mmcsd_state_s *priv, uint32 csd[4]); #if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) -static void mmcsd_decodecid(struct mmcsd_state_s *priv, uint32 cid[4]); +static void mmcsd_decodeCID(struct mmcsd_state_s *priv, uint32 cid[4]); #else -# define mmcsd_decodecid(priv,cid) +# define mmcsd_decodeCID(priv,cid) #endif +static void mmcsd_decodeSCR(struct mmcsd_state_s *priv, uint32 scr[2]); static int mmcsd_verifystandby(struct mmcsd_state_s *priv); +static int mmcsd_verifyidle(struct mmcsd_state_s *priv); /* Transfer helpers *********************************************************/ @@ -167,17 +176,14 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd, /* Initialization/uninitialization/reset ************************************/ -static inline int - mmcsd_mmcinitialize(struct mmcsd_state_s *priv); -static inline int - mmcsd_sdinitialize(struct mmcsd_state_s *priv); -static inline int - mmcsd_cardidentify(struct mmcsd_state_s *priv); +static int mmcsd_widebus(struct mmcsd_state_s *priv); +static int mmcsd_mmcinitialize(struct mmcsd_state_s *priv); +static int mmcsd_sdinitialize(struct mmcsd_state_s *priv); +static int mmcsd_cardidentify(struct mmcsd_state_s *priv); static int mmcsd_probe(struct mmcsd_state_s *priv); static int mmcsd_removed(struct mmcsd_state_s *priv); static int mmcsd_hwinitialize(struct mmcsd_state_s *priv); -static inline void - mmcsd_hwuninitialize(struct mmcsd_state_s *priv); +static void mmcsd_hwuninitialize(struct mmcsd_state_s *priv); /**************************************************************************** * Private Data @@ -299,7 +305,75 @@ static int mmcsd_recvR1(struct mmcsd_state_s *priv, uint32 cmd) } /**************************************************************************** - * Name: mmcsd_decodecsd + * Name: mmcsd_getSCR + * + * Description: + * Obtain the SD card's Configuration Register (SCR) + * + * Returned Value: + * OK on success; a negated ernno on failure. + * + ****************************************************************************/ + +static int mmcsd_getSCR(struct mmcsd_state_s *priv, uint32 scr[2]) +{ + int ret; + + /* Set Block Size To 8 Bytes */ + /* Send CMD55 APP_CMD with argument as card's RCA */ + + mmcsd_sendcmdpoll(priv, MMCSD_CMD16, 8); + ret = mmcsd_recvR1(priv, MMCSD_CMD16); + if (ret != OK) + { + fdbg("ERROR: RECVR1 for CMD16 failed: %d\n", ret); + return ret; + } + + /* Send CMD55 APP_CMD with argument as card's RCA */ + + mmcsd_sendcmdpoll(priv, SD_CMD55, (uint32)priv->rca << 16); + ret = mmcsd_recvR1(priv, SD_CMD55); + if (ret != OK) + { + fdbg("ERROR: RECVR1 for CMD55 failed: %d\n", ret); + return ret; + } + + /* Setup up to receive data */ + + SDIO_RECVSETUP(priv->dev, 8); + + /* Send ACMD51 SD_APP_SEND_SCR with argument as 0 to start data receipt */ + + (void)SDIO_EVENTENABLE(priv->dev, SDIOEVENT_READDATADONE); + mmcsd_sendcmdpoll(priv, SD_ACMD51, 0); + ret = mmcsd_recvR1(priv, SD_ACMD51); + if (ret != OK) + { + fdbg("ERROR: RECVR1 for ACMD51 failed: %d\n", ret); + return ret; + } + + /* Wait for data available */ + + 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); +} + +/**************************************************************************** + * Name: mmcsd_decodeCSD * * Description: * Decode and extract necessary information from the CSD. If debug is @@ -316,7 +390,7 @@ static int mmcsd_recvR1(struct mmcsd_state_s *priv, uint32 cmd) * ****************************************************************************/ -static void mmcsd_decodecsd(struct mmcsd_state_s *priv, uint32 csd[4]) +static void mmcsd_decodeCSD(struct mmcsd_state_s *priv, uint32 csd[4]) { #if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) struct mmcsd_csd_s decoded; @@ -563,15 +637,16 @@ static void mmcsd_decodecsd(struct mmcsd_state_s *priv, uint32 csd[4]) } /**************************************************************************** - * Name: mmcsd_decodecid + * Name: mmcsd_decodeCID * * Description: - * Show the contents of the CID (for debug purposes only) + * Show the contents of the Card Indentification Data (CID) (for debug + * purposes only) * ****************************************************************************/ #if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) -static void mmcsd_decodecid(struct mmcsd_state_s *priv, uint32 cid[4]) +static void mmcsd_decodeCID(struct mmcsd_state_s *priv, uint32 cid[4]) { struct mmcsd_cid_s decoded; @@ -625,11 +700,66 @@ static void mmcsd_decodecid(struct mmcsd_state_s *priv, uint32 cid[4]) } #endif +/**************************************************************************** + * Name: mmcsd_decodeSCR + * + * Description: + * Show the contents of the SD Configuration Register (SCR). The only + * value retained is: priv->buswidth; + * + ****************************************************************************/ + +static void mmcsd_decodeSCR(struct mmcsd_state_s *priv, uint32 scr[2]) +{ +#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) +struct mmcsd_scr_s decoded; +#endif + + /* Word 1, bits 63:32 + * SCR_STRUCTURE 63:60 4-bit SCR structure version + * SD_VERSION 59:56 4-bit SD memory spec. version + * DATA_STATE_AFTER_ERASE 55:55 1-bit erase status + * SD_SECURITY 54:52 3-bit SD security support level + * SD_BUS_WIDTHS 51:48 4-bit bus width indicator + * Reserved 47:32 16-bit SD reserved space + * usage. + * + */ + + priv->buswidth = (scr[0] >> 16) & 15; + +#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) + decoded.scrversion = scr[0] >> 28; + decoded.sdversion = (scr[0] >> 24) & 15; + decoded.erasestate = (scr[0] >> 23) & 1; + decoded.security = (scr[0] >> 20) & 7; + decoded.buswidth = priv->buswidth; +#endif + + /* Word 1, bits 63:32 + * Reserved 31:0 32-bits reserved for manufacturing + * usage. + * + */ + +#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) + decoded.mfgdata = scr[1]; + + fvdbg("SCR:\n"); + fvdbg(" SCR_STRUCTURE: %d SD_VERSION: %d\n", + decoded.scrversion,decoded.sdversion); + fvdbg(" DATA_STATE_AFTER_ERASE: %d SD_SECURITY: %d SD_BUS_WIDTHS: %x\n", + decoded.erasestate, decoded.security, decoded.buswidth); + fvdbg(" Manufacturing data: %08x\n", + decoded.mfgdata); +#endif +} + /**************************************************************************** * Name: mmcsd_verifystandby * * Description: - * Verify that the card is in standby state + * Verify that the card is in STANDBY state * ****************************************************************************/ @@ -639,6 +769,20 @@ static int mmcsd_verifystandby(struct mmcsd_state_s *priv) return -ENOSYS; } +/**************************************************************************** + * Name: mmcsd_verifystandby + * + * Description: + * Verify that the card is in IDLE state + * + ****************************************************************************/ + +static int mmcsd_verifyidle(struct mmcsd_state_s *priv) +{ +#warning "Not implemented" + return -ENOSYS; +} + /**************************************************************************** * Transfer Helpers ****************************************************************************/ @@ -891,6 +1035,93 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg) * Initialization/uninitialization/reset ****************************************************************************/ +/**************************************************************************** + * Name: mmcsd_widebus + * + * Description: + * An SD card has been inserted and its SCR has been obtained. Select wide + * (4-bit) bus operation if the card supports it. + * + * Assumptions: + * This function is called only once per card insertion as part of the SD + * card initialization sequence. It is not necessary to reselect the card + * there is not need to check if wide bus operation has already been + * selected. + * + ****************************************************************************/ + +static int mmcsd_widebus(struct mmcsd_state_s *priv) +{ + int ret; + + /* Check if the SD card supports this feature (as reported in the SCR) */ + + if ((priv->buswidth & MMCSD_SCR_BUSWIDTH_4BIT) != 0) + { + /* Disconnect any CD/DAT3 pull up using ACMD42. ACMD42 is optional and + * need not be supported by all SD calls. + * + * First end CMD55 APP_CMD with argument as card's RCA. + */ + + mmcsd_sendcmdpoll(priv, SD_CMD55, (uint32)priv->rca << 16); + ret = mmcsd_recvR1(priv, SD_CMD55); + if (ret != OK) + { + fdbg("ERROR: RECVR1 for CMD55 of ACMD42: %d\n", ret); + return ret; + } + + /* Then send ACMD42 with the argument to disconnect the CD/DAT3 + * pullup + */ + + mmcsd_sendcmdpoll(priv, SD_ACMD42, MMCSD_ACMD42_CD_DISCONNECT); + ret = mmcsd_recvR1(priv, SD_ACMD42); + if (ret != OK) + { + fvdbg("WARNING: SD card does not support ACMD42: %d\n", ret); + return ret; + } + + /* Now send ACMD6 to select wide, 4-bit bus operation, beginning + * with CMD55, APP_CMD: + */ + + mmcsd_sendcmdpoll(priv, SD_CMD55, (uint32)priv->rca << 16); + ret = mmcsd_recvR1(priv, SD_CMD55); + if (ret != OK) + { + fdbg("ERROR: RECVR1 for CMD55 of ACMD6: %d\n", ret); + return ret; + } + + /* Then send ACMD6 */ + + mmcsd_sendcmdpoll(priv, SD_ACMD6, MMCSD_ACMD6_BUSWIDTH_4); + ret = mmcsd_recvR1(priv, SD_ACMD6); + if (ret != OK) + { + return ret; + } + + /* Configure the SDIO peripheral */ + + fvdbg("Wide bus operation selected\n"); + SDIO_WIDEBUS(priv->dev, TRUE); + priv->widebus = TRUE; + + SDIO_CLOCK(priv->dev, CLOCK_SD_TRANSFER_4BIT); + up_udelay(MMCSD_CLK_DELAY); + return OK; + } + + /* Wide bus operation not supported */ + + fdbg("WARNING: Card does not support wide-bus operation\n"); + return -ENOSYS; +} + /**************************************************************************** * Name: mmcsd_mmcinitialize * @@ -900,7 +1131,7 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg) * ****************************************************************************/ -static inline int mmcsd_mmcinitialize(struct mmcsd_state_s *priv) +static int mmcsd_mmcinitialize(struct mmcsd_state_s *priv) { #ifdef CONFIG_MMCSD_MMCSUPPORT uint32 cid[4]; @@ -912,7 +1143,7 @@ static inline int mmcsd_mmcinitialize(struct mmcsd_state_s *priv) * so there is good evidence that we have an MMC card inserted into the * slot. * - * Send CMD2 = ALL_SEND_CID. This implementation supports only one MMC slot. + * Send CMD2, ALL_SEND_CID. This implementation supports only one MMC slot. * If mulitple cards were installed, each card would respond to CMD2 by * sending its CID (only one card completes the response at a time). The * driver should send CMD2 and assign an RCAs until no response to @@ -926,9 +1157,9 @@ static inline int mmcsd_mmcinitialize(struct mmcsd_state_s *priv) fdbg("ERROR: SDIO_RECVR2 for MMC CID failed: %d\n", ret); return ret; } - mmcsd_decodecid(priv, cid); + mmcsd_decodeCID(priv, cid); - /* Send CMD3 = SET_RELATIVE_ADDR. This command is used to assign a logical + /* Send CMD3, SET_RELATIVE_ADDR. This command is used to assign a logical * address to the card. For MMC, the host assigns the address. CMD3 causes * transition to standby state/data-transfer mode */ @@ -936,7 +1167,7 @@ static inline int mmcsd_mmcinitialize(struct mmcsd_state_s *priv) priv->rca = 1; /* There is only one card */ mmcsd_sendcmdpoll(priv, MMC_CMD3, priv->rca << 16); ret = mmcsd_recvR1(priv, MMC_CMD3); - if (ret != 0) + if (ret != OK) { fdbg("ERROR: mmcsd_recvR1(CMD3) failed: %d\n", ret); return ret; @@ -950,25 +1181,25 @@ static inline int mmcsd_mmcinitialize(struct mmcsd_state_s *priv) */ ret = mmcsd_verifystandby(priv); - if (ret != 0) + if (ret != OK) { fdbg("ERROR: Failed to enter standby state\n"); return ret; } - /* Send CMD9 = SEND_CSD in standby state/data-transfer mode to obtain the + /* Send CMD9, SEND_CSD in standby state/data-transfer mode to obtain the * Card Specific Data (CSD) register, e.g., block length, card storage * capacity, etc. (Stays in standy state/data-transfer mode) */ mmcsd_sendcmdpoll(priv, MMCSD_CMD9, priv->rca << 16); ret = SDIO_RECVR2(priv->dev, MMCSD_CMD9, csd); - if (ret != 0) + if (ret != OK) { fdbg("ERROR: Could not get SD CSD register: %d\n", ret); return ret; } - mmcsd_decodecsd(priv, csd); + mmcsd_decodeCSD(priv, csd); /* Set the Driver Stage Register (DSR) if (1) a CONFIG_MMCSD_DSR has been * provided and (2) the card supports a DSR register. If no DSR value @@ -994,9 +1225,120 @@ static inline int mmcsd_mmcinitialize(struct mmcsd_state_s *priv) * ****************************************************************************/ -static inline int mmcsd_sdinitialize(struct mmcsd_state_s *priv) +static int mmcsd_sdinitialize(struct mmcsd_state_s *priv) { - return -ENOSYS; + uint32 cid[4]; + uint32 csd[4]; + uint32 scr[2]; + uint32 rca; + int ret; + + /* At this point, clocking has been supplied to the card, both CMD0 and + * ACMD41 (with OCR=0) have been sent successfully, the card is no longer + * busy and (presumably) in the IDLE state so there is good evidence + * that we have an SD card inserted into the slot. + * + * Send CMD2, ALL_SEND_CID. The SD CMD2 is similar to the MMC CMD2 except + * that the buffer type used to transmit to response of the card (SD Memory + * Card: Push-Pull, MMC: Open-Drain). This implementation supports only a + * single SD card. If multiple cards were installed in the slot, each card + * would respond to CMD2 by sending its CID (only one card completes the + * response at a time). The driver should send CMD2 and obtain RCAs until + * no response to ALL_SEND_CID is received. + * + * When an SD card receives the CMD2 command it should transition to the + * identification state/card-identification mode + */ + + mmcsd_sendcmdpoll(priv, MMCSD_CMD2, 0); + ret = SDIO_RECVR2(priv->dev, MMCSD_CMD2, cid); + if (ret != OK) + { + fdbg("ERROR: SDIO_RECVR2 for SD CID failed: %d\n", ret); + return ret; + } + mmcsd_decodeCID(priv, cid); + + /* Send CMD3, SET_RELATIVE_ADDR. In both protocols, this command is used + * to assign a logical address to the card. For MMC, the host assigns the + * address; for SD, the memory card has this responsibility. CMD3 causes + * transition to standby state/data-transfer mode + * + * Send CMD3 with argument 0, SD card publishes its RCA in the response. + */ + + mmcsd_sendcmdpoll(priv, SD_CMD3, 0); + ret = SDIO_RECVR6(priv->dev, SD_CMD3, &rca); + if (ret != OK) + { + return ret; + } + + priv->rca = (uint16)rca; + fvdbg("RCA: %04x\n", priv->rca); + + /* This should have caused a transition to standby state. However, this will + * not be reflected in the present R1 status. R1/6 contains the state of + * the card when the command was received, not when it completed execution. + * + * Verify that we are in standby state/data-transfer mode + */ + + ret = mmcsd_verifystandby(priv); + if (ret != OK) + { + fdbg("ERROR: Failed to enter standby state\n"); + return ret; + } + + /* Send CMD9, SEND_CSD, in standby state/data-transfer mode to obtain the + * Card Specific Data (CSD) register. The argument is the RCA that we + * just obtained from CMD3. The card stays in standy state/data-transfer + * mode. + */ + + mmcsd_sendcmdpoll(priv, MMCSD_CMD9, priv->rca << 16); + ret = SDIO_RECVR2(priv->dev, MMCSD_CMD9, csd); + if (ret != OK) + { + fdbg("ERROR: Could not get SD CSD register(%d)\n", ret); + return ret; + } + mmcsd_decodeCSD(priv, csd); + + /* Set the Driver Stage Register (DSR) if (1) a CONFIG_MMCSD_DSR has been + * provided and (2) the card supports a DSR register. If no DSR value + * the card default value (0x0404) will be used. + */ + + (void)mmcsd_sendcmd4(priv); + + /* Select high speed SD clocking (which may depend on the DSR setting) */ + + SDIO_CLOCK(priv->dev, CLOCK_SD_TRANSFER_1BIT); + up_udelay(MMCSD_CLK_DELAY); + + /* Get the SD card Configuration Register (SCR). We need this now because + * that configuration register contains the indication whether or not + * this card supports wide bus operation.\ + */ + + ret = mmcsd_getSCR(priv, scr); + if (ret != OK) + { + fdbg("ERROR: Could not get SD SCR register(%d)\n", ret); + return ret; + } + mmcsd_decodeSCR(priv, scr); + + /* Select width (4-bit) bus operation (if the card supports it) */ + + ret = mmcsd_widebus(priv); + if (ret != OK) + { + fdbg("WARN: Failed to set wide bus operation: %d\n", ret); + } + return OK; } /**************************************************************************** @@ -1008,12 +1350,12 @@ static inline int mmcsd_sdinitialize(struct mmcsd_state_s *priv) * ****************************************************************************/ -static inline int mmcsd_cardidentify(struct mmcsd_state_s *priv) +static int mmcsd_cardidentify(struct mmcsd_state_s *priv) { uint32 response; uint32 start; uint32 elapsed; - uint32 sdcapacity = MMCD_ACMD41_STDCAPACITY; + uint32 sdcapacity = MMCSD_ACMD41_STDCAPACITY; int ret; /* Assume failure to identify the card */ @@ -1074,7 +1416,7 @@ static inline int mmcsd_cardidentify(struct mmcsd_state_s *priv) { fvdbg("SD V2.x card\n"); priv->type = MMCSD_CARDTYPE_SDV2; - sdcapacity = MMCD_ACMD41_HIGHCAPACITY; + sdcapacity = MMCSD_ACMD41_HIGHCAPACITY; } else { @@ -1119,7 +1461,7 @@ static inline int mmcsd_cardidentify(struct mmcsd_state_s *priv) { /* Send ACMD41 */ - mmcsd_sendcmdpoll(priv, SD_ACMD41, MMCD_ACMD41_VOLTAGEWINDOW|sdcapacity); + mmcsd_sendcmdpoll(priv, SD_ACMD41, MMCSD_ACMD41_VOLTAGEWINDOW|sdcapacity); ret = SDIO_RECVR3(priv->dev, SD_CMD55, &response); if (ret != OK) { @@ -1155,7 +1497,7 @@ static inline int mmcsd_cardidentify(struct mmcsd_state_s *priv) * addressing */ - if ((response & MMCD_R3_HIGHCAPACITY) != 0) + if ((response & MMCSD_R3_HIGHCAPACITY) != 0) { fvdbg("SD V2.x card with block addressing\n"); DEBUGASSERT(priv->type == MMCSD_CARDTYPE_SDV2); @@ -1243,6 +1585,15 @@ static inline int mmcsd_cardidentify(struct mmcsd_state_s *priv) return -EIO; } + /* Verify that we are in IDLE state */ + + ret = mmcsd_verifyidle(priv); + if (ret != OK) + { + fdbg("ERROR: Failed to enter IDLE state\n"); + return ret; + } + return OK; } @@ -1417,7 +1768,7 @@ static int mmcsd_hwinitialize(struct mmcsd_state_s *priv) * ****************************************************************************/ -static inline void mmcsd_hwuninitialize(struct mmcsd_state_s *priv) +static void mmcsd_hwuninitialize(struct mmcsd_state_s *priv) { if (priv) { @@ -1498,7 +1849,7 @@ int mmcsd_slotinitialize(int minor, int slotno, FAR struct sdio_dev_s *dev) else { fdbg("ERROR: Failed to initialize MMC/SD slot %d: %d\n", - slotno, -ret); + slotno, ret); goto errout_with_alloc; } } @@ -1510,7 +1861,7 @@ int mmcsd_slotinitialize(int minor, int slotno, FAR struct sdio_dev_s *dev) ret = rwb_initialize(&priv->rwbuffer); if (ret < 0) { - fdbg("ERROR: Buffer setup failed: %d\n", -ret); + fdbg("ERROR: Buffer setup failed: %d\n", ret); goto errout_with_hwinit; } #endif @@ -1524,7 +1875,7 @@ int mmcsd_slotinitialize(int minor, int slotno, FAR struct sdio_dev_s *dev) ret = register_blockdriver(devname, &g_bops, 0, priv); if (ret < 0) { - fdbg("ERROR: register_blockdriver failed: %d\n", -ret); + fdbg("ERROR: register_blockdriver failed: %d\n", ret); goto errout_with_buffers; } } diff --git a/drivers/mmcsd/mmcsd_sdio.h b/drivers/mmcsd/mmcsd_sdio.h index 43997f2f66..e005af2123 100644 --- a/drivers/mmcsd/mmcsd_sdio.h +++ b/drivers/mmcsd/mmcsd_sdio.h @@ -60,11 +60,21 @@ #define MMCSD_CMD8ECHO_MASK (0xff << MMCSD_CMD8ECHO_SHIFT) # define MMCSD_CMD8CHECKPATTERN (0xaa << MMCSD_CMD8ECHO_SHIFT) +/* ACMD6 argument */ + +#define MMCSD_ACMD6_BUSWIDTH_1 (0) /* Bus width = 1-bit */ +#define MMCSD_ACMD6_BUSWIDTH_4 (2) /* Bus width = 4-bit */ + /* ACMD41 argument */ -#define MMCD_ACMD41_VOLTAGEWINDOW 0x80100000 -#define MMCD_ACMD41_HIGHCAPACITY (1 << 30) -#define MMCD_ACMD41_STDCAPACITY (0) +#define MMCSD_ACMD41_VOLTAGEWINDOW 0x80100000 +#define MMCSD_ACMD41_HIGHCAPACITY (1 << 30) +#define MMCSD_ACMD41_STDCAPACITY (0) + +/* ACMD42 argument */ + +#define MMCSD_ACMD42_CD_DISCONNECT (0) /* Disconnect card detection logic */ +#define MMCSD_ACMD42_CD_CONNECT (1) /* Connect card detection logic */ /* R1 Card Status bit definitions */ @@ -135,9 +145,16 @@ #define MMCSD_VDD_33_34 (1 << 21) /* VDD voltage 3.3-3.4 */ #define MMCSD_VDD_34_35 (1 << 22) /* VDD voltage 3.4-3.5 */ #define MMCSD_VDD_35_36 (1 << 23) /* VDD voltage 3.5-3.6 */ -#define MMCD_R3_HIGHCAPACITY (1 << 30) /* TRUE: Card supports block addressing */ +#define MMCSD_R3_HIGHCAPACITY (1 << 30) /* TRUE: Card supports block addressing */ #define MMCSD_CARD_BUSY (1 << 31) /* Card power-up busy bit */ +/* SD Configuration Register (SCR) encoding */ + +#define MMCSD_SCR_BUSWIDTH_1BIT (1) +#define MMCSD_SCR_BUSWIDTH_2BIT (2) +#define MMCSD_SCR_BUSWIDTH_4BIT (4) +#define MMCSD_SCR_BUSWIDTH_8BIT (8) + /* Last 4 bytes of the 48-bit R7 response */ #define MMCSD_R7VERSION_SHIFT 28 /* Bits 28-31: Command version number */ @@ -153,7 +170,7 @@ * Public Types ********************************************************************************************/ -/* Decoded CID register */ +/* Decoded Card Identification (CID) register */ struct mmcsd_cid_s { @@ -168,7 +185,7 @@ struct mmcsd_cid_s /* 0:0 1-bit (not used) */ }; -/* Decoded CSD register */ +/* Decoded Card Specific Data (CSD) register */ struct mmcsd_csd_s { @@ -264,6 +281,17 @@ struct mmcsd_csd_s /* 0:0 Not used */ }; +struct mmcsd_scr_s +{ + ubyte scrversion; /* 63:60 Version of SCR structure */ + ubyte sdversion; /* 59:56 SD memory card physical layer version */ + ubyte erasestate; /* 55:55 Data state after erase (1 or 0) */ + ubyte security; /* 54:52 SD security support */ + ubyte buswidth; /* 51:48 DAT bus widthes supported */ + /* 47:32 SD reserved space */ + uint32 mfgdata; /* 31:0 Reserved for manufacturing data */ +}; + /******************************************************************************************** * Public Data ********************************************************************************************/ diff --git a/include/nuttx/sdio.h b/include/nuttx/sdio.h index 0e4d77c62e..ebecc5923e 100755 --- a/include/nuttx/sdio.h +++ b/include/nuttx/sdio.h @@ -359,25 +359,6 @@ #define SDIO_CLOCK(dev,rate) ((dev)->clock(dev,rate)) -/**************************************************************************** - * Name: SDIO_SETBLOCKLEN - * - * Description: - * Set the MMC/SD block length and block count - * - * Input Parameters: - * dev - An instance of the MMC/SD device interface - * blocklen - The block length - * nblocks - The block count - * - * Returned Value: - * OK on success; negated errno on failure - * - ****************************************************************************/ - -#define SDIO_SETBLOCKLEN(dev,blocklen,nblocks) \ - ((dev)->setblocklen(dev,blocklen,nblocks)) - /**************************************************************************** * Name: SDIO_ATTACH * @@ -413,6 +394,26 @@ #define SDIO_SENDCMD(dev,cmd,arg) ((dev)->sendcmd(dev,cmd,arg)) +/**************************************************************************** + * Name: SDIO_SENDSETUP + * + * 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. + * + * 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_SENDSETUP(dev,nbytes) ((dev)->sendsetup(dev,nbytes)) + /**************************************************************************** * Name: SDIO_SENDDATA * @@ -424,7 +425,7 @@ * data - Data to be sent * * Returned Value: - * Number of bytes sent on succes; a negated errno on failure + * Number of bytes sent on success; a negated errno on failure * ****************************************************************************/ @@ -475,7 +476,28 @@ #define SDIO_RECVR4(dev,cmd,R4) ((dev)->recvR4(dev,cmd,R4)) /* 48-bit */ #define SDIO_RECVR5(dev,cmd,R5) ((dev)->recvR5(dev,cmd,R5)) /* 48-bit */ #define SDIO_RECVR6(dev,cmd,R6) ((dev)->recvR6(dev,cmd,R6)) /* 48-bit */ -#define SDIO_RECVR7(dev,cmd,R7) ((dev)->recvR6(dev,cmd,R7)) /* 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 @@ -488,7 +510,7 @@ * buffer - Buffer in which to receive the data * * Returned Value: - * Number of bytes sent on succes; a negated errno on failure + * Number of bytes sent on success; a negated errno on failure * ****************************************************************************/ @@ -502,18 +524,15 @@ * * Input Parameters: * dev - An instance of the MMC/SD device interface - * eventset - A bitset of events to enable or disable (see SDIOEVENT_* - * definitions - * enable - TRUE: enable event; FALSE: disable events + * eventset - A bitset of events to enable or disable (see MMCSDEVENT_* + * definitions). 0=disable; 1=enable. * * Returned Value: * None * ****************************************************************************/ -#define SDIO_EVENTENABLE(dev,eventset) ((dev)->eventenable(dev,eventset,TRUE)) -#define SDIO_EVENTDISABLE(dev,eventset) ((dev)->eventenable(dev,eventset,FALSE)) -#define SDIO_EVENTDISABLEALL(dev) ((dev)->eventenable(dev,SDIOEVENT_ALLEVENTS,FALSE)) +#define SDIO_EVENTENABLE(dev,eventset) ((dev)->eventenable(dev,eventset)) /**************************************************************************** * Name: SDIO_EVENTWAIT @@ -526,8 +545,9 @@ * timeout - Maximum time in milliseconds to wait. Zero means no timeout. * * Returned Value: - * Event set containing the event(s) that ended the wait. If no events the + * Event set containing the event(s) that ended the wait. If no events the * returned event set is zero, then the wait was terminated by the timeout. + * All events are cleared disabled after the wait concludes. * ****************************************************************************/ @@ -538,13 +558,14 @@ * * Description: * Return the current event set. This supports polling for MMC/SD (vs. - * waiting). + * waiting). Only enabled events need be reported. * * Input Parameters: - * dev - An instance of the MMC/SD device interface + * dev - An instance of the MMC/SD device interface * * Returned Value: - * Event set containing the current events (cleared after reading). + * Event set containing the current events (All pending events are cleared + * after reading). * ****************************************************************************/ @@ -609,7 +630,7 @@ * buffer - The memory to DMA from * * Returned Value: - * OK on succes; a negated errno on failure + * OK on success; a negated errno on failure * ****************************************************************************/ @@ -630,7 +651,7 @@ * buffer - The memory to DMA into * * Returned Value: - * OK on succes; a negated errno on failure + * OK on success; a negated errno on failure * ****************************************************************************/ @@ -650,7 +671,7 @@ * dev - An instance of the MMC/SD device interface * * Returned Value: - * OK on succes; a negated errno on failure + * OK on success; a negated errno on failure * ****************************************************************************/ @@ -670,7 +691,7 @@ * dev - An instance of the MMC/SD device interface * * Returned Value: - * OK on succes; a negated errno on failure + * OK on success; a negated errno on failure * ****************************************************************************/ @@ -692,7 +713,7 @@ * remaining in the transfer. * * Returned Value: - * OK on succes; a negated errno on failure + * OK on success; a negated errno on failure * ****************************************************************************/ @@ -713,9 +734,16 @@ enum sdio_clock_e CLOCK_SDIO_DISABLED = 0, /* Clock is disabled */ CLOCK_IDMODE, /* Initial ID mode clocking (<400KHz) */ CLOCK_MMC_TRANSFER, /* MMC normal operation clocking */ - CLOCK_SD_TRANSFER /* SD normal operation clocking */ + CLOCK_SD_TRANSFER_1BIT, /* SD normal operation clocking (narrow 1-bit mode) */ + CLOCK_SD_TRANSFER_4BIT /* SD normal operation clocking (wide 4-bit mode) */ }; +/* Event set. A ubyte is big enough to hold a set of 8-events. If more are + * needed, change this to a uint16. + */ + +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 * interface is only used in architectures that support SDIO @@ -736,12 +764,12 @@ struct sdio_dev_s ubyte (*status)(FAR struct sdio_dev_s *dev); void (*widebus)(FAR struct sdio_dev_s *dev, boolean enable); void (*clock)(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate); - int (*setblocklen)(FAR struct sdio_dev_s *dev, int blocklen, int nblocks); int (*attach)(FAR struct sdio_dev_s *dev); /* 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 (*waitresponse)(FAR struct sdio_dev_s *dev, uint32 cmd); @@ -752,11 +780,12 @@ 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 (*eventenable)(FAR struct sdio_dev_s *dev, ubyte eventset, boolean enable); + void (*eventenable)(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);