From: Greg Kroah-Hartman Date: Mon, 5 Dec 2022 16:34:04 +0000 (+0100) Subject: 4.9-stable patches X-Git-Tag: v4.9.335~32 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ead357e582e4c1a2c3f52b9b81aedaa9c059f054;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: mmc-sdhci-fix-voltage-switch-delay.patch mmc-sdhci-use-field_get-for-preset-value-bit-masks.patch --- 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 index 00000000000..3e4626434ef --- /dev/null +++ b/queue-4.9/mmc-sdhci-fix-voltage-switch-delay.patch @@ -0,0 +1,181 @@ +From c981cdfb9925f64a364f13c2b4f98f877308a408 Mon Sep 17 00:00:00 2001 +From: Adrian Hunter +Date: Mon, 28 Nov 2022 15:32:56 +0200 +Subject: mmc: sdhci: Fix voltage switch delay + +From: Adrian Hunter + +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 +Link: https://lore.kernel.org/r/20221128133259.38305-2-adrian.hunter@intel.com +Signed-off-by: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..c2389e3ec63 --- /dev/null +++ b/queue-4.9/mmc-sdhci-use-field_get-for-preset-value-bit-masks.patch @@ -0,0 +1,81 @@ +From fa0910107a9fea170b817f31da2a65463e00e80e Mon Sep 17 00:00:00 2001 +From: Masahiro Yamada +Date: Thu, 12 Mar 2020 20:00:50 +0900 +Subject: mmc: sdhci: use FIELD_GET for preset value bit masks + +From: Masahiro Yamada + +commit fa0910107a9fea170b817f31da2a65463e00e80e upstream. + +Use the FIELD_GET macro to get access to the register fields. +Delete the shift macros. + +Signed-off-by: Masahiro Yamada +Link: https://lore.kernel.org/r/20200312110050.21732-1-yamada.masahiro@socionext.com +Signed-off-by: Ulf Hansson +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include + #include +@@ -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 + #include + #include + #include +@@ -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 + diff --git a/queue-4.9/series b/queue-4.9/series index e41a8f06c0e..3b78b2186c4 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -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