Patchwork [v4] mmc: sdhci-msm: Disable CDR function on TX

login
register
mail settings
Submitter Loic Poulain
Date Dec. 4, 2018, 12:25 p.m.
Message ID <1543926332-19546-1-git-send-email-loic.poulain@linaro.org>
Download mbox | patch
Permalink /patch/671859/
State New
Headers show

Comments

Loic Poulain - Dec. 4, 2018, 12:25 p.m.
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@variscite.com>
Reported-by: Manabu Igusa <migusa@arrowjapan.com>
Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Acked-by: Georgi Djakov <georgi.djakov@linaro.org>
---
 v2: reword: previous commit message was not the good version
 v3: rebase on upstream
 v4: remove extra parenthis
     rebase on mmc next branch

 drivers/mmc/host/sdhci-msm.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)
Ulf Hansson - Dec. 5, 2018, 2:24 p.m.
On Tue, 4 Dec 2018 at 13:25, Loic Poulain <loic.poulain@linaro.org> 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@variscite.com>
> Reported-by: Manabu Igusa <migusa@arrowjapan.com>
> Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
> Acked-by: Adrian Hunter <adrian.hunter@intel.com>
> Acked-by: Georgi Djakov <georgi.djakov@linaro.org>

Applied for next, thanks!

Kind regards
Uffe

> ---
>  v2: reword: previous commit message was not the good version
>  v3: rebase on upstream
>  v4: remove extra parenthis
>      rebase on mmc next branch
>
>  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 4cac593..5497a71 100644
> --- a/drivers/mmc/host/sdhci-msm.c
> +++ b/drivers/mmc/host/sdhci-msm.c
> @@ -260,6 +260,8 @@ struct sdhci_msm_host {
>         bool restore_dll_config;
>         const struct sdhci_msm_variant_ops *var_ops;
>         const struct sdhci_msm_offset *offset;
> +       bool use_cdr;
> +       u32 transfer_mode;
>  };
>
>  static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host)
> @@ -1069,6 +1071,27 @@ static int sdhci_msm_restore_sdr_dll_config(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);
> @@ -1079,8 +1102,14 @@ static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
>         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
>         struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
>
> -       if (!sdhci_msm_is_tuning_needed(host))
> +       if (!sdhci_msm_is_tuning_needed(host)) {
> +               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:
> @@ -1562,6 +1591,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) {
> --
> 2.7.4
>

Patch

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 4cac593..5497a71 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -260,6 +260,8 @@  struct sdhci_msm_host {
 	bool restore_dll_config;
 	const struct sdhci_msm_variant_ops *var_ops;
 	const struct sdhci_msm_offset *offset;
+	bool use_cdr;
+	u32 transfer_mode;
 };
 
 static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host)
@@ -1069,6 +1071,27 @@  static int sdhci_msm_restore_sdr_dll_config(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);
@@ -1079,8 +1102,14 @@  static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
 
-	if (!sdhci_msm_is_tuning_needed(host))
+	if (!sdhci_msm_is_tuning_needed(host)) {
+		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:
@@ -1562,6 +1591,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) {