All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/10] mmc: sdhci-esdhc-imx: add std tuning for mx6sl and DDR mode support
@ 2013-10-09 11:20 ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang, b29396,
	john.tobias.ph

The i.MX6SL supports standard tuning as defined in standard host control spec v3.0.
So this patch series add std tuning support for i.MX6SL.
(NOTE i.MX6SL can also work on the old manual tuning mode as i.MX6Q/DL)
In the meanwhile, it also adds DDR mode support.
Then SD3.0 cards which can only support DDR50 can work properly now
with this patch series.

Patch 1~5 add stardard tuning support for i.MX6SL.
Patch 6~7 add DDR mode and delay line support
Patch 8~10 some other related minor fixes.

Tested on i.MX6SL EVK board.

The patch series is generated based on the latest mmc-next branch in Chris' tree.

Dong Aisheng (10):
  ARM: dts: imx6sl: add pinctrl uhs states for usdhc
  mmc: sdhci-esdhc-imx: add std tuning support for mx6sl
  ARM: dts: imx6sl: change usdhc compatible with imx6sl only
  mmc: sdhci-esdhc-imx: fix reading cap_1 register value for mx6sl
  mmc: sdhci: report error once the maximum tuning loops exhausted or
    timeout
  mmc: sdhci-esdhc-imx: add DDR mode support for mx6
  mmc: sdhci-esdhc-imx: add delay line setting support
  mmc: sdhci-esdhc-imx: enable SDR50 tuning for imx6q/dl
  mmc: sdhci-esdhc-imx: add preset value quirk for mx6
  mmc: sdhci: remove unneeded call when have preset value quirk

 .../devicetree/bindings/mmc/fsl-imx-esdhc.txt      |    1 +
 arch/arm/boot/dts/imx6sl-evk.dts                   |   12 ++-
 arch/arm/boot/dts/imx6sl.dtsi                      |   85 +++++++++++-
 drivers/mmc/host/sdhci-esdhc-imx.c                 |  145 ++++++++++++++++----
 drivers/mmc/host/sdhci.c                           |    4 +-
 include/linux/platform_data/mmc-esdhc-imx.h        |    1 +
 6 files changed, 213 insertions(+), 35 deletions(-)

-- 
1.7.2.rc3



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

* [PATCH 00/10] mmc: sdhci-esdhc-imx: add std tuning for mx6sl and DDR mode support
@ 2013-10-09 11:20 ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

The i.MX6SL supports standard tuning as defined in standard host control spec v3.0.
So this patch series add std tuning support for i.MX6SL.
(NOTE i.MX6SL can also work on the old manual tuning mode as i.MX6Q/DL)
In the meanwhile, it also adds DDR mode support.
Then SD3.0 cards which can only support DDR50 can work properly now
with this patch series.

Patch 1~5 add stardard tuning support for i.MX6SL.
Patch 6~7 add DDR mode and delay line support
Patch 8~10 some other related minor fixes.

Tested on i.MX6SL EVK board.

The patch series is generated based on the latest mmc-next branch in Chris' tree.

Dong Aisheng (10):
  ARM: dts: imx6sl: add pinctrl uhs states for usdhc
  mmc: sdhci-esdhc-imx: add std tuning support for mx6sl
  ARM: dts: imx6sl: change usdhc compatible with imx6sl only
  mmc: sdhci-esdhc-imx: fix reading cap_1 register value for mx6sl
  mmc: sdhci: report error once the maximum tuning loops exhausted or
    timeout
  mmc: sdhci-esdhc-imx: add DDR mode support for mx6
  mmc: sdhci-esdhc-imx: add delay line setting support
  mmc: sdhci-esdhc-imx: enable SDR50 tuning for imx6q/dl
  mmc: sdhci-esdhc-imx: add preset value quirk for mx6
  mmc: sdhci: remove unneeded call when have preset value quirk

 .../devicetree/bindings/mmc/fsl-imx-esdhc.txt      |    1 +
 arch/arm/boot/dts/imx6sl-evk.dts                   |   12 ++-
 arch/arm/boot/dts/imx6sl.dtsi                      |   85 +++++++++++-
 drivers/mmc/host/sdhci-esdhc-imx.c                 |  145 ++++++++++++++++----
 drivers/mmc/host/sdhci.c                           |    4 +-
 include/linux/platform_data/mmc-esdhc-imx.h        |    1 +
 6 files changed, 213 insertions(+), 35 deletions(-)

-- 
1.7.2.rc3

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

* [PATCH 01/10] ARM: dts: imx6sl: add pinctrl uhs states for usdhc
  2013-10-09 11:20 ` Dong Aisheng
@ 2013-10-09 11:20   ` Dong Aisheng
  -1 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang, b29396,
	john.tobias.ph

This is needed for SD3.0 cards working on UHS mode.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/boot/dts/imx6sl-evk.dts |   12 ++++-
 arch/arm/boot/dts/imx6sl.dtsi    |   77 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts
index 2886a59..d2f46c6 100644
--- a/arch/arm/boot/dts/imx6sl-evk.dts
+++ b/arch/arm/boot/dts/imx6sl-evk.dts
@@ -50,8 +50,10 @@
 };
 
 &usdhc1 {
-	pinctrl-names = "default";
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc1_1>;
+	pinctrl-1 = <&pinctrl_usdhc1_1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_1_200mhz>;
 	bus-width = <8>;
 	cd-gpios = <&gpio4 7 0>;
 	wp-gpios = <&gpio4 6 0>;
@@ -59,16 +61,20 @@
 };
 
 &usdhc2 {
-	pinctrl-names = "default";
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc2_1>;
+	pinctrl-1 = <&pinctrl_usdhc2_1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc2_1_200mhz>;
 	cd-gpios = <&gpio5 0 0>;
 	wp-gpios = <&gpio4 29 0>;
 	status = "okay";
 };
 
 &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 = <&gpio3 22 0>;
 	status = "okay";
 };
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index c46651e..d0ae4c6 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -572,6 +572,38 @@
 							MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x17059
 						>;
 					};
+
+					pinctrl_usdhc1_1_100mhz: usdhc1grp-1-100mhz {
+						fsl,pins = <
+							MX6SL_PAD_SD1_CMD__SD1_CMD 0x170b9
+							MX6SL_PAD_SD1_CLK__SD1_CLK 0x100b9
+							MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170b9
+							MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170b9
+							MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170b9
+							MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170b9
+							MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170b9
+							MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170b9
+							MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170b9
+							MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170b9
+						>;
+					};
+
+					pinctrl_usdhc1_1_200mhz: usdhc1grp-1-200mhz {
+						fsl,pins = <
+							MX6SL_PAD_SD1_CMD__SD1_CMD 0x170f9
+							MX6SL_PAD_SD1_CLK__SD1_CLK 0x100f9
+							MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170f9
+							MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170f9
+							MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170f9
+							MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170f9
+							MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170f9
+							MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170f9
+							MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170f9
+							MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170f9
+						>;
+					};
+
+
 				};
 
 				usdhc2 {
@@ -585,6 +617,29 @@
 							MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x17059
 						>;
 					};
+
+					pinctrl_usdhc2_1_100mhz: usdhc2grp-1-100mhz {
+						fsl,pins = <
+							MX6SL_PAD_SD2_CMD__SD2_CMD    0x170b9
+							MX6SL_PAD_SD2_CLK__SD2_CLK    0x100b9
+							MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170b9
+							MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170b9
+							MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170b9
+							MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170b9
+						>;
+					};
+
+					pinctrl_usdhc2_1_200mhz: usdhc2grp-1-200mhz {
+						fsl,pins = <
+							MX6SL_PAD_SD2_CMD__SD2_CMD    0x170f9
+							MX6SL_PAD_SD2_CLK__SD2_CLK    0x100f9
+							MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170f9
+							MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170f9
+							MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170f9
+							MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170f9
+						>;
+					};
+
 				};
 
 				usdhc3 {
@@ -598,6 +653,28 @@
 							MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x17059
 						>;
 					};
+
+					pinctrl_usdhc3_1_100mhz: usdhc3grp-1-100mhz {
+						fsl,pins = <
+							MX6SL_PAD_SD3_CMD__SD3_CMD    0x170b9
+							MX6SL_PAD_SD3_CLK__SD3_CLK    0x100b9
+							MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170b9
+							MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170b9
+							MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170b9
+							MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170b9
+						>;
+					};
+
+					pinctrl_usdhc3_1_200mhz: usdhc3grp-1-200mhz {
+						fsl,pins = <
+							MX6SL_PAD_SD3_CMD__SD3_CMD    0x170f9
+							MX6SL_PAD_SD3_CLK__SD3_CLK    0x100f9
+							MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170f9
+							MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170f9
+							MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170f9
+							MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170f9
+						>;
+					};
 				};
 			};
 
-- 
1.7.2.rc3



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

* [PATCH 01/10] ARM: dts: imx6sl: add pinctrl uhs states for usdhc
@ 2013-10-09 11:20   ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

This is needed for SD3.0 cards working on UHS mode.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/boot/dts/imx6sl-evk.dts |   12 ++++-
 arch/arm/boot/dts/imx6sl.dtsi    |   77 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts
index 2886a59..d2f46c6 100644
--- a/arch/arm/boot/dts/imx6sl-evk.dts
+++ b/arch/arm/boot/dts/imx6sl-evk.dts
@@ -50,8 +50,10 @@
 };
 
 &usdhc1 {
-	pinctrl-names = "default";
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc1_1>;
+	pinctrl-1 = <&pinctrl_usdhc1_1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_1_200mhz>;
 	bus-width = <8>;
 	cd-gpios = <&gpio4 7 0>;
 	wp-gpios = <&gpio4 6 0>;
@@ -59,16 +61,20 @@
 };
 
 &usdhc2 {
-	pinctrl-names = "default";
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc2_1>;
+	pinctrl-1 = <&pinctrl_usdhc2_1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc2_1_200mhz>;
 	cd-gpios = <&gpio5 0 0>;
 	wp-gpios = <&gpio4 29 0>;
 	status = "okay";
 };
 
 &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 = <&gpio3 22 0>;
 	status = "okay";
 };
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index c46651e..d0ae4c6 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -572,6 +572,38 @@
 							MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x17059
 						>;
 					};
+
+					pinctrl_usdhc1_1_100mhz: usdhc1grp-1-100mhz {
+						fsl,pins = <
+							MX6SL_PAD_SD1_CMD__SD1_CMD 0x170b9
+							MX6SL_PAD_SD1_CLK__SD1_CLK 0x100b9
+							MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170b9
+							MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170b9
+							MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170b9
+							MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170b9
+							MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170b9
+							MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170b9
+							MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170b9
+							MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170b9
+						>;
+					};
+
+					pinctrl_usdhc1_1_200mhz: usdhc1grp-1-200mhz {
+						fsl,pins = <
+							MX6SL_PAD_SD1_CMD__SD1_CMD 0x170f9
+							MX6SL_PAD_SD1_CLK__SD1_CLK 0x100f9
+							MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170f9
+							MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170f9
+							MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170f9
+							MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170f9
+							MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170f9
+							MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170f9
+							MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170f9
+							MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170f9
+						>;
+					};
+
+
 				};
 
 				usdhc2 {
@@ -585,6 +617,29 @@
 							MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x17059
 						>;
 					};
+
+					pinctrl_usdhc2_1_100mhz: usdhc2grp-1-100mhz {
+						fsl,pins = <
+							MX6SL_PAD_SD2_CMD__SD2_CMD    0x170b9
+							MX6SL_PAD_SD2_CLK__SD2_CLK    0x100b9
+							MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170b9
+							MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170b9
+							MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170b9
+							MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170b9
+						>;
+					};
+
+					pinctrl_usdhc2_1_200mhz: usdhc2grp-1-200mhz {
+						fsl,pins = <
+							MX6SL_PAD_SD2_CMD__SD2_CMD    0x170f9
+							MX6SL_PAD_SD2_CLK__SD2_CLK    0x100f9
+							MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170f9
+							MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170f9
+							MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170f9
+							MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170f9
+						>;
+					};
+
 				};
 
 				usdhc3 {
@@ -598,6 +653,28 @@
 							MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x17059
 						>;
 					};
+
+					pinctrl_usdhc3_1_100mhz: usdhc3grp-1-100mhz {
+						fsl,pins = <
+							MX6SL_PAD_SD3_CMD__SD3_CMD    0x170b9
+							MX6SL_PAD_SD3_CLK__SD3_CLK    0x100b9
+							MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170b9
+							MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170b9
+							MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170b9
+							MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170b9
+						>;
+					};
+
+					pinctrl_usdhc3_1_200mhz: usdhc3grp-1-200mhz {
+						fsl,pins = <
+							MX6SL_PAD_SD3_CMD__SD3_CMD    0x170f9
+							MX6SL_PAD_SD3_CLK__SD3_CLK    0x100f9
+							MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170f9
+							MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170f9
+							MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170f9
+							MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170f9
+						>;
+					};
 				};
 			};
 
-- 
1.7.2.rc3

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

* [PATCH 02/10] mmc: sdhci-esdhc-imx: add std tuning support for mx6sl
  2013-10-09 11:20 ` Dong Aisheng
@ 2013-10-09 11:20   ` Dong Aisheng
  -1 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang, b29396,
	john.tobias.ph

The mx6sl supports standard sdhci tuning, then esdhc_executing_tuning
is only needed for mx6q/dl. We introduce is_imx6_usdhc() and
is_imx6sl_usdhc() to handle the difference.

The standard tuning is enabled by setting ESDHC_TUNE_CTRL_STD_TUNING_EN bit
in new register ESDHC_TUNE_CTRL and operates with new tuning bits
defined in SDHCI_ACMD12_ERR register.

Note: mx6sl can also work on the old manually tuning mode as mx6q/dl if
not enable standard tuning mode.

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

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index b9899e9..2cce244 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -51,6 +51,11 @@
 #define  ESDHC_TUNE_CTRL_MIN		0
 #define  ESDHC_TUNE_CTRL_MAX		((1 << 7) - 1)
 
+#define ESDHC_TUNING_CTRL		0xCC
+#define ESDHC_STD_TUNING_EN		(1 << 24)
+/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
+#define ESDHC_TUNING_START_TAP		0x1
+
 #define ESDHC_TUNING_BLOCK_PATTERN_LEN	64
 
 /* pinctrl state */
@@ -91,6 +96,7 @@ enum imx_esdhc_type {
 	IMX51_ESDHC,
 	IMX53_ESDHC,
 	IMX6Q_USDHC,
+	IMX6SL_USDHC,
 };
 
 struct pltfm_imx_data {
@@ -130,6 +136,9 @@ static struct platform_device_id imx_esdhc_devtype[] = {
 		.name = "sdhci-usdhc-imx6q",
 		.driver_data = IMX6Q_USDHC,
 	}, {
+		.name = "sdhci-usdhc-imx6sl",
+		.driver_data = IMX6SL_USDHC,
+	}, {
 		/* sentinel */
 	}
 };
@@ -141,6 +150,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
 	{ .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
 	{ .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
 	{ .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], },
+	{ .compatible = "fsl,imx6sl-usdhc", .data = &imx_esdhc_devtype[IMX6SL_USDHC], },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
@@ -170,6 +180,17 @@ static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
 	return data->devtype == IMX6Q_USDHC;
 }
 
+static inline int is_imx6sl_usdhc(struct pltfm_imx_data *data)
+{
+	return data->devtype == IMX6SL_USDHC;
+}
+
+static inline int is_imx6_usdhc(struct pltfm_imx_data *data)
+{
+	return (data->devtype == IMX6Q_USDHC) ||
+		(data->devtype == IMX6SL_USDHC);
+}
+
 static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
 {
 	void __iomem *base = host->ioaddr + (reg & ~0x3);
@@ -208,11 +229,16 @@ 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_CAPABILITIES_1)) {
+		if (is_imx6q_usdhc(imx_data))
+			/* imx6q/dl does not have cap_1 register, fake one */
+			val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
+					| SDHCI_SUPPORT_SDR50;
+		else if (is_imx6sl_usdhc(imx_data))
+			val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF;
+	}
 
-	if (unlikely(reg == SDHCI_MAX_CURRENT) && is_imx6q_usdhc(imx_data)) {
+	if (unlikely(reg == SDHCI_MAX_CURRENT) && is_imx6_usdhc(imx_data)) {
 		val = 0;
 		val |= 0xFF << SDHCI_MAX_CURRENT_330_SHIFT;
 		val |= 0xFF << SDHCI_MAX_CURRENT_300_SHIFT;
@@ -316,13 +342,16 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
 		if (val & ESDHC_VENDOR_SPEC_VSELECT)
 			ret |= SDHCI_CTRL_VDD_180;
 
-		if (is_imx6q_usdhc(imx_data)) {
+		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;
-		}
+		else if (is_imx6sl_usdhc(imx_data))
+			/* the std tuning bits is in ACMD12_ERR for imx6sl */
+			val = readl(host->ioaddr + SDHCI_ACMD12_ERR);
+
+		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;
@@ -356,12 +385,37 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 			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);
+		if (is_imx6q_usdhc(imx_data)) {
+			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);
+		} else if (is_imx6sl_usdhc(imx_data)) {
+			u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
+			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
+			new_val = readl(host->ioaddr + ESDHC_TUNING_CTRL);
+			if (val & SDHCI_CTRL_EXEC_TUNING) {
+				new_val |= ESDHC_STD_TUNING_EN |
+						ESDHC_TUNING_START_TAP;
+				v |= ESDHC_MIX_CTRL_EXE_TUNE;
+				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
+			} else {
+				new_val &= ~ESDHC_STD_TUNING_EN;
+				v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
+				m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
+			}
+
+			if (val & SDHCI_CTRL_TUNED_CLK)
+				v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
+			else
+				v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
+
+			writel(new_val, host->ioaddr + ESDHC_TUNING_CTRL);
+			writel(v, host->ioaddr + SDHCI_ACMD12_ERR);
+			writel(m, host->ioaddr + ESDHC_MIX_CTRL);
+		}
 		return;
 	case SDHCI_TRANSFER_MODE:
 		if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
@@ -374,7 +428,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
 		}
 
-		if (is_imx6q_usdhc(imx_data)) {
+		if (is_imx6_usdhc(imx_data)) {
 			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
 			/* Swap AC23 bit */
 			if (val & SDHCI_TRNS_AUTO_CMD23) {
@@ -399,7 +453,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 		    (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
 			imx_data->multiblock_status = MULTIBLK_IN_PROCESS;
 
-		if (is_imx6q_usdhc(imx_data))
+		if (is_imx6_usdhc(imx_data))
 			writel(val << 16,
 			       host->ioaddr + SDHCI_TRANSFER_MODE);
 		else
@@ -465,7 +519,7 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
 		 * The reset on usdhc fails to clear MIX_CTRL register.
 		 * Do it manually here.
 		 */
-		if (is_imx6q_usdhc(imx_data))
+		if (is_imx6_usdhc(imx_data))
 			writel(0, host->ioaddr + ESDHC_MIX_CTRL);
 	}
 }
@@ -502,7 +556,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 	u32 temp, val;
 
 	if (clock == 0) {
-		if (is_imx6q_usdhc(imx_data)) {
+		if (is_imx6_usdhc(imx_data)) {
 			val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
 			writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
 					host->ioaddr + ESDHC_VENDOR_SPEC);
@@ -510,7 +564,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 		goto out;
 	}
 
-	if (is_imx6q_usdhc(imx_data))
+	if (is_imx6_usdhc(imx_data))
 		pre_div = 1;
 
 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
@@ -537,7 +591,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 		| (pre_div << ESDHC_PREDIV_SHIFT));
 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 
-	if (is_imx6q_usdhc(imx_data)) {
+	if (is_imx6_usdhc(imx_data)) {
 		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
 		writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
 		host->ioaddr + ESDHC_VENDOR_SPEC);
@@ -760,7 +814,7 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 	return esdhc_change_pinstate(host, uhs);
 }
 
-static const struct sdhci_ops sdhci_esdhc_ops = {
+static struct sdhci_ops sdhci_esdhc_ops = {
 	.read_l = esdhc_readl_le,
 	.read_w = esdhc_readw_le,
 	.write_l = esdhc_writel_le,
@@ -772,7 +826,6 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
 	.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,
 };
 
 static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
@@ -909,9 +962,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 	 * The imx6q ROM code will change the default watermark level setting
 	 * to something insane.  Change it back here.
 	 */
-	if (is_imx6q_usdhc(imx_data))
+	if (is_imx6_usdhc(imx_data))
 		writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL);
 
+	if (is_imx6q_usdhc(imx_data))
+		sdhci_esdhc_ops.platform_execute_tuning =
+					esdhc_executing_tuning;
 	boarddata = &imx_data->boarddata;
 	if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
 		if (!host->mmc->parent->platform_data) {
@@ -972,7 +1028,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 	}
 
 	/* sdr50 and sdr104 needs work on 1.8v signal voltage */
-	if ((boarddata->support_vsel) && is_imx6q_usdhc(imx_data)) {
+	if ((boarddata->support_vsel) && is_imx6_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,
-- 
1.7.2.rc3



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

* [PATCH 02/10] mmc: sdhci-esdhc-imx: add std tuning support for mx6sl
@ 2013-10-09 11:20   ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

The mx6sl supports standard sdhci tuning, then esdhc_executing_tuning
is only needed for mx6q/dl. We introduce is_imx6_usdhc() and
is_imx6sl_usdhc() to handle the difference.

The standard tuning is enabled by setting ESDHC_TUNE_CTRL_STD_TUNING_EN bit
in new register ESDHC_TUNE_CTRL and operates with new tuning bits
defined in SDHCI_ACMD12_ERR register.

Note: mx6sl can also work on the old manually tuning mode as mx6q/dl if
not enable standard tuning mode.

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

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index b9899e9..2cce244 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -51,6 +51,11 @@
 #define  ESDHC_TUNE_CTRL_MIN		0
 #define  ESDHC_TUNE_CTRL_MAX		((1 << 7) - 1)
 
+#define ESDHC_TUNING_CTRL		0xCC
+#define ESDHC_STD_TUNING_EN		(1 << 24)
+/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
+#define ESDHC_TUNING_START_TAP		0x1
+
 #define ESDHC_TUNING_BLOCK_PATTERN_LEN	64
 
 /* pinctrl state */
@@ -91,6 +96,7 @@ enum imx_esdhc_type {
 	IMX51_ESDHC,
 	IMX53_ESDHC,
 	IMX6Q_USDHC,
+	IMX6SL_USDHC,
 };
 
 struct pltfm_imx_data {
@@ -130,6 +136,9 @@ static struct platform_device_id imx_esdhc_devtype[] = {
 		.name = "sdhci-usdhc-imx6q",
 		.driver_data = IMX6Q_USDHC,
 	}, {
+		.name = "sdhci-usdhc-imx6sl",
+		.driver_data = IMX6SL_USDHC,
+	}, {
 		/* sentinel */
 	}
 };
@@ -141,6 +150,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
 	{ .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
 	{ .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
 	{ .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], },
+	{ .compatible = "fsl,imx6sl-usdhc", .data = &imx_esdhc_devtype[IMX6SL_USDHC], },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
@@ -170,6 +180,17 @@ static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
 	return data->devtype == IMX6Q_USDHC;
 }
 
+static inline int is_imx6sl_usdhc(struct pltfm_imx_data *data)
+{
+	return data->devtype == IMX6SL_USDHC;
+}
+
+static inline int is_imx6_usdhc(struct pltfm_imx_data *data)
+{
+	return (data->devtype == IMX6Q_USDHC) ||
+		(data->devtype == IMX6SL_USDHC);
+}
+
 static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
 {
 	void __iomem *base = host->ioaddr + (reg & ~0x3);
@@ -208,11 +229,16 @@ 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_CAPABILITIES_1)) {
+		if (is_imx6q_usdhc(imx_data))
+			/* imx6q/dl does not have cap_1 register, fake one */
+			val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
+					| SDHCI_SUPPORT_SDR50;
+		else if (is_imx6sl_usdhc(imx_data))
+			val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF;
+	}
 
-	if (unlikely(reg == SDHCI_MAX_CURRENT) && is_imx6q_usdhc(imx_data)) {
+	if (unlikely(reg == SDHCI_MAX_CURRENT) && is_imx6_usdhc(imx_data)) {
 		val = 0;
 		val |= 0xFF << SDHCI_MAX_CURRENT_330_SHIFT;
 		val |= 0xFF << SDHCI_MAX_CURRENT_300_SHIFT;
@@ -316,13 +342,16 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
 		if (val & ESDHC_VENDOR_SPEC_VSELECT)
 			ret |= SDHCI_CTRL_VDD_180;
 
-		if (is_imx6q_usdhc(imx_data)) {
+		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;
-		}
+		else if (is_imx6sl_usdhc(imx_data))
+			/* the std tuning bits is in ACMD12_ERR for imx6sl */
+			val = readl(host->ioaddr + SDHCI_ACMD12_ERR);
+
+		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;
@@ -356,12 +385,37 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 			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);
+		if (is_imx6q_usdhc(imx_data)) {
+			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);
+		} else if (is_imx6sl_usdhc(imx_data)) {
+			u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
+			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
+			new_val = readl(host->ioaddr + ESDHC_TUNING_CTRL);
+			if (val & SDHCI_CTRL_EXEC_TUNING) {
+				new_val |= ESDHC_STD_TUNING_EN |
+						ESDHC_TUNING_START_TAP;
+				v |= ESDHC_MIX_CTRL_EXE_TUNE;
+				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
+			} else {
+				new_val &= ~ESDHC_STD_TUNING_EN;
+				v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
+				m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
+			}
+
+			if (val & SDHCI_CTRL_TUNED_CLK)
+				v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
+			else
+				v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
+
+			writel(new_val, host->ioaddr + ESDHC_TUNING_CTRL);
+			writel(v, host->ioaddr + SDHCI_ACMD12_ERR);
+			writel(m, host->ioaddr + ESDHC_MIX_CTRL);
+		}
 		return;
 	case SDHCI_TRANSFER_MODE:
 		if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
@@ -374,7 +428,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
 		}
 
-		if (is_imx6q_usdhc(imx_data)) {
+		if (is_imx6_usdhc(imx_data)) {
 			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
 			/* Swap AC23 bit */
 			if (val & SDHCI_TRNS_AUTO_CMD23) {
@@ -399,7 +453,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 		    (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
 			imx_data->multiblock_status = MULTIBLK_IN_PROCESS;
 
-		if (is_imx6q_usdhc(imx_data))
+		if (is_imx6_usdhc(imx_data))
 			writel(val << 16,
 			       host->ioaddr + SDHCI_TRANSFER_MODE);
 		else
@@ -465,7 +519,7 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
 		 * The reset on usdhc fails to clear MIX_CTRL register.
 		 * Do it manually here.
 		 */
-		if (is_imx6q_usdhc(imx_data))
+		if (is_imx6_usdhc(imx_data))
 			writel(0, host->ioaddr + ESDHC_MIX_CTRL);
 	}
 }
@@ -502,7 +556,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 	u32 temp, val;
 
 	if (clock == 0) {
-		if (is_imx6q_usdhc(imx_data)) {
+		if (is_imx6_usdhc(imx_data)) {
 			val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
 			writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
 					host->ioaddr + ESDHC_VENDOR_SPEC);
@@ -510,7 +564,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 		goto out;
 	}
 
-	if (is_imx6q_usdhc(imx_data))
+	if (is_imx6_usdhc(imx_data))
 		pre_div = 1;
 
 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
@@ -537,7 +591,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 		| (pre_div << ESDHC_PREDIV_SHIFT));
 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 
-	if (is_imx6q_usdhc(imx_data)) {
+	if (is_imx6_usdhc(imx_data)) {
 		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
 		writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
 		host->ioaddr + ESDHC_VENDOR_SPEC);
@@ -760,7 +814,7 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 	return esdhc_change_pinstate(host, uhs);
 }
 
-static const struct sdhci_ops sdhci_esdhc_ops = {
+static struct sdhci_ops sdhci_esdhc_ops = {
 	.read_l = esdhc_readl_le,
 	.read_w = esdhc_readw_le,
 	.write_l = esdhc_writel_le,
@@ -772,7 +826,6 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
 	.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,
 };
 
 static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
@@ -909,9 +962,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 	 * The imx6q ROM code will change the default watermark level setting
 	 * to something insane.  Change it back here.
 	 */
-	if (is_imx6q_usdhc(imx_data))
+	if (is_imx6_usdhc(imx_data))
 		writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL);
 
+	if (is_imx6q_usdhc(imx_data))
+		sdhci_esdhc_ops.platform_execute_tuning =
+					esdhc_executing_tuning;
 	boarddata = &imx_data->boarddata;
 	if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
 		if (!host->mmc->parent->platform_data) {
@@ -972,7 +1028,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 	}
 
 	/* sdr50 and sdr104 needs work on 1.8v signal voltage */
-	if ((boarddata->support_vsel) && is_imx6q_usdhc(imx_data)) {
+	if ((boarddata->support_vsel) && is_imx6_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,
-- 
1.7.2.rc3

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

* [PATCH 03/10] ARM: dts: imx6sl: change usdhc compatible with imx6sl only
  2013-10-09 11:20 ` Dong Aisheng
@ 2013-10-09 11:20   ` Dong Aisheng
  -1 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang, b29396,
	john.tobias.ph

The uSDHC on i.MX6SL is a little different from i.MX6Q,
especially on SD3.0 tuning part,
This change makes it work on i.MX6SL mode only to utilize the features
introduced in i.MX6SL.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/boot/dts/imx6sl.dtsi |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index d0ae4c6..f72b1d6 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -774,7 +774,7 @@
 			};
 
 			usdhc1: usdhc@02190000 {
-				compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
+				compatible = "fsl,imx6sl-usdhc";
 				reg = <0x02190000 0x4000>;
 				interrupts = <0 22 0x04>;
 				clocks = <&clks IMX6SL_CLK_USDHC1>,
@@ -786,7 +786,7 @@
 			};
 
 			usdhc2: usdhc@02194000 {
-				compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
+				compatible = "fsl,imx6sl-usdhc";
 				reg = <0x02194000 0x4000>;
 				interrupts = <0 23 0x04>;
 				clocks = <&clks IMX6SL_CLK_USDHC2>,
@@ -798,7 +798,7 @@
 			};
 
 			usdhc3: usdhc@02198000 {
-				compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
+				compatible = "fsl,imx6sl-usdhc";
 				reg = <0x02198000 0x4000>;
 				interrupts = <0 24 0x04>;
 				clocks = <&clks IMX6SL_CLK_USDHC3>,
@@ -810,7 +810,7 @@
 			};
 
 			usdhc4: usdhc@0219c000 {
-				compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
+				compatible = "fsl,imx6sl-usdhc";
 				reg = <0x0219c000 0x4000>;
 				interrupts = <0 25 0x04>;
 				clocks = <&clks IMX6SL_CLK_USDHC4>,
-- 
1.7.2.rc3



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

* [PATCH 03/10] ARM: dts: imx6sl: change usdhc compatible with imx6sl only
@ 2013-10-09 11:20   ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

The uSDHC on i.MX6SL is a little different from i.MX6Q,
especially on SD3.0 tuning part,
This change makes it work on i.MX6SL mode only to utilize the features
introduced in i.MX6SL.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/boot/dts/imx6sl.dtsi |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index d0ae4c6..f72b1d6 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -774,7 +774,7 @@
 			};
 
 			usdhc1: usdhc at 02190000 {
-				compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
+				compatible = "fsl,imx6sl-usdhc";
 				reg = <0x02190000 0x4000>;
 				interrupts = <0 22 0x04>;
 				clocks = <&clks IMX6SL_CLK_USDHC1>,
@@ -786,7 +786,7 @@
 			};
 
 			usdhc2: usdhc at 02194000 {
-				compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
+				compatible = "fsl,imx6sl-usdhc";
 				reg = <0x02194000 0x4000>;
 				interrupts = <0 23 0x04>;
 				clocks = <&clks IMX6SL_CLK_USDHC2>,
@@ -798,7 +798,7 @@
 			};
 
 			usdhc3: usdhc at 02198000 {
-				compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
+				compatible = "fsl,imx6sl-usdhc";
 				reg = <0x02198000 0x4000>;
 				interrupts = <0 24 0x04>;
 				clocks = <&clks IMX6SL_CLK_USDHC3>,
@@ -810,7 +810,7 @@
 			};
 
 			usdhc4: usdhc at 0219c000 {
-				compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc";
+				compatible = "fsl,imx6sl-usdhc";
 				reg = <0x0219c000 0x4000>;
 				interrupts = <0 25 0x04>;
 				clocks = <&clks IMX6SL_CLK_USDHC4>,
-- 
1.7.2.rc3

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

* [PATCH 04/10] mmc: sdhci-esdhc-imx: fix reading cap_1 register value for mx6sl
  2013-10-09 11:20 ` Dong Aisheng
@ 2013-10-09 11:20   ` Dong Aisheng
  -1 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang, b29396,
	john.tobias.ph

When reading CAP_1 register for mx6sl, ignore bit[0-15] as it stores
CAP_2 register value which is new introduced in mx6sl.

Without this fix, the max clock for mx6sl may not be correct since
it's wrongly calculated by reading CAP_1 register.

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

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 2cce244..8721549 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -216,6 +216,10 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
 	}
 
 	if (unlikely(reg == SDHCI_CAPABILITIES)) {
+		/* ignore bit[0-15] as it stores cap_2 register val for mx6sl */
+		if (is_imx6sl_usdhc(imx_data))
+			val &= 0xffff0000;
+
 		/* In FSL esdhc IC module, only bit20 is used to indicate the
 		 * ADMA2 capability of esdhc, but this bit is messed up on
 		 * some SOCs (e.g. on MX25, MX35 this bit is set, but they
-- 
1.7.2.rc3



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

* [PATCH 04/10] mmc: sdhci-esdhc-imx: fix reading cap_1 register value for mx6sl
@ 2013-10-09 11:20   ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

When reading CAP_1 register for mx6sl, ignore bit[0-15] as it stores
CAP_2 register value which is new introduced in mx6sl.

Without this fix, the max clock for mx6sl may not be correct since
it's wrongly calculated by reading CAP_1 register.

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

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 2cce244..8721549 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -216,6 +216,10 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
 	}
 
 	if (unlikely(reg == SDHCI_CAPABILITIES)) {
+		/* ignore bit[0-15] as it stores cap_2 register val for mx6sl */
+		if (is_imx6sl_usdhc(imx_data))
+			val &= 0xffff0000;
+
 		/* In FSL esdhc IC module, only bit20 is used to indicate the
 		 * ADMA2 capability of esdhc, but this bit is messed up on
 		 * some SOCs (e.g. on MX25, MX35 this bit is set, but they
-- 
1.7.2.rc3

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

* [PATCH 05/10] mmc: sdhci: report error once the maximum tuning loops exhausted or timeout
  2013-10-09 11:20 ` Dong Aisheng
@ 2013-10-09 11:20   ` Dong Aisheng
  -1 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang, b29396,
	john.tobias.ph

The original code missed to report an error when the maximum tuning loops exhausted
or timeout, it will cause the upper layer to wrongly think the tuning process
is passed.

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

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 66bce7a..cbde17d 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1989,6 +1989,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	if (!tuning_loop_counter || !timeout) {
 		ctrl &= ~SDHCI_CTRL_TUNED_CLK;
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+		err = -EIO;
 	} else {
 		if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
 			pr_info(DRIVER_NAME ": Tuning procedure"
-- 
1.7.2.rc3



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

* [PATCH 05/10] mmc: sdhci: report error once the maximum tuning loops exhausted or timeout
@ 2013-10-09 11:20   ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

The original code missed to report an error when the maximum tuning loops exhausted
or timeout, it will cause the upper layer to wrongly think the tuning process
is passed.

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

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 66bce7a..cbde17d 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1989,6 +1989,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	if (!tuning_loop_counter || !timeout) {
 		ctrl &= ~SDHCI_CTRL_TUNED_CLK;
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+		err = -EIO;
 	} else {
 		if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
 			pr_info(DRIVER_NAME ": Tuning procedure"
-- 
1.7.2.rc3

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

* [PATCH 06/10] mmc: sdhci-esdhc-imx: add DDR mode support for mx6
  2013-10-09 11:20 ` Dong Aisheng
@ 2013-10-09 11:20   ` Dong Aisheng
  -1 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang, b29396,
	john.tobias.ph

When DDR mode is enabled, the initial pre_div should be 2.
And the pre_div value should be changed accordingly
from
...
02h) Base clock divided by 4
01h) Base clock divided by 2
00h) Base clock divided by 1
to
..
02h) Base clock divided by 8
01h) Base clock divided by 4
00h) Base clock divided by 2

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

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 8721549..b6ae5c1 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -38,6 +38,7 @@
 #define  ESDHC_VENDOR_SPEC_FRC_SDCLK_ON	(1 << 8)
 #define ESDHC_WTMK_LVL			0x44
 #define ESDHC_MIX_CTRL			0x48
+#define  ESDHC_MIX_CTRL_DDREN		(1 << 3)
 #define  ESDHC_MIX_CTRL_AC23EN		(1 << 7)
 #define  ESDHC_MIX_CTRL_EXE_TUNE	(1 << 22)
 #define  ESDHC_MIX_CTRL_SMPCLK_SEL	(1 << 23)
@@ -117,6 +118,7 @@ struct pltfm_imx_data {
 		WAIT_FOR_INT,        /* sent CMD12, waiting for response INT */
 	} multiblock_status;
 	u32 uhs_mode;
+	u32 is_ddr;
 };
 
 static struct platform_device_id imx_esdhc_devtype[] = {
@@ -523,8 +525,10 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
 		 * The reset on usdhc fails to clear MIX_CTRL register.
 		 * Do it manually here.
 		 */
-		if (is_imx6_usdhc(imx_data))
+		if (is_imx6_usdhc(imx_data)) {
 			writel(0, host->ioaddr + ESDHC_MIX_CTRL);
+			imx_data->is_ddr = 0;
+		}
 	}
 }
 
@@ -568,7 +572,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 		goto out;
 	}
 
-	if (is_imx6_usdhc(imx_data))
+	if (is_imx6_usdhc(imx_data) && !imx_data->is_ddr)
 		pre_div = 1;
 
 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
@@ -586,7 +590,10 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
 		clock, host->mmc->actual_clock);
 
-	pre_div >>= 1;
+	if (imx_data->is_ddr)
+		pre_div >>= 2;
+	else
+		pre_div >>= 1;
 	div--;
 
 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
@@ -812,6 +819,10 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 		break;
 	case MMC_TIMING_UHS_DDR50:
 		imx_data->uhs_mode = SDHCI_CTRL_UHS_DDR50;
+		writel(readl(host->ioaddr + ESDHC_MIX_CTRL) |
+				ESDHC_MIX_CTRL_DDREN,
+				host->ioaddr + ESDHC_MIX_CTRL);
+		imx_data->is_ddr = 1;
 		break;
 	}
 
-- 
1.7.2.rc3



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

* [PATCH 06/10] mmc: sdhci-esdhc-imx: add DDR mode support for mx6
@ 2013-10-09 11:20   ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

When DDR mode is enabled, the initial pre_div should be 2.
And the pre_div value should be changed accordingly
from
...
02h) Base clock divided by 4
01h) Base clock divided by 2
00h) Base clock divided by 1
to
..
02h) Base clock divided by 8
01h) Base clock divided by 4
00h) Base clock divided by 2

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

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 8721549..b6ae5c1 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -38,6 +38,7 @@
 #define  ESDHC_VENDOR_SPEC_FRC_SDCLK_ON	(1 << 8)
 #define ESDHC_WTMK_LVL			0x44
 #define ESDHC_MIX_CTRL			0x48
+#define  ESDHC_MIX_CTRL_DDREN		(1 << 3)
 #define  ESDHC_MIX_CTRL_AC23EN		(1 << 7)
 #define  ESDHC_MIX_CTRL_EXE_TUNE	(1 << 22)
 #define  ESDHC_MIX_CTRL_SMPCLK_SEL	(1 << 23)
@@ -117,6 +118,7 @@ struct pltfm_imx_data {
 		WAIT_FOR_INT,        /* sent CMD12, waiting for response INT */
 	} multiblock_status;
 	u32 uhs_mode;
+	u32 is_ddr;
 };
 
 static struct platform_device_id imx_esdhc_devtype[] = {
@@ -523,8 +525,10 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
 		 * The reset on usdhc fails to clear MIX_CTRL register.
 		 * Do it manually here.
 		 */
-		if (is_imx6_usdhc(imx_data))
+		if (is_imx6_usdhc(imx_data)) {
 			writel(0, host->ioaddr + ESDHC_MIX_CTRL);
+			imx_data->is_ddr = 0;
+		}
 	}
 }
 
@@ -568,7 +572,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 		goto out;
 	}
 
-	if (is_imx6_usdhc(imx_data))
+	if (is_imx6_usdhc(imx_data) && !imx_data->is_ddr)
 		pre_div = 1;
 
 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
@@ -586,7 +590,10 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
 	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
 		clock, host->mmc->actual_clock);
 
-	pre_div >>= 1;
+	if (imx_data->is_ddr)
+		pre_div >>= 2;
+	else
+		pre_div >>= 1;
 	div--;
 
 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
@@ -812,6 +819,10 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 		break;
 	case MMC_TIMING_UHS_DDR50:
 		imx_data->uhs_mode = SDHCI_CTRL_UHS_DDR50;
+		writel(readl(host->ioaddr + ESDHC_MIX_CTRL) |
+				ESDHC_MIX_CTRL_DDREN,
+				host->ioaddr + ESDHC_MIX_CTRL);
+		imx_data->is_ddr = 1;
 		break;
 	}
 
-- 
1.7.2.rc3

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

* [PATCH 07/10] mmc: sdhci-esdhc-imx: add delay line setting support
  2013-10-09 11:20 ` Dong Aisheng
@ 2013-10-09 11:20   ` Dong Aisheng
  -1 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang, b29396,
	john.tobias.ph

The DLL(Delay Line) is newly added to assist in sampling read data.
The DLL provides the ability to programmatically select a quantized
delay (in fractions of the clock period) regardless of on-chip variations
such as process, voltage and temperature (PVT).

This patch adds a user interface to set slave delay line via device tree.
It's usually used in high speed mode like mmc DDR mode when the signal
quality is not good caused by board design, e.g. the signal path is too long.
User can manual set delay line to find a suitable data sampling window
for card to work properly.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 .../devicetree/bindings/mmc/fsl-imx-esdhc.txt      |    1 +
 drivers/mmc/host/sdhci-esdhc-imx.c                 |   18 ++++++++++++++++++
 include/linux/platform_data/mmc-esdhc-imx.h        |    1 +
 3 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
index 1dd6225..ebd3ff5 100644
--- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
+++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
@@ -12,6 +12,7 @@ Required properties:
 Optional properties:
 - fsl,cd-controller : Indicate to use controller internal card detection
 - fsl,wp-controller : Indicate to use controller internal write protection
+- fsl,delay-line : Specify delay line value of manual override for slave delay.
 
 Examples:
 
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index b6ae5c1..91b2d85 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -46,6 +46,11 @@
 /* Bits 3 and 6 are not SDHCI standard definitions */
 #define  ESDHC_MIX_CTRL_SDHCI_MASK	0xb7
 
+/* dll control register */
+#define ESDHC_DLL_CTRL			0x60
+#define ESDHC_DLL_OVERRIDE_VAL_SHIFT	9
+#define ESDHC_DLL_OVERRIDE_EN_SHIFT	8
+
 /* tune control register */
 #define ESDHC_TUNE_CTRL_STATUS		0x68
 #define  ESDHC_TUNE_CTRL_STEP		1
@@ -803,6 +808,7 @@ 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;
+	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
 
 	switch (uhs) {
 	case MMC_TIMING_UHS_SDR12:
@@ -823,6 +829,15 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 				ESDHC_MIX_CTRL_DDREN,
 				host->ioaddr + ESDHC_MIX_CTRL);
 		imx_data->is_ddr = 1;
+		if (boarddata->delay_line) {
+			u32 v;
+			v = boarddata->delay_line <<
+				ESDHC_DLL_OVERRIDE_VAL_SHIFT |
+				(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
+			if (is_imx53_esdhc(imx_data))
+				v <<= 1;
+			writel(v, host->ioaddr + ESDHC_DLL_CTRL);
+		}
 		break;
 	}
 
@@ -887,6 +902,9 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
 	else
 		boarddata->support_vsel = true;
 
+	if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
+		boarddata->delay_line = 0;
+
 	return 0;
 }
 #else
diff --git a/include/linux/platform_data/mmc-esdhc-imx.h b/include/linux/platform_data/mmc-esdhc-imx.h
index a0f5a8f..75f70f6 100644
--- a/include/linux/platform_data/mmc-esdhc-imx.h
+++ b/include/linux/platform_data/mmc-esdhc-imx.h
@@ -45,5 +45,6 @@ struct esdhc_platform_data {
 	int max_bus_width;
 	unsigned int f_max;
 	bool support_vsel;
+	unsigned int delay_line;
 };
 #endif /* __ASM_ARCH_IMX_ESDHC_H */
-- 
1.7.2.rc3



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

* [PATCH 07/10] mmc: sdhci-esdhc-imx: add delay line setting support
@ 2013-10-09 11:20   ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

The DLL(Delay Line) is newly added to assist in sampling read data.
The DLL provides the ability to programmatically select a quantized
delay (in fractions of the clock period) regardless of on-chip variations
such as process, voltage and temperature (PVT).

This patch adds a user interface to set slave delay line via device tree.
It's usually used in high speed mode like mmc DDR mode when the signal
quality is not good caused by board design, e.g. the signal path is too long.
User can manual set delay line to find a suitable data sampling window
for card to work properly.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 .../devicetree/bindings/mmc/fsl-imx-esdhc.txt      |    1 +
 drivers/mmc/host/sdhci-esdhc-imx.c                 |   18 ++++++++++++++++++
 include/linux/platform_data/mmc-esdhc-imx.h        |    1 +
 3 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
index 1dd6225..ebd3ff5 100644
--- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
+++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
@@ -12,6 +12,7 @@ Required properties:
 Optional properties:
 - fsl,cd-controller : Indicate to use controller internal card detection
 - fsl,wp-controller : Indicate to use controller internal write protection
+- fsl,delay-line : Specify delay line value of manual override for slave delay.
 
 Examples:
 
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index b6ae5c1..91b2d85 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -46,6 +46,11 @@
 /* Bits 3 and 6 are not SDHCI standard definitions */
 #define  ESDHC_MIX_CTRL_SDHCI_MASK	0xb7
 
+/* dll control register */
+#define ESDHC_DLL_CTRL			0x60
+#define ESDHC_DLL_OVERRIDE_VAL_SHIFT	9
+#define ESDHC_DLL_OVERRIDE_EN_SHIFT	8
+
 /* tune control register */
 #define ESDHC_TUNE_CTRL_STATUS		0x68
 #define  ESDHC_TUNE_CTRL_STEP		1
@@ -803,6 +808,7 @@ 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;
+	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
 
 	switch (uhs) {
 	case MMC_TIMING_UHS_SDR12:
@@ -823,6 +829,15 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 				ESDHC_MIX_CTRL_DDREN,
 				host->ioaddr + ESDHC_MIX_CTRL);
 		imx_data->is_ddr = 1;
+		if (boarddata->delay_line) {
+			u32 v;
+			v = boarddata->delay_line <<
+				ESDHC_DLL_OVERRIDE_VAL_SHIFT |
+				(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
+			if (is_imx53_esdhc(imx_data))
+				v <<= 1;
+			writel(v, host->ioaddr + ESDHC_DLL_CTRL);
+		}
 		break;
 	}
 
@@ -887,6 +902,9 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
 	else
 		boarddata->support_vsel = true;
 
+	if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
+		boarddata->delay_line = 0;
+
 	return 0;
 }
 #else
diff --git a/include/linux/platform_data/mmc-esdhc-imx.h b/include/linux/platform_data/mmc-esdhc-imx.h
index a0f5a8f..75f70f6 100644
--- a/include/linux/platform_data/mmc-esdhc-imx.h
+++ b/include/linux/platform_data/mmc-esdhc-imx.h
@@ -45,5 +45,6 @@ struct esdhc_platform_data {
 	int max_bus_width;
 	unsigned int f_max;
 	bool support_vsel;
+	unsigned int delay_line;
 };
 #endif /* __ASM_ARCH_IMX_ESDHC_H */
-- 
1.7.2.rc3

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

* [PATCH 08/10] mmc: sdhci-esdhc-imx: enable SDR50 tuning for imx6q/dl
  2013-10-09 11:20 ` Dong Aisheng
@ 2013-10-09 11:20   ` Dong Aisheng
  -1 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang, b29396,
	john.tobias.ph

The imx6q/dl supports SDR50 tunning, enable it for a better timing
on SDR50 mode.

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

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 91b2d85..8879974 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -244,7 +244,7 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
 		if (is_imx6q_usdhc(imx_data))
 			/* imx6q/dl does not have cap_1 register, fake one */
 			val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
-					| SDHCI_SUPPORT_SDR50;
+				| SDHCI_SUPPORT_SDR50 | SDHCI_USE_SDR50_TUNING;
 		else if (is_imx6sl_usdhc(imx_data))
 			val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF;
 	}
-- 
1.7.2.rc3



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

* [PATCH 08/10] mmc: sdhci-esdhc-imx: enable SDR50 tuning for imx6q/dl
@ 2013-10-09 11:20   ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

The imx6q/dl supports SDR50 tunning, enable it for a better timing
on SDR50 mode.

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

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 91b2d85..8879974 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -244,7 +244,7 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
 		if (is_imx6q_usdhc(imx_data))
 			/* imx6q/dl does not have cap_1 register, fake one */
 			val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
-					| SDHCI_SUPPORT_SDR50;
+				| SDHCI_SUPPORT_SDR50 | SDHCI_USE_SDR50_TUNING;
 		else if (is_imx6sl_usdhc(imx_data))
 			val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF;
 	}
-- 
1.7.2.rc3

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

* [PATCH 09/10] mmc: sdhci-esdhc-imx: add preset value quirk for mx6
  2013-10-09 11:20 ` Dong Aisheng
@ 2013-10-09 11:20   ` Dong Aisheng
  -1 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang, b29396,
	john.tobias.ph

The i.MX6 does not support preset value feature.

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

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 8879974..5cd70e0 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -995,8 +995,10 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 	 * The imx6q ROM code will change the default watermark level setting
 	 * to something insane.  Change it back here.
 	 */
-	if (is_imx6_usdhc(imx_data))
+	if (is_imx6_usdhc(imx_data)) {
 		writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL);
+		host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
+	}
 
 	if (is_imx6q_usdhc(imx_data))
 		sdhci_esdhc_ops.platform_execute_tuning =
-- 
1.7.2.rc3



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

* [PATCH 09/10] mmc: sdhci-esdhc-imx: add preset value quirk for mx6
@ 2013-10-09 11:20   ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

The i.MX6 does not support preset value feature.

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

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 8879974..5cd70e0 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -995,8 +995,10 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 	 * The imx6q ROM code will change the default watermark level setting
 	 * to something insane.  Change it back here.
 	 */
-	if (is_imx6_usdhc(imx_data))
+	if (is_imx6_usdhc(imx_data)) {
 		writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL);
+		host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
+	}
 
 	if (is_imx6q_usdhc(imx_data))
 		sdhci_esdhc_ops.platform_execute_tuning =
-- 
1.7.2.rc3

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

* [PATCH 10/10] mmc: sdhci: remove unneeded call when have preset value quirk
  2013-10-09 11:20 ` Dong Aisheng
@ 2013-10-09 11:20   ` Dong Aisheng
  -1 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-mmc
  Cc: linux-arm-kernel, cjb, shawn.guo, anton, s.hauer, w.sang, b29396,
	john.tobias.ph

Remove unneeded call of call sdhci_enable_preset_value when having
SDHCI_QUIRK2_PRESET_VALUE_BROKEN.

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

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index cbde17d..a21a710 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1435,7 +1435,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 	}
 
 	if (host->version >= SDHCI_SPEC_300 &&
-		(ios->power_mode == MMC_POWER_UP))
+		(ios->power_mode == MMC_POWER_UP) &&
+		!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
 		sdhci_enable_preset_value(host, false);
 
 	sdhci_set_clock(host, ios->clock);
-- 
1.7.2.rc3



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

* [PATCH 10/10] mmc: sdhci: remove unneeded call when have preset value quirk
@ 2013-10-09 11:20   ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-09 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

Remove unneeded call of call sdhci_enable_preset_value when having
SDHCI_QUIRK2_PRESET_VALUE_BROKEN.

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

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index cbde17d..a21a710 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1435,7 +1435,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 	}
 
 	if (host->version >= SDHCI_SPEC_300 &&
-		(ios->power_mode == MMC_POWER_UP))
+		(ios->power_mode == MMC_POWER_UP) &&
+		!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
 		sdhci_enable_preset_value(host, false);
 
 	sdhci_set_clock(host, ios->clock);
-- 
1.7.2.rc3

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

* Re: [PATCH 01/10] ARM: dts: imx6sl: add pinctrl uhs states for usdhc
  2013-10-09 11:20   ` Dong Aisheng
@ 2013-10-12  8:49     ` Shawn Guo
  -1 siblings, 0 replies; 32+ messages in thread
From: Shawn Guo @ 2013-10-12  8:49 UTC (permalink / raw)
  To: Dong Aisheng
  Cc: linux-mmc, linux-arm-kernel, cjb, anton, s.hauer, w.sang, john.tobias.ph

On Wed, Oct 09, 2013 at 07:20:07PM +0800, Dong Aisheng wrote:
> This is needed for SD3.0 cards working on UHS mode.
> 
> Signed-off-by: Dong Aisheng <b29396@freescale.com>

Applied this one.


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

* [PATCH 01/10] ARM: dts: imx6sl: add pinctrl uhs states for usdhc
@ 2013-10-12  8:49     ` Shawn Guo
  0 siblings, 0 replies; 32+ messages in thread
From: Shawn Guo @ 2013-10-12  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Oct 09, 2013 at 07:20:07PM +0800, Dong Aisheng wrote:
> This is needed for SD3.0 cards working on UHS mode.
> 
> Signed-off-by: Dong Aisheng <b29396@freescale.com>

Applied this one.

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

* Re: [PATCH 02/10] mmc: sdhci-esdhc-imx: add std tuning support for mx6sl
  2013-10-09 11:20   ` Dong Aisheng
@ 2013-10-15  7:18     ` Shawn Guo
  -1 siblings, 0 replies; 32+ messages in thread
From: Shawn Guo @ 2013-10-15  7:18 UTC (permalink / raw)
  To: Dong Aisheng
  Cc: linux-mmc, linux-arm-kernel, cjb, anton, s.hauer, w.sang, john.tobias.ph

Wolfram's email address is changed to Wolfram Sang <wsa@the-dreams.de>.

On Wed, Oct 09, 2013 at 07:20:08PM +0800, Dong Aisheng wrote:
> The mx6sl supports standard sdhci tuning, then esdhc_executing_tuning
> is only needed for mx6q/dl. We introduce is_imx6_usdhc() and
> is_imx6sl_usdhc() to handle the difference.

This is clumsy and less future proof.  I sent a series with you on copy
to use a new approach for defining features and quirks among different
esdhc variants. 

> The standard tuning is enabled by setting ESDHC_TUNE_CTRL_STD_TUNING_EN bit
> in new register ESDHC_TUNE_CTRL and operates with new tuning bits
> defined in SDHCI_ACMD12_ERR register.
> 
> Note: mx6sl can also work on the old manually tuning mode as mx6q/dl if
> not enable standard tuning mode.
> 
> Signed-off-by: Dong Aisheng <b29396@freescale.com>
> ---
>  drivers/mmc/host/sdhci-esdhc-imx.c |  108 +++++++++++++++++++++++++++---------
>  1 files changed, 82 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index b9899e9..2cce244 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -51,6 +51,11 @@
>  #define  ESDHC_TUNE_CTRL_MIN		0
>  #define  ESDHC_TUNE_CTRL_MAX		((1 << 7) - 1)
>  
> +#define ESDHC_TUNING_CTRL		0xCC

Please follow the convention in this file to use lowercase for hex
value.

> +#define ESDHC_STD_TUNING_EN		(1 << 24)
> +/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
> +#define ESDHC_TUNING_START_TAP		0x1
> +
>  #define ESDHC_TUNING_BLOCK_PATTERN_LEN	64
>  
>  /* pinctrl state */
> @@ -91,6 +96,7 @@ enum imx_esdhc_type {
>  	IMX51_ESDHC,
>  	IMX53_ESDHC,
>  	IMX6Q_USDHC,
> +	IMX6SL_USDHC,
>  };
>  
>  struct pltfm_imx_data {
> @@ -130,6 +136,9 @@ static struct platform_device_id imx_esdhc_devtype[] = {
>  		.name = "sdhci-usdhc-imx6q",
>  		.driver_data = IMX6Q_USDHC,
>  	}, {
> +		.name = "sdhci-usdhc-imx6sl",
> +		.driver_data = IMX6SL_USDHC,
> +	}, {
>  		/* sentinel */
>  	}
>  };
> @@ -141,6 +150,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
>  	{ .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
>  	{ .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
>  	{ .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], },
> +	{ .compatible = "fsl,imx6sl-usdhc", .data = &imx_esdhc_devtype[IMX6SL_USDHC], },

There are some attempts to get of_match_device() return the best match.

http://thread.gmane.org/gmane.linux.kernel/1572529

But before the attempts succeed, we're suggested to sort the
of_device_id table in driver from the specific to the generic.  That
said, if you put "fsl,imx6sl-usdhc" before "fsl,imx6q-usdhc", we do not
need the changes in patch #3.

Shawn

>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
> @@ -170,6 +180,17 @@ static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
>  	return data->devtype == IMX6Q_USDHC;
>  }
>  
> +static inline int is_imx6sl_usdhc(struct pltfm_imx_data *data)
> +{
> +	return data->devtype == IMX6SL_USDHC;
> +}
> +
> +static inline int is_imx6_usdhc(struct pltfm_imx_data *data)
> +{
> +	return (data->devtype == IMX6Q_USDHC) ||
> +		(data->devtype == IMX6SL_USDHC);
> +}
> +
>  static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
>  {
>  	void __iomem *base = host->ioaddr + (reg & ~0x3);
> @@ -208,11 +229,16 @@ 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_CAPABILITIES_1)) {
> +		if (is_imx6q_usdhc(imx_data))
> +			/* imx6q/dl does not have cap_1 register, fake one */
> +			val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
> +					| SDHCI_SUPPORT_SDR50;
> +		else if (is_imx6sl_usdhc(imx_data))
> +			val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF;
> +	}
>  
> -	if (unlikely(reg == SDHCI_MAX_CURRENT) && is_imx6q_usdhc(imx_data)) {
> +	if (unlikely(reg == SDHCI_MAX_CURRENT) && is_imx6_usdhc(imx_data)) {
>  		val = 0;
>  		val |= 0xFF << SDHCI_MAX_CURRENT_330_SHIFT;
>  		val |= 0xFF << SDHCI_MAX_CURRENT_300_SHIFT;
> @@ -316,13 +342,16 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
>  		if (val & ESDHC_VENDOR_SPEC_VSELECT)
>  			ret |= SDHCI_CTRL_VDD_180;
>  
> -		if (is_imx6q_usdhc(imx_data)) {
> +		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;
> -		}
> +		else if (is_imx6sl_usdhc(imx_data))
> +			/* the std tuning bits is in ACMD12_ERR for imx6sl */
> +			val = readl(host->ioaddr + SDHCI_ACMD12_ERR);
> +
> +		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;
> @@ -356,12 +385,37 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
>  			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);
> +		if (is_imx6q_usdhc(imx_data)) {
> +			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);
> +		} else if (is_imx6sl_usdhc(imx_data)) {
> +			u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
> +			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
> +			new_val = readl(host->ioaddr + ESDHC_TUNING_CTRL);
> +			if (val & SDHCI_CTRL_EXEC_TUNING) {
> +				new_val |= ESDHC_STD_TUNING_EN |
> +						ESDHC_TUNING_START_TAP;
> +				v |= ESDHC_MIX_CTRL_EXE_TUNE;
> +				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
> +			} else {
> +				new_val &= ~ESDHC_STD_TUNING_EN;
> +				v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
> +				m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
> +			}
> +
> +			if (val & SDHCI_CTRL_TUNED_CLK)
> +				v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
> +			else
> +				v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
> +
> +			writel(new_val, host->ioaddr + ESDHC_TUNING_CTRL);
> +			writel(v, host->ioaddr + SDHCI_ACMD12_ERR);
> +			writel(m, host->ioaddr + ESDHC_MIX_CTRL);
> +		}
>  		return;
>  	case SDHCI_TRANSFER_MODE:
>  		if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
> @@ -374,7 +428,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
>  			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
>  		}
>  
> -		if (is_imx6q_usdhc(imx_data)) {
> +		if (is_imx6_usdhc(imx_data)) {
>  			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
>  			/* Swap AC23 bit */
>  			if (val & SDHCI_TRNS_AUTO_CMD23) {
> @@ -399,7 +453,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
>  		    (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
>  			imx_data->multiblock_status = MULTIBLK_IN_PROCESS;
>  
> -		if (is_imx6q_usdhc(imx_data))
> +		if (is_imx6_usdhc(imx_data))
>  			writel(val << 16,
>  			       host->ioaddr + SDHCI_TRANSFER_MODE);
>  		else
> @@ -465,7 +519,7 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
>  		 * The reset on usdhc fails to clear MIX_CTRL register.
>  		 * Do it manually here.
>  		 */
> -		if (is_imx6q_usdhc(imx_data))
> +		if (is_imx6_usdhc(imx_data))
>  			writel(0, host->ioaddr + ESDHC_MIX_CTRL);
>  	}
>  }
> @@ -502,7 +556,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
>  	u32 temp, val;
>  
>  	if (clock == 0) {
> -		if (is_imx6q_usdhc(imx_data)) {
> +		if (is_imx6_usdhc(imx_data)) {
>  			val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
>  			writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
>  					host->ioaddr + ESDHC_VENDOR_SPEC);
> @@ -510,7 +564,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
>  		goto out;
>  	}
>  
> -	if (is_imx6q_usdhc(imx_data))
> +	if (is_imx6_usdhc(imx_data))
>  		pre_div = 1;
>  
>  	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
> @@ -537,7 +591,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
>  		| (pre_div << ESDHC_PREDIV_SHIFT));
>  	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
>  
> -	if (is_imx6q_usdhc(imx_data)) {
> +	if (is_imx6_usdhc(imx_data)) {
>  		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
>  		writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
>  		host->ioaddr + ESDHC_VENDOR_SPEC);
> @@ -760,7 +814,7 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
>  	return esdhc_change_pinstate(host, uhs);
>  }
>  
> -static const struct sdhci_ops sdhci_esdhc_ops = {
> +static struct sdhci_ops sdhci_esdhc_ops = {
>  	.read_l = esdhc_readl_le,
>  	.read_w = esdhc_readw_le,
>  	.write_l = esdhc_writel_le,
> @@ -772,7 +826,6 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
>  	.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,
>  };
>  
>  static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
> @@ -909,9 +962,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
>  	 * The imx6q ROM code will change the default watermark level setting
>  	 * to something insane.  Change it back here.
>  	 */
> -	if (is_imx6q_usdhc(imx_data))
> +	if (is_imx6_usdhc(imx_data))
>  		writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL);
>  
> +	if (is_imx6q_usdhc(imx_data))
> +		sdhci_esdhc_ops.platform_execute_tuning =
> +					esdhc_executing_tuning;
>  	boarddata = &imx_data->boarddata;
>  	if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
>  		if (!host->mmc->parent->platform_data) {
> @@ -972,7 +1028,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
>  	}
>  
>  	/* sdr50 and sdr104 needs work on 1.8v signal voltage */
> -	if ((boarddata->support_vsel) && is_imx6q_usdhc(imx_data)) {
> +	if ((boarddata->support_vsel) && is_imx6_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,
> -- 
> 1.7.2.rc3
> 
> 


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

* [PATCH 02/10] mmc: sdhci-esdhc-imx: add std tuning support for mx6sl
@ 2013-10-15  7:18     ` Shawn Guo
  0 siblings, 0 replies; 32+ messages in thread
From: Shawn Guo @ 2013-10-15  7:18 UTC (permalink / raw)
  To: linux-arm-kernel

Wolfram's email address is changed to Wolfram Sang <wsa@the-dreams.de>.

On Wed, Oct 09, 2013 at 07:20:08PM +0800, Dong Aisheng wrote:
> The mx6sl supports standard sdhci tuning, then esdhc_executing_tuning
> is only needed for mx6q/dl. We introduce is_imx6_usdhc() and
> is_imx6sl_usdhc() to handle the difference.

This is clumsy and less future proof.  I sent a series with you on copy
to use a new approach for defining features and quirks among different
esdhc variants. 

> The standard tuning is enabled by setting ESDHC_TUNE_CTRL_STD_TUNING_EN bit
> in new register ESDHC_TUNE_CTRL and operates with new tuning bits
> defined in SDHCI_ACMD12_ERR register.
> 
> Note: mx6sl can also work on the old manually tuning mode as mx6q/dl if
> not enable standard tuning mode.
> 
> Signed-off-by: Dong Aisheng <b29396@freescale.com>
> ---
>  drivers/mmc/host/sdhci-esdhc-imx.c |  108 +++++++++++++++++++++++++++---------
>  1 files changed, 82 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index b9899e9..2cce244 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -51,6 +51,11 @@
>  #define  ESDHC_TUNE_CTRL_MIN		0
>  #define  ESDHC_TUNE_CTRL_MAX		((1 << 7) - 1)
>  
> +#define ESDHC_TUNING_CTRL		0xCC

Please follow the convention in this file to use lowercase for hex
value.

> +#define ESDHC_STD_TUNING_EN		(1 << 24)
> +/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
> +#define ESDHC_TUNING_START_TAP		0x1
> +
>  #define ESDHC_TUNING_BLOCK_PATTERN_LEN	64
>  
>  /* pinctrl state */
> @@ -91,6 +96,7 @@ enum imx_esdhc_type {
>  	IMX51_ESDHC,
>  	IMX53_ESDHC,
>  	IMX6Q_USDHC,
> +	IMX6SL_USDHC,
>  };
>  
>  struct pltfm_imx_data {
> @@ -130,6 +136,9 @@ static struct platform_device_id imx_esdhc_devtype[] = {
>  		.name = "sdhci-usdhc-imx6q",
>  		.driver_data = IMX6Q_USDHC,
>  	}, {
> +		.name = "sdhci-usdhc-imx6sl",
> +		.driver_data = IMX6SL_USDHC,
> +	}, {
>  		/* sentinel */
>  	}
>  };
> @@ -141,6 +150,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
>  	{ .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
>  	{ .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
>  	{ .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], },
> +	{ .compatible = "fsl,imx6sl-usdhc", .data = &imx_esdhc_devtype[IMX6SL_USDHC], },

There are some attempts to get of_match_device() return the best match.

http://thread.gmane.org/gmane.linux.kernel/1572529

But before the attempts succeed, we're suggested to sort the
of_device_id table in driver from the specific to the generic.  That
said, if you put "fsl,imx6sl-usdhc" before "fsl,imx6q-usdhc", we do not
need the changes in patch #3.

Shawn

>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
> @@ -170,6 +180,17 @@ static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
>  	return data->devtype == IMX6Q_USDHC;
>  }
>  
> +static inline int is_imx6sl_usdhc(struct pltfm_imx_data *data)
> +{
> +	return data->devtype == IMX6SL_USDHC;
> +}
> +
> +static inline int is_imx6_usdhc(struct pltfm_imx_data *data)
> +{
> +	return (data->devtype == IMX6Q_USDHC) ||
> +		(data->devtype == IMX6SL_USDHC);
> +}
> +
>  static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
>  {
>  	void __iomem *base = host->ioaddr + (reg & ~0x3);
> @@ -208,11 +229,16 @@ 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_CAPABILITIES_1)) {
> +		if (is_imx6q_usdhc(imx_data))
> +			/* imx6q/dl does not have cap_1 register, fake one */
> +			val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
> +					| SDHCI_SUPPORT_SDR50;
> +		else if (is_imx6sl_usdhc(imx_data))
> +			val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF;
> +	}
>  
> -	if (unlikely(reg == SDHCI_MAX_CURRENT) && is_imx6q_usdhc(imx_data)) {
> +	if (unlikely(reg == SDHCI_MAX_CURRENT) && is_imx6_usdhc(imx_data)) {
>  		val = 0;
>  		val |= 0xFF << SDHCI_MAX_CURRENT_330_SHIFT;
>  		val |= 0xFF << SDHCI_MAX_CURRENT_300_SHIFT;
> @@ -316,13 +342,16 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
>  		if (val & ESDHC_VENDOR_SPEC_VSELECT)
>  			ret |= SDHCI_CTRL_VDD_180;
>  
> -		if (is_imx6q_usdhc(imx_data)) {
> +		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;
> -		}
> +		else if (is_imx6sl_usdhc(imx_data))
> +			/* the std tuning bits is in ACMD12_ERR for imx6sl */
> +			val = readl(host->ioaddr + SDHCI_ACMD12_ERR);
> +
> +		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;
> @@ -356,12 +385,37 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
>  			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);
> +		if (is_imx6q_usdhc(imx_data)) {
> +			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);
> +		} else if (is_imx6sl_usdhc(imx_data)) {
> +			u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
> +			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
> +			new_val = readl(host->ioaddr + ESDHC_TUNING_CTRL);
> +			if (val & SDHCI_CTRL_EXEC_TUNING) {
> +				new_val |= ESDHC_STD_TUNING_EN |
> +						ESDHC_TUNING_START_TAP;
> +				v |= ESDHC_MIX_CTRL_EXE_TUNE;
> +				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
> +			} else {
> +				new_val &= ~ESDHC_STD_TUNING_EN;
> +				v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
> +				m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
> +			}
> +
> +			if (val & SDHCI_CTRL_TUNED_CLK)
> +				v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
> +			else
> +				v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
> +
> +			writel(new_val, host->ioaddr + ESDHC_TUNING_CTRL);
> +			writel(v, host->ioaddr + SDHCI_ACMD12_ERR);
> +			writel(m, host->ioaddr + ESDHC_MIX_CTRL);
> +		}
>  		return;
>  	case SDHCI_TRANSFER_MODE:
>  		if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
> @@ -374,7 +428,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
>  			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
>  		}
>  
> -		if (is_imx6q_usdhc(imx_data)) {
> +		if (is_imx6_usdhc(imx_data)) {
>  			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
>  			/* Swap AC23 bit */
>  			if (val & SDHCI_TRNS_AUTO_CMD23) {
> @@ -399,7 +453,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
>  		    (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
>  			imx_data->multiblock_status = MULTIBLK_IN_PROCESS;
>  
> -		if (is_imx6q_usdhc(imx_data))
> +		if (is_imx6_usdhc(imx_data))
>  			writel(val << 16,
>  			       host->ioaddr + SDHCI_TRANSFER_MODE);
>  		else
> @@ -465,7 +519,7 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
>  		 * The reset on usdhc fails to clear MIX_CTRL register.
>  		 * Do it manually here.
>  		 */
> -		if (is_imx6q_usdhc(imx_data))
> +		if (is_imx6_usdhc(imx_data))
>  			writel(0, host->ioaddr + ESDHC_MIX_CTRL);
>  	}
>  }
> @@ -502,7 +556,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
>  	u32 temp, val;
>  
>  	if (clock == 0) {
> -		if (is_imx6q_usdhc(imx_data)) {
> +		if (is_imx6_usdhc(imx_data)) {
>  			val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
>  			writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
>  					host->ioaddr + ESDHC_VENDOR_SPEC);
> @@ -510,7 +564,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
>  		goto out;
>  	}
>  
> -	if (is_imx6q_usdhc(imx_data))
> +	if (is_imx6_usdhc(imx_data))
>  		pre_div = 1;
>  
>  	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
> @@ -537,7 +591,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
>  		| (pre_div << ESDHC_PREDIV_SHIFT));
>  	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
>  
> -	if (is_imx6q_usdhc(imx_data)) {
> +	if (is_imx6_usdhc(imx_data)) {
>  		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
>  		writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
>  		host->ioaddr + ESDHC_VENDOR_SPEC);
> @@ -760,7 +814,7 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
>  	return esdhc_change_pinstate(host, uhs);
>  }
>  
> -static const struct sdhci_ops sdhci_esdhc_ops = {
> +static struct sdhci_ops sdhci_esdhc_ops = {
>  	.read_l = esdhc_readl_le,
>  	.read_w = esdhc_readw_le,
>  	.write_l = esdhc_writel_le,
> @@ -772,7 +826,6 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
>  	.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,
>  };
>  
>  static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
> @@ -909,9 +962,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
>  	 * The imx6q ROM code will change the default watermark level setting
>  	 * to something insane.  Change it back here.
>  	 */
> -	if (is_imx6q_usdhc(imx_data))
> +	if (is_imx6_usdhc(imx_data))
>  		writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL);
>  
> +	if (is_imx6q_usdhc(imx_data))
> +		sdhci_esdhc_ops.platform_execute_tuning =
> +					esdhc_executing_tuning;
>  	boarddata = &imx_data->boarddata;
>  	if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
>  		if (!host->mmc->parent->platform_data) {
> @@ -972,7 +1028,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
>  	}
>  
>  	/* sdr50 and sdr104 needs work on 1.8v signal voltage */
> -	if ((boarddata->support_vsel) && is_imx6q_usdhc(imx_data)) {
> +	if ((boarddata->support_vsel) && is_imx6_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,
> -- 
> 1.7.2.rc3
> 
> 

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

* Re: [PATCH 07/10] mmc: sdhci-esdhc-imx: add delay line setting support
  2013-10-09 11:20   ` Dong Aisheng
@ 2013-10-15  7:37     ` Shawn Guo
  -1 siblings, 0 replies; 32+ messages in thread
From: Shawn Guo @ 2013-10-15  7:37 UTC (permalink / raw)
  To: Dong Aisheng
  Cc: linux-mmc, linux-arm-kernel, cjb, anton, s.hauer, w.sang, john.tobias.ph

On Wed, Oct 09, 2013 at 07:20:13PM +0800, Dong Aisheng wrote:
> The DLL(Delay Line) is newly added to assist in sampling read data.
> The DLL provides the ability to programmatically select a quantized
> delay (in fractions of the clock period) regardless of on-chip variations
> such as process, voltage and temperature (PVT).
> 
> This patch adds a user interface to set slave delay line via device tree.
> It's usually used in high speed mode like mmc DDR mode when the signal
> quality is not good caused by board design, e.g. the signal path is too long.
> User can manual set delay line to find a suitable data sampling window
> for card to work properly.
> 
> Signed-off-by: Dong Aisheng <b29396@freescale.com>
> ---
>  .../devicetree/bindings/mmc/fsl-imx-esdhc.txt      |    1 +
>  drivers/mmc/host/sdhci-esdhc-imx.c                 |   18 ++++++++++++++++++
>  include/linux/platform_data/mmc-esdhc-imx.h        |    1 +
>  3 files changed, 20 insertions(+), 0 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
> index 1dd6225..ebd3ff5 100644
> --- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
> +++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
> @@ -12,6 +12,7 @@ Required properties:
>  Optional properties:
>  - fsl,cd-controller : Indicate to use controller internal card detection
>  - fsl,wp-controller : Indicate to use controller internal write protection
> +- fsl,delay-line : Specify delay line value of manual override for slave delay.

It needs more documentation and should refer to the register bits in RM.
Otherwise, I hardly think people will understand what it is.

>  
>  Examples:
>  
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index b6ae5c1..91b2d85 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -46,6 +46,11 @@
>  /* Bits 3 and 6 are not SDHCI standard definitions */
>  #define  ESDHC_MIX_CTRL_SDHCI_MASK	0xb7
>  
> +/* dll control register */
> +#define ESDHC_DLL_CTRL			0x60
> +#define ESDHC_DLL_OVERRIDE_VAL_SHIFT	9
> +#define ESDHC_DLL_OVERRIDE_EN_SHIFT	8
> +
>  /* tune control register */
>  #define ESDHC_TUNE_CTRL_STATUS		0x68
>  #define  ESDHC_TUNE_CTRL_STEP		1
> @@ -803,6 +808,7 @@ 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;
> +	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
>  
>  	switch (uhs) {
>  	case MMC_TIMING_UHS_SDR12:
> @@ -823,6 +829,15 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
>  				ESDHC_MIX_CTRL_DDREN,
>  				host->ioaddr + ESDHC_MIX_CTRL);
>  		imx_data->is_ddr = 1;
> +		if (boarddata->delay_line) {
> +			u32 v;
> +			v = boarddata->delay_line <<
> +				ESDHC_DLL_OVERRIDE_VAL_SHIFT |
> +				(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
> +			if (is_imx53_esdhc(imx_data))
> +				v <<= 1;

Is the patch (series) tested on imx53?  Or is it just a note that imx53
has different bit position? 

> +			writel(v, host->ioaddr + ESDHC_DLL_CTRL);

Is it safe to always write other bits as zero?

Shawn

> +		}
>  		break;
>  	}
>  
> @@ -887,6 +902,9 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
>  	else
>  		boarddata->support_vsel = true;
>  
> +	if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
> +		boarddata->delay_line = 0;
> +
>  	return 0;
>  }
>  #else
> diff --git a/include/linux/platform_data/mmc-esdhc-imx.h b/include/linux/platform_data/mmc-esdhc-imx.h
> index a0f5a8f..75f70f6 100644
> --- a/include/linux/platform_data/mmc-esdhc-imx.h
> +++ b/include/linux/platform_data/mmc-esdhc-imx.h
> @@ -45,5 +45,6 @@ struct esdhc_platform_data {
>  	int max_bus_width;
>  	unsigned int f_max;
>  	bool support_vsel;
> +	unsigned int delay_line;
>  };
>  #endif /* __ASM_ARCH_IMX_ESDHC_H */
> -- 
> 1.7.2.rc3
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* [PATCH 07/10] mmc: sdhci-esdhc-imx: add delay line setting support
@ 2013-10-15  7:37     ` Shawn Guo
  0 siblings, 0 replies; 32+ messages in thread
From: Shawn Guo @ 2013-10-15  7:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Oct 09, 2013 at 07:20:13PM +0800, Dong Aisheng wrote:
> The DLL(Delay Line) is newly added to assist in sampling read data.
> The DLL provides the ability to programmatically select a quantized
> delay (in fractions of the clock period) regardless of on-chip variations
> such as process, voltage and temperature (PVT).
> 
> This patch adds a user interface to set slave delay line via device tree.
> It's usually used in high speed mode like mmc DDR mode when the signal
> quality is not good caused by board design, e.g. the signal path is too long.
> User can manual set delay line to find a suitable data sampling window
> for card to work properly.
> 
> Signed-off-by: Dong Aisheng <b29396@freescale.com>
> ---
>  .../devicetree/bindings/mmc/fsl-imx-esdhc.txt      |    1 +
>  drivers/mmc/host/sdhci-esdhc-imx.c                 |   18 ++++++++++++++++++
>  include/linux/platform_data/mmc-esdhc-imx.h        |    1 +
>  3 files changed, 20 insertions(+), 0 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
> index 1dd6225..ebd3ff5 100644
> --- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
> +++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
> @@ -12,6 +12,7 @@ Required properties:
>  Optional properties:
>  - fsl,cd-controller : Indicate to use controller internal card detection
>  - fsl,wp-controller : Indicate to use controller internal write protection
> +- fsl,delay-line : Specify delay line value of manual override for slave delay.

It needs more documentation and should refer to the register bits in RM.
Otherwise, I hardly think people will understand what it is.

>  
>  Examples:
>  
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index b6ae5c1..91b2d85 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -46,6 +46,11 @@
>  /* Bits 3 and 6 are not SDHCI standard definitions */
>  #define  ESDHC_MIX_CTRL_SDHCI_MASK	0xb7
>  
> +/* dll control register */
> +#define ESDHC_DLL_CTRL			0x60
> +#define ESDHC_DLL_OVERRIDE_VAL_SHIFT	9
> +#define ESDHC_DLL_OVERRIDE_EN_SHIFT	8
> +
>  /* tune control register */
>  #define ESDHC_TUNE_CTRL_STATUS		0x68
>  #define  ESDHC_TUNE_CTRL_STEP		1
> @@ -803,6 +808,7 @@ 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;
> +	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
>  
>  	switch (uhs) {
>  	case MMC_TIMING_UHS_SDR12:
> @@ -823,6 +829,15 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
>  				ESDHC_MIX_CTRL_DDREN,
>  				host->ioaddr + ESDHC_MIX_CTRL);
>  		imx_data->is_ddr = 1;
> +		if (boarddata->delay_line) {
> +			u32 v;
> +			v = boarddata->delay_line <<
> +				ESDHC_DLL_OVERRIDE_VAL_SHIFT |
> +				(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
> +			if (is_imx53_esdhc(imx_data))
> +				v <<= 1;

Is the patch (series) tested on imx53?  Or is it just a note that imx53
has different bit position? 

> +			writel(v, host->ioaddr + ESDHC_DLL_CTRL);

Is it safe to always write other bits as zero?

Shawn

> +		}
>  		break;
>  	}
>  
> @@ -887,6 +902,9 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
>  	else
>  		boarddata->support_vsel = true;
>  
> +	if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
> +		boarddata->delay_line = 0;
> +
>  	return 0;
>  }
>  #else
> diff --git a/include/linux/platform_data/mmc-esdhc-imx.h b/include/linux/platform_data/mmc-esdhc-imx.h
> index a0f5a8f..75f70f6 100644
> --- a/include/linux/platform_data/mmc-esdhc-imx.h
> +++ b/include/linux/platform_data/mmc-esdhc-imx.h
> @@ -45,5 +45,6 @@ struct esdhc_platform_data {
>  	int max_bus_width;
>  	unsigned int f_max;
>  	bool support_vsel;
> +	unsigned int delay_line;
>  };
>  #endif /* __ASM_ARCH_IMX_ESDHC_H */
> -- 
> 1.7.2.rc3
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 02/10] mmc: sdhci-esdhc-imx: add std tuning support for mx6sl
  2013-10-15  7:18     ` Shawn Guo
@ 2013-10-15  7:41       ` Dong Aisheng
  -1 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-15  7:41 UTC (permalink / raw)
  To: Shawn Guo
  Cc: linux-mmc, linux-arm-kernel, cjb, anton, s.hauer, w.sang, john.tobias.ph

On Tue, Oct 15, 2013 at 03:18:28PM +0800, Shawn Guo wrote:
> Wolfram's email address is changed to Wolfram Sang <wsa@the-dreams.de>.
> 
Thanks for the forward.

> On Wed, Oct 09, 2013 at 07:20:08PM +0800, Dong Aisheng wrote:
> > The mx6sl supports standard sdhci tuning, then esdhc_executing_tuning
> > is only needed for mx6q/dl. We introduce is_imx6_usdhc() and
> > is_imx6sl_usdhc() to handle the difference.
> 
> This is clumsy and less future proof.  I sent a series with you on copy
> to use a new approach for defining features and quirks among different
> esdhc variants. 
> 

I just replied some concerns on the new approach in  your patch series.
Can't say it's suitable for usdhc to me.
Please check it.

> > The standard tuning is enabled by setting ESDHC_TUNE_CTRL_STD_TUNING_EN bit
> > in new register ESDHC_TUNE_CTRL and operates with new tuning bits
> > defined in SDHCI_ACMD12_ERR register.
> > 
> > Note: mx6sl can also work on the old manually tuning mode as mx6q/dl if
> > not enable standard tuning mode.
> > 
> > Signed-off-by: Dong Aisheng <b29396@freescale.com>
> > ---
> >  drivers/mmc/host/sdhci-esdhc-imx.c |  108 +++++++++++++++++++++++++++---------
> >  1 files changed, 82 insertions(+), 26 deletions(-)
> > 
> > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> > index b9899e9..2cce244 100644
> > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > @@ -51,6 +51,11 @@
> >  #define  ESDHC_TUNE_CTRL_MIN		0
> >  #define  ESDHC_TUNE_CTRL_MAX		((1 << 7) - 1)
> >  
> > +#define ESDHC_TUNING_CTRL		0xCC
> 
> Please follow the convention in this file to use lowercase for hex
> value.
> 

Got it.

> > +#define ESDHC_STD_TUNING_EN		(1 << 24)
> > +/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
> > +#define ESDHC_TUNING_START_TAP		0x1
> > +
> >  #define ESDHC_TUNING_BLOCK_PATTERN_LEN	64
> >  
> >  /* pinctrl state */
> > @@ -91,6 +96,7 @@ enum imx_esdhc_type {
> >  	IMX51_ESDHC,
> >  	IMX53_ESDHC,
> >  	IMX6Q_USDHC,
> > +	IMX6SL_USDHC,
> >  };
> >  
> >  struct pltfm_imx_data {
> > @@ -130,6 +136,9 @@ static struct platform_device_id imx_esdhc_devtype[] = {
> >  		.name = "sdhci-usdhc-imx6q",
> >  		.driver_data = IMX6Q_USDHC,
> >  	}, {
> > +		.name = "sdhci-usdhc-imx6sl",
> > +		.driver_data = IMX6SL_USDHC,
> > +	}, {
> >  		/* sentinel */
> >  	}
> >  };
> > @@ -141,6 +150,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
> >  	{ .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
> >  	{ .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
> >  	{ .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], },
> > +	{ .compatible = "fsl,imx6sl-usdhc", .data = &imx_esdhc_devtype[IMX6SL_USDHC], },
> 
> There are some attempts to get of_match_device() return the best match.
> 
> http://thread.gmane.org/gmane.linux.kernel/1572529
> 
> But before the attempts succeed, we're suggested to sort the
> of_device_id table in driver from the specific to the generic.  That
> said, if you put "fsl,imx6sl-usdhc" before "fsl,imx6q-usdhc", we do not
> need the changes in patch #3.
> 

Yes, i noticed that issue before and that how patch #3 comes out.
If it's ok, i'm glad to put it before fsl,imx6q-usdhc.

Regards
Dong Aisheng

> Shawn
> 
> >  	{ /* sentinel */ }
> >  };
> >  MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
> > @@ -170,6 +180,17 @@ static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
> >  	return data->devtype == IMX6Q_USDHC;
> >  }
> >  
> > +static inline int is_imx6sl_usdhc(struct pltfm_imx_data *data)
> > +{
> > +	return data->devtype == IMX6SL_USDHC;
> > +}
> > +
> > +static inline int is_imx6_usdhc(struct pltfm_imx_data *data)
> > +{
> > +	return (data->devtype == IMX6Q_USDHC) ||
> > +		(data->devtype == IMX6SL_USDHC);
> > +}
> > +
> >  static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
> >  {
> >  	void __iomem *base = host->ioaddr + (reg & ~0x3);
> > @@ -208,11 +229,16 @@ 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_CAPABILITIES_1)) {
> > +		if (is_imx6q_usdhc(imx_data))
> > +			/* imx6q/dl does not have cap_1 register, fake one */
> > +			val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
> > +					| SDHCI_SUPPORT_SDR50;
> > +		else if (is_imx6sl_usdhc(imx_data))
> > +			val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF;
> > +	}
> >  
> > -	if (unlikely(reg == SDHCI_MAX_CURRENT) && is_imx6q_usdhc(imx_data)) {
> > +	if (unlikely(reg == SDHCI_MAX_CURRENT) && is_imx6_usdhc(imx_data)) {
> >  		val = 0;
> >  		val |= 0xFF << SDHCI_MAX_CURRENT_330_SHIFT;
> >  		val |= 0xFF << SDHCI_MAX_CURRENT_300_SHIFT;
> > @@ -316,13 +342,16 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
> >  		if (val & ESDHC_VENDOR_SPEC_VSELECT)
> >  			ret |= SDHCI_CTRL_VDD_180;
> >  
> > -		if (is_imx6q_usdhc(imx_data)) {
> > +		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;
> > -		}
> > +		else if (is_imx6sl_usdhc(imx_data))
> > +			/* the std tuning bits is in ACMD12_ERR for imx6sl */
> > +			val = readl(host->ioaddr + SDHCI_ACMD12_ERR);
> > +
> > +		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;
> > @@ -356,12 +385,37 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
> >  			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);
> > +		if (is_imx6q_usdhc(imx_data)) {
> > +			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);
> > +		} else if (is_imx6sl_usdhc(imx_data)) {
> > +			u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
> > +			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
> > +			new_val = readl(host->ioaddr + ESDHC_TUNING_CTRL);
> > +			if (val & SDHCI_CTRL_EXEC_TUNING) {
> > +				new_val |= ESDHC_STD_TUNING_EN |
> > +						ESDHC_TUNING_START_TAP;
> > +				v |= ESDHC_MIX_CTRL_EXE_TUNE;
> > +				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
> > +			} else {
> > +				new_val &= ~ESDHC_STD_TUNING_EN;
> > +				v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
> > +				m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
> > +			}
> > +
> > +			if (val & SDHCI_CTRL_TUNED_CLK)
> > +				v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
> > +			else
> > +				v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
> > +
> > +			writel(new_val, host->ioaddr + ESDHC_TUNING_CTRL);
> > +			writel(v, host->ioaddr + SDHCI_ACMD12_ERR);
> > +			writel(m, host->ioaddr + ESDHC_MIX_CTRL);
> > +		}
> >  		return;
> >  	case SDHCI_TRANSFER_MODE:
> >  		if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
> > @@ -374,7 +428,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
> >  			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
> >  		}
> >  
> > -		if (is_imx6q_usdhc(imx_data)) {
> > +		if (is_imx6_usdhc(imx_data)) {
> >  			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
> >  			/* Swap AC23 bit */
> >  			if (val & SDHCI_TRNS_AUTO_CMD23) {
> > @@ -399,7 +453,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
> >  		    (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
> >  			imx_data->multiblock_status = MULTIBLK_IN_PROCESS;
> >  
> > -		if (is_imx6q_usdhc(imx_data))
> > +		if (is_imx6_usdhc(imx_data))
> >  			writel(val << 16,
> >  			       host->ioaddr + SDHCI_TRANSFER_MODE);
> >  		else
> > @@ -465,7 +519,7 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
> >  		 * The reset on usdhc fails to clear MIX_CTRL register.
> >  		 * Do it manually here.
> >  		 */
> > -		if (is_imx6q_usdhc(imx_data))
> > +		if (is_imx6_usdhc(imx_data))
> >  			writel(0, host->ioaddr + ESDHC_MIX_CTRL);
> >  	}
> >  }
> > @@ -502,7 +556,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
> >  	u32 temp, val;
> >  
> >  	if (clock == 0) {
> > -		if (is_imx6q_usdhc(imx_data)) {
> > +		if (is_imx6_usdhc(imx_data)) {
> >  			val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
> >  			writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
> >  					host->ioaddr + ESDHC_VENDOR_SPEC);
> > @@ -510,7 +564,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
> >  		goto out;
> >  	}
> >  
> > -	if (is_imx6q_usdhc(imx_data))
> > +	if (is_imx6_usdhc(imx_data))
> >  		pre_div = 1;
> >  
> >  	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
> > @@ -537,7 +591,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
> >  		| (pre_div << ESDHC_PREDIV_SHIFT));
> >  	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
> >  
> > -	if (is_imx6q_usdhc(imx_data)) {
> > +	if (is_imx6_usdhc(imx_data)) {
> >  		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
> >  		writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
> >  		host->ioaddr + ESDHC_VENDOR_SPEC);
> > @@ -760,7 +814,7 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
> >  	return esdhc_change_pinstate(host, uhs);
> >  }
> >  
> > -static const struct sdhci_ops sdhci_esdhc_ops = {
> > +static struct sdhci_ops sdhci_esdhc_ops = {
> >  	.read_l = esdhc_readl_le,
> >  	.read_w = esdhc_readw_le,
> >  	.write_l = esdhc_writel_le,
> > @@ -772,7 +826,6 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
> >  	.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,
> >  };
> >  
> >  static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
> > @@ -909,9 +962,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
> >  	 * The imx6q ROM code will change the default watermark level setting
> >  	 * to something insane.  Change it back here.
> >  	 */
> > -	if (is_imx6q_usdhc(imx_data))
> > +	if (is_imx6_usdhc(imx_data))
> >  		writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL);
> >  
> > +	if (is_imx6q_usdhc(imx_data))
> > +		sdhci_esdhc_ops.platform_execute_tuning =
> > +					esdhc_executing_tuning;
> >  	boarddata = &imx_data->boarddata;
> >  	if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
> >  		if (!host->mmc->parent->platform_data) {
> > @@ -972,7 +1028,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
> >  	}
> >  
> >  	/* sdr50 and sdr104 needs work on 1.8v signal voltage */
> > -	if ((boarddata->support_vsel) && is_imx6q_usdhc(imx_data)) {
> > +	if ((boarddata->support_vsel) && is_imx6_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,
> > -- 
> > 1.7.2.rc3
> > 
> > 


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

* [PATCH 02/10] mmc: sdhci-esdhc-imx: add std tuning support for mx6sl
@ 2013-10-15  7:41       ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-15  7:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Oct 15, 2013 at 03:18:28PM +0800, Shawn Guo wrote:
> Wolfram's email address is changed to Wolfram Sang <wsa@the-dreams.de>.
> 
Thanks for the forward.

> On Wed, Oct 09, 2013 at 07:20:08PM +0800, Dong Aisheng wrote:
> > The mx6sl supports standard sdhci tuning, then esdhc_executing_tuning
> > is only needed for mx6q/dl. We introduce is_imx6_usdhc() and
> > is_imx6sl_usdhc() to handle the difference.
> 
> This is clumsy and less future proof.  I sent a series with you on copy
> to use a new approach for defining features and quirks among different
> esdhc variants. 
> 

I just replied some concerns on the new approach in  your patch series.
Can't say it's suitable for usdhc to me.
Please check it.

> > The standard tuning is enabled by setting ESDHC_TUNE_CTRL_STD_TUNING_EN bit
> > in new register ESDHC_TUNE_CTRL and operates with new tuning bits
> > defined in SDHCI_ACMD12_ERR register.
> > 
> > Note: mx6sl can also work on the old manually tuning mode as mx6q/dl if
> > not enable standard tuning mode.
> > 
> > Signed-off-by: Dong Aisheng <b29396@freescale.com>
> > ---
> >  drivers/mmc/host/sdhci-esdhc-imx.c |  108 +++++++++++++++++++++++++++---------
> >  1 files changed, 82 insertions(+), 26 deletions(-)
> > 
> > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> > index b9899e9..2cce244 100644
> > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > @@ -51,6 +51,11 @@
> >  #define  ESDHC_TUNE_CTRL_MIN		0
> >  #define  ESDHC_TUNE_CTRL_MAX		((1 << 7) - 1)
> >  
> > +#define ESDHC_TUNING_CTRL		0xCC
> 
> Please follow the convention in this file to use lowercase for hex
> value.
> 

Got it.

> > +#define ESDHC_STD_TUNING_EN		(1 << 24)
> > +/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
> > +#define ESDHC_TUNING_START_TAP		0x1
> > +
> >  #define ESDHC_TUNING_BLOCK_PATTERN_LEN	64
> >  
> >  /* pinctrl state */
> > @@ -91,6 +96,7 @@ enum imx_esdhc_type {
> >  	IMX51_ESDHC,
> >  	IMX53_ESDHC,
> >  	IMX6Q_USDHC,
> > +	IMX6SL_USDHC,
> >  };
> >  
> >  struct pltfm_imx_data {
> > @@ -130,6 +136,9 @@ static struct platform_device_id imx_esdhc_devtype[] = {
> >  		.name = "sdhci-usdhc-imx6q",
> >  		.driver_data = IMX6Q_USDHC,
> >  	}, {
> > +		.name = "sdhci-usdhc-imx6sl",
> > +		.driver_data = IMX6SL_USDHC,
> > +	}, {
> >  		/* sentinel */
> >  	}
> >  };
> > @@ -141,6 +150,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
> >  	{ .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
> >  	{ .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
> >  	{ .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], },
> > +	{ .compatible = "fsl,imx6sl-usdhc", .data = &imx_esdhc_devtype[IMX6SL_USDHC], },
> 
> There are some attempts to get of_match_device() return the best match.
> 
> http://thread.gmane.org/gmane.linux.kernel/1572529
> 
> But before the attempts succeed, we're suggested to sort the
> of_device_id table in driver from the specific to the generic.  That
> said, if you put "fsl,imx6sl-usdhc" before "fsl,imx6q-usdhc", we do not
> need the changes in patch #3.
> 

Yes, i noticed that issue before and that how patch #3 comes out.
If it's ok, i'm glad to put it before fsl,imx6q-usdhc.

Regards
Dong Aisheng

> Shawn
> 
> >  	{ /* sentinel */ }
> >  };
> >  MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
> > @@ -170,6 +180,17 @@ static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
> >  	return data->devtype == IMX6Q_USDHC;
> >  }
> >  
> > +static inline int is_imx6sl_usdhc(struct pltfm_imx_data *data)
> > +{
> > +	return data->devtype == IMX6SL_USDHC;
> > +}
> > +
> > +static inline int is_imx6_usdhc(struct pltfm_imx_data *data)
> > +{
> > +	return (data->devtype == IMX6Q_USDHC) ||
> > +		(data->devtype == IMX6SL_USDHC);
> > +}
> > +
> >  static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
> >  {
> >  	void __iomem *base = host->ioaddr + (reg & ~0x3);
> > @@ -208,11 +229,16 @@ 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_CAPABILITIES_1)) {
> > +		if (is_imx6q_usdhc(imx_data))
> > +			/* imx6q/dl does not have cap_1 register, fake one */
> > +			val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
> > +					| SDHCI_SUPPORT_SDR50;
> > +		else if (is_imx6sl_usdhc(imx_data))
> > +			val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF;
> > +	}
> >  
> > -	if (unlikely(reg == SDHCI_MAX_CURRENT) && is_imx6q_usdhc(imx_data)) {
> > +	if (unlikely(reg == SDHCI_MAX_CURRENT) && is_imx6_usdhc(imx_data)) {
> >  		val = 0;
> >  		val |= 0xFF << SDHCI_MAX_CURRENT_330_SHIFT;
> >  		val |= 0xFF << SDHCI_MAX_CURRENT_300_SHIFT;
> > @@ -316,13 +342,16 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
> >  		if (val & ESDHC_VENDOR_SPEC_VSELECT)
> >  			ret |= SDHCI_CTRL_VDD_180;
> >  
> > -		if (is_imx6q_usdhc(imx_data)) {
> > +		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;
> > -		}
> > +		else if (is_imx6sl_usdhc(imx_data))
> > +			/* the std tuning bits is in ACMD12_ERR for imx6sl */
> > +			val = readl(host->ioaddr + SDHCI_ACMD12_ERR);
> > +
> > +		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;
> > @@ -356,12 +385,37 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
> >  			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);
> > +		if (is_imx6q_usdhc(imx_data)) {
> > +			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);
> > +		} else if (is_imx6sl_usdhc(imx_data)) {
> > +			u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
> > +			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
> > +			new_val = readl(host->ioaddr + ESDHC_TUNING_CTRL);
> > +			if (val & SDHCI_CTRL_EXEC_TUNING) {
> > +				new_val |= ESDHC_STD_TUNING_EN |
> > +						ESDHC_TUNING_START_TAP;
> > +				v |= ESDHC_MIX_CTRL_EXE_TUNE;
> > +				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
> > +			} else {
> > +				new_val &= ~ESDHC_STD_TUNING_EN;
> > +				v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
> > +				m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
> > +			}
> > +
> > +			if (val & SDHCI_CTRL_TUNED_CLK)
> > +				v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
> > +			else
> > +				v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
> > +
> > +			writel(new_val, host->ioaddr + ESDHC_TUNING_CTRL);
> > +			writel(v, host->ioaddr + SDHCI_ACMD12_ERR);
> > +			writel(m, host->ioaddr + ESDHC_MIX_CTRL);
> > +		}
> >  		return;
> >  	case SDHCI_TRANSFER_MODE:
> >  		if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
> > @@ -374,7 +428,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
> >  			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
> >  		}
> >  
> > -		if (is_imx6q_usdhc(imx_data)) {
> > +		if (is_imx6_usdhc(imx_data)) {
> >  			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
> >  			/* Swap AC23 bit */
> >  			if (val & SDHCI_TRNS_AUTO_CMD23) {
> > @@ -399,7 +453,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
> >  		    (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
> >  			imx_data->multiblock_status = MULTIBLK_IN_PROCESS;
> >  
> > -		if (is_imx6q_usdhc(imx_data))
> > +		if (is_imx6_usdhc(imx_data))
> >  			writel(val << 16,
> >  			       host->ioaddr + SDHCI_TRANSFER_MODE);
> >  		else
> > @@ -465,7 +519,7 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
> >  		 * The reset on usdhc fails to clear MIX_CTRL register.
> >  		 * Do it manually here.
> >  		 */
> > -		if (is_imx6q_usdhc(imx_data))
> > +		if (is_imx6_usdhc(imx_data))
> >  			writel(0, host->ioaddr + ESDHC_MIX_CTRL);
> >  	}
> >  }
> > @@ -502,7 +556,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
> >  	u32 temp, val;
> >  
> >  	if (clock == 0) {
> > -		if (is_imx6q_usdhc(imx_data)) {
> > +		if (is_imx6_usdhc(imx_data)) {
> >  			val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
> >  			writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
> >  					host->ioaddr + ESDHC_VENDOR_SPEC);
> > @@ -510,7 +564,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
> >  		goto out;
> >  	}
> >  
> > -	if (is_imx6q_usdhc(imx_data))
> > +	if (is_imx6_usdhc(imx_data))
> >  		pre_div = 1;
> >  
> >  	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
> > @@ -537,7 +591,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
> >  		| (pre_div << ESDHC_PREDIV_SHIFT));
> >  	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
> >  
> > -	if (is_imx6q_usdhc(imx_data)) {
> > +	if (is_imx6_usdhc(imx_data)) {
> >  		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
> >  		writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
> >  		host->ioaddr + ESDHC_VENDOR_SPEC);
> > @@ -760,7 +814,7 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
> >  	return esdhc_change_pinstate(host, uhs);
> >  }
> >  
> > -static const struct sdhci_ops sdhci_esdhc_ops = {
> > +static struct sdhci_ops sdhci_esdhc_ops = {
> >  	.read_l = esdhc_readl_le,
> >  	.read_w = esdhc_readw_le,
> >  	.write_l = esdhc_writel_le,
> > @@ -772,7 +826,6 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
> >  	.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,
> >  };
> >  
> >  static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
> > @@ -909,9 +962,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
> >  	 * The imx6q ROM code will change the default watermark level setting
> >  	 * to something insane.  Change it back here.
> >  	 */
> > -	if (is_imx6q_usdhc(imx_data))
> > +	if (is_imx6_usdhc(imx_data))
> >  		writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL);
> >  
> > +	if (is_imx6q_usdhc(imx_data))
> > +		sdhci_esdhc_ops.platform_execute_tuning =
> > +					esdhc_executing_tuning;
> >  	boarddata = &imx_data->boarddata;
> >  	if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
> >  		if (!host->mmc->parent->platform_data) {
> > @@ -972,7 +1028,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
> >  	}
> >  
> >  	/* sdr50 and sdr104 needs work on 1.8v signal voltage */
> > -	if ((boarddata->support_vsel) && is_imx6q_usdhc(imx_data)) {
> > +	if ((boarddata->support_vsel) && is_imx6_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,
> > -- 
> > 1.7.2.rc3
> > 
> > 

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

* Re: [PATCH 07/10] mmc: sdhci-esdhc-imx: add delay line setting support
  2013-10-15  7:37     ` Shawn Guo
@ 2013-10-15  7:55       ` Dong Aisheng
  -1 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-15  7:55 UTC (permalink / raw)
  To: Shawn Guo
  Cc: linux-mmc, linux-arm-kernel, cjb, anton, s.hauer, w.sang, john.tobias.ph

On Tue, Oct 15, 2013 at 03:37:06PM +0800, Shawn Guo wrote:
> On Wed, Oct 09, 2013 at 07:20:13PM +0800, Dong Aisheng wrote:
> > The DLL(Delay Line) is newly added to assist in sampling read data.
> > The DLL provides the ability to programmatically select a quantized
> > delay (in fractions of the clock period) regardless of on-chip variations
> > such as process, voltage and temperature (PVT).
> > 
> > This patch adds a user interface to set slave delay line via device tree.
> > It's usually used in high speed mode like mmc DDR mode when the signal
> > quality is not good caused by board design, e.g. the signal path is too long.
> > User can manual set delay line to find a suitable data sampling window
> > for card to work properly.
> > 
> > Signed-off-by: Dong Aisheng <b29396@freescale.com>
> > ---
> >  .../devicetree/bindings/mmc/fsl-imx-esdhc.txt      |    1 +
> >  drivers/mmc/host/sdhci-esdhc-imx.c                 |   18 ++++++++++++++++++
> >  include/linux/platform_data/mmc-esdhc-imx.h        |    1 +
> >  3 files changed, 20 insertions(+), 0 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
> > index 1dd6225..ebd3ff5 100644
> > --- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
> > +++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
> > @@ -12,6 +12,7 @@ Required properties:
> >  Optional properties:
> >  - fsl,cd-controller : Indicate to use controller internal card detection
> >  - fsl,wp-controller : Indicate to use controller internal write protection
> > +- fsl,delay-line : Specify delay line value of manual override for slave delay.
> 
> It needs more documentation and should refer to the register bits in RM.
> Otherwise, I hardly think people will understand what it is.
> 

Ok, i could improve it a bit.
But user may still need refer to spec to know the details.

> >  
> >  Examples:
> >  
> > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> > index b6ae5c1..91b2d85 100644
> > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > @@ -46,6 +46,11 @@
> >  /* Bits 3 and 6 are not SDHCI standard definitions */
> >  #define  ESDHC_MIX_CTRL_SDHCI_MASK	0xb7
> >  
> > +/* dll control register */
> > +#define ESDHC_DLL_CTRL			0x60
> > +#define ESDHC_DLL_OVERRIDE_VAL_SHIFT	9
> > +#define ESDHC_DLL_OVERRIDE_EN_SHIFT	8
> > +
> >  /* tune control register */
> >  #define ESDHC_TUNE_CTRL_STATUS		0x68
> >  #define  ESDHC_TUNE_CTRL_STEP		1
> > @@ -803,6 +808,7 @@ 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;
> > +	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
> >  
> >  	switch (uhs) {
> >  	case MMC_TIMING_UHS_SDR12:
> > @@ -823,6 +829,15 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
> >  				ESDHC_MIX_CTRL_DDREN,
> >  				host->ioaddr + ESDHC_MIX_CTRL);
> >  		imx_data->is_ddr = 1;
> > +		if (boarddata->delay_line) {
> > +			u32 v;
> > +			v = boarddata->delay_line <<
> > +				ESDHC_DLL_OVERRIDE_VAL_SHIFT |
> > +				(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
> > +			if (is_imx53_esdhc(imx_data))
> > +				v <<= 1;
> 
> Is the patch (series) tested on imx53?  Or is it just a note that imx53
> has different bit position? 

Only tested on imx6sl.
mx53 register offset is differet.

> 
> > +			writel(v, host->ioaddr + ESDHC_DLL_CTRL);
> 
> Is it safe to always write other bits as zero?

Right, for the feature this patch added, only OVERRIDE_VAL need to set.

Regards
Dong Aisheng

> 
> Shawn
> 
> > +		}
> >  		break;
> >  	}
> >  
> > @@ -887,6 +902,9 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
> >  	else
> >  		boarddata->support_vsel = true;
> >  
> > +	if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
> > +		boarddata->delay_line = 0;
> > +
> >  	return 0;
> >  }
> >  #else
> > diff --git a/include/linux/platform_data/mmc-esdhc-imx.h b/include/linux/platform_data/mmc-esdhc-imx.h
> > index a0f5a8f..75f70f6 100644
> > --- a/include/linux/platform_data/mmc-esdhc-imx.h
> > +++ b/include/linux/platform_data/mmc-esdhc-imx.h
> > @@ -45,5 +45,6 @@ struct esdhc_platform_data {
> >  	int max_bus_width;
> >  	unsigned int f_max;
> >  	bool support_vsel;
> > +	unsigned int delay_line;
> >  };
> >  #endif /* __ASM_ARCH_IMX_ESDHC_H */
> > -- 
> > 1.7.2.rc3
> > 
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* [PATCH 07/10] mmc: sdhci-esdhc-imx: add delay line setting support
@ 2013-10-15  7:55       ` Dong Aisheng
  0 siblings, 0 replies; 32+ messages in thread
From: Dong Aisheng @ 2013-10-15  7:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Oct 15, 2013 at 03:37:06PM +0800, Shawn Guo wrote:
> On Wed, Oct 09, 2013 at 07:20:13PM +0800, Dong Aisheng wrote:
> > The DLL(Delay Line) is newly added to assist in sampling read data.
> > The DLL provides the ability to programmatically select a quantized
> > delay (in fractions of the clock period) regardless of on-chip variations
> > such as process, voltage and temperature (PVT).
> > 
> > This patch adds a user interface to set slave delay line via device tree.
> > It's usually used in high speed mode like mmc DDR mode when the signal
> > quality is not good caused by board design, e.g. the signal path is too long.
> > User can manual set delay line to find a suitable data sampling window
> > for card to work properly.
> > 
> > Signed-off-by: Dong Aisheng <b29396@freescale.com>
> > ---
> >  .../devicetree/bindings/mmc/fsl-imx-esdhc.txt      |    1 +
> >  drivers/mmc/host/sdhci-esdhc-imx.c                 |   18 ++++++++++++++++++
> >  include/linux/platform_data/mmc-esdhc-imx.h        |    1 +
> >  3 files changed, 20 insertions(+), 0 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
> > index 1dd6225..ebd3ff5 100644
> > --- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
> > +++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
> > @@ -12,6 +12,7 @@ Required properties:
> >  Optional properties:
> >  - fsl,cd-controller : Indicate to use controller internal card detection
> >  - fsl,wp-controller : Indicate to use controller internal write protection
> > +- fsl,delay-line : Specify delay line value of manual override for slave delay.
> 
> It needs more documentation and should refer to the register bits in RM.
> Otherwise, I hardly think people will understand what it is.
> 

Ok, i could improve it a bit.
But user may still need refer to spec to know the details.

> >  
> >  Examples:
> >  
> > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> > index b6ae5c1..91b2d85 100644
> > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > @@ -46,6 +46,11 @@
> >  /* Bits 3 and 6 are not SDHCI standard definitions */
> >  #define  ESDHC_MIX_CTRL_SDHCI_MASK	0xb7
> >  
> > +/* dll control register */
> > +#define ESDHC_DLL_CTRL			0x60
> > +#define ESDHC_DLL_OVERRIDE_VAL_SHIFT	9
> > +#define ESDHC_DLL_OVERRIDE_EN_SHIFT	8
> > +
> >  /* tune control register */
> >  #define ESDHC_TUNE_CTRL_STATUS		0x68
> >  #define  ESDHC_TUNE_CTRL_STEP		1
> > @@ -803,6 +808,7 @@ 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;
> > +	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
> >  
> >  	switch (uhs) {
> >  	case MMC_TIMING_UHS_SDR12:
> > @@ -823,6 +829,15 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
> >  				ESDHC_MIX_CTRL_DDREN,
> >  				host->ioaddr + ESDHC_MIX_CTRL);
> >  		imx_data->is_ddr = 1;
> > +		if (boarddata->delay_line) {
> > +			u32 v;
> > +			v = boarddata->delay_line <<
> > +				ESDHC_DLL_OVERRIDE_VAL_SHIFT |
> > +				(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
> > +			if (is_imx53_esdhc(imx_data))
> > +				v <<= 1;
> 
> Is the patch (series) tested on imx53?  Or is it just a note that imx53
> has different bit position? 

Only tested on imx6sl.
mx53 register offset is differet.

> 
> > +			writel(v, host->ioaddr + ESDHC_DLL_CTRL);
> 
> Is it safe to always write other bits as zero?

Right, for the feature this patch added, only OVERRIDE_VAL need to set.

Regards
Dong Aisheng

> 
> Shawn
> 
> > +		}
> >  		break;
> >  	}
> >  
> > @@ -887,6 +902,9 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
> >  	else
> >  		boarddata->support_vsel = true;
> >  
> > +	if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
> > +		boarddata->delay_line = 0;
> > +
> >  	return 0;
> >  }
> >  #else
> > diff --git a/include/linux/platform_data/mmc-esdhc-imx.h b/include/linux/platform_data/mmc-esdhc-imx.h
> > index a0f5a8f..75f70f6 100644
> > --- a/include/linux/platform_data/mmc-esdhc-imx.h
> > +++ b/include/linux/platform_data/mmc-esdhc-imx.h
> > @@ -45,5 +45,6 @@ struct esdhc_platform_data {
> >  	int max_bus_width;
> >  	unsigned int f_max;
> >  	bool support_vsel;
> > +	unsigned int delay_line;
> >  };
> >  #endif /* __ASM_ARCH_IMX_ESDHC_H */
> > -- 
> > 1.7.2.rc3
> > 
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

end of thread, other threads:[~2013-10-15  7:57 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-10-09 11:20 [PATCH 00/10] mmc: sdhci-esdhc-imx: add std tuning for mx6sl and DDR mode support Dong Aisheng
2013-10-09 11:20 ` Dong Aisheng
2013-10-09 11:20 ` [PATCH 01/10] ARM: dts: imx6sl: add pinctrl uhs states for usdhc Dong Aisheng
2013-10-09 11:20   ` Dong Aisheng
2013-10-12  8:49   ` Shawn Guo
2013-10-12  8:49     ` Shawn Guo
2013-10-09 11:20 ` [PATCH 02/10] mmc: sdhci-esdhc-imx: add std tuning support for mx6sl Dong Aisheng
2013-10-09 11:20   ` Dong Aisheng
2013-10-15  7:18   ` Shawn Guo
2013-10-15  7:18     ` Shawn Guo
2013-10-15  7:41     ` Dong Aisheng
2013-10-15  7:41       ` Dong Aisheng
2013-10-09 11:20 ` [PATCH 03/10] ARM: dts: imx6sl: change usdhc compatible with imx6sl only Dong Aisheng
2013-10-09 11:20   ` Dong Aisheng
2013-10-09 11:20 ` [PATCH 04/10] mmc: sdhci-esdhc-imx: fix reading cap_1 register value for mx6sl Dong Aisheng
2013-10-09 11:20   ` Dong Aisheng
2013-10-09 11:20 ` [PATCH 05/10] mmc: sdhci: report error once the maximum tuning loops exhausted or timeout Dong Aisheng
2013-10-09 11:20   ` Dong Aisheng
2013-10-09 11:20 ` [PATCH 06/10] mmc: sdhci-esdhc-imx: add DDR mode support for mx6 Dong Aisheng
2013-10-09 11:20   ` Dong Aisheng
2013-10-09 11:20 ` [PATCH 07/10] mmc: sdhci-esdhc-imx: add delay line setting support Dong Aisheng
2013-10-09 11:20   ` Dong Aisheng
2013-10-15  7:37   ` Shawn Guo
2013-10-15  7:37     ` Shawn Guo
2013-10-15  7:55     ` Dong Aisheng
2013-10-15  7:55       ` Dong Aisheng
2013-10-09 11:20 ` [PATCH 08/10] mmc: sdhci-esdhc-imx: enable SDR50 tuning for imx6q/dl Dong Aisheng
2013-10-09 11:20   ` Dong Aisheng
2013-10-09 11:20 ` [PATCH 09/10] mmc: sdhci-esdhc-imx: add preset value quirk for mx6 Dong Aisheng
2013-10-09 11:20   ` Dong Aisheng
2013-10-09 11:20 ` [PATCH 10/10] mmc: sdhci: remove unneeded call when have preset value quirk Dong Aisheng
2013-10-09 11:20   ` Dong Aisheng

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.