All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps
@ 2017-05-15  6:06 Ziyuan Xu
  2017-05-15  6:06 ` [U-Boot] [PATCH 02/33] mmc: add set_timing entry for timing selection Ziyuan Xu
                   ` (32 more replies)
  0 siblings, 33 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:06 UTC (permalink / raw)
  To: u-boot

The original implementation select HS timing by default, add available
type selection for higher speed mode compatibility, such as hs200,
hs400, hs400es.

By the way, we assume that card run at 1.8V or 1.2V I/O when its timing
is ddr52/hs200/hs400(es).

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/mmc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 include/mmc.h     | 16 +++++++++++++++
 2 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 72fc177..f5b2280 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -546,10 +546,62 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
 
 }
 
+static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd)
+{
+	u8 card_type;
+	u32 host_caps, avail_type = 0;
+
+	card_type = ext_csd[EXT_CSD_CARD_TYPE];
+	host_caps = mmc->cfg->host_caps;
+
+	if ((host_caps & MMC_MODE_HS) &&
+	    (card_type & EXT_CSD_CARD_TYPE_26))
+		avail_type |= EXT_CSD_CARD_TYPE_26;
+
+	if ((host_caps & MMC_MODE_HS) &&
+	    (card_type & EXT_CSD_CARD_TYPE_52))
+		avail_type |= EXT_CSD_CARD_TYPE_52;
+
+	/*
+	 * For the moment, u-boot doesn't support signal voltage
+	 * switch, therefor we assume that host support ddr52
+	 * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and
+	 * hs400 are the same).
+	 */
+	if ((host_caps & MMC_MODE_DDR_52MHz) &&
+	    (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V))
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
+
+	if ((host_caps & MMC_MODE_HS200) &&
+	    (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V))
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
+
+	/*
+	 * If host can support HS400, it means that host can also
+	 * support HS200.
+	 */
+	if ((host_caps & MMC_MODE_HS400) &&
+	    (host_caps & MMC_MODE_8BIT) &&
+	    (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
+				EXT_CSD_CARD_TYPE_HS400_1_8V;
+
+	if ((host_caps & MMC_MODE_HS400ES) &&
+	    (host_caps & MMC_MODE_8BIT) &&
+	    ext_csd[EXT_CSD_STROBE_SUPPORT] &&
+	    (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
+				EXT_CSD_CARD_TYPE_HS400_1_8V |
+				EXT_CSD_CARD_TYPE_HS400ES;
+
+	return avail_type;
+}
+
 static int mmc_change_freq(struct mmc *mmc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
 	char cardtype;
+	u32 avail_type;
 	int err;
 
 	mmc->card_caps = 0;
@@ -569,8 +621,13 @@ static int mmc_change_freq(struct mmc *mmc)
 		return err;
 
 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
+	avail_type = mmc_select_card_type(mmc, ext_csd);
 
-	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
+	if (avail_type & EXT_CSD_CARD_TYPE_HS)
+		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_HS_TIMING, 1);
+	else
+		err = -EINVAL;
 
 	if (err)
 		return err;
diff --git a/include/mmc.h b/include/mmc.h
index fad12d6..0bae1a1 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -58,6 +58,9 @@
 #define MMC_MODE_8BIT		(1 << 3)
 #define MMC_MODE_SPI		(1 << 4)
 #define MMC_MODE_DDR_52MHz	(1 << 5)
+#define MMC_MODE_HS200		(1 << 6)
+#define MMC_MODE_HS400		(1 << 7)
+#define MMC_MODE_HS400ES	(1 << 8)
 
 #define SD_DATA_4BIT	0x00040000
 
@@ -182,6 +185,7 @@
 #define EXT_CSD_BOOT_BUS_WIDTH		177
 #define EXT_CSD_PART_CONF		179	/* R/W */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
+#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
 #define EXT_CSD_REV			192	/* RO */
 #define EXT_CSD_CARD_TYPE		196	/* RO */
@@ -201,6 +205,18 @@
 
 #define EXT_CSD_CARD_TYPE_26	(1 << 0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_52	(1 << 1)	/* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_26 | \
+				 EXT_CSD_CARD_TYPE_52)
+#define EXT_CSD_CARD_TYPE_HS200_1_8V	BIT(4)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_2V	BIT(5)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS200_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400_1_8V	BIT(6)	/* Card can run at 200MHz DDR, 1.8V */
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	BIT(7)	/* Card can run at 200MHz DDR, 1.2V */
+#define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS400_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400ES	BIT(8)	/* Card can run@HS400ES */
+
 #define EXT_CSD_CARD_TYPE_DDR_1_8V	(1 << 2)
 #define EXT_CSD_CARD_TYPE_DDR_1_2V	(1 << 3)
 #define EXT_CSD_CARD_TYPE_DDR_52	(EXT_CSD_CARD_TYPE_DDR_1_8V \
-- 
2.7.4

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

* [U-Boot] [PATCH 02/33] mmc: add set_timing entry for timing selection
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
@ 2017-05-15  6:06 ` Ziyuan Xu
  2017-05-15  6:06 ` [U-Boot] [PATCH 03/33] mmc: xenon_sdhci: drop redundant timing definitions Ziyuan Xu
                   ` (31 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:06 UTC (permalink / raw)
  To: u-boot

Some controller should do some configuration according to the selected
timing.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/mmc.c |  7 +++++++
 include/mmc.h     | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+)

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index f5b2280..1b3652a 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -318,6 +318,12 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
 	return blkcnt;
 }
 
+static void mmc_set_timing(struct mmc *mmc, uint timing)
+{
+	mmc->timing = timing;
+	mmc_set_ios(mmc);
+}
+
 static int mmc_go_idle(struct mmc *mmc)
 {
 	struct mmc_cmd cmd;
@@ -1734,6 +1740,7 @@ int mmc_start_init(struct mmc *mmc)
 	mmc->ddr_mode = 0;
 	mmc_set_bus_width(mmc, 1);
 	mmc_set_clock(mmc, 1);
+	mmc_set_timing(mmc, MMC_TIMING_LEGACY);
 
 	/* Reset the Card */
 	err = mmc_go_idle(mmc);
diff --git a/include/mmc.h b/include/mmc.h
index 0bae1a1..68b6790 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -434,6 +434,21 @@ struct mmc {
 	uint has_init;
 	int high_capacity;
 	uint bus_width;
+	uint timing;
+
+#define MMC_TIMING_LEGACY	0
+#define MMC_TIMING_MMC_HS	1
+#define MMC_TIMING_SD_HS	2
+#define MMC_TIMING_UHS_SDR12	3
+#define MMC_TIMING_UHS_SDR25	4
+#define MMC_TIMING_UHS_SDR50	5
+#define MMC_TIMING_UHS_SDR104	6
+#define MMC_TIMING_UHS_DDR50	7
+#define MMC_TIMING_MMC_DDR52	8
+#define MMC_TIMING_MMC_HS200	9
+#define MMC_TIMING_MMC_HS400	10
+#define MMC_TIMING_MMC_HS400ES	11
+
 	uint clock;
 	uint card_caps;
 	uint ocr;
@@ -493,6 +508,40 @@ enum mmc_hwpart_conf_mode {
 	MMC_HWPART_CONF_COMPLETE,
 };
 
+static inline bool mmc_card_hs(struct mmc *mmc)
+{
+	return (mmc->timing == MMC_TIMING_MMC_HS) ||
+		(mmc->timing == MMC_TIMING_SD_HS);
+}
+
+static inline bool mmc_card_ddr(struct mmc *mmc)
+{
+	return (mmc->timing == MMC_TIMING_UHS_DDR50) ||
+		(mmc->timing == MMC_TIMING_MMC_DDR52) ||
+		(mmc->timing == MMC_TIMING_MMC_HS400) ||
+		(mmc->timing == MMC_TIMING_MMC_HS400ES);
+}
+
+static inline bool mmc_card_hs200(struct mmc *mmc)
+{
+	return mmc->timing == MMC_TIMING_MMC_HS200;
+}
+
+static inline bool mmc_card_ddr52(struct mmc *mmc)
+{
+	return mmc->timing == MMC_TIMING_MMC_DDR52;
+}
+
+static inline bool mmc_card_hs400(struct mmc *mmc)
+{
+	return mmc->timing == MMC_TIMING_MMC_HS400;
+}
+
+static inline bool mmc_card_hs400es(struct mmc *mmc)
+{
+	return mmc->timing == MMC_TIMING_MMC_HS400ES;
+}
+
 struct mmc *mmc_create(const struct mmc_config *cfg, void *priv);
 
 /**
-- 
2.7.4

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

* [U-Boot] [PATCH 03/33] mmc: xenon_sdhci: drop redundant timing definitions
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
  2017-05-15  6:06 ` [U-Boot] [PATCH 02/33] mmc: add set_timing entry for timing selection Ziyuan Xu
@ 2017-05-15  6:06 ` Ziyuan Xu
  2017-05-15  6:06 ` [U-Boot] [PATCH 04/33] mmc: rework high speed mode selection Ziyuan Xu
                   ` (30 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:06 UTC (permalink / raw)
  To: u-boot

Remove the redundant mmc timing definitions which have defined in mmc.h.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/xenon_sdhci.c | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c
index 2a0d8b4..f0a33c1 100644
--- a/drivers/mmc/xenon_sdhci.c
+++ b/drivers/mmc/xenon_sdhci.c
@@ -94,18 +94,6 @@ DECLARE_GLOBAL_DATA_PTR;
 /* Hyperion only have one slot 0 */
 #define XENON_MMC_SLOT_ID_HYPERION		0
 
-#define MMC_TIMING_LEGACY	0
-#define MMC_TIMING_MMC_HS	1
-#define MMC_TIMING_SD_HS	2
-#define MMC_TIMING_UHS_SDR12	3
-#define MMC_TIMING_UHS_SDR25	4
-#define MMC_TIMING_UHS_SDR50	5
-#define MMC_TIMING_UHS_SDR104	6
-#define MMC_TIMING_UHS_DDR50	7
-#define MMC_TIMING_MMC_DDR52	8
-#define MMC_TIMING_MMC_HS200	9
-#define MMC_TIMING_MMC_HS400	10
-
 #define XENON_MMC_MAX_CLK	400000000
 
 enum soc_pad_ctrl_type {
-- 
2.7.4

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

* [U-Boot] [PATCH 04/33] mmc: rework high speed mode selection
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
  2017-05-15  6:06 ` [U-Boot] [PATCH 02/33] mmc: add set_timing entry for timing selection Ziyuan Xu
  2017-05-15  6:06 ` [U-Boot] [PATCH 03/33] mmc: xenon_sdhci: drop redundant timing definitions Ziyuan Xu
@ 2017-05-15  6:06 ` Ziyuan Xu
  2017-05-15  6:06 ` [U-Boot] [PATCH 05/33] mmc: sdhci: fix HISPD bit setting Ziyuan Xu
                   ` (29 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:06 UTC (permalink / raw)
  To: u-boot

Select timing parameter for the host since HS mode switch is completed.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/mmc.c | 16 ++++++++++++++--
 include/mmc.h     |  6 ++++++
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 1b3652a..0b30172 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -552,6 +552,19 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
 
 }
 
+static int mmc_select_hs(struct mmc *mmc)
+{
+	int ret;
+
+	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS);
+
+	if (!ret)
+		mmc_set_timing(mmc, MMC_TIMING_MMC_HS);
+
+	return ret;
+}
+
 static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd)
 {
 	u8 card_type;
@@ -630,8 +643,7 @@ static int mmc_change_freq(struct mmc *mmc)
 	avail_type = mmc_select_card_type(mmc, ext_csd);
 
 	if (avail_type & EXT_CSD_CARD_TYPE_HS)
-		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_HS_TIMING, 1);
+		err = mmc_select_hs(mmc);
 	else
 		err = -EINVAL;
 
diff --git a/include/mmc.h b/include/mmc.h
index 68b6790..060c1f8 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -228,6 +228,12 @@
 #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
 #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
 
+#define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
+#define EXT_CSD_TIMING_HS	1	/* High speed */
+#define EXT_CSD_TIMING_HS200	2	/* HS200 */
+#define EXT_CSD_TIMING_HS400	3	/* HS400 */
+#define EXT_CSD_DRV_STR_SHIFT	4	/* Driver Strength shift */
+
 #define EXT_CSD_BOOT_ACK_ENABLE			(1 << 6)
 #define EXT_CSD_BOOT_PARTITION_ENABLE		(1 << 3)
 #define EXT_CSD_PARTITION_ACCESS_ENABLE		(1 << 0)
-- 
2.7.4

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

* [U-Boot] [PATCH 05/33] mmc: sdhci: fix HISPD bit setting
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (2 preceding siblings ...)
  2017-05-15  6:06 ` [U-Boot] [PATCH 04/33] mmc: rework high speed mode selection Ziyuan Xu
@ 2017-05-15  6:06 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 06/33] mmc: add card_busy to query card status Ziyuan Xu
                   ` (28 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:06 UTC (permalink / raw)
  To: u-boot

Configure HISPD bit field according to the timing parameter instead of
the card clock frequency.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/sdhci.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index b745977..58cc0ab 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -457,14 +457,12 @@ static int sdhci_set_ios(struct mmc *mmc)
 			ctrl &= ~SDHCI_CTRL_4BITBUS;
 	}
 
-	if (mmc->clock > 26000000)
+	if (!(mmc->timing == MMC_TIMING_LEGACY) &&
+	    !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
 		ctrl |= SDHCI_CTRL_HISPD;
 	else
 		ctrl &= ~SDHCI_CTRL_HISPD;
 
-	if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)
-		ctrl &= ~SDHCI_CTRL_HISPD;
-
 	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
 	/* If available, call the driver specific "post" set_ios() function */
-- 
2.7.4

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

* [U-Boot] [PATCH 06/33] mmc: add card_busy to query card status
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (3 preceding siblings ...)
  2017-05-15  6:06 ` [U-Boot] [PATCH 05/33] mmc: sdhci: fix HISPD bit setting Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-25 13:02   ` Jaehoon Chung
  2017-05-15  6:07 ` [U-Boot] [PATCH 07/33] mmc: dw_mmc: implement card_busy detection Ziyuan Xu
                   ` (27 subsequent siblings)
  32 siblings, 1 reply; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

Card devices get into busy status since host request speed mode
switch, if host controller is able to query whether the device is busy,
try it instead of sending cmd13.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/mmc-uclass.c | 16 ++++++++++++++++
 drivers/mmc/mmc.c        | 13 +++++++++++++
 include/mmc.h            | 11 +++++++++++
 3 files changed, 40 insertions(+)

diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index 9c07871..a300a6d 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -38,6 +38,22 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
 	return dm_mmc_send_cmd(mmc->dev, cmd, data);
 }
 
+bool mmc_card_busy(struct mmc *mmc)
+{
+	struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev);
+
+	if (!ops->card_busy)
+		return -ENOSYS;
+	return ops->card_busy(mmc->dev);
+}
+
+bool mmc_can_card_busy(struct mmc *mmc)
+{
+	struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev);
+
+	return !!ops->card_busy;
+}
+
 int dm_mmc_set_ios(struct udevice *dev)
 {
 	struct dm_mmc_ops *ops = mmc_get_ops(dev);
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 0b30172..13d8f04 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -1156,6 +1156,19 @@ static void mmc_set_ios(struct mmc *mmc)
 	if (mmc->cfg->ops->set_ios)
 		mmc->cfg->ops->set_ios(mmc);
 }
+
+static bool mmc_card_busy(struct mmc *mmc)
+{
+	if (!mmc->cfg->ops->card_busy)
+		return -ENOSYS;
+
+	return mmc->cfg->ops->card_busy(mmc);
+}
+
+static bool mmc_can_card_busy(struct mmc *)
+{
+	return !!mmc->cfg->ops->card_busy;
+}
 #endif
 
 void mmc_set_clock(struct mmc *mmc, uint clock)
diff --git a/include/mmc.h b/include/mmc.h
index 060c1f8..9bed935 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -357,6 +357,14 @@ struct dm_mmc_ops {
 			struct mmc_data *data);
 
 	/**
+	 * card_busy() - Query the card device status
+	 *
+	 * @dev:	Device to update
+	 * @return true if card device is busy
+	 */
+	bool (*card_busy)(struct udevice *dev);
+
+	/**
 	 * set_ios() - Set the I/O speed/width for an MMC device
 	 *
 	 * @dev:	Device to update
@@ -390,12 +398,15 @@ int dm_mmc_get_cd(struct udevice *dev);
 int dm_mmc_get_wp(struct udevice *dev);
 
 /* Transition functions for compatibility */
+bool mmc_card_busy(struct mmc *mmc);
+bool mmc_can_card_busy(struct mmc *mmc);
 int mmc_set_ios(struct mmc *mmc);
 int mmc_getcd(struct mmc *mmc);
 int mmc_getwp(struct mmc *mmc);
 
 #else
 struct mmc_ops {
+	bool (*card_busy)(struct mmc *mmc);
 	int (*send_cmd)(struct mmc *mmc,
 			struct mmc_cmd *cmd, struct mmc_data *data);
 	int (*set_ios)(struct mmc *mmc);
-- 
2.7.4

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

* [U-Boot] [PATCH 07/33] mmc: dw_mmc: implement card_busy detection
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (4 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 06/33] mmc: add card_busy to query card status Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 08/33] mmc: sdhci: " Ziyuan Xu
                   ` (26 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/dw_mmc.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 700f764..baf2280 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -384,6 +384,26 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)
 }
 
 #ifdef CONFIG_DM_MMC_OPS
+static bool dwmci_card_busy(struct udevice *dev)
+{
+	struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
+static bool dwmci_card_busy(struct mmc *mmc)
+{
+#endif
+	u32 status;
+	struct dwmci_host *host = (struct dwmci_host *)mmc->priv;
+
+	/*
+	 * Check the busy bit which is low when DAT[3:0]
+	 * (the data lines) are 0000
+	 */
+	status = dwmci_readl(host, DWMCI_STATUS);
+
+	return !!(status & DWMCI_BUSY);
+}
+
+#ifdef CONFIG_DM_MMC_OPS
 static int dwmci_set_ios(struct udevice *dev)
 {
 	struct mmc *mmc = mmc_get_mmc_dev(dev);
@@ -475,12 +495,14 @@ int dwmci_probe(struct udevice *dev)
 }
 
 const struct dm_mmc_ops dm_dwmci_ops = {
+	.card_busy	= dwmci_card_busy,
 	.send_cmd	= dwmci_send_cmd,
 	.set_ios	= dwmci_set_ios,
 };
 
 #else
 static const struct mmc_ops dwmci_ops = {
+	.card_busy	= dwmci_card_busy,
 	.send_cmd	= dwmci_send_cmd,
 	.set_ios	= dwmci_set_ios,
 	.init		= dwmci_init,
-- 
2.7.4

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

* [U-Boot] [PATCH 08/33] mmc: sdhci: implement card_busy detection
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (5 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 07/33] mmc: dw_mmc: implement card_busy detection Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 09/33] mmc: rework mmc_switch for non-send_status scenario Ziyuan Xu
                   ` (25 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/sdhci.c | 19 +++++++++++++++++++
 include/sdhci.h     |  1 +
 2 files changed, 20 insertions(+)

diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 58cc0ab..48bac04 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -424,6 +424,23 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 }
 
 #ifdef CONFIG_DM_MMC_OPS
+static bool sdhci_card_busy(struct udevice *dev)
+{
+	struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
+static bool sdhci_card_busy(struct mmc *mmc)
+{
+#endif
+	struct sdhci_host *host = mmc->priv;
+	u32 present_state;
+
+	/* Check whether DAT[0] is 0 */
+	present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+
+	return !(present_state & SDHCI_DATA_0_LVL);
+}
+
+#ifdef CONFIG_DM_MMC_OPS
 static int sdhci_set_ios(struct udevice *dev)
 {
 	struct mmc *mmc = mmc_get_mmc_dev(dev);
@@ -510,11 +527,13 @@ int sdhci_probe(struct udevice *dev)
 }
 
 const struct dm_mmc_ops sdhci_ops = {
+	.card_busy	= sdhci_card_busy,
 	.send_cmd	= sdhci_send_command,
 	.set_ios	= sdhci_set_ios,
 };
 #else
 static const struct mmc_ops sdhci_ops = {
+	.card_busy	= sdhci_card_busy,
 	.send_cmd	= sdhci_send_command,
 	.set_ios	= sdhci_set_ios,
 	.init		= sdhci_init,
diff --git a/include/sdhci.h b/include/sdhci.h
index 6a43271..75432db 100644
--- a/include/sdhci.h
+++ b/include/sdhci.h
@@ -64,6 +64,7 @@
 #define  SDHCI_CARD_STATE_STABLE	BIT(17)
 #define  SDHCI_CARD_DETECT_PIN_LEVEL	BIT(18)
 #define  SDHCI_WRITE_PROTECT	BIT(19)
+#define SDHCI_DATA_0_LVL	BIT(20)
 
 #define SDHCI_HOST_CONTROL	0x28
 #define  SDHCI_CTRL_LED		BIT(0)
-- 
2.7.4

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

* [U-Boot] [PATCH 09/33] mmc: rework mmc_switch for non-send_status scenario
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (6 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 08/33] mmc: sdhci: " Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 10/33] mmc: add support for HS200 mode of eMMC4.5 Ziyuan Xu
                   ` (24 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

Per JEDEC spec, it is not recommended to use cmd13 to get card status
after speed mode switch. CMD13 can't be guaranteed due to the
asynchronous operation.

Besieds, if the host controller supports busy detection in HW, we use it
instead of cmd13.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/mmc.c | 55 +++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 45 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 13d8f04..9aee6ff 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -523,10 +523,46 @@ static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
 	return err;
 }
 
-int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
+static int mmc_poll_for_busy(struct mmc *mmc)
 {
 	struct mmc_cmd cmd;
+	u8 busy = true;
+	uint start;
+	int ret;
 	int timeout = 1000;
+
+	cmd.cmdidx = MMC_CMD_SEND_STATUS;
+	cmd.resp_type = MMC_RSP_R1;
+	cmd.cmdarg = mmc->rca << 16;
+
+	start = get_timer(0);
+
+	do {
+		if (mmc_can_card_busy(mmc)) {
+			busy = mmc_card_busy(mmc);
+		} else {
+			ret = mmc_send_cmd(mmc, &cmd, NULL);
+
+			if (ret)
+				return ret;
+
+			if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
+				return -EBADMSG;
+			busy = (cmd.response[0] & MMC_STATUS_CURR_STATE) ==
+				MMC_STATE_PRG;
+		}
+
+		if (get_timer(start) > timeout && busy)
+			return -ETIMEDOUT;
+	} while (busy);
+
+	return 0;
+}
+
+static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
+			u8 send_status)
+{
+	struct mmc_cmd cmd;
 	int retries = 3;
 	int ret;
 
@@ -536,20 +572,19 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
 				 (index << 16) |
 				 (value << 8);
 
-	while (retries > 0) {
+	do {
 		ret = mmc_send_cmd(mmc, &cmd, NULL);
 
-		/* Waiting for the ready status */
-		if (!ret) {
-			ret = mmc_send_status(mmc, timeout);
-			return ret;
-		}
-
-		retries--;
-	}
+		if (!ret && send_status)
+			return mmc_poll_for_busy(mmc);
+	} while (--retries > 0 && ret);
 
 	return ret;
+}
 
+int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
+{
+	return __mmc_switch(mmc, set, index, value, true);
 }
 
 static int mmc_select_hs(struct mmc *mmc)
-- 
2.7.4

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

* [U-Boot] [PATCH 10/33] mmc: add support for HS200 mode of eMMC4.5
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (7 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 09/33] mmc: rework mmc_switch for non-send_status scenario Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 11/33] mmc: rework ddr mode judgement with timing Ziyuan Xu
                   ` (23 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

Add the support of the HS200 mode for eMMC 4.5 devices. The eMMC 4.5
device has support up to 200MHz bus speed, it can speed up the boot speed.

We can enable this feature via MMC_MODE_HS200 if the host controller has
the ability to support HS200 timing. Also the tuning feature required
when the HS200 mode is selected.

By the way, mmc card can only switch to high speed mode in SPL stage.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/mmc.c | 395 ++++++++++++++++++++++++++++++++++++------------------
 include/mmc.h     |  27 ++++
 2 files changed, 289 insertions(+), 133 deletions(-)

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 9aee6ff..bebf8f3 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -318,6 +318,26 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
 	return blkcnt;
 }
 
+void mmc_set_clock(struct mmc *mmc, uint clock)
+{
+	if (clock > mmc->cfg->f_max)
+		clock = mmc->cfg->f_max;
+
+	if (clock < mmc->cfg->f_min)
+		clock = mmc->cfg->f_min;
+
+	mmc->clock = clock;
+
+	mmc_set_ios(mmc);
+}
+
+static void mmc_set_bus_width(struct mmc *mmc, uint width)
+{
+	mmc->bus_width = width;
+
+	mmc_set_ios(mmc);
+}
+
 static void mmc_set_timing(struct mmc *mmc, uint timing)
 {
 	mmc->timing = timing;
@@ -587,6 +607,181 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
 	return __mmc_switch(mmc, set, index, value, true);
 }
 
+static int mmc_select_bus_width(struct mmc *mmc)
+{
+	u32 ext_csd_bits[] = {
+		EXT_CSD_BUS_WIDTH_8,
+		EXT_CSD_BUS_WIDTH_4,
+	};
+	u32 bus_widths[] = {
+		MMC_BUS_WIDTH_8BIT,
+		MMC_BUS_WIDTH_4BIT,
+	};
+	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
+	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
+	u32 idx, bus_width = 0;
+	int err = 0;
+
+	if (mmc->version < MMC_VERSION_4 ||
+	    !(mmc->cfg->host_caps & (MMC_MODE_4BIT | MMC_MODE_8BIT)))
+		return 0;
+
+	err = mmc_send_ext_csd(mmc, ext_csd);
+
+	if (err)
+		return err;
+
+	idx = (mmc->cfg->host_caps & MMC_MODE_8BIT) ? 0 : 1;
+
+	/*
+	 * Unlike SD, MMC cards dont have a configuration register to notify
+	 * supported bus width. So bus test command should be run to identify
+	 * the supported bus width or compare the ext csd values of current
+	 * bus width and ext csd values of 1 bit mode read earlier.
+	 */
+	for (; idx < ARRAY_SIZE(bus_widths); idx++) {
+		/*
+		 * Host is capable of 8bit transfer, then switch
+		 * the device to work in 8bit transfer mode. If the
+		 * mmc switch command returns error then switch to
+		 * 4bit transfer mode. On success set the corresponding
+		 * bus width on the host.
+		 */
+		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_BUS_WIDTH, ext_csd_bits[idx]);
+		if (err)
+			continue;
+
+		bus_width = bus_widths[idx];
+		mmc_set_bus_width(mmc, bus_width);
+
+		err = mmc_send_ext_csd(mmc, test_csd);
+
+		if (err)
+			continue;
+
+		/* Only compare read only fields */
+		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] ==
+			test_csd[EXT_CSD_PARTITIONING_SUPPORT]) &&
+		    (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
+			test_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
+		    (ext_csd[EXT_CSD_REV] == test_csd[EXT_CSD_REV]) &&
+			(ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
+			test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
+		    !memcmp(&ext_csd[EXT_CSD_SEC_CNT],
+			&test_csd[EXT_CSD_SEC_CNT], 4)) {
+			err = bus_width;
+			break;
+		} else {
+			err = -EBADMSG;
+		}
+	}
+
+	return err;
+}
+
+static const u8 tuning_blk_pattern_4bit[] = {
+	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
+	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
+	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
+	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
+	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
+	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
+	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
+	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
+};
+
+static const u8 tuning_blk_pattern_8bit[] = {
+	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
+	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
+	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
+	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
+	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
+	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
+	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
+	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
+	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
+	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
+	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
+	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
+	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
+	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
+};
+
+int mmc_send_tuning(struct mmc *mmc, u32 opcode)
+{
+	struct mmc_cmd cmd;
+	struct mmc_data data;
+	const u8 *tuning_block_pattern;
+	int size, err = 0;
+	u8 *data_buf;
+
+	if (mmc->bus_width == MMC_BUS_WIDTH_8BIT) {
+		tuning_block_pattern = tuning_blk_pattern_8bit;
+		size = sizeof(tuning_blk_pattern_8bit);
+	} else if (mmc->bus_width == MMC_BUS_WIDTH_4BIT) {
+		tuning_block_pattern = tuning_blk_pattern_4bit;
+		size = sizeof(tuning_blk_pattern_4bit);
+	} else {
+		return -EINVAL;
+	}
+
+	data_buf = calloc(1, size);
+	if (!data_buf)
+		return -ENOMEM;
+
+	cmd.cmdidx = opcode;
+	cmd.resp_type = MMC_RSP_R1;
+	cmd.cmdarg = 0;
+
+	data.dest = (char *)data_buf;
+	data.blocksize = size;
+	data.blocks = 1;
+	data.flags = MMC_DATA_READ;
+
+	err = mmc_send_cmd(mmc, &cmd, &data);
+	if (err)
+		goto out;
+
+	if (memcmp(data_buf, tuning_block_pattern, size))
+		err = -EIO;
+out:
+	free(data_buf);
+	return err;
+}
+
+static int mmc_execute_tuning(struct mmc *mmc)
+{
+#ifdef CONFIG_DM_MMC_OPS
+	struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev);
+#endif
+	u32 opcode;
+
+	if (IS_SD(mmc))
+		opcode = MMC_SEND_TUNING_BLOCK;
+	else
+		opcode = MMC_SEND_TUNING_BLOCK_HS200;
+
+#ifndef CONFIG_DM_MMC_OPS
+	if (mmc->cfg->ops->execute_tuning) {
+		return mmc->cfg->ops->execute_tuning(mmc, opcode);
+#else
+	if (ops->execute_tuning) {
+		return ops->execute_tuning(mmc->dev, opcode);
+#endif
+	} else {
+		debug("Tuning feature required for HS200 mode.\n");
+		return -EIO;
+	}
+}
+
+static int mmc_hs200_tuning(struct mmc *mmc)
+{
+	return mmc_execute_tuning(mmc);
+}
+
 static int mmc_select_hs(struct mmc *mmc)
 {
 	int ret;
@@ -600,6 +795,45 @@ static int mmc_select_hs(struct mmc *mmc)
 	return ret;
 }
 
+#ifndef CONFIG_SPL_BUILD
+static int mmc_select_hs200(struct mmc *mmc)
+{
+	int ret;
+	struct mmc_cmd cmd;
+
+	/*
+	 * Set the bus width(4 or 8) with host's support and
+	 * switch to HS200 mode if bus width is set successfully.
+	 */
+	ret = mmc_select_bus_width(mmc);
+
+	if (ret > 0) {
+		ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+				   EXT_CSD_HS_TIMING,
+				   EXT_CSD_TIMING_HS200, false);
+
+		if (ret)
+			return ret;
+
+		mmc_set_timing(mmc, MMC_TIMING_MMC_HS200);
+
+		cmd.cmdidx = MMC_CMD_SEND_STATUS;
+		cmd.resp_type = MMC_RSP_R1;
+		cmd.cmdarg = mmc->rca << 16;
+
+		ret = mmc_send_cmd(mmc, &cmd, NULL);
+
+		if (ret)
+			return ret;
+
+		if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
+			return -EBADMSG;
+	}
+
+	return ret;
+}
+#endif
+
 static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd)
 {
 	u8 card_type;
@@ -651,10 +885,24 @@ static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd)
 	return avail_type;
 }
 
+static void mmc_set_bus_speed(struct mmc *mmc, u8 avail_type)
+{
+	int clock = 0;
+
+	if (mmc_card_hs(mmc))
+		clock = (avail_type & EXT_CSD_CARD_TYPE_52) ?
+			MMC_HIGH_52_MAX_DTR : MMC_HIGH_26_MAX_DTR;
+	else if (mmc_card_hs200(mmc) ||
+		 mmc_card_hs400(mmc) ||
+		 mmc_card_hs400es(mmc))
+		clock = MMC_HS200_MAX_DTR;
+
+	mmc_set_clock(mmc, clock);
+}
+
 static int mmc_change_freq(struct mmc *mmc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
-	char cardtype;
 	u32 avail_type;
 	int err;
 
@@ -674,9 +922,13 @@ static int mmc_change_freq(struct mmc *mmc)
 	if (err)
 		return err;
 
-	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
 	avail_type = mmc_select_card_type(mmc, ext_csd);
 
+#ifndef CONFIG_SPL_BUILD
+	if (avail_type & EXT_CSD_CARD_TYPE_HS200)
+		err = mmc_select_hs200(mmc);
+	else
+#endif
 	if (avail_type & EXT_CSD_CARD_TYPE_HS)
 		err = mmc_select_hs(mmc);
 	else
@@ -685,26 +937,14 @@ static int mmc_change_freq(struct mmc *mmc)
 	if (err)
 		return err;
 
-	/* Now check to see that it worked */
-	err = mmc_send_ext_csd(mmc, ext_csd);
-
-	if (err)
-		return err;
+	mmc_set_bus_speed(mmc, avail_type);
 
-	/* No high-speed support */
-	if (!ext_csd[EXT_CSD_HS_TIMING])
-		return 0;
-
-	/* High Speed is set, there are two types: 52MHz and 26MHz */
-	if (cardtype & EXT_CSD_CARD_TYPE_52) {
-		if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
-			mmc->card_caps |= MMC_MODE_DDR_52MHz;
-		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
-	} else {
-		mmc->card_caps |= MMC_MODE_HS;
-	}
+	if (mmc_card_hs200(mmc))
+		err = mmc_hs200_tuning(mmc);
+	else
+		err = mmc_select_bus_width(mmc) > 0 ? 0 : err;
 
-	return 0;
+	return err;
 }
 
 static int mmc_set_capacity(struct mmc *mmc, int part_num)
@@ -1206,26 +1446,6 @@ static bool mmc_can_card_busy(struct mmc *)
 }
 #endif
 
-void mmc_set_clock(struct mmc *mmc, uint clock)
-{
-	if (clock > mmc->cfg->f_max)
-		clock = mmc->cfg->f_max;
-
-	if (clock < mmc->cfg->f_min)
-		clock = mmc->cfg->f_min;
-
-	mmc->clock = clock;
-
-	mmc_set_ios(mmc);
-}
-
-static void mmc_set_bus_width(struct mmc *mmc, uint width)
-{
-	mmc->bus_width = width;
-
-	mmc_set_ios(mmc);
-}
-
 static int mmc_startup(struct mmc *mmc)
 {
 	int err, i;
@@ -1233,7 +1453,6 @@ static int mmc_startup(struct mmc *mmc)
 	u64 cmult, csize, capacity;
 	struct mmc_cmd cmd;
 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
-	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
 	bool has_parts = false;
 	bool part_completed;
 	struct blk_desc *bdesc;
@@ -1576,102 +1795,12 @@ static int mmc_startup(struct mmc *mmc)
 			mmc->tran_speed = 50000000;
 		else
 			mmc->tran_speed = 25000000;
-	} else if (mmc->version >= MMC_VERSION_4) {
-		/* Only version 4 of MMC supports wider bus widths */
-		int idx;
-
-		/* An array of possible bus widths in order of preference */
-		static unsigned ext_csd_bits[] = {
-			EXT_CSD_DDR_BUS_WIDTH_8,
-			EXT_CSD_DDR_BUS_WIDTH_4,
-			EXT_CSD_BUS_WIDTH_8,
-			EXT_CSD_BUS_WIDTH_4,
-			EXT_CSD_BUS_WIDTH_1,
-		};
-
-		/* An array to map CSD bus widths to host cap bits */
-		static unsigned ext_to_hostcaps[] = {
-			[EXT_CSD_DDR_BUS_WIDTH_4] =
-				MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
-			[EXT_CSD_DDR_BUS_WIDTH_8] =
-				MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
-			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
-			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
-		};
-
-		/* An array to map chosen bus width to an integer */
-		static unsigned widths[] = {
-			8, 4, 8, 4, 1,
-		};
-
-		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
-			unsigned int extw = ext_csd_bits[idx];
-			unsigned int caps = ext_to_hostcaps[extw];
-
-			/*
-			 * If the bus width is still not changed,
-			 * don't try to set the default again.
-			 * Otherwise, recover from switch attempts
-			 * by switching to 1-bit bus width.
-			 */
-			if (extw == EXT_CSD_BUS_WIDTH_1 &&
-					mmc->bus_width == 1) {
-				err = 0;
-				break;
-			}
-
-			/*
-			 * Check to make sure the card and controller support
-			 * these capabilities
-			 */
-			if ((mmc->card_caps & caps) != caps)
-				continue;
-
-			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
-					EXT_CSD_BUS_WIDTH, extw);
-
-			if (err)
-				continue;
-
-			mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
-			mmc_set_bus_width(mmc, widths[idx]);
 
-			err = mmc_send_ext_csd(mmc, test_csd);
-
-			if (err)
-				continue;
-
-			/* Only compare read only fields */
-			if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
-				== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
-			    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
-				== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
-			    ext_csd[EXT_CSD_REV]
-				== test_csd[EXT_CSD_REV] &&
-			    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
-				== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
-			    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
-				   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
-				break;
-			else
-				err = -EBADMSG;
-		}
-
-		if (err)
-			return err;
-
-		if (mmc->card_caps & MMC_MODE_HS) {
-			if (mmc->card_caps & MMC_MODE_HS_52MHz)
-				mmc->tran_speed = 52000000;
-			else
-				mmc->tran_speed = 26000000;
-		}
+		mmc_set_clock(mmc, mmc->tran_speed);
 	}
 
-	mmc_set_clock(mmc, mmc->tran_speed);
-
 	/* Fix the block length for DDR mode */
-	if (mmc->ddr_mode) {
+	if (mmc_card_ddr(mmc)) {
 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
 	}
diff --git a/include/mmc.h b/include/mmc.h
index 9bed935..a2ef986 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -85,6 +85,8 @@
 #define MMC_CMD_SET_BLOCKLEN		16
 #define MMC_CMD_READ_SINGLE_BLOCK	17
 #define MMC_CMD_READ_MULTIPLE_BLOCK	18
+#define MMC_SEND_TUNING_BLOCK		19
+#define MMC_SEND_TUNING_BLOCK_HS200	21
 #define MMC_CMD_SET_BLOCK_COUNT         23
 #define MMC_CMD_WRITE_SINGLE_BLOCK	24
 #define MMC_CMD_WRITE_MULTIPLE_BLOCK	25
@@ -387,6 +389,17 @@ struct dm_mmc_ops {
 	 * @return 0 if write-enabled, 1 if write-protected, -ve on error
 	 */
 	int (*get_wp)(struct udevice *dev);
+
+	/**
+	 * execute_tuning() - Find the optimal sampling point of a data
+	 *			input signals.
+	 *
+	 * @dev:	Device to check
+	 * @opcode:	The tuning command opcode value is different
+	 *		for SD and eMMC cards
+	 * @return 0 if write-enabled, 1 if write-protected, -ve on error
+	 */
+	int (*execute_tuning)(struct udevice *dev, u32 opcode);
 };
 
 #define mmc_get_ops(dev)        ((struct dm_mmc_ops *)(dev)->driver->ops)
@@ -413,6 +426,7 @@ struct mmc_ops {
 	int (*init)(struct mmc *mmc);
 	int (*getcd)(struct mmc *mmc);
 	int (*getwp)(struct mmc *mmc);
+	int (*execute_tuning)(struct udevice *dev, u32 opcode);
 };
 #endif
 
@@ -451,6 +465,11 @@ struct mmc {
 	uint has_init;
 	int high_capacity;
 	uint bus_width;
+
+#define MMC_BUS_WIDTH_1BIT	1
+#define MMC_BUS_WIDTH_4BIT	4
+#define MMC_BUS_WIDTH_8BIT	8
+
 	uint timing;
 
 #define MMC_TIMING_LEGACY	0
@@ -467,6 +486,12 @@ struct mmc {
 #define MMC_TIMING_MMC_HS400ES	11
 
 	uint clock;
+
+#define MMC_HIGH_26_MAX_DTR	26000000
+#define MMC_HIGH_52_MAX_DTR	52000000
+#define MMC_HIGH_DDR_MAX_DTR	52000000
+#define MMC_HS200_MAX_DTR	200000000
+
 	uint card_caps;
 	uint ocr;
 	uint dsr;
@@ -559,6 +584,8 @@ static inline bool mmc_card_hs400es(struct mmc *mmc)
 	return mmc->timing == MMC_TIMING_MMC_HS400ES;
 }
 
+int mmc_send_tuning(struct mmc *mmc, u32 opcode);
+
 struct mmc *mmc_create(const struct mmc_config *cfg, void *priv);
 
 /**
-- 
2.7.4

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

* [U-Boot] [PATCH 11/33] mmc: rework ddr mode judgement with timing
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (8 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 10/33] mmc: add support for HS200 mode of eMMC4.5 Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 12/33] mmc: remove tran_speed from struct mmc Ziyuan Xu
                   ` (22 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

Since the card device is set the proper timing after speed mode switch
is completed, host driver can get ddr_mode from timing parameter. So
drop the antiquated ddr_mode.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 cmd/mmc.c                 | 2 +-
 drivers/mmc/dw_mmc.c      | 2 +-
 drivers/mmc/fsl_esdhc.c   | 4 ++--
 drivers/mmc/mmc.c         | 3 +--
 drivers/mmc/uniphier-sd.c | 4 ++--
 drivers/mmc/xenon_sdhci.c | 6 +++---
 include/mmc.h             | 1 -
 7 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/cmd/mmc.c b/cmd/mmc.c
index f83032e..ef05fa5 100644
--- a/cmd/mmc.c
+++ b/cmd/mmc.c
@@ -38,7 +38,7 @@ static void print_mmcinfo(struct mmc *mmc)
 	print_size(mmc->capacity, "\n");
 
 	printf("Bus Width: %d-bit%s\n", mmc->bus_width,
-			mmc->ddr_mode ? " DDR" : "");
+			mmc_card_ddr(mmc) ? " DDR" : "");
 
 	puts("Erase Group Size: ");
 	print_size(((u64)mmc->erase_grp_size) << 9, "\n");
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index baf2280..7e9ffc2 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -432,7 +432,7 @@ static int dwmci_set_ios(struct mmc *mmc)
 	dwmci_writel(host, DWMCI_CTYPE, ctype);
 
 	regs = dwmci_readl(host, DWMCI_UHS_REG);
-	if (mmc->ddr_mode)
+	if (mmc_card_ddr(mmc))
 		regs |= DWMCI_DDR_MODE;
 	else
 		regs &= ~DWMCI_DDR_MODE;
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index f3c6358..5a6942e 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -400,7 +400,7 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
 #if defined(CONFIG_FSL_USDHC)
 	esdhc_write32(&regs->mixctrl,
 	(esdhc_read32(&regs->mixctrl) & 0xFFFFFF80) | (xfertyp & 0x7F)
-			| (mmc->ddr_mode ? XFERTYP_DDREN : 0));
+			| (mmc_card_ddr(mmc) ? XFERTYP_DDREN : 0));
 	esdhc_write32(&regs->xfertyp, xfertyp & 0xFFFF0000);
 #else
 	esdhc_write32(&regs->xfertyp, xfertyp);
@@ -541,7 +541,7 @@ static void set_sysctl(struct mmc *mmc, uint clock)
 		if ((sdhc_clk / (div * pre_div)) <= clock)
 			break;
 
-	pre_div >>= mmc->ddr_mode ? 2 : 1;
+	pre_div >>= mmc_card_ddr(mmc) ? 2 : 1;
 	div -= 1;
 
 	clk = (pre_div << 8) | (div << 4);
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index bebf8f3..d47cfe6 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -210,7 +210,7 @@ int mmc_set_blocklen(struct mmc *mmc, int len)
 {
 	struct mmc_cmd cmd;
 
-	if (mmc->ddr_mode)
+	if (mmc_card_ddr(mmc))
 		return 0;
 
 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
@@ -1926,7 +1926,6 @@ int mmc_start_init(struct mmc *mmc)
 	if (err)
 		return err;
 #endif
-	mmc->ddr_mode = 0;
 	mmc_set_bus_width(mmc, 1);
 	mmc_set_clock(mmc, 1);
 	mmc_set_timing(mmc, MMC_TIMING_LEGACY);
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c
index 7f20ef1..ac7359b 100644
--- a/drivers/mmc/uniphier-sd.c
+++ b/drivers/mmc/uniphier-sd.c
@@ -532,7 +532,7 @@ static void uniphier_sd_set_ddr_mode(struct uniphier_sd_priv *priv,
 	u32 tmp;
 
 	tmp = readl(priv->regbase + UNIPHIER_SD_IF_MODE);
-	if (mmc->ddr_mode)
+	if (mmc_card_ddr(mmc))
 		tmp |= UNIPHIER_SD_IF_MODE_DDR;
 	else
 		tmp &= ~UNIPHIER_SD_IF_MODE_DDR;
@@ -599,7 +599,7 @@ static int uniphier_sd_set_ios(struct udevice *dev)
 	int ret;
 
 	dev_dbg(dev, "clock %uHz, DDRmode %d, width %u\n",
-		mmc->clock, mmc->ddr_mode, mmc->bus_width);
+		mmc->clock, mmc_card_ddr(mmc), mmc->bus_width);
 
 	ret = uniphier_sd_set_bus_width(priv, mmc);
 	if (ret)
diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c
index f0a33c1..7685e15 100644
--- a/drivers/mmc/xenon_sdhci.c
+++ b/drivers/mmc/xenon_sdhci.c
@@ -237,7 +237,7 @@ static void xenon_mmc_phy_set(struct sdhci_host *host)
 	sdhci_writew(host, var, SDHCI_CLOCK_CONTROL);
 
 	var = sdhci_readl(host, EMMC_PHY_FUNC_CONTROL);
-	if (host->mmc->ddr_mode) {
+	if (mmc_card_ddr(host->mmc)) {
 		var |= (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE;
 	} else {
 		var &= ~((DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) |
@@ -329,7 +329,7 @@ static void xenon_sdhci_set_ios_post(struct sdhci_host *host)
 	if (IS_SD(host->mmc)) {
 		/* SD/SDIO */
 		if (pwr_18v) {
-			if (host->mmc->ddr_mode)
+			if (mmc_card_ddr(host->mmc))
 				priv->timing = MMC_TIMING_UHS_DDR50;
 			else if (speed <= 25000000)
 				priv->timing = MMC_TIMING_UHS_SDR25;
@@ -343,7 +343,7 @@ static void xenon_sdhci_set_ios_post(struct sdhci_host *host)
 		}
 	} else {
 		/* eMMC */
-		if (host->mmc->ddr_mode)
+		if (mmc_card_ddr(host->mmc))
 			priv->timing = MMC_TIMING_MMC_DDR52;
 		else if (speed <= 26000000)
 			priv->timing = MMC_TIMING_LEGACY;
diff --git a/include/mmc.h b/include/mmc.h
index a2ef986..bde8b37 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -523,7 +523,6 @@ struct mmc {
 	char op_cond_pending;	/* 1 if we are waiting on an op_cond command */
 	char init_in_progress;	/* 1 if we have done mmc_start_init() */
 	char preinit;		/* start init as early as possible */
-	int ddr_mode;
 #ifdef CONFIG_DM_MMC
 	struct udevice *dev;	/* Device for this MMC controller */
 #endif
-- 
2.7.4

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

* [U-Boot] [PATCH 12/33] mmc: remove tran_speed from struct mmc
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (9 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 11/33] mmc: rework ddr mode judgement with timing Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 13/33] cmd: mmc: show the current speed mode Ziyuan Xu
                   ` (21 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

The clock element is updated by mmc_set_clock every time, it denotes the
current transfer speed.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 cmd/mmc.c                 |  2 +-
 drivers/mmc/mmc.c         | 10 +++++-----
 drivers/mmc/xenon_sdhci.c |  2 +-
 include/mmc.h             |  1 -
 4 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/cmd/mmc.c b/cmd/mmc.c
index ef05fa5..6ead27a 100644
--- a/cmd/mmc.c
+++ b/cmd/mmc.c
@@ -23,7 +23,7 @@ static void print_mmcinfo(struct mmc *mmc)
 			(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
 			(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
 
-	printf("Tran Speed: %d\n", mmc->tran_speed);
+	printf("Tran Speed: %d\n", mmc->clock);
 	printf("Rd Block Len: %d\n", mmc->read_bl_len);
 
 	printf("%s version %d.%d", IS_SD(mmc) ? "SD" : "MMC",
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index d47cfe6..953ffd8 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -1449,7 +1449,7 @@ static bool mmc_can_card_busy(struct mmc *)
 static int mmc_startup(struct mmc *mmc)
 {
 	int err, i;
-	uint mult, freq;
+	uint mult, freq, tran_speed;
 	u64 cmult, csize, capacity;
 	struct mmc_cmd cmd;
 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
@@ -1545,7 +1545,7 @@ static int mmc_startup(struct mmc *mmc)
 	freq = fbase[(cmd.response[0] & 0x7)];
 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
 
-	mmc->tran_speed = freq * mult;
+	tran_speed = freq * mult;
 
 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
@@ -1792,11 +1792,11 @@ static int mmc_startup(struct mmc *mmc)
 			return err;
 
 		if (mmc->card_caps & MMC_MODE_HS)
-			mmc->tran_speed = 50000000;
+			tran_speed = 50000000;
 		else
-			mmc->tran_speed = 25000000;
+			tran_speed = 25000000;
 
-		mmc_set_clock(mmc, mmc->tran_speed);
+		mmc_set_clock(mmc, tran_speed);
 	}
 
 	/* Fix the block length for DDR mode */
diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c
index 7685e15..f18dc8f 100644
--- a/drivers/mmc/xenon_sdhci.c
+++ b/drivers/mmc/xenon_sdhci.c
@@ -318,7 +318,7 @@ static void xenon_mask_cmd_conflict_err(struct sdhci_host *host)
 static void xenon_sdhci_set_ios_post(struct sdhci_host *host)
 {
 	struct xenon_sdhci_priv *priv = host->mmc->priv;
-	uint speed = host->mmc->tran_speed;
+	uint speed = host->mmc->clock;
 	int pwr_18v = 0;
 
 	if ((sdhci_readb(host, SDHCI_POWER_CONTROL) & ~SDHCI_POWER_ON) ==
diff --git a/include/mmc.h b/include/mmc.h
index bde8b37..05bf39d 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -504,7 +504,6 @@ struct mmc {
 	u8 part_attr;
 	u8 wr_rel_set;
 	char part_config;
-	uint tran_speed;
 	uint read_bl_len;
 	uint write_bl_len;
 	uint erase_grp_size;	/* in 512-byte sectors */
-- 
2.7.4

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

* [U-Boot] [PATCH 13/33] cmd: mmc: show the current speed mode
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (10 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 12/33] mmc: remove tran_speed from struct mmc Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 14/33] clk: introduce clk_phase get/set function & callback Ziyuan Xu
                   ` (20 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

So far mmc framework had support speed mode switch, it good to show the
current speed mode from 'mmc info'.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 cmd/mmc.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/cmd/mmc.c b/cmd/mmc.c
index 6ead27a..832eeb0 100644
--- a/cmd/mmc.c
+++ b/cmd/mmc.c
@@ -15,6 +15,10 @@ static int curr_device = -1;
 static void print_mmcinfo(struct mmc *mmc)
 {
 	int i;
+	const char *timing[] = {
+		"Legacy", "High Speed", "High Speed", "SDR12",
+		"SDR25", "SDR50", "SDR104", "DDR50",
+		"DDR52", "HS200", "HS400", "HS400 Enhanced Strobe"};
 
 	printf("Device: %s\n", mmc->cfg->name);
 	printf("Manufacturer ID: %x\n", mmc->cid[0] >> 24);
@@ -23,6 +27,7 @@ static void print_mmcinfo(struct mmc *mmc)
 			(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
 			(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
 
+	printf("Timing Interface: %s\n", timing[mmc->timing]);
 	printf("Tran Speed: %d\n", mmc->clock);
 	printf("Rd Block Len: %d\n", mmc->read_bl_len);
 
-- 
2.7.4

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

* [U-Boot] [PATCH 14/33] clk: introduce clk_phase get/set function & callback
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (11 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 13/33] cmd: mmc: show the current speed mode Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 15/33] rockchip: clk: rk3288: fix mmc clock setting Ziyuan Xu
                   ` (19 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

A common operation for a clock signal generator is to shift the phase of
that signal. This patch introduces a new function to the clk.h API to
dynamically adjust the phase of a clock signal. Additionally this patch
introduces support for the new function in the clock framework via the
.set_phase & .get_phase callback in struct clk_ops.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/clk/clk-uclass.c | 20 ++++++++++++++++++++
 include/clk-uclass.h     | 17 +++++++++++++++++
 include/clk.h            | 20 ++++++++++++++++++++
 3 files changed, 57 insertions(+)

diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 6fcfd69..47628b1 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -165,6 +165,26 @@ ulong clk_set_rate(struct clk *clk, ulong rate)
 	return ops->set_rate(clk, rate);
 }
 
+int clk_get_phase(struct clk *clk)
+{
+	struct clk_ops *ops = clk_dev_ops(clk->dev);
+
+	if (!ops->get_phase)
+		return -ENOSYS;
+
+	return ops->get_phase(clk);
+}
+
+int clk_set_phase(struct clk *clk, int degrees)
+{
+	struct clk_ops *ops = clk_dev_ops(clk->dev);
+
+	if (!ops->set_phase)
+		return -ENOSYS;
+
+	return ops->set_phase(clk, degrees);
+}
+
 int clk_enable(struct clk *clk)
 {
 	struct clk_ops *ops = clk_dev_ops(clk->dev);
diff --git a/include/clk-uclass.h b/include/clk-uclass.h
index 07c1065..0e56daa 100644
--- a/include/clk-uclass.h
+++ b/include/clk-uclass.h
@@ -77,6 +77,23 @@ struct clk_ops {
 	 */
 	ulong (*set_rate)(struct clk *clk, ulong rate);
 	/**
+	 * clk_get_phase() - Get the phase shift of a clock signal.
+	 *
+	 * @clk:	The clock to manipulate.
+	 * @return the phase shift of a clock node in degrees,
+	 *		otherwise returns -ve error code.
+	 */
+	int (*get_phase)(struct clk *clk);
+
+	/**
+	 * clk_set_rate() - Adjust the phase shift of a clock signal.
+	 *
+	 * @clk:	The clock to manipulate.
+	 * @degrees:	Numberof degrees the signal is shifted.
+	 * @return 0 on success, or -ve error code.
+	 */
+	int (*set_phase)(struct clk *clk, int degrees);
+	/**
 	 * enable() - Enable a clock.
 	 *
 	 * @clk:	The clock to manipulate.
diff --git a/include/clk.h b/include/clk.h
index 5a5c2ff..1858fef 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -157,6 +157,26 @@ ulong clk_get_rate(struct clk *clk);
 ulong clk_set_rate(struct clk *clk, ulong rate);
 
 /**
+ * clk_get_phase() - Get the phase shift of a clock signal.
+ *
+ * @clk:	A clock struct that was previously successfully requested by
+ *		clk_request/get_by_*().
+ * @return the phase shift of a clock node in degrees, otherwise returns
+ *		-ve error code.
+ */
+int clk_get_phase(struct clk *clk);
+
+/**
+ * clk_set_rate() - Adjust the phase shift of a clock signal.
+ *
+ * @clk:	A clock struct that was previously successfully requested by
+ *		clk_request/get_by_*().
+ * @degrees:	Numberof degrees the signal is shifted.
+ * @return 0 on success, or -ve error code.
+ */
+int clk_set_phase(struct clk *clk, int degrees);
+
+/**
  * clk_enable() - Enable (turn on) a clock.
  *
  * @clk:	A clock struct that was previously successfully requested by
-- 
2.7.4

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

* [U-Boot] [PATCH 15/33] rockchip: clk: rk3288: fix mmc clock setting
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (12 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 14/33] clk: introduce clk_phase get/set function & callback Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 16/33] rockchip: clk: rk3288: add support for the clock phase Ziyuan Xu
                   ` (18 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

Mmc clock automatically divide 2 in internal.

Before this:
gpll = 594MHz, clock = 148.5MHz
div = 594/148.5-1 = 3
output clock is 99MHz

After this:
gpll = 594MHz, clock = 148.5MHz
div = 297+148.5-1/148.5 = 2
output clock is 148.5Mhz

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/clk/rockchip/clk_rk3288.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/rockchip/clk_rk3288.c b/drivers/clk/rockchip/clk_rk3288.c
index fc369dd..b924a3b 100644
--- a/drivers/clk/rockchip/clk_rk3288.c
+++ b/drivers/clk/rockchip/clk_rk3288.c
@@ -535,7 +535,7 @@ static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint gclk_rate,
 	}
 
 	src_rate = mux == EMMC_PLL_SELECT_24MHZ ? OSC_HZ : gclk_rate;
-	return DIV_TO_RATE(src_rate, div);
+	return DIV_TO_RATE(src_rate, div) / 2;
 }
 
 static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint gclk_rate,
@@ -545,10 +545,10 @@ static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint gclk_rate,
 	int mux;
 
 	debug("%s: gclk_rate=%u\n", __func__, gclk_rate);
-	src_clk_div = RATE_TO_DIV(gclk_rate, freq);
+	src_clk_div = DIV_ROUND_UP(gclk_rate / 2, freq);
 
 	if (src_clk_div > 0x3f) {
-		src_clk_div = RATE_TO_DIV(OSC_HZ, freq);
+		src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, freq);
 		mux = EMMC_PLL_SELECT_24MHZ;
 		assert((int)EMMC_PLL_SELECT_24MHZ ==
 		       (int)MMC0_PLL_SELECT_24MHZ);
-- 
2.7.4

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

* [U-Boot] [PATCH 16/33] rockchip: clk: rk3288: add support for the clock phase
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (13 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 15/33] rockchip: clk: rk3288: fix mmc clock setting Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 17/33] rockchip: clk: rk3399: fix emmc clock setting Ziyuan Xu
                   ` (17 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

This patch adds phase adjustment for mmc clock(ciu_sample), which is
used to select the optimal sampling point of a data input.

The phase shift is achieved through 255 delay elements(40-80
picoseconds),  and calculate the number of delay element via clock
frequency.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/clk/rockchip/clk_rk3288.c | 124 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/drivers/clk/rockchip/clk_rk3288.c b/drivers/clk/rockchip/clk_rk3288.c
index b924a3b..3279e01 100644
--- a/drivers/clk/rockchip/clk_rk3288.c
+++ b/drivers/clk/rockchip/clk_rk3288.c
@@ -514,6 +514,7 @@ static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint gclk_rate,
 	switch (periph) {
 	case HCLK_EMMC:
 	case SCLK_EMMC:
+	case SCLK_EMMC_SAMPLE:
 		con = readl(&cru->cru_clksel_con[12]);
 		mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK;
 		div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK;
@@ -669,7 +670,9 @@ static ulong rk3288_clk_get_rate(struct clk *clk)
 	case HCLK_SDMMC:
 	case HCLK_SDIO0:
 	case SCLK_EMMC:
+	case SCLK_EMMC_SAMPLE:
 	case SCLK_SDMMC:
+	case SCLK_SDMMC_SAMPLE:
 	case SCLK_SDIO0:
 		new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, clk->id);
 		break;
@@ -784,9 +787,130 @@ static ulong rk3288_clk_set_rate(struct clk *clk, ulong rate)
 	return new_rate;
 }
 
+#define ROCKCHIP_MMC_DELAY_SEL		BIT(10)
+#define ROCKCHIP_MMC_DEGREE_MASK	0x3
+#define ROCKCHIP_MMC_DELAYNUM_OFFSET	2
+#define ROCKCHIP_MMC_DELAYNUM_MASK	(0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
+
+#define PSECS_PER_SEC 1000000000000LL
+/*
+ * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
+ * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
+ */
+#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
+
+int rockchip_mmc_get_phase(struct clk *clk)
+{
+	struct rk3288_clk_priv *priv = dev_get_priv(clk->dev);
+	struct rk3288_cru *cru = priv->cru;
+	u32 raw_value, delay_num;
+	u16 degrees = 0;
+	ulong rate;
+
+	rate = rk3288_clk_get_rate(clk);
+
+	if (rate < 0)
+		return rate;
+
+	if (clk->id == SCLK_EMMC_SAMPLE)
+		raw_value = readl(&cru->cru_emmc_con[1]);
+	else
+		raw_value = readl(&cru->cru_sdmmc_con[1]);
+
+	degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
+
+	if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
+		/* degrees/delaynum * 10000 */
+		unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
+					36 * (rate / 1000000);
+
+		delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
+		delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
+		degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
+	}
+
+	return degrees % 360;
+}
+
+int rockchip_mmc_set_phase(struct clk *clk, u32 degrees)
+{
+	struct rk3288_clk_priv *priv = dev_get_priv(clk->dev);
+	struct rk3288_cru *cru = priv->cru;
+	u8 nineties, remainder, delay_num;
+	u32 raw_value, delay;
+	ulong rate;
+
+	rate = rk3288_clk_get_rate(clk);
+
+	if (rate < 0)
+		return rate;
+
+	nineties = degrees / 90;
+	remainder = (degrees % 90);
+
+	/*
+	 * Convert to delay; do a little extra work to make sure we
+	 * don't overflow 32-bit / 64-bit numbers.
+	 */
+	delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
+	delay *= remainder;
+	delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
+				(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
+
+	delay_num = (u8)min_t(u32, delay, 255);
+
+	raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
+	raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
+	raw_value |= nineties;
+
+	if (clk->id == SCLK_EMMC_SAMPLE)
+		writel(raw_value | 0xffff0000, &cru->cru_emmc_con[1]);
+	else
+		writel(raw_value | 0xffff0000, &cru->cru_sdmmc_con[1]);
+
+	debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
+	      degrees, delay_num, raw_value, rockchip_mmc_get_phase(clk));
+
+	return 0;
+}
+
+static int rk3288_clk_get_phase(struct clk *clk)
+{
+	int ret;
+
+	switch (clk->id) {
+	case SCLK_EMMC_SAMPLE:
+	case SCLK_SDMMC_SAMPLE:
+		ret = rockchip_mmc_get_phase(clk);
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	return ret;
+}
+
+static int rk3288_clk_set_phase(struct clk *clk, int degrees)
+{
+	int ret;
+
+	switch (clk->id) {
+	case SCLK_EMMC_SAMPLE:
+	case SCLK_SDMMC_SAMPLE:
+		ret = rockchip_mmc_set_phase(clk, degrees);
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	return ret;
+}
+
 static struct clk_ops rk3288_clk_ops = {
 	.get_rate	= rk3288_clk_get_rate,
 	.set_rate	= rk3288_clk_set_rate,
+	.get_phase	= rk3288_clk_get_phase,
+	.set_phase	= rk3288_clk_set_phase,
 };
 
 static int rk3288_clk_ofdata_to_platdata(struct udevice *dev)
-- 
2.7.4

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

* [U-Boot] [PATCH 17/33] rockchip: clk: rk3399: fix emmc clock setting
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (14 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 16/33] rockchip: clk: rk3288: add support for the clock phase Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 18/33] mmc: dw_mmc: add the support for the tuning scheme Ziyuan Xu
                   ` (16 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

Before this:
gpll = 594MHz, set_clock = 200MHz
div = 594/200 = 2
real clock is 297MHz

After this:
gpll = 594MHz, clock = 148.5MHz
div = 594+200-1/200 = 3
real clock is 198Mhz

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/clk/rockchip/clk_rk3399.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c
index 026ed4d..3656f02 100644
--- a/drivers/clk/rockchip/clk_rk3399.c
+++ b/drivers/clk/rockchip/clk_rk3399.c
@@ -794,7 +794,7 @@ static ulong rk3399_mmc_set_clk(struct rk3399_cru *cru,
 		break;
 	case SCLK_EMMC:
 		/* Select aclk_emmc source from GPLL */
-		src_clk_div = GPLL_HZ / aclk_emmc;
+		src_clk_div = DIV_ROUND_UP(GPLL_HZ, aclk_emmc);
 		assert(src_clk_div - 1 < 31);
 
 		rk_clrsetreg(&cru->clksel_con[21],
@@ -803,7 +803,7 @@ static ulong rk3399_mmc_set_clk(struct rk3399_cru *cru,
 			     (src_clk_div - 1) << ACLK_EMMC_DIV_CON_SHIFT);
 
 		/* Select clk_emmc source from GPLL too */
-		src_clk_div = GPLL_HZ / set_rate;
+		src_clk_div = DIV_ROUND_UP(GPLL_HZ, set_rate);
 		assert(src_clk_div - 1 < 127);
 
 		rk_clrsetreg(&cru->clksel_con[22],
-- 
2.7.4

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

* [U-Boot] [PATCH 18/33] mmc: dw_mmc: add the support for the tuning scheme
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (15 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 17/33] rockchip: clk: rk3399: fix emmc clock setting Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 19/33] mmc: dw_mmc: rockchip: implement tuning with clock phase framework Ziyuan Xu
                   ` (15 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

For the HS200/HS400/SDR104, tuning is needed to determine the optimal
sampling point. Actual tuning procedure is provided by specific host
controller driver.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/dw_mmc.c | 18 ++++++++++++++++++
 include/dwmmc.h      |  1 +
 2 files changed, 19 insertions(+)

diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 7e9ffc2..c05288c 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -404,6 +404,22 @@ static bool dwmci_card_busy(struct mmc *mmc)
 }
 
 #ifdef CONFIG_DM_MMC_OPS
+static int dwmci_execute_tuning(struct udevice *dev, u32 opcode)
+{
+	struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
+static int dwmci_execute_tuning(struct mmc *mmc, u32 opcode)
+{
+#endif
+	struct dwmci_host *host = (struct dwmci_host *)mmc->priv;
+
+	if (!host->execute_tuning)
+		return -EIO;
+
+	return host->execute_tuning(host, opcode);
+}
+
+#ifdef CONFIG_DM_MMC_OPS
 static int dwmci_set_ios(struct udevice *dev)
 {
 	struct mmc *mmc = mmc_get_mmc_dev(dev);
@@ -498,6 +514,7 @@ const struct dm_mmc_ops dm_dwmci_ops = {
 	.card_busy	= dwmci_card_busy,
 	.send_cmd	= dwmci_send_cmd,
 	.set_ios	= dwmci_set_ios,
+	.execute_tuning	= dwmci_execute_tuning,
 };
 
 #else
@@ -506,6 +523,7 @@ static const struct mmc_ops dwmci_ops = {
 	.send_cmd	= dwmci_send_cmd,
 	.set_ios	= dwmci_set_ios,
 	.init		= dwmci_init,
+	.execute_tuning	= dwmci_execute_tuning,
 };
 #endif
 
diff --git a/include/dwmmc.h b/include/dwmmc.h
index 4dda009..95be7c2 100644
--- a/include/dwmmc.h
+++ b/include/dwmmc.h
@@ -180,6 +180,7 @@ struct dwmci_host {
 	 * @freq:	Frequency the host is trying to achieve
 	 */
 	unsigned int (*get_mmc_clk)(struct dwmci_host *host, uint freq);
+	int (*execute_tuning)(struct dwmci_host *host, u32 opcode);
 #ifndef CONFIG_BLK
 	struct mmc_config cfg;
 #endif
-- 
2.7.4

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

* [U-Boot] [PATCH 19/33] mmc: dw_mmc: rockchip: implement tuning with clock phase framework
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (16 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 18/33] mmc: dw_mmc: add the support for the tuning scheme Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 20/33] mmc: dw_mmc: reset controller after data error Ziyuan Xu
                   ` (14 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

This algorithm will try 1 degree increment, since there's no way to tell
what resolution the underlying phase code uses. As an added bonus, doing
many tunings yields better results since some tests are run more than
once (ex: if the underlying driver use 45 degree increments, the tuning
code will try the same angle more than once).

It will then construct a list of good phase ranges (even range that
cross 270/0), will pick the biggest range then it will set the
sample_clk to the middle of that range.

Please notice that it tuning only 0-270 degree in U-Boot, but kernel
tuning range is 0-360 degree. Below are two reasons about this:
1. Expect data-related interrupt may miss during 270-360 degree on
rockchip platform, dw_mmc driver will poll for data interrupt until
240 seconds timeout afterwards. And the host controller will be left in
an unpredictable state.
2. The phase of a clock signal is shift by some delay elements on
rockchip platform. And the delay element affected by logic voltage and
temperature in runtime. These factors wouldn't have changed a lot in
U-Boot stage.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/rockchip_dw_mmc.c | 121 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)

diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index 2885ef2..474ca1c 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -30,6 +30,7 @@ struct rockchip_mmc_plat {
 
 struct rockchip_dwmmc_priv {
 	struct clk clk;
+	struct clk sample_clk;
 	struct dwmci_host host;
 	int fifo_depth;
 	bool fifo_mode;
@@ -99,6 +100,123 @@ static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev)
 	return 0;
 }
 
+#define NUM_PHASES			270
+#define TUNING_ITERATION_TO_PHASE(i)	(DIV_ROUND_UP((i) * 270, NUM_PHASES))
+
+static int rockchip_dwmmc_execute_tuning(struct dwmci_host *host, u32 opcode)
+{
+	int ret = 0;
+	int i;
+	bool v, prev_v = 0, first_v;
+	struct range_t {
+		int start;
+		int end; /* inclusive */
+	};
+	struct range_t *ranges;
+	unsigned int range_count = 0;
+	int longest_range_len = -1;
+	int longest_range = -1;
+	int middle_phase;
+	struct udevice *dev = host->priv;
+	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
+	struct mmc *mmc = host->mmc;
+
+	if (IS_ERR(&priv->sample_clk))
+		return -EIO;
+
+	ranges = calloc(sizeof(*ranges), NUM_PHASES / 2 + 1);
+	if (!ranges)
+		return -ENOMEM;
+
+	/* Try each phase and extract good ranges */
+	for (i = 0; i < NUM_PHASES; ) {
+		clk_set_phase(&priv->sample_clk, TUNING_ITERATION_TO_PHASE(i));
+
+		v = !mmc_send_tuning(mmc, opcode);
+
+		if (i == 0)
+			first_v = v;
+
+		if ((!prev_v) && v) {
+			range_count++;
+			ranges[range_count - 1].start = i;
+		}
+		if (v) {
+			ranges[range_count - 1].end = i;
+			i++;
+		} else if (i == NUM_PHASES - 1) {
+			/* No extra skipping rules if we're at the end */
+			i++;
+		} else {
+			/*
+			 * No need to check too close to an invalid
+			 * one since testing bad phases is slow.  Skip
+			 * 20 degrees.
+			 */
+			i += DIV_ROUND_UP(20 * NUM_PHASES, NUM_PHASES);
+
+			/* Always test the last one */
+			if (i >= NUM_PHASES)
+				i = NUM_PHASES - 1;
+		}
+
+		prev_v = v;
+	}
+
+	if (range_count == 0) {
+		debug("All phases bad!");
+		ret = -EIO;
+		goto free;
+	}
+
+	/* wrap around case, merge the end points */
+	if ((range_count > 1) && first_v && v) {
+		ranges[0].start = ranges[range_count - 1].start;
+		range_count--;
+	}
+
+	if (ranges[0].start == 0 && ranges[0].end == NUM_PHASES - 1) {
+		clk_set_phase(&priv->sample_clk,
+			      TUNING_ITERATION_TO_PHASE(NUM_PHASES / 2));
+		debug("All phases work, using middle phase.\n");
+		goto free;
+	}
+
+	/* Find the longest range */
+	for (i = 0; i < range_count; i++) {
+		int len = (ranges[i].end - ranges[i].start + 1);
+
+		if (len < 0)
+			len += NUM_PHASES;
+
+		if (longest_range_len < len) {
+			longest_range_len = len;
+			longest_range = i;
+		}
+
+		debug("Good phase range %d-%d (%d len)\n",
+		      TUNING_ITERATION_TO_PHASE(ranges[i].start),
+		      TUNING_ITERATION_TO_PHASE(ranges[i].end), len);
+	}
+
+	printf("Best phase range %d-%d (%d len)\n",
+	       TUNING_ITERATION_TO_PHASE(ranges[longest_range].start),
+	       TUNING_ITERATION_TO_PHASE(ranges[longest_range].end),
+	       longest_range_len);
+
+	middle_phase = ranges[longest_range].start + longest_range_len / 2;
+	middle_phase %= NUM_PHASES;
+	debug("Successfully tuned phase to %d\n",
+	      TUNING_ITERATION_TO_PHASE(middle_phase));
+
+	clk_set_phase(&priv->sample_clk,
+		      TUNING_ITERATION_TO_PHASE(middle_phase));
+
+free:
+	free(ranges);
+	return ret;
+}
+
 static int rockchip_dwmmc_probe(struct udevice *dev)
 {
 	struct rockchip_mmc_plat *plat = dev_get_platdata(dev);
@@ -115,6 +233,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev)
 	host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
 	host->buswidth = dtplat->bus_width;
 	host->get_mmc_clk = rockchip_dwmmc_get_mmc_clk;
+	host->execute_tuning = rockchip_dwmmc_execute_tuning;
 	host->priv = dev;
 	host->dev_index = 0;
 	priv->fifo_depth = dtplat->fifo_depth;
@@ -128,6 +247,8 @@ static int rockchip_dwmmc_probe(struct udevice *dev)
 	ret = clk_get_by_name(dev, "ciu", &priv->clk);
 	if (ret < 0)
 		return ret;
+	clk_get_by_name(dev, "ciu_sample", &priv->sample_clk);
+	host->execute_tuning = rockchip_dwmmc_execute_tuning;
 #endif
 	host->fifoth_val = MSIZE(0x2) |
 		RX_WMARK(priv->fifo_depth / 2 - 1) |
-- 
2.7.4

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

* [U-Boot] [PATCH 20/33] mmc: dw_mmc: reset controller after data error
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (17 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 19/33] mmc: dw_mmc: rockchip: implement tuning with clock phase framework Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 21/33] mmc: add DDR52 support for eMMC card Ziyuan Xu
                   ` (13 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

Per dw_mmc databook, it's recommend that reset the host contoller if
some data-related error occurre during tuning progress.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/dw_mmc.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index c05288c..e862eb2 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -97,7 +97,7 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
 {
 	int ret = 0;
 	u32 timeout = 240000;
-	u32 mask, size, i, len = 0;
+	u32 status, ctrl, mask, size, i, len = 0;
 	u32 *buf = NULL;
 	ulong start = get_timer(0);
 	u32 fifo_depth = (((host->fifoth_val & RX_WMARK_MASK) >>
@@ -114,6 +114,23 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
 		/* Error during data transfer. */
 		if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) {
 			debug("%s: DATA ERROR!\n", __func__);
+
+			dwmci_wait_reset(host, DWMCI_RESET_ALL);
+			dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT |
+				     DWMCI_CMD_UPD_CLK | DWMCI_CMD_START);
+
+			do {
+				status = dwmci_readl(host, DWMCI_CMD);
+				if (timeout-- < 0)
+					ret = -ETIMEDOUT;
+			} while (status & DWMCI_CMD_START);
+
+			if (!host->fifo_mode) {
+				ctrl = dwmci_readl(host, DWMCI_BMOD);
+				ctrl |= DWMCI_BMOD_IDMAC_RESET;
+				dwmci_writel(host, DWMCI_BMOD, ctrl);
+			}
+
 			ret = -EINVAL;
 			break;
 		}
-- 
2.7.4

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

* [U-Boot] [PATCH 21/33] mmc: add DDR52 support for eMMC card
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (18 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 20/33] mmc: dw_mmc: reset controller after data error Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 22/33] mmc: dw_mmc: rockchip: fix data crc error on ddr52 8bit mode Ziyuan Xu
                   ` (12 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

4.41+ eMMC card devices can run at 52MHz on DDR 8-bit mode, it can
improve write/read performance. Host driver can set MMC_MODE_DDR_52Mhz
to enable this feature.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/mmc.c | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 953ffd8..c1f54c3 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -795,6 +795,27 @@ static int mmc_select_hs(struct mmc *mmc)
 	return ret;
 }
 
+static int mmc_select_hs_ddr(struct mmc *mmc)
+{
+	u32 ext_csd_bits;
+	int err = 0;
+
+	if (mmc->bus_width == MMC_BUS_WIDTH_1BIT)
+		return 0;
+
+	ext_csd_bits = (mmc->bus_width == MMC_BUS_WIDTH_8BIT) ?
+			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+
+	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH, ext_csd_bits);
+	if (err)
+		return err;
+
+	mmc_set_timing(mmc, MMC_TIMING_MMC_DDR52);
+
+	return 0;
+}
+
 #ifndef CONFIG_SPL_BUILD
 static int mmc_select_hs200(struct mmc *mmc)
 {
@@ -941,8 +962,11 @@ static int mmc_change_freq(struct mmc *mmc)
 
 	if (mmc_card_hs200(mmc))
 		err = mmc_hs200_tuning(mmc);
-	else
+	else if (!mmc_card_hs400es(mmc)) {
 		err = mmc_select_bus_width(mmc) > 0 ? 0 : err;
+		if (!err && avail_type & EXT_CSD_CARD_TYPE_DDR_52)
+			err = mmc_select_hs_ddr(mmc);
+	}
 
 	return err;
 }
-- 
2.7.4

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

* [U-Boot] [PATCH 22/33] mmc: dw_mmc: rockchip: fix data crc error on ddr52 8bit mode
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (19 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 21/33] mmc: add DDR52 support for eMMC card Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 23/33] mmc: dw_mmc: fix bus width setting Ziyuan Xu
                   ` (11 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

The clk_divider must be set to 1 on ddr52 8bit mode for rockchip
platform. Otherwise we will get a data crc error during data
transmission.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/dw_mmc.c          | 2 +-
 drivers/mmc/rockchip_dw_mmc.c | 7 +++++++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index e862eb2..dcd7fba 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -344,7 +344,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)
 	int timeout = 10000;
 	unsigned long sclk;
 
-	if ((freq == host->clock) || (freq == 0))
+	if (freq == 0)
 		return 0;
 	/*
 	 * If host->get_mmc_clk isn't defined,
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index 474ca1c..b2b7f5a 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -43,6 +43,13 @@ static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq)
 	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
 	int ret;
 
+	/*
+	 * If DDR52 8bit mode(only emmc work in 8bit mode),
+	 * divider must be set 1
+	 */
+	if (mmc_card_ddr52(host->mmc) && host->mmc->bus_width == 8)
+		freq *= 2;
+
 	ret = clk_set_rate(&priv->clk, freq);
 	if (ret < 0) {
 		printf("%s: err=%d\n", __func__, ret);
-- 
2.7.4

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

* [U-Boot] [PATCH 23/33] mmc: dw_mmc: fix bus width setting
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (20 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 22/33] mmc: dw_mmc: rockchip: fix data crc error on ddr52 8bit mode Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 24/33] mmc: sdhci: rockchip: " Ziyuan Xu
                   ` (10 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

Hosts capable of 8-bit transfers can also do 4 bits.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/dw_mmc.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index dcd7fba..3b89e7a 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -559,8 +559,7 @@ void dwmci_setup_cfg(struct mmc_config *cfg, struct dwmci_host *host,
 	cfg->host_caps = host->caps;
 
 	if (host->buswidth == 8) {
-		cfg->host_caps |= MMC_MODE_8BIT;
-		cfg->host_caps &= ~MMC_MODE_4BIT;
+		cfg->host_caps |= MMC_MODE_8BIT | MMC_MODE_4BIT;
 	} else {
 		cfg->host_caps |= MMC_MODE_4BIT;
 		cfg->host_caps &= ~MMC_MODE_8BIT;
-- 
2.7.4

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

* [U-Boot] [PATCH 24/33] mmc: sdhci: rockchip: fix bus width setting
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (21 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 23/33] mmc: dw_mmc: fix bus width setting Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 25/33] mmc: sdhci: update host->clock after clock setting Ziyuan Xu
                   ` (9 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

Rockchip sdhci controller capable of 8-bit transfer. The original can
only run at 4 bit mode.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/rockchip_sdhci.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index bdde831..562fb35 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -47,11 +47,26 @@ static int arasan_sdhci_probe(struct udevice *dev)
 
 	host->name = dev->name;
 	host->ioaddr = map_sysmem(dtplat->reg[1], dtplat->reg[3]);
+	host->host_caps |= MMC_MODE_8BIT;
 	max_frequency = dtplat->max_frequency;
 	ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &clk);
 #else
 	max_frequency = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
 			"max-frequency", 0);
+	switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+			       "bus-width", 4)) {
+	case 8:
+		host->host_caps |= MMC_MODE_8BIT;
+		break;
+	case 4:
+		host->host_caps |= MMC_MODE_4BIT;
+		break;
+	case 1:
+		break;
+	default:
+		printf("Invalid \"bus-width\" value\n");
+		return -EINVAL;
+	}
 	ret = clk_get_by_index(dev, 0, &clk);
 #endif
 	if (!ret) {
-- 
2.7.4

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

* [U-Boot] [PATCH 25/33] mmc: sdhci: update host->clock after clock setting
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (22 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 24/33] mmc: sdhci: rockchip: " Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 26/33] mmc: sdhci: add support for UHS timing Ziyuan Xu
                   ` (8 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

Overwrite host->clock after clock setting to avoid repetitive reset
clock.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/sdhci.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 48bac04..ad86278 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -390,6 +390,9 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
 
 	clk |= SDHCI_CLOCK_CARD_EN;
 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+	host->clock = clock;
+
 	return 0;
 }
 
-- 
2.7.4

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

* [U-Boot] [PATCH 26/33] mmc: sdhci: add support for UHS timing
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (23 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 25/33] mmc: sdhci: update host->clock after clock setting Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 27/33] mmc: sdhci: rename set_clock callback Ziyuan Xu
                   ` (7 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

To support UHS speed mode, controller should enable 1.8V signaling and
select one of UHS modes.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/sdhci.c | 40 ++++++++++++++++++++++++++++++++++++++++
 include/mmc.h       |  1 +
 include/sdhci.h     | 17 +++++++++++++++++
 3 files changed, 58 insertions(+)

diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index ad86278..8f4a2a1 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -426,6 +426,39 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 	sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
 }
 
+static void sdhci_set_uhs_signaling(struct sdhci_host *host)
+{
+	u16 ctrl_2;
+	u32 timing = host->mmc->timing;
+
+	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+	/* Select Bus Speed Mode for host */
+	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+
+	if ((timing != MMC_TIMING_LEGACY) &&
+	    (timing != MMC_TIMING_MMC_HS) &&
+	    (timing != MMC_TIMING_SD_HS))
+		ctrl_2 |= SDHCI_CTRL_VDD_180;
+
+	if ((timing == MMC_TIMING_MMC_HS200) ||
+	    (timing == MMC_TIMING_UHS_SDR104))
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_DRV_TYPE_A;
+	else if (timing == MMC_TIMING_UHS_SDR12)
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+	else if (timing == MMC_TIMING_UHS_SDR25)
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+	else if (timing == MMC_TIMING_UHS_SDR50)
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+	else if ((timing == MMC_TIMING_UHS_DDR50) ||
+		 (timing == MMC_TIMING_MMC_DDR52))
+		ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+	else if (timing == MMC_TIMING_MMC_HS400 ||
+		 timing == MMC_TIMING_MMC_HS400ES)
+		ctrl_2 |= SDHCI_CTRL_HS400 | SDHCI_CTRL_DRV_TYPE_A;
+
+	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+
 #ifdef CONFIG_DM_MMC_OPS
 static bool sdhci_card_busy(struct udevice *dev)
 {
@@ -485,6 +518,13 @@ static int sdhci_set_ios(struct mmc *mmc)
 
 	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
+	if ((mmc->timing != MMC_TIMING_LEGACY) &&
+	    (mmc->timing != MMC_TIMING_MMC_HS) &&
+	    (mmc->timing != MMC_TIMING_SD_HS))
+		sdhci_set_power(host, MMC_VDD_165_195_SHIFT);
+
+	sdhci_set_uhs_signaling(host);
+
 	/* If available, call the driver specific "post" set_ios() function */
 	if (host->ops && host->ops->set_ios_post)
 		host->ops->set_ios_post(host);
diff --git a/include/mmc.h b/include/mmc.h
index 05bf39d..b5817f3 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -138,6 +138,7 @@
 
 #define MMC_STATE_PRG		(7 << 9)
 
+#define MMC_VDD_165_195_SHIFT	7
 #define MMC_VDD_165_195		0x00000080	/* VDD voltage 1.65 - 1.95 */
 #define MMC_VDD_20_21		0x00000100	/* VDD voltage 2.0 ~ 2.1 */
 #define MMC_VDD_21_22		0x00000200	/* VDD voltage 2.1 ~ 2.2 */
diff --git a/include/sdhci.h b/include/sdhci.h
index 75432db..449ada1 100644
--- a/include/sdhci.h
+++ b/include/sdhci.h
@@ -147,6 +147,23 @@
 #define SDHCI_ACMD12_ERR	0x3C
 
 /* 3E-3F reserved */
+#define SDHCI_HOST_CONTROL2		0x3E
+#define SDHCI_CTRL_UHS_MASK		0x0007
+#define SDHCI_CTRL_UHS_SDR12		0x0000
+#define SDHCI_CTRL_UHS_SDR25		0x0001
+#define SDHCI_CTRL_UHS_SDR50		0x0002
+#define SDHCI_CTRL_UHS_SDR104		0x0003
+#define SDHCI_CTRL_UHS_DDR50		0x0004
+#define SDHCI_CTRL_HS400		0x0005
+#define SDHCI_CTRL_VDD_180		0x0008
+#define SDHCI_CTRL_DRV_TYPE_MASK	0x0030
+#define SDHCI_CTRL_DRV_TYPE_B		0x0000
+#define SDHCI_CTRL_DRV_TYPE_A		0x0010
+#define SDHCI_CTRL_DRV_TYPE_C		0x0020
+#define SDHCI_CTRL_DRV_TYPE_D		0x0030
+#define SDHCI_CTRL_EXEC_TUNING		0x0040
+#define SDHCI_CTRL_TUNED_CLK		0x0080
+#define SDHCI_CTRL_PRESET_VAL_ENABLE	0x8000
 
 #define SDHCI_CAPABILITIES	0x40
 #define  SDHCI_TIMEOUT_CLK_MASK	0x0000003F
-- 
2.7.4

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

* [U-Boot] [PATCH 27/33] mmc: sdhci: rename set_clock callback
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (24 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 26/33] mmc: sdhci: add support for UHS timing Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 28/33] mmc: sdhci: export sdhci_set_clock() Ziyuan Xu
                   ` (6 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

In fact, the original name is unsuitable for its behavior. It's better
to rename to set_clock_ext.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/s5p_sdhci.c | 4 ++--
 drivers/mmc/sdhci.c     | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c
index 640ea02..b8d3ded 100644
--- a/drivers/mmc/s5p_sdhci.c
+++ b/drivers/mmc/s5p_sdhci.c
@@ -73,14 +73,14 @@ static void s5p_sdhci_set_control_reg(struct sdhci_host *host)
 	sdhci_writel(host, ctrl, SDHCI_CONTROL2);
 }
 
-static void s5p_set_clock(struct sdhci_host *host, u32 div)
+static void s5p_set_clock_ext(struct sdhci_host *host, u32 div)
 {
 	/* ToDo : Use the Clock Framework */
 	set_mmc_clk(host->index, div);
 }
 
 static const struct sdhci_ops s5p_sdhci_ops = {
-	.set_clock	= &s5p_set_clock,
+	.set_clock_ext	= &s5p_set_clock_ext,
 	.set_control_reg = &s5p_sdhci_set_control_reg,
 };
 
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 8f4a2a1..5c6dbdc 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -366,8 +366,8 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
 		div >>= 1;
 	}
 
-	if (host->ops && host->ops->set_clock)
-		host->ops->set_clock(host, div);
+	if (host->ops && host->ops->set_clock_ext)
+		host->ops->set_clock_ext(host, div);
 
 	clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
 	clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
-- 
2.7.4

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

* [U-Boot] [PATCH 28/33] mmc: sdhci: export sdhci_set_clock()
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (25 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 27/33] mmc: sdhci: rename set_clock callback Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 29/33] mmc: sdhci: rockchip: add phy support Ziyuan Xu
                   ` (5 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

For arasan-rk3399-sdhci controller, we should make sure the phy is in
poweroff status before we configure the clock stuff. So that we need to
export it for phy configuration.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/sdhci.c | 16 +++++++---------
 include/sdhci.h     |  5 ++++-
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 5c6dbdc..b9cd13a 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -301,9 +301,8 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
 		return -ECOMM;
 }
 
-static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
+int sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 {
-	struct sdhci_host *host = mmc->priv;
 	unsigned int div, clk = 0, timeout;
 
 	/* Wait max 20 ms */
@@ -319,12 +318,10 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
 		timeout--;
 		udelay(100);
 	}
-
 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 
 	if (clock == 0)
 		return 0;
-
 	if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
 		/*
 		 * Check if the Host Controller supports Programmable Clock
@@ -365,7 +362,6 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
 		}
 		div >>= 1;
 	}
-
 	if (host->ops && host->ops->set_clock_ext)
 		host->ops->set_clock_ext(host, div);
 
@@ -387,12 +383,10 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
 		timeout--;
 		udelay(1000);
 	}
-
 	clk |= SDHCI_CLOCK_CARD_EN;
 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
 	host->clock = clock;
-
 	return 0;
 }
 
@@ -490,8 +484,12 @@ static int sdhci_set_ios(struct mmc *mmc)
 	if (host->ops && host->ops->set_control_reg)
 		host->ops->set_control_reg(host);
 
-	if (mmc->clock != host->clock)
-		sdhci_set_clock(mmc, mmc->clock);
+	if (mmc->clock != host->clock) {
+		if (host->ops && host->ops->set_clock)
+			host->ops->set_clock(host, mmc->clock);
+		else
+			sdhci_set_clock(host, mmc->clock);
+	}
 
 	/* Set bus width */
 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
diff --git a/include/sdhci.h b/include/sdhci.h
index 449ada1..da21194 100644
--- a/include/sdhci.h
+++ b/include/sdhci.h
@@ -254,7 +254,8 @@ struct sdhci_ops {
 	int	(*get_cd)(struct sdhci_host *host);
 	void	(*set_control_reg)(struct sdhci_host *host);
 	void	(*set_ios_post)(struct sdhci_host *host);
-	void	(*set_clock)(struct sdhci_host *host, u32 div);
+	int	(*set_clock)(struct sdhci_host *host, unsigned int clock);
+	void	(*set_clock_ext)(struct sdhci_host *host, u32 div);
 };
 
 struct sdhci_host {
@@ -279,6 +280,8 @@ struct sdhci_host {
 	struct mmc_config cfg;
 };
 
+int sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
+
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
 
 static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg)
-- 
2.7.4

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

* [U-Boot] [PATCH 29/33] mmc: sdhci: rockchip: add phy support
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (26 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 28/33] mmc: sdhci: export sdhci_set_clock() Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 30/33] mmc: sdhci: add the support for tuning Ziyuan Xu
                   ` (4 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

This patch gets phy phandle from dt-binding, and power
cycle/re-configure phy whilst changing card clock.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/rockchip_sdhci.c | 147 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 147 insertions(+)

diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index 562fb35..5b6b262 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -6,6 +6,7 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
+#include <asm/arch/hardware.h>
 #include <common.h>
 #include <dm.h>
 #include <dt-structs.h>
@@ -28,11 +29,151 @@ struct rockchip_sdhc_plat {
 	struct mmc mmc;
 };
 
+struct rockchip_emmc_phy {
+	u32 emmcphy_con[7];
+	u32 reserved;
+	u32 emmcphy_status;
+};
+
 struct rockchip_sdhc {
 	struct sdhci_host host;
 	void *base;
+	struct rockchip_emmc_phy *phy;
 };
 
+#define PHYCTRL_CALDONE_MASK		0x1
+#define PHYCTRL_CALDONE_SHIFT		0x6
+#define PHYCTRL_CALDONE_DONE		0x1
+
+#define PHYCTRL_DLLRDY_MASK		0x1
+#define PHYCTRL_DLLRDY_SHIFT		0x5
+#define PHYCTRL_DLLRDY_DONE		0x1
+
+#define PHYCTRL_FREQSEL_200M            0x0
+#define PHYCTRL_FREQSEL_50M             0x1
+#define PHYCTRL_FREQSEL_100M            0x2
+#define PHYCTRL_FREQSEL_150M            0x3
+
+#define KHz	(1000)
+#define MHz	(1000 * KHz)
+
+static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock)
+{
+	u32 caldone, dllrdy, freqsel;
+	uint start;
+
+	writel(RK_CLRSETBITS(7 << 4, 0), &phy->emmcphy_con[6]);
+	writel(RK_CLRSETBITS(1 << 11, 1 << 11), &phy->emmcphy_con[0]);
+	writel(RK_CLRSETBITS(0xf << 7, 4 << 7), &phy->emmcphy_con[0]);
+
+	/*
+	 * According to the user manual, calpad calibration
+	 * cycle takes more than 2us without the minimal recommended
+	 * value, so we may need a little margin here
+	 */
+	udelay(3);
+	writel(RK_CLRSETBITS(1, 1), &phy->emmcphy_con[6]);
+
+	/*
+	 * According to the user manual, it asks driver to
+	 * wait 5us for calpad busy trimming
+	 */
+	udelay(5);
+	caldone = readl(&phy->emmcphy_status);
+	caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK;
+	if (caldone != PHYCTRL_CALDONE_DONE) {
+		debug("%s: caldone timeout.\n", __func__);
+		return;
+	}
+
+	/* Set the frequency of the DLL operation */
+	if (clock < 75 * MHz)
+		freqsel = PHYCTRL_FREQSEL_50M;
+	else if (clock < 125 * MHz)
+		freqsel = PHYCTRL_FREQSEL_100M;
+	else if (clock < 175 * MHz)
+		freqsel = PHYCTRL_FREQSEL_150M;
+	else
+		freqsel = PHYCTRL_FREQSEL_200M;
+
+	/* Set the frequency of the DLL operation */
+	writel(RK_CLRSETBITS(3 << 12, freqsel << 12), &phy->emmcphy_con[0]);
+	writel(RK_CLRSETBITS(1 << 1, 1 << 1), &phy->emmcphy_con[6]);
+
+	start = get_timer(0);
+
+	do {
+		udelay(1);
+		dllrdy = readl(&phy->emmcphy_status);
+		dllrdy = (dllrdy >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK;
+		if (dllrdy == PHYCTRL_DLLRDY_DONE)
+			break;
+	} while (get_timer(start) < 50000);
+
+	if (dllrdy != PHYCTRL_DLLRDY_DONE)
+		debug("%s: dllrdy timeout.\n", __func__);
+}
+
+static void rk3399_emmc_phy_power_off(struct rockchip_emmc_phy *phy)
+{
+	writel(RK_CLRSETBITS(1, 0), &phy->emmcphy_con[6]);
+	writel(RK_CLRSETBITS(1 << 1, 0), &phy->emmcphy_con[6]);
+}
+
+static int arasan_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	struct rockchip_sdhc *priv =
+			container_of(host, struct rockchip_sdhc, host);
+	int cycle_phy = host->clock != clock &&
+			clock > EMMC_MIN_FREQ;
+
+	if (cycle_phy)
+		rk3399_emmc_phy_power_off(priv->phy);
+
+	sdhci_set_clock(host, clock);
+
+	if (cycle_phy)
+		rk3399_emmc_phy_power_on(priv->phy, clock);
+
+	return 0;
+}
+
+static struct sdhci_ops arasan_sdhci_ops = {
+	.set_clock	= arasan_sdhci_set_clock,
+};
+
+static int arasan_get_phy(struct udevice *dev)
+{
+	struct rockchip_sdhc *priv = dev_get_priv(dev);
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	priv->phy = (struct rockchip_emmc_phy *)0xff77f780;
+#else
+	int phy_node, grf_node;
+	fdt_addr_t grf_base, grf_phy_offset;
+
+	phy_node = fdtdec_lookup_phandle(gd->fdt_blob,
+					 dev_of_offset(dev), "phys");
+	if (phy_node <= 0) {
+		debug("Not found emmc phy device\n");
+		return -ENODEV;
+	}
+
+	grf_node = fdt_parent_offset(gd->fdt_blob, phy_node);
+	if (grf_node <= 0) {
+		debug("Not found usb phy device\n");
+		return -ENODEV;
+	}
+
+	grf_base = fdtdec_get_addr(gd->fdt_blob, grf_node, "reg");
+	grf_phy_offset = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
+				grf_node, phy_node, "reg", 0, NULL, false);
+
+	priv->phy = (struct rockchip_emmc_phy *)(grf_base + grf_phy_offset);
+#endif
+	return 0;
+}
+
 static int arasan_sdhci_probe(struct udevice *dev)
 {
 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
@@ -77,6 +218,12 @@ static int arasan_sdhci_probe(struct udevice *dev)
 		printf("%s fail to get clk\n", __func__);
 	}
 
+	ret = arasan_get_phy(dev);
+	if (ret)
+		return ret;
+
+	host->ops = &arasan_sdhci_ops;
+
 	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
 	host->max_clk = max_frequency;
 
-- 
2.7.4

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

* [U-Boot] [PATCH 30/33] mmc: sdhci: add the support for tuning
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (27 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 29/33] mmc: sdhci: rockchip: add phy support Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 31/33] mmc: add support for HS400 mode of eMMC5.0 Ziyuan Xu
                   ` (3 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

MMC framework has already implemented hs200 mode for eMMC devices,
moreover the standard SDHC3.0 controller support tuning. We can set the
corresponding flag in host->host_cpas.

Host driver issue tuning command repeatedly until the host controller
resets Execute Tuning to 0. Host controller resets Execute Tuning to 0
when tuning is completed or tuning is not completed within 40 times.
Host driver can abort this loop by 40 times CMD19/CMD21 issue or 150ms
time-out. If tuning is completed successfully, driver set Sampling Clock
Select to 1 and this means the host contorller start to use tuned
sampling clcok. If tuning is failed, host controller keeps Sampling
Clock Select to 0.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/sdhci.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 115 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index b9cd13a..e346820 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -158,7 +158,10 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
 	static unsigned int cmd_timeout = SDHCI_CMD_DEFAULT_TIMEOUT;
 
 	sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
-	mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT;
+	mask = SDHCI_CMD_INHIBIT;
+
+	if (data)
+		mask |= SDHCI_DATA_INHIBIT;
 
 	/* We shouldn't wait for data inihibit for stop commands, even
 	   though they might use busy signaling */
@@ -200,6 +203,13 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
 	if (data)
 		flags |= SDHCI_CMD_DATA;
 
+	if (cmd->cmdidx == MMC_SEND_TUNING_BLOCK ||
+	    cmd->cmdidx == MMC_SEND_TUNING_BLOCK_HS200) {
+		mask &= ~SDHCI_INT_RESPONSE;
+		mask |= SDHCI_INT_DATA_AVAIL;
+		flags |= SDHCI_CMD_DATA;
+	}
+
 	/* Set Transfer mode regarding to data flag */
 	if (data != 0) {
 		sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
@@ -559,6 +569,108 @@ static int sdhci_init(struct mmc *mmc)
 	return 0;
 }
 
+static int sdhci_send_tuning(struct sdhci_host *host, u32 opcode)
+{
+	struct mmc_cmd cmd;
+
+	cmd.cmdidx = opcode;
+	cmd.resp_type = MMC_RSP_R1;
+	cmd.cmdarg = 0;
+	/*
+	 * In response to CMD19, the card sends 64 bytes of tuning
+	 * block to the Host Controller. So we set the block size
+	 * to 64 here.
+	 */
+	if (opcode == MMC_SEND_TUNING_BLOCK_HS200 &&
+	    host->mmc->bus_width == MMC_BUS_WIDTH_8BIT)
+		sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), SDHCI_BLOCK_SIZE);
+	else
+		sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);
+
+	/*
+	 * The tuning block is sent by the card to the host controller.
+	 * So we set the TRNS_READ bit in the Transfer Mode register.
+	 * This also takes care of setting DMA Enable and Multi Block
+	 * Select in the same register to 0.
+	 */
+	sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
+
+#ifdef CONFIG_DM_MMC_OPS
+	return sdhci_send_command(host->mmc->dev, &cmd, NULL);
+#else
+	return sdhci_send_command(host->mmc, &cmd, NULL);
+#endif
+}
+
+#define MAX_TUNING_LOOP 40
+static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+	int i;
+	int ret;
+
+	/*
+	 * Issue opcode repeatedly till Execute Tuning is set to 0 or the number
+	 * of loops reaches 40 times.
+	 */
+	for (i = 0; i < MAX_TUNING_LOOP; i++) {
+		u16 ctrl;
+
+		ret = sdhci_send_tuning(host, opcode);
+
+		if (ret)
+			return ret;
+
+		ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+		if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
+			if (ctrl & SDHCI_CTRL_TUNED_CLK)
+				/* Tuning successfully */
+				return 0;
+			break;
+		}
+	}
+
+	return -ETIMEDOUT;
+}
+
+#ifdef CONFIG_DM_MMC_OPS
+static int sdhci_execute_tuning(struct udevice *dev, u32 opcode)
+{
+	struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
+static int sdhci_execute_tuning(struct mmc *mmc, u32 opcode)
+{
+#endif
+	struct sdhci_host *host = mmc->priv;
+	u16 ctrl;
+
+	/*
+	 * The Host Controller needs tuning in case of SDR104 and DDR50
+	 * mode, and for SDR50 mode when Use Tuning for SDR50 is set in
+	 * the Capabilities register.
+	 * If the Host Controller supports the HS200 mode then the
+	 * tuning function has to be executed.
+	 */
+	switch (mmc->timing) {
+	/* HS400 tuning is done in HS200 mode */
+	case MMC_TIMING_MMC_HS400:
+		return -EINVAL;
+	case MMC_TIMING_MMC_HS200:
+		/*
+		 * Periodic re-tuning for HS400 is not expected to be needed, so
+		 * disable it here.
+		 */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+	ctrl |= SDHCI_CTRL_EXEC_TUNING;
+	sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+	return __sdhci_execute_tuning(host, opcode);
+}
+
 #ifdef CONFIG_DM_MMC_OPS
 int sdhci_probe(struct udevice *dev)
 {
@@ -571,6 +683,7 @@ const struct dm_mmc_ops sdhci_ops = {
 	.card_busy	= sdhci_card_busy,
 	.send_cmd	= sdhci_send_command,
 	.set_ios	= sdhci_set_ios,
+	.execute_tuning = sdhci_execute_tuning,
 };
 #else
 static const struct mmc_ops sdhci_ops = {
@@ -578,6 +691,7 @@ static const struct mmc_ops sdhci_ops = {
 	.send_cmd	= sdhci_send_command,
 	.set_ios	= sdhci_set_ios,
 	.init		= sdhci_init,
+	.execute_tuning = sdhci_execute_tuning,
 };
 #endif
 
-- 
2.7.4

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

* [U-Boot] [PATCH 31/33] mmc: add support for HS400 mode of eMMC5.0
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (28 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 30/33] mmc: sdhci: add the support for tuning Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 32/33] dts: rk3399: change the maximum eMMC clock frequency to 150MHz Ziyuan Xu
                   ` (2 subsequent siblings)
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

This patch adds HS400 mode support for eMMC5.0 device. HS400 mode is
high speed DDR interface timing from HS200. Clock frequency is up to
200MHz and only 8-bit bus width is supported. In addition, tuning
process of HS200 is required to synchronize the command response on the
CMD line because CMD input timing for HS400 mode is the same as HS200
mode.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 46 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index c1f54c3..71c9cfa 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -855,6 +855,45 @@ static int mmc_select_hs200(struct mmc *mmc)
 }
 #endif
 
+static int mmc_select_hs400(struct mmc *mmc)
+{
+	int ret;
+
+	/* Switch card to HS mode */
+	ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, false);
+	if (ret)
+		return ret;
+
+	/* Set host controller to HS timing */
+	mmc_set_timing(mmc, MMC_TIMING_MMC_HS);
+
+	/* Reduce frequency to HS frequency */
+	mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR);
+
+	ret = mmc_send_status(mmc, 1000);
+	if (ret)
+		return ret;
+
+	/* Switch card to DDR */
+	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_DDR_BUS_WIDTH_8);
+	if (ret)
+		return ret;
+
+	/* Switch card to HS400 */
+	ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400, false);
+	if (ret)
+		return ret;
+
+	/* Set host controller to HS400 timing and frequency */
+	mmc_set_timing(mmc, MMC_TIMING_MMC_HS400);
+
+	return ret;
+}
+
 static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd)
 {
 	u8 card_type;
@@ -960,9 +999,14 @@ static int mmc_change_freq(struct mmc *mmc)
 
 	mmc_set_bus_speed(mmc, avail_type);
 
-	if (mmc_card_hs200(mmc))
+	if (mmc_card_hs200(mmc)) {
 		err = mmc_hs200_tuning(mmc);
-	else if (!mmc_card_hs400es(mmc)) {
+		if (avail_type & EXT_CSD_CARD_TYPE_HS400 &&
+		    mmc->bus_width == MMC_BUS_WIDTH_8BIT) {
+			err = mmc_select_hs400(mmc);
+			mmc_set_bus_speed(mmc, avail_type);
+		}
+	} else if (!mmc_card_hs400es(mmc)) {
 		err = mmc_select_bus_width(mmc) > 0 ? 0 : err;
 		if (!err && avail_type & EXT_CSD_CARD_TYPE_DDR_52)
 			err = mmc_select_hs_ddr(mmc);
-- 
2.7.4

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

* [U-Boot] [PATCH 32/33] dts: rk3399: change the maximum eMMC clock frequency to 150MHz
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (29 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 31/33] mmc: add support for HS400 mode of eMMC5.0 Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-15  6:07 ` [U-Boot] [PATCH 33/33] SPL: tiny-printf: add "X" modifier Ziyuan Xu
  2017-05-16  0:18 ` [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Simon Glass
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

The rockchip mmc controllers don't support _the _odd__ divider,
otherwise probably cause unpredictable error.

The driver originally select gpll(594M) as the clock source, and we set
div to 3 at 200MHz. We have to change the maximum eMMC clock frequency
to 150MHz in U-Boot stage, so that the div will be 4.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 arch/arm/dts/rk3399.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/dts/rk3399.dtsi b/arch/arm/dts/rk3399.dtsi
index f3d3f53..b2122b6 100644
--- a/arch/arm/dts/rk3399.dtsi
+++ b/arch/arm/dts/rk3399.dtsi
@@ -283,7 +283,7 @@
 		arasan,soc-ctl-syscon = <&grf>;
 		assigned-clocks = <&cru SCLK_EMMC>;
 		assigned-clock-rates = <200000000>;
-		max-frequency = <200000000>;
+		max-frequency = <150000000>;
 		clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
 		clock-names = "clk_xin", "clk_ahb";
 		clock-output-names = "emmc_cardclock";
-- 
2.7.4

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

* [U-Boot] [PATCH 33/33] SPL: tiny-printf: add "X" modifier
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (30 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 32/33] dts: rk3399: change the maximum eMMC clock frequency to 150MHz Ziyuan Xu
@ 2017-05-15  6:07 ` Ziyuan Xu
  2017-05-16  0:18 ` [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Simon Glass
  32 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  6:07 UTC (permalink / raw)
  To: u-boot

tiny-printf does not know about the "X" modifier so far, which print
all zero. The mmc driver use '0x%08X' to print command argument and
response.

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 lib/tiny-printf.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c
index 0b04813..f1183d5 100644
--- a/lib/tiny-printf.c
+++ b/lib/tiny-printf.c
@@ -273,6 +273,7 @@ static int _vprintf(struct printf_info *info, const char *fmt, va_list va)
 				}
 				break;
 			case 'x':
+			case 'X':
 				if (islong) {
 					num = va_arg(va, unsigned long);
 					div = 1UL << (sizeof(long) * 8 - 4);
-- 
2.7.4

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

* [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps
  2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
                   ` (31 preceding siblings ...)
  2017-05-15  6:07 ` [U-Boot] [PATCH 33/33] SPL: tiny-printf: add "X" modifier Ziyuan Xu
@ 2017-05-16  0:18 ` Simon Glass
  2017-05-16  1:15   ` Ziyuan
  32 siblings, 1 reply; 45+ messages in thread
From: Simon Glass @ 2017-05-16  0:18 UTC (permalink / raw)
  To: u-boot

Hi Ziyuan,

On 15 May 2017 at 00:06, Ziyuan Xu <xzy.xu@rock-chips.com> wrote:
> The original implementation select HS timing by default, add available
> type selection for higher speed mode compatibility, such as hs200,
> hs400, hs400es.
>
> By the way, we assume that card run at 1.8V or 1.2V I/O when its timing
> is ddr52/hs200/hs400(es).
>
> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
> ---
>
>  drivers/mmc/mmc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  include/mmc.h     | 16 +++++++++++++++
>  2 files changed, 74 insertions(+), 1 deletion(-)
>

Is there a cover letter for this series, please?

I just reviewed an MMC series at add higher speed support. I'm not
sure but I suspect these overlap.

Regards,
Simon

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

* [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps
  2017-05-16  0:18 ` [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Simon Glass
@ 2017-05-16  1:15   ` Ziyuan
  2017-05-16  1:55     ` Jaehoon Chung
  2017-05-17  1:38     ` Simon Glass
  0 siblings, 2 replies; 45+ messages in thread
From: Ziyuan @ 2017-05-16  1:15 UTC (permalink / raw)
  To: u-boot

hi Simon & Jaehoon,

On 05/16/2017 08:18 AM, Simon Glass wrote:
> Hi Ziyuan,
>
> On 15 May 2017 at 00:06, Ziyuan Xu <xzy.xu@rock-chips.com> wrote:
>> The original implementation select HS timing by default, add available
>> type selection for higher speed mode compatibility, such as hs200,
>> hs400, hs400es.
>>
>> By the way, we assume that card run at 1.8V or 1.2V I/O when its timing
>> is ddr52/hs200/hs400(es).
>>
>> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
>> ---
>>
>>   drivers/mmc/mmc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>   include/mmc.h     | 16 +++++++++++++++
>>   2 files changed, 74 insertions(+), 1 deletion(-)
>>
> Is there a cover letter for this series, please?

This patchset is used for hs200/hs400/ddr52 mode of eMMC device, and 
fixes some bug for dw_mmc & sdhci controller.
It's only valid in U-Boot stage, we still use 'High Speed' in SPL.

I tested it on evb-rk3288 board(eMMC 4.5) and evb-rk3388 board(eMMC 5.0).
>
> I just reviewed an MMC series at add higher speed support. I'm not
> sure but I suspect these overlap.

Ha, I just reviewed Vignesh's patches, it focuses on uhs mode of sd 
card. It looks to me.
But some details are not the same as mine. Anyway, what do you think?

>
> Regards,
> Simon
>
>
>

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

* [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps
  2017-05-16  1:15   ` Ziyuan
@ 2017-05-16  1:55     ` Jaehoon Chung
  2017-05-16  2:22       ` Ziyuan
  2017-05-25  8:12       ` Ziyuan
  2017-05-17  1:38     ` Simon Glass
  1 sibling, 2 replies; 45+ messages in thread
From: Jaehoon Chung @ 2017-05-16  1:55 UTC (permalink / raw)
  To: u-boot

Hi Ziyuan,

On 05/16/2017 10:15 AM, Ziyuan wrote:
> hi Simon & Jaehoon,
> 
> On 05/16/2017 08:18 AM, Simon Glass wrote:
>> Hi Ziyuan,
>>
>> On 15 May 2017 at 00:06, Ziyuan Xu <xzy.xu@rock-chips.com> wrote:
>>> The original implementation select HS timing by default, add available
>>> type selection for higher speed mode compatibility, such as hs200,
>>> hs400, hs400es.
>>>
>>> By the way, we assume that card run at 1.8V or 1.2V I/O when its timing
>>> is ddr52/hs200/hs400(es).
>>>
>>> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
>>> ---
>>>
>>>   drivers/mmc/mmc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>>   include/mmc.h     | 16 +++++++++++++++
>>>   2 files changed, 74 insertions(+), 1 deletion(-)
>>>
>> Is there a cover letter for this series, please?
> 
> This patchset is used for hs200/hs400/ddr52 mode of eMMC device, and fixes some bug for dw_mmc & sdhci controller.
> It's only valid in U-Boot stage, we still use 'High Speed' in SPL.
> 
> I tested it on evb-rk3288 board(eMMC 4.5) and evb-rk3388 board(eMMC 5.0).
>>
>> I just reviewed an MMC series at add higher speed support. I'm not
>> sure but I suspect these overlap.
> 
> Ha, I just reviewed Vignesh's patches, it focuses on uhs mode of sd card. It looks to me.
> But some details are not the same as mine. Anyway, what do you think?

I didn't review both yet..After checking, i will share my opinion. how about?

> 
>>
>> Regards,
>> Simon
>>
>>
>>
> 
> 
> 
> 
> 

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

* [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps
  2017-05-16  1:55     ` Jaehoon Chung
@ 2017-05-16  2:22       ` Ziyuan
  2017-05-25  8:12       ` Ziyuan
  1 sibling, 0 replies; 45+ messages in thread
From: Ziyuan @ 2017-05-16  2:22 UTC (permalink / raw)
  To: u-boot

hi Jaehoon,

On 05/16/2017 09:55 AM, Jaehoon Chung wrote:
> Hi Ziyuan,
>
> On 05/16/2017 10:15 AM, Ziyuan wrote:
>> hi Simon & Jaehoon,
>>
>> On 05/16/2017 08:18 AM, Simon Glass wrote:
>>> Hi Ziyuan,
>>>
>>> On 15 May 2017 at 00:06, Ziyuan Xu <xzy.xu@rock-chips.com> wrote:
>>>> The original implementation select HS timing by default, add available
>>>> type selection for higher speed mode compatibility, such as hs200,
>>>> hs400, hs400es.
>>>>
>>>> By the way, we assume that card run at 1.8V or 1.2V I/O when its timing
>>>> is ddr52/hs200/hs400(es).
>>>>
>>>> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
>>>> ---
>>>>
>>>>    drivers/mmc/mmc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>>>    include/mmc.h     | 16 +++++++++++++++
>>>>    2 files changed, 74 insertions(+), 1 deletion(-)
>>>>
>>> Is there a cover letter for this series, please?
>> This patchset is used for hs200/hs400/ddr52 mode of eMMC device, and fixes some bug for dw_mmc & sdhci controller.
>> It's only valid in U-Boot stage, we still use 'High Speed' in SPL.
>>
>> I tested it on evb-rk3288 board(eMMC 4.5) and evb-rk3388 board(eMMC 5.0).
>>> I just reviewed an MMC series at add higher speed support. I'm not
>>> sure but I suspect these overlap.
>> Ha, I just reviewed Vignesh's patches, it focuses on uhs mode of sd card. It looks to me.
>> But some details are not the same as mine. Anyway, what do you think?
> I didn't review both yet..After checking, i will share my opinion. how about?

Fine, I look forward to your opinion.
>
>>> Regards,
>>> Simon
>>>
>>>
>>>
>>
>>
>>
>>
>
>
>

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

* [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps
  2017-05-16  1:15   ` Ziyuan
  2017-05-16  1:55     ` Jaehoon Chung
@ 2017-05-17  1:38     ` Simon Glass
  1 sibling, 0 replies; 45+ messages in thread
From: Simon Glass @ 2017-05-17  1:38 UTC (permalink / raw)
  To: u-boot

Hi,

On 15 May 2017 at 19:15, Ziyuan <xzy.xu@rock-chips.com> wrote:
> hi Simon & Jaehoon,
>
> On 05/16/2017 08:18 AM, Simon Glass wrote:
>>
>> Hi Ziyuan,
>>
>> On 15 May 2017 at 00:06, Ziyuan Xu <xzy.xu@rock-chips.com> wrote:
>>>
>>> The original implementation select HS timing by default, add available
>>> type selection for higher speed mode compatibility, such as hs200,
>>> hs400, hs400es.
>>>
>>> By the way, we assume that card run at 1.8V or 1.2V I/O when its timing
>>> is ddr52/hs200/hs400(es).
>>>
>>> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
>>> ---
>>>
>>>   drivers/mmc/mmc.c | 59
>>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>>   include/mmc.h     | 16 +++++++++++++++
>>>   2 files changed, 74 insertions(+), 1 deletion(-)
>>>
>> Is there a cover letter for this series, please?
>
>
> This patchset is used for hs200/hs400/ddr52 mode of eMMC device, and fixes
> some bug for dw_mmc & sdhci controller.
> It's only valid in U-Boot stage, we still use 'High Speed' in SPL.
>
> I tested it on evb-rk3288 board(eMMC 4.5) and evb-rk3388 board(eMMC 5.0).
>>
>>
>> I just reviewed an MMC series at add higher speed support. I'm not
>> sure but I suspect these overlap.
>
>
> Ha, I just reviewed Vignesh's patches, it focuses on uhs mode of sd card. It
> looks to me.
> But some details are not the same as mine. Anyway, what do you think?

I think the other series should go in first, so if there are conflicts
can you rebase on top of it?

Regards,
Simon

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

* [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps
  2017-05-16  1:55     ` Jaehoon Chung
  2017-05-16  2:22       ` Ziyuan
@ 2017-05-25  8:12       ` Ziyuan
  2017-05-25 10:50         ` Jaehoon Chung
  2017-05-25 13:08         ` Jaehoon Chung
  1 sibling, 2 replies; 45+ messages in thread
From: Ziyuan @ 2017-05-25  8:12 UTC (permalink / raw)
  To: u-boot

hi Jaehoon,

On 05/16/2017 09:55 AM, Jaehoon Chung wrote:
> Hi Ziyuan,
>
> On 05/16/2017 10:15 AM, Ziyuan wrote:
>> hi Simon & Jaehoon,
>>
>> On 05/16/2017 08:18 AM, Simon Glass wrote:
>>> Hi Ziyuan,
>>>
>>> On 15 May 2017 at 00:06, Ziyuan Xu <xzy.xu@rock-chips.com> wrote:
>>>> The original implementation select HS timing by default, add available
>>>> type selection for higher speed mode compatibility, such as hs200,
>>>> hs400, hs400es.
>>>>
>>>> By the way, we assume that card run at 1.8V or 1.2V I/O when its timing
>>>> is ddr52/hs200/hs400(es).
>>>>
>>>> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
>>>> ---
>>>>
>>>>    drivers/mmc/mmc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>>>    include/mmc.h     | 16 +++++++++++++++
>>>>    2 files changed, 74 insertions(+), 1 deletion(-)
>>>>
>>> Is there a cover letter for this series, please?
>> This patchset is used for hs200/hs400/ddr52 mode of eMMC device, and fixes some bug for dw_mmc & sdhci controller.
>> It's only valid in U-Boot stage, we still use 'High Speed' in SPL.
>>
>> I tested it on evb-rk3288 board(eMMC 4.5) and evb-rk3388 board(eMMC 5.0).
>>> I just reviewed an MMC series at add higher speed support. I'm not
>>> sure but I suspect these overlap.
>> Ha, I just reviewed Vignesh's patches, it focuses on uhs mode of sd card. It looks to me.
>> But some details are not the same as mine. Anyway, what do you think?
> I didn't review both yet..After checking, i will share my opinion. how about?

*ping*...
Did you test this patchset on Samsung platform? As far as I know, 
Samsung SoCs also make use of dw_mmc and sdhci controllers.

>
>>> Regards,
>>> Simon
>>>
>>>
>>>
>>
>>
>>
>>
>
>
>

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

* [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps
  2017-05-25  8:12       ` Ziyuan
@ 2017-05-25 10:50         ` Jaehoon Chung
  2017-05-25 13:08         ` Jaehoon Chung
  1 sibling, 0 replies; 45+ messages in thread
From: Jaehoon Chung @ 2017-05-25 10:50 UTC (permalink / raw)
  To: u-boot

On 05/25/2017 05:12 PM, Ziyuan wrote:
> hi Jaehoon,
> 
> On 05/16/2017 09:55 AM, Jaehoon Chung wrote:
>> Hi Ziyuan,
>>
>> On 05/16/2017 10:15 AM, Ziyuan wrote:
>>> hi Simon & Jaehoon,
>>>
>>> On 05/16/2017 08:18 AM, Simon Glass wrote:
>>>> Hi Ziyuan,
>>>>
>>>> On 15 May 2017 at 00:06, Ziyuan Xu <xzy.xu@rock-chips.com> wrote:
>>>>> The original implementation select HS timing by default, add available
>>>>> type selection for higher speed mode compatibility, such as hs200,
>>>>> hs400, hs400es.
>>>>>
>>>>> By the way, we assume that card run at 1.8V or 1.2V I/O when its timing
>>>>> is ddr52/hs200/hs400(es).
>>>>>
>>>>> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
>>>>> ---
>>>>>
>>>>>    drivers/mmc/mmc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>>>>    include/mmc.h     | 16 +++++++++++++++
>>>>>    2 files changed, 74 insertions(+), 1 deletion(-)
>>>>>
>>>> Is there a cover letter for this series, please?
>>> This patchset is used for hs200/hs400/ddr52 mode of eMMC device, and fixes some bug for dw_mmc & sdhci controller.
>>> It's only valid in U-Boot stage, we still use 'High Speed' in SPL.
>>>
>>> I tested it on evb-rk3288 board(eMMC 4.5) and evb-rk3388 board(eMMC 5.0).
>>>> I just reviewed an MMC series at add higher speed support. I'm not
>>>> sure but I suspect these overlap.
>>> Ha, I just reviewed Vignesh's patches, it focuses on uhs mode of sd card. It looks to me.
>>> But some details are not the same as mine. Anyway, what do you think?
>> I didn't review both yet..After checking, i will share my opinion. how about?
> 
> *ping*...
> Did you test this patchset on Samsung platform? As far as I know, Samsung SoCs also make use of dw_mmc and sdhci controllers.

Sorry for late..Sure I will test this..Thanks for kindly ping.

Best Regards,
Jaehoon Chung

> 
>>
>>>> Regards,
>>>> Simon
>>>>
>>>>
>>>>
>>>
>>>
>>>
>>>
>>
>>
>>
> 
> 
> 
> 
> 

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

* [U-Boot] [PATCH 06/33] mmc: add card_busy to query card status
  2017-05-15  6:07 ` [U-Boot] [PATCH 06/33] mmc: add card_busy to query card status Ziyuan Xu
@ 2017-05-25 13:02   ` Jaehoon Chung
  0 siblings, 0 replies; 45+ messages in thread
From: Jaehoon Chung @ 2017-05-25 13:02 UTC (permalink / raw)
  To: u-boot

On 05/15/2017 03:07 PM, Ziyuan Xu wrote:
> Card devices get into busy status since host request speed mode
> switch, if host controller is able to query whether the device is busy,
> try it instead of sending cmd13.

This patch is similar to one of Jean-Jacques's patches.

> 
> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
> ---
> 
>  drivers/mmc/mmc-uclass.c | 16 ++++++++++++++++
>  drivers/mmc/mmc.c        | 13 +++++++++++++
>  include/mmc.h            | 11 +++++++++++
>  3 files changed, 40 insertions(+)
> 
> diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
> index 9c07871..a300a6d 100644
> --- a/drivers/mmc/mmc-uclass.c
> +++ b/drivers/mmc/mmc-uclass.c
> @@ -38,6 +38,22 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
>  	return dm_mmc_send_cmd(mmc->dev, cmd, data);
>  }
>  
> +bool mmc_card_busy(struct mmc *mmc)
> +{
> +	struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev);
> +
> +	if (!ops->card_busy)
> +		return -ENOSYS;

return is ENOSYS but this function is return bool type..fix it.

> +	return ops->card_busy(mmc->dev);
> +}
> +
> +bool mmc_can_card_busy(struct mmc *mmc)
> +{
> +	struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev);
> +
> +	return !!ops->card_busy;
> +}
> +
>  int dm_mmc_set_ios(struct udevice *dev)
>  {
>  	struct dm_mmc_ops *ops = mmc_get_ops(dev);
> diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
> index 0b30172..13d8f04 100644
> --- a/drivers/mmc/mmc.c
> +++ b/drivers/mmc/mmc.c
> @@ -1156,6 +1156,19 @@ static void mmc_set_ios(struct mmc *mmc)
>  	if (mmc->cfg->ops->set_ios)
>  		mmc->cfg->ops->set_ios(mmc);
>  }
> +
> +static bool mmc_card_busy(struct mmc *mmc)
> +{
> +	if (!mmc->cfg->ops->card_busy)
> +		return -ENOSYS;
> +
> +	return mmc->cfg->ops->card_busy(mmc);

ditto.

> +}
> +
> +static bool mmc_can_card_busy(struct mmc *)
> +{
> +	return !!mmc->cfg->ops->card_busy;
> +}
>  #endif
>  
>  void mmc_set_clock(struct mmc *mmc, uint clock)
> diff --git a/include/mmc.h b/include/mmc.h
> index 060c1f8..9bed935 100644
> --- a/include/mmc.h
> +++ b/include/mmc.h
> @@ -357,6 +357,14 @@ struct dm_mmc_ops {
>  			struct mmc_data *data);
>  
>  	/**
> +	 * card_busy() - Query the card device status
> +	 *
> +	 * @dev:	Device to update
> +	 * @return true if card device is busy
> +	 */
> +	bool (*card_busy)(struct udevice *dev);
> +
> +	/**
>  	 * set_ios() - Set the I/O speed/width for an MMC device
>  	 *
>  	 * @dev:	Device to update
> @@ -390,12 +398,15 @@ int dm_mmc_get_cd(struct udevice *dev);
>  int dm_mmc_get_wp(struct udevice *dev);
>  
>  /* Transition functions for compatibility */
> +bool mmc_card_busy(struct mmc *mmc);
> +bool mmc_can_card_busy(struct mmc *mmc);
>  int mmc_set_ios(struct mmc *mmc);
>  int mmc_getcd(struct mmc *mmc);
>  int mmc_getwp(struct mmc *mmc);
>  
>  #else
>  struct mmc_ops {
> +	bool (*card_busy)(struct mmc *mmc);
>  	int (*send_cmd)(struct mmc *mmc,
>  			struct mmc_cmd *cmd, struct mmc_data *data);
>  	int (*set_ios)(struct mmc *mmc);
> 

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

* [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps
  2017-05-25  8:12       ` Ziyuan
  2017-05-25 10:50         ` Jaehoon Chung
@ 2017-05-25 13:08         ` Jaehoon Chung
  2017-06-05  0:50           ` Ziyuan
  1 sibling, 1 reply; 45+ messages in thread
From: Jaehoon Chung @ 2017-05-25 13:08 UTC (permalink / raw)
  To: u-boot

Hi Ziyuan,

On 05/25/2017 05:12 PM, Ziyuan wrote:
> hi Jaehoon,
> 
> On 05/16/2017 09:55 AM, Jaehoon Chung wrote:
>> Hi Ziyuan,
>>
>> On 05/16/2017 10:15 AM, Ziyuan wrote:
>>> hi Simon & Jaehoon,
>>>
>>> On 05/16/2017 08:18 AM, Simon Glass wrote:
>>>> Hi Ziyuan,
>>>>
>>>> On 15 May 2017 at 00:06, Ziyuan Xu <xzy.xu@rock-chips.com> wrote:
>>>>> The original implementation select HS timing by default, add available
>>>>> type selection for higher speed mode compatibility, such as hs200,
>>>>> hs400, hs400es.
>>>>>
>>>>> By the way, we assume that card run at 1.8V or 1.2V I/O when its timing
>>>>> is ddr52/hs200/hs400(es).
>>>>>
>>>>> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
>>>>> ---
>>>>>
>>>>>    drivers/mmc/mmc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>>>>    include/mmc.h     | 16 +++++++++++++++
>>>>>    2 files changed, 74 insertions(+), 1 deletion(-)
>>>>>
>>>> Is there a cover letter for this series, please?
>>> This patchset is used for hs200/hs400/ddr52 mode of eMMC device, and fixes some bug for dw_mmc & sdhci controller.
>>> It's only valid in U-Boot stage, we still use 'High Speed' in SPL.
>>>
>>> I tested it on evb-rk3288 board(eMMC 4.5) and evb-rk3388 board(eMMC 5.0).
>>>> I just reviewed an MMC series at add higher speed support. I'm not
>>>> sure but I suspect these overlap.
>>> Ha, I just reviewed Vignesh's patches, it focuses on uhs mode of sd card. It looks to me.
>>> But some details are not the same as mine. Anyway, what do you think?
>> I didn't review both yet..After checking, i will share my opinion. how about?
> 
> *ping*...
> Did you test this patchset on Samsung platform? As far as I know, Samsung SoCs also make use of dw_mmc and sdhci controllers.

some details are not the same as yours..but some points are duplicated.
DWMMC and  sdhci controller side are not duplicated..

As i am feeling..your patches are based on Linux kernel code..right?

> 
>>
>>>> Regards,
>>>> Simon
>>>>
>>>>
>>>>
>>>
>>>
>>>
>>>
>>
>>
>>
> 
> 
> 
> 
> 

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

* [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps
  2017-05-25 13:08         ` Jaehoon Chung
@ 2017-06-05  0:50           ` Ziyuan
  2017-06-05  1:13             ` Jaehoon Chung
  0 siblings, 1 reply; 45+ messages in thread
From: Ziyuan @ 2017-06-05  0:50 UTC (permalink / raw)
  To: u-boot

hi Jaehoon,

On 05/25/2017 09:08 PM, Jaehoon Chung wrote:
> Hi Ziyuan,
>
> On 05/25/2017 05:12 PM, Ziyuan wrote:
>> hi Jaehoon,
>>
>> On 05/16/2017 09:55 AM, Jaehoon Chung wrote:
>>> Hi Ziyuan,
>>>
>>> On 05/16/2017 10:15 AM, Ziyuan wrote:
>>>> hi Simon & Jaehoon,
>>>>
>>>> On 05/16/2017 08:18 AM, Simon Glass wrote:
>>>>> Hi Ziyuan,
>>>>>
>>>>> On 15 May 2017 at 00:06, Ziyuan Xu <xzy.xu@rock-chips.com> wrote:
>>>>>> The original implementation select HS timing by default, add available
>>>>>> type selection for higher speed mode compatibility, such as hs200,
>>>>>> hs400, hs400es.
>>>>>>
>>>>>> By the way, we assume that card run at 1.8V or 1.2V I/O when its timing
>>>>>> is ddr52/hs200/hs400(es).
>>>>>>
>>>>>> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
>>>>>> ---
>>>>>>
>>>>>>     drivers/mmc/mmc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>>>>>     include/mmc.h     | 16 +++++++++++++++
>>>>>>     2 files changed, 74 insertions(+), 1 deletion(-)
>>>>>>
>>>>> Is there a cover letter for this series, please?
>>>> This patchset is used for hs200/hs400/ddr52 mode of eMMC device, and fixes some bug for dw_mmc & sdhci controller.
>>>> It's only valid in U-Boot stage, we still use 'High Speed' in SPL.
>>>>
>>>> I tested it on evb-rk3288 board(eMMC 4.5) and evb-rk3388 board(eMMC 5.0).
>>>>> I just reviewed an MMC series at add higher speed support. I'm not
>>>>> sure but I suspect these overlap.
>>>> Ha, I just reviewed Vignesh's patches, it focuses on uhs mode of sd card. It looks to me.
>>>> But some details are not the same as mine. Anyway, what do you think?
>>> I didn't review both yet..After checking, i will share my opinion. how about?
>> *ping*...
>> Did you test this patchset on Samsung platform? As far as I know, Samsung SoCs also make use of dw_mmc and sdhci controllers.
> some details are not the same as yours..but some points are duplicated.
> DWMMC and  sdhci controller side are not duplicated..
>
> As i am feeling..your patches are based on Linux kernel code..right?

Yup, the kernel's mmc driver is stabilized and it was tested on so many 
various boards.
Simon had review Jean-jacques's patch,  but a little glitch need to be 
debugged.  So I should wait for him, and rebase?

>>>>> Regards,
>>>>> Simon
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>>
>>
>
>
>

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

* [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps
  2017-06-05  0:50           ` Ziyuan
@ 2017-06-05  1:13             ` Jaehoon Chung
  0 siblings, 0 replies; 45+ messages in thread
From: Jaehoon Chung @ 2017-06-05  1:13 UTC (permalink / raw)
  To: u-boot

Hi Ziyuan,

On 06/05/2017 09:50 AM, Ziyuan wrote:
> hi Jaehoon,
> 
> On 05/25/2017 09:08 PM, Jaehoon Chung wrote:
>> Hi Ziyuan,
>>
>> On 05/25/2017 05:12 PM, Ziyuan wrote:
>>> hi Jaehoon,
>>>
>>> On 05/16/2017 09:55 AM, Jaehoon Chung wrote:
>>>> Hi Ziyuan,
>>>>
>>>> On 05/16/2017 10:15 AM, Ziyuan wrote:
>>>>> hi Simon & Jaehoon,
>>>>>
>>>>> On 05/16/2017 08:18 AM, Simon Glass wrote:
>>>>>> Hi Ziyuan,
>>>>>>
>>>>>> On 15 May 2017 at 00:06, Ziyuan Xu <xzy.xu@rock-chips.com> wrote:
>>>>>>> The original implementation select HS timing by default, add available
>>>>>>> type selection for higher speed mode compatibility, such as hs200,
>>>>>>> hs400, hs400es.
>>>>>>>
>>>>>>> By the way, we assume that card run at 1.8V or 1.2V I/O when its timing
>>>>>>> is ddr52/hs200/hs400(es).
>>>>>>>
>>>>>>> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
>>>>>>> ---
>>>>>>>
>>>>>>>     drivers/mmc/mmc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>>>>>>     include/mmc.h     | 16 +++++++++++++++
>>>>>>>     2 files changed, 74 insertions(+), 1 deletion(-)
>>>>>>>
>>>>>> Is there a cover letter for this series, please?
>>>>> This patchset is used for hs200/hs400/ddr52 mode of eMMC device, and fixes some bug for dw_mmc & sdhci controller.
>>>>> It's only valid in U-Boot stage, we still use 'High Speed' in SPL.
>>>>>
>>>>> I tested it on evb-rk3288 board(eMMC 4.5) and evb-rk3388 board(eMMC 5.0).
>>>>>> I just reviewed an MMC series at add higher speed support. I'm not
>>>>>> sure but I suspect these overlap.
>>>>> Ha, I just reviewed Vignesh's patches, it focuses on uhs mode of sd card. It looks to me.
>>>>> But some details are not the same as mine. Anyway, what do you think?
>>>> I didn't review both yet..After checking, i will share my opinion. how about?
>>> *ping*...
>>> Did you test this patchset on Samsung platform? As far as I know, Samsung SoCs also make use of dw_mmc and sdhci controllers.
>> some details are not the same as yours..but some points are duplicated.
>> DWMMC and  sdhci controller side are not duplicated..
>>
>> As i am feeling..your patches are based on Linux kernel code..right?
> 
> Yup, the kernel's mmc driver is stabilized and it was tested on so many various boards.
> Simon had review Jean-jacques's patch,  but a little glitch need to be debugged.  So I should wait for him, and rebase?

I will make a branch for testing about HS200 and UHS-I..then you can make the patches based on it.
Well, after making branch, i will share it at mailing. Thanks for your effort!

Best Regards,
Jaehoon Chung

> 
>>>>>> Regards,
>>>>>> Simon
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>>
>>>
>>
>>
>>
> 
> 
> 
> 
> 

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

* [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps
@ 2017-05-15  5:56 Ziyuan Xu
  0 siblings, 0 replies; 45+ messages in thread
From: Ziyuan Xu @ 2017-05-15  5:56 UTC (permalink / raw)
  To: u-boot

The original implementation select HS timing by default, add available
type selection for higher speed mode compatibility, such as hs200,
hs400, hs400es.

By the way, we assume that card run at 1.8V or 1.2V I/O when its timing
is ddr52/hs200/hs400(es).

Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
---

 drivers/mmc/mmc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 include/mmc.h     | 16 +++++++++++++++
 2 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 72fc177..f5b2280 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -546,10 +546,62 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
 
 }
 
+static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd)
+{
+	u8 card_type;
+	u32 host_caps, avail_type = 0;
+
+	card_type = ext_csd[EXT_CSD_CARD_TYPE];
+	host_caps = mmc->cfg->host_caps;
+
+	if ((host_caps & MMC_MODE_HS) &&
+	    (card_type & EXT_CSD_CARD_TYPE_26))
+		avail_type |= EXT_CSD_CARD_TYPE_26;
+
+	if ((host_caps & MMC_MODE_HS) &&
+	    (card_type & EXT_CSD_CARD_TYPE_52))
+		avail_type |= EXT_CSD_CARD_TYPE_52;
+
+	/*
+	 * For the moment, u-boot doesn't support signal voltage
+	 * switch, therefor we assume that host support ddr52
+	 * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and
+	 * hs400 are the same).
+	 */
+	if ((host_caps & MMC_MODE_DDR_52MHz) &&
+	    (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V))
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
+
+	if ((host_caps & MMC_MODE_HS200) &&
+	    (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V))
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
+
+	/*
+	 * If host can support HS400, it means that host can also
+	 * support HS200.
+	 */
+	if ((host_caps & MMC_MODE_HS400) &&
+	    (host_caps & MMC_MODE_8BIT) &&
+	    (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
+				EXT_CSD_CARD_TYPE_HS400_1_8V;
+
+	if ((host_caps & MMC_MODE_HS400ES) &&
+	    (host_caps & MMC_MODE_8BIT) &&
+	    ext_csd[EXT_CSD_STROBE_SUPPORT] &&
+	    (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
+				EXT_CSD_CARD_TYPE_HS400_1_8V |
+				EXT_CSD_CARD_TYPE_HS400ES;
+
+	return avail_type;
+}
+
 static int mmc_change_freq(struct mmc *mmc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
 	char cardtype;
+	u32 avail_type;
 	int err;
 
 	mmc->card_caps = 0;
@@ -569,8 +621,13 @@ static int mmc_change_freq(struct mmc *mmc)
 		return err;
 
 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
+	avail_type = mmc_select_card_type(mmc, ext_csd);
 
-	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
+	if (avail_type & EXT_CSD_CARD_TYPE_HS)
+		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_HS_TIMING, 1);
+	else
+		err = -EINVAL;
 
 	if (err)
 		return err;
diff --git a/include/mmc.h b/include/mmc.h
index fad12d6..0bae1a1 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -58,6 +58,9 @@
 #define MMC_MODE_8BIT		(1 << 3)
 #define MMC_MODE_SPI		(1 << 4)
 #define MMC_MODE_DDR_52MHz	(1 << 5)
+#define MMC_MODE_HS200		(1 << 6)
+#define MMC_MODE_HS400		(1 << 7)
+#define MMC_MODE_HS400ES	(1 << 8)
 
 #define SD_DATA_4BIT	0x00040000
 
@@ -182,6 +185,7 @@
 #define EXT_CSD_BOOT_BUS_WIDTH		177
 #define EXT_CSD_PART_CONF		179	/* R/W */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
+#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
 #define EXT_CSD_REV			192	/* RO */
 #define EXT_CSD_CARD_TYPE		196	/* RO */
@@ -201,6 +205,18 @@
 
 #define EXT_CSD_CARD_TYPE_26	(1 << 0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_52	(1 << 1)	/* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_26 | \
+				 EXT_CSD_CARD_TYPE_52)
+#define EXT_CSD_CARD_TYPE_HS200_1_8V	BIT(4)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_2V	BIT(5)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS200_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400_1_8V	BIT(6)	/* Card can run at 200MHz DDR, 1.8V */
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	BIT(7)	/* Card can run at 200MHz DDR, 1.2V */
+#define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS400_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400ES	BIT(8)	/* Card can run@HS400ES */
+
 #define EXT_CSD_CARD_TYPE_DDR_1_8V	(1 << 2)
 #define EXT_CSD_CARD_TYPE_DDR_1_2V	(1 << 3)
 #define EXT_CSD_CARD_TYPE_DDR_52	(EXT_CSD_CARD_TYPE_DDR_1_8V \
-- 
2.7.4

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

end of thread, other threads:[~2017-06-05  1:13 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-15  6:06 [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Ziyuan Xu
2017-05-15  6:06 ` [U-Boot] [PATCH 02/33] mmc: add set_timing entry for timing selection Ziyuan Xu
2017-05-15  6:06 ` [U-Boot] [PATCH 03/33] mmc: xenon_sdhci: drop redundant timing definitions Ziyuan Xu
2017-05-15  6:06 ` [U-Boot] [PATCH 04/33] mmc: rework high speed mode selection Ziyuan Xu
2017-05-15  6:06 ` [U-Boot] [PATCH 05/33] mmc: sdhci: fix HISPD bit setting Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 06/33] mmc: add card_busy to query card status Ziyuan Xu
2017-05-25 13:02   ` Jaehoon Chung
2017-05-15  6:07 ` [U-Boot] [PATCH 07/33] mmc: dw_mmc: implement card_busy detection Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 08/33] mmc: sdhci: " Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 09/33] mmc: rework mmc_switch for non-send_status scenario Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 10/33] mmc: add support for HS200 mode of eMMC4.5 Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 11/33] mmc: rework ddr mode judgement with timing Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 12/33] mmc: remove tran_speed from struct mmc Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 13/33] cmd: mmc: show the current speed mode Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 14/33] clk: introduce clk_phase get/set function & callback Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 15/33] rockchip: clk: rk3288: fix mmc clock setting Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 16/33] rockchip: clk: rk3288: add support for the clock phase Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 17/33] rockchip: clk: rk3399: fix emmc clock setting Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 18/33] mmc: dw_mmc: add the support for the tuning scheme Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 19/33] mmc: dw_mmc: rockchip: implement tuning with clock phase framework Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 20/33] mmc: dw_mmc: reset controller after data error Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 21/33] mmc: add DDR52 support for eMMC card Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 22/33] mmc: dw_mmc: rockchip: fix data crc error on ddr52 8bit mode Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 23/33] mmc: dw_mmc: fix bus width setting Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 24/33] mmc: sdhci: rockchip: " Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 25/33] mmc: sdhci: update host->clock after clock setting Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 26/33] mmc: sdhci: add support for UHS timing Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 27/33] mmc: sdhci: rename set_clock callback Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 28/33] mmc: sdhci: export sdhci_set_clock() Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 29/33] mmc: sdhci: rockchip: add phy support Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 30/33] mmc: sdhci: add the support for tuning Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 31/33] mmc: add support for HS400 mode of eMMC5.0 Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 32/33] dts: rk3399: change the maximum eMMC clock frequency to 150MHz Ziyuan Xu
2017-05-15  6:07 ` [U-Boot] [PATCH 33/33] SPL: tiny-printf: add "X" modifier Ziyuan Xu
2017-05-16  0:18 ` [U-Boot] [PATCH 01/33] mmc: select the available type from host_caps and card_caps Simon Glass
2017-05-16  1:15   ` Ziyuan
2017-05-16  1:55     ` Jaehoon Chung
2017-05-16  2:22       ` Ziyuan
2017-05-25  8:12       ` Ziyuan
2017-05-25 10:50         ` Jaehoon Chung
2017-05-25 13:08         ` Jaehoon Chung
2017-06-05  0:50           ` Ziyuan
2017-06-05  1:13             ` Jaehoon Chung
2017-05-17  1:38     ` Simon Glass
  -- strict thread matches above, loose matches on Subject: below --
2017-05-15  5:56 Ziyuan Xu

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.