[PATCH] mmc: dw_mmc: add status check before clock update

Andrzej Hajda
2015-02-10T12:52:30Z

According to specs for version 250A, status register should be
tested before clock update. Otherwise in case MMC card is missing
mci_send_cmd timeouts and subsequent CTYPE registry write causes system hang.
This behavior has been observed on Exynos5422/Odroid-XU3.

Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
---
drivers/mmc/host/dw_mmc.c | 26 ++++++++++++++++++++++++--
drivers/mmc/host/dw_mmc.h | 1 +
2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 67c0451..5852067 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -878,6 +878,25 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
cmd, arg, cmd_status);
}

+static bool dw_mci_wait_busy(struct dw_mci *host)
+{
+ unsigned long timeout;
+
+ if (host->verid < DW_MMC_250A)
+ return true;
+
+ timeout = jiffies + msecs_to_jiffies(500);
+ while (time_before(jiffies, timeout)) {
+ if (!(mci_readl(host, STATUS) & SDMMC_STATUS_BUSY))
+ return true;
+
+ usleep(1000, 2000);
+ }
+ dev_err(host->dev, "Busy timeout\n");
+
+ return false;
+}
+
static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
{
struct dw_mci *host = slot->host;
@@ -891,8 +910,11 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;

if (!clock) {
- mci_writel(host, CLKENA, 0);
- mci_send_cmd(slot, sdmmc_cmd_bits, 0);
+ if (dw_mci_wait_busy(host)) {
+ mci_writel(host, CLKENA, 0);
+ mci_send_cmd(slot, sdmmc_cmd_bits, 0);
+ } else
+ return;
} else if (clock != host->current_speed || force_clkinit) {
div = host->bus_hz / clock;
if (host->bus_hz % clock && host->bus_hz > clock)
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 0d0f7a27..ea6d4d1 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -15,6 +15,7 @@
#define _DW_MMC_H_

#define DW_MMC_240A 0x240a
+#define DW_MMC_250A 0x250a

#define SDMMC_CTRL 0x000
#define SDMMC_PWREN 0x004
--
1.9.1