소스 검색

Merge tag 'mmc-v4.6-rc4' of git://git.linaro.org/people/ulf.hansson/mmc

Pull MMC fixes from Ulf Hansson:
 "Here are a two MMC host fixes:

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

  - sunxi: Disable eMMC HS-DDR for Allwinner A80"

* tag 'mmc-v4.6-rc4' of git://git.linaro.org/people/ulf.hansson/mmc:
  mmc: sunxi: Disable eMMC HS-DDR (MMC_CAP_1_8V_DDR) for Allwinner A80
  mmc: sdhci-acpi: Reduce Baytrail eMMC/SD/SDIO hangs
Linus Torvalds 9 년 전
부모
커밋
a8feb78209
3개의 변경된 파일87개의 추가작업 그리고 0개의 파일을 삭제
  1. 1 0
      drivers/mmc/host/Kconfig
  2. 81 0
      drivers/mmc/host/sdhci-acpi.c
  3. 5 0
      drivers/mmc/host/sunxi-mmc.c

+ 1 - 0
drivers/mmc/host/Kconfig

@@ -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

+ 81 - 0
drivers/mmc/host/sdhci-acpi.c

@@ -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 {
@@ -116,6 +121,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);
@@ -322,6 +396,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;
 
 
@@ -447,6 +524,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);
 }
 }
 
 
@@ -470,6 +549,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);
 }
 }
 
 

+ 5 - 0
drivers/mmc/host/sunxi-mmc.c

@@ -1129,6 +1129,11 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
 				  MMC_CAP_1_8V_DDR |
 				  MMC_CAP_1_8V_DDR |
 				  MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ;
 				  MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ;
 
 
+	/* TODO MMC DDR is not working on A80 */
+	if (of_device_is_compatible(pdev->dev.of_node,
+				    "allwinner,sun9i-a80-mmc"))
+		mmc->caps &= ~MMC_CAP_1_8V_DDR;
+
 	ret = mmc_of_parse(mmc);
 	ret = mmc_of_parse(mmc);
 	if (ret)
 	if (ret)
 		goto error_free_dma;
 		goto error_free_dma;