forked from mirrors/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
					
				
					 2 changed files with 82 additions and 0 deletions
				
			
		|  | @ -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 a new issue
	
	 Adrian Hunter
						Adrian Hunter