diff mbox

[U-Boot,RFC,1/3] mmc: checking status after commands with R1b response

Message ID 1299689478-22747-2-git-send-email-lamiaposta71@gmail.com
State Superseded, archived
Headers show

Commit Message

Raffaele Recalcati March 9, 2011, 4:51 p.m. UTC
From: Raffaele Recalcati <raffaele.recalcati@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@bticino.it>
---
 drivers/mmc/mmc.c |  106 +++++++++++++++++++++++++++++++++++++++--------------
 include/mmc.h     |    4 ++
 2 files changed, 82 insertions(+), 28 deletions(-)

Comments

Lei Wen March 10, 2011, 7:45 a.m. UTC | #1
Hi Raffaele,

On Thu, Mar 10, 2011 at 12:51 AM, Raffaele Recalcati
<lamiaposta71@gmail.com> wrote:
> From: Raffaele Recalcati <raffaele.recalcati@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@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--);

I apply your patch and test on my board and find this patch mess my sd card...
Why you need to keep send the stop command (Also the other command in
this patch)
if mmc_send_status fail? As my understanding, the command should only send once,
and then start to call the mmc_send_status till the status stable.

This is also what kernel does. You could refer to
drivers/mmc/core/mmc_ops.c in the linux kernel.

Best regards,
Lei
Raffaele Recalcati March 10, 2011, 1:37 p.m. UTC | #2
Hi Lei,

> I apply your patch and test on my board and find this patch mess my sd card...

Can't you trace the behaviour using the latest patch and send the
results to me ?

> Why you need to keep send the stop command (Also the other command in
> this patch)
> if mmc_send_status fail? As my understanding, the command should only send once,
> and then start to call the mmc_send_status till the status stable.

Right.
I was confused by the possibility to use mmc_send_status to redo also
other kind of commands,
for example write_block, in the case that the write can go wrong (due
to ECC inner nand failure).

> This is also what kernel does. You could refer to
> drivers/mmc/core/mmc_ops.c in the linux kernel.

I'll change every mmc_send_status call in order only to wait that the
new state is stable.
I can do in about two hours.

Thx for your help,
Raffaele
diff mbox

Patch

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 */