Linux-mmc Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH] mmc: sdhci-cadence: do not use hardware tuning for SD mode
@ 2020-07-20  6:11 Masahiro Yamada
  2020-08-05  6:33 ` Ulf Hansson
  0 siblings, 1 reply; 2+ messages in thread
From: Masahiro Yamada @ 2020-07-20  6:11 UTC (permalink / raw)
  To: Adrian Hunter, linux-mmc, Ulf Hansson; +Cc: Masahiro Yamada, linux-kernel

As commit ef6b75671b5f ("mmc: sdhci-cadence: send tune request twice to
work around errata") stated, this IP has an errata. This commit applies
the second workaround for the SD mode.

Due to the errata, it is not possible to use the hardware tuning provided
by SDHCI_HOST_CONTROL2.

Use the software-controlled tuning like the eMMC mode.

Set sdhci_host_ops::platform_execute_tuning instead of overriding
mmc_host_ops::execute_tuning.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 drivers/mmc/host/sdhci-cadence.c | 123 ++++++++++++++++---------------
 1 file changed, 62 insertions(+), 61 deletions(-)

diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
index 4a6c9ba82538..4d9f7681817c 100644
--- a/drivers/mmc/host/sdhci-cadence.c
+++ b/drivers/mmc/host/sdhci-cadence.c
@@ -202,57 +202,6 @@ static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv)
 	return FIELD_GET(SDHCI_CDNS_HRS06_MODE, tmp);
 }
 
-static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
-					 unsigned int timing)
-{
-	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
-	u32 mode;
-
-	switch (timing) {
-	case MMC_TIMING_MMC_HS:
-		mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
-		break;
-	case MMC_TIMING_MMC_DDR52:
-		mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
-		break;
-	case MMC_TIMING_MMC_HS200:
-		mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
-		break;
-	case MMC_TIMING_MMC_HS400:
-		if (priv->enhanced_strobe)
-			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
-		else
-			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
-		break;
-	default:
-		mode = SDHCI_CDNS_HRS06_MODE_SD;
-		break;
-	}
-
-	sdhci_cdns_set_emmc_mode(priv, mode);
-
-	/* For SD, fall back to the default handler */
-	if (mode == SDHCI_CDNS_HRS06_MODE_SD)
-		sdhci_set_uhs_signaling(host, timing);
-}
-
-static const struct sdhci_ops sdhci_cdns_ops = {
-	.set_clock = sdhci_set_clock,
-	.get_timeout_clock = sdhci_cdns_get_timeout_clock,
-	.set_bus_width = sdhci_set_bus_width,
-	.reset = sdhci_reset,
-	.set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
-};
-
-static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
-	.ops = &sdhci_cdns_ops,
-	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
-};
-
-static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
-	.ops = &sdhci_cdns_ops,
-};
-
 static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
 {
 	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
@@ -286,23 +235,24 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
 	return 0;
 }
 
-static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode)
+/*
+ * In SD mode, software must not use the hardware tuning and instead perform
+ * an almost identical procedure to eMMC.
+ */
+static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
 {
-	struct sdhci_host *host = mmc_priv(mmc);
 	int cur_streak = 0;
 	int max_streak = 0;
 	int end_of_streak = 0;
 	int i;
 
 	/*
-	 * This handler only implements the eMMC tuning that is specific to
-	 * this controller.  Fall back to the standard method for SD timing.
+	 * Do not execute tuning for UHS_SDR50 or UHS_DDR50.
+	 * The delay is set by probe, based on the DT properties.
 	 */
-	if (host->timing != MMC_TIMING_MMC_HS200)
-		return sdhci_execute_tuning(mmc, opcode);
-
-	if (WARN_ON(opcode != MMC_SEND_TUNING_BLOCK_HS200))
-		return -EINVAL;
+	if (host->timing != MMC_TIMING_MMC_HS200 &&
+	    host->timing != MMC_TIMING_UHS_SDR104)
+		return 0;
 
 	for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
 		if (sdhci_cdns_set_tune_val(host, i) ||
@@ -325,6 +275,58 @@ static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
 }
 
+static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
+					 unsigned int timing)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	u32 mode;
+
+	switch (timing) {
+	case MMC_TIMING_MMC_HS:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
+		break;
+	case MMC_TIMING_MMC_DDR52:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
+		break;
+	case MMC_TIMING_MMC_HS200:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
+		break;
+	case MMC_TIMING_MMC_HS400:
+		if (priv->enhanced_strobe)
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
+		else
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
+		break;
+	default:
+		mode = SDHCI_CDNS_HRS06_MODE_SD;
+		break;
+	}
+
+	sdhci_cdns_set_emmc_mode(priv, mode);
+
+	/* For SD, fall back to the default handler */
+	if (mode == SDHCI_CDNS_HRS06_MODE_SD)
+		sdhci_set_uhs_signaling(host, timing);
+}
+
+static const struct sdhci_ops sdhci_cdns_ops = {
+	.set_clock = sdhci_set_clock,
+	.get_timeout_clock = sdhci_cdns_get_timeout_clock,
+	.set_bus_width = sdhci_set_bus_width,
+	.reset = sdhci_reset,
+	.platform_execute_tuning = sdhci_cdns_execute_tuning,
+	.set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
+};
+
+static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
+	.ops = &sdhci_cdns_ops,
+	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
+static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
+	.ops = &sdhci_cdns_ops,
+};
+
 static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
 					     struct mmc_ios *ios)
 {
@@ -385,7 +387,6 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
 	priv->hrs_addr = host->ioaddr;
 	priv->enhanced_strobe = false;
 	host->ioaddr += SDHCI_CDNS_SRS_BASE;
-	host->mmc_host_ops.execute_tuning = sdhci_cdns_execute_tuning;
 	host->mmc_host_ops.hs400_enhanced_strobe =
 				sdhci_cdns_hs400_enhanced_strobe;
 	sdhci_enable_v4_mode(host);
-- 
2.25.1


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] mmc: sdhci-cadence: do not use hardware tuning for SD mode
  2020-07-20  6:11 [PATCH] mmc: sdhci-cadence: do not use hardware tuning for SD mode Masahiro Yamada
@ 2020-08-05  6:33 ` Ulf Hansson
  0 siblings, 0 replies; 2+ messages in thread
From: Ulf Hansson @ 2020-08-05  6:33 UTC (permalink / raw)
  To: Masahiro Yamada; +Cc: Adrian Hunter, linux-mmc, Linux Kernel Mailing List

On Mon, 20 Jul 2020 at 08:12, Masahiro Yamada
<yamada.masahiro@socionext.com> wrote:
>
> As commit ef6b75671b5f ("mmc: sdhci-cadence: send tune request twice to
> work around errata") stated, this IP has an errata. This commit applies
> the second workaround for the SD mode.
>
> Due to the errata, it is not possible to use the hardware tuning provided
> by SDHCI_HOST_CONTROL2.
>
> Use the software-controlled tuning like the eMMC mode.
>
> Set sdhci_host_ops::platform_execute_tuning instead of overriding
> mmc_host_ops::execute_tuning.
>
> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

Applied for next (a while ago), thanks!
Kind regards
Uffe


> ---
>
>  drivers/mmc/host/sdhci-cadence.c | 123 ++++++++++++++++---------------
>  1 file changed, 62 insertions(+), 61 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
> index 4a6c9ba82538..4d9f7681817c 100644
> --- a/drivers/mmc/host/sdhci-cadence.c
> +++ b/drivers/mmc/host/sdhci-cadence.c
> @@ -202,57 +202,6 @@ static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv)
>         return FIELD_GET(SDHCI_CDNS_HRS06_MODE, tmp);
>  }
>
> -static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
> -                                        unsigned int timing)
> -{
> -       struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
> -       u32 mode;
> -
> -       switch (timing) {
> -       case MMC_TIMING_MMC_HS:
> -               mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
> -               break;
> -       case MMC_TIMING_MMC_DDR52:
> -               mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
> -               break;
> -       case MMC_TIMING_MMC_HS200:
> -               mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
> -               break;
> -       case MMC_TIMING_MMC_HS400:
> -               if (priv->enhanced_strobe)
> -                       mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
> -               else
> -                       mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
> -               break;
> -       default:
> -               mode = SDHCI_CDNS_HRS06_MODE_SD;
> -               break;
> -       }
> -
> -       sdhci_cdns_set_emmc_mode(priv, mode);
> -
> -       /* For SD, fall back to the default handler */
> -       if (mode == SDHCI_CDNS_HRS06_MODE_SD)
> -               sdhci_set_uhs_signaling(host, timing);
> -}
> -
> -static const struct sdhci_ops sdhci_cdns_ops = {
> -       .set_clock = sdhci_set_clock,
> -       .get_timeout_clock = sdhci_cdns_get_timeout_clock,
> -       .set_bus_width = sdhci_set_bus_width,
> -       .reset = sdhci_reset,
> -       .set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
> -};
> -
> -static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
> -       .ops = &sdhci_cdns_ops,
> -       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
> -};
> -
> -static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
> -       .ops = &sdhci_cdns_ops,
> -};
> -
>  static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
>  {
>         struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
> @@ -286,23 +235,24 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
>         return 0;
>  }
>
> -static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode)
> +/*
> + * In SD mode, software must not use the hardware tuning and instead perform
> + * an almost identical procedure to eMMC.
> + */
> +static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
>  {
> -       struct sdhci_host *host = mmc_priv(mmc);
>         int cur_streak = 0;
>         int max_streak = 0;
>         int end_of_streak = 0;
>         int i;
>
>         /*
> -        * This handler only implements the eMMC tuning that is specific to
> -        * this controller.  Fall back to the standard method for SD timing.
> +        * Do not execute tuning for UHS_SDR50 or UHS_DDR50.
> +        * The delay is set by probe, based on the DT properties.
>          */
> -       if (host->timing != MMC_TIMING_MMC_HS200)
> -               return sdhci_execute_tuning(mmc, opcode);
> -
> -       if (WARN_ON(opcode != MMC_SEND_TUNING_BLOCK_HS200))
> -               return -EINVAL;
> +       if (host->timing != MMC_TIMING_MMC_HS200 &&
> +           host->timing != MMC_TIMING_UHS_SDR104)
> +               return 0;
>
>         for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
>                 if (sdhci_cdns_set_tune_val(host, i) ||
> @@ -325,6 +275,58 @@ static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode)
>         return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
>  }
>
> +static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
> +                                        unsigned int timing)
> +{
> +       struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
> +       u32 mode;
> +
> +       switch (timing) {
> +       case MMC_TIMING_MMC_HS:
> +               mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
> +               break;
> +       case MMC_TIMING_MMC_DDR52:
> +               mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
> +               break;
> +       case MMC_TIMING_MMC_HS200:
> +               mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
> +               break;
> +       case MMC_TIMING_MMC_HS400:
> +               if (priv->enhanced_strobe)
> +                       mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
> +               else
> +                       mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
> +               break;
> +       default:
> +               mode = SDHCI_CDNS_HRS06_MODE_SD;
> +               break;
> +       }
> +
> +       sdhci_cdns_set_emmc_mode(priv, mode);
> +
> +       /* For SD, fall back to the default handler */
> +       if (mode == SDHCI_CDNS_HRS06_MODE_SD)
> +               sdhci_set_uhs_signaling(host, timing);
> +}
> +
> +static const struct sdhci_ops sdhci_cdns_ops = {
> +       .set_clock = sdhci_set_clock,
> +       .get_timeout_clock = sdhci_cdns_get_timeout_clock,
> +       .set_bus_width = sdhci_set_bus_width,
> +       .reset = sdhci_reset,
> +       .platform_execute_tuning = sdhci_cdns_execute_tuning,
> +       .set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
> +};
> +
> +static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
> +       .ops = &sdhci_cdns_ops,
> +       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
> +};
> +
> +static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
> +       .ops = &sdhci_cdns_ops,
> +};
> +
>  static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
>                                              struct mmc_ios *ios)
>  {
> @@ -385,7 +387,6 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
>         priv->hrs_addr = host->ioaddr;
>         priv->enhanced_strobe = false;
>         host->ioaddr += SDHCI_CDNS_SRS_BASE;
> -       host->mmc_host_ops.execute_tuning = sdhci_cdns_execute_tuning;
>         host->mmc_host_ops.hs400_enhanced_strobe =
>                                 sdhci_cdns_hs400_enhanced_strobe;
>         sdhci_enable_v4_mode(host);
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, back to index

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-20  6:11 [PATCH] mmc: sdhci-cadence: do not use hardware tuning for SD mode Masahiro Yamada
2020-08-05  6:33 ` Ulf Hansson

Linux-mmc Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-mmc/0 linux-mmc/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-mmc linux-mmc/ https://lore.kernel.org/linux-mmc \
		linux-mmc@vger.kernel.org
	public-inbox-index linux-mmc

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-mmc


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git