summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorPrzemyslaw Marczak <p.marczak@samsung.com>2013-10-08 18:12:09 +0200
committerPantelis Antoniou <panto@antoniou-consulting.com>2013-10-31 09:55:33 +0200
commit56b34bc617f64ce34b34cebc7cbde7a8e4c1002f (patch)
treed9716cee9cc8083c8a6194284c0518f81d5dcf0e /drivers/mmc
parentb44fe83a580c21082486931367277c02d48c6469 (diff)
downloadu-boot-imx-56b34bc617f64ce34b34cebc7cbde7a8e4c1002f.zip
u-boot-imx-56b34bc617f64ce34b34cebc7cbde7a8e4c1002f.tar.gz
u-boot-imx-56b34bc617f64ce34b34cebc7cbde7a8e4c1002f.tar.bz2
mmc: sdhci: Avoid commands errors by simple timeout adaptation.
Old command timeout value was too small and it caused I/O errors which led to uncompleted read/write/erase operations and filesystem errors. Timeout adaptation fixes this issue. Changes in sdhci_send_command() function: - change timeout variable to static - increase default command timeout to 100 ms - add definition of max command timeout value, which can be redefined in each board config file - wait for card ready state for max defined time if it doesn't exceed defined maximum or return COMM_ERR Once successfully increased timeout value will be used in next function call. This fix was tested on Goni, Trats, Trats2 boards by testing UMS on MMC storage. Changes v2: - move global variable cmd_timeout into function sdhci_send_command() - change condition "==" to ">=" when comparing time with timeout - print information about timeout increasing and card busy timeout Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com> Cc: Pantelis Antoniou <panto@antoniou-consulting.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/sdhci.c35
1 files changed, 28 insertions, 7 deletions
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index dfb2eee..46ae9cb 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -109,6 +109,19 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
return 0;
}
+/*
+ * No command will be sent by driver if card is busy, so driver must wait
+ * for card ready state.
+ * Every time when card is busy after timeout then (last) timeout value will be
+ * increased twice but only if it doesn't exceed global defined maximum.
+ * Each function call will use last timeout value. Max timeout can be redefined
+ * in board config file.
+ */
+#ifndef CONFIG_SDHCI_CMD_MAX_TIMEOUT
+#define CONFIG_SDHCI_CMD_MAX_TIMEOUT 3200
+#endif
+#define CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT 100
+
int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data)
{
@@ -117,11 +130,12 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
int ret = 0;
int trans_bytes = 0, is_aligned = 1;
u32 mask, flags, mode;
- unsigned int timeout, start_addr = 0;
+ unsigned int time = 0, start_addr = 0;
unsigned int retry = 10000;
+ int mmc_dev = mmc->block_dev.dev;
- /* Wait max 10 ms */
- timeout = 10;
+ /* Timeout unit - ms */
+ static unsigned int cmd_timeout = CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT;
sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT;
@@ -132,11 +146,18 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
mask &= ~SDHCI_DATA_INHIBIT;
while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
- if (timeout == 0) {
- printf("Controller never released inhibit bit(s).\n");
- return COMM_ERR;
+ if (time >= cmd_timeout) {
+ printf("MMC: %d busy ", mmc_dev);
+ if (2 * cmd_timeout <= CONFIG_SDHCI_CMD_MAX_TIMEOUT) {
+ cmd_timeout += cmd_timeout;
+ printf("timeout increasing to: %u ms.\n",
+ cmd_timeout);
+ } else {
+ puts("timeout.\n");
+ return COMM_ERR;
+ }
}
- timeout--;
+ time++;
udelay(1000);
}