Other Parts Discussed in Thread: CSD
Hello!
We are in the process of bringing up our first design of an AM623-based board with eMMC as boot media. Our issue is that the eMMC fails to enter HS200 mode in Linux.
For hardware, we have copied the same pinout and DTS as the AM62-SK dev kit, i.e. using MMC0 at 1.8V on the AM62. The only difference is that we have changed the eMMC from Micron to SanDisk SDINBDG4-8G.
For software, we are using the 8.6 TI SDK.
In U-boot, the eMMC seems to enter HS200 mode successfully:
... and we can measure 200MHz on the CLK pin.
Once entering Linux however, the system attempts to configure the eMMC again in HS200 and fails. By editing the code in mmc.c to fall through the HS200 change, the
Specifically, it seems it is hanging on the command (error -110 timeout) to write the Bus Width (EXT_CSD register 183). Both 8 -bit (mode 2) and 4-bit (mode 1) fail before giving up. Also interesting, the same command after setting the mode to HS in a write to EXT_CSD register 185, the command succeeds without issue.
With this patch:
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 8f2465394..7e18ca6ce 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -405,11 +405,13 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card))
+ {
+ printk(". . . mmc_wait_for_req_done() - finished: err=%d retries=%d removed=%d", cmd->error, cmd->retries, mmc_card_removed(host->card));
break;
-
+ }
mmc_retune_recheck(host);
- pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
+ printk("%s: req failed (CMD%u): %d, retrying...\n",
mmc_hostname(host), cmd->opcode, cmd->error);
cmd->retries--;
cmd->error = 0;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 09a2a887c..7880c7aca 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1012,6 +1012,8 @@ static int mmc_select_bus_width(struct mmc_card *card)
idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
+ printk(". mmc_select_bus_width(): mmc_can_ext_csd() returned True. host->caps = %x, idx=%d", host->caps, idx);
+
/*
* Unlike SD, MMC cards dont have a configuration register to notify
* supported bus width. So bus test command should be run to identify
@@ -1030,6 +1032,9 @@ static int mmc_select_bus_width(struct mmc_card *card)
EXT_CSD_BUS_WIDTH,
ext_csd_bits[idx],
card->ext_csd.generic_cmd6_time);
+
+ printk(". mmc_switch() returned error: %d, continuing. idx=%d", err, idx);
+
if (err)
continue;
@@ -1450,6 +1455,8 @@ static int mmc_select_hs200(struct mmc_card *card)
int err = -EINVAL;
u8 val;
+ printk("mmc_select_hs200()");
+
old_signal_voltage = host->ios.signal_voltage;
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
@@ -1468,7 +1475,9 @@ static int mmc_select_hs200(struct mmc_card *card)
* switch to HS200 mode if bus width is set successfully.
*/
err = mmc_select_bus_width(card);
+
if (err > 0) {
+ printk("Error from mmc_select_bus_width() = %d", err);
val = EXT_CSD_TIMING_HS200 |
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index ebad70e44..914d9ae3d 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -566,6 +566,9 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
bool use_r1b_resp = true;
unsigned char old_timing = host->ios.timing;
+ printk(". . __mmc_switch() %s: set=%d, index=%d, value=%d, timeout_ms=%d, timing=%d, send_status=%d, retry_crc_err=%d)",
+ mmc_hostname(host), set, index, value, timeout_ms, timing, send_status, retry_crc_err);
+
mmc_retune_hold(host);
if (!timeout_ms) {
@@ -599,6 +602,8 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
}
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+ printk(". . __mmc_switch(): mmc_wait_for_cmd() returned error %d. Used r1b response? %d", err, use_r1b_resp);
+
if (err)
goto out;
@@ -610,6 +615,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
/* Let's try to poll to find out when the command is completed. */
err = __mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err,
MMC_BUSY_CMD6);
+ if (err) printk("__mmc_switch()): __mmc_poll_for_busy() returned error %d", err);
if (err)
goto out;
@@ -623,6 +629,9 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
if (err && timing)
mmc_set_timing(host, old_timing);
}
+
+ if (err) printk("__mmc_switch()): mmc_switch_status() returned error %d", err);
+
out:
mmc_retune_release(host);
I get this printout on boot:
[ 1.238502] mmc_select_hs200()
[ 1.238516] . mmc_select_bus_width(): mmc_can_ext_csd() returned True. host->caps = 4000114b, idx=0
[ 1.238521] . . __mmc_switch() mmc0: set=1, index=183, value=2, timeout_ms=250, timing=0, send_status=1, retry_crc_err=0)
[ 1.238891] mmc0: req failed (CMD6): -110, retrying...
[ 1.239255] mmc0: req failed (CMD6): -110, retrying...
[ 1.239617] mmc0: req failed (CMD6): -110, retrying...
[ 1.239980] . . . mmc_wait_for_req_done() - finished: err=-110 retries=1 removed=0
[ 1.239984] . . __mmc_switch(): mmc_wait_for_cmd() returned error -110. Used r1b response? 1
[ 1.239987] . mmc_switch() returned error: -110, continuing. idx=0
[ 1.239990] . . __mmc_switch() mmc0: set=1, index=183, value=1, timeout_ms=250, timing=0, send_status=1, retry_crc_err=0)
[ 1.240357] mmc0: req failed (CMD6): -110, retrying...
[ 1.240719] mmc0: req failed (CMD6): -110, retrying...
[ 1.241082] mmc0: req failed (CMD6): -110, retrying...
[ 1.241446] . . . mmc_wait_for_req_done() - finished: err=-110 retries=1 removed=0
[ 1.241450] . . __mmc_switch(): mmc_wait_for_cmd() returned error -110. Used r1b response? 1
[ 1.241453] . mmc_switch() returned error: -110, continuing. idx=1
[ 1.246972] mmc0: mmc_select_hs200 failed, error -110
[ 1.246977] mmc_select_timing() -> Falling back to HS mode.
[ 1.246980] . . __mmc_switch() mmc0: set=1, index=185, value=1, timeout_ms=250, timing=1, send_status=1, retry_crc_err=1)
[ 1.247702] . . . mmc_wait_for_req_done() - finished: err=0 retries=0 removed=0
[ 1.247706] . . __mmc_switch(): mmc_wait_for_cmd() returned error 0. Used r1b response? 1
[ 1.248072] . . . mmc_wait_for_req_done() - finished: err=0 retries=0 removed=0
[ 1.248129] . mmc_select_bus_width(): mmc_can_ext_csd() returned True. host->caps = 4000114b, idx=0
[ 1.248133] . . __mmc_switch() mmc0: set=1, index=183, value=2, timeout_ms=250, timing=0, send_status=1, retry_crc_err=0)
[ 1.248180] . . . mmc_wait_for_req_done() - finished: err=0 retries=0 removed=0
[ 1.248184] . . __mmc_switch(): mmc_wait_for_cmd() returned error 0. Used r1b response? 1
[ 1.248208] . . . mmc_wait_for_req_done() - finished: err=0 retries=0 removed=0
[ 1.248212] . mmc_switch() returned error: 0, continuing. idx=0
After this, the system boots and runs normally, but at the low eMMC speed.
Looking for any help on any additional testing or software patches we can try to solve this issue... thanks!