forked from Minki/linux
mmc: sdhci-acpi: Reduce Baytrail eMMC/SD/SDIO hangs
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: Adrian Hunter <adrian.hunter@intel.com> Cc: stable@vger.kernel.org # v4.4+ Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
parent
c3b46c7326
commit
6e1c7d6103
@ -97,6 +97,7 @@ config MMC_RICOH_MMC
|
||||
config MMC_SDHCI_ACPI
|
||||
tristate "SDHCI support for ACPI enumerated SDHCI controllers"
|
||||
depends on MMC_SDHCI && ACPI
|
||||
select IOSF_MBI if X86
|
||||
help
|
||||
This selects support for ACPI enumerated SDHCI controllers,
|
||||
identified by ACPI Compatibility ID PNP0D40 or specific
|
||||
|
@ -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 {
|
||||
@ -116,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);
|
||||
@ -322,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;
|
||||
|
||||
@ -447,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);
|
||||
}
|
||||
|
||||
@ -470,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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user