Re: [PATCH 10/14] mmc: sdhci-esdhc-imx: optimize the clock setting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 15/11/19 1:18 PM, haibo.chen@xxxxxxx wrote:
> From: Haibo Chen <haibo.chen@xxxxxxx>
> 
> When force clock off, check the SDOFF of register PRSSTAT to make sure
> the clock is gate off. Before force clock on, check the SDSTB of register
> PRSSTAT to make sure the clock is stable, this will eliminate the clock
> glitch.
> 
> Signed-off-by: Haibo Chen <haibo.chen@xxxxxxx>

Acked-by: Adrian Hunter <adrian.hunter@xxxxxxxxx>

> ---
>  drivers/mmc/host/sdhci-esdhc-imx.c | 24 +++++++++++++++++++++++-
>  drivers/mmc/host/sdhci-esdhc.h     |  1 +
>  2 files changed, 24 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index 2ed945f5c259..0667b6903708 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -9,6 +9,7 @@
>   */
>  
>  #include <linux/io.h>
> +#include <linux/iopoll.h>
>  #include <linux/delay.h>
>  #include <linux/err.h>
>  #include <linux/clk.h>
> @@ -313,6 +314,17 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i
>  	writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
>  }
>  
> +static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host)
> +{
> +	u32 present_state;
> +	int ret;
> +
> +	ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, present_state,
> +				(present_state & ESDHC_CLOCK_GATE_OFF), 2, 100);
> +	if (ret == -ETIMEDOUT)
> +		dev_warn(mmc_dev(host->mmc), "%s: card clock still not gate off in 100us!.\n", __func__);
> +}
> +
>  static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
>  {
>  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> @@ -526,6 +538,8 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
>  		else
>  			new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
>  		writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
> +		if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON))
> +			esdhc_wait_for_card_clock_gate_off(host);
>  		return;
>  	case SDHCI_HOST_CONTROL2:
>  		new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
> @@ -754,12 +768,14 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
>  	int ddr_pre_div = imx_data->is_ddr ? 2 : 1;
>  	int pre_div = 1;
>  	int div = 1;
> +	int ret;
>  	u32 temp, val;
>  
>  	if (esdhc_is_usdhc(imx_data)) {
>  		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
>  		writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
>  			host->ioaddr + ESDHC_VENDOR_SPEC);
> +		esdhc_wait_for_card_clock_gate_off(host);
>  	}
>  
>  	if (clock == 0) {
> @@ -814,13 +830,18 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
>  		| (pre_div << ESDHC_PREDIV_SHIFT));
>  	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
>  
> +	/* need to wait the bit 3 of the PRSSTAT to be set, make sure card clock is stable */
> +	ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, temp,
> +				(temp & ESDHC_CLOCK_STABLE), 2, 100);
> +	if (ret == -ETIMEDOUT)
> +		dev_warn(mmc_dev(host->mmc), "card clock still not stable in 100us!.\n");
> +
>  	if (esdhc_is_usdhc(imx_data)) {
>  		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
>  		writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
>  			host->ioaddr + ESDHC_VENDOR_SPEC);
>  	}
>  
> -	mdelay(1);
>  }
>  
>  static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
> @@ -1005,6 +1026,7 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host)
>  	writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) &
>  		~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
>  		host->ioaddr + ESDHC_VENDOR_SPEC);
> +	esdhc_wait_for_card_clock_gate_off(host);
>  
>  	/* force a reset on strobe dll */
>  	writel(ESDHC_STROBE_DLL_CTRL_RESET,
> diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
> index 9289bb4d633e..947212f16bc6 100644
> --- a/drivers/mmc/host/sdhci-esdhc.h
> +++ b/drivers/mmc/host/sdhci-esdhc.h
> @@ -31,6 +31,7 @@
>  
>  /* Present State Register */
>  #define ESDHC_PRSSTAT			0x24
> +#define ESDHC_CLOCK_GATE_OFF		0x00000080
>  #define ESDHC_CLOCK_STABLE		0x00000008
>  
>  /* Protocol Control Register */
> 




[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux