diff options
-rw-r--r-- | drivers/mmc/imx_esdhc.c | 41 |
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(®s->sysctl) | SYSCTL_RSTC, ®s->sysctl); while (readl(®s->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(®s->mixctrl); + if (mixctrl & USDHC_MIXCTRL_EXE_TUNE) { + mixctrl &= ~USDHC_MIXCTRL_EXE_TUNE; + writel(mixctrl, ®s->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(®s->irqstat) & IRQSTAT_BRR)) - ; + while (!(readl(®s->irqstat) & IRQSTAT_BRR)) { + /*Check data error to avoid dead loop*/ + if (readl(®s->irqstat) & DATA_ERR) { + goto send_end; + } + } for (j = 0; j < (block_size >> 2); ++j, ++tmp_ptr) { *tmp_ptr = readl(®s->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(®s->irqstat) & IRQSTAT_BWR)) - ; + while (!(readl(®s->irqstat) & IRQSTAT_BWR)) { + /*Check timeout error to avoid dead loop*/ + if (readl(®s->irqstat) & IRQSTAT_DTOE) { + goto send_end; + } + } for (j = 0; j < (block_size >> 2); ++j, ++tmp_ptr) { writel(*tmp_ptr, ®s->datport); @@ -357,6 +379,15 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) while (!(readl(®s->irqstat) & IRQSTAT_TC)) ; } +send_end: + + /* Clear the tune execute bit*/ + mixctrl = readl(®s->mixctrl); + if (mixctrl & USDHC_MIXCTRL_EXE_TUNE) { + mixctrl &= ~USDHC_MIXCTRL_EXE_TUNE; + writel(mixctrl, ®s->mixctrl); + } + /* Reset CMD and DATA portions of the controller on error */ if (readl(®s->irqstat) & 0xFFFF0000) { writel(readl(®s->sysctl) | SYSCTL_RSTC | SYSCTL_RSTD, |