public inbox for linux-mmc@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mmc: dw_mmc: add status check before clock update
@ 2015-02-10 12:51 Andrzej Hajda
  2015-02-10 14:29 ` [RFC PATCH] " Andrzej Hajda
  0 siblings, 1 reply; 11+ messages in thread
From: Andrzej Hajda @ 2015-02-10 12:51 UTC (permalink / raw)
  To: linux-mmc
  Cc: Andrzej Hajda, Seungwon Jeon, Jaehoon Chung, Chris Ball,
	Ulf Hansson, Marek Szyprowski, Kyungmin Park

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


^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2015-02-16 16:33 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-02-10 12:51 [PATCH] mmc: dw_mmc: add status check before clock update Andrzej Hajda
2015-02-10 14:29 ` [RFC PATCH] " Andrzej Hajda
2015-02-10 14:54   ` Alim Akhtar
2015-02-11  7:51     ` Andrzej Hajda
2015-02-11  8:32       ` Jaehoon Chung
2015-02-11  9:06         ` Andrzej Hajda
2015-02-12 16:53           ` Javier Martinez Canillas
2015-02-13  7:30             ` Jaehoon Chung
2015-02-13  8:13               ` Andrzej Hajda
2015-02-13 11:10                 ` Jaehoon Chung
2015-02-16 16:33                   ` Andrzej Hajda

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox