diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-acpi.c')
-rw-r--r-- | drivers/mmc/host/sdhci-acpi.c | 128 |
1 files changed, 98 insertions, 30 deletions
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index a5cda926d38e..bed6a494f52c 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -41,6 +41,11 @@ #include <linux/mmc/pm.h> #include <linux/mmc/slot-gpio.h> +#ifdef CONFIG_X86 +#include <asm/cpu_device_id.h> +#include <asm/iosf_mbi.h> +#endif + #include "sdhci.h" enum { @@ -75,7 +80,6 @@ struct sdhci_acpi_host { const struct sdhci_acpi_slot *slot; struct platform_device *pdev; bool use_runtime_pm; - bool dma_setup; }; static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) @@ -83,33 +87,6 @@ static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) return c->slot && (c->slot->flags & flag); } -static int sdhci_acpi_enable_dma(struct sdhci_host *host) -{ - struct sdhci_acpi_host *c = sdhci_priv(host); - struct device *dev = &c->pdev->dev; - int err = -1; - - if (c->dma_setup) - return 0; - - if (host->flags & SDHCI_USE_64_BIT_DMA) { - if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) { - host->flags &= ~SDHCI_USE_64_BIT_DMA; - } else { - err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); - if (err) - dev_warn(dev, "Failed to set 64-bit DMA mask\n"); - } - } - - if (err) - err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); - - c->dma_setup = !err; - - return err; -} - static void sdhci_acpi_int_hw_reset(struct sdhci_host *host) { u8 reg; @@ -127,7 +104,6 @@ static void sdhci_acpi_int_hw_reset(struct sdhci_host *host) static const struct sdhci_ops sdhci_acpi_ops_dflt = { .set_clock = sdhci_set_clock, - .enable_dma = sdhci_acpi_enable_dma, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, @@ -135,7 +111,6 @@ static const struct sdhci_ops sdhci_acpi_ops_dflt = { static const struct sdhci_ops sdhci_acpi_ops_int = { .set_clock = sdhci_set_clock, - .enable_dma = sdhci_acpi_enable_dma, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, @@ -146,6 +121,75 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = { .ops = &sdhci_acpi_ops_int, }; +#ifdef CONFIG_X86 + +static bool sdhci_acpi_byt(void) +{ + static const struct x86_cpu_id byt[] = { + { X86_VENDOR_INTEL, 6, 0x37 }, + {} + }; + + return x86_match_cpu(byt); +} + +#define BYT_IOSF_SCCEP 0x63 +#define BYT_IOSF_OCP_NETCTRL0 0x1078 +#define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8) + +static void sdhci_acpi_byt_setting(struct device *dev) +{ + u32 val = 0; + + if (!sdhci_acpi_byt()) + return; + + if (iosf_mbi_read(BYT_IOSF_SCCEP, MBI_CR_READ, BYT_IOSF_OCP_NETCTRL0, + &val)) { + dev_err(dev, "%s read error\n", __func__); + return; + } + + if (!(val & BYT_IOSF_OCP_TIMEOUT_BASE)) + return; + + val &= ~BYT_IOSF_OCP_TIMEOUT_BASE; + + if (iosf_mbi_write(BYT_IOSF_SCCEP, MBI_CR_WRITE, BYT_IOSF_OCP_NETCTRL0, + val)) { + dev_err(dev, "%s write error\n", __func__); + return; + } + + dev_dbg(dev, "%s completed\n", __func__); +} + +static bool sdhci_acpi_byt_defer(struct device *dev) +{ + if (!sdhci_acpi_byt()) + return false; + + if (!iosf_mbi_available()) + return true; + + sdhci_acpi_byt_setting(dev); + + return false; +} + +#else + +static inline void sdhci_acpi_byt_setting(struct device *dev) +{ +} + +static inline bool sdhci_acpi_byt_defer(struct device *dev) +{ + return false; +} + +#endif + static int bxt_get_cd(struct mmc_host *mmc) { int gpio_cd = mmc_gpio_get_cd(mmc); @@ -264,6 +308,17 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { .probe_slot = sdhci_acpi_sd_probe_slot, }; +static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = { + .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION, + .quirks2 = SDHCI_QUIRK2_NO_1_8_V, + .caps = MMC_CAP_NONREMOVABLE, +}; + +static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = { + .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION, + .caps = MMC_CAP_NONREMOVABLE, +}; + struct sdhci_acpi_uid_slot { const char *hid; const char *uid; @@ -284,6 +339,8 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = { { "INT344D" , NULL, &sdhci_acpi_slot_int_sdio }, { "PNP0FFF" , "3" , &sdhci_acpi_slot_int_sd }, { "PNP0D40" }, + { "QCOM8051", NULL, &sdhci_acpi_slot_qcom_sd_3v }, + { "QCOM8052", NULL, &sdhci_acpi_slot_qcom_sd }, { }, }; @@ -298,6 +355,8 @@ static const struct acpi_device_id sdhci_acpi_ids[] = { { "INT3436" }, { "INT344D" }, { "PNP0D40" }, + { "QCOM8051" }, + { "QCOM8052" }, { }, }; MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); @@ -337,6 +396,9 @@ static int sdhci_acpi_probe(struct platform_device *pdev) if (acpi_bus_get_status(device) || !device->status.present) return -ENODEV; + if (sdhci_acpi_byt_defer(dev)) + return -EPROBE_DEFER; + hid = acpi_device_hid(device); uid = device->pnp.unique_id; @@ -418,6 +480,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev) pm_runtime_enable(dev); } + device_enable_async_suspend(dev); + return 0; err_free: @@ -460,6 +524,8 @@ static int sdhci_acpi_resume(struct device *dev) { struct sdhci_acpi_host *c = dev_get_drvdata(dev); + sdhci_acpi_byt_setting(&c->pdev->dev); + return sdhci_resume_host(c->host); } @@ -483,6 +549,8 @@ static int sdhci_acpi_runtime_resume(struct device *dev) { struct sdhci_acpi_host *c = dev_get_drvdata(dev); + sdhci_acpi_byt_setting(&c->pdev->dev); + return sdhci_runtime_resume_host(c->host); } |