diff options
author | Anish Trivedi <anish@freescale.com> | 2011-09-09 14:01:24 -0500 |
---|---|---|
committer | Anish Trivedi <anish@freescale.com> | 2011-09-13 10:12:25 -0500 |
commit | e436525a70fe47623d346bc7d9f08f12ff8ad787 (patch) | |
tree | a267ee5afbf84e7b708af1749b0116e34c642f74 /drivers | |
parent | ecee97c3abeaf39c1d862c47cc6f0e9a55865ed0 (diff) | |
download | u-boot-imx-e436525a70fe47623d346bc7d9f08f12ff8ad787.zip u-boot-imx-e436525a70fe47623d346bc7d9f08f12ff8ad787.tar.gz u-boot-imx-e436525a70fe47623d346bc7d9f08f12ff8ad787.tar.bz2 |
ENGR00156405 ESDHC: Add workaround for auto-clock gate errata ENGcm03648
The errata, not applicable to USDHC, causes ESDHC to shut off clock to
the card when auto-clock gating is enabled for commands with busy
signalling and no data phase. The card might require the clock to exit
the busy state, so the workaround is to disable the auto-clock gate
bits in SYSCTL register for such commands. The workaround also entails
polling on DAT0 bit in the PRSSTAT register to learn when busy state is
complete. Auto-clock gating is re-enabled at the end of busy state.
Signed-off-by: Anish Trivedi <anish@freescale.com>
Diffstat (limited to 'drivers')
-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; |