mmc: msm_sdcc: check MCLK_REG_WR_ACTIVE bit for register write completion
When SW writes to MCI_POWER, MCI_CLK, MCI_CMD and MCI_DATA_CTL
registers, the register write operation is completed after
3HCLK + 2 MCLK clock cycles. SW should access these registers
only after the register write operation is completed.
This synchronization delay can't be ignored, especially in case
the MCLK is slow (e.g. 400 KHz).
Special status bit is defined to wait properly for register
write completion bit MCLK_REG_WR_ACTIVE of MCI_STATUS2 register.
SW should always wait until bit MCLK_REG_WR_ACTIVE of MCI_STATUS2
register is low after writing to one of mentioned above registers
and before accessing them again.
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 0195ed4..a5fa1d9 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -309,12 +309,32 @@
static inline unsigned int msmsdcc_get_min_sup_clk_rate(
struct msmsdcc_host *host);
+
static inline void msmsdcc_delay(struct msmsdcc_host *host)
{
+ ktime_t start, diff;
+
mb();
udelay(1 + ((3 * USEC_PER_SEC) /
(host->clk_rate ? host->clk_rate :
msmsdcc_get_min_sup_clk_rate(host))));
+
+ if (host->plat->sdcc_v4_sup &&
+ (readl_relaxed(host->base + MCI_STATUS2) &
+ MCI_MCLK_REG_WR_ACTIVE)) {
+ start = ktime_get();
+ while (readl_relaxed(host->base + MCI_STATUS2) &
+ MCI_MCLK_REG_WR_ACTIVE) {
+ diff = ktime_sub(ktime_get(), start);
+ /* poll for max. 1 ms */
+ if (ktime_to_us(diff) > 1000) {
+ pr_warning("%s: previous reg. write is"
+ " still active\n",
+ mmc_hostname(host->mmc));
+ break;
+ }
+ }
+ }
}
static inline void
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index a6a9369..f6f76ff 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -179,6 +179,9 @@
#define MCI_DLL_STATUS 0x068
#define MCI_DLL_LOCK (1 << 7)
+#define MCI_STATUS2 0x06C
+#define MCI_MCLK_REG_WR_ACTIVE (1 << 0)
+
#define MMCIFIFO 0x080 /* to 0x0bc */
#define MCI_TEST_INPUT 0x0D4