Commit 2068f468 authored by Adrian Hunter's avatar Adrian Hunter Committed by Greg Kroah-Hartman

mmc: sdhci-acpi: Reduce Baytrail eMMC/SD/SDIO hangs

commit 6e1c7d61 upstream.

Baytrail eMMC/SD/SDIO host controllers have been known to
hang.  A change to a hardware setting has been found to
reduce the occurrence of such hangs.  This patch ensures
the correct setting.

This patch applies cleanly to v4.4+.  It could go to
earlier kernels also, so I will send backports to the
stable list in due course.
Signed-off-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2df18bf8
...@@ -97,6 +97,7 @@ config MMC_RICOH_MMC ...@@ -97,6 +97,7 @@ config MMC_RICOH_MMC
config MMC_SDHCI_ACPI config MMC_SDHCI_ACPI
tristate "SDHCI support for ACPI enumerated SDHCI controllers" tristate "SDHCI support for ACPI enumerated SDHCI controllers"
depends on MMC_SDHCI && ACPI depends on MMC_SDHCI && ACPI
select IOSF_MBI if X86
help help
This selects support for ACPI enumerated SDHCI controllers, This selects support for ACPI enumerated SDHCI controllers,
identified by ACPI Compatibility ID PNP0D40 or specific identified by ACPI Compatibility ID PNP0D40 or specific
......
...@@ -41,6 +41,11 @@ ...@@ -41,6 +41,11 @@
#include <linux/mmc/pm.h> #include <linux/mmc/pm.h>
#include <linux/mmc/slot-gpio.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" #include "sdhci.h"
enum { enum {
...@@ -146,6 +151,75 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = { ...@@ -146,6 +151,75 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = {
.ops = &sdhci_acpi_ops_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) static int bxt_get_cd(struct mmc_host *mmc)
{ {
int gpio_cd = mmc_gpio_get_cd(mmc); int gpio_cd = mmc_gpio_get_cd(mmc);
...@@ -337,6 +411,9 @@ static int sdhci_acpi_probe(struct platform_device *pdev) ...@@ -337,6 +411,9 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
if (acpi_bus_get_status(device) || !device->status.present) if (acpi_bus_get_status(device) || !device->status.present)
return -ENODEV; return -ENODEV;
if (sdhci_acpi_byt_defer(dev))
return -EPROBE_DEFER;
hid = acpi_device_hid(device); hid = acpi_device_hid(device);
uid = device->pnp.unique_id; uid = device->pnp.unique_id;
...@@ -460,6 +537,8 @@ static int sdhci_acpi_resume(struct device *dev) ...@@ -460,6 +537,8 @@ static int sdhci_acpi_resume(struct device *dev)
{ {
struct sdhci_acpi_host *c = dev_get_drvdata(dev); struct sdhci_acpi_host *c = dev_get_drvdata(dev);
sdhci_acpi_byt_setting(&c->pdev->dev);
return sdhci_resume_host(c->host); return sdhci_resume_host(c->host);
} }
...@@ -483,6 +562,8 @@ static int sdhci_acpi_runtime_resume(struct device *dev) ...@@ -483,6 +562,8 @@ static int sdhci_acpi_runtime_resume(struct device *dev)
{ {
struct sdhci_acpi_host *c = dev_get_drvdata(dev); struct sdhci_acpi_host *c = dev_get_drvdata(dev);
sdhci_acpi_byt_setting(&c->pdev->dev);
return sdhci_runtime_resume_host(c->host); return sdhci_runtime_resume_host(c->host);
} }
......
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