@@ -650,6 +650,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 */
@@ -806,6 +821,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);
@@ -814,6 +830,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;
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@nxp.com> --- drivers/mmc/host/sdhci-of-esdhc.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)