Merge tag 'mmc-v5.6-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 19 Mar 2020 19:45:14 +0000 (12:45 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 19 Mar 2020 19:45:14 +0000 (12:45 -0700)
Pull MMC fixes from Ulf Hansson:

 - rtsx_pci: Fix support for some various speed modes

 - sdhci-of-at91: Fix support for GPIO card detect on SAMA5D2

 - sdhci-cadence: Fix support for DDR52 speed mode for eMMC on UniPhier

 - sdhci-acpi: Fix broken WP support on Acer Aspire Switch 10

 - sdhci-acpi: Workaround FW bug for suspend on Lenovo Miix 320

* tag 'mmc-v5.6-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: rtsx_pci: Fix support for speed-modes that relies on tuning
  mmc: sdhci-of-at91: fix cd-gpios for SAMA5D2
  mmc: sdhci-cadence: set SDHCI_QUIRK2_PRESET_VALUE_BROKEN for UniPhier
  mmc: sdhci-acpi: Disable write protect detection on Acer Aspire Switch 10 (SW5-012)
  mmc: sdhci-acpi: Switch signal voltage back to 3.3V on suspend on external microSD on Lenovo Miix 320

drivers/misc/cardreader/rts5227.c
drivers/misc/cardreader/rts5249.c
drivers/misc/cardreader/rts5260.c
drivers/misc/cardreader/rts5261.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-cadence.c
drivers/mmc/host/sdhci-of-at91.c

index 4feed29..423fecc 100644 (file)
@@ -394,7 +394,7 @@ static const struct pcr_ops rts522a_pcr_ops = {
 void rts522a_init_params(struct rtsx_pcr *pcr)
 {
        rts5227_init_params(pcr);
-
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(20, 20, 11);
        pcr->reg_pm_ctrl3 = RTS522A_PM_CTRL3;
 
        pcr->option.ocp_en = 1;
index db936e4..1a81cda 100644 (file)
@@ -618,6 +618,7 @@ static const struct pcr_ops rts524a_pcr_ops = {
 void rts524a_init_params(struct rtsx_pcr *pcr)
 {
        rts5249_init_params(pcr);
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 29, 11);
        pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
        pcr->option.ltr_l1off_snooze_sspwrgate =
                LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
@@ -733,6 +734,7 @@ static const struct pcr_ops rts525a_pcr_ops = {
 void rts525a_init_params(struct rtsx_pcr *pcr)
 {
        rts5249_init_params(pcr);
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(25, 29, 11);
        pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
        pcr->option.ltr_l1off_snooze_sspwrgate =
                LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
index 4214f02..711054e 100644 (file)
@@ -662,7 +662,7 @@ void rts5260_init_params(struct rtsx_pcr *pcr)
        pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
        pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
        pcr->aspm_en = ASPM_L1_EN;
-       pcr->tx_initial_phase = SET_CLOCK_PHASE(1, 29, 16);
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 29, 11);
        pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
 
        pcr->ic_version = rts5260_get_ic_version(pcr);
index bc4967a..78c3b1d 100644 (file)
@@ -764,7 +764,7 @@ void rts5261_init_params(struct rtsx_pcr *pcr)
        pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
        pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
        pcr->aspm_en = ASPM_L1_EN;
-       pcr->tx_initial_phase = SET_CLOCK_PHASE(20, 27, 16);
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 11);
        pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
 
        pcr->ic_version = rts5261_get_ic_version(pcr);
index bd50935..1108797 100644 (file)
@@ -606,19 +606,22 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host,
                u8 sample_point, bool rx)
 {
        struct rtsx_pcr *pcr = host->pcr;
-
+       u16 SD_VP_CTL = 0;
        dev_dbg(sdmmc_dev(host), "%s(%s): sample_point = %d\n",
                        __func__, rx ? "RX" : "TX", sample_point);
 
        rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, CHANGE_CLK);
-       if (rx)
+       if (rx) {
+               SD_VP_CTL = SD_VPRX_CTL;
                rtsx_pci_write_register(pcr, SD_VPRX_CTL,
                        PHASE_SELECT_MASK, sample_point);
-       else
+       } else {
+               SD_VP_CTL = SD_VPTX_CTL;
                rtsx_pci_write_register(pcr, SD_VPTX_CTL,
                        PHASE_SELECT_MASK, sample_point);
-       rtsx_pci_write_register(pcr, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
-       rtsx_pci_write_register(pcr, SD_VPCLK0_CTL, PHASE_NOT_RESET,
+       }
+       rtsx_pci_write_register(pcr, SD_VP_CTL, PHASE_NOT_RESET, 0);
+       rtsx_pci_write_register(pcr, SD_VP_CTL, PHASE_NOT_RESET,
                                PHASE_NOT_RESET);
        rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, 0);
        rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
index 9651dca..2a2173d 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/delay.h>
+#include <linux/dmi.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/pm.h>
@@ -72,9 +73,16 @@ struct sdhci_acpi_host {
        const struct sdhci_acpi_slot    *slot;
        struct platform_device          *pdev;
        bool                            use_runtime_pm;
+       bool                            is_intel;
+       bool                            reset_signal_volt_on_suspend;
        unsigned long                   private[0] ____cacheline_aligned;
 };
 
+enum {
+       DMI_QUIRK_RESET_SD_SIGNAL_VOLT_ON_SUSP                  = BIT(0),
+       DMI_QUIRK_SD_NO_WRITE_PROTECT                           = BIT(1),
+};
+
 static inline void *sdhci_acpi_priv(struct sdhci_acpi_host *c)
 {
        return (void *)c->private;
@@ -391,6 +399,8 @@ static int intel_probe_slot(struct platform_device *pdev, struct acpi_device *ad
        host->mmc_host_ops.start_signal_voltage_switch =
                                        intel_start_signal_voltage_switch;
 
+       c->is_intel = true;
+
        return 0;
 }
 
@@ -647,6 +657,36 @@ static const struct acpi_device_id sdhci_acpi_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);
 
+static const struct dmi_system_id sdhci_acpi_quirks[] = {
+       {
+               /*
+                * The Lenovo Miix 320-10ICR has a bug in the _PS0 method of
+                * the SHC1 ACPI device, this bug causes it to reprogram the
+                * wrong LDO (DLDO3) to 1.8V if 1.8V modes are used and the
+                * card is (runtime) suspended + resumed. DLDO3 is used for
+                * the LCD and setting it to 1.8V causes the LCD to go black.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
+               },
+               .driver_data = (void *)DMI_QUIRK_RESET_SD_SIGNAL_VOLT_ON_SUSP,
+       },
+       {
+               /*
+                * The Acer Aspire Switch 10 (SW5-012) microSD slot always
+                * reports the card being write-protected even though microSD
+                * cards do not have a write-protect switch at all.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
+               },
+               .driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT,
+       },
+       {} /* Terminating entry */
+};
+
 static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(struct acpi_device *adev)
 {
        const struct sdhci_acpi_uid_slot *u;
@@ -663,17 +703,23 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        const struct sdhci_acpi_slot *slot;
        struct acpi_device *device, *child;
+       const struct dmi_system_id *id;
        struct sdhci_acpi_host *c;
        struct sdhci_host *host;
        struct resource *iomem;
        resource_size_t len;
        size_t priv_size;
+       int quirks = 0;
        int err;
 
        device = ACPI_COMPANION(dev);
        if (!device)
                return -ENODEV;
 
+       id = dmi_first_match(sdhci_acpi_quirks);
+       if (id)
+               quirks = (long)id->driver_data;
+
        slot = sdhci_acpi_get_slot(device);
 
        /* Power on the SDHCI controller and its children */
@@ -759,6 +805,12 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
                        dev_warn(dev, "failed to setup card detect gpio\n");
                        c->use_runtime_pm = false;
                }
+
+               if (quirks & DMI_QUIRK_RESET_SD_SIGNAL_VOLT_ON_SUSP)
+                       c->reset_signal_volt_on_suspend = true;
+
+               if (quirks & DMI_QUIRK_SD_NO_WRITE_PROTECT)
+                       host->mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;
        }
 
        err = sdhci_setup_host(host);
@@ -823,17 +875,39 @@ static int sdhci_acpi_remove(struct platform_device *pdev)
        return 0;
 }
 
+static void __maybe_unused sdhci_acpi_reset_signal_voltage_if_needed(
+       struct device *dev)
+{
+       struct sdhci_acpi_host *c = dev_get_drvdata(dev);
+       struct sdhci_host *host = c->host;
+
+       if (c->is_intel && c->reset_signal_volt_on_suspend &&
+           host->mmc->ios.signal_voltage != MMC_SIGNAL_VOLTAGE_330) {
+               struct intel_host *intel_host = sdhci_acpi_priv(c);
+               unsigned int fn = INTEL_DSM_V33_SWITCH;
+               u32 result = 0;
+
+               intel_dsm(intel_host, dev, fn, &result);
+       }
+}
+
 #ifdef CONFIG_PM_SLEEP
 
 static int sdhci_acpi_suspend(struct device *dev)
 {
        struct sdhci_acpi_host *c = dev_get_drvdata(dev);
        struct sdhci_host *host = c->host;
+       int ret;
 
        if (host->tuning_mode != SDHCI_TUNING_MODE_3)
                mmc_retune_needed(host->mmc);
 
-       return sdhci_suspend_host(host);
+       ret = sdhci_suspend_host(host);
+       if (ret)
+               return ret;
+
+       sdhci_acpi_reset_signal_voltage_if_needed(dev);
+       return 0;
 }
 
 static int sdhci_acpi_resume(struct device *dev)
@@ -853,11 +927,17 @@ static int sdhci_acpi_runtime_suspend(struct device *dev)
 {
        struct sdhci_acpi_host *c = dev_get_drvdata(dev);
        struct sdhci_host *host = c->host;
+       int ret;
 
        if (host->tuning_mode != SDHCI_TUNING_MODE_3)
                mmc_retune_needed(host->mmc);
 
-       return sdhci_runtime_suspend_host(host);
+       ret = sdhci_runtime_suspend_host(host);
+       if (ret)
+               return ret;
+
+       sdhci_acpi_reset_signal_voltage_if_needed(dev);
+       return 0;
 }
 
 static int sdhci_acpi_runtime_resume(struct device *dev)
index 5827d37..e573495 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 
 #include "sdhci-pltfm.h"
 
@@ -235,6 +236,11 @@ static const struct sdhci_ops sdhci_cdns_ops = {
        .set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
 };
 
+static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
+       .ops = &sdhci_cdns_ops,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
 static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
        .ops = &sdhci_cdns_ops,
 };
@@ -334,6 +340,7 @@ static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
 static int sdhci_cdns_probe(struct platform_device *pdev)
 {
        struct sdhci_host *host;
+       const struct sdhci_pltfm_data *data;
        struct sdhci_pltfm_host *pltfm_host;
        struct sdhci_cdns_priv *priv;
        struct clk *clk;
@@ -350,8 +357,12 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       data = of_device_get_match_data(dev);
+       if (!data)
+               data = &sdhci_cdns_pltfm_data;
+
        nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node);
-       host = sdhci_pltfm_init(pdev, &sdhci_cdns_pltfm_data,
+       host = sdhci_pltfm_init(pdev, data,
                                struct_size(priv, phy_params, nr_phy_params));
        if (IS_ERR(host)) {
                ret = PTR_ERR(host);
@@ -431,7 +442,10 @@ static const struct dev_pm_ops sdhci_cdns_pm_ops = {
 };
 
 static const struct of_device_id sdhci_cdns_match[] = {
-       { .compatible = "socionext,uniphier-sd4hc" },
+       {
+               .compatible = "socionext,uniphier-sd4hc",
+               .data = &sdhci_cdns_uniphier_pltfm_data,
+       },
        { .compatible = "cdns,sd4hc" },
        { /* sentinel */ }
 };
index ab2bd31..fcef5c0 100644 (file)
@@ -132,7 +132,8 @@ static void sdhci_at91_reset(struct sdhci_host *host, u8 mask)
 
        sdhci_reset(host, mask);
 
-       if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+       if ((host->mmc->caps & MMC_CAP_NONREMOVABLE)
+           || mmc_gpio_get_cd(host->mmc) >= 0)
                sdhci_at91_set_force_card_detect(host);
 
        if (priv->cal_always_on && (mask & SDHCI_RESET_ALL))
@@ -427,8 +428,11 @@ static int sdhci_at91_probe(struct platform_device *pdev)
         * detection procedure using the SDMCC_CD signal is bypassed.
         * This bit is reset when a software reset for all command is performed
         * so we need to implement our own reset function to set back this bit.
+        *
+        * WA: SAMA5D2 doesn't drive CMD if using CD GPIO line.
         */
-       if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+       if ((host->mmc->caps & MMC_CAP_NONREMOVABLE)
+           || mmc_gpio_get_cd(host->mmc) >= 0)
                sdhci_at91_set_force_card_detect(host);
 
        pm_runtime_put_autosuspend(&pdev->dev);