Re: [PATCH v2] mmc: sdhci-msm: Disable CDR function on TX

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

 



On 22/11/18 12:18 PM, Loic Poulain wrote:
> The Clock Data Recovery (CDR) circuit allows to automatically adjust
> the RX sampling-point/phase for high frequency cards (SDR104, HS200...).
> CDR is automatically enabled during DLL configuration.
> However, according to the APQ8016 reference manual, this function
> must be disabled during TX and tuning phase in order to prevent any
> interferences during tuning challenges and unexpected phase alteration
> during TX transfers.
> 
> This patch enables/disables CDR according to the current transfer mode.
> 
> This fixes sporadic write transfer issues observed with some SDR104 and
> HS200 cards.
> 
> Inspired by sdhci-msm downstream patch:
> https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/432516/
> 
> Reported-by: Leonid Segal <leonid.s@xxxxxxxxxxxxx>
> Reported-by: Manabu Igusa <migusa@xxxxxxxxxxxxxx>
> Signed-off-by: Loic Poulain <loic.poulain@xxxxxxxxxx>

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

> ---
>  v2: reword: previous commit message was not the good version
> 
>  drivers/mmc/host/sdhci-msm.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 43 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
> index a28f5fe..7495854 100644
> --- a/drivers/mmc/host/sdhci-msm.c
> +++ b/drivers/mmc/host/sdhci-msm.c
> @@ -260,6 +260,8 @@ struct sdhci_msm_host {
>  	const struct sdhci_msm_variant_ops *var_ops;
>  	const struct sdhci_msm_offset *offset;
>  	struct icc_path *path;
> +	bool use_cdr;
> +	u32 transfer_mode;
>  };
>  
>  static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host)
> @@ -1027,6 +1029,27 @@ static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
>  	return ret;
>  }
>  
> +static void sdhci_msm_set_cdr(struct sdhci_host *host, bool enable)
> +{
> +	const struct sdhci_msm_offset *msm_offset = sdhci_priv_msm_offset(host);
> +	u32 config, oldconfig = readl_relaxed(host->ioaddr +
> +					      msm_offset->core_dll_config);
> +
> +	config = oldconfig;
> +	if (enable) {
> +		config |= CORE_CDR_EN;
> +		config &= ~CORE_CDR_EXT_EN;
> +	} else {
> +		config &= ~CORE_CDR_EN;
> +		config |= CORE_CDR_EXT_EN;
> +	}
> +
> +	if (config != oldconfig) {
> +		writel_relaxed(config, host->ioaddr +
> +			       msm_offset->core_dll_config);
> +	}
> +}
> +
>  static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
>  {
>  	struct sdhci_host *host = mmc_priv(mmc);
> @@ -1044,8 +1067,14 @@ static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
>  	if (host->clock <= CORE_FREQ_100MHZ ||
>  	    !(ios.timing == MMC_TIMING_MMC_HS400 ||
>  	    ios.timing == MMC_TIMING_MMC_HS200 ||
> -	    ios.timing == MMC_TIMING_UHS_SDR104))
> +	    ios.timing == MMC_TIMING_UHS_SDR104)) {
> +		msm_host->use_cdr = false;
> +		sdhci_msm_set_cdr(host, false);
>  		return 0;
> +	}
> +
> +	/* Clock-Data-Recovery used to dynamically adjust RX sampling point */
> +	msm_host->use_cdr = true;
>  
>  	/*
>  	 * For HS400 tuning in HS200 timing requires:
> @@ -1527,6 +1556,19 @@ static int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg)
>  	case SDHCI_POWER_CONTROL:
>  		req_type = !val ? REQ_BUS_OFF : REQ_BUS_ON;
>  		break;
> +	case SDHCI_TRANSFER_MODE:
> +		msm_host->transfer_mode = val;
> +		break;
> +	case SDHCI_COMMAND:
> +		if (!msm_host->use_cdr)
> +			break;
> +		if ((msm_host->transfer_mode & SDHCI_TRNS_READ) &&
> +		    (SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK_HS200) &&
> +		    (SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK))
> +			sdhci_msm_set_cdr(host, true);
> +		else
> +			sdhci_msm_set_cdr(host, false);
> +		break;
>  	}
>  
>  	if (req_type) {
> 




[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