From: Raffaele Recalcati <raffaele.recalc...@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.recalc...@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

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to