Skip to content

Commit c981cdf

Browse files
ahunter6storulf
authored andcommitted
mmc: sdhci: Fix voltage switch delay
Commit 20b92a3 ("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: 20b92a3 ("mmc: sdhci: update signal voltage switch code") Cc: [email protected] Signed-off-by: Adrian Hunter <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ulf Hansson <[email protected]>
1 parent c61bfb1 commit c981cdf

File tree

2 files changed

+56
-7
lines changed

2 files changed

+56
-7
lines changed

drivers/mmc/host/sdhci.c

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ static void sdhci_init(struct sdhci_host *host, int soft)
373373
if (soft) {
374374
/* force clock reconfiguration */
375375
host->clock = 0;
376+
host->reinit_uhs = true;
376377
mmc->ops->set_ios(mmc, &mmc->ios);
377378
}
378379
}
@@ -2293,11 +2294,46 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
22932294
}
22942295
EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
22952296

2297+
static bool sdhci_timing_has_preset(unsigned char timing)
2298+
{
2299+
switch (timing) {
2300+
case MMC_TIMING_UHS_SDR12:
2301+
case MMC_TIMING_UHS_SDR25:
2302+
case MMC_TIMING_UHS_SDR50:
2303+
case MMC_TIMING_UHS_SDR104:
2304+
case MMC_TIMING_UHS_DDR50:
2305+
case MMC_TIMING_MMC_DDR52:
2306+
return true;
2307+
};
2308+
return false;
2309+
}
2310+
2311+
static bool sdhci_preset_needed(struct sdhci_host *host, unsigned char timing)
2312+
{
2313+
return !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
2314+
sdhci_timing_has_preset(timing);
2315+
}
2316+
2317+
static bool sdhci_presetable_values_change(struct sdhci_host *host, struct mmc_ios *ios)
2318+
{
2319+
/*
2320+
* Preset Values are: Driver Strength, Clock Generator and SDCLK/RCLK
2321+
* Frequency. Check if preset values need to be enabled, or the Driver
2322+
* Strength needs updating. Note, clock changes are handled separately.
2323+
*/
2324+
return !host->preset_enabled &&
2325+
(sdhci_preset_needed(host, ios->timing) || host->drv_type != ios->drv_type);
2326+
}
2327+
22962328
void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
22972329
{
22982330
struct sdhci_host *host = mmc_priv(mmc);
2331+
bool reinit_uhs = host->reinit_uhs;
2332+
bool turning_on_clk = false;
22992333
u8 ctrl;
23002334

2335+
host->reinit_uhs = false;
2336+
23012337
if (ios->power_mode == MMC_POWER_UNDEFINED)
23022338
return;
23032339

@@ -2323,6 +2359,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
23232359
sdhci_enable_preset_value(host, false);
23242360

23252361
if (!ios->clock || ios->clock != host->clock) {
2362+
turning_on_clk = ios->clock && !host->clock;
2363+
23262364
host->ops->set_clock(host, ios->clock);
23272365
host->clock = ios->clock;
23282366

@@ -2349,6 +2387,17 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
23492387

23502388
host->ops->set_bus_width(host, ios->bus_width);
23512389

2390+
/*
2391+
* Special case to avoid multiple clock changes during voltage
2392+
* switching.
2393+
*/
2394+
if (!reinit_uhs &&
2395+
turning_on_clk &&
2396+
host->timing == ios->timing &&
2397+
host->version >= SDHCI_SPEC_300 &&
2398+
!sdhci_presetable_values_change(host, ios))
2399+
return;
2400+
23522401
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
23532402

23542403
if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) {
@@ -2392,6 +2441,7 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
23922441
}
23932442

23942443
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
2444+
host->drv_type = ios->drv_type;
23952445
} else {
23962446
/*
23972447
* According to SDHC Spec v3.00, if the Preset Value
@@ -2419,19 +2469,14 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
24192469
host->ops->set_uhs_signaling(host, ios->timing);
24202470
host->timing = ios->timing;
24212471

2422-
if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
2423-
((ios->timing == MMC_TIMING_UHS_SDR12) ||
2424-
(ios->timing == MMC_TIMING_UHS_SDR25) ||
2425-
(ios->timing == MMC_TIMING_UHS_SDR50) ||
2426-
(ios->timing == MMC_TIMING_UHS_SDR104) ||
2427-
(ios->timing == MMC_TIMING_UHS_DDR50) ||
2428-
(ios->timing == MMC_TIMING_MMC_DDR52))) {
2472+
if (sdhci_preset_needed(host, ios->timing)) {
24292473
u16 preset;
24302474

24312475
sdhci_enable_preset_value(host, true);
24322476
preset = sdhci_get_preset_value(host);
24332477
ios->drv_type = FIELD_GET(SDHCI_PRESET_DRV_MASK,
24342478
preset);
2479+
host->drv_type = ios->drv_type;
24352480
}
24362481

24372482
/* Re-enable SD Clock */
@@ -3768,6 +3813,7 @@ int sdhci_resume_host(struct sdhci_host *host)
37683813
sdhci_init(host, 0);
37693814
host->pwr = 0;
37703815
host->clock = 0;
3816+
host->reinit_uhs = true;
37713817
mmc->ops->set_ios(mmc, &mmc->ios);
37723818
} else {
37733819
sdhci_init(host, (mmc->pm_flags & MMC_PM_KEEP_POWER));
@@ -3830,6 +3876,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset)
38303876
/* Force clock and power re-program */
38313877
host->pwr = 0;
38323878
host->clock = 0;
3879+
host->reinit_uhs = true;
38333880
mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
38343881
mmc->ops->set_ios(mmc, &mmc->ios);
38353882

drivers/mmc/host/sdhci.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,8 @@ struct sdhci_host {
524524

525525
unsigned int clock; /* Current clock (MHz) */
526526
u8 pwr; /* Current voltage */
527+
u8 drv_type; /* Current UHS-I driver type */
528+
bool reinit_uhs; /* Force UHS-related re-initialization */
527529

528530
bool runtime_suspended; /* Host is runtime suspended */
529531
bool bus_on; /* Bus power prevents runtime suspend */

0 commit comments

Comments
 (0)