]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 5 Dec 2022 16:34:04 +0000 (17:34 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 5 Dec 2022 16:34:04 +0000 (17:34 +0100)
added patches:
mmc-sdhci-fix-voltage-switch-delay.patch
mmc-sdhci-use-field_get-for-preset-value-bit-masks.patch

queue-4.9/mmc-sdhci-fix-voltage-switch-delay.patch [new file with mode: 0644]
queue-4.9/mmc-sdhci-use-field_get-for-preset-value-bit-masks.patch [new file with mode: 0644]
queue-4.9/series

diff --git a/queue-4.9/mmc-sdhci-fix-voltage-switch-delay.patch b/queue-4.9/mmc-sdhci-fix-voltage-switch-delay.patch
new file mode 100644 (file)
index 0000000..3e46264
--- /dev/null
@@ -0,0 +1,181 @@
+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 */
diff --git a/queue-4.9/mmc-sdhci-use-field_get-for-preset-value-bit-masks.patch b/queue-4.9/mmc-sdhci-use-field_get-for-preset-value-bit-masks.patch
new file mode 100644 (file)
index 0000000..c2389e3
--- /dev/null
@@ -0,0 +1,81 @@
+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
index e41a8f06c0e21ae7f793cf4967495586c9bf9097..3b78b2186c48f43cd346429ff451de8c8b1bda99 100644 (file)
@@ -58,3 +58,5 @@ x86-tsx-add-a-feature-bit-for-tsx-control-msr-support.patch
 x86-pm-add-enumeration-check-before-spec-msrs-save-restore-setup.patch
 bluetooth-l2cap-fix-accepting-connection-request-for-invalid-spsm.patch
 x86-ioremap-fix-page-aligned-size-calculation-in-__i.patch
+mmc-sdhci-use-field_get-for-preset-value-bit-masks.patch
+mmc-sdhci-fix-voltage-switch-delay.patch