linux-mmc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support
@ 2013-09-13 11:11 Dong Aisheng
  2013-09-13 11:11 ` [PATCH v2 1/9] mmc: sdhci: add hooks for platform specific tuning Dong Aisheng
                   ` (9 more replies)
  0 siblings, 10 replies; 14+ messages in thread
From: Dong Aisheng @ 2013-09-13 11:11 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang,
	ulf.hansson, neko, b29396

This patch series add SD3.0 support for i.MX6Q/DL.
Since freescale i.MX6Q/DL uSDHC clock tuning progress is a little different from
the standard tuning process defined in host controller spec v3.0.
So we add a hook to allow execute platform specific tuning instead of
standard host controller tuning.

The main difference are:
1) not only generate Buffer Read Ready interrupt when tuning is performing.
It generates all other DATA interrupts like the normal data command.
2) SDHCI_CTRL_EXEC_TUNING is not automatically cleared by HW,
instead it's controlled by SW.
3) SDHCI_CTRL_TUNED_CLK is not automatically set by HW,
it's controlled by SW.
4) the clock delay for every tuning is set by SW.

Tested on i.MX6Q Sabreauto board.

The series is based on latest Linus tree.

ChangeLog since v1:
* some minor changes made by addressing Shawn's comments
* move esdhc_set_clock shared by imx and powerpc to each platform driver
since it's not much common anymore based on Shawn's suggestion.
* dts pinctrl group name changed according to Sascha's suggestion and
rebased on latest tree.

Dong Aisheng (9):
  mmc: sdhci: add hooks for platform specific tuning
  mmc: sdhci: allow platform access of sdhci_send_command
  mmc: sdhci-esdhci: move common esdhc_set_clock to platform driver
  sdhci: sdhci-esdhc-imx: support real clock on and off for imx6q
  sdhci: sdhci-esdhci-imx: add sd3.0 clock tuning support
  sdhci: sdhci-esdhc-imx: change pinctrl state according to uhs mode
  mmc: sdhci-esdhc-imx: correct pre_div for imx6q
  mmc: sdhci-esdhc-imx: set actual_clock in clock setting
  ARM: dts: imx6qdl: add uhs pinctrl state for usdhc3

 arch/arm/boot/dts/imx6qdl-sabreauto.dtsi    |    5 +-
 arch/arm/boot/dts/imx6qdl.dtsi              |   30 +++
 drivers/mmc/host/sdhci-esdhc-imx.c          |  344 ++++++++++++++++++++++++++-
 drivers/mmc/host/sdhci-esdhc.h              |   37 ---
 drivers/mmc/host/sdhci-of-esdhc.c           |   35 +++-
 drivers/mmc/host/sdhci.c                    |   12 +-
 drivers/mmc/host/sdhci.h                    |    3 +
 include/linux/platform_data/mmc-esdhc-imx.h |    4 +
 8 files changed, 425 insertions(+), 45 deletions(-)



^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 1/9] mmc: sdhci: add hooks for platform specific tuning
  2013-09-13 11:11 [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Dong Aisheng
@ 2013-09-13 11:11 ` Dong Aisheng
  2013-09-13 11:11 ` [PATCH v2 2/9] mmc: sdhci: allow platform access of sdhci_send_command Dong Aisheng
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Dong Aisheng @ 2013-09-13 11:11 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang,
	ulf.hansson, neko, b29396

The tuning of some platforms may not follow the standard host control
spec v3.0, e.g. Freescale uSDHC on i.MX6Q/DL.
Add a hook here to allow execute platform specific tuning instead of
standard host controller tuning.

The hook only replaces the tuning process, so it's placed after tuning
checking and before the real tuning process.

Some notes for the tuning hook:
1) it needs handle lock itself if it wants to access host controller
according platform specific implementation.
2) do not need to handle runtime pm since it executes with runtime pm
get already.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
ChangeLog since v1:
* add more description of hook in commit message
---
 drivers/mmc/host/sdhci.c |    8 ++++++++
 drivers/mmc/host/sdhci.h |    1 +
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 7a7fb4f..072d78c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1875,6 +1875,14 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 		return 0;
 	}
 
+	if (host->ops->platform_execute_tuning) {
+		spin_unlock(&host->lock);
+		enable_irq(host->irq);
+		err = host->ops->platform_execute_tuning(host, opcode);
+		sdhci_runtime_pm_put(host);
+		return err;
+	}
+
 	sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
 	/*
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index b037f18..976c14b 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -288,6 +288,7 @@ struct sdhci_ops {
 	unsigned int    (*get_ro)(struct sdhci_host *host);
 	void	(*platform_reset_enter)(struct sdhci_host *host, u8 mask);
 	void	(*platform_reset_exit)(struct sdhci_host *host, u8 mask);
+	int	(*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
 	int	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
 	void	(*hw_reset)(struct sdhci_host *host);
 	void	(*platform_suspend)(struct sdhci_host *host);
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 2/9] mmc: sdhci: allow platform access of sdhci_send_command
  2013-09-13 11:11 [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Dong Aisheng
  2013-09-13 11:11 ` [PATCH v2 1/9] mmc: sdhci: add hooks for platform specific tuning Dong Aisheng
@ 2013-09-13 11:11 ` Dong Aisheng
  2013-09-13 11:11 ` [PATCH v2 3/9] mmc: sdhci-esdhci: move common esdhc_set_clock to platform driver Dong Aisheng
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Dong Aisheng @ 2013-09-13 11:11 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang,
	ulf.hansson, neko, b29396

It helps for platform code to use it send tuning commands.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 drivers/mmc/host/sdhci.c |    4 ++--
 drivers/mmc/host/sdhci.h |    2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 072d78c..66bce7a 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -49,7 +49,6 @@ static unsigned int debug_quirks2;
 
 static void sdhci_finish_data(struct sdhci_host *);
 
-static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
 static void sdhci_finish_command(struct sdhci_host *);
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 static void sdhci_tuning_timer(unsigned long data);
@@ -981,7 +980,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
 		tasklet_schedule(&host->finish_tasklet);
 }
 
-static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
+void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 {
 	int flags;
 	u32 mask;
@@ -1053,6 +1052,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 
 	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
 }
+EXPORT_SYMBOL_GPL(sdhci_send_command);
 
 static void sdhci_finish_command(struct sdhci_host *host)
 {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 976c14b..0a3ed01 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -394,6 +394,8 @@ static inline void *sdhci_priv(struct sdhci_host *host)
 extern void sdhci_card_detect(struct sdhci_host *host);
 extern int sdhci_add_host(struct sdhci_host *host);
 extern void sdhci_remove_host(struct sdhci_host *host, int dead);
+extern void sdhci_send_command(struct sdhci_host *host,
+				struct mmc_command *cmd);
 
 #ifdef CONFIG_PM
 extern int sdhci_suspend_host(struct sdhci_host *host);
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 3/9] mmc: sdhci-esdhci: move common esdhc_set_clock to platform driver
  2013-09-13 11:11 [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Dong Aisheng
  2013-09-13 11:11 ` [PATCH v2 1/9] mmc: sdhci: add hooks for platform specific tuning Dong Aisheng
  2013-09-13 11:11 ` [PATCH v2 2/9] mmc: sdhci: allow platform access of sdhci_send_command Dong Aisheng
@ 2013-09-13 11:11 ` Dong Aisheng
  2013-09-13 11:11 ` [PATCH v2 4/9] sdhci: sdhci-esdhc-imx: support real clock on and off for imx6q Dong Aisheng
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Dong Aisheng @ 2013-09-13 11:11 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang,
	ulf.hansson, neko, b29396

We need a lot of imx6 specific things into common esdhc_set_clock
for support SD3.0 and eMMC DDR mode which is not needed for power pc
platforms, so esdhc_set_clock seems not so common anymore.

Instead of keeping add platform specfics things into this common API,
we choose to move that code into platform driver itself to handle.
This can also exclude the dependency between imx and power pc on this
headfile and is easy for maintain in the future.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 drivers/mmc/host/sdhci-esdhc-imx.c |   35 ++++++++++++++++++++++++++++++++-
 drivers/mmc/host/sdhci-esdhc.h     |   37 ------------------------------------
 drivers/mmc/host/sdhci-of-esdhc.c  |   35 ++++++++++++++++++++++++++++++++-
 3 files changed, 66 insertions(+), 41 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index abc8cf0..67eaec9 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -409,8 +409,39 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 					 unsigned int clock)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-
-	esdhc_set_clock(host, clock, clk_get_rate(pltfm_host->clk));
+	unsigned int host_clock = clk_get_rate(pltfm_host->clk);
+	int pre_div = 2;
+	int div = 1;
+	u32 temp;
+
+	if (clock == 0)
+		goto out;
+
+	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+	temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
+		| ESDHC_CLOCK_MASK);
+	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+
+	while (host_clock / pre_div / 16 > clock && pre_div < 256)
+		pre_div *= 2;
+
+	while (host_clock / pre_div / div > clock && div < 16)
+		div++;
+
+	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
+		clock, host_clock / pre_div / div);
+
+	pre_div >>= 1;
+	div--;
+
+	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+	temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
+		| (div << ESDHC_DIVIDER_SHIFT)
+		| (pre_div << ESDHC_PREDIV_SHIFT));
+	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+	mdelay(1);
+out:
+	host->clock = clock;
 }
 
 static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index a2a0642..a7d9f95 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -49,41 +49,4 @@
 
 #define ESDHC_HOST_CONTROL_RES	0x05
 
-static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock,
-				   unsigned int host_clock)
-{
-	int pre_div = 2;
-	int div = 1;
-	u32 temp;
-
-	if (clock == 0)
-		goto out;
-
-	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
-	temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
-		| ESDHC_CLOCK_MASK);
-	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
-
-	while (host_clock / pre_div / 16 > clock && pre_div < 256)
-		pre_div *= 2;
-
-	while (host_clock / pre_div / div > clock && div < 16)
-		div++;
-
-	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
-		clock, host_clock / pre_div / div);
-
-	pre_div >>= 1;
-	div--;
-
-	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
-	temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
-		| (div << ESDHC_DIVIDER_SHIFT)
-		| (pre_div << ESDHC_PREDIV_SHIFT));
-	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
-	mdelay(1);
-out:
-	host->clock = clock;
-}
-
 #endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index e328252..b1605a1 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -199,6 +199,14 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
 
 static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
 {
+
+	int pre_div = 2;
+	int div = 1;
+	u32 temp;
+
+	if (clock == 0)
+		goto out;
+
 	/* Workaround to reduce the clock frequency for p1010 esdhc */
 	if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
 		if (clock > 20000000)
@@ -207,8 +215,31 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
 			clock -= 5000000;
 	}
 
-	/* Set the clock */
-	esdhc_set_clock(host, clock, host->max_clk);
+	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+	temp &= ~(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)
+		pre_div *= 2;
+
+	while (host->max_clk / pre_div / div > clock && div < 16)
+		div++;
+
+	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
+		clock, host_clock / pre_div / div);
+
+	pre_div >>= 1;
+	div--;
+
+	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+	temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
+		| (div << ESDHC_DIVIDER_SHIFT)
+		| (pre_div << ESDHC_PREDIV_SHIFT));
+	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+	mdelay(1);
+out:
+	host->clock = clock;
 }
 
 #ifdef CONFIG_PM
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 4/9] sdhci: sdhci-esdhc-imx: support real clock on and off for imx6q
  2013-09-13 11:11 [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Dong Aisheng
                   ` (2 preceding siblings ...)
  2013-09-13 11:11 ` [PATCH v2 3/9] mmc: sdhci-esdhci: move common esdhc_set_clock to platform driver Dong Aisheng
@ 2013-09-13 11:11 ` Dong Aisheng
  2013-09-13 11:11 ` [PATCH v2 5/9] sdhci: sdhci-esdhci-imx: add sd3.0 clock tuning support Dong Aisheng
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Dong Aisheng @ 2013-09-13 11:11 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang,
	ulf.hansson, neko, b29396

The signal voltage switch flow requires to shutdown and output
clock in a specific sequence according to standard host controller
v3.0 spec. In that timing, the card must really receive clock or not.

However, for i.MX6Q, the uSDHC will not output clock even the clock
is enabled until there is command or data in transfer on the bus,
which will then cause singal voltage switch always to fail.

For i.MX6Q, we clear ESDHC_VENDOR_SPEC_FRC_SDCLK_ON bit to let
controller to gate off clock automatically and set that bit
to force clock output if clock is on.

This is required by SD3.0 support.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 drivers/mmc/host/sdhci-esdhc-imx.c |   19 +++++++++++++++++--
 1 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 67eaec9..37fafd7 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -34,6 +34,7 @@
 /* VENDOR SPEC register */
 #define ESDHC_VENDOR_SPEC		0xc0
 #define  ESDHC_VENDOR_SPEC_SDIO_QUIRK	(1 << 1)
+#define  ESDHC_VENDOR_SPEC_FRC_SDCLK_ON	(1 << 8)
 #define ESDHC_WTMK_LVL			0x44
 #define ESDHC_MIX_CTRL			0x48
 #define  ESDHC_MIX_CTRL_AC23EN		(1 << 7)
@@ -409,13 +410,20 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 					 unsigned int clock)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = pltfm_host->priv;
 	unsigned int host_clock = clk_get_rate(pltfm_host->clk);
 	int pre_div = 2;
 	int div = 1;
-	u32 temp;
+	u32 temp, val;
 
-	if (clock == 0)
+	if (clock == 0) {
+		if (is_imx6q_usdhc(imx_data)) {
+			val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
+			writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
+					host->ioaddr + ESDHC_VENDOR_SPEC);
+		}
 		goto out;
+	}
 
 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
 	temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
@@ -439,6 +447,13 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 		| (div << ESDHC_DIVIDER_SHIFT)
 		| (pre_div << ESDHC_PREDIV_SHIFT));
 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+
+	if (is_imx6q_usdhc(imx_data)) {
+		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
+		writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
+		host->ioaddr + ESDHC_VENDOR_SPEC);
+	}
+
 	mdelay(1);
 out:
 	host->clock = clock;
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 5/9] sdhci: sdhci-esdhci-imx: add sd3.0 clock tuning support
  2013-09-13 11:11 [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Dong Aisheng
                   ` (3 preceding siblings ...)
  2013-09-13 11:11 ` [PATCH v2 4/9] sdhci: sdhci-esdhc-imx: support real clock on and off for imx6q Dong Aisheng
@ 2013-09-13 11:11 ` Dong Aisheng
  2013-09-13 11:11 ` [PATCH v2 6/9] sdhci: sdhci-esdhc-imx: change pinctrl state according to uhs mode Dong Aisheng
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Dong Aisheng @ 2013-09-13 11:11 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang,
	ulf.hansson, neko, b29396

Freescale i.MX6Q/DL uSDHC clock tuning progress is a little different from
the standard tuning process defined in host controller spec v3.0.
Thus we use platform_execute_tuning instead of standard sdhci tuning.

The main difference are:
1) not only generate Buffer Read Ready interrupt when tuning is performing.
It generates all other DATA interrupts like the normal data command.
2) SDHCI_CTRL_EXEC_TUNING is not automatically cleared by HW,
instead it's controlled by SW.
3) SDHCI_CTRL_TUNED_CLK is not automatically set by HW,
it's controlled by SW.
4) the clock delay for every tuning is set by SW.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
ChangeLog since v1:
* some minor changes addressed Shawn's comments
* add a bit delay for the card to be ready for the next tuning.
---
 drivers/mmc/host/sdhci-esdhc-imx.c |  196 +++++++++++++++++++++++++++++++++++-
 1 files changed, 195 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 37fafd7..f906c20 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -34,13 +34,25 @@
 /* VENDOR SPEC register */
 #define ESDHC_VENDOR_SPEC		0xc0
 #define  ESDHC_VENDOR_SPEC_SDIO_QUIRK	(1 << 1)
+#define  ESDHC_VENDOR_SPEC_VSELECT	(1 << 1)
 #define  ESDHC_VENDOR_SPEC_FRC_SDCLK_ON	(1 << 8)
 #define ESDHC_WTMK_LVL			0x44
 #define ESDHC_MIX_CTRL			0x48
 #define  ESDHC_MIX_CTRL_AC23EN		(1 << 7)
+#define  ESDHC_MIX_CTRL_EXE_TUNE	(1 << 22)
+#define  ESDHC_MIX_CTRL_SMPCLK_SEL	(1 << 23)
+#define  ESDHC_MIX_CTRL_FBCLK_SEL	(1 << 25)
 /* Bits 3 and 6 are not SDHCI standard definitions */
 #define  ESDHC_MIX_CTRL_SDHCI_MASK	0xb7
 
+/* tune control register */
+#define ESDHC_TUNE_CTRL_STATUS		0x68
+#define  ESDHC_TUNE_CTRL_STEP		1
+#define  ESDHC_TUNE_CTRL_MIN		0
+#define  ESDHC_TUNE_CTRL_MAX		((1 << 7) - 1)
+
+#define ESDHC_TUNING_BLOCK_PATTERN_LEN	64
+
 /*
  * Our interpretation of the SDHCI_HOST_CONTROL register
  */
@@ -91,7 +103,7 @@ struct pltfm_imx_data {
 		MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
 		WAIT_FOR_INT,        /* sent CMD12, waiting for response INT */
 	} multiblock_status;
-
+	u32 uhs_mode;
 };
 
 static struct platform_device_id imx_esdhc_devtype[] = {
@@ -165,6 +177,16 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
 	u32 val = readl(host->ioaddr + reg);
 
+	if (unlikely(reg == SDHCI_PRESENT_STATE)) {
+		u32 fsl_prss = val;
+		/* save the least 20 bits */
+		val = fsl_prss & 0x000FFFFF;
+		/* move dat[0-3] bits */
+		val |= (fsl_prss & 0x0F000000) >> 4;
+		/* move cmd line bit */
+		val |= (fsl_prss & 0x00800000) << 1;
+	}
+
 	if (unlikely(reg == SDHCI_CAPABILITIES)) {
 		/* In FSL esdhc IC module, only bit20 is used to indicate the
 		 * ADMA2 capability of esdhc, but this bit is messed up on
@@ -179,6 +201,17 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
 		}
 	}
 
+	if (unlikely(reg == SDHCI_CAPABILITIES_1) && is_imx6q_usdhc(imx_data))
+		val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
+				| SDHCI_SUPPORT_SDR50;
+
+	if (unlikely(reg == SDHCI_MAX_CURRENT) && is_imx6q_usdhc(imx_data)) {
+		val = 0;
+		val |= 0xFF << SDHCI_MAX_CURRENT_330_SHIFT;
+		val |= 0xFF << SDHCI_MAX_CURRENT_300_SHIFT;
+		val |= 0xFF << SDHCI_MAX_CURRENT_180_SHIFT;
+	}
+
 	if (unlikely(reg == SDHCI_INT_STATUS)) {
 		if (val & ESDHC_INT_VENDOR_SPEC_DMA_ERR) {
 			val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR;
@@ -257,6 +290,8 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
+	u16 ret = 0;
+	u32 val;
 
 	if (unlikely(reg == SDHCI_HOST_VERSION)) {
 		reg ^= 2;
@@ -269,6 +304,25 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
 		}
 	}
 
+	if (unlikely(reg == SDHCI_HOST_CONTROL2)) {
+		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
+		if (val & ESDHC_VENDOR_SPEC_VSELECT)
+			ret |= SDHCI_CTRL_VDD_180;
+
+		if (is_imx6q_usdhc(imx_data)) {
+			val = readl(host->ioaddr + ESDHC_MIX_CTRL);
+			if (val & ESDHC_MIX_CTRL_EXE_TUNE)
+				ret |= SDHCI_CTRL_EXEC_TUNING;
+			if (val & ESDHC_MIX_CTRL_SMPCLK_SEL)
+				ret |= SDHCI_CTRL_TUNED_CLK;
+		}
+
+		ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK);
+		ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+
+		return ret;
+	}
+
 	return readw(host->ioaddr + reg);
 }
 
@@ -276,8 +330,32 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
+	u32 new_val = 0;
 
 	switch (reg) {
+	case SDHCI_CLOCK_CONTROL:
+		new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
+		if (val & SDHCI_CLOCK_CARD_EN)
+			new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
+		else
+			new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
+			writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
+		return;
+	case SDHCI_HOST_CONTROL2:
+		new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
+		if (val & SDHCI_CTRL_VDD_180)
+			new_val |= ESDHC_VENDOR_SPEC_VSELECT;
+		else
+			new_val &= ~ESDHC_VENDOR_SPEC_VSELECT;
+		writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
+		imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK;
+		new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
+		if (val & SDHCI_CTRL_TUNED_CLK)
+			new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL;
+		else
+			new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
+		writel(new_val , host->ioaddr + ESDHC_MIX_CTRL);
+		return;
 	case SDHCI_TRANSFER_MODE:
 		if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
 				&& (host->cmd->opcode == SD_IO_RW_EXTENDED)
@@ -500,6 +578,121 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
 	return 0;
 }
 
+static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
+{
+	u32 reg;
+
+	/* FIXME: delay a bit for card to be ready for next tuning due to errors */
+	mdelay(1);
+
+	reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
+	reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
+			ESDHC_MIX_CTRL_FBCLK_SEL;
+	writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
+	writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
+	dev_dbg(mmc_dev(host->mmc),
+		"tunning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n",
+			val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS));
+}
+
+static void esdhc_request_done(struct mmc_request *mrq)
+{
+	complete(&mrq->completion);
+}
+
+static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode)
+{
+	struct mmc_command cmd = {0};
+	struct mmc_request mrq = {0};
+	struct mmc_data data = {0};
+	struct scatterlist sg;
+	char tuning_pattern[ESDHC_TUNING_BLOCK_PATTERN_LEN];
+
+	cmd.opcode = opcode;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	data.blksz = ESDHC_TUNING_BLOCK_PATTERN_LEN;
+	data.blocks = 1;
+	data.flags = MMC_DATA_READ;
+	data.sg = &sg;
+	data.sg_len = 1;
+
+	sg_init_one(&sg, tuning_pattern, sizeof(tuning_pattern));
+
+	mrq.cmd = &cmd;
+	mrq.cmd->mrq = &mrq;
+	mrq.data = &data;
+	mrq.data->mrq = &mrq;
+	mrq.cmd->data = mrq.data;
+
+	mrq.done = esdhc_request_done;
+	init_completion(&(mrq.completion));
+
+	disable_irq(host->irq);
+	spin_lock(&host->lock);
+	host->mrq = &mrq;
+
+	sdhci_send_command(host, mrq.cmd);
+
+	spin_unlock(&host->lock);
+	enable_irq(host->irq);
+
+	wait_for_completion(&mrq.completion);
+
+	if (cmd.error)
+		return cmd.error;
+	if (data.error)
+		return data.error;
+
+	return 0;
+}
+
+static void esdhc_post_tuning(struct sdhci_host *host)
+{
+	u32 reg;
+
+	reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
+	reg &= ~ESDHC_MIX_CTRL_EXE_TUNE;
+	writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
+}
+
+static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
+{
+	int min, max, avg, ret;
+
+	/* find the mininum delay first which can pass tuning */
+	min = ESDHC_TUNE_CTRL_MIN;
+	while (min < ESDHC_TUNE_CTRL_MAX) {
+		esdhc_prepare_tuning(host, min);
+		if (!esdhc_send_tuning_cmd(host, opcode))
+			break;
+		min += ESDHC_TUNE_CTRL_STEP;
+	}
+
+	/* find the maxinum delay which can not pass tuning */
+	max = min + ESDHC_TUNE_CTRL_STEP;
+	while (max < ESDHC_TUNE_CTRL_MAX) {
+		esdhc_prepare_tuning(host, max);
+		if (esdhc_send_tuning_cmd(host, opcode)) {
+			max -= ESDHC_TUNE_CTRL_STEP;
+			break;
+		}
+		max += ESDHC_TUNE_CTRL_STEP;
+	}
+
+	/* use average delay to get the best timing */
+	avg = (min + max) / 2;
+	esdhc_prepare_tuning(host, avg);
+	ret = esdhc_send_tuning_cmd(host, opcode);
+	esdhc_post_tuning(host);
+
+	dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
+		ret ? "failed" : "passed", avg, ret);
+
+	return ret;
+}
+
 static const struct sdhci_ops sdhci_esdhc_ops = {
 	.read_l = esdhc_readl_le,
 	.read_w = esdhc_readw_le,
@@ -511,6 +704,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
 	.get_min_clock = esdhc_pltfm_get_min_clock,
 	.get_ro = esdhc_pltfm_get_ro,
 	.platform_bus_width = esdhc_pltfm_bus_width,
+	.platform_execute_tuning = esdhc_executing_tuning,
 };
 
 static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 6/9] sdhci: sdhci-esdhc-imx: change pinctrl state according to uhs mode
  2013-09-13 11:11 [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Dong Aisheng
                   ` (4 preceding siblings ...)
  2013-09-13 11:11 ` [PATCH v2 5/9] sdhci: sdhci-esdhci-imx: add sd3.0 clock tuning support Dong Aisheng
@ 2013-09-13 11:11 ` Dong Aisheng
  2013-09-13 11:11 ` [PATCH v2 7/9] mmc: sdhci-esdhc-imx: correct pre_div for imx6q Dong Aisheng
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Dong Aisheng @ 2013-09-13 11:11 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang,
	ulf.hansson, neko, b29396

Without proper pinctrl state, the card may not be able to work
on high speed stablely. e.g. SDR104.

This patch add pinctrl state switch code according to different
uhs mode include 100mhz sate, 200mhz sate and normal state
(50Mhz and below).

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
ChangeLog since v1:
* addressed Shawn's comments
---
 drivers/mmc/host/sdhci-esdhc-imx.c          |   96 ++++++++++++++++++++++++++-
 include/linux/platform_data/mmc-esdhc-imx.h |    4 +
 2 files changed, 99 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index f906c20..ed00d6d 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -53,6 +53,10 @@
 
 #define ESDHC_TUNING_BLOCK_PATTERN_LEN	64
 
+/* pinctrl state */
+#define ESDHC_PINCTRL_STATE_100MHZ	"state_100mhz"
+#define ESDHC_PINCTRL_STATE_200MHZ	"state_200mhz"
+
 /*
  * Our interpretation of the SDHCI_HOST_CONTROL register
  */
@@ -94,6 +98,9 @@ struct pltfm_imx_data {
 	u32 scratchpad;
 	enum imx_esdhc_type devtype;
 	struct pinctrl *pinctrl;
+	struct pinctrl_state *pins_default;
+	struct pinctrl_state *pins_100mhz;
+	struct pinctrl_state *pins_200mhz;
 	struct esdhc_platform_data boarddata;
 	struct clk *clk_ipg;
 	struct clk *clk_ahb;
@@ -693,6 +700,62 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
 	return ret;
 }
 
+static int esdhc_change_pinstate(struct sdhci_host *host,
+						unsigned int uhs)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = pltfm_host->priv;
+	struct pinctrl_state *pinctrl;
+
+	dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs);
+
+	if (IS_ERR(imx_data->pinctrl) ||
+		IS_ERR(imx_data->pins_default) ||
+		IS_ERR(imx_data->pins_100mhz) ||
+		IS_ERR(imx_data->pins_200mhz))
+		return -EINVAL;
+
+	switch (uhs) {
+	case MMC_TIMING_UHS_SDR50:
+		pinctrl = imx_data->pins_100mhz;
+		break;
+	case MMC_TIMING_UHS_SDR104:
+		pinctrl = imx_data->pins_200mhz;
+		break;
+	default:
+		/* back to default state for other legacy timing */
+		pinctrl = imx_data->pins_default;
+	}
+
+	return pinctrl_select_state(imx_data->pinctrl, pinctrl);
+}
+
+static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = pltfm_host->priv;
+
+	switch (uhs) {
+	case MMC_TIMING_UHS_SDR12:
+		imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR12;
+		break;
+	case MMC_TIMING_UHS_SDR25:
+		imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR25;
+		break;
+	case MMC_TIMING_UHS_SDR50:
+		imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR50;
+		break;
+	case MMC_TIMING_UHS_SDR104:
+		imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR104;
+		break;
+	case MMC_TIMING_UHS_DDR50:
+		imx_data->uhs_mode = SDHCI_CTRL_UHS_DDR50;
+		break;
+	}
+
+	return esdhc_change_pinstate(host, uhs);
+}
+
 static const struct sdhci_ops sdhci_esdhc_ops = {
 	.read_l = esdhc_readl_le,
 	.read_w = esdhc_readw_le,
@@ -704,6 +767,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
 	.get_min_clock = esdhc_pltfm_get_min_clock,
 	.get_ro = esdhc_pltfm_get_ro,
 	.platform_bus_width = esdhc_pltfm_bus_width,
+	.set_uhs_signaling = esdhc_set_uhs_signaling,
 	.platform_execute_tuning = esdhc_executing_tuning,
 };
 
@@ -746,6 +810,11 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
 
 	of_property_read_u32(np, "max-frequency", &boarddata->f_max);
 
+	if (of_find_property(np, "no-1-8-v", NULL))
+		boarddata->support_vsel = false;
+	else
+		boarddata->support_vsel = true;
+
 	return 0;
 }
 #else
@@ -808,12 +877,20 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 	clk_prepare_enable(imx_data->clk_ipg);
 	clk_prepare_enable(imx_data->clk_ahb);
 
-	imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	imx_data->pinctrl = devm_pinctrl_get(&pdev->dev);
 	if (IS_ERR(imx_data->pinctrl)) {
 		err = PTR_ERR(imx_data->pinctrl);
 		goto disable_clk;
 	}
 
+	imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl,
+						PINCTRL_STATE_DEFAULT);
+	if (IS_ERR(imx_data->pins_default)) {
+		err = PTR_ERR(imx_data->pins_default);
+		dev_err(mmc_dev(host->mmc), "could not get default state\n");
+		goto disable_clk;
+	}
+
 	host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
 
 	if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data))
@@ -890,6 +967,23 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 		break;
 	}
 
+	/* sdr50 and sdr104 needs work on 1.8v signal voltage */
+	if ((boarddata->support_vsel) && is_imx6q_usdhc(imx_data)) {
+		imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
+						ESDHC_PINCTRL_STATE_100MHZ);
+		imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,
+						ESDHC_PINCTRL_STATE_200MHZ);
+		if (IS_ERR(imx_data->pins_100mhz) ||
+				IS_ERR(imx_data->pins_200mhz)) {
+			dev_warn(mmc_dev(host->mmc),
+				"could not get ultra high speed state, work on normal mode\n");
+			/* fall back to not support uhs by specify no 1.8v quirk */
+			host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
+		}
+	} else {
+		host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
+	}
+
 	err = sdhci_add_host(host);
 	if (err)
 		goto disable_clk;
diff --git a/include/linux/platform_data/mmc-esdhc-imx.h b/include/linux/platform_data/mmc-esdhc-imx.h
index d44912d..a0f5a8f 100644
--- a/include/linux/platform_data/mmc-esdhc-imx.h
+++ b/include/linux/platform_data/mmc-esdhc-imx.h
@@ -10,6 +10,8 @@
 #ifndef __ASM_ARCH_IMX_ESDHC_H
 #define __ASM_ARCH_IMX_ESDHC_H
 
+#include <linux/types.h>
+
 enum wp_types {
 	ESDHC_WP_NONE,		/* no WP, neither controller nor gpio */
 	ESDHC_WP_CONTROLLER,	/* mmc controller internal WP */
@@ -32,6 +34,7 @@ enum cd_types {
  * @cd_gpio:	gpio for card_detect interrupt
  * @wp_type:	type of write_protect method (see wp_types enum above)
  * @cd_type:	type of card_detect method (see cd_types enum above)
+ * @support_vsel:  indicate it supports 1.8v switching
  */
 
 struct esdhc_platform_data {
@@ -41,5 +44,6 @@ struct esdhc_platform_data {
 	enum cd_types cd_type;
 	int max_bus_width;
 	unsigned int f_max;
+	bool support_vsel;
 };
 #endif /* __ASM_ARCH_IMX_ESDHC_H */
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 7/9] mmc: sdhci-esdhc-imx: correct pre_div for imx6q
  2013-09-13 11:11 [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Dong Aisheng
                   ` (5 preceding siblings ...)
  2013-09-13 11:11 ` [PATCH v2 6/9] sdhci: sdhci-esdhc-imx: change pinctrl state according to uhs mode Dong Aisheng
@ 2013-09-13 11:11 ` Dong Aisheng
  2013-09-13 11:11 ` [PATCH v2 8/9] mmc: sdhci-esdhc-imx: set actual_clock in clock setting Dong Aisheng
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Dong Aisheng @ 2013-09-13 11:11 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang,
	ulf.hansson, neko, b29396

According to spec, the pre_div for imx6q should be 1, or the biggest clock
rate we can get is a half of host clock rate.
This may cause we can not get the proper clock rate as we want.
e.g. if the desired clock is 200Mhz, however, the host clock is 200Mhz too,
then it causes the actual clock we get is 100Mhz due to pre_div is 2.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 drivers/mmc/host/sdhci-esdhc-imx.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index ed00d6d..fe48ec3 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -510,6 +510,9 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 		goto out;
 	}
 
+	if (is_imx6q_usdhc(imx_data))
+		pre_div = 1;
+
 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
 	temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
 		| ESDHC_CLOCK_MASK);
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 8/9] mmc: sdhci-esdhc-imx: set actual_clock in clock setting
  2013-09-13 11:11 [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Dong Aisheng
                   ` (6 preceding siblings ...)
  2013-09-13 11:11 ` [PATCH v2 7/9] mmc: sdhci-esdhc-imx: correct pre_div for imx6q Dong Aisheng
@ 2013-09-13 11:11 ` Dong Aisheng
  2013-09-13 11:11 ` [PATCH v2 9/9] ARM: dts: imx6qdl: add uhs pinctrl state for usdhc3 Dong Aisheng
  2013-09-26  2:01 ` [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Chris Ball
  9 siblings, 0 replies; 14+ messages in thread
From: Dong Aisheng @ 2013-09-13 11:11 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang,
	ulf.hansson, neko, b29396

This enables access the actual_clock via sys.
root@imx6qsabreauto:~# cat /sys/kernel/debug/mmc0/ios
clock:          198000000 Hz
actual clock:   198000000 Hz
vdd:            17 (2.9 ~ 3.0 V)
bus mode:       2 (push-pull)
chip select:    0 (don't care)
power mode:     2 (on)
bus width:      2 (4 bits)
timing spec:    6 (sd uhs SDR104)
signal voltage: 0 (1.80 V)

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 drivers/mmc/host/sdhci-esdhc-imx.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index fe48ec3..b9899e9 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -524,8 +524,9 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 	while (host_clock / pre_div / div > clock && div < 16)
 		div++;
 
+	host->mmc->actual_clock = host_clock / pre_div / div;
 	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
-		clock, host_clock / pre_div / div);
+		clock, host->mmc->actual_clock);
 
 	pre_div >>= 1;
 	div--;
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 9/9] ARM: dts: imx6qdl: add uhs pinctrl state for usdhc3
  2013-09-13 11:11 [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Dong Aisheng
                   ` (7 preceding siblings ...)
  2013-09-13 11:11 ` [PATCH v2 8/9] mmc: sdhci-esdhc-imx: set actual_clock in clock setting Dong Aisheng
@ 2013-09-13 11:11 ` Dong Aisheng
  2013-09-16  8:44   ` Shawn Guo
  2013-09-26  2:01 ` [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Chris Ball
  9 siblings, 1 reply; 14+ messages in thread
From: Dong Aisheng @ 2013-09-13 11:11 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang,
	ulf.hansson, neko, b29396

This is needed for supporting ultra high speed cards like SD3.0 cards.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/boot/dts/imx6qdl-sabreauto.dtsi |    5 ++++-
 arch/arm/boot/dts/imx6qdl.dtsi           |   30 ++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 1 deletions(-)

diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
index 1cbbc51..ff6f1e8 100644
--- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
@@ -54,6 +54,7 @@
 			fsl,pins = <
 				MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x80000000
 				MX6QDL_PAD_SD2_DAT2__GPIO1_IO13  0x80000000
+				MX6QDL_PAD_GPIO_18__SD3_VSELECT 0x17059
 			>;
 		};
 	};
@@ -74,8 +75,10 @@
 };
 
 &usdhc3 {
-	pinctrl-names = "default";
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc3_1>;
+	pinctrl-1 = <&pinctrl_usdhc3_1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_1_200mhz>;
 	cd-gpios = <&gpio6 15 0>;
 	wp-gpios = <&gpio1 13 0>;
 	status = "okay";
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index ccd55c2..cb17574 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1184,6 +1184,36 @@
 						>;
 					};
 
+					pinctrl_usdhc3_1_100mhz: usdhc3grp-1-100mhz { /* 100Mhz */
+						fsl,pins = <
+							MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170B9
+							MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100B9
+							MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170B9
+							MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170B9
+							MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170B9
+							MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170B9
+							MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170B9
+							MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170B9
+							MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170B9
+							MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170B9
+						>;
+					};
+
+					pinctrl_usdhc3_1_200mhz: usdhc3grp-1-200mhz { /* 200Mhz */
+						fsl,pins = <
+							MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170F9
+							MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100F9
+							MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170F9
+							MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170F9
+							MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170F9
+							MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170F9
+							MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170F9
+							MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170F9
+							MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170F9
+							MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170F9
+						>;
+					};
+
 					pinctrl_usdhc3_2: usdhc3grp-2 {
 						fsl,pins = <
 							MX6QDL_PAD_SD3_CMD__SD3_CMD    0x17059
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 9/9] ARM: dts: imx6qdl: add uhs pinctrl state for usdhc3
  2013-09-13 11:11 ` [PATCH v2 9/9] ARM: dts: imx6qdl: add uhs pinctrl state for usdhc3 Dong Aisheng
@ 2013-09-16  8:44   ` Shawn Guo
  0 siblings, 0 replies; 14+ messages in thread
From: Shawn Guo @ 2013-09-16  8:44 UTC (permalink / raw)
  To: Dong Aisheng
  Cc: linux-mmc, linux-arm-kernel, cjb, anton, s.hauer, w.sang,
	ulf.hansson, neko

On Fri, Sep 13, 2013 at 07:11:38PM +0800, Dong Aisheng wrote:
> This is needed for supporting ultra high speed cards like SD3.0 cards.
> 
> Signed-off-by: Dong Aisheng <b29396@freescale.com>
> ---
>  arch/arm/boot/dts/imx6qdl-sabreauto.dtsi |    5 ++++-
>  arch/arm/boot/dts/imx6qdl.dtsi           |   30 ++++++++++++++++++++++++++++++
>  2 files changed, 34 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
> index 1cbbc51..ff6f1e8 100644
> --- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
> +++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
> @@ -54,6 +54,7 @@
>  			fsl,pins = <
>  				MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x80000000
>  				MX6QDL_PAD_SD2_DAT2__GPIO1_IO13  0x80000000
> +				MX6QDL_PAD_GPIO_18__SD3_VSELECT 0x17059
>  			>;
>  		};
>  	};
> @@ -74,8 +75,10 @@
>  };
>  
>  &usdhc3 {
> -	pinctrl-names = "default";
> +	pinctrl-names = "default", "state_100mhz", "state_200mhz";
>  	pinctrl-0 = <&pinctrl_usdhc3_1>;
> +	pinctrl-1 = <&pinctrl_usdhc3_1_100mhz>;
> +	pinctrl-2 = <&pinctrl_usdhc3_1_200mhz>;
>  	cd-gpios = <&gpio6 15 0>;
>  	wp-gpios = <&gpio1 13 0>;
>  	status = "okay";
> diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
> index ccd55c2..cb17574 100644
> --- a/arch/arm/boot/dts/imx6qdl.dtsi
> +++ b/arch/arm/boot/dts/imx6qdl.dtsi
> @@ -1184,6 +1184,36 @@
>  						>;
>  					};
>  
> +					pinctrl_usdhc3_1_100mhz: usdhc3grp-1-100mhz { /* 100Mhz */
> +						fsl,pins = <
> +							MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170B9
> +							MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100B9
> +							MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170B9
> +							MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170B9
> +							MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170B9
> +							MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170B9
> +							MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170B9
> +							MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170B9
> +							MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170B9
> +							MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170B9

I commented in the previous review that we use lowercase for hex values
in device tree.  It seems that you missed the comment.  Since this patch
can be applied independently, I just fixed them up and applied it.

Shawn

> +						>;
> +					};
> +
> +					pinctrl_usdhc3_1_200mhz: usdhc3grp-1-200mhz { /* 200Mhz */
> +						fsl,pins = <
> +							MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170F9
> +							MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100F9
> +							MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170F9
> +							MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170F9
> +							MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170F9
> +							MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170F9
> +							MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170F9
> +							MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170F9
> +							MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170F9
> +							MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170F9
> +						>;
> +					};
> +
>  					pinctrl_usdhc3_2: usdhc3grp-2 {
>  						fsl,pins = <
>  							MX6QDL_PAD_SD3_CMD__SD3_CMD    0x17059
> -- 
> 1.7.1
> 
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support
  2013-09-13 11:11 [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Dong Aisheng
                   ` (8 preceding siblings ...)
  2013-09-13 11:11 ` [PATCH v2 9/9] ARM: dts: imx6qdl: add uhs pinctrl state for usdhc3 Dong Aisheng
@ 2013-09-26  2:01 ` Chris Ball
  2013-09-26  9:02   ` Shawn Guo
  9 siblings, 1 reply; 14+ messages in thread
From: Chris Ball @ 2013-09-26  2:01 UTC (permalink / raw)
  To: Dong Aisheng
  Cc: linux-mmc, linux-arm-kernel, shawn.guo, anton, s.hauer, w.sang,
	ulf.hansson, neko

Hi Shawn, Sascha,

On Fri, Sep 13 2013, Dong Aisheng wrote:
> This patch series add SD3.0 support for i.MX6Q/DL.
> Since freescale i.MX6Q/DL uSDHC clock tuning progress is a little different from
> the standard tuning process defined in host controller spec v3.0.
> So we add a hook to allow execute platform specific tuning instead of
> standard host controller tuning.
>
> The main difference are:
> 1) not only generate Buffer Read Ready interrupt when tuning is performing.
> It generates all other DATA interrupts like the normal data command.
> 2) SDHCI_CTRL_EXEC_TUNING is not automatically cleared by HW,
> instead it's controlled by SW.
> 3) SDHCI_CTRL_TUNED_CLK is not automatically set by HW,
> it's controlled by SW.
> 4) the clock delay for every tuning is set by SW.
>
> Tested on i.MX6Q Sabreauto board.

Please could someone ACK this series?  Thanks,

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support
  2013-09-26  2:01 ` [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Chris Ball
@ 2013-09-26  9:02   ` Shawn Guo
  2013-09-26 11:57     ` Chris Ball
  0 siblings, 1 reply; 14+ messages in thread
From: Shawn Guo @ 2013-09-26  9:02 UTC (permalink / raw)
  To: Chris Ball
  Cc: ulf.hansson, s.hauer, anton, linux-mmc, w.sang, neko,
	Dong Aisheng, linux-arm-kernel

On Wed, Sep 25, 2013 at 10:01:52PM -0400, Chris Ball wrote:
> Hi Shawn, Sascha,
> 
> On Fri, Sep 13 2013, Dong Aisheng wrote:
> > This patch series add SD3.0 support for i.MX6Q/DL.
> > Since freescale i.MX6Q/DL uSDHC clock tuning progress is a little different from
> > the standard tuning process defined in host controller spec v3.0.
> > So we add a hook to allow execute platform specific tuning instead of
> > standard host controller tuning.
> >
> > The main difference are:
> > 1) not only generate Buffer Read Ready interrupt when tuning is performing.
> > It generates all other DATA interrupts like the normal data command.
> > 2) SDHCI_CTRL_EXEC_TUNING is not automatically cleared by HW,
> > instead it's controlled by SW.
> > 3) SDHCI_CTRL_TUNED_CLK is not automatically set by HW,
> > it's controlled by SW.
> > 4) the clock delay for every tuning is set by SW.
> >
> > Tested on i.MX6Q Sabreauto board.
> 
> Please could someone ACK this series?  Thanks,

Acked-by: Shawn Guo <shawn.guo@linaro.org>

One thing need to mention is that the series only adds support for
UHS SDR cards, and DDR cards haven't been working yet.

Shawn

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support
  2013-09-26  9:02   ` Shawn Guo
@ 2013-09-26 11:57     ` Chris Ball
  0 siblings, 0 replies; 14+ messages in thread
From: Chris Ball @ 2013-09-26 11:57 UTC (permalink / raw)
  To: Shawn Guo
  Cc: ulf.hansson, s.hauer, anton, linux-mmc, w.sang, neko,
	Dong Aisheng, linux-arm-kernel

Hi,

On Thu, Sep 26 2013, Shawn Guo wrote:
> On Wed, Sep 25, 2013 at 10:01:52PM -0400, Chris Ball wrote:
>> Hi Shawn, Sascha,
>> 
>> On Fri, Sep 13 2013, Dong Aisheng wrote:
>> > This patch series add SD3.0 support for i.MX6Q/DL.
>> > Since freescale i.MX6Q/DL uSDHC clock tuning progress is a little
>> > different from
>> > the standard tuning process defined in host controller spec v3.0.
>> > So we add a hook to allow execute platform specific tuning instead of
>> > standard host controller tuning.
>> >
>> > The main difference are:
>> > 1) not only generate Buffer Read Ready interrupt when tuning is performing.
>> > It generates all other DATA interrupts like the normal data command.
>> > 2) SDHCI_CTRL_EXEC_TUNING is not automatically cleared by HW,
>> > instead it's controlled by SW.
>> > 3) SDHCI_CTRL_TUNED_CLK is not automatically set by HW,
>> > it's controlled by SW.
>> > 4) the clock delay for every tuning is set by SW.
>> >
>> > Tested on i.MX6Q Sabreauto board.
>> 
>> Please could someone ACK this series?  Thanks,
>
> Acked-by: Shawn Guo <shawn.guo@linaro.org>
>
> One thing need to mention is that the series only adds support for
> UHS SDR cards, and DDR cards haven't been working yet.

Thanks, patches 1-8 pushed to mmc-next for 3.13 with Shawn's ACK.

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2013-09-26 11:57 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-13 11:11 [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Dong Aisheng
2013-09-13 11:11 ` [PATCH v2 1/9] mmc: sdhci: add hooks for platform specific tuning Dong Aisheng
2013-09-13 11:11 ` [PATCH v2 2/9] mmc: sdhci: allow platform access of sdhci_send_command Dong Aisheng
2013-09-13 11:11 ` [PATCH v2 3/9] mmc: sdhci-esdhci: move common esdhc_set_clock to platform driver Dong Aisheng
2013-09-13 11:11 ` [PATCH v2 4/9] sdhci: sdhci-esdhc-imx: support real clock on and off for imx6q Dong Aisheng
2013-09-13 11:11 ` [PATCH v2 5/9] sdhci: sdhci-esdhci-imx: add sd3.0 clock tuning support Dong Aisheng
2013-09-13 11:11 ` [PATCH v2 6/9] sdhci: sdhci-esdhc-imx: change pinctrl state according to uhs mode Dong Aisheng
2013-09-13 11:11 ` [PATCH v2 7/9] mmc: sdhci-esdhc-imx: correct pre_div for imx6q Dong Aisheng
2013-09-13 11:11 ` [PATCH v2 8/9] mmc: sdhci-esdhc-imx: set actual_clock in clock setting Dong Aisheng
2013-09-13 11:11 ` [PATCH v2 9/9] ARM: dts: imx6qdl: add uhs pinctrl state for usdhc3 Dong Aisheng
2013-09-16  8:44   ` Shawn Guo
2013-09-26  2:01 ` [PATCH v2 0/9] mmc: sdhci-esdhc-imx: add SD3.0 support Chris Ball
2013-09-26  9:02   ` Shawn Guo
2013-09-26 11:57     ` Chris Ball

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).