diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2016-10-05 05:11:24 -0400 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@linaro.org> | 2016-10-10 08:20:52 -0400 |
commit | fee686b74a9c115d3c4c851eb6613d1378ad0e0c (patch) | |
tree | 203e96d98eecd9b89288802c4af29aa5c11c6ae9 | |
parent | 6bc090631dfc3394da0619e920662e6636dbe89c (diff) |
mmc: sdhci-pci: Fix bus power failing to enable for some Intel controllers
Some Intel controllers (e.g. BXT) might fail to set bus power after a
D3 -> D0 transition due to the present state not yet having propagated.
Retry for up to 2 milliseconds.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
-rw-r--r-- | drivers/mmc/host/sdhci-pci-core.c | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 5e11e0e3be63..1d9e00a00e9f 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c | |||
@@ -32,6 +32,14 @@ | |||
32 | #include "sdhci-pci.h" | 32 | #include "sdhci-pci.h" |
33 | #include "sdhci-pci-o2micro.h" | 33 | #include "sdhci-pci-o2micro.h" |
34 | 34 | ||
35 | static int sdhci_pci_enable_dma(struct sdhci_host *host); | ||
36 | static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width); | ||
37 | static void sdhci_pci_hw_reset(struct sdhci_host *host); | ||
38 | static int sdhci_pci_select_drive_strength(struct sdhci_host *host, | ||
39 | struct mmc_card *card, | ||
40 | unsigned int max_dtr, int host_drv, | ||
41 | int card_drv, int *drv_type); | ||
42 | |||
35 | /*****************************************************************************\ | 43 | /*****************************************************************************\ |
36 | * * | 44 | * * |
37 | * Hardware specific quirk handling * | 45 | * Hardware specific quirk handling * |
@@ -390,6 +398,45 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) | |||
390 | return 0; | 398 | return 0; |
391 | } | 399 | } |
392 | 400 | ||
401 | #define SDHCI_INTEL_PWR_TIMEOUT_CNT 20 | ||
402 | #define SDHCI_INTEL_PWR_TIMEOUT_UDELAY 100 | ||
403 | |||
404 | static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode, | ||
405 | unsigned short vdd) | ||
406 | { | ||
407 | int cntr; | ||
408 | u8 reg; | ||
409 | |||
410 | sdhci_set_power(host, mode, vdd); | ||
411 | |||
412 | if (mode == MMC_POWER_OFF) | ||
413 | return; | ||
414 | |||
415 | /* | ||
416 | * Bus power might not enable after D3 -> D0 transition due to the | ||
417 | * present state not yet having propagated. Retry for up to 2ms. | ||
418 | */ | ||
419 | for (cntr = 0; cntr < SDHCI_INTEL_PWR_TIMEOUT_CNT; cntr++) { | ||
420 | reg = sdhci_readb(host, SDHCI_POWER_CONTROL); | ||
421 | if (reg & SDHCI_POWER_ON) | ||
422 | break; | ||
423 | udelay(SDHCI_INTEL_PWR_TIMEOUT_UDELAY); | ||
424 | reg |= SDHCI_POWER_ON; | ||
425 | sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); | ||
426 | } | ||
427 | } | ||
428 | |||
429 | static const struct sdhci_ops sdhci_intel_byt_ops = { | ||
430 | .set_clock = sdhci_set_clock, | ||
431 | .set_power = sdhci_intel_set_power, | ||
432 | .enable_dma = sdhci_pci_enable_dma, | ||
433 | .set_bus_width = sdhci_pci_set_bus_width, | ||
434 | .reset = sdhci_reset, | ||
435 | .set_uhs_signaling = sdhci_set_uhs_signaling, | ||
436 | .hw_reset = sdhci_pci_hw_reset, | ||
437 | .select_drive_strength = sdhci_pci_select_drive_strength, | ||
438 | }; | ||
439 | |||
393 | static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { | 440 | static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { |
394 | .allow_runtime_pm = true, | 441 | .allow_runtime_pm = true, |
395 | .probe_slot = byt_emmc_probe_slot, | 442 | .probe_slot = byt_emmc_probe_slot, |
@@ -397,6 +444,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { | |||
397 | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | | 444 | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | |
398 | SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 | | 445 | SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 | |
399 | SDHCI_QUIRK2_STOP_WITH_TC, | 446 | SDHCI_QUIRK2_STOP_WITH_TC, |
447 | .ops = &sdhci_intel_byt_ops, | ||
400 | }; | 448 | }; |
401 | 449 | ||
402 | static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { | 450 | static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { |
@@ -405,6 +453,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { | |||
405 | SDHCI_QUIRK2_PRESET_VALUE_BROKEN, | 453 | SDHCI_QUIRK2_PRESET_VALUE_BROKEN, |
406 | .allow_runtime_pm = true, | 454 | .allow_runtime_pm = true, |
407 | .probe_slot = byt_sdio_probe_slot, | 455 | .probe_slot = byt_sdio_probe_slot, |
456 | .ops = &sdhci_intel_byt_ops, | ||
408 | }; | 457 | }; |
409 | 458 | ||
410 | static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { | 459 | static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { |
@@ -415,6 +464,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { | |||
415 | .allow_runtime_pm = true, | 464 | .allow_runtime_pm = true, |
416 | .own_cd_for_runtime_pm = true, | 465 | .own_cd_for_runtime_pm = true, |
417 | .probe_slot = byt_sd_probe_slot, | 466 | .probe_slot = byt_sd_probe_slot, |
467 | .ops = &sdhci_intel_byt_ops, | ||
418 | }; | 468 | }; |
419 | 469 | ||
420 | /* Define Host controllers for Intel Merrifield platform */ | 470 | /* Define Host controllers for Intel Merrifield platform */ |