The ESDHC_FLUSH_ASYNC_FIFO bit which is set to flush asynchronous FIFO should be polled until it's auto cleared by hardware. Signed-off-by: Yangbo Lu <yangbo.lu@xxxxxxx> --- Changes for v2: - None. --- drivers/mmc/host/sdhci-of-esdhc.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 1d1953d..be0ba6b 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -655,6 +655,21 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) temp = sdhci_readl(host, ESDHC_DMA_SYSCTL); temp |= ESDHC_FLUSH_ASYNC_FIFO; sdhci_writel(host, temp, ESDHC_DMA_SYSCTL); + /* Wait max 20 ms */ + timeout = ktime_add_ms(ktime_get(), 20); + while (1) { + bool timedout = ktime_after(ktime_get(), timeout); + + if (!(sdhci_readl(host, ESDHC_DMA_SYSCTL) & + ESDHC_FLUSH_ASYNC_FIFO)) + break; + if (timedout) { + pr_err("%s: tuning block polling FLUSH_ASYNC_FIFO timeout.\n", + mmc_hostname(host->mmc)); + break; + } + udelay(10); + } } /* Wait max 20 ms */ @@ -811,6 +826,7 @@ static struct soc_device_attribute soc_fixup_tuning[] = { static void esdhc_tuning_block_enable(struct sdhci_host *host, bool enable) { + ktime_t timeout; u32 val; esdhc_clock_enable(host, false); @@ -819,6 +835,22 @@ static void esdhc_tuning_block_enable(struct sdhci_host *host, bool enable) val |= ESDHC_FLUSH_ASYNC_FIFO; sdhci_writel(host, val, ESDHC_DMA_SYSCTL); + /* Wait max 20 ms */ + timeout = ktime_add_ms(ktime_get(), 20); + while (1) { + bool timedout = ktime_after(ktime_get(), timeout); + + if (!(sdhci_readl(host, ESDHC_DMA_SYSCTL) & + ESDHC_FLUSH_ASYNC_FIFO)) + break; + if (timedout) { + pr_err("%s: tuning block polling FLUSH_ASYNC_FIFO timeout.\n", + mmc_hostname(host->mmc)); + break; + } + udelay(10); + } + val = sdhci_readl(host, ESDHC_TBCTL); if (enable) val |= ESDHC_TB_EN; -- 2.7.4