]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/mmc/host/sdhci-pci-core.c
mmc: sdhci-pci: Try "cd" for card-detect lookup before using NULL
[mirror_ubuntu-bionic-kernel.git] / drivers / mmc / host / sdhci-pci-core.c
index 3e4f04fd51755c6473d3fff0e9adefdca013c32b..01b8b650dfd90514aacbb9003c00db309f272037 100644 (file)
@@ -593,9 +593,36 @@ static void byt_read_dsm(struct sdhci_pci_slot *slot)
        slot->chip->rpm_retune = intel_host->d3_retune;
 }
 
-static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
+static int intel_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
+       int err = sdhci_execute_tuning(mmc, opcode);
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       if (err)
+               return err;
+
+       /*
+        * Tuning can leave the IP in an active state (Buffer Read Enable bit
+        * set) which prevents the entry to low power states (i.e. S0i3). Data
+        * reset will clear it.
+        */
+       sdhci_reset(host, SDHCI_RESET_DATA);
+
+       return 0;
+}
+
+static void byt_probe_slot(struct sdhci_pci_slot *slot)
+{
+       struct mmc_host_ops *ops = &slot->host->mmc_host_ops;
+
        byt_read_dsm(slot);
+
+       ops->execute_tuning = intel_execute_tuning;
+}
+
+static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
+{
+       byt_probe_slot(slot);
        slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
                                 MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
                                 MMC_CAP_CMD_DURING_TFR |
@@ -650,7 +677,7 @@ static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
 {
        int err;
 
-       byt_read_dsm(slot);
+       byt_probe_slot(slot);
 
        err = ni_set_max_freq(slot);
        if (err)
@@ -663,7 +690,7 @@ static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
 
 static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
 {
-       byt_read_dsm(slot);
+       byt_probe_slot(slot);
        slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE |
                                 MMC_CAP_WAIT_WHILE_BUSY;
        return 0;
@@ -671,7 +698,7 @@ static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
 
 static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
 {
-       byt_read_dsm(slot);
+       byt_probe_slot(slot);
        slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY |
                                 MMC_CAP_AGGRESSIVE_PM | MMC_CAP_CD_WAKE;
        slot->cd_idx = 0;
@@ -778,6 +805,8 @@ static int intel_mrfld_mmc_probe_slot(struct sdhci_pci_slot *slot)
                slot->host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
                break;
        case INTEL_MRFLD_SDIO:
+               /* Advertise 2.0v for compatibility with the SDIO card's OCR */
+               slot->host->ocr_mask = MMC_VDD_20_21 | MMC_VDD_165_195;
                slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE |
                                         MMC_CAP_POWER_OFF_CARD;
                break;
@@ -1153,7 +1182,7 @@ static void amd_enable_manual_tuning(struct pci_dev *pdev)
        pci_write_config_dword(pdev, AMD_SD_MISC_CONTROL, val);
 }
 
-static int amd_execute_tuning(struct sdhci_host *host, u32 opcode)
+static int amd_execute_tuning_hs200(struct sdhci_host *host, u32 opcode)
 {
        struct sdhci_pci_slot *slot = sdhci_priv(host);
        struct pci_dev *pdev = slot->chip->pdev;
@@ -1192,6 +1221,27 @@ static int amd_execute_tuning(struct sdhci_host *host, u32 opcode)
        return 0;
 }
 
+static int amd_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       /* AMD requires custom HS200 tuning */
+       if (host->timing == MMC_TIMING_MMC_HS200)
+               return amd_execute_tuning_hs200(host, opcode);
+
+       /* Otherwise perform standard SDHCI tuning */
+       return sdhci_execute_tuning(mmc, opcode);
+}
+
+static int amd_probe_slot(struct sdhci_pci_slot *slot)
+{
+       struct mmc_host_ops *ops = &slot->host->mmc_host_ops;
+
+       ops->execute_tuning = amd_execute_tuning;
+
+       return 0;
+}
+
 static int amd_probe(struct sdhci_pci_chip *chip)
 {
        struct pci_dev  *smbus_dev;
@@ -1226,12 +1276,12 @@ static const struct sdhci_ops amd_sdhci_pci_ops = {
        .set_bus_width                  = sdhci_set_bus_width,
        .reset                          = sdhci_reset,
        .set_uhs_signaling              = sdhci_set_uhs_signaling,
-       .platform_execute_tuning        = amd_execute_tuning,
 };
 
 static const struct sdhci_pci_fixes sdhci_amd = {
        .probe          = amd_probe,
        .ops            = &amd_sdhci_pci_ops,
+       .probe_slot     = amd_probe_slot,
 };
 
 static const struct pci_device_id pci_ids[] = {
@@ -1548,8 +1598,13 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
        host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP;
 
        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;