提交 25c719e2 编写于 作者: G Grazvydas Ignotas 提交者: Andy Fleming

mmc: omap: handle controller errors properly

According to OMAP3 TRM, when the controller reports certain errors,
driver must perform a software reset. This is done by setting a bit
in SYSCTL and waiting it to clear:
- SRC on command timeout (CTO)
- SRD on data errors (DTO, DCRC and DEB)

This fixes a problem seen on OMAP3 pandora board with some cards
that won't work with a message printed multiple times:
  timedout waiting on cmd inhibit to clear

Code loosely based on Linux omap_hsmmc driver.
Signed-off-by: NGrazvydas Ignotas <notasas@gmail.com>
Tested-by: NTom Rini <trini@ti.com>
Tested-by: NPali Rohár <pali.rohar@gmail.com>
上级 15ceb1de
......@@ -33,6 +33,10 @@
#include <asm/arch/mmc_host_def.h>
#include <asm/arch/sys_proto.h>
/* common definitions for all OMAPs */
#define SYSCTL_SRC (1 << 25)
#define SYSCTL_SRD (1 << 26)
/* If we fail after 1 second wait, something is really bad */
#define MAX_RETRY_MS 1000
......@@ -195,6 +199,27 @@ static int mmc_init_setup(struct mmc *mmc)
return 0;
}
/*
* MMC controller internal finite state machine reset
*
* Used to reset command or data internal state machines, using respectively
* SRC or SRD bit of SYSCTL register
*/
static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)
{
ulong start;
mmc_reg_out(&mmc_base->sysctl, bit, bit);
start = get_timer(0);
while ((readl(&mmc_base->sysctl) & bit) != 0) {
if (get_timer(0) - start > MAX_RETRY_MS) {
printf("%s: timedout waiting for sysctl %x to clear\n",
__func__, bit);
return;
}
}
}
static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data)
......@@ -284,9 +309,10 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
}
} while (!mmc_stat);
if ((mmc_stat & IE_CTO) != 0)
if ((mmc_stat & IE_CTO) != 0) {
mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
return TIMEOUT;
else if ((mmc_stat & ERRI_MASK) != 0)
} else if ((mmc_stat & ERRI_MASK) != 0)
return -1;
if (mmc_stat & CC_MASK) {
......@@ -337,6 +363,9 @@ static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size)
}
} while (mmc_stat == 0);
if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
if ((mmc_stat & ERRI_MASK) != 0)
return 1;
......@@ -389,6 +418,9 @@ static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
}
} while (mmc_stat == 0);
if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
if ((mmc_stat & ERRI_MASK) != 0)
return 1;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册