summaryrefslogtreecommitdiff
path: root/drivers/mmc/imx_esdhc.c
diff options
context:
space:
mode:
authorAnish Trivedi <anish@freescale.com>2011-09-09 14:01:24 -0500
committerAnish Trivedi <anish@freescale.com>2011-09-13 10:12:25 -0500
commite436525a70fe47623d346bc7d9f08f12ff8ad787 (patch)
treea267ee5afbf84e7b708af1749b0116e34c642f74 /drivers/mmc/imx_esdhc.c
parentecee97c3abeaf39c1d862c47cc6f0e9a55865ed0 (diff)
downloadu-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/mmc/imx_esdhc.c')
-rw-r--r--drivers/mmc/imx_esdhc.c35
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(&regs->sysctl);
+ writel(sysctl_restore | 0xF, &regs->sysctl);
+ }
+
/* Send the command */
writel(cmd->cmdarg, &regs->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, &regs->irqstat);
/* Reset CMD portion on error */
- if (irqstat & (CMD_ERR | IRQSTAT_CTOE))
+ if (irqstat & (CMD_ERR | IRQSTAT_CTOE)) {
writel(readl(&regs->sysctl) | SYSCTL_RSTC, &regs->sysctl);
+ /* Restore auto-clock gate if error */
+ if (!cfg->is_usdhc && !data && (cmd->resp_type & MMC_RSP_BUSY))
+ writel(sysctl_restore, &regs->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(&regs->prsstat) & PRSSTAT_DAT0)) {
+ udelay(100);
+ timeout--;
+ }
+
+ writel(sysctl_restore, &regs->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;