summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYe.Li <B37916@freescale.com>2014-01-26 18:05:57 +0800
committerYe.Li <B37916@freescale.com>2014-01-27 18:22:36 +0800
commit86817422ce90ea2106ba9cce7c8ce1624ea286a0 (patch)
treee3a752876c34e484ed3a8e18b101647999d8d95e
parentbc1148f504898d851e5bfdbdc7dcde754d94adba (diff)
downloadu-boot-imx-86817422ce90ea2106ba9cce7c8ce1624ea286a0.zip
u-boot-imx-86817422ce90ea2106ba9cce7c8ce1624ea286a0.tar.gz
u-boot-imx-86817422ce90ea2106ba9cce7c8ce1624ea286a0.tar.bz2
ENGR00293946 SD:ESDHC/USDHC Fix command timeout after UHS-I tunning error
Got intermittent boot failure of android image from UHS-I SD card. The MBR read is failed. When doing the UHS-I tunning of sampling point, ESDHC may get some command errors (CIE, CEBE or CCE) at incorrect sampling point. In this case, current driver will return from the "esdhc_send_cmd" function immediately with having host reset, which also gates off the SD clock automatically. But the SD card remains in the status of sending tuning block data and waits the clock. When the next new command is sent from host, the clock enables the SD card to sending the tuning block and does not respond to the new command. Fix this issue by adding a delay before host reset. So the SD card can output tunning block and turn to "tran" status. The tunning execute bit "EXE_TUNE" also be cleaned after each tunning. Signed-off-by: Ye.Li <B37916@freescale.com> (cherry picked from commit f68b8cbdedba855b87a11d525afe7c50fc4d7b0e)
-rw-r--r--drivers/mmc/imx_esdhc.c41
1 files changed, 36 insertions, 5 deletions
diff --git a/drivers/mmc/imx_esdhc.c b/drivers/mmc/imx_esdhc.c
index b242755..fe1fb2f 100644
--- a/drivers/mmc/imx_esdhc.c
+++ b/drivers/mmc/imx_esdhc.c
@@ -2,7 +2,7 @@
* Copyright 2007, Freescale Semiconductor, Inc
* Andy Fleming
*
- * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008-2014 Freescale Semiconductor, Inc.
*
* Based vaguely on the pxa mmc code:
* (C) Copyright 2003
@@ -233,6 +233,12 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
/* Reset CMD and DATA portions on error */
if (irqstat & (CMD_ERR | IRQSTAT_CTOE)) {
+
+ if (SD_CMD_TUNING == cmd->cmdidx) {
+ /*add delay to output tunning block from card*/
+ udelay(50);
+ }
+
writel(readl(&regs->sysctl) | SYSCTL_RSTC, &regs->sysctl);
while (readl(&regs->sysctl) & SYSCTL_RSTC)
;
@@ -252,6 +258,14 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V)
printf("CMD11 to switch to 1.8V mode failed."
"Card requires power cycle\n");
+
+ /* Clear the tune execute bit*/
+ mixctrl = readl(&regs->mixctrl);
+ if (mixctrl & USDHC_MIXCTRL_EXE_TUNE) {
+ mixctrl &= ~USDHC_MIXCTRL_EXE_TUNE;
+ writel(mixctrl, &regs->mixctrl);
+ }
+
}
if (irqstat & CMD_ERR)
@@ -328,8 +342,12 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
tmp_ptr = (u32 *)data->dest;
for (i = 0; i < (block_cnt); ++i) {
- while (!(readl(&regs->irqstat) & IRQSTAT_BRR))
- ;
+ while (!(readl(&regs->irqstat) & IRQSTAT_BRR)) {
+ /*Check data error to avoid dead loop*/
+ if (readl(&regs->irqstat) & DATA_ERR) {
+ goto send_end;
+ }
+ }
for (j = 0; j < (block_size >> 2); ++j, ++tmp_ptr) {
*tmp_ptr = readl(&regs->datport);
@@ -342,8 +360,12 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
tmp_ptr = (u32 *)data->src;
for (i = 0; i < (block_cnt); ++i) {
- while (!(readl(&regs->irqstat) & IRQSTAT_BWR))
- ;
+ while (!(readl(&regs->irqstat) & IRQSTAT_BWR)) {
+ /*Check timeout error to avoid dead loop*/
+ if (readl(&regs->irqstat) & IRQSTAT_DTOE) {
+ goto send_end;
+ }
+ }
for (j = 0; j < (block_size >> 2); ++j, ++tmp_ptr) {
writel(*tmp_ptr, &regs->datport);
@@ -357,6 +379,15 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
while (!(readl(&regs->irqstat) & IRQSTAT_TC)) ;
}
+send_end:
+
+ /* Clear the tune execute bit*/
+ mixctrl = readl(&regs->mixctrl);
+ if (mixctrl & USDHC_MIXCTRL_EXE_TUNE) {
+ mixctrl &= ~USDHC_MIXCTRL_EXE_TUNE;
+ writel(mixctrl, &regs->mixctrl);
+ }
+
/* Reset CMD and DATA portions of the controller on error */
if (readl(&regs->irqstat) & 0xFFFF0000) {
writel(readl(&regs->sysctl) | SYSCTL_RSTC | SYSCTL_RSTD,