[U-Boot] [RFC 0/3][v2] mmc inizialization steps enhanced

I have added some better inizializations and status check. I have created following patchset for Davinci dm365 against git://arago-project.org/git/projects/u-boot-davinci.git git tree. There are two commits more in that tree, but they are not in conflict with my work. I have finally tested this series on basi board, based on Davinci dm365, that contains an eMMC device.
Raffaele Recalcati (3): mmc: checking status after commands with R1b response mmc: SEND_OP_COND considers card capabilities (voltage) mmc: trace added
drivers/mmc/mmc.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++-- include/mmc.h | 6 ++ 2 files changed, 149 insertions(+), 5 deletions(-)

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 card status field is displayed.
Signed-off-by: Raffaele Recalcati raffaele.recalcati@bticino.it --- It is not clear what should nice to do in case of status error. Maybe it can happen only in case of hw failure.
drivers/mmc/mmc.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++-- include/mmc.h | 4 +++ 2 files changed, 57 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 6805b33..042653f 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -48,6 +48,36 @@ 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; + 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); + break; + 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--); + + return 0; +} + int mmc_set_blocklen(struct mmc *mmc, int len) { struct mmc_cmd cmd; @@ -82,6 +112,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", @@ -121,6 +152,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, 1000); }
return blkcnt; @@ -158,6 +192,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; @@ -189,6 +224,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, 1000); }
return blkcnt; @@ -369,15 +407,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, 1000); + + return ret; + }
int mmc_change_freq(struct mmc *mmc) @@ -610,6 +656,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; @@ -722,6 +769,9 @@ int mmc_startup(struct mmc *mmc) cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL);
+ /* Waiting for the ready status */ + mmc_send_status(mmc, 1000); + 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 */

Hi Raffaele,
On Thu, Mar 10, 2011 at 11:43 PM, 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 card status field is displayed.
Signed-off-by: Raffaele Recalcati raffaele.recalcati@bticino.it
It is not clear what should nice to do in case of status error. Maybe it can happen only in case of hw failure.
drivers/mmc/mmc.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++-- include/mmc.h | 4 +++ 2 files changed, 57 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 6805b33..042653f 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -48,6 +48,36 @@ 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;
- 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);
- break;
- 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--);
- return 0;
+}
int mmc_set_blocklen(struct mmc *mmc, int len) { struct mmc_cmd cmd; @@ -82,6 +112,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", @@ -121,6 +152,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, 1000);
}
return blkcnt; @@ -158,6 +192,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; @@ -189,6 +224,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, 1000);
}
return blkcnt; @@ -369,15 +407,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, 1000);
- return ret;
}
int mmc_change_freq(struct mmc *mmc) @@ -610,6 +656,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; @@ -722,6 +769,9 @@ int mmc_startup(struct mmc *mmc) cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL);
- /* Waiting for the ready status */
- mmc_send_status(mmc, 1000);
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
It works on my board now. :)
Best regards, Lei

From: Raffaele Recalcati raffaele.recalcati@bticino.it
The first SEND_OP_COND (CMD1) is used only to ask card capabilities, waiting that the card is not busy. After it, an AND operation is done between card capabilities and host capabilities, (at the moment only for the voltage field). Finally the correct value is sent to the MMC.
Signed-off-by: Raffaele Recalcati raffaele.recalcati@bticino.it --- drivers/mmc/mmc.c | 21 +++++++++++++++++++-- include/mmc.h | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 042653f..ded630b 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -347,17 +347,34 @@ sd_send_op_cond(struct mmc *mmc)
int mmc_send_op_cond(struct mmc *mmc) { - int timeout = 1000; + int timeout = 10000; struct mmc_cmd cmd; int err;
/* Some cards seem to need this */ mmc_go_idle(mmc);
+ /* Asking to the card its capabilities */ + do { + cmd.cmdidx = MMC_CMD_SEND_OP_COND; + cmd.resp_type = MMC_RSP_R3; + cmd.cmdarg = 0; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + udelay(1000); + } while (!(cmd.response[0] & OCR_BUSY) && timeout--); + do { cmd.cmdidx = MMC_CMD_SEND_OP_COND; cmd.resp_type = MMC_RSP_R3; - cmd.cmdarg = OCR_HCS | mmc->voltages; + cmd.cmdarg = ((mmc->voltages & + (cmd.response[0] & OCR_VOLTAGE_MASK)) | + (cmd.response[0] & OCR_ACCESS_MODE)); cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL); diff --git a/include/mmc.h b/include/mmc.h index 4ee8e1c..d18526d 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -93,6 +93,8 @@
#define OCR_BUSY 0x80000000 #define OCR_HCS 0x40000000 +#define OCR_VOLTAGE_MASK 0x007FFF80 +#define OCR_ACCESS_MODE 0x60000000
#define MMC_STATUS_MASK (~0x0206BF7F) #define MMC_STATUS_RDY_FOR_DATA (1<<8)

Hi Raffaele,
On Thu, Mar 10, 2011 at 11:43 PM, Raffaele Recalcati lamiaposta71@gmail.com wrote:
From: Raffaele Recalcati raffaele.recalcati@bticino.it
The first SEND_OP_COND (CMD1) is used only to ask card capabilities, waiting that the card is not busy. After it, an AND operation is done between card capabilities and host capabilities, (at the moment only for the voltage field). Finally the correct value is sent to the MMC.
Signed-off-by: Raffaele Recalcati raffaele.recalcati@bticino.it
drivers/mmc/mmc.c | 21 +++++++++++++++++++-- include/mmc.h | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 042653f..ded630b 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -347,17 +347,34 @@ sd_send_op_cond(struct mmc *mmc)
int mmc_send_op_cond(struct mmc *mmc) {
- int timeout = 1000;
- int timeout = 10000;
struct mmc_cmd cmd; int err;
/* Some cards seem to need this */ mmc_go_idle(mmc);
- /* Asking to the card its capabilities */
- do {
- cmd.cmdidx = MMC_CMD_SEND_OP_COND;
- cmd.resp_type = MMC_RSP_R3;
- cmd.cmdarg = 0;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- udelay(1000);
- } while (!(cmd.response[0] & OCR_BUSY) && timeout--);
I think you should not put the first probe a multi-time. In linux framework, it would skip the first probing.
I test with this patch and fail to detect my emmc card... While just let the first probe once, it works fine.
Best regards, Lei

On Thu, Mar 10, 2011 at 5:29 PM, Lei Wen adrian.wenl@gmail.com wrote:
Hi Raffaele,
On Thu, Mar 10, 2011 at 11:43 PM, Raffaele Recalcati lamiaposta71@gmail.com wrote:
From: Raffaele Recalcati raffaele.recalcati@bticino.it
The first SEND_OP_COND (CMD1) is used only to ask card capabilities, waiting that the card is not busy. After it, an AND operation is done between card capabilities and host capabilities, (at the moment only for the voltage field). Finally the correct value is sent to the MMC.
Signed-off-by: Raffaele Recalcati raffaele.recalcati@bticino.it
drivers/mmc/mmc.c | 21 +++++++++++++++++++-- include/mmc.h | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 042653f..ded630b 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -347,17 +347,34 @@ sd_send_op_cond(struct mmc *mmc)
int mmc_send_op_cond(struct mmc *mmc) {
- int timeout = 1000;
- int timeout = 10000;
struct mmc_cmd cmd; int err;
/* Some cards seem to need this */ mmc_go_idle(mmc);
- /* Asking to the card its capabilities */
- do {
- cmd.cmdidx = MMC_CMD_SEND_OP_COND;
- cmd.resp_type = MMC_RSP_R3;
- cmd.cmdarg = 0;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- udelay(1000);
- } while (!(cmd.response[0] & OCR_BUSY) && timeout--);
I think you should not put the first probe a multi-time. In linux framework, it would skip the first probing.
I test with this patch and fail to detect my emmc card... While just let the first probe once, it works fine.
Best regards, Lei
Look at JEDEC Standard No. 84-A441 document at page 190. It is normal to ask the card capabilities before setting. But I understand also that in your case there is some issue. I'm sorry, what does "multi-time" mean?
Thx, Raffaele

On Fri, Mar 11, 2011 at 12:59 AM, Raffaele Recalcati lamiaposta71@gmail.com wrote:
On Thu, Mar 10, 2011 at 5:29 PM, Lei Wen adrian.wenl@gmail.com wrote:
Hi Raffaele,
On Thu, Mar 10, 2011 at 11:43 PM, Raffaele Recalcati lamiaposta71@gmail.com wrote:
From: Raffaele Recalcati raffaele.recalcati@bticino.it
The first SEND_OP_COND (CMD1) is used only to ask card capabilities, waiting that the card is not busy. After it, an AND operation is done between card capabilities and host capabilities, (at the moment only for the voltage field). Finally the correct value is sent to the MMC.
Signed-off-by: Raffaele Recalcati raffaele.recalcati@bticino.it
drivers/mmc/mmc.c | 21 +++++++++++++++++++-- include/mmc.h | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 042653f..ded630b 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -347,17 +347,34 @@ sd_send_op_cond(struct mmc *mmc)
int mmc_send_op_cond(struct mmc *mmc) {
- int timeout = 1000;
- int timeout = 10000;
struct mmc_cmd cmd; int err;
/* Some cards seem to need this */ mmc_go_idle(mmc);
- /* Asking to the card its capabilities */
- do {
- cmd.cmdidx = MMC_CMD_SEND_OP_COND;
- cmd.resp_type = MMC_RSP_R3;
- cmd.cmdarg = 0;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- udelay(1000);
- } while (!(cmd.response[0] & OCR_BUSY) && timeout--);
I think you should not put the first probe a multi-time. In linux framework, it would skip the first probing.
I test with this patch and fail to detect my emmc card... While just let the first probe once, it works fine.
Best regards, Lei
Look at JEDEC Standard No. 84-A441 document at page 190. It is normal to ask the card capabilities before setting. But I understand also that in your case there is some issue. I'm sorry, what does "multi-time" mean?
I mean on my board I cannot get (!(cmd.response[0] & OCR_BUSY) to be true for the first MMC_CMD_SEND_OP_COND until its timeout, which lead to card init fail.
Best regards, Lei

On Fri, Mar 11, 2011 at 4:14 AM, Lei Wen adrian.wenl@gmail.com wrote:
On Fri, Mar 11, 2011 at 12:59 AM, Raffaele Recalcati lamiaposta71@gmail.com wrote:
On Thu, Mar 10, 2011 at 5:29 PM, Lei Wen adrian.wenl@gmail.com wrote:
Hi Raffaele,
On Thu, Mar 10, 2011 at 11:43 PM, Raffaele Recalcati lamiaposta71@gmail.com wrote:
From: Raffaele Recalcati raffaele.recalcati@bticino.it
The first SEND_OP_COND (CMD1) is used only to ask card capabilities, waiting that the card is not busy. After it, an AND operation is done between card capabilities and host capabilities, (at the moment only for the voltage field). Finally the correct value is sent to the MMC.
Signed-off-by: Raffaele Recalcati raffaele.recalcati@bticino.it
drivers/mmc/mmc.c | 21 +++++++++++++++++++-- include/mmc.h | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 042653f..ded630b 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -347,17 +347,34 @@ sd_send_op_cond(struct mmc *mmc)
int mmc_send_op_cond(struct mmc *mmc) {
- int timeout = 1000;
- int timeout = 10000;
struct mmc_cmd cmd; int err;
/* Some cards seem to need this */ mmc_go_idle(mmc);
- /* Asking to the card its capabilities */
- do {
- cmd.cmdidx = MMC_CMD_SEND_OP_COND;
- cmd.resp_type = MMC_RSP_R3;
- cmd.cmdarg = 0;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- udelay(1000);
- } while (!(cmd.response[0] & OCR_BUSY) && timeout--);
I think you should not put the first probe a multi-time. In linux framework, it would skip the first probing.
I test with this patch and fail to detect my emmc card... While just let the first probe once, it works fine.
Best regards, Lei
Look at JEDEC Standard No. 84-A441 document at page 190. It is normal to ask the card capabilities before setting. But I understand also that in your case there is some issue. I'm sorry, what does "multi-time" mean?
I mean on my board I cannot get (!(cmd.response[0] & OCR_BUSY) to be true for the first MMC_CMD_SEND_OP_COND until its timeout, which lead to card init fail.
Best regards, Lei
This means 10msec are not enough. Even if a board dependent value should be better, can you find please the minimum value that it nice for your board? With this value I'll resend the updated patch. Can you also please test the trace patch (the third one), I think it is quite useful to discover hw related problems. Sorry for having sent a not nice patchset (two PATCH and one RFC).
Regards, Raffaele

Hi Raffaele,
On Fri, Mar 11, 2011 at 2:30 PM, Raffaele Recalcati lamiaposta71@gmail.com wrote:
On Fri, Mar 11, 2011 at 4:14 AM, Lei Wen adrian.wenl@gmail.com wrote:
On Fri, Mar 11, 2011 at 12:59 AM, Raffaele Recalcati lamiaposta71@gmail.com wrote:
On Thu, Mar 10, 2011 at 5:29 PM, Lei Wen adrian.wenl@gmail.com wrote:
Hi Raffaele,
On Thu, Mar 10, 2011 at 11:43 PM, Raffaele Recalcati lamiaposta71@gmail.com wrote:
From: Raffaele Recalcati raffaele.recalcati@bticino.it
The first SEND_OP_COND (CMD1) is used only to ask card capabilities, waiting that the card is not busy. After it, an AND operation is done between card capabilities and host capabilities, (at the moment only for the voltage field). Finally the correct value is sent to the MMC.
Signed-off-by: Raffaele Recalcati raffaele.recalcati@bticino.it
drivers/mmc/mmc.c | 21 +++++++++++++++++++-- include/mmc.h | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 042653f..ded630b 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -347,17 +347,34 @@ sd_send_op_cond(struct mmc *mmc)
int mmc_send_op_cond(struct mmc *mmc) {
- int timeout = 1000;
- int timeout = 10000;
struct mmc_cmd cmd; int err;
/* Some cards seem to need this */ mmc_go_idle(mmc);
- /* Asking to the card its capabilities */
- do {
- cmd.cmdidx = MMC_CMD_SEND_OP_COND;
- cmd.resp_type = MMC_RSP_R3;
- cmd.cmdarg = 0;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- udelay(1000);
- } while (!(cmd.response[0] & OCR_BUSY) && timeout--);
I think you should not put the first probe a multi-time. In linux framework, it would skip the first probing.
I test with this patch and fail to detect my emmc card... While just let the first probe once, it works fine.
Best regards, Lei
Look at JEDEC Standard No. 84-A441 document at page 190. It is normal to ask the card capabilities before setting. But I understand also that in your case there is some issue. I'm sorry, what does "multi-time" mean?
I mean on my board I cannot get (!(cmd.response[0] & OCR_BUSY) to be true for the first MMC_CMD_SEND_OP_COND until its timeout, which lead to card init fail.
Best regards, Lei
This means 10msec are not enough. Even if a board dependent value should be better, can you find please the minimum value that it nice for your board?
It is not about the delay, it is about you shouldn't let the probe perform multi-times. As you also mention the JESD84-A44 doc, you could see the query mode only perform _ONCE_, then continue to send SEND_OP_COND till card accept that.
So my point is that: in this patch, you shouldn't add a do{} while for the first query. Please remove it. As I test, my board works fine with the do{} while remove.
Best regards, Lei

From: Raffaele Recalcati raffaele.recalcati@bticino.it
Defining CONFIG_MMC_TRACE in the include board file it is possible to activate a tracing support. This code helps in case of eMMC hw failure or to investigate possible eMMC initialization issues.
Signed-off-by: Raffaele Recalcati raffaele.recalcati@bticino.it --- drivers/mmc/mmc.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 71 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index ded630b..a70801f 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -45,7 +45,60 @@ int board_mmc_getcd(u8 *cd, struct mmc *mmc)__attribute__((weak,
int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { +#ifdef CONFIG_MMC_TRACE + int ret; + int i; + u8 *ptr; + + printf("CMD_SEND:%d\n", cmd->cmdidx); + printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); + printf("\t\tFLAG\t\t\t %d\n", cmd->flags); + ret = mmc->send_cmd(mmc, cmd, data); + switch (cmd->resp_type) { + case MMC_RSP_NONE: + printf("\t\tMMC_RSP_NONE\n"); + break; + case MMC_RSP_R1: + printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", + cmd->response[0]); + break; + case MMC_RSP_R1b: + printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", + cmd->response[0]); + break; + case MMC_RSP_R2: + printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", + cmd->response[0]); + printf("\t\t \t\t 0x%08X \n", + cmd->response[1]); + printf("\t\t \t\t 0x%08X \n", + cmd->response[2]); + printf("\t\t \t\t 0x%08X \n", + cmd->response[3]); + printf("\n"); + printf("\t\t\t\t\tDUMPING DATA\n"); + for (i = 0; i < 4; i++) { + int j; + printf("\t\t\t\t\t%03d - ", i*4); + ptr = &cmd->response[i]; + ptr += 3; + for (j = 0; j < 4; j++) + printf("%02X ", *ptr--); + printf("\n"); + } + break; + case MMC_RSP_R3: + printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", + cmd->response[0]); + break; + default: + printf("\t\tERROR MMC rsp not supported\n"); + break; + } + return ret; +#else return mmc->send_cmd(mmc, cmd, data); +#endif }
int mmc_send_status(struct mmc *mmc, int timeout) @@ -75,6 +128,10 @@ int mmc_send_status(struct mmc *mmc, int timeout) } } while (timeout--);
+#ifdef CONFIG_MMC_TRACE + status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9; + printf("CURR STATE:%d\n", status); +#endif return 0; }
@@ -417,6 +474,20 @@ int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd)
err = mmc_send_cmd(mmc, &cmd, &data);
+#ifdef CONFIG_MMC_TRACE + { + int i; + printf("\n"); + printf("MMC_SEND_EXT_CSD: DUMPING DATA\n"); + for (i = 0; i < 32; i++) { + int j; + printf("%03d - ", i*16); + for (j = 0; j < 16; j++) + printf("%02X ", data.dest[j+i*16]); + printf("\n"); + } + } +#endif return err; }
participants (2)
-
Lei Wen
-
Raffaele Recalcati