diff options
Diffstat (limited to 'drivers/mmc/imx_esdhc.c')
-rw-r--r-- | drivers/mmc/imx_esdhc.c | 35 |
1 files changed, 33 insertions, 2 deletions
diff --git a/drivers/mmc/imx_esdhc.c b/drivers/mmc/imx_esdhc.c index 052b747..489fd6a 100644 --- a/drivers/mmc/imx_esdhc.c +++ b/drivers/mmc/imx_esdhc.c @@ -167,7 +167,7 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { uint xfertyp; uint irqstat; - u32 tmp; + u32 tmp, sysctl_restore; struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; @@ -208,6 +208,14 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) mmc->card_caps & EMMC_MODE_8BIT_DDR) xfertyp |= XFERTYP_DDR_EN; + /* ESDHC errata ENGcm03648: Turn off auto-clock gate for commands + * with busy signaling and no data + */ + if (!cfg->is_usdhc && !data && (cmd->resp_type & MMC_RSP_BUSY)) { + sysctl_restore = readl(®s->sysctl); + writel(sysctl_restore | 0xF, ®s->sysctl); + } + /* Send the command */ writel(cmd->cmdarg, ®s->cmdarg); /* for uSDHC, write lower-half of xfertyp to mixctrl */ @@ -225,15 +233,38 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) writel(irqstat, ®s->irqstat); /* Reset CMD portion on error */ - if (irqstat & (CMD_ERR | IRQSTAT_CTOE)) + if (irqstat & (CMD_ERR | IRQSTAT_CTOE)) { writel(readl(®s->sysctl) | SYSCTL_RSTC, ®s->sysctl); + /* Restore auto-clock gate if error */ + if (!cfg->is_usdhc && !data && (cmd->resp_type & MMC_RSP_BUSY)) + writel(sysctl_restore, ®s->sysctl); + } + if (irqstat & CMD_ERR) return COMM_ERR; if (irqstat & IRQSTAT_CTOE) return TIMEOUT; + /* Workaround for ESDHC errata ENGcm03648 */ + if (!cfg->is_usdhc && !data && (cmd->resp_type & MMC_RSP_BUSY)) { + int timeout = 2500; + + /* Poll on DATA0 line for cmd with busy signal for 250 ms */ + while (timeout > 0 && !(readl(®s->prsstat) & PRSSTAT_DAT0)) { + udelay(100); + timeout--; + } + + writel(sysctl_restore, ®s->sysctl); + + if (timeout <= 0) { + printf("Timeout waiting for DAT0 to go high!\n"); + return TIMEOUT; + } + } + /* Copy the response to the response buffer */ if (cmd->resp_type & MMC_RSP_136) { u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0; |