mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 22:44:27 -05:00 
			
		
		
		
	Refresh patches, following required reworking: ar71xx/patches-4.9/930-chipidea-pullup.patch layerscape/patches-4.9/302-dts-support-layercape.patch sunxi/patches-4.9/0052-stmmac-form-4-12.patch Fixes for CVEs: CVE-2018-1108 CVE-2018-1092 Tested on: ar71xx Archer C7 v2 Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> Tested-by: Koen Vandeputte <koen.vandeputte@ncentric.com> Tested-by: Arjen de Korte <build+openwrt@de-korte.org>
		
			
				
	
	
		
			595 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			595 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 4215d5757595e7ec7ca146c2b901beb177f415d8 Mon Sep 17 00:00:00 2001
 | 
						|
From: Yangbo Lu <yangbo.lu@nxp.com>
 | 
						|
Date: Wed, 17 Jan 2018 15:37:13 +0800
 | 
						|
Subject: [PATCH 24/30] mmc: layerscape support
 | 
						|
 | 
						|
This is an integrated patch for layerscape mmc support.
 | 
						|
 | 
						|
Adrian Hunter <adrian.hunter@intel.com>
 | 
						|
Jaehoon Chung <jh80.chung@samsung.com>
 | 
						|
Masahiro Yamada <yamada.masahiro@socionext.com>
 | 
						|
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
 | 
						|
---
 | 
						|
 drivers/mmc/host/Kconfig          |   1 +
 | 
						|
 drivers/mmc/host/sdhci-esdhc.h    |  52 +++++---
 | 
						|
 drivers/mmc/host/sdhci-of-esdhc.c | 265 ++++++++++++++++++++++++++++++++++++--
 | 
						|
 drivers/mmc/host/sdhci.c          |  45 ++++---
 | 
						|
 drivers/mmc/host/sdhci.h          |   3 +
 | 
						|
 5 files changed, 320 insertions(+), 46 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/mmc/host/Kconfig
 | 
						|
+++ b/drivers/mmc/host/Kconfig
 | 
						|
@@ -144,6 +144,7 @@ config MMC_SDHCI_OF_ESDHC
 | 
						|
 	depends on MMC_SDHCI_PLTFM
 | 
						|
 	depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE
 | 
						|
 	select MMC_SDHCI_IO_ACCESSORS
 | 
						|
+	select FSL_GUTS
 | 
						|
 	help
 | 
						|
 	  This selects the Freescale eSDHC controller support.
 | 
						|
 
 | 
						|
--- a/drivers/mmc/host/sdhci-esdhc.h
 | 
						|
+++ b/drivers/mmc/host/sdhci-esdhc.h
 | 
						|
@@ -24,30 +24,46 @@
 | 
						|
 				SDHCI_QUIRK_PIO_NEEDS_DELAY | \
 | 
						|
 				SDHCI_QUIRK_NO_HISPD_BIT)
 | 
						|
 
 | 
						|
-#define ESDHC_PROCTL		0x28
 | 
						|
-
 | 
						|
-#define ESDHC_SYSTEM_CONTROL	0x2c
 | 
						|
-#define ESDHC_CLOCK_MASK	0x0000fff0
 | 
						|
-#define ESDHC_PREDIV_SHIFT	8
 | 
						|
-#define ESDHC_DIVIDER_SHIFT	4
 | 
						|
-#define ESDHC_CLOCK_PEREN	0x00000004
 | 
						|
-#define ESDHC_CLOCK_HCKEN	0x00000002
 | 
						|
-#define ESDHC_CLOCK_IPGEN	0x00000001
 | 
						|
-
 | 
						|
 /* pltfm-specific */
 | 
						|
 #define ESDHC_HOST_CONTROL_LE	0x20
 | 
						|
 
 | 
						|
 /*
 | 
						|
- * P2020 interpretation of the SDHCI_HOST_CONTROL register
 | 
						|
+ * eSDHC register definition
 | 
						|
  */
 | 
						|
-#define ESDHC_CTRL_4BITBUS          (0x1 << 1)
 | 
						|
-#define ESDHC_CTRL_8BITBUS          (0x2 << 1)
 | 
						|
-#define ESDHC_CTRL_BUSWIDTH_MASK    (0x3 << 1)
 | 
						|
-
 | 
						|
-/* OF-specific */
 | 
						|
-#define ESDHC_DMA_SYSCTL	0x40c
 | 
						|
-#define ESDHC_DMA_SNOOP		0x00000040
 | 
						|
 
 | 
						|
-#define ESDHC_HOST_CONTROL_RES	0x01
 | 
						|
+/* Present State Register */
 | 
						|
+#define ESDHC_PRSSTAT			0x24
 | 
						|
+#define ESDHC_CLOCK_STABLE		0x00000008
 | 
						|
+
 | 
						|
+/* Protocol Control Register */
 | 
						|
+#define ESDHC_PROCTL			0x28
 | 
						|
+#define ESDHC_VOLT_SEL			0x00000400
 | 
						|
+#define ESDHC_CTRL_4BITBUS		(0x1 << 1)
 | 
						|
+#define ESDHC_CTRL_8BITBUS		(0x2 << 1)
 | 
						|
+#define ESDHC_CTRL_BUSWIDTH_MASK	(0x3 << 1)
 | 
						|
+#define ESDHC_HOST_CONTROL_RES		0x01
 | 
						|
+
 | 
						|
+/* System Control Register */
 | 
						|
+#define ESDHC_SYSTEM_CONTROL		0x2c
 | 
						|
+#define ESDHC_CLOCK_MASK		0x0000fff0
 | 
						|
+#define ESDHC_PREDIV_SHIFT		8
 | 
						|
+#define ESDHC_DIVIDER_SHIFT		4
 | 
						|
+#define ESDHC_CLOCK_SDCLKEN		0x00000008
 | 
						|
+#define ESDHC_CLOCK_PEREN		0x00000004
 | 
						|
+#define ESDHC_CLOCK_HCKEN		0x00000002
 | 
						|
+#define ESDHC_CLOCK_IPGEN		0x00000001
 | 
						|
+
 | 
						|
+/* Host Controller Capabilities Register 2 */
 | 
						|
+#define ESDHC_CAPABILITIES_1		0x114
 | 
						|
+
 | 
						|
+/* Tuning Block Control Register */
 | 
						|
+#define ESDHC_TBCTL			0x120
 | 
						|
+#define ESDHC_TB_EN			0x00000004
 | 
						|
+
 | 
						|
+/* Control Register for DMA transfer */
 | 
						|
+#define ESDHC_DMA_SYSCTL		0x40c
 | 
						|
+#define ESDHC_PERIPHERAL_CLK_SEL	0x00080000
 | 
						|
+#define ESDHC_FLUSH_ASYNC_FIFO		0x00040000
 | 
						|
+#define ESDHC_DMA_SNOOP			0x00000040
 | 
						|
 
 | 
						|
 #endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
 | 
						|
--- a/drivers/mmc/host/sdhci-of-esdhc.c
 | 
						|
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
 | 
						|
@@ -16,8 +16,12 @@
 | 
						|
 #include <linux/err.h>
 | 
						|
 #include <linux/io.h>
 | 
						|
 #include <linux/of.h>
 | 
						|
+#include <linux/of_address.h>
 | 
						|
 #include <linux/delay.h>
 | 
						|
 #include <linux/module.h>
 | 
						|
+#include <linux/sys_soc.h>
 | 
						|
+#include <linux/clk.h>
 | 
						|
+#include <linux/ktime.h>
 | 
						|
 #include <linux/mmc/host.h>
 | 
						|
 #include "sdhci-pltfm.h"
 | 
						|
 #include "sdhci-esdhc.h"
 | 
						|
@@ -28,8 +32,12 @@
 | 
						|
 struct sdhci_esdhc {
 | 
						|
 	u8 vendor_ver;
 | 
						|
 	u8 spec_ver;
 | 
						|
+	bool quirk_incorrect_hostver;
 | 
						|
+	unsigned int peripheral_clock;
 | 
						|
 };
 | 
						|
 
 | 
						|
+static void esdhc_clock_enable(struct sdhci_host *host, bool enable);
 | 
						|
+
 | 
						|
 /**
 | 
						|
  * esdhc_read*_fixup - Fixup the value read from incompatible eSDHC register
 | 
						|
  *		       to make it compatible with SD spec.
 | 
						|
@@ -80,6 +88,17 @@ static u32 esdhc_readl_fixup(struct sdhc
 | 
						|
 		return ret;
 | 
						|
 	}
 | 
						|
 
 | 
						|
+	/*
 | 
						|
+	 * DTS properties of mmc host are used to enable each speed mode
 | 
						|
+	 * according to soc and board capability. So clean up
 | 
						|
+	 * SDR50/SDR104/DDR50 support bits here.
 | 
						|
+	 */
 | 
						|
+	if (spec_reg == SDHCI_CAPABILITIES_1) {
 | 
						|
+		ret = value & (~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
 | 
						|
+				 SDHCI_SUPPORT_DDR50));
 | 
						|
+		return ret;
 | 
						|
+	}
 | 
						|
+
 | 
						|
 	ret = value;
 | 
						|
 	return ret;
 | 
						|
 }
 | 
						|
@@ -87,6 +106,8 @@ static u32 esdhc_readl_fixup(struct sdhc
 | 
						|
 static u16 esdhc_readw_fixup(struct sdhci_host *host,
 | 
						|
 				     int spec_reg, u32 value)
 | 
						|
 {
 | 
						|
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 | 
						|
+	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
 | 
						|
 	u16 ret;
 | 
						|
 	int shift = (spec_reg & 0x2) * 8;
 | 
						|
 
 | 
						|
@@ -94,6 +115,12 @@ static u16 esdhc_readw_fixup(struct sdhc
 | 
						|
 		ret = value & 0xffff;
 | 
						|
 	else
 | 
						|
 		ret = (value >> shift) & 0xffff;
 | 
						|
+	/* Workaround for T4240-R1.0-R2.0 eSDHC which has incorrect
 | 
						|
+	 * vendor version and spec version information.
 | 
						|
+	 */
 | 
						|
+	if ((spec_reg == SDHCI_HOST_VERSION) &&
 | 
						|
+	    (esdhc->quirk_incorrect_hostver))
 | 
						|
+		ret = (VENDOR_V_23 << SDHCI_VENDOR_VER_SHIFT) | SDHCI_SPEC_200;
 | 
						|
 	return ret;
 | 
						|
 }
 | 
						|
 
 | 
						|
@@ -235,7 +262,11 @@ static u32 esdhc_be_readl(struct sdhci_h
 | 
						|
 	u32 ret;
 | 
						|
 	u32 value;
 | 
						|
 
 | 
						|
-	value = ioread32be(host->ioaddr + reg);
 | 
						|
+	if (reg == SDHCI_CAPABILITIES_1)
 | 
						|
+		value = ioread32be(host->ioaddr + ESDHC_CAPABILITIES_1);
 | 
						|
+	else
 | 
						|
+		value = ioread32be(host->ioaddr + reg);
 | 
						|
+
 | 
						|
 	ret = esdhc_readl_fixup(host, reg, value);
 | 
						|
 
 | 
						|
 	return ret;
 | 
						|
@@ -246,7 +277,11 @@ static u32 esdhc_le_readl(struct sdhci_h
 | 
						|
 	u32 ret;
 | 
						|
 	u32 value;
 | 
						|
 
 | 
						|
-	value = ioread32(host->ioaddr + reg);
 | 
						|
+	if (reg == SDHCI_CAPABILITIES_1)
 | 
						|
+		value = ioread32(host->ioaddr + ESDHC_CAPABILITIES_1);
 | 
						|
+	else
 | 
						|
+		value = ioread32(host->ioaddr + reg);
 | 
						|
+
 | 
						|
 	ret = esdhc_readl_fixup(host, reg, value);
 | 
						|
 
 | 
						|
 	return ret;
 | 
						|
@@ -404,15 +439,25 @@ static int esdhc_of_enable_dma(struct sd
 | 
						|
 static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host)
 | 
						|
 {
 | 
						|
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 | 
						|
+	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
 | 
						|
 
 | 
						|
-	return pltfm_host->clock;
 | 
						|
+	if (esdhc->peripheral_clock)
 | 
						|
+		return esdhc->peripheral_clock;
 | 
						|
+	else
 | 
						|
+		return pltfm_host->clock;
 | 
						|
 }
 | 
						|
 
 | 
						|
 static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
 | 
						|
 {
 | 
						|
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 | 
						|
+	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
 | 
						|
+	unsigned int clock;
 | 
						|
 
 | 
						|
-	return pltfm_host->clock / 256 / 16;
 | 
						|
+	if (esdhc->peripheral_clock)
 | 
						|
+		clock = esdhc->peripheral_clock;
 | 
						|
+	else
 | 
						|
+		clock = pltfm_host->clock;
 | 
						|
+	return clock / 256 / 16;
 | 
						|
 }
 | 
						|
 
 | 
						|
 static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
 | 
						|
@@ -421,12 +466,15 @@ static void esdhc_of_set_clock(struct sd
 | 
						|
 	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
 | 
						|
 	int pre_div = 1;
 | 
						|
 	int div = 1;
 | 
						|
+	ktime_t timeout;
 | 
						|
 	u32 temp;
 | 
						|
 
 | 
						|
 	host->mmc->actual_clock = 0;
 | 
						|
 
 | 
						|
-	if (clock == 0)
 | 
						|
+	if (clock == 0) {
 | 
						|
+		esdhc_clock_enable(host, false);
 | 
						|
 		return;
 | 
						|
+	}
 | 
						|
 
 | 
						|
 	/* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */
 | 
						|
 	if (esdhc->vendor_ver < VENDOR_V_23)
 | 
						|
@@ -454,9 +502,15 @@ static void esdhc_of_set_clock(struct sd
 | 
						|
 			clock -= 5000000;
 | 
						|
 	}
 | 
						|
 
 | 
						|
+	/* Workaround to reduce the clock frequency for ls1021a esdhc */
 | 
						|
+	if (of_find_compatible_node(NULL, NULL, "fsl,ls1021a-esdhc")) {
 | 
						|
+		if (clock == 50000000)
 | 
						|
+			clock = 46500000;
 | 
						|
+	}
 | 
						|
+
 | 
						|
 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
 | 
						|
-	temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
 | 
						|
-		| ESDHC_CLOCK_MASK);
 | 
						|
+	temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN |
 | 
						|
+		  ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
 | 
						|
 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 | 
						|
 
 | 
						|
 	while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
 | 
						|
@@ -476,7 +530,20 @@ static void esdhc_of_set_clock(struct sd
 | 
						|
 		| (div << ESDHC_DIVIDER_SHIFT)
 | 
						|
 		| (pre_div << ESDHC_PREDIV_SHIFT));
 | 
						|
 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 | 
						|
-	mdelay(1);
 | 
						|
+
 | 
						|
+	/* Wait max 20 ms */
 | 
						|
+	timeout = ktime_add_ms(ktime_get(), 20);
 | 
						|
+	while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) {
 | 
						|
+		if (ktime_after(ktime_get(), timeout)) {
 | 
						|
+			pr_err("%s: Internal clock never stabilised.\n",
 | 
						|
+				mmc_hostname(host->mmc));
 | 
						|
+			return;
 | 
						|
+		}
 | 
						|
+		udelay(10);
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	temp |= ESDHC_CLOCK_SDCLKEN;
 | 
						|
+	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 | 
						|
 }
 | 
						|
 
 | 
						|
 static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
 | 
						|
@@ -501,12 +568,136 @@ static void esdhc_pltfm_set_bus_width(st
 | 
						|
 	sdhci_writel(host, ctrl, ESDHC_PROCTL);
 | 
						|
 }
 | 
						|
 
 | 
						|
+static void esdhc_clock_enable(struct sdhci_host *host, bool enable)
 | 
						|
+{
 | 
						|
+	u32 val;
 | 
						|
+	ktime_t timeout;
 | 
						|
+
 | 
						|
+	val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
 | 
						|
+
 | 
						|
+	if (enable)
 | 
						|
+		val |= ESDHC_CLOCK_SDCLKEN;
 | 
						|
+	else
 | 
						|
+		val &= ~ESDHC_CLOCK_SDCLKEN;
 | 
						|
+
 | 
						|
+	sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL);
 | 
						|
+
 | 
						|
+	/* Wait max 20 ms */
 | 
						|
+	timeout = ktime_add_ms(ktime_get(), 20);
 | 
						|
+	val = ESDHC_CLOCK_STABLE;
 | 
						|
+	while (!(sdhci_readl(host, ESDHC_PRSSTAT) & val)) {
 | 
						|
+		if (ktime_after(ktime_get(), timeout)) {
 | 
						|
+			pr_err("%s: Internal clock never stabilised.\n",
 | 
						|
+				mmc_hostname(host->mmc));
 | 
						|
+			break;
 | 
						|
+		}
 | 
						|
+		udelay(10);
 | 
						|
+	}
 | 
						|
+}
 | 
						|
+
 | 
						|
 static void esdhc_reset(struct sdhci_host *host, u8 mask)
 | 
						|
 {
 | 
						|
+	u32 val;
 | 
						|
+
 | 
						|
 	sdhci_reset(host, mask);
 | 
						|
 
 | 
						|
 	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
 | 
						|
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 | 
						|
+
 | 
						|
+	if (mask & SDHCI_RESET_ALL) {
 | 
						|
+		val = sdhci_readl(host, ESDHC_TBCTL);
 | 
						|
+		val &= ~ESDHC_TB_EN;
 | 
						|
+		sdhci_writel(host, val, ESDHC_TBCTL);
 | 
						|
+	}
 | 
						|
+}
 | 
						|
+
 | 
						|
+/* The SCFG, Supplemental Configuration Unit, provides SoC specific
 | 
						|
+ * configuration and status registers for the device. There is a
 | 
						|
+ * SDHC IO VSEL control register on SCFG for some platforms. It's
 | 
						|
+ * used to support SDHC IO voltage switching.
 | 
						|
+ */
 | 
						|
+static const struct of_device_id scfg_device_ids[] = {
 | 
						|
+	{ .compatible = "fsl,t1040-scfg", },
 | 
						|
+	{ .compatible = "fsl,ls1012a-scfg", },
 | 
						|
+	{ .compatible = "fsl,ls1046a-scfg", },
 | 
						|
+	{}
 | 
						|
+};
 | 
						|
+
 | 
						|
+/* SDHC IO VSEL control register definition */
 | 
						|
+#define SCFG_SDHCIOVSELCR	0x408
 | 
						|
+#define SDHCIOVSELCR_TGLEN	0x80000000
 | 
						|
+#define SDHCIOVSELCR_VSELVAL	0x60000000
 | 
						|
+#define SDHCIOVSELCR_SDHC_VS	0x00000001
 | 
						|
+
 | 
						|
+static int esdhc_signal_voltage_switch(struct mmc_host *mmc,
 | 
						|
+				       struct mmc_ios *ios)
 | 
						|
+{
 | 
						|
+	struct sdhci_host *host = mmc_priv(mmc);
 | 
						|
+	struct device_node *scfg_node;
 | 
						|
+	void __iomem *scfg_base = NULL;
 | 
						|
+	u32 sdhciovselcr;
 | 
						|
+	u32 val;
 | 
						|
+
 | 
						|
+	/*
 | 
						|
+	 * Signal Voltage Switching is only applicable for Host Controllers
 | 
						|
+	 * v3.00 and above.
 | 
						|
+	 */
 | 
						|
+	if (host->version < SDHCI_SPEC_300)
 | 
						|
+		return 0;
 | 
						|
+
 | 
						|
+	val = sdhci_readl(host, ESDHC_PROCTL);
 | 
						|
+
 | 
						|
+	switch (ios->signal_voltage) {
 | 
						|
+	case MMC_SIGNAL_VOLTAGE_330:
 | 
						|
+		val &= ~ESDHC_VOLT_SEL;
 | 
						|
+		sdhci_writel(host, val, ESDHC_PROCTL);
 | 
						|
+		return 0;
 | 
						|
+	case MMC_SIGNAL_VOLTAGE_180:
 | 
						|
+		scfg_node = of_find_matching_node(NULL, scfg_device_ids);
 | 
						|
+		if (scfg_node)
 | 
						|
+			scfg_base = of_iomap(scfg_node, 0);
 | 
						|
+		if (scfg_base) {
 | 
						|
+			sdhciovselcr = SDHCIOVSELCR_TGLEN |
 | 
						|
+				       SDHCIOVSELCR_VSELVAL;
 | 
						|
+			iowrite32be(sdhciovselcr,
 | 
						|
+				scfg_base + SCFG_SDHCIOVSELCR);
 | 
						|
+
 | 
						|
+			val |= ESDHC_VOLT_SEL;
 | 
						|
+			sdhci_writel(host, val, ESDHC_PROCTL);
 | 
						|
+			mdelay(5);
 | 
						|
+
 | 
						|
+			sdhciovselcr = SDHCIOVSELCR_TGLEN |
 | 
						|
+				       SDHCIOVSELCR_SDHC_VS;
 | 
						|
+			iowrite32be(sdhciovselcr,
 | 
						|
+				scfg_base + SCFG_SDHCIOVSELCR);
 | 
						|
+			iounmap(scfg_base);
 | 
						|
+		} else {
 | 
						|
+			val |= ESDHC_VOLT_SEL;
 | 
						|
+			sdhci_writel(host, val, ESDHC_PROCTL);
 | 
						|
+		}
 | 
						|
+		return 0;
 | 
						|
+	default:
 | 
						|
+		return 0;
 | 
						|
+	}
 | 
						|
+}
 | 
						|
+
 | 
						|
+static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 | 
						|
+{
 | 
						|
+	struct sdhci_host *host = mmc_priv(mmc);
 | 
						|
+	u32 val;
 | 
						|
+
 | 
						|
+	/* Use tuning block for tuning procedure */
 | 
						|
+	esdhc_clock_enable(host, false);
 | 
						|
+	val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
 | 
						|
+	val |= ESDHC_FLUSH_ASYNC_FIFO;
 | 
						|
+	sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
 | 
						|
+
 | 
						|
+	val = sdhci_readl(host, ESDHC_TBCTL);
 | 
						|
+	val |= ESDHC_TB_EN;
 | 
						|
+	sdhci_writel(host, val, ESDHC_TBCTL);
 | 
						|
+	esdhc_clock_enable(host, true);
 | 
						|
+
 | 
						|
+	return sdhci_execute_tuning(mmc, opcode);
 | 
						|
 }
 | 
						|
 
 | 
						|
 #ifdef CONFIG_PM_SLEEP
 | 
						|
@@ -589,10 +780,19 @@ static const struct sdhci_pltfm_data sdh
 | 
						|
 	.ops = &sdhci_esdhc_le_ops,
 | 
						|
 };
 | 
						|
 
 | 
						|
+static struct soc_device_attribute soc_incorrect_hostver[] = {
 | 
						|
+	{ .family = "QorIQ T4240", .revision = "1.0", },
 | 
						|
+	{ .family = "QorIQ T4240", .revision = "2.0", },
 | 
						|
+	{ },
 | 
						|
+};
 | 
						|
+
 | 
						|
 static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
 | 
						|
 {
 | 
						|
 	struct sdhci_pltfm_host *pltfm_host;
 | 
						|
 	struct sdhci_esdhc *esdhc;
 | 
						|
+	struct device_node *np;
 | 
						|
+	struct clk *clk;
 | 
						|
+	u32 val;
 | 
						|
 	u16 host_ver;
 | 
						|
 
 | 
						|
 	pltfm_host = sdhci_priv(host);
 | 
						|
@@ -602,6 +802,36 @@ static void esdhc_init(struct platform_d
 | 
						|
 	esdhc->vendor_ver = (host_ver & SDHCI_VENDOR_VER_MASK) >>
 | 
						|
 			     SDHCI_VENDOR_VER_SHIFT;
 | 
						|
 	esdhc->spec_ver = host_ver & SDHCI_SPEC_VER_MASK;
 | 
						|
+	if (soc_device_match(soc_incorrect_hostver))
 | 
						|
+		esdhc->quirk_incorrect_hostver = true;
 | 
						|
+	else
 | 
						|
+		esdhc->quirk_incorrect_hostver = false;
 | 
						|
+
 | 
						|
+	np = pdev->dev.of_node;
 | 
						|
+	clk = of_clk_get(np, 0);
 | 
						|
+	if (!IS_ERR(clk)) {
 | 
						|
+		/*
 | 
						|
+		 * esdhc->peripheral_clock would be assigned with a value
 | 
						|
+		 * which is eSDHC base clock when use periperal clock.
 | 
						|
+		 * For ls1046a, the clock value got by common clk API is
 | 
						|
+		 * peripheral clock while the eSDHC base clock is 1/2
 | 
						|
+		 * peripheral clock.
 | 
						|
+		 */
 | 
						|
+		if (of_device_is_compatible(np, "fsl,ls1046a-esdhc"))
 | 
						|
+			esdhc->peripheral_clock = clk_get_rate(clk) / 2;
 | 
						|
+		else
 | 
						|
+			esdhc->peripheral_clock = clk_get_rate(clk);
 | 
						|
+
 | 
						|
+		clk_put(clk);
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if (esdhc->peripheral_clock) {
 | 
						|
+		esdhc_clock_enable(host, false);
 | 
						|
+		val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
 | 
						|
+		val |= ESDHC_PERIPHERAL_CLK_SEL;
 | 
						|
+		sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
 | 
						|
+		esdhc_clock_enable(host, true);
 | 
						|
+	}
 | 
						|
 }
 | 
						|
 
 | 
						|
 static int sdhci_esdhc_probe(struct platform_device *pdev)
 | 
						|
@@ -624,6 +854,11 @@ static int sdhci_esdhc_probe(struct plat
 | 
						|
 	if (IS_ERR(host))
 | 
						|
 		return PTR_ERR(host);
 | 
						|
 
 | 
						|
+	host->mmc_host_ops.start_signal_voltage_switch =
 | 
						|
+		esdhc_signal_voltage_switch;
 | 
						|
+	host->mmc_host_ops.execute_tuning = esdhc_execute_tuning;
 | 
						|
+	host->tuning_delay = 1;
 | 
						|
+
 | 
						|
 	esdhc_init(pdev, host);
 | 
						|
 
 | 
						|
 	sdhci_get_of_property(pdev);
 | 
						|
--- a/drivers/mmc/host/sdhci.c
 | 
						|
+++ b/drivers/mmc/host/sdhci.c
 | 
						|
@@ -1631,26 +1631,24 @@ static void sdhci_set_ios(struct mmc_hos
 | 
						|
 
 | 
						|
 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 | 
						|
 
 | 
						|
-	if ((ios->timing == MMC_TIMING_SD_HS ||
 | 
						|
-	     ios->timing == MMC_TIMING_MMC_HS)
 | 
						|
-	    && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
 | 
						|
-		ctrl |= SDHCI_CTRL_HISPD;
 | 
						|
-	else
 | 
						|
-		ctrl &= ~SDHCI_CTRL_HISPD;
 | 
						|
+	if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) {
 | 
						|
+		if ((ios->timing == MMC_TIMING_SD_HS ||
 | 
						|
+		     ios->timing == MMC_TIMING_MMC_HS ||
 | 
						|
+		     ios->timing == MMC_TIMING_MMC_HS400 ||
 | 
						|
+		     ios->timing == MMC_TIMING_MMC_HS200 ||
 | 
						|
+		     ios->timing == MMC_TIMING_MMC_DDR52 ||
 | 
						|
+		     ios->timing == MMC_TIMING_UHS_SDR50 ||
 | 
						|
+		     ios->timing == MMC_TIMING_UHS_SDR104 ||
 | 
						|
+		     ios->timing == MMC_TIMING_UHS_DDR50 ||
 | 
						|
+		     ios->timing == MMC_TIMING_UHS_SDR25))
 | 
						|
+			ctrl |= SDHCI_CTRL_HISPD;
 | 
						|
+		else
 | 
						|
+			ctrl &= ~SDHCI_CTRL_HISPD;
 | 
						|
+	}
 | 
						|
 
 | 
						|
 	if (host->version >= SDHCI_SPEC_300) {
 | 
						|
 		u16 clk, ctrl_2;
 | 
						|
 
 | 
						|
-		/* In case of UHS-I modes, set High Speed Enable */
 | 
						|
-		if ((ios->timing == MMC_TIMING_MMC_HS400) ||
 | 
						|
-		    (ios->timing == MMC_TIMING_MMC_HS200) ||
 | 
						|
-		    (ios->timing == MMC_TIMING_MMC_DDR52) ||
 | 
						|
-		    (ios->timing == MMC_TIMING_UHS_SDR50) ||
 | 
						|
-		    (ios->timing == MMC_TIMING_UHS_SDR104) ||
 | 
						|
-		    (ios->timing == MMC_TIMING_UHS_DDR50) ||
 | 
						|
-		    (ios->timing == MMC_TIMING_UHS_SDR25))
 | 
						|
-			ctrl |= SDHCI_CTRL_HISPD;
 | 
						|
-
 | 
						|
 		if (!host->preset_enabled) {
 | 
						|
 			sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 | 
						|
 			/*
 | 
						|
@@ -1963,7 +1961,7 @@ static int sdhci_prepare_hs400_tuning(st
 | 
						|
 	return 0;
 | 
						|
 }
 | 
						|
 
 | 
						|
-static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 | 
						|
+int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 | 
						|
 {
 | 
						|
 	struct sdhci_host *host = mmc_priv(mmc);
 | 
						|
 	u16 ctrl;
 | 
						|
@@ -2022,6 +2020,9 @@ static int sdhci_execute_tuning(struct m
 | 
						|
 		return err;
 | 
						|
 	}
 | 
						|
 
 | 
						|
+	if (host->tuning_delay < 0)
 | 
						|
+	host->tuning_delay = opcode == MMC_SEND_TUNING_BLOCK;
 | 
						|
+
 | 
						|
 	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 | 
						|
 	ctrl |= SDHCI_CTRL_EXEC_TUNING;
 | 
						|
 	if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND)
 | 
						|
@@ -2134,9 +2135,10 @@ static int sdhci_execute_tuning(struct m
 | 
						|
 
 | 
						|
 		ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 | 
						|
 
 | 
						|
-		/* eMMC spec does not require a delay between tuning cycles */
 | 
						|
-		if (opcode == MMC_SEND_TUNING_BLOCK)
 | 
						|
-			mdelay(1);
 | 
						|
+		/* Spec does not require a delay between tuning cycles */
 | 
						|
+		if (host->tuning_delay > 0)
 | 
						|
+		mdelay(host->tuning_delay);
 | 
						|
+
 | 
						|
 	} while (ctrl & SDHCI_CTRL_EXEC_TUNING);
 | 
						|
 
 | 
						|
 	/*
 | 
						|
@@ -2172,6 +2174,7 @@ out_unlock:
 | 
						|
 	spin_unlock_irqrestore(&host->lock, flags);
 | 
						|
 	return err;
 | 
						|
 }
 | 
						|
+EXPORT_SYMBOL_GPL(sdhci_execute_tuning);
 | 
						|
 
 | 
						|
 static int sdhci_select_drive_strength(struct mmc_card *card,
 | 
						|
 				       unsigned int max_dtr, int host_drv,
 | 
						|
@@ -3004,6 +3007,8 @@ struct sdhci_host *sdhci_alloc_host(stru
 | 
						|
 
 | 
						|
 	host->flags = SDHCI_SIGNALING_330;
 | 
						|
 
 | 
						|
+	host->tuning_delay = -1;
 | 
						|
+
 | 
						|
 	return host;
 | 
						|
 }
 | 
						|
 
 | 
						|
--- a/drivers/mmc/host/sdhci.h
 | 
						|
+++ b/drivers/mmc/host/sdhci.h
 | 
						|
@@ -524,6 +524,8 @@ struct sdhci_host {
 | 
						|
 #define SDHCI_TUNING_MODE_1	0
 | 
						|
 #define SDHCI_TUNING_MODE_2	1
 | 
						|
 #define SDHCI_TUNING_MODE_3	2
 | 
						|
+	/* Delay (ms) between tuning commands */
 | 
						|
+	int			tuning_delay;
 | 
						|
 
 | 
						|
 	unsigned long private[0] ____cacheline_aligned;
 | 
						|
 };
 | 
						|
@@ -689,6 +691,7 @@ void sdhci_set_power_noreg(struct sdhci_
 | 
						|
 void sdhci_set_bus_width(struct sdhci_host *host, int width);
 | 
						|
 void sdhci_reset(struct sdhci_host *host, u8 mask);
 | 
						|
 void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
 | 
						|
+int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 | 
						|
 
 | 
						|
 #ifdef CONFIG_PM
 | 
						|
 extern int sdhci_suspend_host(struct sdhci_host *host);
 |