Commit 6c90b86a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v5.6-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

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
parents cd607737 4686392c
...@@ -394,7 +394,7 @@ static const struct pcr_ops rts522a_pcr_ops = { ...@@ -394,7 +394,7 @@ static const struct pcr_ops rts522a_pcr_ops = {
void rts522a_init_params(struct rtsx_pcr *pcr) void rts522a_init_params(struct rtsx_pcr *pcr)
{ {
rts5227_init_params(pcr); rts5227_init_params(pcr);
pcr->tx_initial_phase = SET_CLOCK_PHASE(20, 20, 11);
pcr->reg_pm_ctrl3 = RTS522A_PM_CTRL3; pcr->reg_pm_ctrl3 = RTS522A_PM_CTRL3;
pcr->option.ocp_en = 1; pcr->option.ocp_en = 1;
......
...@@ -618,6 +618,7 @@ static const struct pcr_ops rts524a_pcr_ops = { ...@@ -618,6 +618,7 @@ static const struct pcr_ops rts524a_pcr_ops = {
void rts524a_init_params(struct rtsx_pcr *pcr) void rts524a_init_params(struct rtsx_pcr *pcr)
{ {
rts5249_init_params(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_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
pcr->option.ltr_l1off_snooze_sspwrgate = pcr->option.ltr_l1off_snooze_sspwrgate =
LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF; LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
...@@ -733,6 +734,7 @@ static const struct pcr_ops rts525a_pcr_ops = { ...@@ -733,6 +734,7 @@ static const struct pcr_ops rts525a_pcr_ops = {
void rts525a_init_params(struct rtsx_pcr *pcr) void rts525a_init_params(struct rtsx_pcr *pcr)
{ {
rts5249_init_params(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_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
pcr->option.ltr_l1off_snooze_sspwrgate = pcr->option.ltr_l1off_snooze_sspwrgate =
LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF; LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
......
...@@ -662,7 +662,7 @@ void rts5260_init_params(struct rtsx_pcr *pcr) ...@@ -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_1v8 = CFG_DRIVER_TYPE_B;
pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B; pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
pcr->aspm_en = ASPM_L1_EN; 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->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
pcr->ic_version = rts5260_get_ic_version(pcr); pcr->ic_version = rts5260_get_ic_version(pcr);
......
...@@ -764,7 +764,7 @@ void rts5261_init_params(struct rtsx_pcr *pcr) ...@@ -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_1v8 = CFG_DRIVER_TYPE_B;
pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B; pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
pcr->aspm_en = ASPM_L1_EN; 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->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
pcr->ic_version = rts5261_get_ic_version(pcr); pcr->ic_version = rts5261_get_ic_version(pcr);
......
...@@ -606,19 +606,22 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host, ...@@ -606,19 +606,22 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host,
u8 sample_point, bool rx) u8 sample_point, bool rx)
{ {
struct rtsx_pcr *pcr = host->pcr; struct rtsx_pcr *pcr = host->pcr;
u16 SD_VP_CTL = 0;
dev_dbg(sdmmc_dev(host), "%s(%s): sample_point = %d\n", dev_dbg(sdmmc_dev(host), "%s(%s): sample_point = %d\n",
__func__, rx ? "RX" : "TX", sample_point); __func__, rx ? "RX" : "TX", sample_point);
rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, CHANGE_CLK); 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, rtsx_pci_write_register(pcr, SD_VPRX_CTL,
PHASE_SELECT_MASK, sample_point); PHASE_SELECT_MASK, sample_point);
else } else {
SD_VP_CTL = SD_VPTX_CTL;
rtsx_pci_write_register(pcr, SD_VPTX_CTL, rtsx_pci_write_register(pcr, SD_VPTX_CTL,
PHASE_SELECT_MASK, sample_point); 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); PHASE_NOT_RESET);
rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, 0); rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, 0);
rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0); rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/pm.h> #include <linux/mmc/pm.h>
...@@ -72,9 +73,16 @@ struct sdhci_acpi_host { ...@@ -72,9 +73,16 @@ struct sdhci_acpi_host {
const struct sdhci_acpi_slot *slot; const struct sdhci_acpi_slot *slot;
struct platform_device *pdev; struct platform_device *pdev;
bool use_runtime_pm; bool use_runtime_pm;
bool is_intel;
bool reset_signal_volt_on_suspend;
unsigned long private[0] ____cacheline_aligned; 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) static inline void *sdhci_acpi_priv(struct sdhci_acpi_host *c)
{ {
return (void *)c->private; return (void *)c->private;
...@@ -391,6 +399,8 @@ static int intel_probe_slot(struct platform_device *pdev, struct acpi_device *ad ...@@ -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 = host->mmc_host_ops.start_signal_voltage_switch =
intel_start_signal_voltage_switch; intel_start_signal_voltage_switch;
c->is_intel = true;
return 0; return 0;
} }
...@@ -647,6 +657,36 @@ static const struct acpi_device_id sdhci_acpi_ids[] = { ...@@ -647,6 +657,36 @@ static const struct acpi_device_id sdhci_acpi_ids[] = {
}; };
MODULE_DEVICE_TABLE(acpi, 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) static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(struct acpi_device *adev)
{ {
const struct sdhci_acpi_uid_slot *u; const struct sdhci_acpi_uid_slot *u;
...@@ -663,17 +703,23 @@ static int sdhci_acpi_probe(struct platform_device *pdev) ...@@ -663,17 +703,23 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const struct sdhci_acpi_slot *slot; const struct sdhci_acpi_slot *slot;
struct acpi_device *device, *child; struct acpi_device *device, *child;
const struct dmi_system_id *id;
struct sdhci_acpi_host *c; struct sdhci_acpi_host *c;
struct sdhci_host *host; struct sdhci_host *host;
struct resource *iomem; struct resource *iomem;
resource_size_t len; resource_size_t len;
size_t priv_size; size_t priv_size;
int quirks = 0;
int err; int err;
device = ACPI_COMPANION(dev); device = ACPI_COMPANION(dev);
if (!device) if (!device)
return -ENODEV; return -ENODEV;
id = dmi_first_match(sdhci_acpi_quirks);
if (id)
quirks = (long)id->driver_data;
slot = sdhci_acpi_get_slot(device); slot = sdhci_acpi_get_slot(device);
/* Power on the SDHCI controller and its children */ /* Power on the SDHCI controller and its children */
...@@ -759,6 +805,12 @@ static int sdhci_acpi_probe(struct platform_device *pdev) ...@@ -759,6 +805,12 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
dev_warn(dev, "failed to setup card detect gpio\n"); dev_warn(dev, "failed to setup card detect gpio\n");
c->use_runtime_pm = false; 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); err = sdhci_setup_host(host);
...@@ -823,17 +875,39 @@ static int sdhci_acpi_remove(struct platform_device *pdev) ...@@ -823,17 +875,39 @@ static int sdhci_acpi_remove(struct platform_device *pdev)
return 0; 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 #ifdef CONFIG_PM_SLEEP
static int sdhci_acpi_suspend(struct device *dev) static int sdhci_acpi_suspend(struct device *dev)
{ {
struct sdhci_acpi_host *c = dev_get_drvdata(dev); struct sdhci_acpi_host *c = dev_get_drvdata(dev);
struct sdhci_host *host = c->host; struct sdhci_host *host = c->host;
int ret;
if (host->tuning_mode != SDHCI_TUNING_MODE_3) if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc); 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) static int sdhci_acpi_resume(struct device *dev)
...@@ -853,11 +927,17 @@ static int sdhci_acpi_runtime_suspend(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_acpi_host *c = dev_get_drvdata(dev);
struct sdhci_host *host = c->host; struct sdhci_host *host = c->host;
int ret;
if (host->tuning_mode != SDHCI_TUNING_MODE_3) if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc); 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) static int sdhci_acpi_runtime_resume(struct device *dev)
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
...@@ -235,6 +236,11 @@ static const struct sdhci_ops sdhci_cdns_ops = { ...@@ -235,6 +236,11 @@ static const struct sdhci_ops sdhci_cdns_ops = {
.set_uhs_signaling = sdhci_cdns_set_uhs_signaling, .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 = { static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
.ops = &sdhci_cdns_ops, .ops = &sdhci_cdns_ops,
}; };
...@@ -334,6 +340,7 @@ static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc, ...@@ -334,6 +340,7 @@ static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
static int sdhci_cdns_probe(struct platform_device *pdev) static int sdhci_cdns_probe(struct platform_device *pdev)
{ {
struct sdhci_host *host; struct sdhci_host *host;
const struct sdhci_pltfm_data *data;
struct sdhci_pltfm_host *pltfm_host; struct sdhci_pltfm_host *pltfm_host;
struct sdhci_cdns_priv *priv; struct sdhci_cdns_priv *priv;
struct clk *clk; struct clk *clk;
...@@ -350,8 +357,12 @@ static int sdhci_cdns_probe(struct platform_device *pdev) ...@@ -350,8 +357,12 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
if (ret) if (ret)
return 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); 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)); struct_size(priv, phy_params, nr_phy_params));
if (IS_ERR(host)) { if (IS_ERR(host)) {
ret = PTR_ERR(host); ret = PTR_ERR(host);
...@@ -431,7 +442,10 @@ static const struct dev_pm_ops sdhci_cdns_pm_ops = { ...@@ -431,7 +442,10 @@ static const struct dev_pm_ops sdhci_cdns_pm_ops = {
}; };
static const struct of_device_id sdhci_cdns_match[] = { 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" }, { .compatible = "cdns,sd4hc" },
{ /* sentinel */ } { /* sentinel */ }
}; };
......
...@@ -132,7 +132,8 @@ static void sdhci_at91_reset(struct sdhci_host *host, u8 mask) ...@@ -132,7 +132,8 @@ static void sdhci_at91_reset(struct sdhci_host *host, u8 mask)
sdhci_reset(host, 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); sdhci_at91_set_force_card_detect(host);
if (priv->cal_always_on && (mask & SDHCI_RESET_ALL)) if (priv->cal_always_on && (mask & SDHCI_RESET_ALL))
...@@ -427,8 +428,11 @@ static int sdhci_at91_probe(struct platform_device *pdev) ...@@ -427,8 +428,11 @@ static int sdhci_at91_probe(struct platform_device *pdev)
* detection procedure using the SDMCC_CD signal is bypassed. * detection procedure using the SDMCC_CD signal is bypassed.
* This bit is reset when a software reset for all command is performed * 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. * 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); sdhci_at91_set_force_card_detect(host);
pm_runtime_put_autosuspend(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment