mmc: sdhci-tegra: Fix switch to HS400ES mode
authorPrathamesh Shete <pshete@nvidia.com>
Tue, 14 Dec 2021 11:36:53 +0000 (17:06 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 29 Dec 2021 11:28:56 +0000 (12:28 +0100)
commit 4fc7261dbab139d3c64c3b618262504e16cfe7ee upstream.

When CMD13 is sent after switching to HS400ES mode, the bus
is operating at either MMC_HIGH_26_MAX_DTR or MMC_HIGH_52_MAX_DTR.
To meet Tegra SDHCI requirement at HS400ES mode, force SDHCI
interface clock to MMC_HS200_MAX_DTR (200 MHz) so that host
controller CAR clock and the interface clock are rate matched.

Signed-off-by: Prathamesh Shete <pshete@nvidia.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Fixes: dfc9700cef77 ("mmc: tegra: Implement HS400 enhanced strobe")
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20211214113653.4631-1-pshete@nvidia.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/mmc/host/sdhci-tegra.c

index a500187..9762ffa 100644 (file)
@@ -356,23 +356,6 @@ static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap)
        }
 }
 
-static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc,
-                                             struct mmc_ios *ios)
-{
-       struct sdhci_host *host = mmc_priv(mmc);
-       u32 val;
-
-       val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
-
-       if (ios->enhanced_strobe)
-               val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
-       else
-               val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
-
-       sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
-
-}
-
 static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -793,6 +776,32 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
        }
 }
 
+static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc,
+                                             struct mmc_ios *ios)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+       u32 val;
+
+       val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
+
+       if (ios->enhanced_strobe) {
+               val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
+               /*
+                * When CMD13 is sent from mmc_select_hs400es() after
+                * switching to HS400ES mode, the bus is operating at
+                * either MMC_HIGH_26_MAX_DTR or MMC_HIGH_52_MAX_DTR.
+                * To meet Tegra SDHCI requirement at HS400ES mode, force SDHCI
+                * interface clock to MMC_HS200_MAX_DTR (200 MHz) so that host
+                * controller CAR clock and the interface clock are rate matched.
+                */
+               tegra_sdhci_set_clock(host, MMC_HS200_MAX_DTR);
+       } else {
+               val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
+       }
+
+       sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
+}
+
 static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);