[U-Boot] [PATCH 0/2] mmc: card status polling fixes

Hi,
These are two patches for some card status polling issues that we ran across lately. The first patch fixes single block writes to cards because the card status was not always checked (only for multi block writes). Also, if the card status could not be obtained, the error was not propagated upwards.
The second patch aligns the status polling with the Linux kernel (retrying the command five times) to make it more robust...
Regards, Jan Kloetzke

A MMC/SD card may always go into the programming state (and hence be busy) after a block write. Therefore always check the card state, even after single block writes. On the other hand there is no need to check the card status after a read.
Also make sure that errors during busy polling are propagated upwards.
Signed-off-by: Jan Kloetzke jan.kloetzke@dspg.com Cc: Andy Fleming afleming@gmail.com --- drivers/mmc/mmc.c | 14 ++++++-------- 1 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 6db37b1..7b09272 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -305,11 +305,12 @@ 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); }
+ /* Waiting for the ready status */ + if (mmc_send_status(mmc, timeout)) + return 0; + return blkcnt; }
@@ -341,7 +342,6 @@ 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; @@ -373,9 +373,6 @@ 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; @@ -610,7 +607,8 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) ret = mmc_send_cmd(mmc, &cmd, NULL);
/* Waiting for the ready status */ - mmc_send_status(mmc, timeout); + if (!ret) + ret = mmc_send_status(mmc, timeout);
return ret;

Align the card status polling with the Linux kernel and retry the command at least five times. Also some cards apparently mishandle the status bits, so make sure to check the card state too.
Signed-off-by: Jan Kloetzke jan.kloetzke@dspg.com Cc: Andy Fleming afleming@gmail.com --- drivers/mmc/mmc.c | 20 ++++++++++++-------- include/mmc.h | 2 ++ 2 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 7b09272..49c3349 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -108,7 +108,7 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) int mmc_send_status(struct mmc *mmc, int timeout) { struct mmc_cmd cmd; - int err; + int err, retries = 5; #ifdef CONFIG_MMC_TRACE int status; #endif @@ -121,17 +121,21 @@ int mmc_send_status(struct mmc *mmc, int timeout)
do { err = mmc_send_cmd(mmc, &cmd, NULL); - if (err) + if (!err) { + if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && + (cmd.response[0] & MMC_STATUS_CURR_STATE) != + MMC_STATE_PRG) + break; + else if (cmd.response[0] & MMC_STATUS_MASK) { + printf("Status Error: 0x%08X\n", + cmd.response[0]); + return COMM_ERR; + } + } else if (--retries < 0) 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--);
#ifdef CONFIG_MMC_TRACE diff --git a/include/mmc.h b/include/mmc.h index 8744604..30c2375 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -112,6 +112,8 @@ #define MMC_STATUS_CURR_STATE (0xf << 9) #define MMC_STATUS_ERROR (1 << 19)
+#define MMC_STATE_PRG (7 << 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 */
participants (1)
-
Jan Kloetzke