mirror of
https://github.com/apache/nuttx.git
synced 2026-06-02 17:48:54 +08:00
drivers/mmcsd: Added support for MMC(eMMC) bigger than 2 GB (Tested with IMXRT1050EVKB and samsung eMMC 16GB). arch/arm/src/imxrt: IMXRT uSDHC driver cmd line reset logic modified.
This commit is contained in:
committed by
Gregory Nutt
parent
fe6f9b1f24
commit
19c070e0d1
@@ -4,6 +4,7 @@
|
|||||||
* Copyright (C) 2018-2019 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2018-2019 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
* Dave Marples <dave@marples.net>
|
* Dave Marples <dave@marples.net>
|
||||||
|
* Ivan Ucherdzhiev <ivanucherdjiev@gmail.com>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@@ -2021,7 +2022,11 @@ static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
|
|||||||
|
|
||||||
if ((getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET) & USDHC_RESPERR_INTS) != 0)
|
if ((getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET) & USDHC_RESPERR_INTS) != 0)
|
||||||
{
|
{
|
||||||
putreg32(USDHC_SYSCTL_RSTC, priv->addr + IMXRT_USDHC_SYSCTL_OFFSET);
|
modifyreg32(priv->addr + IMXRT_USDHC_SYSCTL_OFFSET, 0, USDHC_SYSCTL_RSTC);
|
||||||
|
while ((getreg32(priv->addr + IMXRT_USDHC_SYSCTL_OFFSET) &
|
||||||
|
USDHC_SYSCTL_RSTC) != 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout = USDHC_CMDTIMEOUT;
|
timeout = USDHC_CMDTIMEOUT;
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
#define MMCSD_CARDTYPE_MMC 1 /* Bit 0: MMC card */
|
#define MMCSD_CARDTYPE_MMC 1 /* Bit 0: MMC card */
|
||||||
#define MMCSD_CARDTYPE_SDV1 2 /* Bit 1: SD version 1.x */
|
#define MMCSD_CARDTYPE_SDV1 2 /* Bit 1: SD version 1.x */
|
||||||
#define MMCSD_CARDTYPE_SDV2 4 /* Bit 2: SD version 2.x with byte addressing */
|
#define MMCSD_CARDTYPE_SDV2 4 /* Bit 2: SD version 2.x with byte addressing */
|
||||||
#define MMCSD_CARDTYPE_BLOCK 8 /* Bit 3: SD version 2.x with block addressing */
|
#define MMCSD_CARDTYPE_BLOCK 8 /* Bit 3: SD version 2.x or MMC with block addressing */
|
||||||
|
|
||||||
#define IS_MMC(t) (((t) & MMCSD_CARDTYPE_MMC) != 0)
|
#define IS_MMC(t) (((t) & MMCSD_CARDTYPE_MMC) != 0)
|
||||||
#define IS_SD(t) (((t) & (MMCSD_CARDTYPE_SDV1|MMCSD_CARDTYPE_SDV2)) != 0)
|
#define IS_SD(t) (((t) & (MMCSD_CARDTYPE_SDV1|MMCSD_CARDTYPE_SDV2)) != 0)
|
||||||
@@ -81,7 +81,8 @@
|
|||||||
#undef EXTERN
|
#undef EXTERN
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
#define EXTERN extern "C"
|
#define EXTERN extern "C"
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#else
|
#else
|
||||||
#define EXTERN extern
|
#define EXTERN extern
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+323
-16
@@ -1,9 +1,10 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* drivers/mmcsd/mmcsd_sdio.c
|
* drivers/mmcsd/mmcsd_sdio.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009-2013, 2016-2018 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2009-2013, 2016-2019 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
* Bob Feretich <bob.fereich@rafresearch.com>
|
* Bob Feretich <bob.fereich@rafresearch.com>
|
||||||
|
* Ivan Ucherdzhiev <ivanucherdjiev@gmail.com>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@@ -245,6 +246,7 @@ static void mmcsd_mediachange(FAR void *arg);
|
|||||||
static int mmcsd_widebus(FAR struct mmcsd_state_s *priv);
|
static int mmcsd_widebus(FAR struct mmcsd_state_s *priv);
|
||||||
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
||||||
static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv);
|
static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv);
|
||||||
|
static int mmcsd_mmcreadextCSD (FAR struct mmcsd_state_s *priv);
|
||||||
#endif
|
#endif
|
||||||
static int mmcsd_sdinitialize(FAR struct mmcsd_state_s *priv);
|
static int mmcsd_sdinitialize(FAR struct mmcsd_state_s *priv);
|
||||||
static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv);
|
static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv);
|
||||||
@@ -656,6 +658,49 @@ static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32_t csd[4])
|
|||||||
|
|
||||||
if (IS_BLOCK(priv->type))
|
if (IS_BLOCK(priv->type))
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
||||||
|
if (IS_MMC(priv->type))
|
||||||
|
{
|
||||||
|
/* Block addressed MMC:
|
||||||
|
*
|
||||||
|
* C_SIZE: 73:64 from Word 2 and 63:62 from Word 3
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* If the card is MMC and it has Block addressing
|
||||||
|
* then the correct number of blocks should already be
|
||||||
|
* read from extended CSD register.
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint16_t csize = ((csd[1] & 0x03ff) << 2) | ((csd[2] >> 30) & 3);
|
||||||
|
uint8_t csizemult = (csd[2] >> 15) & 7;
|
||||||
|
|
||||||
|
priv->blockshift = readbllen;
|
||||||
|
priv->blocksize = (1 << readbllen);
|
||||||
|
#ifdef CONFIG_HAVE_LONG_LONG
|
||||||
|
priv->capacity = ((uint64_t)(priv->nblocks)) << readbllen;
|
||||||
|
#else
|
||||||
|
priv->capacity = (priv->nblocks << readbllen);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (priv->blocksize > 512)
|
||||||
|
{
|
||||||
|
priv->blocksize = 512;
|
||||||
|
priv->blockshift = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
decoded.u.mmc.csize = csize;
|
||||||
|
decoded.u.mmc.vddrcurrmin = (csd[2] >> 27) & 7;
|
||||||
|
decoded.u.mmc.vddrcurrmax = (csd[2] >> 24) & 7;
|
||||||
|
decoded.u.mmc.vddwcurrmin = (csd[2] >> 21) & 7;
|
||||||
|
decoded.u.mmc.vddwcurrmax = (csd[2] >> 18) & 7;
|
||||||
|
decoded.u.mmc.csizemult = csizemult;
|
||||||
|
decoded.u.mmc.er.mmc22.sectorsize = (csd[2] >> 10) & 0x1f;
|
||||||
|
decoded.u.mmc.er.mmc22.ergrpsize = (csd[2] >> 5) & 0x1f;
|
||||||
|
decoded.u.mmc.mmcwpgrpsize = csd[2] & 0x1f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
/* Block addressed SD:
|
/* Block addressed SD:
|
||||||
*
|
*
|
||||||
* C_SIZE: 69:64 from Word 2 and 63:48 from Word 3
|
* C_SIZE: 69:64 from Word 2 and 63:48 from Word 3
|
||||||
@@ -682,6 +727,7 @@ static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32_t csd[4])
|
|||||||
decoded.u.sdblock.sdwpgrpsize = csd[2] & 0x7f;
|
decoded.u.sdblock.sdwpgrpsize = csd[2] & 0x7f;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Byte addressed SD:
|
/* Byte addressed SD:
|
||||||
@@ -792,12 +838,30 @@ static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32_t csd[4])
|
|||||||
|
|
||||||
if (IS_BLOCK(priv->type))
|
if (IS_BLOCK(priv->type))
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
||||||
|
if (IS_MMC(priv->type))
|
||||||
|
{
|
||||||
|
finfo(" MMC Block Addressing:\n");
|
||||||
|
finfo(" C_SIZE: %d C_SIZE_MULT: %d\n",
|
||||||
|
decoded.u.mmc.csize, decoded.u.mmc.csizemult);
|
||||||
|
finfo(" VDD_R_CURR_MIN: %d VDD_R_CURR_MAX: %d\n",
|
||||||
|
decoded.u.mmc.vddrcurrmin, decoded.u.mmc.vddrcurrmax);
|
||||||
|
finfo(" VDD_W_CURR_MIN: %d VDD_W_CURR_MAX: %d\n",
|
||||||
|
decoded.u.mmc.vddwcurrmin, decoded.u.mmc.vddwcurrmax);
|
||||||
|
finfo(" MMC_SECTOR_SIZE: %d MMC_ER_GRP_SIZE: %d MMC_WP_GRP_SIZE: %d\n",
|
||||||
|
decoded.u.mmc.er.mmc22.sectorsize, decoded.u.mmc.er.mmc22.ergrpsize,
|
||||||
|
decoded.u.mmc.mmcwpgrpsize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
finfo(" SD Block Addressing:\n");
|
finfo(" SD Block Addressing:\n");
|
||||||
finfo(" C_SIZE: %d SD_ER_BLK_EN: %d\n",
|
finfo(" C_SIZE: %d SD_ER_BLK_EN: %d\n",
|
||||||
decoded.u.sdblock.csize, decoded.u.sdblock.sderblen);
|
decoded.u.sdblock.csize, decoded.u.sdblock.sderblen);
|
||||||
finfo(" SD_SECTOR_SIZE: %d SD_WP_GRP_SIZE: %d\n",
|
finfo(" SD_SECTOR_SIZE: %d SD_WP_GRP_SIZE: %d\n",
|
||||||
decoded.u.sdblock.sdsectorsize, decoded.u.sdblock.sdwpgrpsize);
|
decoded.u.sdblock.sdsectorsize, decoded.u.sdblock.sdwpgrpsize);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (IS_SD(priv->type))
|
else if (IS_SD(priv->type))
|
||||||
{
|
{
|
||||||
finfo(" SD Byte Addressing:\n");
|
finfo(" SD Byte Addressing:\n");
|
||||||
@@ -808,7 +872,8 @@ static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32_t csd[4])
|
|||||||
finfo(" VDD_W_CURR_MIN: %d VDD_W_CURR_MAX: %d\n",
|
finfo(" VDD_W_CURR_MIN: %d VDD_W_CURR_MAX: %d\n",
|
||||||
decoded.u.sdbyte.vddwcurrmin, decoded.u.sdbyte.vddwcurrmax);
|
decoded.u.sdbyte.vddwcurrmin, decoded.u.sdbyte.vddwcurrmax);
|
||||||
finfo(" SD_ER_BLK_EN: %d SD_SECTOR_SIZE: %d (SD) SD_WP_GRP_SIZE: %d\n",
|
finfo(" SD_ER_BLK_EN: %d SD_SECTOR_SIZE: %d (SD) SD_WP_GRP_SIZE: %d\n",
|
||||||
decoded.u.sdbyte.sderblen, decoded.u.sdbyte.sdsectorsize, decoded.u.sdbyte.sdwpgrpsize);
|
decoded.u.sdbyte.sderblen, decoded.u.sdbyte.sdsectorsize,
|
||||||
|
decoded.u.sdbyte.sdwpgrpsize);
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
||||||
else if (IS_MMC(priv->type))
|
else if (IS_MMC(priv->type))
|
||||||
@@ -847,7 +912,7 @@ static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32_t csd[4])
|
|||||||
* Name: mmcsd_decodeCID
|
* Name: mmcsd_decodeCID
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Show the contents of the Card Indentification Data (CID) (for debug
|
* Show the contents of the Card Identification Data (CID) (for debug
|
||||||
* purposes only)
|
* purposes only)
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -2569,7 +2634,8 @@ static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv)
|
|||||||
* sending its CID (only one card completes the response at a time). The
|
* 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
|
* driver should send CMD2 and assign an RCAs until no response to
|
||||||
* ALL_SEND_CID is received. CMD2 causes transition to identification state/
|
* ALL_SEND_CID is received. CMD2 causes transition to identification state/
|
||||||
* card-identification mode */
|
* card-identification mode.
|
||||||
|
*/
|
||||||
|
|
||||||
mmcsd_sendcmdpoll(priv, MMCSD_CMD2, 0);
|
mmcsd_sendcmdpoll(priv, MMCSD_CMD2, 0);
|
||||||
ret = SDIO_RECVR2(priv->dev, MMCSD_CMD2, cid);
|
ret = SDIO_RECVR2(priv->dev, MMCSD_CMD2, cid);
|
||||||
@@ -2622,8 +2688,6 @@ static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
mmcsd_decodeCSD(priv, csd);
|
|
||||||
|
|
||||||
/* Set the Driver Stage Register (DSR) if (1) a CONFIG_MMCSD_DSR has been
|
/* 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
|
* provided and (2) the card supports a DSR register. If no DSR value
|
||||||
* the card default value (0x0404) will be used.
|
* the card default value (0x0404) will be used.
|
||||||
@@ -2631,12 +2695,165 @@ static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv)
|
|||||||
|
|
||||||
(void)mmcsd_sendcmd4(priv);
|
(void)mmcsd_sendcmd4(priv);
|
||||||
|
|
||||||
|
/* Send CMD7 with the argument == RCA in order to select the card
|
||||||
|
* and send it in data-trasfer mode. Since we are supporting
|
||||||
|
* only a single card, we just leave the card selected all of the time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mmcsd_sendcmdpoll(priv, MMCSD_CMD7S, (uint32_t)priv->rca << 16);
|
||||||
|
ret = mmcsd_recvR1(priv, MMCSD_CMD7S);
|
||||||
|
if (ret != OK)
|
||||||
|
{
|
||||||
|
ferr("ERROR: mmcsd_recvR1 for CMD7 failed: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CSD Decoding for MMC should be done after entering in data-transfer mode
|
||||||
|
* because if the card has block addressing then extended CSD register
|
||||||
|
* must be read in order to get the right number of blocks and capacity,
|
||||||
|
* but it has to be done in data-transfer mode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (IS_BLOCK(priv->type))
|
||||||
|
{
|
||||||
|
ret = mmcsd_mmcreadextCSD(priv);
|
||||||
|
if (ret != OK)
|
||||||
|
{
|
||||||
|
ferr("ERROR: Failed to determinate number of blocks: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mmcsd_decodeCSD(priv, csd);
|
||||||
|
|
||||||
/* Select high speed MMC clocking (which may depend on the DSR setting) */
|
/* Select high speed MMC clocking (which may depend on the DSR setting) */
|
||||||
|
|
||||||
SDIO_CLOCK(priv->dev, CLOCK_MMC_TRANSFER);
|
SDIO_CLOCK(priv->dev, CLOCK_MMC_TRANSFER);
|
||||||
up_udelay(MMCSD_CLK_DELAY);
|
up_udelay(MMCSD_CLK_DELAY);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: mmcsd_mmcreadextCSD
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* MMC card is detected with block addressing and this function will read
|
||||||
|
* the correct number of blocks and capacity. Returns OK if ext CSD is read
|
||||||
|
* correctly or error in not.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int mmcsd_mmcreadextCSD (FAR struct mmcsd_state_s *priv)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint8_t buffer[512];
|
||||||
|
|
||||||
|
DEBUGASSERT(priv != NULL);
|
||||||
|
|
||||||
|
/* Check if the card is locked */
|
||||||
|
|
||||||
|
if (priv->locked)
|
||||||
|
{
|
||||||
|
ferr("ERROR: Card is locked\n");
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_SDIO_DMA) && defined(CONFIG_ARCH_HAVE_SDIO_PREFLIGHT)
|
||||||
|
/* If we think we are going to perform a DMA transfer, make sure that we
|
||||||
|
* will be able to before we commit the card to the operation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((priv->caps & SDIO_CAPS_DMASUPPORTED) != 0)
|
||||||
|
{
|
||||||
|
ret = SDIO_DMAPREFLIGHT(priv->dev, buffer, priv->blocksize);
|
||||||
|
if (ret != OK)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Verify that the card is ready for the transfer. The card may still be
|
||||||
|
* busy from the preceding write transfer. It would be simpler to check
|
||||||
|
* for write busy at the end of each write, rather than at the beginning of
|
||||||
|
* each read AND write, but putting the busy-wait at the beginning of the
|
||||||
|
* transfer allows for more overlap and, hopefully, better performance
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = mmcsd_transferready(priv);
|
||||||
|
if (ret != OK)
|
||||||
|
{
|
||||||
|
ferr("ERROR: Card not ready: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select the block size for the card */
|
||||||
|
|
||||||
|
ret = mmcsd_setblocklen(priv, 512);
|
||||||
|
if (ret != OK)
|
||||||
|
{
|
||||||
|
ferr("ERROR: mmcsd_setblocklen failed: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure SDIO controller hardware for the read transfer */
|
||||||
|
|
||||||
|
SDIO_BLOCKSETUP(priv->dev, 512, 1);
|
||||||
|
SDIO_WAITENABLE(priv->dev,
|
||||||
|
SDIOWAIT_TRANSFERDONE | SDIOWAIT_TIMEOUT | SDIOWAIT_ERROR);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SDIO_DMA
|
||||||
|
if ((priv->caps & SDIO_CAPS_DMASUPPORTED) != 0)
|
||||||
|
{
|
||||||
|
ret = SDIO_DMARECVSETUP(priv->dev, buffer, 512);
|
||||||
|
if (ret != OK)
|
||||||
|
{
|
||||||
|
finfo("SDIO_DMARECVSETUP: error %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
SDIO_RECVSETUP(priv->dev, buffer, 512);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send CMD8 in data-transfer mode to obtain the
|
||||||
|
* extended Card Specific Data (CSD) register, e.g., block length, card storage
|
||||||
|
* capacity, etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mmcsd_sendcmdpoll(priv, MMC_CMD8, 0);
|
||||||
|
ret = mmcsd_recvR1(priv, MMC_CMD8);
|
||||||
|
if (ret != OK)
|
||||||
|
{
|
||||||
|
ferr("ERROR: Could not get MMC extended CSD register: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Then wait for the data transfer to complete */
|
||||||
|
|
||||||
|
ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT | SDIOWAIT_ERROR,
|
||||||
|
MMCSD_BLOCK_RDATADELAY);
|
||||||
|
#ifdef CONFIG_SDIO_DMA
|
||||||
|
SDIO_DMADELYDINVLDT(priv->dev, buffer, 512);
|
||||||
|
#endif
|
||||||
|
if (ret != OK)
|
||||||
|
{
|
||||||
|
ferr("ERROR: CMD17 transfer failed: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->nblocks = (buffer[215] << 24) | (buffer[214] << 16) |
|
||||||
|
(buffer[213] << 8) | buffer[212];
|
||||||
|
|
||||||
|
finfo("MMC ext CSD read succsesfully, number of block %d\n",
|
||||||
|
priv->nblocks);
|
||||||
|
|
||||||
|
/* Return value: One sector read */
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -2798,6 +3015,7 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv)
|
|||||||
{
|
{
|
||||||
uint32_t response;
|
uint32_t response;
|
||||||
uint32_t sdcapacity = MMCSD_ACMD41_STDCAPACITY;
|
uint32_t sdcapacity = MMCSD_ACMD41_STDCAPACITY;
|
||||||
|
uint32_t mmccapacity = MMCSD_R3_HIGHCAPACITY;
|
||||||
clock_t start;
|
clock_t start;
|
||||||
clock_t elapsed;
|
clock_t elapsed;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -2832,6 +3050,65 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv)
|
|||||||
mmcsd_sendcmdpoll(priv, MMCSD_CMD0, 0);
|
mmcsd_sendcmdpoll(priv, MMCSD_CMD0, 0);
|
||||||
up_udelay(MMCSD_IDLE_DELAY);
|
up_udelay(MMCSD_IDLE_DELAY);
|
||||||
|
|
||||||
|
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
||||||
|
/* send CMD3 which is supported only by MMC.
|
||||||
|
* if there is valid response then the card
|
||||||
|
* is definetly of MMC type
|
||||||
|
*/
|
||||||
|
|
||||||
|
mmcsd_sendcmdpoll(priv, MMC_CMD1, MMCSD_VDD_33_34 | mmccapacity);
|
||||||
|
ret = SDIO_RECVR3(priv->dev, MMC_CMD1, &response);
|
||||||
|
|
||||||
|
/* Was the operating range set successfully */
|
||||||
|
|
||||||
|
if (ret != OK)
|
||||||
|
{
|
||||||
|
ferr("ERROR: CMD1 RECVR3: %d\n", ret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* CMD1 succeeded... this must be an MMC card */
|
||||||
|
|
||||||
|
finfo("MMC card detected\n");
|
||||||
|
priv->type = MMCSD_CARDTYPE_MMC;
|
||||||
|
|
||||||
|
/* Now, check if this is a MMC card/chip that supports block
|
||||||
|
* addressing
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((response & MMCSD_R3_HIGHCAPACITY) != 0)
|
||||||
|
{
|
||||||
|
finfo("MMC card/chip with block addressing\n");
|
||||||
|
mmccapacity = MMCSD_R3_HIGHCAPACITY;
|
||||||
|
priv->type |= MMCSD_CARDTYPE_BLOCK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mmccapacity = MMCSD_R3_STDCAPACITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the card is busy. Very confusing, BUSY is set LOW
|
||||||
|
* if the card has not finished its initialization, so it really
|
||||||
|
* means NOT busy.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((response & MMCSD_CARD_BUSY) != 0)
|
||||||
|
{
|
||||||
|
/* NO.. We really should check the current state to see if the
|
||||||
|
* MMC successfully made it to the IDLE state, but at least for now,
|
||||||
|
* we will simply assume that that is the case.
|
||||||
|
*
|
||||||
|
* Then break out of the look with an MMC card identified
|
||||||
|
*/
|
||||||
|
|
||||||
|
finfo("MMC card/chip ready!\n");
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IS_MMC(priv->type))
|
||||||
|
{
|
||||||
|
#endif
|
||||||
/* Check for SDHC Version 2.x. Send CMD8 to verify SD card interface
|
/* Check for SDHC Version 2.x. Send CMD8 to verify SD card interface
|
||||||
* operating condition. CMD 8 is reserved on SD version 1.0 and MMC.
|
* operating condition. CMD 8 is reserved on SD version 1.0 and MMC.
|
||||||
*
|
*
|
||||||
@@ -2872,6 +3149,7 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv)
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* At this point, type is either UNKNOWN or SDV2. Try sending
|
/* At this point, type is either UNKNOWN or SDV2. Try sending
|
||||||
* CMD55 and (maybe) ACMD41 for up to 1 second or until the card
|
* CMD55 and (maybe) ACMD41 for up to 1 second or until the card
|
||||||
@@ -2887,9 +3165,8 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv)
|
|||||||
* an earlier pass through through this loop. In that case, we should
|
* an earlier pass through through this loop. In that case, we should
|
||||||
* skip the SD-specific commands.
|
* skip the SD-specific commands.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
||||||
if (priv->type != MMCSD_CARDTYPE_MMC)
|
if (!IS_MMC(priv->type))
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
/* Send CMD55 with argument = 0 */
|
/* Send CMD55 with argument = 0 */
|
||||||
@@ -2973,7 +3250,7 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
||||||
if (priv->type == MMCSD_CARDTYPE_UNKNOWN || priv->type == MMCSD_CARDTYPE_MMC)
|
if (IS_MMC(priv->type))
|
||||||
{
|
{
|
||||||
/* Send the MMC CMD1 to specify the operating voltage. CMD1 causes
|
/* Send the MMC CMD1 to specify the operating voltage. CMD1 causes
|
||||||
* transition to ready state/ card-identification mode. NOTE: If the
|
* transition to ready state/ card-identification mode. NOTE: If the
|
||||||
@@ -2988,7 +3265,7 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv)
|
|||||||
* go back to the standby state).
|
* go back to the standby state).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
mmcsd_sendcmdpoll(priv, MMC_CMD1, MMCSD_VDD_33_34);
|
mmcsd_sendcmdpoll(priv, MMC_CMD1, MMCSD_VDD_33_34 | mmccapacity);
|
||||||
ret = SDIO_RECVR3(priv->dev, MMC_CMD1, &response);
|
ret = SDIO_RECVR3(priv->dev, MMC_CMD1, &response);
|
||||||
|
|
||||||
/* Was the operating range set successfully */
|
/* Was the operating range set successfully */
|
||||||
@@ -3001,9 +3278,22 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv)
|
|||||||
{
|
{
|
||||||
/* CMD1 succeeded... this must be an MMC card */
|
/* CMD1 succeeded... this must be an MMC card */
|
||||||
|
|
||||||
finfo("CMD1 succeeded, assuming MMC card\n");
|
|
||||||
priv->type = MMCSD_CARDTYPE_MMC;
|
priv->type = MMCSD_CARDTYPE_MMC;
|
||||||
|
|
||||||
|
/* Now, check if this is a MMC card/chip that supports block
|
||||||
|
* addressing
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((response & MMCSD_R3_HIGHCAPACITY) != 0)
|
||||||
|
{
|
||||||
|
mmccapacity = MMCSD_R3_HIGHCAPACITY;
|
||||||
|
priv->type |= MMCSD_CARDTYPE_BLOCK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mmccapacity = MMCSD_R3_STDCAPACITY;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if the card is busy. Very confusing, BUSY is set LOW
|
/* Check if the card is busy. Very confusing, BUSY is set LOW
|
||||||
* if the card has not finished its initialization, so it really
|
* if the card has not finished its initialization, so it really
|
||||||
* means NOT busy.
|
* means NOT busy.
|
||||||
@@ -3018,6 +3308,7 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv)
|
|||||||
* Then break out of the look with an MMC card identified
|
* Then break out of the look with an MMC card identified
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
finfo("MMC card/chip ready!\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3101,18 +3392,34 @@ static int mmcsd_probe(FAR struct mmcsd_state_s *priv)
|
|||||||
|
|
||||||
switch (priv->type)
|
switch (priv->type)
|
||||||
{
|
{
|
||||||
case MMCSD_CARDTYPE_SDV1: /* Bit 1: SD version 1.x */
|
/* Bit 1: SD version 1.x */
|
||||||
case MMCSD_CARDTYPE_SDV2: /* SD version 2.x with byte addressing */
|
|
||||||
case MMCSD_CARDTYPE_SDV2 | MMCSD_CARDTYPE_BLOCK: /* SD version 2.x with block addressing */
|
case MMCSD_CARDTYPE_SDV1:
|
||||||
|
|
||||||
|
/* SD version 2.x with byte addressing */
|
||||||
|
|
||||||
|
case MMCSD_CARDTYPE_SDV2:
|
||||||
|
|
||||||
|
/* SD version 2.x with block addressing */
|
||||||
|
|
||||||
|
case MMCSD_CARDTYPE_SDV2 | MMCSD_CARDTYPE_BLOCK:
|
||||||
ret = mmcsd_sdinitialize(priv);
|
ret = mmcsd_sdinitialize(priv);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MMCSD_CARDTYPE_MMC: /* MMC card */
|
/* MMC card with byte addressing */
|
||||||
|
|
||||||
|
case MMCSD_CARDTYPE_MMC:
|
||||||
|
|
||||||
|
/* MMC card with block addressing */
|
||||||
|
|
||||||
|
case MMCSD_CARDTYPE_MMC | MMCSD_CARDTYPE_BLOCK:
|
||||||
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
||||||
ret = mmcsd_mmcinitialize(priv);
|
ret = mmcsd_mmcinitialize(priv);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case MMCSD_CARDTYPE_UNKNOWN: /* Unknown card type */
|
/* Unknown card type */
|
||||||
|
|
||||||
|
case MMCSD_CARDTYPE_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
ferr("ERROR: Internal confusion: %d\n", priv->type);
|
ferr("ERROR: Internal confusion: %d\n", priv->type);
|
||||||
ret = -EPERM;
|
ret = -EPERM;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/********************************************************************************************
|
/********************************************************************************************
|
||||||
* drivers/mmcsd/mmcsd_sdio.h
|
* drivers/mmcsd/mmcsd_sdio.h
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2009, 2011, 2019 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -150,6 +150,7 @@
|
|||||||
#define MMCSD_VDD_35_36 ((uint32_t)1 << 23) /* VDD voltage 3.5-3.6 */
|
#define MMCSD_VDD_35_36 ((uint32_t)1 << 23) /* VDD voltage 3.5-3.6 */
|
||||||
#define MMCSD_R3_HIGHCAPACITY ((uint32_t)1 << 30) /* true: Card supports block addressing */
|
#define MMCSD_R3_HIGHCAPACITY ((uint32_t)1 << 30) /* true: Card supports block addressing */
|
||||||
#define MMCSD_CARD_BUSY ((uint32_t)1 << 31) /* Card power-up busy bit */
|
#define MMCSD_CARD_BUSY ((uint32_t)1 << 31) /* Card power-up busy bit */
|
||||||
|
#define MMCSD_R3_STDCAPACITY ((uint32_t)0)
|
||||||
|
|
||||||
/* R6 Card Status bit definitions */
|
/* R6 Card Status bit definitions */
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* include/nuttx/sdio.h
|
* include/nuttx/sdio.h
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009, 2011-2013, 2017 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2009, 2011-2013, 2017, 2019 Gregory Nutt. All rights
|
||||||
|
* reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -118,8 +119,9 @@
|
|||||||
# define MMCSD_CMDIDX6 6 /* HS_SWITCH: Checks switchable function */
|
# define MMCSD_CMDIDX6 6 /* HS_SWITCH: Checks switchable function */
|
||||||
# define MMCSD_CMDIDX7 7 /* SELECT/DESELECT CARD
|
# define MMCSD_CMDIDX7 7 /* SELECT/DESELECT CARD
|
||||||
* -Addressed Command, R1 response 31:16=RCA */
|
* -Addressed Command, R1 response 31:16=RCA */
|
||||||
# define SD_CMDIDX8 8 /* IF_COND: Sends SD Memory Card interface condition
|
# define MMCSD_CMDIDX8 8 /* SD: IF_COND: Sends SD Memory Card interface condition
|
||||||
* R7 response */
|
* R7 response;
|
||||||
|
* MMC: get extended CSD register 512 bytes R1 response */
|
||||||
# define MMCSD_CMDIDX9 9 /* SEND_CSD: Asks card to send its card specific data (CSD)
|
# define MMCSD_CMDIDX9 9 /* SEND_CSD: Asks card to send its card specific data (CSD)
|
||||||
* -Addressed Command, R2 response 31:16=RCA */
|
* -Addressed Command, R2 response 31:16=RCA */
|
||||||
# define MMCSD_CMDIDX10 10 /* SEND_CID: Asks card to send its card identification (CID)
|
# define MMCSD_CMDIDX10 10 /* SEND_CID: Asks card to send its card identification (CID)
|
||||||
@@ -274,7 +276,8 @@
|
|||||||
#define MMCSD_CMD6 (MMCSD_CMDIDX6 |MMCSD_R1_RESPONSE |MMCSD_RDDATAXFR)
|
#define MMCSD_CMD6 (MMCSD_CMDIDX6 |MMCSD_R1_RESPONSE |MMCSD_RDDATAXFR)
|
||||||
#define MMCSD_CMD7S (MMCSD_CMDIDX7 |MMCSD_R1B_RESPONSE|MMCSD_NODATAXFR)
|
#define MMCSD_CMD7S (MMCSD_CMDIDX7 |MMCSD_R1B_RESPONSE|MMCSD_NODATAXFR)
|
||||||
#define MMCSD_CMD7D (MMCSD_CMDIDX7 |MMCSD_NO_RESPONSE |MMCSD_NODATAXFR) /* No response when de-selecting card */
|
#define MMCSD_CMD7D (MMCSD_CMDIDX7 |MMCSD_NO_RESPONSE |MMCSD_NODATAXFR) /* No response when de-selecting card */
|
||||||
#define SD_CMD8 (SD_CMDIDX8 |MMCSD_R7_RESPONSE |MMCSD_NODATAXFR)
|
#define SD_CMD8 (MMCSD_CMDIDX8 |MMCSD_R7_RESPONSE |MMCSD_NODATAXFR)
|
||||||
|
#define MMC_CMD8 (MMCSD_CMDIDX8 |MMCSD_R1_RESPONSE |MMCSD_RDDATAXFR)
|
||||||
#define MMCSD_CMD9 (MMCSD_CMDIDX9 |MMCSD_R2_RESPONSE |MMCSD_NODATAXFR)
|
#define MMCSD_CMD9 (MMCSD_CMDIDX9 |MMCSD_R2_RESPONSE |MMCSD_NODATAXFR)
|
||||||
#define MMCSD_CMD10 (MMCSD_CMDIDX10|MMCSD_R2_RESPONSE |MMCSD_NODATAXFR)
|
#define MMCSD_CMD10 (MMCSD_CMDIDX10|MMCSD_R2_RESPONSE |MMCSD_NODATAXFR)
|
||||||
#define MMC_CMD11 (MMC_CMDIDX11 |MMCSD_R1_RESPONSE |MMCSD_RDSTREAM )
|
#define MMC_CMD11 (MMC_CMDIDX11 |MMCSD_R1_RESPONSE |MMCSD_RDSTREAM )
|
||||||
|
|||||||
Reference in New Issue
Block a user