Skip to contentSkip to conversation

mmc: dw_mmc: exynos: Add HS400 support

PATCH Superseded Alim Akhtar 5 participants 12 messages Jan 14, 2015 – Jan 29, 2015

Subsystems (4)

v4 of 5 Superseded Latest is v5 →

lore
Share & tools
lore

Alim Akhtar

author reviewer
#0 lore raw

v4 cover mmc: dw_mmc: exynos: Add HS400 support

This adds HS400 mode support for exynos dw_mmc host controller.

Currently tested on Exynos5800-peach-pi platform for HS400 mode. Tested HS200 mode with this series applied, HS200 still works.

Appreciate testing on other exynos5/7 platform which supports emmc5.0

Changes in V4:
* drop the idea of changing existing binding for ciu_div as per [1]
* addressed comments from Jaehoon Chung [2]

[1] http://www.spinics.net/lists/linux-samsung-soc/msg40923.html
[2] http://www.spinics.net/lists/devicetree/msg64373.html

Changes in V3:
rebased on ulf's next (commit: 607b448 mmc: core: Make tuning block patterns static)

Seungwon Jeon (2):
mmc: dw_mmc: exynos: Support eMMC's HS400 mode
ARM: dts: Add HS400 support for exynos5420 and exynos5800

 .../devicetree/bindings/mmc/exynos-dw-mshc.txt     |    7 +
 arch/arm/boot/dts/exynos5420-peach-pit.dts         |    4 +-
 arch/arm/boot/dts/exynos5420-pinctrl.dtsi          |    7 +
 arch/arm/boot/dts/exynos5420-smdk5420.dts          |    4 +-
 arch/arm/boot/dts/exynos5800-peach-pi.dts          |    4 +-
 drivers/mmc/host/dw_mmc-exynos.c                   |  187 ++++++++++++++++----
 drivers/mmc/host/dw_mmc-exynos.h                   |   19 +-
 drivers/mmc/host/dw_mmc.c                          |   16 +-
 drivers/mmc/host/dw_mmc.h                          |    2 +
 9 files changed, 212 insertions(+), 38 deletions(-)
Signature · 1 line
1.7.9.5
author reviewer
#1 lore raw

PATCH v4 1/2 mmc: dw_mmc: exynos: Support eMMC's HS400 mode

From: Seungwon Jeon <[email protected]>

Implements HS400 mode support for exynos host driver. This also include some updates as new mode is added.

[Alim: addressed review comments]
---
 .../devicetree/bindings/mmc/exynos-dw-mshc.txt     |    7 +
 drivers/mmc/host/dw_mmc-exynos.c                   |  187 ++++++++++++++++----
 drivers/mmc/host/dw_mmc-exynos.h                   |   19 +-
 drivers/mmc/host/dw_mmc.c                          |   16 +-
 drivers/mmc/host/dw_mmc.h                          |    2 +
 5 files changed, 196 insertions(+), 35 deletions(-)
Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt +7 -0
index ee4fc05..dcab52c 100644
@@ -36,6 +36,8 @@ Required Properties:
   in transmit mode and CIU clock phase shift value in receive mode for double
   data rate mode operation. Refer notes below for the order of the cells and the
   valid values.
+* samsung,dw-mshc-hs400-timing: Specifies the value of CIU TX and RX clock phase
+  shift value for hs400 mode operation.
 
   Notes for the sdr-timing and ddr-timing values:
 
@@ -50,6 +52,9 @@ Required Properties:
       - if CIU clock divider value is 0 (that is divide by 1), both tx and rx
         phase shift clocks should be 0.
 
+* read-strobe-delay: RCLK (Data strobe) delay to control HS400 mode
+  (Latency value for delay line in Read path)
+
 Required properties for a slot (Deprecated - Recommend to use one slot per host):
 
 * gpios: specifies a list of gpios used for command, clock and data bus. The
@@ -82,5 +87,7 @@ Example:
 		samsung,dw-mshc-ciu-div = <3>;
 		samsung,dw-mshc-sdr-timing = <2 3>;
 		samsung,dw-mshc-ddr-timing = <1 2>;
+		samsung,dw-mshc-hs400-timing = <0 2>;
+		read-strobe-delay = <90>;
 		bus-width = <8>;
 	};
drivers/mmc/host/dw_mmc-exynos.c +154 -33

283 lines not on this page · raw message

drivers/mmc/host/dw_mmc-exynos.h +18 -1
index 7872ce5..595c934 100644
@@ -12,20 +12,36 @@
 #ifndef _DW_MMC_EXYNOS_H_
 #define _DW_MMC_EXYNOS_H_
 
-/* Extended Register's Offset */
 #define SDMMC_CLKSEL			0x09C
 #define SDMMC_CLKSEL64			0x0A8
 
+/* Extended Register's Offset */
+#define SDMMC_HS400_DQS_EN		0x180
+#define SDMMC_HS400_ASYNC_FIFO_CTRL	0x184
+#define SDMMC_HS400_DLINE_CTRL		0x188
+
 /* CLKSEL register defines */
 #define SDMMC_CLKSEL_CCLK_SAMPLE(x)	(((x) & 7) << 0)
 #define SDMMC_CLKSEL_CCLK_DRIVE(x)	(((x) & 7) << 16)
 #define SDMMC_CLKSEL_CCLK_DIVIDER(x)	(((x) & 7) << 24)
 #define SDMMC_CLKSEL_GET_DRV_WD3(x)	(((x) >> 16) & 0x7)
+#define SDMMC_CLKSEL_GET_DIV(x)		(((x) >> 24) & 0x7)
+#define SDMMC_CLKSEL_UP_SAMPLE(x, y)	(((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\
+					 SDMMC_CLKSEL_CCLK_SAMPLE(y))
 #define SDMMC_CLKSEL_TIMING(x, y, z)	(SDMMC_CLKSEL_CCLK_SAMPLE(x) |	\
 					 SDMMC_CLKSEL_CCLK_DRIVE(y) |	\
 					 SDMMC_CLKSEL_CCLK_DIVIDER(z))
+#define SDMMC_CLKSEL_TIMING_MASK	SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7)
 #define SDMMC_CLKSEL_WAKEUP_INT		BIT(11)
 
+/* RCLK_EN register defines */
+#define DATA_STROBE_EN			BIT(0)
+#define AXI_NON_BLOCKING_WR	BIT(7)
+
+/* DLINE_CTRL register defines */
+#define DQS_CTRL_RD_DELAY(x, y)		(((x) & ~0x3FF) | ((y) & 0x3FF))
+#define DQS_CTRL_GET_RD_DELAY(x)	((x) & 0x3FF)
+
 /* Protector Register */
 #define SDMMC_EMMCP_BASE	0x1000
 #define SDMMC_MPSECURITY	(SDMMC_EMMCP_BASE + 0x0010)
@@ -49,6 +65,7 @@
 /* Fixed clock divider */
 #define EXYNOS4210_FIXED_CIU_CLK_DIV	2
 #define EXYNOS4412_FIXED_CIU_CLK_DIV	4
+#define HS400_FIXED_CIU_CLK_DIV		1
 
 /* Minimal required clock frequency for cclkin, unit: HZ */
 #define EXYNOS_CCLKIN_MIN	50000000
drivers/mmc/host/dw_mmc.c +15 -1
index 2e8abc8..43a3a5b 100644
@@ -1084,7 +1084,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	regs = mci_readl(slot->host, UHS_REG);
 
 	/* DDR mode set */
-	if (ios->timing == MMC_TIMING_MMC_DDR52)
+	if (ios->timing == MMC_TIMING_MMC_DDR52 ||
+	    ios->timing == MMC_TIMING_MMC_HS400)
 		regs |= ((0x1 << slot->id) << 16);
 	else
 		regs &= ~((0x1 << slot->id) << 16);
@@ -1321,6 +1322,18 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	return err;
 }
 
+int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct dw_mci_slot *slot = mmc_priv(mmc);
+	struct dw_mci *host = slot->host;
+	const struct dw_mci_drv_data *drv_data = host->drv_data;
+
+	if (drv_data && drv_data->prepare_hs400_tuning)
+		return drv_data->prepare_hs400_tuning(host, ios);
+
+	return 0;
+}
+
 static const struct mmc_host_ops dw_mci_ops = {
 	.request		= dw_mci_request,
 	.pre_req		= dw_mci_pre_req,
@@ -1333,6 +1346,7 @@ static const struct mmc_host_ops dw_mci_ops = {
 	.card_busy		= dw_mci_card_busy,
 	.start_signal_voltage_switch = dw_mci_switch_voltage,
 	.init_card		= dw_mci_init_card,
+	.prepare_hs400_tuning	= dw_mci_prepare_hs400_tuning,
 };
 
 static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
drivers/mmc/host/dw_mmc.h +2 -0
index 18c4afe..d239867 100644
@@ -271,5 +271,7 @@ struct dw_mci_drv_data {
 	void		(*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
 	int		(*parse_dt)(struct dw_mci *host);
 	int		(*execute_tuning)(struct dw_mci_slot *slot);
+	int		(*prepare_hs400_tuning)(struct dw_mci *host,
+						struct mmc_ios *ios);
 };
 #endif /* _DW_MMC_H_ */
Signature · 1 line
1.7.9.5
maintainer
#2 lore raw

PATCH v4 1/2 mmc: dw_mmc: exynos: Support eMMC's HS400 mode

Hi,

This patch can be separated.
When i tested on my board, it's not working fine.
I think it depends on my timing, so i will check after change the timing.

Quoted 40 lines · Alim Akhtar

From: Seungwon Jeon <[email protected]>

Implements HS400 mode support for exynos host driver. This also include some updates as new mode is added.

[Alim: addressed review comments]
---
 .../devicetree/bindings/mmc/exynos-dw-mshc.txt     |    7 +
 drivers/mmc/host/dw_mmc-exynos.c                   |  187 ++++++++++++++++----
 drivers/mmc/host/dw_mmc-exynos.h                   |   19 +-
 drivers/mmc/host/dw_mmc.c                          |   16 +-
 drivers/mmc/host/dw_mmc.h                          |    2 +
 5 files changed, 196 insertions(+), 35 deletions(-)
Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt +5 -0
index ee4fc05..dcab52c 100644
@@ -36,6 +36,8 @@ Required Properties:
   in transmit mode and CIU clock phase shift value in receive mode for double
   data rate mode operation. Refer notes below for the order of the cells and the
   valid values.
+* samsung,dw-mshc-hs400-timing: Specifies the value of CIU TX and RX clock phase
+  shift value for hs400 mode operation.
 
   Notes for the sdr-timing and ddr-timing values:
 
@@ -50,6 +52,9 @@ Required Properties:
       - if CIU clock divider value is 0 (that is divide by 1), both tx and rx
         phase shift clocks should be 0.
 
+* read-strobe-delay: RCLK (Data strobe) delay to control HS400 mode
+  (Latency value for delay line in Read path)
+
 Required properties for a slot (Deprecated - Recommend to use one slot per host):
 
 * gpios: specifies a list of gpios used for command, clock and data bus. The

Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt Example: · line 91

Quoted 5 lines
Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt +2 -0
@@ -82,5 +87,7 @@ Example:
 		samsung,dw-mshc-ciu-div = <3>;
 		samsung,dw-mshc-sdr-timing = <2 3>;
 		samsung,dw-mshc-ddr-timing = <1 2>;
+		samsung,dw-mshc-hs400-timing = <0 2>;
+		read-strobe-delay = <90>;

read-strobe-delay is exynos specific, isn't?
read-strobe-delay -> samsung.read-strobe-delay.

Quoted 59 lines
Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt +0 -0
 		bus-width = <8>;
 	};
drivers/mmc/host/dw_mmc-exynos.c +30 -0
index 12a5eaa..172a2a8 100644
@@ -40,7 +40,12 @@ struct dw_mci_exynos_priv_data {
 	u8				ciu_div;
 	u32				sdr_timing;
 	u32				ddr_timing;
+	u32				hs400_timing;
+	u32				tuned_sample;
 	u32				cur_speed;
+	u32				dqs_delay;
+	u32				saved_dqs_en;
+	u32				saved_strobe_ctrl;
 };
 
 static struct dw_mci_exynos_compatible {
@@ -71,6 +76,21 @@ static struct dw_mci_exynos_compatible {
 	},
 };
 
+static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
+{
+	struct dw_mci_exynos_priv_data *priv = host->priv;
+
+	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
+		return EXYNOS4412_FIXED_CIU_CLK_DIV;
+	else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
+		return EXYNOS4210_FIXED_CIU_CLK_DIV;
+	else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+			priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+		return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
+	else
+		return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
+}
+
 static int dw_mci_exynos_priv_init(struct dw_mci *host)
 {
 	struct dw_mci_exynos_priv_data *priv = host->priv;
@@ -85,6 +105,16 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
 			   SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
 	}
 
+	if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) {
+		priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL);
+		priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN);
+		priv->saved_dqs_en |= AXI_NON_BLOCKING_WR;
+		mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en);
+		if (!priv->dqs_delay)
+			priv->dqs_delay =
+				DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
+	}
+
 	return 0;
 }
 

drivers/mmc/host/dw_mmc-exynos.c static int dw_mci_exynos_setup_clock(struct dw_mci *host) · line 125

Quoted 5 lines
drivers/mmc/host/dw_mmc-exynos.c +1 -1
@@ -92,11 +122,31 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
 {
 	struct dw_mci_exynos_priv_data *priv = host->priv;
 
-	host->bus_hz /= (priv->ciu_div + 1);
+	host->bus_hz /= priv->ciu_div;

Don't need to consider the case that priv->ciu_div set to 0?

Quoted 41 lines
drivers/mmc/host/dw_mmc-exynos.c +22 -5
 	return 0;
 }
 
+static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
+{
+	struct dw_mci_exynos_priv_data *priv = host->priv;
+	u32 clksel;
+
+	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+		clksel = mci_readl(host, CLKSEL64);
+	else
+		clksel = mci_readl(host, CLKSEL);
+
+	clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing;
+
+	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+		mci_writel(host, CLKSEL64, clksel);
+	else
+		mci_writel(host, CLKSEL, clksel);
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int dw_mci_exynos_suspend(struct device *dev)
 {
@@ -172,30 +222,38 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
 	}
 }
 
-static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
 {
 	struct dw_mci_exynos_priv_data *priv = host->priv;
-	unsigned int wanted = ios->clock;
-	unsigned long actual;
-	u8 div = priv->ciu_div + 1;
+	u32 dqs, strobe;
 
-	if (ios->timing == MMC_TIMING_MMC_DDR52) {

drivers/mmc/host/dw_mmc-exynos.c static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) · line 231

Quoted 10 lines
drivers/mmc/host/dw_mmc-exynos.c +2 -8
-		if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
-			priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
-			mci_writel(host, CLKSEL64, priv->ddr_timing);
-		else
-			mci_writel(host, CLKSEL, priv->ddr_timing);
-		/* Should be double rate for DDR mode */
-		if (ios->bus_width == MMC_BUS_WIDTH_8)
-			wanted <<= 1;
+	/*
+	 * Not suppported to configure register

Typo..supported

drivers/mmc/host/dw_mmc-exynos.c static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) · line 238

Quoted 7 lines
drivers/mmc/host/dw_mmc-exynos.c +7 -0
+	 * related to HS400
+	 */
+	if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420)
+		return;
+
+	dqs = priv->saved_dqs_en;
+	strobe = priv->saved_strobe_ctrl;

priv->saved_dqs_en is set at init-time.
And you read the RDDQS_EN and HS400_DLINE_CTRL register at that time. Doesn't it need to consider the changed value at those register?

priv->saved_xxx is reset value?

Quoted 90 lines
drivers/mmc/host/dw_mmc-exynos.c +60 -15
+
+	if (timing == MMC_TIMING_MMC_HS400) {
+		dqs |= DATA_STROBE_EN;
+		strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
 	} else {
-		if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
-			priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
-			mci_writel(host, CLKSEL64, priv->sdr_timing);
-		else
-			mci_writel(host, CLKSEL, priv->sdr_timing);
+		dqs &= ~DATA_STROBE_EN;
 	}
 
+	mci_writel(host, HS400_DQS_EN, dqs);
+	mci_writel(host, HS400_DLINE_CTRL, strobe);
+}
+
+static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted)
+{
+	struct dw_mci_exynos_priv_data *priv = host->priv;
+	unsigned long actual;
+	u8 div;
+	int ret;
 	/*
 	 * Don't care if wanted clock is zero or
 	 * ciu clock is unavailable
@@ -207,17 +265,52 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
 	if (wanted < EXYNOS_CCLKIN_MIN)
 		wanted = EXYNOS_CCLKIN_MIN;
 
-	if (wanted != priv->cur_speed) {
-		int ret = clk_set_rate(host->ciu_clk, wanted * div);
-		if (ret)
-			dev_warn(host->dev,
-				"failed to set clk-rate %u error: %d\n",
-				 wanted * div, ret);
-		actual = clk_get_rate(host->ciu_clk);
-		host->bus_hz = actual / div;
-		priv->cur_speed = wanted;
-		host->current_speed = 0;
+	if (wanted == priv->cur_speed)
+		return;
+
+	div = dw_mci_exynos_get_ciu_div(host);
+	ret = clk_set_rate(host->ciu_clk, wanted * div);
+	if (ret)
+		dev_warn(host->dev,
+			"failed to set clk-rate %u error: %d\n",
+			wanted * div, ret);
+	actual = clk_get_rate(host->ciu_clk);
+	host->bus_hz = actual / div;
+	priv->cur_speed = wanted;
+	host->current_speed = 0;
+}
+
+static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+	struct dw_mci_exynos_priv_data *priv = host->priv;
+	unsigned int wanted = ios->clock;
+	u32 timing = ios->timing, clksel;
+
+	switch (timing) {
+	case MMC_TIMING_MMC_HS400:
+		/* Update tuned sample timing */
+		clksel = SDMMC_CLKSEL_UP_SAMPLE(
+				priv->hs400_timing, priv->tuned_sample);
+		wanted <<= 1;
+		break;
+	case MMC_TIMING_MMC_DDR52:
+		clksel = priv->ddr_timing;
+		/* Should be double rate for DDR mode */
+		if (ios->bus_width == MMC_BUS_WIDTH_8)
+			wanted <<= 1;
+		break;
+	default:
+		clksel = priv->sdr_timing;
 	}
+
+	/* Set clock timing for the requested speed mode*/
+	dw_mci_exynos_set_clksel_timing(host, clksel);
+
+	/* Configure setting for HS400 */
+	dw_mci_exynos_config_hs400(host, timing);
+
+	/* Configure clock rate */
+	dw_mci_exynos_adjust_clock(host, wanted);
 }
 
 static int dw_mci_exynos_parse_dt(struct dw_mci *host)

drivers/mmc/host/dw_mmc-exynos.c static int dw_mci_exynos_parse_dt(struct dw_mci *host) · line 362

Quoted 10 lines
drivers/mmc/host/dw_mmc-exynos.c +7 -0
@@ -260,6 +353,16 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
 		return ret;
 
 	priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
+
+	ret = of_property_read_u32_array(np,
+			"samsung,dw-mshc-hs400-timing", timing, 2);
+	if (!ret && of_property_read_u32(np,
+				"read-strobe-delay", &priv->dqs_delay))
+		dev_info(host->dev,
+			"read-strobe-delay is not found, assuming usage of default value\n");

Need the message?

drivers/mmc/host/dw_mmc-exynos.c static int dw_mci_exynos_parse_dt(struct dw_mci *host) · line 365

Quoted 3 lines
drivers/mmc/host/dw_mmc-exynos.c +3 -0
+
+	priv->hs400_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1],
+						HS400_FIXED_CIU_CLK_DIV);

Why useed the HS400_FIXED_CIU_CLK_DIV? always set to 1?

Best Regards,
Jaehoon Chung

Quoted 180 lines
drivers/mmc/host/dw_mmc-exynos.c +22 -4
 	host->priv = priv;
 	return 0;
 }
@@ -285,7 +388,7 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
 		clksel = mci_readl(host, CLKSEL64);
 	else
 		clksel = mci_readl(host, CLKSEL);
-	clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample);
+	clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
 	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
 		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
 		mci_writel(host, CLKSEL64, clksel);
@@ -304,13 +407,16 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
 		clksel = mci_readl(host, CLKSEL64);
 	else
 		clksel = mci_readl(host, CLKSEL);
+
 	sample = (clksel + 1) & 0x7;
-	clksel = (clksel & ~0x7) | sample;
+	clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
+
 	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
 		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
 		mci_writel(host, CLKSEL64, clksel);
 	else
 		mci_writel(host, CLKSEL, clksel);
+
 	return sample;
 }
 
@@ -343,6 +449,7 @@ out:
 static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
 {
 	struct dw_mci *host = slot->host;
+	struct dw_mci_exynos_priv_data *priv = host->priv;
 	struct mmc_host *mmc = slot->mmc;
 	u8 start_smpl, smpl, candiates = 0;
 	s8 found = -1;
@@ -360,14 +467,27 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
 	} while (start_smpl != smpl);
 
 	found = dw_mci_exynos_get_best_clksmpl(candiates);
-	if (found >= 0)
+	if (found >= 0) {
 		dw_mci_exynos_set_clksmpl(host, found);
-	else
+		priv->tuned_sample = found;
+	} else {
 		ret = -EIO;
+	}
 
 	return ret;
 }
 
+int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
+					struct mmc_ios *ios)
+{
+	struct dw_mci_exynos_priv_data *priv = host->priv;
+
+	dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing);
+	dw_mci_exynos_adjust_clock(host, (ios->clock) << 1);
+
+	return 0;
+}
+
 /* Common capabilities of Exynos4/Exynos5 SoC */
 static unsigned long exynos_dwmmc_caps[4] = {
 	MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
@@ -384,6 +504,7 @@ static const struct dw_mci_drv_data exynos_drv_data = {
 	.set_ios		= dw_mci_exynos_set_ios,
 	.parse_dt		= dw_mci_exynos_parse_dt,
 	.execute_tuning		= dw_mci_exynos_execute_tuning,
+	.prepare_hs400_tuning	= dw_mci_exynos_prepare_hs400_tuning,
 };
 
 static const struct of_device_id dw_mci_exynos_match[] = {
drivers/mmc/host/dw_mmc-exynos.h +18 -1
index 7872ce5..595c934 100644
@@ -12,20 +12,36 @@
 #ifndef _DW_MMC_EXYNOS_H_
 #define _DW_MMC_EXYNOS_H_
 
-/* Extended Register's Offset */
 #define SDMMC_CLKSEL			0x09C
 #define SDMMC_CLKSEL64			0x0A8
 
+/* Extended Register's Offset */
+#define SDMMC_HS400_DQS_EN		0x180
+#define SDMMC_HS400_ASYNC_FIFO_CTRL	0x184
+#define SDMMC_HS400_DLINE_CTRL		0x188
+
 /* CLKSEL register defines */
 #define SDMMC_CLKSEL_CCLK_SAMPLE(x)	(((x) & 7) << 0)
 #define SDMMC_CLKSEL_CCLK_DRIVE(x)	(((x) & 7) << 16)
 #define SDMMC_CLKSEL_CCLK_DIVIDER(x)	(((x) & 7) << 24)
 #define SDMMC_CLKSEL_GET_DRV_WD3(x)	(((x) >> 16) & 0x7)
+#define SDMMC_CLKSEL_GET_DIV(x)		(((x) >> 24) & 0x7)
+#define SDMMC_CLKSEL_UP_SAMPLE(x, y)	(((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\
+					 SDMMC_CLKSEL_CCLK_SAMPLE(y))
 #define SDMMC_CLKSEL_TIMING(x, y, z)	(SDMMC_CLKSEL_CCLK_SAMPLE(x) |	\
 					 SDMMC_CLKSEL_CCLK_DRIVE(y) |	\
 					 SDMMC_CLKSEL_CCLK_DIVIDER(z))
+#define SDMMC_CLKSEL_TIMING_MASK	SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7)
 #define SDMMC_CLKSEL_WAKEUP_INT		BIT(11)
 
+/* RCLK_EN register defines */
+#define DATA_STROBE_EN			BIT(0)
+#define AXI_NON_BLOCKING_WR	BIT(7)
+
+/* DLINE_CTRL register defines */
+#define DQS_CTRL_RD_DELAY(x, y)		(((x) & ~0x3FF) | ((y) & 0x3FF))
+#define DQS_CTRL_GET_RD_DELAY(x)	((x) & 0x3FF)
+
 /* Protector Register */
 #define SDMMC_EMMCP_BASE	0x1000
 #define SDMMC_MPSECURITY	(SDMMC_EMMCP_BASE + 0x0010)
@@ -49,6 +65,7 @@
 /* Fixed clock divider */
 #define EXYNOS4210_FIXED_CIU_CLK_DIV	2
 #define EXYNOS4412_FIXED_CIU_CLK_DIV	4
+#define HS400_FIXED_CIU_CLK_DIV		1
 
 /* Minimal required clock frequency for cclkin, unit: HZ */
 #define EXYNOS_CCLKIN_MIN	50000000
drivers/mmc/host/dw_mmc.c +15 -1
index 2e8abc8..43a3a5b 100644
@@ -1084,7 +1084,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	regs = mci_readl(slot->host, UHS_REG);
 
 	/* DDR mode set */
-	if (ios->timing == MMC_TIMING_MMC_DDR52)
+	if (ios->timing == MMC_TIMING_MMC_DDR52 ||
+	    ios->timing == MMC_TIMING_MMC_HS400)
 		regs |= ((0x1 << slot->id) << 16);
 	else
 		regs &= ~((0x1 << slot->id) << 16);
@@ -1321,6 +1322,18 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	return err;
 }
 
+int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct dw_mci_slot *slot = mmc_priv(mmc);
+	struct dw_mci *host = slot->host;
+	const struct dw_mci_drv_data *drv_data = host->drv_data;
+
+	if (drv_data && drv_data->prepare_hs400_tuning)
+		return drv_data->prepare_hs400_tuning(host, ios);
+
+	return 0;
+}
+
 static const struct mmc_host_ops dw_mci_ops = {
 	.request		= dw_mci_request,
 	.pre_req		= dw_mci_pre_req,
@@ -1333,6 +1346,7 @@ static const struct mmc_host_ops dw_mci_ops = {
 	.card_busy		= dw_mci_card_busy,
 	.start_signal_voltage_switch = dw_mci_switch_voltage,
 	.init_card		= dw_mci_init_card,
+	.prepare_hs400_tuning	= dw_mci_prepare_hs400_tuning,
 };
 
 static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
drivers/mmc/host/dw_mmc.h +2 -0
index 18c4afe..d239867 100644
@@ -271,5 +271,7 @@ struct dw_mci_drv_data {
 	void		(*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
 	int		(*parse_dt)(struct dw_mci *host);
 	int		(*execute_tuning)(struct dw_mci_slot *slot);
+	int		(*prepare_hs400_tuning)(struct dw_mci *host,
+						struct mmc_ios *ios);
 };
 #endif /* _DW_MMC_H_ */
#3 lore raw

PATCH v4 1/2 mmc: dw_mmc: exynos: Support eMMC's HS400 mode

Hi Jaehoon

Quoted 45 lines · Jaehoon Chung

Hi,

This patch can be separated.
When i tested on my board, it's not working fine.
I think it depends on my timing, so i will check after change the timing.

Quoted 38 lines · Alim Akhtar

From: Seungwon Jeon <[email protected]>

Implements HS400 mode support for exynos host driver. This also include some updates as new mode is added.

[Alim: addressed review comments]
---
 .../devicetree/bindings/mmc/exynos-dw-mshc.txt     |    7 +
 drivers/mmc/host/dw_mmc-exynos.c                   |  187 ++++++++++++++++----
 drivers/mmc/host/dw_mmc-exynos.h                   |   19 +-
 drivers/mmc/host/dw_mmc.c                          |   16 +-
 drivers/mmc/host/dw_mmc.h                          |    2 +
 5 files changed, 196 insertions(+), 35 deletions(-)
Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt +5 -0
index ee4fc05..dcab52c 100644
@@ -36,6 +36,8 @@ Required Properties:
   in transmit mode and CIU clock phase shift value in receive mode for double
   data rate mode operation. Refer notes below for the order of the cells and the
   valid values.
+* samsung,dw-mshc-hs400-timing: Specifies the value of CIU TX and RX clock phase
+  shift value for hs400 mode operation.
 
   Notes for the sdr-timing and ddr-timing values:
 
@@ -50,6 +52,9 @@ Required Properties:
       - if CIU clock divider value is 0 (that is divide by 1), both tx and rx
         phase shift clocks should be 0.
 
+* read-strobe-delay: RCLK (Data strobe) delay to control HS400 mode
+  (Latency value for delay line in Read path)
+
 Required properties for a slot (Deprecated - Recommend to use one slot per host):
 
Quoted 11 lines

Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt Example: · line 91

Quoted 7 lines
Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt +2 -0
 * gpios: specifies a list of gpios used for command, clock and data bus. The
@@ -82,5 +87,7 @@ Example:
              samsung,dw-mshc-ciu-div = <3>;
              samsung,dw-mshc-sdr-timing = <2 3>;
              samsung,dw-mshc-ddr-timing = <1 2>;
+             samsung,dw-mshc-hs400-timing = <0 2>;
+             read-strobe-delay = <90>;

read-strobe-delay is exynos specific, isn't?
read-strobe-delay -> samsung.read-strobe-delay.

read-strobe are as per hs400 spec, ok I will change this to match the naming with other properties.

Quoted 58 lines
Quoted 58 lines
Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt +0 -0
              bus-width = <8>;
      };
drivers/mmc/host/dw_mmc-exynos.c +30 -0
index 12a5eaa..172a2a8 100644
@@ -40,7 +40,12 @@ struct dw_mci_exynos_priv_data {
      u8                              ciu_div;
      u32                             sdr_timing;
      u32                             ddr_timing;
+     u32                             hs400_timing;
+     u32                             tuned_sample;
      u32                             cur_speed;
+     u32                             dqs_delay;
+     u32                             saved_dqs_en;
+     u32                             saved_strobe_ctrl;
 };
 
 static struct dw_mci_exynos_compatible {
@@ -71,6 +76,21 @@ static struct dw_mci_exynos_compatible {
      },
 };
 
+static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
+{
+     struct dw_mci_exynos_priv_data *priv = host->priv;
+
+     if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
+             return EXYNOS4412_FIXED_CIU_CLK_DIV;
+     else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
+             return EXYNOS4210_FIXED_CIU_CLK_DIV;
+     else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+                     priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+             return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
+     else
+             return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
+}
+
 static int dw_mci_exynos_priv_init(struct dw_mci *host)
 {
      struct dw_mci_exynos_priv_data *priv = host->priv;
@@ -85,6 +105,16 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
                         SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
      }
 
+     if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) {
+             priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL);
+             priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN);
+             priv->saved_dqs_en |= AXI_NON_BLOCKING_WR;
+             mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en);
+             if (!priv->dqs_delay)
+                     priv->dqs_delay =
+                             DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
+     }
+
      return 0;
 }
 
Quoted 9 lines

drivers/mmc/host/dw_mmc-exynos.c static int dw_mci_exynos_setup_clock(struct dw_mci *host) · line 125

Quoted 6 lines
drivers/mmc/host/dw_mmc-exynos.c +1 -1
@@ -92,11 +122,31 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
 {
      struct dw_mci_exynos_priv_data *priv = host->priv;
 
-     host->bus_hz /= (priv->ciu_div + 1);
+     host->bus_hz /= priv->ciu_div;

Don't need to consider the case that priv->ciu_div set to 0?

Ah ok, I know at least one board sets ciu_div as zero, let me remove this change. thanks

Quoted 40 lines
Quoted 40 lines
drivers/mmc/host/dw_mmc-exynos.c +22 -4
      return 0;
 }
 
+static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
+{
+     struct dw_mci_exynos_priv_data *priv = host->priv;
+     u32 clksel;
+
+     if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+             priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+             clksel = mci_readl(host, CLKSEL64);
+     else
+             clksel = mci_readl(host, CLKSEL);
+
+     clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing;
+
+     if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+             priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+             mci_writel(host, CLKSEL64, clksel);
+     else
+             mci_writel(host, CLKSEL, clksel);
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int dw_mci_exynos_suspend(struct device *dev)
 {
@@ -172,30 +222,38 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
      }
 }
 
-static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
 {
      struct dw_mci_exynos_priv_data *priv = host->priv;
-     unsigned int wanted = ios->clock;
-     unsigned long actual;
-     u8 div = priv->ciu_div + 1;
+     u32 dqs, strobe;
 
Quoted 14 lines

drivers/mmc/host/dw_mmc-exynos.c static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) · line 231

Quoted 11 lines
drivers/mmc/host/dw_mmc-exynos.c +2 -9
-     if (ios->timing == MMC_TIMING_MMC_DDR52) {
-             if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
-                     priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
-                     mci_writel(host, CLKSEL64, priv->ddr_timing);
-             else
-                     mci_writel(host, CLKSEL, priv->ddr_timing);
-             /* Should be double rate for DDR mode */
-             if (ios->bus_width == MMC_BUS_WIDTH_8)
-                     wanted <<= 1;
+     /*
+      * Not suppported to configure register

Typo..supported

ok will correct.

Quoted 8 lines

drivers/mmc/host/dw_mmc-exynos.c static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) · line 238

Quoted 7 lines
drivers/mmc/host/dw_mmc-exynos.c +7 -0
+      * related to HS400
+      */
+     if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420)
+             return;
+
+     dqs = priv->saved_dqs_en;
+     strobe = priv->saved_strobe_ctrl;
Quoted 6 lines

priv->saved_dqs_en is set at init-time.
And you read the RDDQS_EN and HS400_DLINE_CTRL register at that time. Doesn't it need to consider the changed value at those register?

priv->saved_xxx is reset value?

Default values are read in init and adjusted below, for now only these bits are touched other bits of these register are kept as their reset values.

Quoted 92 lines
Quoted 92 lines
drivers/mmc/host/dw_mmc-exynos.c +60 -15
+
+     if (timing == MMC_TIMING_MMC_HS400) {
+             dqs |= DATA_STROBE_EN;
+             strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
      } else {
-             if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
-                     priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
-                     mci_writel(host, CLKSEL64, priv->sdr_timing);
-             else
-                     mci_writel(host, CLKSEL, priv->sdr_timing);
+             dqs &= ~DATA_STROBE_EN;
      }
 
+     mci_writel(host, HS400_DQS_EN, dqs);
+     mci_writel(host, HS400_DLINE_CTRL, strobe);
+}
+
+static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted)
+{
+     struct dw_mci_exynos_priv_data *priv = host->priv;
+     unsigned long actual;
+     u8 div;
+     int ret;
      /*
       * Don't care if wanted clock is zero or
       * ciu clock is unavailable
@@ -207,17 +265,52 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
      if (wanted < EXYNOS_CCLKIN_MIN)
              wanted = EXYNOS_CCLKIN_MIN;
 
-     if (wanted != priv->cur_speed) {
-             int ret = clk_set_rate(host->ciu_clk, wanted * div);
-             if (ret)
-                     dev_warn(host->dev,
-                             "failed to set clk-rate %u error: %d\n",
-                              wanted * div, ret);
-             actual = clk_get_rate(host->ciu_clk);
-             host->bus_hz = actual / div;
-             priv->cur_speed = wanted;
-             host->current_speed = 0;
+     if (wanted == priv->cur_speed)
+             return;
+
+     div = dw_mci_exynos_get_ciu_div(host);
+     ret = clk_set_rate(host->ciu_clk, wanted * div);
+     if (ret)
+             dev_warn(host->dev,
+                     "failed to set clk-rate %u error: %d\n",
+                     wanted * div, ret);
+     actual = clk_get_rate(host->ciu_clk);
+     host->bus_hz = actual / div;
+     priv->cur_speed = wanted;
+     host->current_speed = 0;
+}
+
+static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+     struct dw_mci_exynos_priv_data *priv = host->priv;
+     unsigned int wanted = ios->clock;
+     u32 timing = ios->timing, clksel;
+
+     switch (timing) {
+     case MMC_TIMING_MMC_HS400:
+             /* Update tuned sample timing */
+             clksel = SDMMC_CLKSEL_UP_SAMPLE(
+                             priv->hs400_timing, priv->tuned_sample);
+             wanted <<= 1;
+             break;
+     case MMC_TIMING_MMC_DDR52:
+             clksel = priv->ddr_timing;
+             /* Should be double rate for DDR mode */
+             if (ios->bus_width == MMC_BUS_WIDTH_8)
+                     wanted <<= 1;
+             break;
+     default:
+             clksel = priv->sdr_timing;
      }
+
+     /* Set clock timing for the requested speed mode*/
+     dw_mci_exynos_set_clksel_timing(host, clksel);
+
+     /* Configure setting for HS400 */
+     dw_mci_exynos_config_hs400(host, timing);
+
+     /* Configure clock rate */
+     dw_mci_exynos_adjust_clock(host, wanted);
 }
 
 static int dw_mci_exynos_parse_dt(struct dw_mci *host)
@@ -260,6 +353,16 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
              return ret;
 
Quoted 11 lines

drivers/mmc/host/dw_mmc-exynos.c static int dw_mci_exynos_parse_dt(struct dw_mci *host) · line 362

Quoted 8 lines
drivers/mmc/host/dw_mmc-exynos.c +7 -0
      priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
+
+     ret = of_property_read_u32_array(np,
+                     "samsung,dw-mshc-hs400-timing", timing, 2);
+     if (!ret && of_property_read_u32(np,
+                             "read-strobe-delay", &priv->dqs_delay))
+             dev_info(host->dev,
+                     "read-strobe-delay is not found, assuming usage of default value\n");

Need the message?

Just in case the default values does not work, then user will know this is something they need to change as per their boards.

Quoted 6 lines

drivers/mmc/host/dw_mmc-exynos.c static int dw_mci_exynos_parse_dt(struct dw_mci *host) · line 365

Quoted 3 lines
drivers/mmc/host/dw_mmc-exynos.c +3 -0
+
+     priv->hs400_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1],
+                                             HS400_FIXED_CIU_CLK_DIV);

Why useed the HS400_FIXED_CIU_CLK_DIV? always set to 1?

I thought about this, but I didn't find a case where it is anytime set to more then div by 2 to support HS400 clock input value requirement. So instead of getting this via DT, I kept fixed value,
Let me know your opinion on this, in case you wants me to change this.

Quoted 184 lines

Best Regards,
Jaehoon Chung

Quoted 180 lines
drivers/mmc/host/dw_mmc-exynos.c +22 -4
      host->priv = priv;
      return 0;
 }
@@ -285,7 +388,7 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
              clksel = mci_readl(host, CLKSEL64);
      else
              clksel = mci_readl(host, CLKSEL);
-     clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample);
+     clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
      if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
              priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
              mci_writel(host, CLKSEL64, clksel);
@@ -304,13 +407,16 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
              clksel = mci_readl(host, CLKSEL64);
      else
              clksel = mci_readl(host, CLKSEL);
+
      sample = (clksel + 1) & 0x7;
-     clksel = (clksel & ~0x7) | sample;
+     clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
+
      if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
              priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
              mci_writel(host, CLKSEL64, clksel);
      else
              mci_writel(host, CLKSEL, clksel);
+
      return sample;
 }
 
@@ -343,6 +449,7 @@ out:
 static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
 {
      struct dw_mci *host = slot->host;
+     struct dw_mci_exynos_priv_data *priv = host->priv;
      struct mmc_host *mmc = slot->mmc;
      u8 start_smpl, smpl, candiates = 0;
      s8 found = -1;
@@ -360,14 +467,27 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
      } while (start_smpl != smpl);
 
      found = dw_mci_exynos_get_best_clksmpl(candiates);
-     if (found >= 0)
+     if (found >= 0) {
              dw_mci_exynos_set_clksmpl(host, found);
-     else
+             priv->tuned_sample = found;
+     } else {
              ret = -EIO;
+     }
 
      return ret;
 }
 
+int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
+                                     struct mmc_ios *ios)
+{
+     struct dw_mci_exynos_priv_data *priv = host->priv;
+
+     dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing);
+     dw_mci_exynos_adjust_clock(host, (ios->clock) << 1);
+
+     return 0;
+}
+
 /* Common capabilities of Exynos4/Exynos5 SoC */
 static unsigned long exynos_dwmmc_caps[4] = {
      MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
@@ -384,6 +504,7 @@ static const struct dw_mci_drv_data exynos_drv_data = {
      .set_ios                = dw_mci_exynos_set_ios,
      .parse_dt               = dw_mci_exynos_parse_dt,
      .execute_tuning         = dw_mci_exynos_execute_tuning,
+     .prepare_hs400_tuning   = dw_mci_exynos_prepare_hs400_tuning,
 };
 
 static const struct of_device_id dw_mci_exynos_match[] = {
drivers/mmc/host/dw_mmc-exynos.h +18 -1
index 7872ce5..595c934 100644
@@ -12,20 +12,36 @@
 #ifndef _DW_MMC_EXYNOS_H_
 #define _DW_MMC_EXYNOS_H_
 
-/* Extended Register's Offset */
 #define SDMMC_CLKSEL                 0x09C
 #define SDMMC_CLKSEL64                       0x0A8
 
+/* Extended Register's Offset */
+#define SDMMC_HS400_DQS_EN           0x180
+#define SDMMC_HS400_ASYNC_FIFO_CTRL  0x184
+#define SDMMC_HS400_DLINE_CTRL               0x188
+
 /* CLKSEL register defines */
 #define SDMMC_CLKSEL_CCLK_SAMPLE(x)  (((x) & 7) << 0)
 #define SDMMC_CLKSEL_CCLK_DRIVE(x)   (((x) & 7) << 16)
 #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
 #define SDMMC_CLKSEL_GET_DRV_WD3(x)  (((x) >> 16) & 0x7)
+#define SDMMC_CLKSEL_GET_DIV(x)              (((x) >> 24) & 0x7)
+#define SDMMC_CLKSEL_UP_SAMPLE(x, y) (((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\
+                                      SDMMC_CLKSEL_CCLK_SAMPLE(y))
 #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) |  \
                                       SDMMC_CLKSEL_CCLK_DRIVE(y) |   \
                                       SDMMC_CLKSEL_CCLK_DIVIDER(z))
+#define SDMMC_CLKSEL_TIMING_MASK     SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7)
 #define SDMMC_CLKSEL_WAKEUP_INT              BIT(11)
 
+/* RCLK_EN register defines */
+#define DATA_STROBE_EN                       BIT(0)
+#define AXI_NON_BLOCKING_WR  BIT(7)
+
+/* DLINE_CTRL register defines */
+#define DQS_CTRL_RD_DELAY(x, y)              (((x) & ~0x3FF) | ((y) & 0x3FF))
+#define DQS_CTRL_GET_RD_DELAY(x)     ((x) & 0x3FF)
+
 /* Protector Register */
 #define SDMMC_EMMCP_BASE     0x1000
 #define SDMMC_MPSECURITY     (SDMMC_EMMCP_BASE + 0x0010)
@@ -49,6 +65,7 @@
 /* Fixed clock divider */
 #define EXYNOS4210_FIXED_CIU_CLK_DIV 2
 #define EXYNOS4412_FIXED_CIU_CLK_DIV 4
+#define HS400_FIXED_CIU_CLK_DIV              1
 
 /* Minimal required clock frequency for cclkin, unit: HZ */
 #define EXYNOS_CCLKIN_MIN    50000000
drivers/mmc/host/dw_mmc.c +15 -1
index 2e8abc8..43a3a5b 100644
@@ -1084,7 +1084,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
      regs = mci_readl(slot->host, UHS_REG);
 
      /* DDR mode set */
-     if (ios->timing == MMC_TIMING_MMC_DDR52)
+     if (ios->timing == MMC_TIMING_MMC_DDR52 ||
+         ios->timing == MMC_TIMING_MMC_HS400)
              regs |= ((0x1 << slot->id) << 16);
      else
              regs &= ~((0x1 << slot->id) << 16);
@@ -1321,6 +1322,18 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
      return err;
 }
 
+int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+     struct dw_mci_slot *slot = mmc_priv(mmc);
+     struct dw_mci *host = slot->host;
+     const struct dw_mci_drv_data *drv_data = host->drv_data;
+
+     if (drv_data && drv_data->prepare_hs400_tuning)
+             return drv_data->prepare_hs400_tuning(host, ios);
+
+     return 0;
+}
+
 static const struct mmc_host_ops dw_mci_ops = {
      .request                = dw_mci_request,
      .pre_req                = dw_mci_pre_req,
@@ -1333,6 +1346,7 @@ static const struct mmc_host_ops dw_mci_ops = {
      .card_busy              = dw_mci_card_busy,
      .start_signal_voltage_switch = dw_mci_switch_voltage,
      .init_card              = dw_mci_init_card,
+     .prepare_hs400_tuning   = dw_mci_prepare_hs400_tuning,
 };
 
 static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
drivers/mmc/host/dw_mmc.h +2 -0
index 18c4afe..d239867 100644
@@ -271,5 +271,7 @@ struct dw_mci_drv_data {
      void            (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
      int             (*parse_dt)(struct dw_mci *host);
      int             (*execute_tuning)(struct dw_mci_slot *slot);
+     int             (*prepare_hs400_tuning)(struct dw_mci *host,
+                                             struct mmc_ios *ios);
 };
 #endif /* _DW_MMC_H_ */
Signature · 2 lines
Regards,
Alim
author reviewer
#4 lore raw

PATCH v4 2/2 ARM: dts: Add HS400 support for exynos5420 and exynos5800

In reply to Alim Akhtar

From: Seungwon Jeon <[email protected]>

HS400 timing values are added for SMDK5420, exynos5420-peach-pit and exynos5800-peach-pi boards.
This also adds RCLK GPIO line, this gpio should be in pull-down state.

[Alim: addressed review comments]
---
 arch/arm/boot/dts/exynos5420-peach-pit.dts |    4 +++-
 arch/arm/boot/dts/exynos5420-pinctrl.dtsi  |    7 +++++++
 arch/arm/boot/dts/exynos5420-smdk5420.dts  |    4 +++-
 arch/arm/boot/dts/exynos5800-peach-pi.dts  |    4 +++-
 4 files changed, 16 insertions(+), 3 deletions(-)
arch/arm/boot/dts/exynos5420-peach-pit.dts +3 -1
index 9a050e1..7ffaba8 100644
@@ -569,8 +569,10 @@
 	samsung,dw-mshc-ciu-div = <3>;
 	samsung,dw-mshc-sdr-timing = <0 4>;
 	samsung,dw-mshc-ddr-timing = <0 2>;
+	samsung,dw-mshc-hs400-timing = <0 2>;
+	read-strobe-delay = <90>;
 	pinctrl-names = "default";
-	pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+	pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
 	bus-width = <8>;
 };
 
arch/arm/boot/dts/exynos5420-pinctrl.dtsi +7 -0
index ba686e4..8b15316 100644
@@ -201,6 +201,13 @@
 			samsung,pin-drv = <3>;
 		};
 
+		sd0_rclk: sd0-rclk {
+			samsung,pins = "gpc0-7";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <1>;
+			samsung,pin-drv = <3>;
+		};
+
 		sd1_cmd: sd1-cmd {
 			samsung,pins = "gpc1-1";
 			samsung,pin-function = <2>;
arch/arm/boot/dts/exynos5420-smdk5420.dts +3 -1
index 8be3d7b..5290e79 100644
@@ -80,8 +80,10 @@
 		samsung,dw-mshc-ciu-div = <3>;
 		samsung,dw-mshc-sdr-timing = <0 4>;
 		samsung,dw-mshc-ddr-timing = <0 2>;
+		samsung,dw-mshc-hs400-timing = <0 2>;
+		read-strobe-delay = <90>;
 		pinctrl-names = "default";
-		pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+		pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
 		bus-width = <8>;
 		cap-mmc-highspeed;
 	};
arch/arm/boot/dts/exynos5800-peach-pi.dts +3 -1
index e8fdda8..fa1c858 100644
@@ -557,8 +557,10 @@
 	samsung,dw-mshc-ciu-div = <3>;
 	samsung,dw-mshc-sdr-timing = <0 4>;
 	samsung,dw-mshc-ddr-timing = <0 2>;
+	samsung,dw-mshc-hs400-timing = <0 2>;
+	read-strobe-delay = <90>;
 	pinctrl-names = "default";
-	pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+	pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
 	bus-width = <8>;
 };
 
Signature · 1 line
1.7.9.5
maintainer
#5 lore raw

PATCH v4 2/2 ARM: dts: Add HS400 support for exynos5420 and exynos5800

Hi,

If you want to enable the hs400 mode, need to add "mmc-hs400-1_8v" or "mmc-hs400-1_2v". But this patch didn't add them. do you have any other plan?

Quoted 38 lines · Alim Akhtar

From: Seungwon Jeon <[email protected]>

HS400 timing values are added for SMDK5420, exynos5420-peach-pit and exynos5800-peach-pi boards.
This also adds RCLK GPIO line, this gpio should be in pull-down state.

[Alim: addressed review comments]
---
 arch/arm/boot/dts/exynos5420-peach-pit.dts |    4 +++-
 arch/arm/boot/dts/exynos5420-pinctrl.dtsi  |    7 +++++++
 arch/arm/boot/dts/exynos5420-smdk5420.dts  |    4 +++-
 arch/arm/boot/dts/exynos5800-peach-pi.dts  |    4 +++-
 4 files changed, 16 insertions(+), 3 deletions(-)
arch/arm/boot/dts/exynos5420-peach-pit.dts +3 -1
index 9a050e1..7ffaba8 100644
@@ -569,8 +569,10 @@
 	samsung,dw-mshc-ciu-div = <3>;
 	samsung,dw-mshc-sdr-timing = <0 4>;
 	samsung,dw-mshc-ddr-timing = <0 2>;
+	samsung,dw-mshc-hs400-timing = <0 2>;
+	read-strobe-delay = <90>;
 	pinctrl-names = "default";
-	pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+	pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
 	bus-width = <8>;
 };
 
arch/arm/boot/dts/exynos5420-pinctrl.dtsi +0 -0
index ba686e4..8b15316 100644

arch/arm/boot/dts/exynos5420-pinctrl.dtsi line 204

Quoted 4 lines
arch/arm/boot/dts/exynos5420-pinctrl.dtsi +1 -0
@@ -201,6 +201,13 @@
 			samsung,pin-drv = <3>;
 		};
 
+		sd0_rclk: sd0-rclk {

I know it used to "sd0_rdqs", not "sd0_rclk".
Change name.

Best Regards,
Jaehoon Chung

Quoted 42 lines
arch/arm/boot/dts/exynos5420-pinctrl.dtsi +6 -0
+			samsung,pins = "gpc0-7";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <1>;
+			samsung,pin-drv = <3>;
+		};
+
 		sd1_cmd: sd1-cmd {
 			samsung,pins = "gpc1-1";
 			samsung,pin-function = <2>;
arch/arm/boot/dts/exynos5420-smdk5420.dts +3 -1
index 8be3d7b..5290e79 100644
@@ -80,8 +80,10 @@
 		samsung,dw-mshc-ciu-div = <3>;
 		samsung,dw-mshc-sdr-timing = <0 4>;
 		samsung,dw-mshc-ddr-timing = <0 2>;
+		samsung,dw-mshc-hs400-timing = <0 2>;
+		read-strobe-delay = <90>;
 		pinctrl-names = "default";
-		pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+		pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
 		bus-width = <8>;
 		cap-mmc-highspeed;
 	};
arch/arm/boot/dts/exynos5800-peach-pi.dts +3 -1
index e8fdda8..fa1c858 100644
@@ -557,8 +557,10 @@
 	samsung,dw-mshc-ciu-div = <3>;
 	samsung,dw-mshc-sdr-timing = <0 4>;
 	samsung,dw-mshc-ddr-timing = <0 2>;
+	samsung,dw-mshc-hs400-timing = <0 2>;
+	read-strobe-delay = <90>;
 	pinctrl-names = "default";
-	pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+	pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
 	bus-width = <8>;
 };
 
#6 lore raw

PATCH v4 2/2 ARM: dts: Add HS400 support for exynos5420 and exynos5800

Hi Jaehoon

Quoted 5 lines · Jaehoon Chung

Hi,

If you want to enable the hs400 mode, need to add "mmc-hs400-1_8v" or "mmc-hs400-1_2v". But this patch didn't add them. do you have any other plan?

Yes, right, plan is to send separate patch to enable hs400, as of now I am not sure if all the 5800-peach-pi boards are populated with emmc5.0 device or not. So I will enable HS400 after confirming this point.

Quoted 42 lines · Alim Akhtar
Quoted 41 lines

From: Seungwon Jeon <[email protected]>

HS400 timing values are added for SMDK5420, exynos5420-peach-pit and exynos5800-peach-pi boards.
This also adds RCLK GPIO line, this gpio should be in pull-down state.

[Alim: addressed review comments]
---
 arch/arm/boot/dts/exynos5420-peach-pit.dts |    4 +++-
 arch/arm/boot/dts/exynos5420-pinctrl.dtsi  |    7 +++++++
 arch/arm/boot/dts/exynos5420-smdk5420.dts  |    4 +++-
 arch/arm/boot/dts/exynos5800-peach-pi.dts  |    4 +++-
 4 files changed, 16 insertions(+), 3 deletions(-)
arch/arm/boot/dts/exynos5420-peach-pit.dts +3 -1
index 9a050e1..7ffaba8 100644
@@ -569,8 +569,10 @@
      samsung,dw-mshc-ciu-div = <3>;
      samsung,dw-mshc-sdr-timing = <0 4>;
      samsung,dw-mshc-ddr-timing = <0 2>;
+     samsung,dw-mshc-hs400-timing = <0 2>;
+     read-strobe-delay = <90>;
      pinctrl-names = "default";
-     pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+     pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
      bus-width = <8>;
 };
 
arch/arm/boot/dts/exynos5420-pinctrl.dtsi +0 -0
index ba686e4..8b15316 100644
@@ -201,6 +201,13 @@
                      samsung,pin-drv = <3>;
              };
 
Quoted 5 lines

arch/arm/boot/dts/exynos5420-pinctrl.dtsi line 204

Quoted 1 line
arch/arm/boot/dts/exynos5420-pinctrl.dtsi +1 -0
+             sd0_rclk: sd0-rclk {

I know it used to "sd0_rdqs", not "sd0_rclk".
Change name.

Ok, I will change as per UM of 5800/5420,

Quoted 45 lines

Best Regards,
Jaehoon Chung

Quoted 42 lines
arch/arm/boot/dts/exynos5420-pinctrl.dtsi +6 -0
+                     samsung,pins = "gpc0-7";
+                     samsung,pin-function = <2>;
+                     samsung,pin-pud = <1>;
+                     samsung,pin-drv = <3>;
+             };
+
              sd1_cmd: sd1-cmd {
                      samsung,pins = "gpc1-1";
                      samsung,pin-function = <2>;
arch/arm/boot/dts/exynos5420-smdk5420.dts +3 -1
index 8be3d7b..5290e79 100644
@@ -80,8 +80,10 @@
              samsung,dw-mshc-ciu-div = <3>;
              samsung,dw-mshc-sdr-timing = <0 4>;
              samsung,dw-mshc-ddr-timing = <0 2>;
+             samsung,dw-mshc-hs400-timing = <0 2>;
+             read-strobe-delay = <90>;
              pinctrl-names = "default";
-             pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+             pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
              bus-width = <8>;
              cap-mmc-highspeed;
      };
arch/arm/boot/dts/exynos5800-peach-pi.dts +3 -1
index e8fdda8..fa1c858 100644
@@ -557,8 +557,10 @@
      samsung,dw-mshc-ciu-div = <3>;
      samsung,dw-mshc-sdr-timing = <0 4>;
      samsung,dw-mshc-ddr-timing = <0 2>;
+     samsung,dw-mshc-hs400-timing = <0 2>;
+     read-strobe-delay = <90>;
      pinctrl-names = "default";
-     pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+     pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
      bus-width = <8>;
 };
 
Signature · 2 lines
Regards,
Alim
maintainer
#7 lore raw

PATCH v4 2/2 ARM: dts: Add HS400 support for exynos5420 and exynos5800

Hi.

Quoted 5 lines · Alim Akhtar

Hi Jaehoon

Quoted 2 lines · Jaehoon Chung

Hi,

Quoted 7 lines
Quoted 3 lines

If you want to enable the hs400 mode, need to add "mmc-hs400-1_8v" or "mmc-hs400-1_2v". But this patch didn't add them. do you have any other plan?

Yes, right, plan is to send separate patch to enable hs400, as of now I am not sure if all the 5800-peach-pi boards are populated with emmc5.0 device or not. So I will enable HS400 after confirming this point.

I know if card is not support hs400, then it should be enabled to other bus mode.

Best Regards,
Jaehoon Chung

Quoted 97 lines
Quoted 42 lines · Alim Akhtar
Quoted 41 lines

From: Seungwon Jeon <[email protected]>

HS400 timing values are added for SMDK5420, exynos5420-peach-pit and exynos5800-peach-pi boards.
This also adds RCLK GPIO line, this gpio should be in pull-down state.

[Alim: addressed review comments]
---
 arch/arm/boot/dts/exynos5420-peach-pit.dts |    4 +++-
 arch/arm/boot/dts/exynos5420-pinctrl.dtsi  |    7 +++++++
 arch/arm/boot/dts/exynos5420-smdk5420.dts  |    4 +++-
 arch/arm/boot/dts/exynos5800-peach-pi.dts  |    4 +++-
 4 files changed, 16 insertions(+), 3 deletions(-)
arch/arm/boot/dts/exynos5420-peach-pit.dts +3 -1
index 9a050e1..7ffaba8 100644
@@ -569,8 +569,10 @@
      samsung,dw-mshc-ciu-div = <3>;
      samsung,dw-mshc-sdr-timing = <0 4>;
      samsung,dw-mshc-ddr-timing = <0 2>;
+     samsung,dw-mshc-hs400-timing = <0 2>;
+     read-strobe-delay = <90>;
      pinctrl-names = "default";
-     pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+     pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
      bus-width = <8>;
 };
 
arch/arm/boot/dts/exynos5420-pinctrl.dtsi +0 -0
index ba686e4..8b15316 100644
@@ -201,6 +201,13 @@
                      samsung,pin-drv = <3>;
              };
 
Quoted 5 lines

arch/arm/boot/dts/exynos5420-pinctrl.dtsi line 204

Quoted 1 line
arch/arm/boot/dts/exynos5420-pinctrl.dtsi +1 -0
+             sd0_rclk: sd0-rclk {

I know it used to "sd0_rdqs", not "sd0_rclk".
Change name.

Ok, I will change as per UM of 5800/5420,

Quoted 45 lines

Best Regards,
Jaehoon Chung

Quoted 42 lines
arch/arm/boot/dts/exynos5420-pinctrl.dtsi +6 -0
+                     samsung,pins = "gpc0-7";
+                     samsung,pin-function = <2>;
+                     samsung,pin-pud = <1>;
+                     samsung,pin-drv = <3>;
+             };
+
              sd1_cmd: sd1-cmd {
                      samsung,pins = "gpc1-1";
                      samsung,pin-function = <2>;
arch/arm/boot/dts/exynos5420-smdk5420.dts +3 -1
index 8be3d7b..5290e79 100644
@@ -80,8 +80,10 @@
              samsung,dw-mshc-ciu-div = <3>;
              samsung,dw-mshc-sdr-timing = <0 4>;
              samsung,dw-mshc-ddr-timing = <0 2>;
+             samsung,dw-mshc-hs400-timing = <0 2>;
+             read-strobe-delay = <90>;
              pinctrl-names = "default";
-             pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+             pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
              bus-width = <8>;
              cap-mmc-highspeed;
      };
arch/arm/boot/dts/exynos5800-peach-pi.dts +3 -1
index e8fdda8..fa1c858 100644
@@ -557,8 +557,10 @@
      samsung,dw-mshc-ciu-div = <3>;
      samsung,dw-mshc-sdr-timing = <0 4>;
      samsung,dw-mshc-ddr-timing = <0 2>;
+     samsung,dw-mshc-hs400-timing = <0 2>;
+     read-strobe-delay = <90>;
      pinctrl-names = "default";
-     pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+     pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
      bus-width = <8>;
 };
 
#8 lore raw

PATCH v4 2/2 ARM: dts: Add HS400 support for exynos5420 and exynos5800

Hi Jaehoon,

Thanks for review.

Quoted 11 lines · Jaehoon Chung

Hi.

Quoted 8 lines · Alim Akhtar

Hi Jaehoon

Quoted 5 lines · Jaehoon Chung

Hi,

If you want to enable the hs400 mode, need to add "mmc-hs400-1_8v" or "mmc-hs400-1_2v". But this patch didn't add them. do you have any other plan?

Quoted 7 lines
Quoted 4 lines

Yes, right, plan is to send separate patch to enable hs400, as of now I am not sure if all the 5800-peach-pi boards are populated with emmc5.0 device or not. So I will enable HS400 after confirming this point.

I know if card is not support hs400, then it should be enabled to other bus mode.

hmm...mmc-hs{200/400}-1_8v are host capabilities, so host should first support this, then we can enable it.
ok, I will enable HS400 for peach-pi in this series.
Also I checked UMs for 5420/5800, in UM, strobe signal is named as RCLK, so going to keep the same name as UM.
Will resend the patches after modification shortly.

Quoted 101 lines

Best Regards,
Jaehoon Chung

Quoted 97 lines
Quoted 42 lines · Alim Akhtar
Quoted 41 lines

From: Seungwon Jeon <[email protected]>

HS400 timing values are added for SMDK5420, exynos5420-peach-pit and exynos5800-peach-pi boards.
This also adds RCLK GPIO line, this gpio should be in pull-down state.

[Alim: addressed review comments]
---
 arch/arm/boot/dts/exynos5420-peach-pit.dts |    4 +++-
 arch/arm/boot/dts/exynos5420-pinctrl.dtsi  |    7 +++++++
 arch/arm/boot/dts/exynos5420-smdk5420.dts  |    4 +++-
 arch/arm/boot/dts/exynos5800-peach-pi.dts  |    4 +++-
 4 files changed, 16 insertions(+), 3 deletions(-)
arch/arm/boot/dts/exynos5420-peach-pit.dts +3 -1
index 9a050e1..7ffaba8 100644
@@ -569,8 +569,10 @@
      samsung,dw-mshc-ciu-div = <3>;
      samsung,dw-mshc-sdr-timing = <0 4>;
      samsung,dw-mshc-ddr-timing = <0 2>;
+     samsung,dw-mshc-hs400-timing = <0 2>;
+     read-strobe-delay = <90>;
      pinctrl-names = "default";
-     pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+     pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
      bus-width = <8>;
 };
 
arch/arm/boot/dts/exynos5420-pinctrl.dtsi +0 -0
index ba686e4..8b15316 100644
@@ -201,6 +201,13 @@
                      samsung,pin-drv = <3>;
              };
 
Quoted 5 lines

arch/arm/boot/dts/exynos5420-pinctrl.dtsi line 204

Quoted 1 line
arch/arm/boot/dts/exynos5420-pinctrl.dtsi +1 -0
+             sd0_rclk: sd0-rclk {

I know it used to "sd0_rdqs", not "sd0_rclk".
Change name.

Ok, I will change as per UM of 5800/5420,

Quoted 45 lines

Best Regards,
Jaehoon Chung

Quoted 42 lines
arch/arm/boot/dts/exynos5420-pinctrl.dtsi +6 -0
+                     samsung,pins = "gpc0-7";
+                     samsung,pin-function = <2>;
+                     samsung,pin-pud = <1>;
+                     samsung,pin-drv = <3>;
+             };
+
              sd1_cmd: sd1-cmd {
                      samsung,pins = "gpc1-1";
                      samsung,pin-function = <2>;
arch/arm/boot/dts/exynos5420-smdk5420.dts +3 -1
index 8be3d7b..5290e79 100644
@@ -80,8 +80,10 @@
              samsung,dw-mshc-ciu-div = <3>;
              samsung,dw-mshc-sdr-timing = <0 4>;
              samsung,dw-mshc-ddr-timing = <0 2>;
+             samsung,dw-mshc-hs400-timing = <0 2>;
+             read-strobe-delay = <90>;
              pinctrl-names = "default";
-             pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+             pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
              bus-width = <8>;
              cap-mmc-highspeed;
      };
arch/arm/boot/dts/exynos5800-peach-pi.dts +3 -1
index e8fdda8..fa1c858 100644
@@ -557,8 +557,10 @@
      samsung,dw-mshc-ciu-div = <3>;
      samsung,dw-mshc-sdr-timing = <0 4>;
      samsung,dw-mshc-ddr-timing = <0 2>;
+     samsung,dw-mshc-hs400-timing = <0 2>;
+     read-strobe-delay = <90>;
      pinctrl-names = "default";
-     pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+     pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
      bus-width = <8>;
 };
 
Signature · 2 lines
Regards,
Alim
maintainer
#9 lore raw

v4 cover mmc: dw_mmc: exynos: Add HS400 support

In reply to Alim Akhtar

Hi, Alim.

Quoted 6 lines · Alim Akhtar

This adds HS400 mode support for exynos dw_mmc host controller.

Currently tested on Exynos5800-peach-pi platform for HS400 mode. Tested HS200 mode with this series applied, HS200 still works.

Appreciate testing on other exynos5/7 platform which supports emmc5.0

I will test this patch on exynos5/7 board.

Best Regards,
Jaehoon Chung

Quoted 26 lines

Changes in V4:
* drop the idea of changing existing binding for ciu_div as per [1]
* addressed comments from Jaehoon Chung [2]

[1] http://www.spinics.net/lists/linux-samsung-soc/msg40923.html
[2] http://www.spinics.net/lists/devicetree/msg64373.html

Changes in V3:
rebased on ulf's next (commit: 607b448 mmc: core: Make tuning block patterns static)

Seungwon Jeon (2):
mmc: dw_mmc: exynos: Support eMMC's HS400 mode
ARM: dts: Add HS400 support for exynos5420 and exynos5800

 .../devicetree/bindings/mmc/exynos-dw-mshc.txt     |    7 +
 arch/arm/boot/dts/exynos5420-peach-pit.dts         |    4 +-
 arch/arm/boot/dts/exynos5420-pinctrl.dtsi          |    7 +
 arch/arm/boot/dts/exynos5420-smdk5420.dts          |    4 +-
 arch/arm/boot/dts/exynos5800-peach-pi.dts          |    4 +-
 drivers/mmc/host/dw_mmc-exynos.c                   |  187 ++++++++++++++++----
 drivers/mmc/host/dw_mmc-exynos.h                   |   19 +-
 drivers/mmc/host/dw_mmc.c                          |   16 +-
 drivers/mmc/host/dw_mmc.h                          |    2 +
 9 files changed, 212 insertions(+), 38 deletions(-)
#10 lore raw

v4 cover mmc: dw_mmc: exynos: Add HS400 support

Quoted 12 lines · Jaehoon Chung

Hi, Alim.

Quoted 6 lines · Alim Akhtar

This adds HS400 mode support for exynos dw_mmc host controller.

Currently tested on Exynos5800-peach-pi platform for HS400 mode. Tested HS200 mode with this series applied, HS200 still works.

Appreciate testing on other exynos5/7 platform which supports emmc5.0

I will test this patch on exynos5/7 board.

What's the result? :-) If it's OK, I'll take DT changes for exynos stuff, I'm not sure about the driver changes though...

Thanks,
Kukjin

Quoted 27 lines

Best Regards,
Jaehoon Chung

Quoted 25 lines

Changes in V4:
* drop the idea of changing existing binding for ciu_div as per [1]
* addressed comments from Jaehoon Chung [2]

[1] http://www.spinics.net/lists/linux-samsung-soc/msg40923.html
[2] http://www.spinics.net/lists/devicetree/msg64373.html

Changes in V3:
rebased on ulf's next (commit: 607b448 mmc: core: Make tuning block patterns static)

Seungwon Jeon (2):
mmc: dw_mmc: exynos: Support eMMC's HS400 mode
ARM: dts: Add HS400 support for exynos5420 and exynos5800

 .../devicetree/bindings/mmc/exynos-dw-mshc.txt     |    7 +
 arch/arm/boot/dts/exynos5420-peach-pit.dts         |    4 +-
 arch/arm/boot/dts/exynos5420-pinctrl.dtsi          |    7 +
 arch/arm/boot/dts/exynos5420-smdk5420.dts          |    4 +-
 arch/arm/boot/dts/exynos5800-peach-pi.dts          |    4 +-
 drivers/mmc/host/dw_mmc-exynos.c                   |  187 ++++++++++++++++----
 drivers/mmc/host/dw_mmc-exynos.h                   |   19 +-
 drivers/mmc/host/dw_mmc.c                          |   16 +-
 drivers/mmc/host/dw_mmc.h                          |    2 +
 9 files changed, 212 insertions(+), 38 deletions(-)
#11 lore raw

v4 cover mmc: dw_mmc: exynos: Add HS400 support

Quoted 9 lines · Kukjin Kim
Quoted 8 lines · Jaehoon Chung

Hi, Alim.

Quoted 5 lines · Alim Akhtar

This adds HS400 mode support for exynos dw_mmc host controller.

Currently tested on Exynos5800-peach-pi platform for HS400 mode. Tested HS200 mode with this series applied, HS200 still works.

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

Appreciate testing on other exynos5/7 platform which supports emmc5.0

I will test this patch on exynos5/7 board.

What's the result? :-) If it's OK, I'll take DT changes for exynos stuff, I'm not sure about the driver changes though...

Kukjin,

As I understand it, there is a dependency between the patches, since driver adds supports for new DT bindings.

So, unless I am mistaken I think it would be best to take this complete patchset through my mmc tree. With your ack of course.

Kind regards
Uffe