From a7778f8fbee098c78b1fa1e1331313a7e217fb30 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Mon, 30 Jan 2012 11:22:25 +0000 Subject: omap_hsmmc: Wait for CMDI to be clear MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before we can send a command we need both the DATI (command inhibit on mmc_dat line) bit and CMDI (command inhibit on mmc_cmd line) are clear. The previous behavior of only checking on DATI was insufficient on some cards and incorrect behavior in any case. This makes the code check for both bits being clear and makes the error print more clear as to what happened. DATI_CMDDIS is removed as it was unused elsewhere in the code and stood for 'DATI is set, cmds are disabled still'. Fix originally spotted by Peter Bigot. Tested-by: Peter A. Bigot Tested-by: Robert Nelson Signed-off-by: Tom Rini Tested-by: Andreas Müller --- drivers/mmc/omap_hsmmc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index ef64e37411..2400db2f35 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -198,9 +198,10 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, ulong start; start = get_timer(0); - while ((readl(&mmc_base->pstate) & DATI_MASK) == DATI_CMDDIS) { + while ((readl(&mmc_base->pstate) & (DATI_MASK | CMDI_MASK)) != 0) { if (get_timer(0) - start > MAX_RETRY_MS) { - printf("%s: timedout waiting for cmddis!\n", __func__); + printf("%s: timedout waiting on cmd inhibit to clear\n", + __func__); return TIMEOUT; } } -- cgit v1.2.3 From cf39cf55971136b54c5aba3de9d0ac0c038c230b Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Tue, 7 Feb 2012 06:17:16 +0000 Subject: Tegra: mmc: Fixed handling of interrupts in timeouts. We are seeing occasional timeouts in the Tegra mmc code when we are reading from external MMC cards. These don't seem to be detrimental if they are handled properly. This CL properly clears the "normal interrupt status register" (norintsts) in error conditions. If we don't do this, when we come back into mmc_send_cmd() the register will still contain status from the last transaction. Signed-off-by: Doug Anderson Signed-off-by: Tom Warren --- drivers/mmc/tegra2_mmc.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/tegra2_mmc.c b/drivers/mmc/tegra2_mmc.c index 3191557c5b..33cc8fb804 100644 --- a/drivers/mmc/tegra2_mmc.c +++ b/drivers/mmc/tegra2_mmc.c @@ -227,16 +227,19 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, if (i == retry) { printf("%s: waiting for status update\n", __func__); + writel(mask, &host->reg->norintsts); return TIMEOUT; } if (mask & TEGRA_MMC_NORINTSTS_CMD_TIMEOUT) { /* Timeout Error */ debug("timeout: %08x cmd %d\n", mask, cmd->cmdidx); + writel(mask, &host->reg->norintsts); return TIMEOUT; } else if (mask & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) { /* Error Interrupt */ debug("error: %08x cmd %d\n", mask, cmd->cmdidx); + writel(mask, &host->reg->norintsts); return -1; } @@ -265,6 +268,7 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, if (i == retry) { printf("%s: card is still busy\n", __func__); + writel(mask, &host->reg->norintsts); return TIMEOUT; } -- cgit v1.2.3 From 93ad0d18c0ff1fb0a141bdfe66c76b7d4f922619 Mon Sep 17 00:00:00 2001 From: Jan Kloetzke Date: Sun, 5 Feb 2012 22:29:11 +0000 Subject: mmc: fix card busy polling A MMC/SD card may always go into the programming state (and hence be busy) after a block write. Therefore always check the card state, even after single block writes. On the other hand there is no need to check the card status after a read. Also make sure that errors during busy polling are propagated upwards. Signed-off-by: Jan Kloetzke Cc: Andy Fleming --- drivers/mmc/mmc.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 6db37b1fc5..7b0927257b 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -305,11 +305,12 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src) printf("mmc fail to send stop cmd\n"); return 0; } - - /* Waiting for the ready status */ - mmc_send_status(mmc, timeout); } + /* Waiting for the ready status */ + if (mmc_send_status(mmc, timeout)) + return 0; + return blkcnt; } @@ -341,7 +342,6 @@ int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt) { struct mmc_cmd cmd; struct mmc_data data; - int timeout = 1000; if (blkcnt > 1) cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; @@ -373,9 +373,6 @@ int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt) printf("mmc fail to send stop cmd\n"); return 0; } - - /* Waiting for the ready status */ - mmc_send_status(mmc, timeout); } return blkcnt; @@ -610,7 +607,8 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) ret = mmc_send_cmd(mmc, &cmd, NULL); /* Waiting for the ready status */ - mmc_send_status(mmc, timeout); + if (!ret) + ret = mmc_send_status(mmc, timeout); return ret; -- cgit v1.2.3 From d617c426a6ef8d731da1936bca7649a1574d5420 Mon Sep 17 00:00:00 2001 From: Jan Kloetzke Date: Sun, 5 Feb 2012 22:29:12 +0000 Subject: mmc: make mmc_send_status() more reliable Align the card status polling with the Linux kernel and retry the command at least five times. Also some cards apparently mishandle the status bits, so make sure to check the card state too. Signed-off-by: Jan Kloetzke Cc: Andy Fleming --- drivers/mmc/mmc.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 7b0927257b..49c3349f55 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -108,7 +108,7 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) int mmc_send_status(struct mmc *mmc, int timeout) { struct mmc_cmd cmd; - int err; + int err, retries = 5; #ifdef CONFIG_MMC_TRACE int status; #endif @@ -121,17 +121,21 @@ int mmc_send_status(struct mmc *mmc, int timeout) do { err = mmc_send_cmd(mmc, &cmd, NULL); - if (err) + if (!err) { + if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && + (cmd.response[0] & MMC_STATUS_CURR_STATE) != + MMC_STATE_PRG) + break; + else if (cmd.response[0] & MMC_STATUS_MASK) { + printf("Status Error: 0x%08X\n", + cmd.response[0]); + return COMM_ERR; + } + } else if (--retries < 0) return err; - else if (cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) - break; udelay(1000); - if (cmd.response[0] & MMC_STATUS_MASK) { - printf("Status Error: 0x%08X\n", cmd.response[0]); - return COMM_ERR; - } } while (timeout--); #ifdef CONFIG_MMC_TRACE -- cgit v1.2.3