diff options
author | Raffaele Recalcati <raffaele.recalcati@bticino.it> | 2011-03-11 02:01:12 +0000 |
---|---|---|
committer | Andy Fleming <afleming@freescale.com> | 2011-04-13 07:08:57 -0500 |
commit | 5d4fc8d907ed12844b9c9190601fef2919f3ec25 (patch) | |
tree | 20c8c639facdd3ecfbe87d54880b400b68e8981a /drivers/mmc | |
parent | 8baf939c2c5e0eb1f3d0cba1067e069e199cbf7f (diff) | |
download | u-boot-5d4fc8d907ed12844b9c9190601fef2919f3ec25.zip u-boot-5d4fc8d907ed12844b9c9190601fef2919f3ec25.tar.gz u-boot-5d4fc8d907ed12844b9c9190601fef2919f3ec25.tar.bz2 |
mmc: checking status after commands with R1b response
It is recommended to check card status after these kind of commands.
This is done using CMD13 (SEND_STATUS) JEDEC command until
the card is ready.
In case of error the card status field is displayed.
Signed-off-by: Raffaele Recalcati <raffaele.recalcati@bticino.it>
Signed-off-by: Andy Fleming <afleming@freescale.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/mmc.c | 62 |
1 files changed, 59 insertions, 3 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 41c28d4..3d445c0 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -52,6 +52,42 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) return mmc->send_cmd(mmc, cmd, data); } +int mmc_send_status(struct mmc *mmc, int timeout) +{ + struct mmc_cmd cmd; + int err; +#ifdef CONFIG_MMC_TRACE + int status; +#endif + + cmd.cmdidx = MMC_CMD_SEND_STATUS; + cmd.resp_type = MMC_RSP_R1; + cmd.cmdarg = 0; + cmd.flags = 0; + + do { + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) + return err; + else if (cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) + break; + + udelay(1000); + + if (cmd.response[0] & MMC_STATUS_MASK) { + printf("Status Error: 0x%08X\n", cmd.response[0]); + return COMM_ERR; + } + } while (timeout--); + + if (!timeout) { + printf("Timeout waiting card ready\n"); + return TIMEOUT; + } + + return 0; +} + int mmc_set_blocklen(struct mmc *mmc, int len) { struct mmc_cmd cmd; @@ -86,6 +122,7 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src) { struct mmc_cmd cmd; struct mmc_data data; + int timeout = 1000; if ((start + blkcnt) > mmc->block_dev.lba) { printf("MMC: block number 0x%lx exceeds max(0x%lx)\n", @@ -128,6 +165,9 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src) printf("mmc fail to send stop cmd\n"); return 0; } + + /* Waiting for the ready status */ + mmc_send_status(mmc, timeout); } return blkcnt; @@ -162,6 +202,7 @@ int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt) { struct mmc_cmd cmd; struct mmc_data data; + int timeout = 1000; if (blkcnt > 1) cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; @@ -193,6 +234,9 @@ int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt) printf("mmc fail to send stop cmd\n"); return 0; } + + /* Waiting for the ready status */ + mmc_send_status(mmc, timeout); } return blkcnt; @@ -396,15 +440,23 @@ int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd) int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) { struct mmc_cmd cmd; + int timeout = 1000; + int ret; cmd.cmdidx = MMC_CMD_SWITCH; cmd.resp_type = MMC_RSP_R1b; cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | - (index << 16) | - (value << 8); + (index << 16) | + (value << 8); cmd.flags = 0; - return mmc_send_cmd(mmc, &cmd, NULL); + ret = mmc_send_cmd(mmc, &cmd, NULL); + + /* Waiting for the ready status */ + mmc_send_status(mmc, timeout); + + return ret; + } int mmc_change_freq(struct mmc *mmc) @@ -643,6 +695,7 @@ int mmc_startup(struct mmc *mmc) u64 cmult, csize; struct mmc_cmd cmd; char ext_csd[512]; + int timeout = 1000; #ifdef CONFIG_MMC_SPI_CRC_ON if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ @@ -699,6 +752,9 @@ int mmc_startup(struct mmc *mmc) err = mmc_send_cmd(mmc, &cmd, NULL); + /* Waiting for the ready status */ + mmc_send_status(mmc, timeout); + if (err) return err; |