diff mbox series

[v2,1/2] mmc: sdhci-of-esdhc: poll ESDHC_FLUSH_ASYNC_FIFO bit until completion

Message ID 20190924093131.17471-2-yangbo.lu@nxp.com (mailing list archive)
State New, archived
Headers show
Series mmc: sdhci-of-esdhc: fix up erratum A-008171 workaround | expand

Commit Message

Yangbo Lu Sept. 24, 2019, 9:31 a.m. UTC
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>
---
Changes for v2:
	- None.
---
 drivers/mmc/host/sdhci-of-esdhc.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

Comments

Adrian Hunter Oct. 8, 2019, 10:49 a.m. UTC | #1
On 24/09/19 12:31 PM, Yangbo Lu wrote:
> 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>
> ---
> 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);
> +	}

That code is the same as the block above, so it could be a separate
function.  Also you don't use SDHCI_QUIRK_CLOCK_BEFORE_RESET so using
usleep_range would be ok instead of udelay.

> +
>  	val = sdhci_readl(host, ESDHC_TBCTL);
>  	if (enable)
>  		val |= ESDHC_TB_EN;
>
Yangbo Lu Oct. 9, 2019, 7:42 a.m. UTC | #2
Hi Adrian,

> -----Original Message-----
> From: Adrian Hunter <adrian.hunter@intel.com>
> Sent: Tuesday, October 8, 2019 6:49 PM
> To: Y.b. Lu <yangbo.lu@nxp.com>; linux-mmc@vger.kernel.org; Ulf Hansson
> <ulf.hansson@linaro.org>
> Subject: Re: [v2, 1/2] mmc: sdhci-of-esdhc: poll ESDHC_FLUSH_ASYNC_FIFO
> bit until completion
> 
> On 24/09/19 12:31 PM, Yangbo Lu wrote:
> > 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>
> > ---
> > 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);
> > +	}
> 
> That code is the same as the block above, so it could be a separate function.
> Also you don't use SDHCI_QUIRK_CLOCK_BEFORE_RESET so using
> usleep_range would be ok instead of udelay.

[Y.b. Lu] Sent out v3. Converted to use esdhc_flush_async_fifo(), and used usleep_range() instead of udelay().
Thanks!

> 
> > +
> >  	val = sdhci_readl(host, ESDHC_TBCTL);
> >  	if (enable)
> >  		val |= ESDHC_TB_EN;
> >
diff mbox series

Patch

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;