Merge tag 'mmc-v4.20-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 23 Nov 2018 18:36:02 +0000 (10:36 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 23 Nov 2018 18:36:02 +0000 (10:36 -0800)
Pull MMC fixes from Ulf Hansson:
 "MMC host:

   - sdhci-pci: Fixup card detect lookup

   - sdhci-pci: Workaround GLK firmware bug for tuning"

* tag 'mmc-v4.20-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: sdhci-pci: Workaround GLK firmware failing to restore the tuning value
  mmc: sdhci-pci: Try "cd" for card-detect lookup before using NULL

drivers/mmc/host/sdhci-pci-core.c

index 7bfd366d970dae374bae6acd36624eb23f719506..c4115bae5db187f1a331efd5c495b20bc31a5c86 100644 (file)
@@ -12,6 +12,7 @@
  *     - JMicron (hardware and technical support)
  */
 
+#include <linux/bitfield.h>
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/highmem.h>
@@ -462,6 +463,9 @@ struct intel_host {
        u32     dsm_fns;
        int     drv_strength;
        bool    d3_retune;
+       bool    rpm_retune_ok;
+       u32     glk_rx_ctrl1;
+       u32     glk_tun_val;
 };
 
 static const guid_t intel_dsm_guid =
@@ -791,6 +795,77 @@ cleanup:
        return ret;
 }
 
+#ifdef CONFIG_PM
+#define GLK_RX_CTRL1   0x834
+#define GLK_TUN_VAL    0x840
+#define GLK_PATH_PLL   GENMASK(13, 8)
+#define GLK_DLY                GENMASK(6, 0)
+/* Workaround firmware failing to restore the tuning value */
+static void glk_rpm_retune_wa(struct sdhci_pci_chip *chip, bool susp)
+{
+       struct sdhci_pci_slot *slot = chip->slots[0];
+       struct intel_host *intel_host = sdhci_pci_priv(slot);
+       struct sdhci_host *host = slot->host;
+       u32 glk_rx_ctrl1;
+       u32 glk_tun_val;
+       u32 dly;
+
+       if (intel_host->rpm_retune_ok || !mmc_can_retune(host->mmc))
+               return;
+
+       glk_rx_ctrl1 = sdhci_readl(host, GLK_RX_CTRL1);
+       glk_tun_val = sdhci_readl(host, GLK_TUN_VAL);
+
+       if (susp) {
+               intel_host->glk_rx_ctrl1 = glk_rx_ctrl1;
+               intel_host->glk_tun_val = glk_tun_val;
+               return;
+       }
+
+       if (!intel_host->glk_tun_val)
+               return;
+
+       if (glk_rx_ctrl1 != intel_host->glk_rx_ctrl1) {
+               intel_host->rpm_retune_ok = true;
+               return;
+       }
+
+       dly = FIELD_PREP(GLK_DLY, FIELD_GET(GLK_PATH_PLL, glk_rx_ctrl1) +
+                                 (intel_host->glk_tun_val << 1));
+       if (dly == FIELD_GET(GLK_DLY, glk_rx_ctrl1))
+               return;
+
+       glk_rx_ctrl1 = (glk_rx_ctrl1 & ~GLK_DLY) | dly;
+       sdhci_writel(host, glk_rx_ctrl1, GLK_RX_CTRL1);
+
+       intel_host->rpm_retune_ok = true;
+       chip->rpm_retune = true;
+       mmc_retune_needed(host->mmc);
+       pr_info("%s: Requiring re-tune after rpm resume", mmc_hostname(host->mmc));
+}
+
+static void glk_rpm_retune_chk(struct sdhci_pci_chip *chip, bool susp)
+{
+       if (chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC &&
+           !chip->rpm_retune)
+               glk_rpm_retune_wa(chip, susp);
+}
+
+static int glk_runtime_suspend(struct sdhci_pci_chip *chip)
+{
+       glk_rpm_retune_chk(chip, true);
+
+       return sdhci_cqhci_runtime_suspend(chip);
+}
+
+static int glk_runtime_resume(struct sdhci_pci_chip *chip)
+{
+       glk_rpm_retune_chk(chip, false);
+
+       return sdhci_cqhci_runtime_resume(chip);
+}
+#endif
+
 #ifdef CONFIG_ACPI
 static int ni_set_max_freq(struct sdhci_pci_slot *slot)
 {
@@ -879,8 +954,8 @@ static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = {
        .resume                 = sdhci_cqhci_resume,
 #endif
 #ifdef CONFIG_PM
-       .runtime_suspend        = sdhci_cqhci_runtime_suspend,
-       .runtime_resume         = sdhci_cqhci_runtime_resume,
+       .runtime_suspend        = glk_runtime_suspend,
+       .runtime_resume         = glk_runtime_resume,
 #endif
        .quirks                 = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
        .quirks2                = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
@@ -1762,8 +1837,13 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
                device_init_wakeup(&pdev->dev, true);
 
        if (slot->cd_idx >= 0) {
-               ret = mmc_gpiod_request_cd(host->mmc, NULL, slot->cd_idx,
+               ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx,
                                           slot->cd_override_level, 0, NULL);
+               if (ret && ret != -EPROBE_DEFER)
+                       ret = mmc_gpiod_request_cd(host->mmc, NULL,
+                                                  slot->cd_idx,
+                                                  slot->cd_override_level,
+                                                  0, NULL);
                if (ret == -EPROBE_DEFER)
                        goto remove;