--- /dev/null
+From c981cdfb9925f64a364f13c2b4f98f877308a408 Mon Sep 17 00:00:00 2001
+From: Adrian Hunter <adrian.hunter@intel.com>
+Date: Mon, 28 Nov 2022 15:32:56 +0200
+Subject: mmc: sdhci: Fix voltage switch delay
+
+From: Adrian Hunter <adrian.hunter@intel.com>
+
+commit c981cdfb9925f64a364f13c2b4f98f877308a408 upstream.
+
+Commit 20b92a30b561 ("mmc: sdhci: update signal voltage switch code")
+removed voltage switch delays from sdhci because mmc core had been
+enhanced to support them. However that assumed that sdhci_set_ios()
+did a single clock change, which it did not, and so the delays in mmc
+core, which should have come after the first clock change, were not
+effective.
+
+Fix by avoiding re-configuring UHS and preset settings when the clock
+is turning on and the settings have not changed. That then also avoids
+the associated clock changes, so that then sdhci_set_ios() does a single
+clock change when voltage switching, and the mmc core delays become
+effective.
+
+To do that has meant keeping track of driver strength (host->drv_type),
+and cases of reinitialization (host->reinit_uhs).
+
+Note also, the 'turning_on_clk' restriction should not be necessary
+but is done to minimize the impact of the change on stable kernels.
+
+Fixes: 20b92a30b561 ("mmc: sdhci: update signal voltage switch code")
+Cc: stable@vger.kernel.org
+Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
+Link: https://lore.kernel.org/r/20221128133259.38305-2-adrian.hunter@intel.com
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mmc/host/sdhci.c | 61 +++++++++++++++++++++++++++++++++++++++++------
+ drivers/mmc/host/sdhci.h | 2 +
+ 2 files changed, 56 insertions(+), 7 deletions(-)
+
+--- a/drivers/mmc/host/sdhci.c
++++ b/drivers/mmc/host/sdhci.c
+@@ -240,6 +240,7 @@ static void sdhci_init(struct sdhci_host
+ if (soft) {
+ /* force clock reconfiguration */
+ host->clock = 0;
++ host->reinit_uhs = true;
+ mmc->ops->set_ios(mmc, &mmc->ios);
+ }
+ }
+@@ -1580,12 +1581,47 @@ void sdhci_set_uhs_signaling(struct sdhc
+ }
+ EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
+
++static bool sdhci_timing_has_preset(unsigned char timing)
++{
++ switch (timing) {
++ case MMC_TIMING_UHS_SDR12:
++ case MMC_TIMING_UHS_SDR25:
++ case MMC_TIMING_UHS_SDR50:
++ case MMC_TIMING_UHS_SDR104:
++ case MMC_TIMING_UHS_DDR50:
++ case MMC_TIMING_MMC_DDR52:
++ return true;
++ };
++ return false;
++}
++
++static bool sdhci_preset_needed(struct sdhci_host *host, unsigned char timing)
++{
++ return !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
++ sdhci_timing_has_preset(timing);
++}
++
++static bool sdhci_presetable_values_change(struct sdhci_host *host, struct mmc_ios *ios)
++{
++ /*
++ * Preset Values are: Driver Strength, Clock Generator and SDCLK/RCLK
++ * Frequency. Check if preset values need to be enabled, or the Driver
++ * Strength needs updating. Note, clock changes are handled separately.
++ */
++ return !host->preset_enabled &&
++ (sdhci_preset_needed(host, ios->timing) || host->drv_type != ios->drv_type);
++}
++
+ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+ {
+ struct sdhci_host *host = mmc_priv(mmc);
++ bool reinit_uhs = host->reinit_uhs;
++ bool turning_on_clk = false;
+ unsigned long flags;
+ u8 ctrl;
+
++ host->reinit_uhs = false;
++
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (host->flags & SDHCI_DEVICE_DEAD) {
+@@ -1611,6 +1647,8 @@ static void sdhci_set_ios(struct mmc_hos
+ sdhci_enable_preset_value(host, false);
+
+ if (!ios->clock || ios->clock != host->clock) {
++ turning_on_clk = ios->clock && !host->clock;
++
+ host->ops->set_clock(host, ios->clock);
+ host->clock = ios->clock;
+
+@@ -1637,6 +1675,17 @@ static void sdhci_set_ios(struct mmc_hos
+
+ host->ops->set_bus_width(host, ios->bus_width);
+
++ /*
++ * Special case to avoid multiple clock changes during voltage
++ * switching.
++ */
++ if (!reinit_uhs &&
++ turning_on_clk &&
++ host->timing == ios->timing &&
++ host->version >= SDHCI_SPEC_300 &&
++ !sdhci_presetable_values_change(host, ios))
++ return;
++
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+
+ if ((ios->timing == MMC_TIMING_SD_HS ||
+@@ -1682,6 +1731,7 @@ static void sdhci_set_ios(struct mmc_hos
+ }
+
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
++ host->drv_type = ios->drv_type;
+ } else {
+ /*
+ * According to SDHC Spec v3.00, if the Preset Value
+@@ -1709,19 +1759,14 @@ static void sdhci_set_ios(struct mmc_hos
+ host->ops->set_uhs_signaling(host, ios->timing);
+ host->timing = ios->timing;
+
+- if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
+- ((ios->timing == MMC_TIMING_UHS_SDR12) ||
+- (ios->timing == MMC_TIMING_UHS_SDR25) ||
+- (ios->timing == MMC_TIMING_UHS_SDR50) ||
+- (ios->timing == MMC_TIMING_UHS_SDR104) ||
+- (ios->timing == MMC_TIMING_UHS_DDR50) ||
+- (ios->timing == MMC_TIMING_MMC_DDR52))) {
++ if (sdhci_preset_needed(host, ios->timing)) {
+ u16 preset;
+
+ sdhci_enable_preset_value(host, true);
+ preset = sdhci_get_preset_value(host);
+ ios->drv_type = FIELD_GET(SDHCI_PRESET_DRV_MASK,
+ preset);
++ host->drv_type = ios->drv_type;
+ }
+
+ /* Re-enable SD Clock */
+@@ -2882,6 +2927,7 @@ int sdhci_resume_host(struct sdhci_host
+ sdhci_init(host, 0);
+ host->pwr = 0;
+ host->clock = 0;
++ host->reinit_uhs = true;
+ mmc->ops->set_ios(mmc, &mmc->ios);
+ } else {
+ sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
+@@ -2946,6 +2992,7 @@ int sdhci_runtime_resume_host(struct sdh
+ /* Force clock and power re-program */
+ host->pwr = 0;
+ host->clock = 0;
++ host->reinit_uhs = true;
+ mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
+ mmc->ops->set_ios(mmc, &mmc->ios);
+
+--- a/drivers/mmc/host/sdhci.h
++++ b/drivers/mmc/host/sdhci.h
+@@ -466,6 +466,8 @@ struct sdhci_host {
+
+ unsigned int clock; /* Current clock (MHz) */
+ u8 pwr; /* Current voltage */
++ u8 drv_type; /* Current UHS-I driver type */
++ bool reinit_uhs; /* Force UHS-related re-initialization */
+
+ bool runtime_suspended; /* Host is runtime suspended */
+ bool bus_on; /* Bus power prevents runtime suspend */
--- /dev/null
+From fa0910107a9fea170b817f31da2a65463e00e80e Mon Sep 17 00:00:00 2001
+From: Masahiro Yamada <yamada.masahiro@socionext.com>
+Date: Thu, 12 Mar 2020 20:00:50 +0900
+Subject: mmc: sdhci: use FIELD_GET for preset value bit masks
+
+From: Masahiro Yamada <yamada.masahiro@socionext.com>
+
+commit fa0910107a9fea170b817f31da2a65463e00e80e upstream.
+
+Use the FIELD_GET macro to get access to the register fields.
+Delete the shift macros.
+
+Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
+Link: https://lore.kernel.org/r/20200312110050.21732-1-yamada.masahiro@socionext.com
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mmc/host/sdhci.c | 10 +++++-----
+ drivers/mmc/host/sdhci.h | 10 ++++------
+ 2 files changed, 9 insertions(+), 11 deletions(-)
+
+--- a/drivers/mmc/host/sdhci.c
++++ b/drivers/mmc/host/sdhci.c
+@@ -13,6 +13,7 @@
+ * - JMicron (hardware and technical support)
+ */
+
++#include <linux/bitfield.h>
+ #include <linux/delay.h>
+ #include <linux/highmem.h>
+ #include <linux/io.h>
+@@ -1266,10 +1267,9 @@ u16 sdhci_calc_clk(struct sdhci_host *ho
+
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ pre_val = sdhci_get_preset_value(host);
+- div = (pre_val & SDHCI_PRESET_SDCLK_FREQ_MASK)
+- >> SDHCI_PRESET_SDCLK_FREQ_SHIFT;
++ div = FIELD_GET(SDHCI_PRESET_SDCLK_FREQ_MASK, pre_val);
+ if (host->clk_mul &&
+- (pre_val & SDHCI_PRESET_CLKGEN_SEL_MASK)) {
++ (pre_val & SDHCI_PRESET_CLKGEN_SEL)) {
+ clk = SDHCI_PROG_CLOCK_MODE;
+ real_div = div + 1;
+ clk_mul = host->clk_mul;
+@@ -1720,8 +1720,8 @@ static void sdhci_set_ios(struct mmc_hos
+
+ sdhci_enable_preset_value(host, true);
+ preset = sdhci_get_preset_value(host);
+- ios->drv_type = (preset & SDHCI_PRESET_DRV_MASK)
+- >> SDHCI_PRESET_DRV_SHIFT;
++ ios->drv_type = FIELD_GET(SDHCI_PRESET_DRV_MASK,
++ preset);
+ }
+
+ /* Re-enable SD Clock */
+--- a/drivers/mmc/host/sdhci.h
++++ b/drivers/mmc/host/sdhci.h
+@@ -13,6 +13,7 @@
+ #ifndef __SDHCI_HW_H
+ #define __SDHCI_HW_H
+
++#include <linux/bits.h>
+ #include <linux/scatterlist.h>
+ #include <linux/compiler.h>
+ #include <linux/types.h>
+@@ -244,12 +245,9 @@
+ #define SDHCI_PRESET_FOR_SDR104 0x6C
+ #define SDHCI_PRESET_FOR_DDR50 0x6E
+ #define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
+-#define SDHCI_PRESET_DRV_MASK 0xC000
+-#define SDHCI_PRESET_DRV_SHIFT 14
+-#define SDHCI_PRESET_CLKGEN_SEL_MASK 0x400
+-#define SDHCI_PRESET_CLKGEN_SEL_SHIFT 10
+-#define SDHCI_PRESET_SDCLK_FREQ_MASK 0x3FF
+-#define SDHCI_PRESET_SDCLK_FREQ_SHIFT 0
++#define SDHCI_PRESET_DRV_MASK GENMASK(15, 14)
++#define SDHCI_PRESET_CLKGEN_SEL BIT(10)
++#define SDHCI_PRESET_SDCLK_FREQ_MASK GENMASK(9, 0)
+
+ #define SDHCI_SLOT_INT_STATUS 0xFC
+