aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc/fsl_esdhc.c
diff options
context:
space:
mode:
authorDirk Behme2012-03-26 03:13:05 +0000
committerAndy Fleming2012-05-08 18:02:22 -0500
commit7a5b80297bc6cef0c10e5f57ac0450678dc7bc5e (patch)
tree8fba80e7160033710083598973ef35be98ef0765 /drivers/mmc/fsl_esdhc.c
parentffdea5dab902b522f8744234184ffa11a4e275c2 (diff)
mmc: fsl_esdhc: Poll until card is not busy anymore
This patch imports parts of two patches from the Freescale U-Boot with the following commit messages: ENGR00156405 ESDHC: Add workaround for auto-clock gate errata ENGcm03648 http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/commit/drivers/mmc/imx_esdhc.c?h=imx_v2009.08_12.01.01&id=e436525a70fe47623d346bc7d9f08f12ff8ad787 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. ENGR00156670-1 ESDHC/USDHC: Remove delay before each cmd and some bug fixes http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/commit/drivers/mmc/imx_esdhc.c?h=imx_v2009.08_12.01.01&id=a77c6fec8596891be96b2cdbc742c9824844b92a Removed delay of 10 ms before each command. There should not be a need to have this delay after the ENGR00156405 patch that polls until card is not busy anymore before proceeding to next cmd. This patch imports the polling part of both patches. The auto-clock gating code don't apply for i.MX6 as implemented in these two patches. SYSCTL_RSTA was defined twice. Remove one definition. Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com> CC: Andy Fleming <afleming@freescale.com> CC: Fabio Estevam <fabio.estevam@freescale.com> CC: Stefano Babic <sbabic@denx.de>
Diffstat (limited to 'drivers/mmc/fsl_esdhc.c')
-rw-r--r--drivers/mmc/fsl_esdhc.c39
1 files changed, 38 insertions, 1 deletions
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index a2f35e3e991..07370b57291 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -307,19 +307,56 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
#else
esdhc_write32(&regs->xfertyp, xfertyp);
#endif
+
+ /* Mask all irqs */
+ esdhc_write32(&regs->irqsigen, 0);
+
/* Wait for the command to complete */
- while (!(esdhc_read32(&regs->irqstat) & IRQSTAT_CC))
+ while (!(esdhc_read32(&regs->irqstat) & (IRQSTAT_CC | IRQSTAT_CTOE)))
;
irqstat = esdhc_read32(&regs->irqstat);
esdhc_write32(&regs->irqstat, irqstat);
+ /* Reset CMD and DATA portions on error */
+ if (irqstat & (CMD_ERR | IRQSTAT_CTOE)) {
+ esdhc_write32(&regs->sysctl, esdhc_read32(&regs->sysctl) |
+ SYSCTL_RSTC);
+ while (esdhc_read32(&regs->sysctl) & SYSCTL_RSTC)
+ ;
+
+ if (data) {
+ esdhc_write32(&regs->sysctl,
+ esdhc_read32(&regs->sysctl) |
+ SYSCTL_RSTD);
+ while ((esdhc_read32(&regs->sysctl) & SYSCTL_RSTD))
+ ;
+ }
+ }
+
if (irqstat & CMD_ERR)
return COMM_ERR;
if (irqstat & IRQSTAT_CTOE)
return TIMEOUT;
+ /* Workaround for ESDHC errata ENGcm03648 */
+ if (!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 && !(esdhc_read32(&regs->prsstat) &
+ PRSSTAT_DAT0)) {
+ udelay(100);
+ timeout--;
+ }
+
+ 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;