[U-Boot] [RFC 1/3] mmc: checking status after commands with R1b response
Raffaele Recalcati
lamiaposta71 at gmail.com
Wed Mar 9 17:51:16 CET 2011
From: Raffaele Recalcati <raffaele.recalcati at bticino.it>
It is a recommended to check card status after these kind of commands.
This is done using CMD13 (SEND_STATUS) JEDEC command.
In case of error the previous command is issued again.
Signed-off-by: Raffaele Recalcati <raffaele.recalcati at bticino.it>
---
drivers/mmc/mmc.c | 106 +++++++++++++++++++++++++++++++++++++++--------------
include/mmc.h | 4 ++
2 files changed, 82 insertions(+), 28 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6805b33..53ed36f 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -48,6 +48,32 @@ 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)
+{
+ struct mmc_cmd cmd;
+ int err;
+ int timeout = 1000;
+ int status;
+
+ 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;
+ udelay(1000);
+ if (cmd.response[0] & MMC_STATUS_MASK) {
+ printf("Status Error: 0x%08X\n", cmd.response[0]);
+ return 1;
+ }
+ } while (!(cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && timeout--);
+
+ return 0;
+}
+
int mmc_set_blocklen(struct mmc *mmc, int len)
{
struct mmc_cmd cmd;
@@ -82,6 +108,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",
@@ -113,14 +140,22 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
}
if (blkcnt > 1) {
- cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
- cmd.cmdarg = 0;
- cmd.resp_type = MMC_RSP_R1b;
- cmd.flags = 0;
- if (mmc_send_cmd(mmc, &cmd, NULL)) {
- printf("mmc fail to send stop cmd\n");
- return 0;
- }
+ do {
+ cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.flags = 0;
+ if (mmc_send_cmd(mmc, &cmd, NULL)) {
+ printf("mmc fail to send stop cmd\n");
+ return 0;
+ }
+
+ udelay(1000);
+
+ } while (mmc_send_status(mmc) && timeout--);
+
+ if (!timeout)
+ printf("mmc send status failed\n");
}
return blkcnt;
@@ -158,6 +193,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;
@@ -181,14 +217,17 @@ int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt)
return 0;
if (blkcnt > 1) {
- cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
- cmd.cmdarg = 0;
- cmd.resp_type = MMC_RSP_R1b;
- cmd.flags = 0;
- if (mmc_send_cmd(mmc, &cmd, NULL)) {
- printf("mmc fail to send stop cmd\n");
- return 0;
- }
+ do {
+ cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.flags = 0;
+ if (mmc_send_cmd(mmc, &cmd, NULL)) {
+ printf("mmc fail to send stop cmd\n");
+ return 0;
+ }
+ udelay(1000);
+ } while (mmc_send_status(mmc) && timeout--);
}
return blkcnt;
@@ -369,15 +408,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);
- cmd.flags = 0;
+ do {
+ cmd.cmdidx = MMC_CMD_SWITCH;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (index << 16) |
+ (value << 8);
+ cmd.flags = 0;
+
+ ret = mmc_send_cmd(mmc, &cmd, NULL);
+ udelay(1000);
+ } while (mmc_send_status(mmc) && timeout--);
+
+ return ret;
- return mmc_send_cmd(mmc, &cmd, NULL);
}
int mmc_change_freq(struct mmc *mmc)
@@ -610,6 +657,7 @@ int mmc_startup(struct mmc *mmc)
u64 cmult, csize;
struct mmc_cmd cmd;
char ext_csd[512];
+ int timeout = 1000;
/* Put the Card in Identify Mode */
cmd.cmdidx = MMC_CMD_ALL_SEND_CID;
@@ -716,11 +764,13 @@ int mmc_startup(struct mmc *mmc)
mmc->write_bl_len = 512;
/* Select the card, and put it into Transfer Mode */
- cmd.cmdidx = MMC_CMD_SELECT_CARD;
- cmd.resp_type = MMC_RSP_R1b;
- cmd.cmdarg = mmc->rca << 16;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
+ do {
+ cmd.cmdidx = MMC_CMD_SELECT_CARD;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = mmc->rca << 16;
+ cmd.flags = 0;
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ } while (mmc_send_status(mmc) && timeout--);
if (err)
return err;
diff --git a/include/mmc.h b/include/mmc.h
index fcd0fd1..4ee8e1c 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -94,6 +94,10 @@
#define OCR_BUSY 0x80000000
#define OCR_HCS 0x40000000
+#define MMC_STATUS_MASK (~0x0206BF7F)
+#define MMC_STATUS_RDY_FOR_DATA (1<<8)
+#define MMC_STATUS_CURR_STATE (0xf<<9)
+
#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
--
1.7.0.4
More information about the U-Boot
mailing list