All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] mmc: tmio: Use modern PM ops
@ 2013-11-05 12:10 Ulf Hansson
  2013-11-05 12:10 ` [PATCH 1/3] mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks Ulf Hansson
                   ` (36 more replies)
  0 siblings, 37 replies; 182+ messages in thread
From: Ulf Hansson @ 2013-11-05 12:10 UTC (permalink / raw)
  To: linux-mmc, Chris Ball, Guennadi Liakhovetski, Ian Molton; +Cc: Ulf Hansson

This patchset converts tmio and sh_mobile_sdhi to use the modern PM ops.

Ulf Hansson (3):
  mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks
  mmc: tmio_mmc: Convert from legacy to modern PM ops
  mmc: tmio: Adapt to proper PM configs for exported functions

 drivers/mmc/host/sh_mobile_sdhi.c |    8 ++++----
 drivers/mmc/host/tmio_mmc.c       |   32 ++++++++++++++++++--------------
 drivers/mmc/host/tmio_mmc.h       |    7 +++----
 drivers/mmc/host/tmio_mmc_pio.c   |    7 ++++---
 4 files changed, 29 insertions(+), 25 deletions(-)

-- 
1.7.9.5


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

* [PATCH 1/3] mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
@ 2013-11-05 12:10 ` Ulf Hansson
  2013-11-05 22:29   ` Guennadi Liakhovetski
  2013-11-05 12:10 ` [PATCH 2/3] mmc: tmio_mmc: Convert from legacy to modern PM ops Ulf Hansson
                   ` (35 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2013-11-05 12:10 UTC (permalink / raw)
  To: linux-mmc, Chris Ball, Guennadi Liakhovetski, Ian Molton; +Cc: Ulf Hansson

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/sh_mobile_sdhi.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 87ed3fb..2227a9f 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -297,10 +297,10 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
 }
 
 static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
-	.suspend = tmio_mmc_host_suspend,
-	.resume = tmio_mmc_host_resume,
-	.runtime_suspend = tmio_mmc_host_runtime_suspend,
-	.runtime_resume = tmio_mmc_host_runtime_resume,
+	SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_host_suspend, tmio_mmc_host_resume)
+	SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
+			tmio_mmc_host_runtime_resume,
+			NULL)
 };
 
 static struct platform_driver sh_mobile_sdhi_driver = {
-- 
1.7.9.5


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

* [PATCH 2/3] mmc: tmio_mmc: Convert from legacy to modern PM ops
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
  2013-11-05 12:10 ` [PATCH 1/3] mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks Ulf Hansson
@ 2013-11-05 12:10 ` Ulf Hansson
  2013-11-05 22:24   ` Guennadi Liakhovetski
  2013-11-05 12:10 ` [PATCH 3/3] mmc: tmio: Adapt to proper PM configs for exported functions Ulf Hansson
                   ` (34 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2013-11-05 12:10 UTC (permalink / raw)
  To: linux-mmc, Chris Ball, Guennadi Liakhovetski, Ian Molton; +Cc: Ulf Hansson

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/tmio_mmc.c |   32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index 8860d4d..a56a3fe 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -23,38 +23,39 @@
 
 #include "tmio_mmc.h"
 
-#ifdef CONFIG_PM
-static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int tmio_mmc_suspend(struct device *dev)
 {
-	const struct mfd_cell *cell = mfd_get_cell(dev);
+	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+	const struct mfd_cell *cell = mfd_get_cell(host->pdev);
 	int ret;
 
-	ret = tmio_mmc_host_suspend(&dev->dev);
+	ret = tmio_mmc_host_suspend(dev);
 
 	/* Tell MFD core it can disable us now.*/
 	if (!ret && cell->disable)
-		cell->disable(dev);
+		cell->disable(host->pdev);
 
 	return ret;
 }
 
-static int tmio_mmc_resume(struct platform_device *dev)
+static int tmio_mmc_resume(struct device *dev)
 {
-	const struct mfd_cell *cell = mfd_get_cell(dev);
+	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+	const struct mfd_cell *cell = mfd_get_cell(host->pdev);
 	int ret = 0;
 
 	/* Tell the MFD core we are ready to be enabled */
 	if (cell->resume)
-		ret = cell->resume(dev);
+		ret = cell->resume(host->pdev);
 
 	if (!ret)
-		ret = tmio_mmc_host_resume(&dev->dev);
+		ret = tmio_mmc_host_resume(dev);
 
 	return ret;
 }
-#else
-#define tmio_mmc_suspend NULL
-#define tmio_mmc_resume NULL
 #endif
 
 static int tmio_mmc_probe(struct platform_device *pdev)
@@ -125,15 +126,18 @@ static int tmio_mmc_remove(struct platform_device *pdev)
 
 /* ------------------- device registration ----------------------- */
 
+static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_suspend, tmio_mmc_resume)
+};
+
 static struct platform_driver tmio_mmc_driver = {
 	.driver = {
 		.name = "tmio-mmc",
 		.owner = THIS_MODULE,
+		.pm = &tmio_mmc_dev_pm_ops,
 	},
 	.probe = tmio_mmc_probe,
 	.remove = tmio_mmc_remove,
-	.suspend = tmio_mmc_suspend,
-	.resume = tmio_mmc_resume,
 };
 
 module_platform_driver(tmio_mmc_driver);
-- 
1.7.9.5


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

* [PATCH 3/3] mmc: tmio: Adapt to proper PM configs for exported functions
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
  2013-11-05 12:10 ` [PATCH 1/3] mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks Ulf Hansson
  2013-11-05 12:10 ` [PATCH 2/3] mmc: tmio_mmc: Convert from legacy to modern PM ops Ulf Hansson
@ 2013-11-05 12:10 ` Ulf Hansson
  2013-11-05 22:29   ` Guennadi Liakhovetski
  2013-11-05 13:26 ` [PATCH] mmc: trivial: fix the compiling warning Seungwon Jeon
                   ` (33 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2013-11-05 12:10 UTC (permalink / raw)
  To: linux-mmc, Chris Ball, Guennadi Liakhovetski, Ian Molton; +Cc: Ulf Hansson

Since the users of the exported PM functions are now using the modern
PM ops macros, we can convert to the proper corresponding PM configs.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/tmio_mmc.h     |    7 +++----
 drivers/mmc/host/tmio_mmc_pio.c |    7 ++++---
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 86fd21e..6c5b45a 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -163,16 +163,15 @@ static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
 }
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int tmio_mmc_host_suspend(struct device *dev);
 int tmio_mmc_host_resume(struct device *dev);
-#else
-#define tmio_mmc_host_suspend NULL
-#define tmio_mmc_host_resume NULL
 #endif
 
+#ifdef CONFIG_PM_RUNTIME
 int tmio_mmc_host_runtime_suspend(struct device *dev);
 int tmio_mmc_host_runtime_resume(struct device *dev);
+#endif
 
 static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
 {
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index f3b2d8c..472e803 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -1140,7 +1140,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
 }
 EXPORT_SYMBOL(tmio_mmc_host_remove);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int tmio_mmc_host_suspend(struct device *dev)
 {
 	struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -1163,9 +1163,9 @@ int tmio_mmc_host_resume(struct device *dev)
 	return 0;
 }
 EXPORT_SYMBOL(tmio_mmc_host_resume);
+#endif
 
-#endif	/* CONFIG_PM */
-
+#ifdef CONFIG_PM_RUNTIME
 int tmio_mmc_host_runtime_suspend(struct device *dev)
 {
 	return 0;
@@ -1182,5 +1182,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
 	return 0;
 }
 EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
+#endif
 
 MODULE_LICENSE("GPL v2");
-- 
1.7.9.5


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

* [PATCH] mmc: trivial: fix the compiling warning
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (2 preceding siblings ...)
  2013-11-05 12:10 ` [PATCH 3/3] mmc: tmio: Adapt to proper PM configs for exported functions Ulf Hansson
@ 2013-11-05 13:26 ` Seungwon Jeon
  2013-11-06  3:20   ` Jaehoon Chung
  2013-11-05 13:27 ` [PATCH 0/3] mmc: update bus speed mode Seungwon Jeon
                   ` (32 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2013-11-05 13:26 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson'; +Cc: linux-mmc

Fixed the following warning.

drivers/mmc/core/mmc_ops.c:484:11: warning: 'status' may be used
uninitialized in this function [-Wmaybe-uninitialized]

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/mmc_ops.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index aae8d8b..e5b5eeb 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -414,7 +414,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 	int err;
 	struct mmc_command cmd = {0};
 	unsigned long timeout;
-	u32 status;
+	u32 status = 0;
 	bool ignore_crc = false;
 
 	BUG_ON(!card);
-- 
1.7.0.4



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

* [PATCH 0/3] mmc: update bus speed mode
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (3 preceding siblings ...)
  2013-11-05 13:26 ` [PATCH] mmc: trivial: fix the compiling warning Seungwon Jeon
@ 2013-11-05 13:27 ` Seungwon Jeon
  2013-11-05 13:27 ` [PATCH 1/3] mmc: rework selection of " Seungwon Jeon
                   ` (31 subsequent siblings)
  36 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2013-11-05 13:27 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson'; +Cc: linux-mmc

This series contains the change for selection of bus speed mode.
Previous implementation is a little complicated and some sequence
is duplicated. And specially, HS400 mode eMMC5.0 is introduced this time.

Seungwon Jeon (3):
  mmc: rework selection of bus speed mode
  mmc: correct some exclusive card state to clear
  mmc: add support for hs400 mode of eMMC5.0

 drivers/mmc/core/bus.c   |    3 +-
 drivers/mmc/core/core.c  |    1 -
 drivers/mmc/core/mmc.c   |  694 ++++++++++++++++++++++++++++++----------------
 drivers/mmc/core/sd.c    |    5 +-
 drivers/mmc/core/sdio.c  |    5 +-
 include/linux/mmc/card.h |   51 +++-
 include/linux/mmc/host.h |   12 +-
 include/linux/mmc/mmc.h  |   12 +-
 8 files changed, 522 insertions(+), 261 deletions(-)


Thanks,
Seungwon Jeon


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

* [PATCH 1/3] mmc: rework selection of bus speed mode
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (4 preceding siblings ...)
  2013-11-05 13:27 ` [PATCH 0/3] mmc: update bus speed mode Seungwon Jeon
@ 2013-11-05 13:27 ` Seungwon Jeon
  2013-11-05 14:06   ` Ulf Hansson
  2013-11-05 13:27 ` [PATCH 2/3] mmc: correct some exclusive card state to clear Seungwon Jeon
                   ` (30 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2013-11-05 13:27 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson'; +Cc: linux-mmc

Current implementation for bus speed mode selection is too
complicated. This patch is to simplify the codes and remove
some duplicate parts.

The following changes are including:
* Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
* Rearranged the mode selection sequence with supported device type
* Power class is switched once only after bus modes(speed/width)
  are selected finally
* Adds maximum speed for HS200 mode(hs200_max_dtr)
* Adds available device type to be supported by both host and device
* Adds field definition for HS_TIMING of EXT_CSD

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/mmc.c   |  574 +++++++++++++++++++++++++++-------------------
 include/linux/mmc/card.h |    6 +-
 include/linux/mmc/host.h |    6 -
 include/linux/mmc/mmc.h  |    4 +
 4 files changed, 345 insertions(+), 245 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f631f5a..f4f8991 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -242,29 +242,48 @@ static void mmc_select_card_type(struct mmc_card *card)
 	struct mmc_host *host = card->host;
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
-	unsigned int hs_max_dtr = 0;
+	unsigned int avail_type = 0;
+	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 
-	if (card_type & EXT_CSD_CARD_TYPE_26)
+	if (card_type & EXT_CSD_CARD_TYPE_26) {
 		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_26;
+	}
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
-			card_type & EXT_CSD_CARD_TYPE_52)
+	    card_type & EXT_CSD_CARD_TYPE_52) {
 		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_52;
+	}
+
+	if (caps & MMC_CAP_1_8V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
+		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
+	}
 
-	if ((caps & MMC_CAP_1_8V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
-	    (caps & MMC_CAP_1_2V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
+	if (caps & MMC_CAP_1_2V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
 		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
+	}
+
+	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_SDR_1_8V;
+	}
 
-	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
-	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_SDR_1_2V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_SDR_1_2V;
+	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
+	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->ext_csd.card_type = card_type;
+	card->mmc_avail_type = avail_type;
 }
 
 /*
@@ -714,8 +733,8 @@ static struct device_type mmc_type = {
  * extended CSD register, select it by executing the
  * mmc_switch command.
  */
-static int mmc_select_powerclass(struct mmc_card *card,
-		unsigned int bus_width)
+static int __mmc_select_powerclass(struct mmc_card *card,
+				   unsigned int bus_width, u8 *ext_csd)
 {
 	int err = 0;
 	unsigned int pwrclass_val = 0;
@@ -787,40 +806,99 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	return err;
 }
 
+static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
+{
+	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+}
+
+static int mmc_select_powerclass(struct mmc_card *card, u8 *ext_csd)
+{
+	int err, ddr;
+	u32 bus_width, ext_csd_bits;
+	struct mmc_host *host;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if (!ext_csd)
+		return 0;
+
+	/* Power class selection is supported for versions >= 4.0 */
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	/* Power class values are defined only for 4/8 bit bus */
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ddr = mmc_snoop_ddr(card);
+	if (ddr)
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+	else
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
+
+	err = __mmc_select_powerclass(card, ext_csd_bits, ext_csd);
+	if (err)
+		pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
+			mmc_hostname(host), 1 << bus_width, ddr);
+
+	return err;
+}
+
 /*
- * Selects the desired buswidth and switch to the HS200 mode
- * if bus width set without error
+ * Set the bus speed for the selected speed mode.
  */
-static int mmc_select_hs200(struct mmc_card *card)
+static void mmc_set_bus_speed(struct mmc_card *card)
+{
+	unsigned int max_dtr = (unsigned int)-1;
+
+	BUG_ON(!card);
+
+	if (mmc_card_hs200(card)) {
+		if (max_dtr > card->ext_csd.hs200_max_dtr)
+			max_dtr = card->ext_csd.hs200_max_dtr;
+	} else if (mmc_card_highspeed(card)) {
+		if (max_dtr > card->ext_csd.hs_max_dtr)
+			max_dtr = card->ext_csd.hs_max_dtr;
+	} else if (max_dtr > card->csd.max_dtr) {
+		max_dtr = card->csd.max_dtr;
+	}
+
+	mmc_set_clock(card->host, max_dtr);
+}
+
+/*
+ * Select the bus width amoung 4-bit and 8-bit(SDR).
+ * If the bus width is changed successfully, return the slected width value.
+ * Zero is returned instead of error value if the wide width is not supported.
+ */
+static int mmc_select_bus_width(struct mmc_card *card)
 {
-	int idx, err = -EINVAL;
-	struct mmc_host *host;
 	static unsigned ext_csd_bits[] = {
-		EXT_CSD_BUS_WIDTH_4,
 		EXT_CSD_BUS_WIDTH_8,
+		EXT_CSD_BUS_WIDTH_4,
 	};
 	static unsigned bus_widths[] = {
-		MMC_BUS_WIDTH_4,
 		MMC_BUS_WIDTH_8,
+		MMC_BUS_WIDTH_4,
 	};
+	struct mmc_host *host;
+	unsigned idx, bus_width = 0;
+	int err = 0;
 
 	BUG_ON(!card);
 
 	host = card->host;
 
-	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
-			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
-
-	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
-			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
-
-	/* If fails try again during next card power cycle */
-	if (err)
-		goto err;
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
+	    !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
+		return 0;
 
-	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
 
 	/*
 	 * Unlike SD, MMC cards dont have a configuration register to notify
@@ -828,8 +906,7 @@ static int mmc_select_hs200(struct mmc_card *card)
 	 * 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 >= 0; idx--) {
-
+	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
@@ -844,25 +921,226 @@ static int mmc_select_hs200(struct mmc_card *card)
 		if (err)
 			continue;
 
-		mmc_set_bus_width(card->host, bus_widths[idx]);
+		bus_width = bus_widths[idx];
+		mmc_set_bus_width(host, bus_width);
 
+		/*
+		 * If controller can't handle bus width test,
+		 * compare ext_csd previously read in 1 bit mode
+		 * against ext_csd at new bus width
+		 */
 		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-			err = mmc_compare_ext_csds(card, bus_widths[idx]);
+			err = mmc_compare_ext_csds(card, bus_width);
 		else
-			err = mmc_bus_test(card, bus_widths[idx]);
-		if (!err)
+			err = mmc_bus_test(card, bus_width);
+
+		if (!err) {
+			err = bus_width;
 			break;
+		} else {
+			pr_warn("%s: switch to bus width %d failed\n",
+				mmc_hostname(card->host), ext_csd_bits[idx]);
+		}
 	}
 
-	/* switch to HS200 mode if bus width set successfully */
-	if (!err)
+	return err;
+}
+
+/*
+ * Switch to the high-speed mode
+ */
+static int mmc_select_hs(struct mmc_card *card)
+{
+	int err;
+
+	BUG_ON(!card);
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			 card->ext_csd.generic_cmd6_time);
+	if (!err) {
+		mmc_card_set_highspeed(card);
+		mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+	}
+
+	return err;
+}
+
+/*
+ * Activate wide bus and DDR if supported.
+ */
+static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
+{
+	struct mmc_host *host;
+	u32 bus_width, ext_csd_bits;
+	int err = 0, ddr;
+
+	BUG_ON(!card);
+
+	ddr = mmc_snoop_ddr(card);
+	if (!(ddr & EXT_CSD_CARD_TYPE_DDR_52))
+		return 0;
+
+	host = card->host;
+	bus_width = host->ios.bus_width;
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+		EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_BUS_WIDTH,
+			ext_csd_bits,
+			card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width %d ddr failed\n",
+			mmc_hostname(host), 1 << bus_width);
+		return err;
+	}
+
+	/*
+	 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+	 * signaling.
+	 *
+	 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+	 *
+	 * 1.8V vccq at 3.3V core voltage (vcc) is not required
+	 * in the JEDEC spec for DDR.
+	 *
+	 * Do not force change in vccq since we are obviously
+	 * working and no change to vccq is needed.
+	 *
+	 * WARNING: eMMC rules are NOT the same as SD DDR
+	 */
+	if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		err = __mmc_set_signal_voltage(host,
+				MMC_SIGNAL_VOLTAGE_120);
+		if (err)
+			return err;
+	}
+
+	mmc_card_set_ddr_mode(card);
+	mmc_set_timing(host, MMC_TIMING_UHS_DDR50);
+
+	return err;
+}
+
+/*
+ * For device supporting HS200 mode, the following sequence
+ * should be done before executing the tuning process.
+ * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
+ * 2. switch to HS200 mode
+ * 3. set the clock to > 52Mhz and <=200MHz
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+	int err = -EINVAL;
+	struct mmc_host *host;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_SDR_1_2V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_SDR_1_8V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+
+	/* If fails try again during next card power cycle */
+	if (err)
+		goto err;
+
+	/*
+	 * Set the bus width(4 or 8) with host's support and
+	 * switch to HS200 mode if bus width is set successfully.
+	 */
+	err = mmc_select_bus_width(card);
+	if (!IS_ERR_VALUE(err)) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_HS_TIMING, 2, 0);
+				 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
+				 card->ext_csd.generic_cmd6_time);
+		if (!err) {
+			mmc_card_set_hs200(card);
+			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+		}
+	}
 err:
 	return err;
 }
 
 /*
+ * Activate High Speed or HS200 mode if supported.
+ */
+static int mmc_select_timing(struct mmc_card *card)
+{
+	struct mmc_host *host;
+	int err = 0;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
+	     card->ext_csd.hs_max_dtr == 0))
+		goto bus_speed;
+
+	if (card->ext_csd.hs200_max_dtr > 52000000 &&
+			host->caps2 & MMC_CAP2_HS200)
+		err = mmc_select_hs200(card);
+	else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
+		err = mmc_select_hs(card);
+
+	if (err && err != -EBADMSG)
+		return err;
+
+	if (err) {
+		pr_warn("%s: switch to %s failed\n",
+			mmc_card_highspeed(card) ? "high-speed" :
+			(mmc_card_hs200(card) ? "hs200" : ""),
+			mmc_hostname(card->host));
+		err = 0;
+	}
+
+bus_speed:
+	/*
+	 * Set the bus speed to the selected bus timing.
+	 * If timing is not selected, backward compatible is the default.
+	 */
+	mmc_set_bus_speed(card);
+	return err;
+}
+
+/*
+ * Execute tuning sequence to seek the proper bus operating
+ * conditions for HS200, which sends CMD21 to the device.
+ */
+static int mmc_hs200_tuning(struct mmc_card *card)
+{
+	int err = 0;
+	struct mmc_host *host;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if (host->caps2 & MMC_CAP2_HS200 &&
+	    card->host->ops->execute_tuning) {
+		mmc_host_clk_hold(card->host);
+		err = card->host->ops->execute_tuning(card->host,
+				MMC_SEND_TUNING_BLOCK_HS200);
+		mmc_host_clk_release(card->host);
+
+		if (err)
+			pr_warn("%s: tuning execution failed\n",
+				mmc_hostname(card->host));
+	}
+
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -872,9 +1150,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	struct mmc_card *oldcard)
 {
 	struct mmc_card *card;
-	int err, ddr = 0;
+	int err;
 	u32 cid[4];
-	unsigned int max_dtr;
 	u32 rocr;
 	u8 *ext_csd = NULL;
 
@@ -1066,209 +1343,30 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
-	 * Activate high speed (if supported)
-	 */
-	if (card->ext_csd.hs_max_dtr != 0) {
-		err = 0;
-		if (card->ext_csd.hs_max_dtr > 52000000 &&
-		    host->caps2 & MMC_CAP2_HS200)
-			err = mmc_select_hs200(card);
-		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_HS_TIMING, 1,
-					 card->ext_csd.generic_cmd6_time);
-
-		if (err && err != -EBADMSG)
-			goto free_card;
-
-		if (err) {
-			pr_warning("%s: switch to highspeed failed\n",
-			       mmc_hostname(card->host));
-			err = 0;
-		} else {
-			if (card->ext_csd.hs_max_dtr > 52000000 &&
-			    host->caps2 & MMC_CAP2_HS200) {
-				mmc_card_set_hs200(card);
-				mmc_set_timing(card->host,
-					       MMC_TIMING_MMC_HS200);
-			} else {
-				mmc_card_set_highspeed(card);
-				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-			}
-		}
-	}
-
-	/*
-	 * Compute bus speed.
-	 */
-	max_dtr = (unsigned int)-1;
-
-	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
-		if (max_dtr > card->ext_csd.hs_max_dtr)
-			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_highspeed(card) && (max_dtr > 52000000))
-			max_dtr = 52000000;
-	} else if (max_dtr > card->csd.max_dtr) {
-		max_dtr = card->csd.max_dtr;
-	}
-
-	mmc_set_clock(host, max_dtr);
-
-	/*
-	 * Indicate DDR mode (if supported).
+	 * Select timing interface
 	 */
-	if (mmc_card_highspeed(card)) {
-		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-			&& ((host->caps & (MMC_CAP_1_8V_DDR |
-			     MMC_CAP_UHS_DDR50))
-				== (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
-				ddr = MMC_1_8V_DDR_MODE;
-		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-			&& ((host->caps & (MMC_CAP_1_2V_DDR |
-			     MMC_CAP_UHS_DDR50))
-				== (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
-				ddr = MMC_1_2V_DDR_MODE;
-	}
+	err = mmc_select_timing(card);
+	if (err)
+		goto free_card;
 
-	/*
-	 * Indicate HS200 SDR mode (if supported).
-	 */
 	if (mmc_card_hs200(card)) {
-		u32 ext_csd_bits;
-		u32 bus_width = card->host->ios.bus_width;
-
-		/*
-		 * For devices supporting HS200 mode, the bus width has
-		 * to be set before executing the tuning function. If
-		 * set before tuning, then device will respond with CRC
-		 * errors for responses on CMD line. So for HS200 the
-		 * sequence will be
-		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
-		 * 2. switch to HS200 mode
-		 * 3. set the clock to > 52Mhz <=200MHz and
-		 * 4. execute tuning for HS200
-		 */
-		if ((host->caps2 & MMC_CAP2_HS200) &&
-		    card->host->ops->execute_tuning) {
-			mmc_host_clk_hold(card->host);
-			err = card->host->ops->execute_tuning(card->host,
-				MMC_SEND_TUNING_BLOCK_HS200);
-			mmc_host_clk_release(card->host);
-		}
-		if (err) {
-			pr_warning("%s: tuning execution failed\n",
-				   mmc_hostname(card->host));
+		err = mmc_hs200_tuning(card);
+		if (err)
 			goto err;
+	} else if (mmc_card_highspeed(card)) {
+		/* Select the desired bus width optionally */
+		err = mmc_select_bus_width(card);
+		if (!IS_ERR_VALUE(err)) {
+			err = mmc_select_hs_ddr(card, ext_csd);
+			if (err)
+				goto err;
 		}
-
-		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
-				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-		err = mmc_select_powerclass(card, ext_csd_bits);
-		if (err)
-			pr_warning("%s: power class selection to bus width %d"
-				   " failed\n", mmc_hostname(card->host),
-				   1 << bus_width);
 	}
 
 	/*
-	 * Activate wide bus and DDR (if supported).
+	 * Choose the power calss with selected bus interface
 	 */
-	if (!mmc_card_hs200(card) &&
-	    (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
-	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
-		static unsigned ext_csd_bits[][2] = {
-			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
-			{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
-			{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
-		};
-		static unsigned bus_widths[] = {
-			MMC_BUS_WIDTH_8,
-			MMC_BUS_WIDTH_4,
-			MMC_BUS_WIDTH_1
-		};
-		unsigned idx, bus_width = 0;
-
-		if (host->caps & MMC_CAP_8_BIT_DATA)
-			idx = 0;
-		else
-			idx = 1;
-		for (; idx < ARRAY_SIZE(bus_widths); idx++) {
-			bus_width = bus_widths[idx];
-			if (bus_width == MMC_BUS_WIDTH_1)
-				ddr = 0; /* no DDR for 1-bit width */
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width);
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][0],
-					 card->ext_csd.generic_cmd6_time);
-			if (!err) {
-				mmc_set_bus_width(card->host, bus_width);
-
-				/*
-				 * If controller can't handle bus width test,
-				 * compare ext_csd previously read in 1 bit mode
-				 * against ext_csd at new bus width
-				 */
-				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					err = mmc_compare_ext_csds(card,
-						bus_width);
-				else
-					err = mmc_bus_test(card, bus_width);
-				if (!err)
-					break;
-			}
-		}
-
-		if (!err && ddr) {
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d ddr %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width, ddr);
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][1],
-					 card->ext_csd.generic_cmd6_time);
-		}
-		if (err) {
-			pr_warning("%s: switch to bus width %d ddr %d "
-				"failed\n", mmc_hostname(card->host),
-				1 << bus_width, ddr);
-			goto free_card;
-		} else if (ddr) {
-			/*
-			 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
-			 * signaling.
-			 *
-			 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
-			 *
-			 * 1.8V vccq at 3.3V core voltage (vcc) is not required
-			 * in the JEDEC spec for DDR.
-			 *
-			 * Do not force change in vccq since we are obviously
-			 * working and no change to vccq is needed.
-			 *
-			 * WARNING: eMMC rules are NOT the same as SD DDR
-			 */
-			if (ddr == MMC_1_2V_DDR_MODE) {
-				err = __mmc_set_signal_voltage(host,
-					MMC_SIGNAL_VOLTAGE_120);
-				if (err)
-					goto err;
-			}
-			mmc_card_set_ddr_mode(card);
-			mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
-			mmc_set_bus_width(card->host, bus_width);
-		}
-	}
+	mmc_select_powerclass(card, ext_csd);
 
 	/*
 	 * Enable HPI feature (if supported)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 176fdf8..c119735 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -63,6 +63,7 @@ struct mmc_ext_csd {
 	unsigned int            power_off_longtime;     /* Units: ms */
 	u8			power_off_notification;	/* state */
 	unsigned int		hs_max_dtr;
+	unsigned int		hs200_max_dtr;
 #define MMC_HIGH_26_MAX_DTR	26000000
 #define MMC_HIGH_52_MAX_DTR	52000000
 #define MMC_HIGH_DDR_MAX_DTR	52000000
@@ -299,7 +300,10 @@ struct mmc_card {
 	const char		**info;		/* info strings */
 	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
 
-	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+	union {
+		unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+		unsigned int		mmc_avail_type;	/* supported device type by both host and card */
+	};
 
 	struct dentry		*debugfs_root;
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 99f5709..69d58b1 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -60,12 +60,6 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_DDR50	7
 #define MMC_TIMING_MMC_HS200	8
 
-#define MMC_SDR_MODE		0
-#define MMC_1_2V_DDR_MODE	1
-#define MMC_1_8V_DDR_MODE	2
-#define MMC_1_2V_SDR_MODE	3
-#define MMC_1_8V_SDR_MODE	4
-
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
 #define MMC_SIGNAL_VOLTAGE_330	0
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 50bcde3..87df508 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -373,6 +373,10 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
 #define EXT_CSD_SEC_GB_CL_EN	BIT(4)
-- 
1.7.0.4



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

* [PATCH 2/3] mmc: correct some exclusive card state to clear
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (5 preceding siblings ...)
  2013-11-05 13:27 ` [PATCH 1/3] mmc: rework selection of " Seungwon Jeon
@ 2013-11-05 13:27 ` Seungwon Jeon
  2013-11-05 14:33   ` Ulf Hansson
  2013-11-05 13:28 ` [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0 Seungwon Jeon
                   ` (29 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2013-11-05 13:27 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson'; +Cc: linux-mmc

Card state related to speed mode should be in non-overlapped.
Consideration for all cases is required when being cleared.
Also, MMC_STATE_PRESENT and MMC_STATE_REMOVED are same.
It's exclusive state which cannot be set at the same time.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/core.c  |    1 -
 drivers/mmc/core/mmc.c   |    4 ++--
 drivers/mmc/core/sd.c    |    5 +++--
 drivers/mmc/core/sdio.c  |    5 ++++-
 include/linux/mmc/card.h |   37 +++++++++++++++++++++++++++++++------
 5 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 57a2b40..b183d56 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2281,7 +2281,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
 		}
 	}
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
 	if (mmc_host_is_spi(host)) {
 		host->ios.chip_select = MMC_CS_HIGH;
 		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f4f8991..1668ea4 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1597,11 +1597,11 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 		err = mmc_sleep(host);
 	else if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 
 	if (!err) {
 		mmc_power_off(host);
 		mmc_card_set_suspended(host->card);
+		mmc_card_set_ds(host->card);
 	}
 out:
 	mmc_release_host(host);
@@ -1727,8 +1727,8 @@ static int mmc_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 	mmc_claim_host(host);
+	mmc_card_set_ds(host->card);
 	ret = mmc_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
 
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 6f42050..b19a8f4 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1082,10 +1082,11 @@ static int _mmc_sd_suspend(struct mmc_host *host)
 
 	if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
+
 	if (!err) {
 		mmc_power_off(host);
 		mmc_card_set_suspended(host->card);
+		mmc_card_set_ds(host->card);
 	}
 
 out:
@@ -1191,8 +1192,8 @@ static int mmc_sd_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
+	mmc_card_set_ds(host->card);
 	ret = mmc_sd_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
 
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4d721c6..7c6c43c 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -968,8 +968,10 @@ static int mmc_sdio_suspend(struct mmc_host *host)
 		mmc_release_host(host);
 	}
 
-	if (!err && !mmc_card_keep_power(host))
+	if (!err && !mmc_card_keep_power(host)) {
 		mmc_power_off(host);
+		mmc_card_set_ds(host->card);
+	}
 
 	return err;
 }
@@ -1075,6 +1077,7 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
 	if (ret)
 		goto out;
 
+	mmc_card_set_ds(host->card);
 	ret = mmc_sdio_init_card(host, host->card->ocr, host->card,
 				mmc_card_keep_power(host));
 	if (!ret && host->sdio_irqs)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c119735..f2c2620 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -260,6 +260,11 @@ struct mmc_card {
 #define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
 #define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
 #define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
+#define MMC_STATE_SPEED_MASK	(MMC_STATE_HIGHSPEED | \
+				 MMC_STATE_HIGHSPEED_DDR | \
+				 MMC_STATE_ULTRAHIGHSPEED | \
+				 MMC_STATE_HIGHSPEED_200)
+						/* Mask for default speed(DS) */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -431,19 +436,39 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
 #define mmc_card_suspended(c)	((c)->state & MMC_STATE_SUSPENDED)
 
-#define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
+
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
-#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
-#define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
-#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
-#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_doing_bkops(c)	((c)->state |= MMC_STATE_DOING_BKOPS)
 #define mmc_card_clr_doing_bkops(c)	((c)->state &= ~MMC_STATE_DOING_BKOPS)
 #define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
 #define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
+#define mmc_card_set_highspeed(c) \
+			((c)->state = \
+			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
+			 MMC_STATE_HIGHSPEED)
+#define mmc_card_set_ddr_mode(c) \
+			((c)->state = \
+			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
+			 MMC_STATE_HIGHSPEED_DDR)
+#define mmc_card_set_hs200(c) \
+			((c)->state = \
+			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
+			 MMC_STATE_HIGHSPEED_200)
+#define mmc_card_set_uhs(c) \
+			((c)->state = \
+			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
+			 MMC_STATE_ULTRAHIGHSPEED)
+#define mmc_card_set_present(c) \
+			((c)->state = \
+			 ((c)->state & ~MMC_CARD_REMOVED) | \
+			 MMC_STATE_PRESENT)
+#define mmc_card_set_removed(c) \
+			((c)->state = \
+			 ((c)->state & ~MMC_STATE_PRESENT) | \
+			 MMC_CARD_REMOVED)
+#define mmc_card_set_ds(c)	((c)->state &= ~MMC_STATE_SPEED_MASK)
 
 /*
  * Quirk add/remove for MMC products.
-- 
1.7.0.4



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

* [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (6 preceding siblings ...)
  2013-11-05 13:27 ` [PATCH 2/3] mmc: correct some exclusive card state to clear Seungwon Jeon
@ 2013-11-05 13:28 ` Seungwon Jeon
  2013-11-07  7:38   ` Shen, Jackey
  2013-11-08 12:16 ` [PATCH 0/3] mmc: tmio: Use modern PM ops Guennadi Liakhovetski
                   ` (28 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2013-11-05 13:28 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson'; +Cc: linux-mmc

This patch adds HS400 mode support for eMMC5.0 device.
HS400 mode is high speed DDDR 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: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/bus.c   |    3 +-
 drivers/mmc/core/mmc.c   |  128 +++++++++++++++++++++++++++++++++++++++++++---
 include/linux/mmc/card.h |   10 +++-
 include/linux/mmc/host.h |    6 ++
 include/linux/mmc/mmc.h  |    8 +++-
 5 files changed, 144 insertions(+), 11 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index cdca8a7..fd4ba2b 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -351,10 +351,11 @@ int mmc_add_card(struct mmc_card *card)
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			type);
 	} else {
-		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
+		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_highspeed(card) ? "high speed " : ""),
+			mmc_card_hs400(card) ? "HS400 " : "",
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 1668ea4..7c23b67 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -280,6 +280,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_SDR_1_2V;
 	}
 
+	if (caps2 & MMC_CAP2_HS400_1_8V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS400_1_2V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
+	}
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->ext_csd.card_type = card_type;
@@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
 		card->ext_csd.raw_pwr_cl_ddr_52_360 =
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
+		card->ext_csd.raw_pwr_cl_ddr_200_360 =
+			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
 	}
 
 	if (card->ext_csd.rev >= 5) {
@@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
 		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
 			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
 		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
-			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
+		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
+
 	if (err)
 		err = -EINVAL;
 
@@ -780,7 +797,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
 				card->ext_csd.raw_pwr_cl_52_360 :
 				card->ext_csd.raw_pwr_cl_ddr_52_360;
 		else if (host->ios.clock <= 200000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
+			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
+				card->ext_csd.raw_pwr_cl_ddr_200_360 :
+				card->ext_csd.raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -808,7 +827,8 @@ static int __mmc_select_powerclass(struct mmc_card *card,
 
 static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
 {
-	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	return card->mmc_avail_type &
+		(EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_HS400);
 }
 
 static int mmc_select_powerclass(struct mmc_card *card, u8 *ext_csd)
@@ -858,7 +878,7 @@ static void mmc_set_bus_speed(struct mmc_card *card)
 
 	BUG_ON(!card);
 
-	if (mmc_card_hs200(card)) {
+	if (mmc_card_hs200(card) || mmc_card_hs400(card)) {
 		if (max_dtr > card->ext_csd.hs200_max_dtr)
 			max_dtr = card->ext_csd.hs200_max_dtr;
 	} else if (mmc_card_highspeed(card)) {
@@ -967,6 +987,31 @@ static int mmc_select_hs(struct mmc_card *card)
 }
 
 /*
+ * Revert to the high-speed mode from above speed
+ */
+static int mmc_revert_to_hs(struct mmc_card *card)
+{
+	BUG_ON(!card);
+
+	/*
+	 * CMD13, which is used to confirm the completion of timing
+	 * change, will be issued at higher speed timing condtion
+	 * rather than high-speed. If device has completed the change
+	 * to high-speed mode, it may not be proper timing to issue
+	 * command. Low speed supplies better timing margin than high
+	 * speed. Accordingly clock rate & timging should be chagned
+	 * ahead before actual switch.
+	 */
+	mmc_card_set_highspeed(card);
+	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+	mmc_set_bus_speed(card);
+
+	return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			  card->ext_csd.generic_cmd6_time);
+}
+
+/*
  * Activate wide bus and DDR if supported.
  */
 static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
@@ -1026,6 +1071,61 @@ static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
 	return err;
 }
 
+static int mmc_select_hs400(struct mmc_card *card, u8 *ext_csd)
+{
+	struct mmc_host *host;
+	int err = 0, ddr;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	ddr = mmc_snoop_ddr(card);
+
+	/*
+	 * The bus width is set to only 8 DDR in HS400 mode
+	 */
+	if (!(ddr & EXT_CSD_CARD_TYPE_HS400 &&
+	      card->host->ios.bus_width == MMC_BUS_WIDTH_8))
+		return 0;
+
+	/*
+	 * Before setting BUS_WIDTH for dual data rate operation,
+	 * HS_TIMING must be set to High Speed(0x1)
+	 */
+	err = mmc_revert_to_hs(card);
+	if (err) {
+		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
+			mmc_hostname(card->host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_DDR_BUS_WIDTH_8,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
+			mmc_hostname(card->host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to hs400 failed, err:%d\n",
+			 mmc_hostname(card->host), err);
+		return err;
+	}
+
+	mmc_card_set_hs400(card);
+	mmc_set_timing(card->host, MMC_TIMING_MMC_HS400);
+	mmc_set_bus_speed(card);
+
+	return 0;
+}
+
 /*
  * For device supporting HS200 mode, the following sequence
  * should be done before executing the tuning process.
@@ -1061,10 +1161,19 @@ static int mmc_select_hs200(struct mmc_card *card)
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
 				 card->ext_csd.generic_cmd6_time);
-		if (!err) {
-			mmc_card_set_hs200(card);
+		if (err)
+			goto err;
+
+		mmc_card_set_hs200(card);
+
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
+			/*
+			 * Timing should be adjusted to the HS400 target
+			 * operation frequency for tuning process
+			 */
+			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
+		else
 			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
-		}
 	}
 err:
 	return err;
@@ -1114,7 +1223,7 @@ bus_speed:
 
 /*
  * Execute tuning sequence to seek the proper bus operating
- * conditions for HS200, which sends CMD21 to the device.
+ * conditions for HS200 and HS400, which sends CMD21 to the device.
  */
 static int mmc_hs200_tuning(struct mmc_card *card)
 {
@@ -1353,6 +1462,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_hs200_tuning(card);
 		if (err)
 			goto err;
+		err = mmc_select_hs400(card, ext_csd);
+		if (err)
+			goto err;
 	} else if (mmc_card_highspeed(card)) {
 		/* Select the desired bus width optionally */
 		err = mmc_select_bus_width(card);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index f2c2620..3d41869 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -111,6 +111,7 @@ struct mmc_ext_csd {
 	u8			raw_pwr_cl_200_360;	/* 237 */
 	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
 	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
+	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
 	u8			raw_bkops_status;	/* 246 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
 
@@ -258,12 +259,14 @@ struct mmc_card {
 #define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
 #define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
 #define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
+#define MMC_STATE_HIGHSPEED_400	(1<<9)		/* card is in HS400 mode */
 #define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
 #define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
 #define MMC_STATE_SPEED_MASK	(MMC_STATE_HIGHSPEED | \
 				 MMC_STATE_HIGHSPEED_DDR | \
 				 MMC_STATE_ULTRAHIGHSPEED | \
-				 MMC_STATE_HIGHSPEED_200)
+				 MMC_STATE_HIGHSPEED_200 | \
+				 MMC_STATE_HIGHSPEED_400)
 						/* Mask for default speed(DS) */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
@@ -428,6 +431,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
 #define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
+#define mmc_card_hs400(c)	((c)->state & MMC_STATE_HIGHSPEED_400)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
 #define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
 #define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
@@ -456,6 +460,10 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 			((c)->state = \
 			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
 			 MMC_STATE_HIGHSPEED_200)
+#define mmc_card_set_hs400(c) \
+			((c)->state = \
+			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
+			 MMC_STATE_HIGHSPEED_400)
 #define mmc_card_set_uhs(c) \
 			((c)->state = \
 			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 69d58b1..8e66f4d 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -59,6 +59,8 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_SDR104	6
 #define MMC_TIMING_UHS_DDR50	7
 #define MMC_TIMING_MMC_HS200	8
+#define MMC_TIMING_MMC_HS400	9
+#define MMC_TIMING_MMC_HS400_TUNING 10
 
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
@@ -276,6 +278,10 @@ struct mmc_host {
 				 MMC_CAP2_PACKED_WR)
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
 #define MMC_CAP2_SANITIZE	(1 << 15)		/* Support Sanitize */
+#define MMC_CAP2_HS400_1_8V	(1 << 16)	/* Can support HS400 1.8V */
+#define MMC_CAP2_HS400_1_2V	(1 << 17)	/* Can support HS400 1.2V */
+#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
+				 MMC_CAP2_HS400_1_2V)
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 87df508..7d5c27d 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -325,6 +325,7 @@ struct _mmc_csd {
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
 #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
 #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
 #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
@@ -356,7 +357,7 @@ struct _mmc_csd {
 
 #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_MASK	0x3F	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_MASK	0xFF	/* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
 					     /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
@@ -366,6 +367,10 @@ struct _mmc_csd {
 #define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
 #define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
 						/* SDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS400_1_8V	(1<<6)	/* Card can run at 200MHz DDR, 1.8V */
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
@@ -376,6 +381,7 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
-- 
1.7.0.4



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

* Re: [PATCH 1/3] mmc: rework selection of bus speed mode
  2013-11-05 13:27 ` [PATCH 1/3] mmc: rework selection of " Seungwon Jeon
@ 2013-11-05 14:06   ` Ulf Hansson
  2013-11-06  9:09     ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2013-11-05 14:06 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: Chris Ball, linux-mmc

Hi Seungwon,

On 5 November 2013 14:27, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Current implementation for bus speed mode selection is too
> complicated. This patch is to simplify the codes and remove
> some duplicate parts.
>
> The following changes are including:
> * Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
> * Rearranged the mode selection sequence with supported device type
> * Power class is switched once only after bus modes(speed/width)
>   are selected finally
> * Adds maximum speed for HS200 mode(hs200_max_dtr)
> * Adds available device type to be supported by both host and device
> * Adds field definition for HS_TIMING of EXT_CSD

Very nice work you are doing here, this is certainly needed.

Although, from a reviewing point of view it would be nice if you could
split up and do re-factoring in more minor pieces. Could that be done?

Kind regards
Ulf Hansson

>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
>  drivers/mmc/core/mmc.c   |  574 +++++++++++++++++++++++++++-------------------
>  include/linux/mmc/card.h |    6 +-
>  include/linux/mmc/host.h |    6 -
>  include/linux/mmc/mmc.h  |    4 +
>  4 files changed, 345 insertions(+), 245 deletions(-)
>
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index f631f5a..f4f8991 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -242,29 +242,48 @@ static void mmc_select_card_type(struct mmc_card *card)
>         struct mmc_host *host = card->host;
>         u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>         u32 caps = host->caps, caps2 = host->caps2;
> -       unsigned int hs_max_dtr = 0;
> +       unsigned int avail_type = 0;
> +       unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>
> -       if (card_type & EXT_CSD_CARD_TYPE_26)
> +       if (card_type & EXT_CSD_CARD_TYPE_26) {
>                 hs_max_dtr = MMC_HIGH_26_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_26;
> +       }
>
>         if (caps & MMC_CAP_MMC_HIGHSPEED &&
> -                       card_type & EXT_CSD_CARD_TYPE_52)
> +           card_type & EXT_CSD_CARD_TYPE_52) {
>                 hs_max_dtr = MMC_HIGH_52_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_52;
> +       }
> +
> +       if (caps & MMC_CAP_1_8V_DDR &&
> +           card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
> +               hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
> +       }
>
> -       if ((caps & MMC_CAP_1_8V_DDR &&
> -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
> -           (caps & MMC_CAP_1_2V_DDR &&
> -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
> +       if (caps & MMC_CAP_1_2V_DDR &&
> +           card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
>                 hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
> +       }
> +
> +       if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> +           card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) {
> +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_SDR_1_8V;
> +       }
>
> -       if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
> -           (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
> -               hs_max_dtr = MMC_HS200_MAX_DTR;
> +       if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> +           card_type & EXT_CSD_CARD_TYPE_SDR_1_2V) {
> +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_SDR_1_2V;
> +       }
>
>         card->ext_csd.hs_max_dtr = hs_max_dtr;
> +       card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>         card->ext_csd.card_type = card_type;
> +       card->mmc_avail_type = avail_type;
>  }
>
>  /*
> @@ -714,8 +733,8 @@ static struct device_type mmc_type = {
>   * extended CSD register, select it by executing the
>   * mmc_switch command.
>   */
> -static int mmc_select_powerclass(struct mmc_card *card,
> -               unsigned int bus_width)
> +static int __mmc_select_powerclass(struct mmc_card *card,
> +                                  unsigned int bus_width, u8 *ext_csd)
>  {
>         int err = 0;
>         unsigned int pwrclass_val = 0;
> @@ -787,40 +806,99 @@ static int mmc_select_powerclass(struct mmc_card *card,
>         return err;
>  }
>
> +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> +{
> +       return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> +}
> +
> +static int mmc_select_powerclass(struct mmc_card *card, u8 *ext_csd)
> +{
> +       int err, ddr;
> +       u32 bus_width, ext_csd_bits;
> +       struct mmc_host *host;
> +
> +       BUG_ON(!card);
> +
> +       host = card->host;
> +
> +       if (!ext_csd)
> +               return 0;
> +
> +       /* Power class selection is supported for versions >= 4.0 */
> +       if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
> +               return 0;
> +
> +       bus_width = host->ios.bus_width;
> +       /* Power class values are defined only for 4/8 bit bus */
> +       if (bus_width == MMC_BUS_WIDTH_1)
> +               return 0;
> +
> +       ddr = mmc_snoop_ddr(card);
> +       if (ddr)
> +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> +                       EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
> +       else
> +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> +                       EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
> +
> +       err = __mmc_select_powerclass(card, ext_csd_bits, ext_csd);
> +       if (err)
> +               pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
> +                       mmc_hostname(host), 1 << bus_width, ddr);
> +
> +       return err;
> +}
> +
>  /*
> - * Selects the desired buswidth and switch to the HS200 mode
> - * if bus width set without error
> + * Set the bus speed for the selected speed mode.
>   */
> -static int mmc_select_hs200(struct mmc_card *card)
> +static void mmc_set_bus_speed(struct mmc_card *card)
> +{
> +       unsigned int max_dtr = (unsigned int)-1;
> +
> +       BUG_ON(!card);
> +
> +       if (mmc_card_hs200(card)) {
> +               if (max_dtr > card->ext_csd.hs200_max_dtr)
> +                       max_dtr = card->ext_csd.hs200_max_dtr;
> +       } else if (mmc_card_highspeed(card)) {
> +               if (max_dtr > card->ext_csd.hs_max_dtr)
> +                       max_dtr = card->ext_csd.hs_max_dtr;
> +       } else if (max_dtr > card->csd.max_dtr) {
> +               max_dtr = card->csd.max_dtr;
> +       }
> +
> +       mmc_set_clock(card->host, max_dtr);
> +}
> +
> +/*
> + * Select the bus width amoung 4-bit and 8-bit(SDR).
> + * If the bus width is changed successfully, return the slected width value.
> + * Zero is returned instead of error value if the wide width is not supported.
> + */
> +static int mmc_select_bus_width(struct mmc_card *card)
>  {
> -       int idx, err = -EINVAL;
> -       struct mmc_host *host;
>         static unsigned ext_csd_bits[] = {
> -               EXT_CSD_BUS_WIDTH_4,
>                 EXT_CSD_BUS_WIDTH_8,
> +               EXT_CSD_BUS_WIDTH_4,
>         };
>         static unsigned bus_widths[] = {
> -               MMC_BUS_WIDTH_4,
>                 MMC_BUS_WIDTH_8,
> +               MMC_BUS_WIDTH_4,
>         };
> +       struct mmc_host *host;
> +       unsigned idx, bus_width = 0;
> +       int err = 0;
>
>         BUG_ON(!card);
>
>         host = card->host;
>
> -       if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
> -                       host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
> -               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
> -
> -       if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
> -                       host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
> -               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
> -
> -       /* If fails try again during next card power cycle */
> -       if (err)
> -               goto err;
> +       if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
> +           !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
> +               return 0;
>
> -       idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
> +       idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
>
>         /*
>          * Unlike SD, MMC cards dont have a configuration register to notify
> @@ -828,8 +906,7 @@ static int mmc_select_hs200(struct mmc_card *card)
>          * 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 >= 0; idx--) {
> -
> +       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
> @@ -844,25 +921,226 @@ static int mmc_select_hs200(struct mmc_card *card)
>                 if (err)
>                         continue;
>
> -               mmc_set_bus_width(card->host, bus_widths[idx]);
> +               bus_width = bus_widths[idx];
> +               mmc_set_bus_width(host, bus_width);
>
> +               /*
> +                * If controller can't handle bus width test,
> +                * compare ext_csd previously read in 1 bit mode
> +                * against ext_csd at new bus width
> +                */
>                 if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
> -                       err = mmc_compare_ext_csds(card, bus_widths[idx]);
> +                       err = mmc_compare_ext_csds(card, bus_width);
>                 else
> -                       err = mmc_bus_test(card, bus_widths[idx]);
> -               if (!err)
> +                       err = mmc_bus_test(card, bus_width);
> +
> +               if (!err) {
> +                       err = bus_width;
>                         break;
> +               } else {
> +                       pr_warn("%s: switch to bus width %d failed\n",
> +                               mmc_hostname(card->host), ext_csd_bits[idx]);
> +               }
>         }
>
> -       /* switch to HS200 mode if bus width set successfully */
> -       if (!err)
> +       return err;
> +}
> +
> +/*
> + * Switch to the high-speed mode
> + */
> +static int mmc_select_hs(struct mmc_card *card)
> +{
> +       int err;
> +
> +       BUG_ON(!card);
> +
> +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> +                        card->ext_csd.generic_cmd6_time);
> +       if (!err) {
> +               mmc_card_set_highspeed(card);
> +               mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> +       }
> +
> +       return err;
> +}
> +
> +/*
> + * Activate wide bus and DDR if supported.
> + */
> +static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
> +{
> +       struct mmc_host *host;
> +       u32 bus_width, ext_csd_bits;
> +       int err = 0, ddr;
> +
> +       BUG_ON(!card);
> +
> +       ddr = mmc_snoop_ddr(card);
> +       if (!(ddr & EXT_CSD_CARD_TYPE_DDR_52))
> +               return 0;
> +
> +       host = card->host;
> +       bus_width = host->ios.bus_width;
> +       if (bus_width == MMC_BUS_WIDTH_1)
> +               return 0;
> +
> +       ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> +               EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
> +
> +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                       EXT_CSD_BUS_WIDTH,
> +                       ext_csd_bits,
> +                       card->ext_csd.generic_cmd6_time);
> +       if (err) {
> +               pr_warn("%s: switch to bus width %d ddr failed\n",
> +                       mmc_hostname(host), 1 << bus_width);
> +               return err;
> +       }
> +
> +       /*
> +        * eMMC cards can support 3.3V to 1.2V i/o (vccq)
> +        * signaling.
> +        *
> +        * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
> +        *
> +        * 1.8V vccq at 3.3V core voltage (vcc) is not required
> +        * in the JEDEC spec for DDR.
> +        *
> +        * Do not force change in vccq since we are obviously
> +        * working and no change to vccq is needed.
> +        *
> +        * WARNING: eMMC rules are NOT the same as SD DDR
> +        */
> +       if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> +               err = __mmc_set_signal_voltage(host,
> +                               MMC_SIGNAL_VOLTAGE_120);
> +               if (err)
> +                       return err;
> +       }
> +
> +       mmc_card_set_ddr_mode(card);
> +       mmc_set_timing(host, MMC_TIMING_UHS_DDR50);
> +
> +       return err;
> +}
> +
> +/*
> + * For device supporting HS200 mode, the following sequence
> + * should be done before executing the tuning process.
> + * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
> + * 2. switch to HS200 mode
> + * 3. set the clock to > 52Mhz and <=200MHz
> + */
> +static int mmc_select_hs200(struct mmc_card *card)
> +{
> +       int err = -EINVAL;
> +       struct mmc_host *host;
> +
> +       BUG_ON(!card);
> +
> +       host = card->host;
> +
> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_SDR_1_2V)
> +               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
> +
> +       if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_SDR_1_8V)
> +               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
> +
> +       /* If fails try again during next card power cycle */
> +       if (err)
> +               goto err;
> +
> +       /*
> +        * Set the bus width(4 or 8) with host's support and
> +        * switch to HS200 mode if bus width is set successfully.
> +        */
> +       err = mmc_select_bus_width(card);
> +       if (!IS_ERR_VALUE(err)) {
>                 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> -                                EXT_CSD_HS_TIMING, 2, 0);
> +                                EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> +                                card->ext_csd.generic_cmd6_time);
> +               if (!err) {
> +                       mmc_card_set_hs200(card);
> +                       mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> +               }
> +       }
>  err:
>         return err;
>  }
>
>  /*
> + * Activate High Speed or HS200 mode if supported.
> + */
> +static int mmc_select_timing(struct mmc_card *card)
> +{
> +       struct mmc_host *host;
> +       int err = 0;
> +
> +       BUG_ON(!card);
> +
> +       host = card->host;
> +
> +       if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
> +            card->ext_csd.hs_max_dtr == 0))
> +               goto bus_speed;
> +
> +       if (card->ext_csd.hs200_max_dtr > 52000000 &&
> +                       host->caps2 & MMC_CAP2_HS200)
> +               err = mmc_select_hs200(card);
> +       else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> +               err = mmc_select_hs(card);
> +
> +       if (err && err != -EBADMSG)
> +               return err;
> +
> +       if (err) {
> +               pr_warn("%s: switch to %s failed\n",
> +                       mmc_card_highspeed(card) ? "high-speed" :
> +                       (mmc_card_hs200(card) ? "hs200" : ""),
> +                       mmc_hostname(card->host));
> +               err = 0;
> +       }
> +
> +bus_speed:
> +       /*
> +        * Set the bus speed to the selected bus timing.
> +        * If timing is not selected, backward compatible is the default.
> +        */
> +       mmc_set_bus_speed(card);
> +       return err;
> +}
> +
> +/*
> + * Execute tuning sequence to seek the proper bus operating
> + * conditions for HS200, which sends CMD21 to the device.
> + */
> +static int mmc_hs200_tuning(struct mmc_card *card)
> +{
> +       int err = 0;
> +       struct mmc_host *host;
> +
> +       BUG_ON(!card);
> +
> +       host = card->host;
> +
> +       if (host->caps2 & MMC_CAP2_HS200 &&
> +           card->host->ops->execute_tuning) {
> +               mmc_host_clk_hold(card->host);
> +               err = card->host->ops->execute_tuning(card->host,
> +                               MMC_SEND_TUNING_BLOCK_HS200);
> +               mmc_host_clk_release(card->host);
> +
> +               if (err)
> +                       pr_warn("%s: tuning execution failed\n",
> +                               mmc_hostname(card->host));
> +       }
> +
> +       return err;
> +}
> +
> +/*
>   * Handle the detection and initialisation of a card.
>   *
>   * In the case of a resume, "oldcard" will contain the card
> @@ -872,9 +1150,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>         struct mmc_card *oldcard)
>  {
>         struct mmc_card *card;
> -       int err, ddr = 0;
> +       int err;
>         u32 cid[4];
> -       unsigned int max_dtr;
>         u32 rocr;
>         u8 *ext_csd = NULL;
>
> @@ -1066,209 +1343,30 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>         }
>
>         /*
> -        * Activate high speed (if supported)
> -        */
> -       if (card->ext_csd.hs_max_dtr != 0) {
> -               err = 0;
> -               if (card->ext_csd.hs_max_dtr > 52000000 &&
> -                   host->caps2 & MMC_CAP2_HS200)
> -                       err = mmc_select_hs200(card);
> -               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> -                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> -                                        EXT_CSD_HS_TIMING, 1,
> -                                        card->ext_csd.generic_cmd6_time);
> -
> -               if (err && err != -EBADMSG)
> -                       goto free_card;
> -
> -               if (err) {
> -                       pr_warning("%s: switch to highspeed failed\n",
> -                              mmc_hostname(card->host));
> -                       err = 0;
> -               } else {
> -                       if (card->ext_csd.hs_max_dtr > 52000000 &&
> -                           host->caps2 & MMC_CAP2_HS200) {
> -                               mmc_card_set_hs200(card);
> -                               mmc_set_timing(card->host,
> -                                              MMC_TIMING_MMC_HS200);
> -                       } else {
> -                               mmc_card_set_highspeed(card);
> -                               mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> -                       }
> -               }
> -       }
> -
> -       /*
> -        * Compute bus speed.
> -        */
> -       max_dtr = (unsigned int)-1;
> -
> -       if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
> -               if (max_dtr > card->ext_csd.hs_max_dtr)
> -                       max_dtr = card->ext_csd.hs_max_dtr;
> -               if (mmc_card_highspeed(card) && (max_dtr > 52000000))
> -                       max_dtr = 52000000;
> -       } else if (max_dtr > card->csd.max_dtr) {
> -               max_dtr = card->csd.max_dtr;
> -       }
> -
> -       mmc_set_clock(host, max_dtr);
> -
> -       /*
> -        * Indicate DDR mode (if supported).
> +        * Select timing interface
>          */
> -       if (mmc_card_highspeed(card)) {
> -               if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
> -                       && ((host->caps & (MMC_CAP_1_8V_DDR |
> -                            MMC_CAP_UHS_DDR50))
> -                               == (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
> -                               ddr = MMC_1_8V_DDR_MODE;
> -               else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
> -                       && ((host->caps & (MMC_CAP_1_2V_DDR |
> -                            MMC_CAP_UHS_DDR50))
> -                               == (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
> -                               ddr = MMC_1_2V_DDR_MODE;
> -       }
> +       err = mmc_select_timing(card);
> +       if (err)
> +               goto free_card;
>
> -       /*
> -        * Indicate HS200 SDR mode (if supported).
> -        */
>         if (mmc_card_hs200(card)) {
> -               u32 ext_csd_bits;
> -               u32 bus_width = card->host->ios.bus_width;
> -
> -               /*
> -                * For devices supporting HS200 mode, the bus width has
> -                * to be set before executing the tuning function. If
> -                * set before tuning, then device will respond with CRC
> -                * errors for responses on CMD line. So for HS200 the
> -                * sequence will be
> -                * 1. set bus width 4bit / 8 bit (1 bit not supported)
> -                * 2. switch to HS200 mode
> -                * 3. set the clock to > 52Mhz <=200MHz and
> -                * 4. execute tuning for HS200
> -                */
> -               if ((host->caps2 & MMC_CAP2_HS200) &&
> -                   card->host->ops->execute_tuning) {
> -                       mmc_host_clk_hold(card->host);
> -                       err = card->host->ops->execute_tuning(card->host,
> -                               MMC_SEND_TUNING_BLOCK_HS200);
> -                       mmc_host_clk_release(card->host);
> -               }
> -               if (err) {
> -                       pr_warning("%s: tuning execution failed\n",
> -                                  mmc_hostname(card->host));
> +               err = mmc_hs200_tuning(card);
> +               if (err)
>                         goto err;
> +       } else if (mmc_card_highspeed(card)) {
> +               /* Select the desired bus width optionally */
> +               err = mmc_select_bus_width(card);
> +               if (!IS_ERR_VALUE(err)) {
> +                       err = mmc_select_hs_ddr(card, ext_csd);
> +                       if (err)
> +                               goto err;
>                 }
> -
> -               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> -                               EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
> -               err = mmc_select_powerclass(card, ext_csd_bits);
> -               if (err)
> -                       pr_warning("%s: power class selection to bus width %d"
> -                                  " failed\n", mmc_hostname(card->host),
> -                                  1 << bus_width);
>         }
>
>         /*
> -        * Activate wide bus and DDR (if supported).
> +        * Choose the power calss with selected bus interface
>          */
> -       if (!mmc_card_hs200(card) &&
> -           (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
> -           (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
> -               static unsigned ext_csd_bits[][2] = {
> -                       { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
> -                       { EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
> -                       { EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
> -               };
> -               static unsigned bus_widths[] = {
> -                       MMC_BUS_WIDTH_8,
> -                       MMC_BUS_WIDTH_4,
> -                       MMC_BUS_WIDTH_1
> -               };
> -               unsigned idx, bus_width = 0;
> -
> -               if (host->caps & MMC_CAP_8_BIT_DATA)
> -                       idx = 0;
> -               else
> -                       idx = 1;
> -               for (; idx < ARRAY_SIZE(bus_widths); idx++) {
> -                       bus_width = bus_widths[idx];
> -                       if (bus_width == MMC_BUS_WIDTH_1)
> -                               ddr = 0; /* no DDR for 1-bit width */
> -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
> -                       if (err)
> -                               pr_warning("%s: power class selection to "
> -                                          "bus width %d failed\n",
> -                                          mmc_hostname(card->host),
> -                                          1 << bus_width);
> -
> -                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> -                                        EXT_CSD_BUS_WIDTH,
> -                                        ext_csd_bits[idx][0],
> -                                        card->ext_csd.generic_cmd6_time);
> -                       if (!err) {
> -                               mmc_set_bus_width(card->host, bus_width);
> -
> -                               /*
> -                                * If controller can't handle bus width test,
> -                                * compare ext_csd previously read in 1 bit mode
> -                                * against ext_csd at new bus width
> -                                */
> -                               if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
> -                                       err = mmc_compare_ext_csds(card,
> -                                               bus_width);
> -                               else
> -                                       err = mmc_bus_test(card, bus_width);
> -                               if (!err)
> -                                       break;
> -                       }
> -               }
> -
> -               if (!err && ddr) {
> -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
> -                       if (err)
> -                               pr_warning("%s: power class selection to "
> -                                          "bus width %d ddr %d failed\n",
> -                                          mmc_hostname(card->host),
> -                                          1 << bus_width, ddr);
> -
> -                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> -                                        EXT_CSD_BUS_WIDTH,
> -                                        ext_csd_bits[idx][1],
> -                                        card->ext_csd.generic_cmd6_time);
> -               }
> -               if (err) {
> -                       pr_warning("%s: switch to bus width %d ddr %d "
> -                               "failed\n", mmc_hostname(card->host),
> -                               1 << bus_width, ddr);
> -                       goto free_card;
> -               } else if (ddr) {
> -                       /*
> -                        * eMMC cards can support 3.3V to 1.2V i/o (vccq)
> -                        * signaling.
> -                        *
> -                        * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
> -                        *
> -                        * 1.8V vccq at 3.3V core voltage (vcc) is not required
> -                        * in the JEDEC spec for DDR.
> -                        *
> -                        * Do not force change in vccq since we are obviously
> -                        * working and no change to vccq is needed.
> -                        *
> -                        * WARNING: eMMC rules are NOT the same as SD DDR
> -                        */
> -                       if (ddr == MMC_1_2V_DDR_MODE) {
> -                               err = __mmc_set_signal_voltage(host,
> -                                       MMC_SIGNAL_VOLTAGE_120);
> -                               if (err)
> -                                       goto err;
> -                       }
> -                       mmc_card_set_ddr_mode(card);
> -                       mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
> -                       mmc_set_bus_width(card->host, bus_width);
> -               }
> -       }
> +       mmc_select_powerclass(card, ext_csd);
>
>         /*
>          * Enable HPI feature (if supported)
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 176fdf8..c119735 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -63,6 +63,7 @@ struct mmc_ext_csd {
>         unsigned int            power_off_longtime;     /* Units: ms */
>         u8                      power_off_notification; /* state */
>         unsigned int            hs_max_dtr;
> +       unsigned int            hs200_max_dtr;
>  #define MMC_HIGH_26_MAX_DTR    26000000
>  #define MMC_HIGH_52_MAX_DTR    52000000
>  #define MMC_HIGH_DDR_MAX_DTR   52000000
> @@ -299,7 +300,10 @@ struct mmc_card {
>         const char              **info;         /* info strings */
>         struct sdio_func_tuple  *tuples;        /* unknown common tuples */
>
> -       unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
> +       union {
> +               unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
> +               unsigned int            mmc_avail_type; /* supported device type by both host and card */
> +       };
>
>         struct dentry           *debugfs_root;
>         struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 99f5709..69d58b1 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -60,12 +60,6 @@ struct mmc_ios {
>  #define MMC_TIMING_UHS_DDR50   7
>  #define MMC_TIMING_MMC_HS200   8
>
> -#define MMC_SDR_MODE           0
> -#define MMC_1_2V_DDR_MODE      1
> -#define MMC_1_8V_DDR_MODE      2
> -#define MMC_1_2V_SDR_MODE      3
> -#define MMC_1_8V_SDR_MODE      4
> -
>         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
>
>  #define MMC_SIGNAL_VOLTAGE_330 0
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 50bcde3..87df508 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -373,6 +373,10 @@ struct _mmc_csd {
>  #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_SEC_ER_EN      BIT(0)
>  #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
>  #define EXT_CSD_SEC_GB_CL_EN   BIT(4)
> --
> 1.7.0.4
>
>

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

* Re: [PATCH 2/3] mmc: correct some exclusive card state to clear
  2013-11-05 13:27 ` [PATCH 2/3] mmc: correct some exclusive card state to clear Seungwon Jeon
@ 2013-11-05 14:33   ` Ulf Hansson
  2013-11-06  9:35     ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2013-11-05 14:33 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: Chris Ball, linux-mmc

Hi Seungwon,


On 5 November 2013 14:27, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Card state related to speed mode should be in non-overlapped.
> Consideration for all cases is required when being cleared.
> Also, MMC_STATE_PRESENT and MMC_STATE_REMOVED are same.
> It's exclusive state which cannot be set at the same time.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
>  drivers/mmc/core/core.c  |    1 -
>  drivers/mmc/core/mmc.c   |    4 ++--
>  drivers/mmc/core/sd.c    |    5 +++--
>  drivers/mmc/core/sdio.c  |    5 ++++-
>  include/linux/mmc/card.h |   37 +++++++++++++++++++++++++++++++------
>  5 files changed, 40 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 57a2b40..b183d56 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -2281,7 +2281,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
>                 }
>         }
>
> -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
>         if (mmc_host_is_spi(host)) {
>                 host->ios.chip_select = MMC_CS_HIGH;
>                 host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index f4f8991..1668ea4 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -1597,11 +1597,11 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
>                 err = mmc_sleep(host);
>         else if (!mmc_host_is_spi(host))
>                 err = mmc_deselect_cards(host);
> -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
>
>         if (!err) {
>                 mmc_power_off(host);
>                 mmc_card_set_suspended(host->card);
> +               mmc_card_set_ds(host->card);
>         }
>  out:
>         mmc_release_host(host);
> @@ -1727,8 +1727,8 @@ static int mmc_power_restore(struct mmc_host *host)
>  {
>         int ret;
>
> -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
>         mmc_claim_host(host);
> +       mmc_card_set_ds(host->card);
>         ret = mmc_init_card(host, host->card->ocr, host->card);
>         mmc_release_host(host);
>
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index 6f42050..b19a8f4 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -1082,10 +1082,11 @@ static int _mmc_sd_suspend(struct mmc_host *host)
>
>         if (!mmc_host_is_spi(host))
>                 err = mmc_deselect_cards(host);
> -       host->card->state &= ~MMC_STATE_HIGHSPEED;
> +
>         if (!err) {
>                 mmc_power_off(host);
>                 mmc_card_set_suspended(host->card);
> +               mmc_card_set_ds(host->card);
>         }
>
>  out:
> @@ -1191,8 +1192,8 @@ static int mmc_sd_power_restore(struct mmc_host *host)
>  {
>         int ret;
>
> -       host->card->state &= ~MMC_STATE_HIGHSPEED;
>         mmc_claim_host(host);
> +       mmc_card_set_ds(host->card);
>         ret = mmc_sd_init_card(host, host->card->ocr, host->card);
>         mmc_release_host(host);
>
> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> index 4d721c6..7c6c43c 100644
> --- a/drivers/mmc/core/sdio.c
> +++ b/drivers/mmc/core/sdio.c
> @@ -968,8 +968,10 @@ static int mmc_sdio_suspend(struct mmc_host *host)
>                 mmc_release_host(host);
>         }
>
> -       if (!err && !mmc_card_keep_power(host))
> +       if (!err && !mmc_card_keep_power(host)) {
>                 mmc_power_off(host);
> +               mmc_card_set_ds(host->card);
> +       }
>
>         return err;
>  }
> @@ -1075,6 +1077,7 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
>         if (ret)
>                 goto out;
>
> +       mmc_card_set_ds(host->card);
>         ret = mmc_sdio_init_card(host, host->card->ocr, host->card,
>                                 mmc_card_keep_power(host));
>         if (!ret && host->sdio_irqs)
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index c119735..f2c2620 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -260,6 +260,11 @@ struct mmc_card {
>  #define MMC_STATE_HIGHSPEED_200        (1<<8)          /* card is in HS200 mode */
>  #define MMC_STATE_DOING_BKOPS  (1<<10)         /* card is doing BKOPS */
>  #define MMC_STATE_SUSPENDED    (1<<11)         /* card is suspended */
> +#define MMC_STATE_SPEED_MASK   (MMC_STATE_HIGHSPEED | \
> +                                MMC_STATE_HIGHSPEED_DDR | \
> +                                MMC_STATE_ULTRAHIGHSPEED | \
> +                                MMC_STATE_HIGHSPEED_200)
> +                                               /* Mask for default speed(DS) */
>         unsigned int            quirks;         /* card quirks */
>  #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
> @@ -431,19 +436,39 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
>  #define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
>  #define mmc_card_suspended(c)  ((c)->state & MMC_STATE_SUSPENDED)
>
> -#define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
> +
>  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
> -#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
> -#define mmc_card_set_hs200(c)  ((c)->state |= MMC_STATE_HIGHSPEED_200)
>  #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
> -#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
> -#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
>  #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
> -#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
>  #define mmc_card_set_doing_bkops(c)    ((c)->state |= MMC_STATE_DOING_BKOPS)
>  #define mmc_card_clr_doing_bkops(c)    ((c)->state &= ~MMC_STATE_DOING_BKOPS)
>  #define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
>  #define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
> +#define mmc_card_set_highspeed(c) \
> +                       ((c)->state = \
> +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> +                        MMC_STATE_HIGHSPEED)
> +#define mmc_card_set_ddr_mode(c) \
> +                       ((c)->state = \
> +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> +                        MMC_STATE_HIGHSPEED_DDR)
> +#define mmc_card_set_hs200(c) \
> +                       ((c)->state = \
> +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> +                        MMC_STATE_HIGHSPEED_200)
> +#define mmc_card_set_uhs(c) \
> +                       ((c)->state = \
> +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> +                        MMC_STATE_ULTRAHIGHSPEED)
> +#define mmc_card_set_present(c) \
> +                       ((c)->state = \
> +                        ((c)->state & ~MMC_CARD_REMOVED) | \
> +                        MMC_STATE_PRESENT)
> +#define mmc_card_set_removed(c) \
> +                       ((c)->state = \
> +                        ((c)->state & ~MMC_STATE_PRESENT) | \
> +                        MMC_CARD_REMOVED)
> +#define mmc_card_set_ds(c)     ((c)->state &= ~MMC_STATE_SPEED_MASK)

I have a feeling of that this "card->state" has become a container for
a lot of mixed stuff. So your clean up is definitely justified.

I have a suggestion for how we can improve simplicity, how about
dividing the state into two variables instead:

-> One part are actually used in the mmc core code to track a state
and to make certain decisions during execution, like
MMC_STATE_SUSPENDED, MMC_STATE_PRESENT, MMC_CARD_REMOVED.

-> The other part is more to be considered as the current operational
state, for example the bus speed mode. The information in this "state
variable" will be re-negotiated as a part of mmc_sd|sdio_init_card and
can therefore always be reset in the beginning of these functions.

Does it make sense?

Kind regards
Ulf Hansson

>
>  /*
>   * Quirk add/remove for MMC products.
> --
> 1.7.0.4
>
>

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

* Re: [PATCH 2/3] mmc: tmio_mmc: Convert from legacy to modern PM ops
  2013-11-05 12:10 ` [PATCH 2/3] mmc: tmio_mmc: Convert from legacy to modern PM ops Ulf Hansson
@ 2013-11-05 22:24   ` Guennadi Liakhovetski
  0 siblings, 0 replies; 182+ messages in thread
From: Guennadi Liakhovetski @ 2013-11-05 22:24 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: linux-mmc, Chris Ball, Ian Molton

Hi Ulf,

The patch looks good to me in general, just one possible optimisation:

On Tue, 5 Nov 2013, Ulf Hansson wrote:

> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>  drivers/mmc/host/tmio_mmc.c |   32 ++++++++++++++++++--------------
>  1 file changed, 18 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
> index 8860d4d..a56a3fe 100644
> --- a/drivers/mmc/host/tmio_mmc.c
> +++ b/drivers/mmc/host/tmio_mmc.c
> @@ -23,38 +23,39 @@
>  
>  #include "tmio_mmc.h"
>  
> -#ifdef CONFIG_PM
> -static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
> +#ifdef CONFIG_PM_SLEEP
> +static int tmio_mmc_suspend(struct device *dev)
>  {
> -	const struct mfd_cell *cell = mfd_get_cell(dev);
> +	struct mmc_host *mmc = dev_get_drvdata(dev);
> +	struct tmio_mmc_host *host = mmc_priv(mmc);
> +	const struct mfd_cell *cell = mfd_get_cell(host->pdev);

Wouldn't it be better to just add

+	struct platform_device *pdev = to_platform_device(dev);

which would also simplify

>  	int ret;
>  
> -	ret = tmio_mmc_host_suspend(&dev->dev);
> +	ret = tmio_mmc_host_suspend(dev);
>  
>  	/* Tell MFD core it can disable us now.*/
>  	if (!ret && cell->disable)
> -		cell->disable(dev);
> +		cell->disable(host->pdev);

the above line to just

+		cell->disable(pdev);

>  
>  	return ret;
>  }
>  
> -static int tmio_mmc_resume(struct platform_device *dev)
> +static int tmio_mmc_resume(struct device *dev)
>  {
> -	const struct mfd_cell *cell = mfd_get_cell(dev);
> +	struct mmc_host *mmc = dev_get_drvdata(dev);
> +	struct tmio_mmc_host *host = mmc_priv(mmc);
> +	const struct mfd_cell *cell = mfd_get_cell(host->pdev);
>  	int ret = 0;
>  
>  	/* Tell the MFD core we are ready to be enabled */
>  	if (cell->resume)
> -		ret = cell->resume(dev);
> +		ret = cell->resume(host->pdev);

Ditto in this function.

Thanks
Guennadi

>  
>  	if (!ret)
> -		ret = tmio_mmc_host_resume(&dev->dev);
> +		ret = tmio_mmc_host_resume(dev);
>  
>  	return ret;
>  }
> -#else
> -#define tmio_mmc_suspend NULL
> -#define tmio_mmc_resume NULL
>  #endif
>  
>  static int tmio_mmc_probe(struct platform_device *pdev)
> @@ -125,15 +126,18 @@ static int tmio_mmc_remove(struct platform_device *pdev)
>  
>  /* ------------------- device registration ----------------------- */
>  
> +static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
> +	SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_suspend, tmio_mmc_resume)
> +};
> +
>  static struct platform_driver tmio_mmc_driver = {
>  	.driver = {
>  		.name = "tmio-mmc",
>  		.owner = THIS_MODULE,
> +		.pm = &tmio_mmc_dev_pm_ops,
>  	},
>  	.probe = tmio_mmc_probe,
>  	.remove = tmio_mmc_remove,
> -	.suspend = tmio_mmc_suspend,
> -	.resume = tmio_mmc_resume,
>  };
>  
>  module_platform_driver(tmio_mmc_driver);
> -- 
> 1.7.9.5
> 

---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

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

* Re: [PATCH 1/3] mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks
  2013-11-05 12:10 ` [PATCH 1/3] mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks Ulf Hansson
@ 2013-11-05 22:29   ` Guennadi Liakhovetski
  0 siblings, 0 replies; 182+ messages in thread
From: Guennadi Liakhovetski @ 2013-11-05 22:29 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: linux-mmc, Chris Ball, Ian Molton

On Tue, 5 Nov 2013, Ulf Hansson wrote:

> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Acked-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>

Thanks
Guennadi

> ---
>  drivers/mmc/host/sh_mobile_sdhi.c |    8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
> index 87ed3fb..2227a9f 100644
> --- a/drivers/mmc/host/sh_mobile_sdhi.c
> +++ b/drivers/mmc/host/sh_mobile_sdhi.c
> @@ -297,10 +297,10 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
>  }
>  
>  static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
> -	.suspend = tmio_mmc_host_suspend,
> -	.resume = tmio_mmc_host_resume,
> -	.runtime_suspend = tmio_mmc_host_runtime_suspend,
> -	.runtime_resume = tmio_mmc_host_runtime_resume,
> +	SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_host_suspend, tmio_mmc_host_resume)
> +	SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
> +			tmio_mmc_host_runtime_resume,
> +			NULL)
>  };
>  
>  static struct platform_driver sh_mobile_sdhi_driver = {
> -- 
> 1.7.9.5
> 

---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

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

* Re: [PATCH 3/3] mmc: tmio: Adapt to proper PM configs for exported functions
  2013-11-05 12:10 ` [PATCH 3/3] mmc: tmio: Adapt to proper PM configs for exported functions Ulf Hansson
@ 2013-11-05 22:29   ` Guennadi Liakhovetski
  0 siblings, 0 replies; 182+ messages in thread
From: Guennadi Liakhovetski @ 2013-11-05 22:29 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: linux-mmc, Chris Ball, Ian Molton

On Tue, 5 Nov 2013, Ulf Hansson wrote:

> Since the users of the exported PM functions are now using the modern
> PM ops macros, we can convert to the proper corresponding PM configs.
> 
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Acked-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>

Thanks
Guennadi

> ---
>  drivers/mmc/host/tmio_mmc.h     |    7 +++----
>  drivers/mmc/host/tmio_mmc_pio.c |    7 ++++---
>  2 files changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
> index 86fd21e..6c5b45a 100644
> --- a/drivers/mmc/host/tmio_mmc.h
> +++ b/drivers/mmc/host/tmio_mmc.h
> @@ -163,16 +163,15 @@ static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
>  }
>  #endif
>  
> -#ifdef CONFIG_PM
> +#ifdef CONFIG_PM_SLEEP
>  int tmio_mmc_host_suspend(struct device *dev);
>  int tmio_mmc_host_resume(struct device *dev);
> -#else
> -#define tmio_mmc_host_suspend NULL
> -#define tmio_mmc_host_resume NULL
>  #endif
>  
> +#ifdef CONFIG_PM_RUNTIME
>  int tmio_mmc_host_runtime_suspend(struct device *dev);
>  int tmio_mmc_host_runtime_resume(struct device *dev);
> +#endif
>  
>  static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
>  {
> diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
> index f3b2d8c..472e803 100644
> --- a/drivers/mmc/host/tmio_mmc_pio.c
> +++ b/drivers/mmc/host/tmio_mmc_pio.c
> @@ -1140,7 +1140,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
>  }
>  EXPORT_SYMBOL(tmio_mmc_host_remove);
>  
> -#ifdef CONFIG_PM
> +#ifdef CONFIG_PM_SLEEP
>  int tmio_mmc_host_suspend(struct device *dev)
>  {
>  	struct mmc_host *mmc = dev_get_drvdata(dev);
> @@ -1163,9 +1163,9 @@ int tmio_mmc_host_resume(struct device *dev)
>  	return 0;
>  }
>  EXPORT_SYMBOL(tmio_mmc_host_resume);
> +#endif
>  
> -#endif	/* CONFIG_PM */
> -
> +#ifdef CONFIG_PM_RUNTIME
>  int tmio_mmc_host_runtime_suspend(struct device *dev)
>  {
>  	return 0;
> @@ -1182,5 +1182,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
>  	return 0;
>  }
>  EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
> +#endif
>  
>  MODULE_LICENSE("GPL v2");
> -- 
> 1.7.9.5
> 

---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

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

* Re: [PATCH] mmc: trivial: fix the compiling warning
  2013-11-05 13:26 ` [PATCH] mmc: trivial: fix the compiling warning Seungwon Jeon
@ 2013-11-06  3:20   ` Jaehoon Chung
  2013-11-06  9:42     ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Jaehoon Chung @ 2013-11-06  3:20 UTC (permalink / raw)
  To: Seungwon Jeon, 'Chris Ball', 'Ulf Hansson'; +Cc: linux-mmc

I known this patch is already included into Ulf's patchset.

mmc: core: Silence compiler warning in __mmc_switch

Best regards,
Jaehoon Chung

On 11/05/2013 10:26 PM, Seungwon Jeon wrote:
> Fixed the following warning.
> 
> drivers/mmc/core/mmc_ops.c:484:11: warning: 'status' may be used
> uninitialized in this function [-Wmaybe-uninitialized]
> 
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
>  drivers/mmc/core/mmc_ops.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
> index aae8d8b..e5b5eeb 100644
> --- a/drivers/mmc/core/mmc_ops.c
> +++ b/drivers/mmc/core/mmc_ops.c
> @@ -414,7 +414,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
>  	int err;
>  	struct mmc_command cmd = {0};
>  	unsigned long timeout;
> -	u32 status;
> +	u32 status = 0;
>  	bool ignore_crc = false;
>  
>  	BUG_ON(!card);
> 


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

* RE: [PATCH 1/3] mmc: rework selection of bus speed mode
  2013-11-05 14:06   ` Ulf Hansson
@ 2013-11-06  9:09     ` Seungwon Jeon
  2013-11-06 10:46       ` Ulf Hansson
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2013-11-06  9:09 UTC (permalink / raw)
  To: 'Ulf Hansson'; +Cc: 'Chris Ball', 'linux-mmc'

Hi Ulf,

On Tue, November 05, 2013, Ulf Hansson wrote:
> Hi Seungwon,
> 
> On 5 November 2013 14:27, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Current implementation for bus speed mode selection is too
> > complicated. This patch is to simplify the codes and remove
> > some duplicate parts.
> >
> > The following changes are including:
> > * Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
> > * Rearranged the mode selection sequence with supported device type
> > * Power class is switched once only after bus modes(speed/width)
> >   are selected finally
> > * Adds maximum speed for HS200 mode(hs200_max_dtr)
> > * Adds available device type to be supported by both host and device
> > * Adds field definition for HS_TIMING of EXT_CSD
> 
> Very nice work you are doing here, this is certainly needed.
> 
> Although, from a reviewing point of view it would be nice if you could
> split up and do re-factoring in more minor pieces. Could that be done?

Ok. I'll consider that.
But I guess it would not be done nicely because a whole flow is organic.
If you have any opinion, please let me know.

Thanks,
Seungwon Jeon

> 
> Kind regards
> Ulf Hansson
> 
> >
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > ---
> >  drivers/mmc/core/mmc.c   |  574 +++++++++++++++++++++++++++-------------------
> >  include/linux/mmc/card.h |    6 +-
> >  include/linux/mmc/host.h |    6 -
> >  include/linux/mmc/mmc.h  |    4 +
> >  4 files changed, 345 insertions(+), 245 deletions(-)
> >
> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > index f631f5a..f4f8991 100644
> > --- a/drivers/mmc/core/mmc.c
> > +++ b/drivers/mmc/core/mmc.c
> > @@ -242,29 +242,48 @@ static void mmc_select_card_type(struct mmc_card *card)
> >         struct mmc_host *host = card->host;
> >         u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> >         u32 caps = host->caps, caps2 = host->caps2;
> > -       unsigned int hs_max_dtr = 0;
> > +       unsigned int avail_type = 0;
> > +       unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
> >
> > -       if (card_type & EXT_CSD_CARD_TYPE_26)
> > +       if (card_type & EXT_CSD_CARD_TYPE_26) {
> >                 hs_max_dtr = MMC_HIGH_26_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_26;
> > +       }
> >
> >         if (caps & MMC_CAP_MMC_HIGHSPEED &&
> > -                       card_type & EXT_CSD_CARD_TYPE_52)
> > +           card_type & EXT_CSD_CARD_TYPE_52) {
> >                 hs_max_dtr = MMC_HIGH_52_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_52;
> > +       }
> > +
> > +       if (caps & MMC_CAP_1_8V_DDR &&
> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
> > +               hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
> > +       }
> >
> > -       if ((caps & MMC_CAP_1_8V_DDR &&
> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
> > -           (caps & MMC_CAP_1_2V_DDR &&
> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
> > +       if (caps & MMC_CAP_1_2V_DDR &&
> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> >                 hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
> > +       }
> > +
> > +       if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> > +           card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) {
> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_SDR_1_8V;
> > +       }
> >
> > -       if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
> > -           (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
> > -               hs_max_dtr = MMC_HS200_MAX_DTR;
> > +       if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> > +           card_type & EXT_CSD_CARD_TYPE_SDR_1_2V) {
> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_SDR_1_2V;
> > +       }
> >
> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
> > +       card->ext_csd.hs200_max_dtr = hs200_max_dtr;
> >         card->ext_csd.card_type = card_type;
> > +       card->mmc_avail_type = avail_type;
> >  }
> >
> >  /*
> > @@ -714,8 +733,8 @@ static struct device_type mmc_type = {
> >   * extended CSD register, select it by executing the
> >   * mmc_switch command.
> >   */
> > -static int mmc_select_powerclass(struct mmc_card *card,
> > -               unsigned int bus_width)
> > +static int __mmc_select_powerclass(struct mmc_card *card,
> > +                                  unsigned int bus_width, u8 *ext_csd)
> >  {
> >         int err = 0;
> >         unsigned int pwrclass_val = 0;
> > @@ -787,40 +806,99 @@ static int mmc_select_powerclass(struct mmc_card *card,
> >         return err;
> >  }
> >
> > +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> > +{
> > +       return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> > +}
> > +
> > +static int mmc_select_powerclass(struct mmc_card *card, u8 *ext_csd)
> > +{
> > +       int err, ddr;
> > +       u32 bus_width, ext_csd_bits;
> > +       struct mmc_host *host;
> > +
> > +       BUG_ON(!card);
> > +
> > +       host = card->host;
> > +
> > +       if (!ext_csd)
> > +               return 0;
> > +
> > +       /* Power class selection is supported for versions >= 4.0 */
> > +       if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
> > +               return 0;
> > +
> > +       bus_width = host->ios.bus_width;
> > +       /* Power class values are defined only for 4/8 bit bus */
> > +       if (bus_width == MMC_BUS_WIDTH_1)
> > +               return 0;
> > +
> > +       ddr = mmc_snoop_ddr(card);
> > +       if (ddr)
> > +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> > +                       EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
> > +       else
> > +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> > +                       EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
> > +
> > +       err = __mmc_select_powerclass(card, ext_csd_bits, ext_csd);
> > +       if (err)
> > +               pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
> > +                       mmc_hostname(host), 1 << bus_width, ddr);
> > +
> > +       return err;
> > +}
> > +
> >  /*
> > - * Selects the desired buswidth and switch to the HS200 mode
> > - * if bus width set without error
> > + * Set the bus speed for the selected speed mode.
> >   */
> > -static int mmc_select_hs200(struct mmc_card *card)
> > +static void mmc_set_bus_speed(struct mmc_card *card)
> > +{
> > +       unsigned int max_dtr = (unsigned int)-1;
> > +
> > +       BUG_ON(!card);
> > +
> > +       if (mmc_card_hs200(card)) {
> > +               if (max_dtr > card->ext_csd.hs200_max_dtr)
> > +                       max_dtr = card->ext_csd.hs200_max_dtr;
> > +       } else if (mmc_card_highspeed(card)) {
> > +               if (max_dtr > card->ext_csd.hs_max_dtr)
> > +                       max_dtr = card->ext_csd.hs_max_dtr;
> > +       } else if (max_dtr > card->csd.max_dtr) {
> > +               max_dtr = card->csd.max_dtr;
> > +       }
> > +
> > +       mmc_set_clock(card->host, max_dtr);
> > +}
> > +
> > +/*
> > + * Select the bus width amoung 4-bit and 8-bit(SDR).
> > + * If the bus width is changed successfully, return the slected width value.
> > + * Zero is returned instead of error value if the wide width is not supported.
> > + */
> > +static int mmc_select_bus_width(struct mmc_card *card)
> >  {
> > -       int idx, err = -EINVAL;
> > -       struct mmc_host *host;
> >         static unsigned ext_csd_bits[] = {
> > -               EXT_CSD_BUS_WIDTH_4,
> >                 EXT_CSD_BUS_WIDTH_8,
> > +               EXT_CSD_BUS_WIDTH_4,
> >         };
> >         static unsigned bus_widths[] = {
> > -               MMC_BUS_WIDTH_4,
> >                 MMC_BUS_WIDTH_8,
> > +               MMC_BUS_WIDTH_4,
> >         };
> > +       struct mmc_host *host;
> > +       unsigned idx, bus_width = 0;
> > +       int err = 0;
> >
> >         BUG_ON(!card);
> >
> >         host = card->host;
> >
> > -       if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
> > -                       host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
> > -               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
> > -
> > -       if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
> > -                       host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
> > -               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
> > -
> > -       /* If fails try again during next card power cycle */
> > -       if (err)
> > -               goto err;
> > +       if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
> > +           !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
> > +               return 0;
> >
> > -       idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
> > +       idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
> >
> >         /*
> >          * Unlike SD, MMC cards dont have a configuration register to notify
> > @@ -828,8 +906,7 @@ static int mmc_select_hs200(struct mmc_card *card)
> >          * 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 >= 0; idx--) {
> > -
> > +       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
> > @@ -844,25 +921,226 @@ static int mmc_select_hs200(struct mmc_card *card)
> >                 if (err)
> >                         continue;
> >
> > -               mmc_set_bus_width(card->host, bus_widths[idx]);
> > +               bus_width = bus_widths[idx];
> > +               mmc_set_bus_width(host, bus_width);
> >
> > +               /*
> > +                * If controller can't handle bus width test,
> > +                * compare ext_csd previously read in 1 bit mode
> > +                * against ext_csd at new bus width
> > +                */
> >                 if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
> > -                       err = mmc_compare_ext_csds(card, bus_widths[idx]);
> > +                       err = mmc_compare_ext_csds(card, bus_width);
> >                 else
> > -                       err = mmc_bus_test(card, bus_widths[idx]);
> > -               if (!err)
> > +                       err = mmc_bus_test(card, bus_width);
> > +
> > +               if (!err) {
> > +                       err = bus_width;
> >                         break;
> > +               } else {
> > +                       pr_warn("%s: switch to bus width %d failed\n",
> > +                               mmc_hostname(card->host), ext_csd_bits[idx]);
> > +               }
> >         }
> >
> > -       /* switch to HS200 mode if bus width set successfully */
> > -       if (!err)
> > +       return err;
> > +}
> > +
> > +/*
> > + * Switch to the high-speed mode
> > + */
> > +static int mmc_select_hs(struct mmc_card *card)
> > +{
> > +       int err;
> > +
> > +       BUG_ON(!card);
> > +
> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> > +                        card->ext_csd.generic_cmd6_time);
> > +       if (!err) {
> > +               mmc_card_set_highspeed(card);
> > +               mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> > +       }
> > +
> > +       return err;
> > +}
> > +
> > +/*
> > + * Activate wide bus and DDR if supported.
> > + */
> > +static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
> > +{
> > +       struct mmc_host *host;
> > +       u32 bus_width, ext_csd_bits;
> > +       int err = 0, ddr;
> > +
> > +       BUG_ON(!card);
> > +
> > +       ddr = mmc_snoop_ddr(card);
> > +       if (!(ddr & EXT_CSD_CARD_TYPE_DDR_52))
> > +               return 0;
> > +
> > +       host = card->host;
> > +       bus_width = host->ios.bus_width;
> > +       if (bus_width == MMC_BUS_WIDTH_1)
> > +               return 0;
> > +
> > +       ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> > +               EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
> > +
> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +                       EXT_CSD_BUS_WIDTH,
> > +                       ext_csd_bits,
> > +                       card->ext_csd.generic_cmd6_time);
> > +       if (err) {
> > +               pr_warn("%s: switch to bus width %d ddr failed\n",
> > +                       mmc_hostname(host), 1 << bus_width);
> > +               return err;
> > +       }
> > +
> > +       /*
> > +        * eMMC cards can support 3.3V to 1.2V i/o (vccq)
> > +        * signaling.
> > +        *
> > +        * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
> > +        *
> > +        * 1.8V vccq at 3.3V core voltage (vcc) is not required
> > +        * in the JEDEC spec for DDR.
> > +        *
> > +        * Do not force change in vccq since we are obviously
> > +        * working and no change to vccq is needed.
> > +        *
> > +        * WARNING: eMMC rules are NOT the same as SD DDR
> > +        */
> > +       if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> > +               err = __mmc_set_signal_voltage(host,
> > +                               MMC_SIGNAL_VOLTAGE_120);
> > +               if (err)
> > +                       return err;
> > +       }
> > +
> > +       mmc_card_set_ddr_mode(card);
> > +       mmc_set_timing(host, MMC_TIMING_UHS_DDR50);
> > +
> > +       return err;
> > +}
> > +
> > +/*
> > + * For device supporting HS200 mode, the following sequence
> > + * should be done before executing the tuning process.
> > + * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
> > + * 2. switch to HS200 mode
> > + * 3. set the clock to > 52Mhz and <=200MHz
> > + */
> > +static int mmc_select_hs200(struct mmc_card *card)
> > +{
> > +       int err = -EINVAL;
> > +       struct mmc_host *host;
> > +
> > +       BUG_ON(!card);
> > +
> > +       host = card->host;
> > +
> > +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_SDR_1_2V)
> > +               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
> > +
> > +       if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_SDR_1_8V)
> > +               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
> > +
> > +       /* If fails try again during next card power cycle */
> > +       if (err)
> > +               goto err;
> > +
> > +       /*
> > +        * Set the bus width(4 or 8) with host's support and
> > +        * switch to HS200 mode if bus width is set successfully.
> > +        */
> > +       err = mmc_select_bus_width(card);
> > +       if (!IS_ERR_VALUE(err)) {
> >                 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > -                                EXT_CSD_HS_TIMING, 2, 0);
> > +                                EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> > +                                card->ext_csd.generic_cmd6_time);
> > +               if (!err) {
> > +                       mmc_card_set_hs200(card);
> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> > +               }
> > +       }
> >  err:
> >         return err;
> >  }
> >
> >  /*
> > + * Activate High Speed or HS200 mode if supported.
> > + */
> > +static int mmc_select_timing(struct mmc_card *card)
> > +{
> > +       struct mmc_host *host;
> > +       int err = 0;
> > +
> > +       BUG_ON(!card);
> > +
> > +       host = card->host;
> > +
> > +       if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
> > +            card->ext_csd.hs_max_dtr == 0))
> > +               goto bus_speed;
> > +
> > +       if (card->ext_csd.hs200_max_dtr > 52000000 &&
> > +                       host->caps2 & MMC_CAP2_HS200)
> > +               err = mmc_select_hs200(card);
> > +       else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> > +               err = mmc_select_hs(card);
> > +
> > +       if (err && err != -EBADMSG)
> > +               return err;
> > +
> > +       if (err) {
> > +               pr_warn("%s: switch to %s failed\n",
> > +                       mmc_card_highspeed(card) ? "high-speed" :
> > +                       (mmc_card_hs200(card) ? "hs200" : ""),
> > +                       mmc_hostname(card->host));
> > +               err = 0;
> > +       }
> > +
> > +bus_speed:
> > +       /*
> > +        * Set the bus speed to the selected bus timing.
> > +        * If timing is not selected, backward compatible is the default.
> > +        */
> > +       mmc_set_bus_speed(card);
> > +       return err;
> > +}
> > +
> > +/*
> > + * Execute tuning sequence to seek the proper bus operating
> > + * conditions for HS200, which sends CMD21 to the device.
> > + */
> > +static int mmc_hs200_tuning(struct mmc_card *card)
> > +{
> > +       int err = 0;
> > +       struct mmc_host *host;
> > +
> > +       BUG_ON(!card);
> > +
> > +       host = card->host;
> > +
> > +       if (host->caps2 & MMC_CAP2_HS200 &&
> > +           card->host->ops->execute_tuning) {
> > +               mmc_host_clk_hold(card->host);
> > +               err = card->host->ops->execute_tuning(card->host,
> > +                               MMC_SEND_TUNING_BLOCK_HS200);
> > +               mmc_host_clk_release(card->host);
> > +
> > +               if (err)
> > +                       pr_warn("%s: tuning execution failed\n",
> > +                               mmc_hostname(card->host));
> > +       }
> > +
> > +       return err;
> > +}
> > +
> > +/*
> >   * Handle the detection and initialisation of a card.
> >   *
> >   * In the case of a resume, "oldcard" will contain the card
> > @@ -872,9 +1150,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >         struct mmc_card *oldcard)
> >  {
> >         struct mmc_card *card;
> > -       int err, ddr = 0;
> > +       int err;
> >         u32 cid[4];
> > -       unsigned int max_dtr;
> >         u32 rocr;
> >         u8 *ext_csd = NULL;
> >
> > @@ -1066,209 +1343,30 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >         }
> >
> >         /*
> > -        * Activate high speed (if supported)
> > -        */
> > -       if (card->ext_csd.hs_max_dtr != 0) {
> > -               err = 0;
> > -               if (card->ext_csd.hs_max_dtr > 52000000 &&
> > -                   host->caps2 & MMC_CAP2_HS200)
> > -                       err = mmc_select_hs200(card);
> > -               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> > -                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > -                                        EXT_CSD_HS_TIMING, 1,
> > -                                        card->ext_csd.generic_cmd6_time);
> > -
> > -               if (err && err != -EBADMSG)
> > -                       goto free_card;
> > -
> > -               if (err) {
> > -                       pr_warning("%s: switch to highspeed failed\n",
> > -                              mmc_hostname(card->host));
> > -                       err = 0;
> > -               } else {
> > -                       if (card->ext_csd.hs_max_dtr > 52000000 &&
> > -                           host->caps2 & MMC_CAP2_HS200) {
> > -                               mmc_card_set_hs200(card);
> > -                               mmc_set_timing(card->host,
> > -                                              MMC_TIMING_MMC_HS200);
> > -                       } else {
> > -                               mmc_card_set_highspeed(card);
> > -                               mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> > -                       }
> > -               }
> > -       }
> > -
> > -       /*
> > -        * Compute bus speed.
> > -        */
> > -       max_dtr = (unsigned int)-1;
> > -
> > -       if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
> > -               if (max_dtr > card->ext_csd.hs_max_dtr)
> > -                       max_dtr = card->ext_csd.hs_max_dtr;
> > -               if (mmc_card_highspeed(card) && (max_dtr > 52000000))
> > -                       max_dtr = 52000000;
> > -       } else if (max_dtr > card->csd.max_dtr) {
> > -               max_dtr = card->csd.max_dtr;
> > -       }
> > -
> > -       mmc_set_clock(host, max_dtr);
> > -
> > -       /*
> > -        * Indicate DDR mode (if supported).
> > +        * Select timing interface
> >          */
> > -       if (mmc_card_highspeed(card)) {
> > -               if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
> > -                       && ((host->caps & (MMC_CAP_1_8V_DDR |
> > -                            MMC_CAP_UHS_DDR50))
> > -                               == (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
> > -                               ddr = MMC_1_8V_DDR_MODE;
> > -               else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
> > -                       && ((host->caps & (MMC_CAP_1_2V_DDR |
> > -                            MMC_CAP_UHS_DDR50))
> > -                               == (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
> > -                               ddr = MMC_1_2V_DDR_MODE;
> > -       }
> > +       err = mmc_select_timing(card);
> > +       if (err)
> > +               goto free_card;
> >
> > -       /*
> > -        * Indicate HS200 SDR mode (if supported).
> > -        */
> >         if (mmc_card_hs200(card)) {
> > -               u32 ext_csd_bits;
> > -               u32 bus_width = card->host->ios.bus_width;
> > -
> > -               /*
> > -                * For devices supporting HS200 mode, the bus width has
> > -                * to be set before executing the tuning function. If
> > -                * set before tuning, then device will respond with CRC
> > -                * errors for responses on CMD line. So for HS200 the
> > -                * sequence will be
> > -                * 1. set bus width 4bit / 8 bit (1 bit not supported)
> > -                * 2. switch to HS200 mode
> > -                * 3. set the clock to > 52Mhz <=200MHz and
> > -                * 4. execute tuning for HS200
> > -                */
> > -               if ((host->caps2 & MMC_CAP2_HS200) &&
> > -                   card->host->ops->execute_tuning) {
> > -                       mmc_host_clk_hold(card->host);
> > -                       err = card->host->ops->execute_tuning(card->host,
> > -                               MMC_SEND_TUNING_BLOCK_HS200);
> > -                       mmc_host_clk_release(card->host);
> > -               }
> > -               if (err) {
> > -                       pr_warning("%s: tuning execution failed\n",
> > -                                  mmc_hostname(card->host));
> > +               err = mmc_hs200_tuning(card);
> > +               if (err)
> >                         goto err;
> > +       } else if (mmc_card_highspeed(card)) {
> > +               /* Select the desired bus width optionally */
> > +               err = mmc_select_bus_width(card);
> > +               if (!IS_ERR_VALUE(err)) {
> > +                       err = mmc_select_hs_ddr(card, ext_csd);
> > +                       if (err)
> > +                               goto err;
> >                 }
> > -
> > -               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> > -                               EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
> > -               err = mmc_select_powerclass(card, ext_csd_bits);
> > -               if (err)
> > -                       pr_warning("%s: power class selection to bus width %d"
> > -                                  " failed\n", mmc_hostname(card->host),
> > -                                  1 << bus_width);
> >         }
> >
> >         /*
> > -        * Activate wide bus and DDR (if supported).
> > +        * Choose the power calss with selected bus interface
> >          */
> > -       if (!mmc_card_hs200(card) &&
> > -           (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
> > -           (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
> > -               static unsigned ext_csd_bits[][2] = {
> > -                       { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
> > -                       { EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
> > -                       { EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
> > -               };
> > -               static unsigned bus_widths[] = {
> > -                       MMC_BUS_WIDTH_8,
> > -                       MMC_BUS_WIDTH_4,
> > -                       MMC_BUS_WIDTH_1
> > -               };
> > -               unsigned idx, bus_width = 0;
> > -
> > -               if (host->caps & MMC_CAP_8_BIT_DATA)
> > -                       idx = 0;
> > -               else
> > -                       idx = 1;
> > -               for (; idx < ARRAY_SIZE(bus_widths); idx++) {
> > -                       bus_width = bus_widths[idx];
> > -                       if (bus_width == MMC_BUS_WIDTH_1)
> > -                               ddr = 0; /* no DDR for 1-bit width */
> > -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
> > -                       if (err)
> > -                               pr_warning("%s: power class selection to "
> > -                                          "bus width %d failed\n",
> > -                                          mmc_hostname(card->host),
> > -                                          1 << bus_width);
> > -
> > -                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > -                                        EXT_CSD_BUS_WIDTH,
> > -                                        ext_csd_bits[idx][0],
> > -                                        card->ext_csd.generic_cmd6_time);
> > -                       if (!err) {
> > -                               mmc_set_bus_width(card->host, bus_width);
> > -
> > -                               /*
> > -                                * If controller can't handle bus width test,
> > -                                * compare ext_csd previously read in 1 bit mode
> > -                                * against ext_csd at new bus width
> > -                                */
> > -                               if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
> > -                                       err = mmc_compare_ext_csds(card,
> > -                                               bus_width);
> > -                               else
> > -                                       err = mmc_bus_test(card, bus_width);
> > -                               if (!err)
> > -                                       break;
> > -                       }
> > -               }
> > -
> > -               if (!err && ddr) {
> > -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
> > -                       if (err)
> > -                               pr_warning("%s: power class selection to "
> > -                                          "bus width %d ddr %d failed\n",
> > -                                          mmc_hostname(card->host),
> > -                                          1 << bus_width, ddr);
> > -
> > -                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > -                                        EXT_CSD_BUS_WIDTH,
> > -                                        ext_csd_bits[idx][1],
> > -                                        card->ext_csd.generic_cmd6_time);
> > -               }
> > -               if (err) {
> > -                       pr_warning("%s: switch to bus width %d ddr %d "
> > -                               "failed\n", mmc_hostname(card->host),
> > -                               1 << bus_width, ddr);
> > -                       goto free_card;
> > -               } else if (ddr) {
> > -                       /*
> > -                        * eMMC cards can support 3.3V to 1.2V i/o (vccq)
> > -                        * signaling.
> > -                        *
> > -                        * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
> > -                        *
> > -                        * 1.8V vccq at 3.3V core voltage (vcc) is not required
> > -                        * in the JEDEC spec for DDR.
> > -                        *
> > -                        * Do not force change in vccq since we are obviously
> > -                        * working and no change to vccq is needed.
> > -                        *
> > -                        * WARNING: eMMC rules are NOT the same as SD DDR
> > -                        */
> > -                       if (ddr == MMC_1_2V_DDR_MODE) {
> > -                               err = __mmc_set_signal_voltage(host,
> > -                                       MMC_SIGNAL_VOLTAGE_120);
> > -                               if (err)
> > -                                       goto err;
> > -                       }
> > -                       mmc_card_set_ddr_mode(card);
> > -                       mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
> > -                       mmc_set_bus_width(card->host, bus_width);
> > -               }
> > -       }
> > +       mmc_select_powerclass(card, ext_csd);
> >
> >         /*
> >          * Enable HPI feature (if supported)
> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > index 176fdf8..c119735 100644
> > --- a/include/linux/mmc/card.h
> > +++ b/include/linux/mmc/card.h
> > @@ -63,6 +63,7 @@ struct mmc_ext_csd {
> >         unsigned int            power_off_longtime;     /* Units: ms */
> >         u8                      power_off_notification; /* state */
> >         unsigned int            hs_max_dtr;
> > +       unsigned int            hs200_max_dtr;
> >  #define MMC_HIGH_26_MAX_DTR    26000000
> >  #define MMC_HIGH_52_MAX_DTR    52000000
> >  #define MMC_HIGH_DDR_MAX_DTR   52000000
> > @@ -299,7 +300,10 @@ struct mmc_card {
> >         const char              **info;         /* info strings */
> >         struct sdio_func_tuple  *tuples;        /* unknown common tuples */
> >
> > -       unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
> > +       union {
> > +               unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
> > +               unsigned int            mmc_avail_type; /* supported device type by both host and card */
> > +       };
> >
> >         struct dentry           *debugfs_root;
> >         struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > index 99f5709..69d58b1 100644
> > --- a/include/linux/mmc/host.h
> > +++ b/include/linux/mmc/host.h
> > @@ -60,12 +60,6 @@ struct mmc_ios {
> >  #define MMC_TIMING_UHS_DDR50   7
> >  #define MMC_TIMING_MMC_HS200   8
> >
> > -#define MMC_SDR_MODE           0
> > -#define MMC_1_2V_DDR_MODE      1
> > -#define MMC_1_8V_DDR_MODE      2
> > -#define MMC_1_2V_SDR_MODE      3
> > -#define MMC_1_8V_SDR_MODE      4
> > -
> >         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
> >
> >  #define MMC_SIGNAL_VOLTAGE_330 0
> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> > index 50bcde3..87df508 100644
> > --- a/include/linux/mmc/mmc.h
> > +++ b/include/linux/mmc/mmc.h
> > @@ -373,6 +373,10 @@ struct _mmc_csd {
> >  #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_SEC_ER_EN      BIT(0)
> >  #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
> >  #define EXT_CSD_SEC_GB_CL_EN   BIT(4)
> > --
> > 1.7.0.4
> >
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* RE: [PATCH 2/3] mmc: correct some exclusive card state to clear
  2013-11-05 14:33   ` Ulf Hansson
@ 2013-11-06  9:35     ` Seungwon Jeon
  2013-11-06 10:38       ` Ulf Hansson
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2013-11-06  9:35 UTC (permalink / raw)
  To: 'Ulf Hansson'; +Cc: 'Chris Ball', 'linux-mmc'

On Tue, November 05, 2013, Ulf Hansson wrote:
> Hi Seungwon,
> 
> 
> On 5 November 2013 14:27, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Card state related to speed mode should be in non-overlapped.
> > Consideration for all cases is required when being cleared.
> > Also, MMC_STATE_PRESENT and MMC_STATE_REMOVED are same.
> > It's exclusive state which cannot be set at the same time.
> >
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > ---
> >  drivers/mmc/core/core.c  |    1 -
> >  drivers/mmc/core/mmc.c   |    4 ++--
> >  drivers/mmc/core/sd.c    |    5 +++--
> >  drivers/mmc/core/sdio.c  |    5 ++++-
> >  include/linux/mmc/card.h |   37 +++++++++++++++++++++++++++++++------
> >  5 files changed, 40 insertions(+), 12 deletions(-)
> >
> > diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> > index 57a2b40..b183d56 100644
> > --- a/drivers/mmc/core/core.c
> > +++ b/drivers/mmc/core/core.c
> > @@ -2281,7 +2281,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
> >                 }
> >         }
> >
> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
> >         if (mmc_host_is_spi(host)) {
> >                 host->ios.chip_select = MMC_CS_HIGH;
> >                 host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > index f4f8991..1668ea4 100644
> > --- a/drivers/mmc/core/mmc.c
> > +++ b/drivers/mmc/core/mmc.c
> > @@ -1597,11 +1597,11 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
> >                 err = mmc_sleep(host);
> >         else if (!mmc_host_is_spi(host))
> >                 err = mmc_deselect_cards(host);
> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
> >
> >         if (!err) {
> >                 mmc_power_off(host);
> >                 mmc_card_set_suspended(host->card);
> > +               mmc_card_set_ds(host->card);
> >         }
> >  out:
> >         mmc_release_host(host);
> > @@ -1727,8 +1727,8 @@ static int mmc_power_restore(struct mmc_host *host)
> >  {
> >         int ret;
> >
> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
> >         mmc_claim_host(host);
> > +       mmc_card_set_ds(host->card);
> >         ret = mmc_init_card(host, host->card->ocr, host->card);
> >         mmc_release_host(host);
> >
> > diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> > index 6f42050..b19a8f4 100644
> > --- a/drivers/mmc/core/sd.c
> > +++ b/drivers/mmc/core/sd.c
> > @@ -1082,10 +1082,11 @@ static int _mmc_sd_suspend(struct mmc_host *host)
> >
> >         if (!mmc_host_is_spi(host))
> >                 err = mmc_deselect_cards(host);
> > -       host->card->state &= ~MMC_STATE_HIGHSPEED;
> > +
> >         if (!err) {
> >                 mmc_power_off(host);
> >                 mmc_card_set_suspended(host->card);
> > +               mmc_card_set_ds(host->card);
> >         }
> >
> >  out:
> > @@ -1191,8 +1192,8 @@ static int mmc_sd_power_restore(struct mmc_host *host)
> >  {
> >         int ret;
> >
> > -       host->card->state &= ~MMC_STATE_HIGHSPEED;
> >         mmc_claim_host(host);
> > +       mmc_card_set_ds(host->card);
> >         ret = mmc_sd_init_card(host, host->card->ocr, host->card);
> >         mmc_release_host(host);
> >
> > diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> > index 4d721c6..7c6c43c 100644
> > --- a/drivers/mmc/core/sdio.c
> > +++ b/drivers/mmc/core/sdio.c
> > @@ -968,8 +968,10 @@ static int mmc_sdio_suspend(struct mmc_host *host)
> >                 mmc_release_host(host);
> >         }
> >
> > -       if (!err && !mmc_card_keep_power(host))
> > +       if (!err && !mmc_card_keep_power(host)) {
> >                 mmc_power_off(host);
> > +               mmc_card_set_ds(host->card);
> > +       }
> >
> >         return err;
> >  }
> > @@ -1075,6 +1077,7 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
> >         if (ret)
> >                 goto out;
> >
> > +       mmc_card_set_ds(host->card);
> >         ret = mmc_sdio_init_card(host, host->card->ocr, host->card,
> >                                 mmc_card_keep_power(host));
> >         if (!ret && host->sdio_irqs)
> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > index c119735..f2c2620 100644
> > --- a/include/linux/mmc/card.h
> > +++ b/include/linux/mmc/card.h
> > @@ -260,6 +260,11 @@ struct mmc_card {
> >  #define MMC_STATE_HIGHSPEED_200        (1<<8)          /* card is in HS200 mode */
> >  #define MMC_STATE_DOING_BKOPS  (1<<10)         /* card is doing BKOPS */
> >  #define MMC_STATE_SUSPENDED    (1<<11)         /* card is suspended */
> > +#define MMC_STATE_SPEED_MASK   (MMC_STATE_HIGHSPEED | \
> > +                                MMC_STATE_HIGHSPEED_DDR | \
> > +                                MMC_STATE_ULTRAHIGHSPEED | \
> > +                                MMC_STATE_HIGHSPEED_200)
> > +                                               /* Mask for default speed(DS) */
> >         unsigned int            quirks;         /* card quirks */
> >  #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range
> */
> >  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
> > @@ -431,19 +436,39 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
> >  #define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
> >  #define mmc_card_suspended(c)  ((c)->state & MMC_STATE_SUSPENDED)
> >
> > -#define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
> > +
> >  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
> > -#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
> > -#define mmc_card_set_hs200(c)  ((c)->state |= MMC_STATE_HIGHSPEED_200)
> >  #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
> > -#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
> > -#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
> >  #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
> > -#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
> >  #define mmc_card_set_doing_bkops(c)    ((c)->state |= MMC_STATE_DOING_BKOPS)
> >  #define mmc_card_clr_doing_bkops(c)    ((c)->state &= ~MMC_STATE_DOING_BKOPS)
> >  #define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
> >  #define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
> > +#define mmc_card_set_highspeed(c) \
> > +                       ((c)->state = \
> > +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> > +                        MMC_STATE_HIGHSPEED)
> > +#define mmc_card_set_ddr_mode(c) \
> > +                       ((c)->state = \
> > +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> > +                        MMC_STATE_HIGHSPEED_DDR)
> > +#define mmc_card_set_hs200(c) \
> > +                       ((c)->state = \
> > +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> > +                        MMC_STATE_HIGHSPEED_200)
> > +#define mmc_card_set_uhs(c) \
> > +                       ((c)->state = \
> > +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> > +                        MMC_STATE_ULTRAHIGHSPEED)
> > +#define mmc_card_set_present(c) \
> > +                       ((c)->state = \
> > +                        ((c)->state & ~MMC_CARD_REMOVED) | \
> > +                        MMC_STATE_PRESENT)
> > +#define mmc_card_set_removed(c) \
> > +                       ((c)->state = \
> > +                        ((c)->state & ~MMC_STATE_PRESENT) | \
> > +                        MMC_CARD_REMOVED)
> > +#define mmc_card_set_ds(c)     ((c)->state &= ~MMC_STATE_SPEED_MASK)
> 
> I have a feeling of that this "card->state" has become a container for
> a lot of mixed stuff. So your clean up is definitely justified.
> 
> I have a suggestion for how we can improve simplicity, how about
> dividing the state into two variables instead:
> 
> -> One part are actually used in the mmc core code to track a state
> and to make certain decisions during execution, like
> MMC_STATE_SUSPENDED, MMC_STATE_PRESENT, MMC_CARD_REMOVED.
> 
> -> The other part is more to be considered as the current operational
> state, for example the bus speed mode. The information in this "state
> variable" will be re-negotiated as a part of mmc_sd|sdio_init_card and
> can therefore always be reset in the beginning of these functions.
> 
> Does it make sense?
Thank you for suggestion. I also feel that.
Hmm, but when considering there is no case we access 'card->sate' directly,
splitting into two types of state doesn't seem to give much.
So I guess being kept is not bad.

Thanks,
Seungwon Jeon

> 
> Kind regards
> Ulf Hansson
> 
> >
> >  /*
> >   * Quirk add/remove for MMC products.
> > --
> > 1.7.0.4
> >
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* RE: [PATCH] mmc: trivial: fix the compiling warning
  2013-11-06  3:20   ` Jaehoon Chung
@ 2013-11-06  9:42     ` Seungwon Jeon
  0 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2013-11-06  9:42 UTC (permalink / raw)
  To: 'Jaehoon Chung', 'Chris Ball', 'Ulf Hansson'
  Cc: linux-mmc

On Wed, November 06, 2013, Jaehoon Chung wrote:
> I known this patch is already included into Ulf's patchset.
> 
> mmc: core: Silence compiler warning in __mmc_switch

Oh, good!

Thanks,
Seungwon Jeon
> 
> Best regards,
> Jaehoon Chung
> 
> On 11/05/2013 10:26 PM, Seungwon Jeon wrote:
> > Fixed the following warning.
> >
> > drivers/mmc/core/mmc_ops.c:484:11: warning: 'status' may be used
> > uninitialized in this function [-Wmaybe-uninitialized]
> >
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > ---
> >  drivers/mmc/core/mmc_ops.c |    2 +-
> >  1 files changed, 1 insertions(+), 1 deletions(-)
> >
> > diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
> > index aae8d8b..e5b5eeb 100644
> > --- a/drivers/mmc/core/mmc_ops.c
> > +++ b/drivers/mmc/core/mmc_ops.c
> > @@ -414,7 +414,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
> >  	int err;
> >  	struct mmc_command cmd = {0};
> >  	unsigned long timeout;
> > -	u32 status;
> > +	u32 status = 0;
> >  	bool ignore_crc = false;
> >
> >  	BUG_ON(!card);
> >
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH 2/3] mmc: correct some exclusive card state to clear
  2013-11-06  9:35     ` Seungwon Jeon
@ 2013-11-06 10:38       ` Ulf Hansson
  2013-11-07  3:51         ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2013-11-06 10:38 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: Chris Ball, linux-mmc

On 6 November 2013 10:35, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> On Tue, November 05, 2013, Ulf Hansson wrote:
>> Hi Seungwon,
>>
>>
>> On 5 November 2013 14:27, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> > Card state related to speed mode should be in non-overlapped.
>> > Consideration for all cases is required when being cleared.
>> > Also, MMC_STATE_PRESENT and MMC_STATE_REMOVED are same.
>> > It's exclusive state which cannot be set at the same time.
>> >
>> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> > ---
>> >  drivers/mmc/core/core.c  |    1 -
>> >  drivers/mmc/core/mmc.c   |    4 ++--
>> >  drivers/mmc/core/sd.c    |    5 +++--
>> >  drivers/mmc/core/sdio.c  |    5 ++++-
>> >  include/linux/mmc/card.h |   37 +++++++++++++++++++++++++++++++------
>> >  5 files changed, 40 insertions(+), 12 deletions(-)
>> >
>> > diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>> > index 57a2b40..b183d56 100644
>> > --- a/drivers/mmc/core/core.c
>> > +++ b/drivers/mmc/core/core.c
>> > @@ -2281,7 +2281,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
>> >                 }
>> >         }
>> >
>> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
>> >         if (mmc_host_is_spi(host)) {
>> >                 host->ios.chip_select = MMC_CS_HIGH;
>> >                 host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
>> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> > index f4f8991..1668ea4 100644
>> > --- a/drivers/mmc/core/mmc.c
>> > +++ b/drivers/mmc/core/mmc.c
>> > @@ -1597,11 +1597,11 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
>> >                 err = mmc_sleep(host);
>> >         else if (!mmc_host_is_spi(host))
>> >                 err = mmc_deselect_cards(host);
>> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
>> >
>> >         if (!err) {
>> >                 mmc_power_off(host);
>> >                 mmc_card_set_suspended(host->card);
>> > +               mmc_card_set_ds(host->card);
>> >         }
>> >  out:
>> >         mmc_release_host(host);
>> > @@ -1727,8 +1727,8 @@ static int mmc_power_restore(struct mmc_host *host)
>> >  {
>> >         int ret;
>> >
>> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
>> >         mmc_claim_host(host);
>> > +       mmc_card_set_ds(host->card);
>> >         ret = mmc_init_card(host, host->card->ocr, host->card);
>> >         mmc_release_host(host);
>> >
>> > diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>> > index 6f42050..b19a8f4 100644
>> > --- a/drivers/mmc/core/sd.c
>> > +++ b/drivers/mmc/core/sd.c
>> > @@ -1082,10 +1082,11 @@ static int _mmc_sd_suspend(struct mmc_host *host)
>> >
>> >         if (!mmc_host_is_spi(host))
>> >                 err = mmc_deselect_cards(host);
>> > -       host->card->state &= ~MMC_STATE_HIGHSPEED;
>> > +
>> >         if (!err) {
>> >                 mmc_power_off(host);
>> >                 mmc_card_set_suspended(host->card);
>> > +               mmc_card_set_ds(host->card);
>> >         }
>> >
>> >  out:
>> > @@ -1191,8 +1192,8 @@ static int mmc_sd_power_restore(struct mmc_host *host)
>> >  {
>> >         int ret;
>> >
>> > -       host->card->state &= ~MMC_STATE_HIGHSPEED;
>> >         mmc_claim_host(host);
>> > +       mmc_card_set_ds(host->card);
>> >         ret = mmc_sd_init_card(host, host->card->ocr, host->card);
>> >         mmc_release_host(host);
>> >
>> > diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
>> > index 4d721c6..7c6c43c 100644
>> > --- a/drivers/mmc/core/sdio.c
>> > +++ b/drivers/mmc/core/sdio.c
>> > @@ -968,8 +968,10 @@ static int mmc_sdio_suspend(struct mmc_host *host)
>> >                 mmc_release_host(host);
>> >         }
>> >
>> > -       if (!err && !mmc_card_keep_power(host))
>> > +       if (!err && !mmc_card_keep_power(host)) {
>> >                 mmc_power_off(host);
>> > +               mmc_card_set_ds(host->card);
>> > +       }
>> >
>> >         return err;
>> >  }
>> > @@ -1075,6 +1077,7 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
>> >         if (ret)
>> >                 goto out;
>> >
>> > +       mmc_card_set_ds(host->card);
>> >         ret = mmc_sdio_init_card(host, host->card->ocr, host->card,
>> >                                 mmc_card_keep_power(host));
>> >         if (!ret && host->sdio_irqs)
>> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> > index c119735..f2c2620 100644
>> > --- a/include/linux/mmc/card.h
>> > +++ b/include/linux/mmc/card.h
>> > @@ -260,6 +260,11 @@ struct mmc_card {
>> >  #define MMC_STATE_HIGHSPEED_200        (1<<8)          /* card is in HS200 mode */
>> >  #define MMC_STATE_DOING_BKOPS  (1<<10)         /* card is doing BKOPS */
>> >  #define MMC_STATE_SUSPENDED    (1<<11)         /* card is suspended */
>> > +#define MMC_STATE_SPEED_MASK   (MMC_STATE_HIGHSPEED | \
>> > +                                MMC_STATE_HIGHSPEED_DDR | \
>> > +                                MMC_STATE_ULTRAHIGHSPEED | \
>> > +                                MMC_STATE_HIGHSPEED_200)
>> > +                                               /* Mask for default speed(DS) */
>> >         unsigned int            quirks;         /* card quirks */
>> >  #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range
>> */
>> >  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
>> > @@ -431,19 +436,39 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
>> >  #define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
>> >  #define mmc_card_suspended(c)  ((c)->state & MMC_STATE_SUSPENDED)
>> >
>> > -#define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
>> > +
>> >  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
>> > -#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
>> > -#define mmc_card_set_hs200(c)  ((c)->state |= MMC_STATE_HIGHSPEED_200)
>> >  #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
>> > -#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
>> > -#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
>> >  #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
>> > -#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
>> >  #define mmc_card_set_doing_bkops(c)    ((c)->state |= MMC_STATE_DOING_BKOPS)
>> >  #define mmc_card_clr_doing_bkops(c)    ((c)->state &= ~MMC_STATE_DOING_BKOPS)
>> >  #define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
>> >  #define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
>> > +#define mmc_card_set_highspeed(c) \
>> > +                       ((c)->state = \
>> > +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
>> > +                        MMC_STATE_HIGHSPEED)
>> > +#define mmc_card_set_ddr_mode(c) \
>> > +                       ((c)->state = \
>> > +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
>> > +                        MMC_STATE_HIGHSPEED_DDR)
>> > +#define mmc_card_set_hs200(c) \
>> > +                       ((c)->state = \
>> > +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
>> > +                        MMC_STATE_HIGHSPEED_200)
>> > +#define mmc_card_set_uhs(c) \
>> > +                       ((c)->state = \
>> > +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
>> > +                        MMC_STATE_ULTRAHIGHSPEED)
>> > +#define mmc_card_set_present(c) \
>> > +                       ((c)->state = \
>> > +                        ((c)->state & ~MMC_CARD_REMOVED) | \
>> > +                        MMC_STATE_PRESENT)
>> > +#define mmc_card_set_removed(c) \
>> > +                       ((c)->state = \
>> > +                        ((c)->state & ~MMC_STATE_PRESENT) | \
>> > +                        MMC_CARD_REMOVED)
>> > +#define mmc_card_set_ds(c)     ((c)->state &= ~MMC_STATE_SPEED_MASK)
>>
>> I have a feeling of that this "card->state" has become a container for
>> a lot of mixed stuff. So your clean up is definitely justified.
>>
>> I have a suggestion for how we can improve simplicity, how about
>> dividing the state into two variables instead:
>>
>> -> One part are actually used in the mmc core code to track a state
>> and to make certain decisions during execution, like
>> MMC_STATE_SUSPENDED, MMC_STATE_PRESENT, MMC_CARD_REMOVED.
>>
>> -> The other part is more to be considered as the current operational
>> state, for example the bus speed mode. The information in this "state
>> variable" will be re-negotiated as a part of mmc_sd|sdio_init_card and
>> can therefore always be reset in the beginning of these functions.
>>
>> Does it make sense?
> Thank you for suggestion. I also feel that.
> Hmm, but when considering there is no case we access 'card->sate' directly,
> splitting into two types of state doesn't seem to give much.

Actually, on a second thought, why are we even caching the bus speeds
in the card state? The bus speeds are already reflected in the
"ios->timing" struct, which moreover also is available through
debugfs. Can we remove the bus speeds entirely from the card state
instead?

Kind regards
Ulf Hansson

> So I guess being kept is not bad.
>
> Thanks,
> Seungwon Jeon
>
>>
>> Kind regards
>> Ulf Hansson
>>
>> >
>> >  /*
>> >   * Quirk add/remove for MMC products.
>> > --
>> > 1.7.0.4
>> >
>> >
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

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

* Re: [PATCH 1/3] mmc: rework selection of bus speed mode
  2013-11-06  9:09     ` Seungwon Jeon
@ 2013-11-06 10:46       ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2013-11-06 10:46 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: Chris Ball, linux-mmc

On 6 November 2013 10:09, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Hi Ulf,
>
> On Tue, November 05, 2013, Ulf Hansson wrote:
>> Hi Seungwon,
>>
>> On 5 November 2013 14:27, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> > Current implementation for bus speed mode selection is too
>> > complicated. This patch is to simplify the codes and remove
>> > some duplicate parts.
>> >
>> > The following changes are including:
>> > * Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
>> > * Rearranged the mode selection sequence with supported device type
>> > * Power class is switched once only after bus modes(speed/width)
>> >   are selected finally
>> > * Adds maximum speed for HS200 mode(hs200_max_dtr)
>> > * Adds available device type to be supported by both host and device
>> > * Adds field definition for HS_TIMING of EXT_CSD
>>
>> Very nice work you are doing here, this is certainly needed.
>>
>> Although, from a reviewing point of view it would be nice if you could
>> split up and do re-factoring in more minor pieces. Could that be done?
>
> Ok. I'll consider that.
> But I guess it would not be done nicely because a whole flow is organic.
> If you have any opinion, please let me know.

Yes, please split it up.

Certainly it can be done nicely as well. In your commit message you
kind of already have a step by step procedure how the split up can be
done, just adopt to it. :-)

Kind regards
Ulf Hansson

>
> Thanks,
> Seungwon Jeon
>
>>
>> Kind regards
>> Ulf Hansson
>>
>> >
>> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> > ---
>> >  drivers/mmc/core/mmc.c   |  574 +++++++++++++++++++++++++++-------------------
>> >  include/linux/mmc/card.h |    6 +-
>> >  include/linux/mmc/host.h |    6 -
>> >  include/linux/mmc/mmc.h  |    4 +
>> >  4 files changed, 345 insertions(+), 245 deletions(-)
>> >
>> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> > index f631f5a..f4f8991 100644
>> > --- a/drivers/mmc/core/mmc.c
>> > +++ b/drivers/mmc/core/mmc.c
>> > @@ -242,29 +242,48 @@ static void mmc_select_card_type(struct mmc_card *card)
>> >         struct mmc_host *host = card->host;
>> >         u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>> >         u32 caps = host->caps, caps2 = host->caps2;
>> > -       unsigned int hs_max_dtr = 0;
>> > +       unsigned int avail_type = 0;
>> > +       unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>> >
>> > -       if (card_type & EXT_CSD_CARD_TYPE_26)
>> > +       if (card_type & EXT_CSD_CARD_TYPE_26) {
>> >                 hs_max_dtr = MMC_HIGH_26_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_26;
>> > +       }
>> >
>> >         if (caps & MMC_CAP_MMC_HIGHSPEED &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_52)
>> > +           card_type & EXT_CSD_CARD_TYPE_52) {
>> >                 hs_max_dtr = MMC_HIGH_52_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_52;
>> > +       }
>> > +
>> > +       if (caps & MMC_CAP_1_8V_DDR &&
>> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
>> > +               hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
>> > +       }
>> >
>> > -       if ((caps & MMC_CAP_1_8V_DDR &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
>> > -           (caps & MMC_CAP_1_2V_DDR &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
>> > +       if (caps & MMC_CAP_1_2V_DDR &&
>> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
>> >                 hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
>> > +       }
>> > +
>> > +       if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
>> > +           card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) {
>> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_SDR_1_8V;
>> > +       }
>> >
>> > -       if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
>> > -           (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
>> > -               hs_max_dtr = MMC_HS200_MAX_DTR;
>> > +       if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
>> > +           card_type & EXT_CSD_CARD_TYPE_SDR_1_2V) {
>> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_SDR_1_2V;
>> > +       }
>> >
>> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
>> > +       card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>> >         card->ext_csd.card_type = card_type;
>> > +       card->mmc_avail_type = avail_type;
>> >  }
>> >
>> >  /*
>> > @@ -714,8 +733,8 @@ static struct device_type mmc_type = {
>> >   * extended CSD register, select it by executing the
>> >   * mmc_switch command.
>> >   */
>> > -static int mmc_select_powerclass(struct mmc_card *card,
>> > -               unsigned int bus_width)
>> > +static int __mmc_select_powerclass(struct mmc_card *card,
>> > +                                  unsigned int bus_width, u8 *ext_csd)
>> >  {
>> >         int err = 0;
>> >         unsigned int pwrclass_val = 0;
>> > @@ -787,40 +806,99 @@ static int mmc_select_powerclass(struct mmc_card *card,
>> >         return err;
>> >  }
>> >
>> > +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
>> > +{
>> > +       return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
>> > +}
>> > +
>> > +static int mmc_select_powerclass(struct mmc_card *card, u8 *ext_csd)
>> > +{
>> > +       int err, ddr;
>> > +       u32 bus_width, ext_csd_bits;
>> > +       struct mmc_host *host;
>> > +
>> > +       BUG_ON(!card);
>> > +
>> > +       host = card->host;
>> > +
>> > +       if (!ext_csd)
>> > +               return 0;
>> > +
>> > +       /* Power class selection is supported for versions >= 4.0 */
>> > +       if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
>> > +               return 0;
>> > +
>> > +       bus_width = host->ios.bus_width;
>> > +       /* Power class values are defined only for 4/8 bit bus */
>> > +       if (bus_width == MMC_BUS_WIDTH_1)
>> > +               return 0;
>> > +
>> > +       ddr = mmc_snoop_ddr(card);
>> > +       if (ddr)
>> > +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
>> > +                       EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
>> > +       else
>> > +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
>> > +                       EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
>> > +
>> > +       err = __mmc_select_powerclass(card, ext_csd_bits, ext_csd);
>> > +       if (err)
>> > +               pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
>> > +                       mmc_hostname(host), 1 << bus_width, ddr);
>> > +
>> > +       return err;
>> > +}
>> > +
>> >  /*
>> > - * Selects the desired buswidth and switch to the HS200 mode
>> > - * if bus width set without error
>> > + * Set the bus speed for the selected speed mode.
>> >   */
>> > -static int mmc_select_hs200(struct mmc_card *card)
>> > +static void mmc_set_bus_speed(struct mmc_card *card)
>> > +{
>> > +       unsigned int max_dtr = (unsigned int)-1;
>> > +
>> > +       BUG_ON(!card);
>> > +
>> > +       if (mmc_card_hs200(card)) {
>> > +               if (max_dtr > card->ext_csd.hs200_max_dtr)
>> > +                       max_dtr = card->ext_csd.hs200_max_dtr;
>> > +       } else if (mmc_card_highspeed(card)) {
>> > +               if (max_dtr > card->ext_csd.hs_max_dtr)
>> > +                       max_dtr = card->ext_csd.hs_max_dtr;
>> > +       } else if (max_dtr > card->csd.max_dtr) {
>> > +               max_dtr = card->csd.max_dtr;
>> > +       }
>> > +
>> > +       mmc_set_clock(card->host, max_dtr);
>> > +}
>> > +
>> > +/*
>> > + * Select the bus width amoung 4-bit and 8-bit(SDR).
>> > + * If the bus width is changed successfully, return the slected width value.
>> > + * Zero is returned instead of error value if the wide width is not supported.
>> > + */
>> > +static int mmc_select_bus_width(struct mmc_card *card)
>> >  {
>> > -       int idx, err = -EINVAL;
>> > -       struct mmc_host *host;
>> >         static unsigned ext_csd_bits[] = {
>> > -               EXT_CSD_BUS_WIDTH_4,
>> >                 EXT_CSD_BUS_WIDTH_8,
>> > +               EXT_CSD_BUS_WIDTH_4,
>> >         };
>> >         static unsigned bus_widths[] = {
>> > -               MMC_BUS_WIDTH_4,
>> >                 MMC_BUS_WIDTH_8,
>> > +               MMC_BUS_WIDTH_4,
>> >         };
>> > +       struct mmc_host *host;
>> > +       unsigned idx, bus_width = 0;
>> > +       int err = 0;
>> >
>> >         BUG_ON(!card);
>> >
>> >         host = card->host;
>> >
>> > -       if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
>> > -                       host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
>> > -               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
>> > -
>> > -       if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
>> > -                       host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
>> > -               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
>> > -
>> > -       /* If fails try again during next card power cycle */
>> > -       if (err)
>> > -               goto err;
>> > +       if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
>> > +           !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
>> > +               return 0;
>> >
>> > -       idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
>> > +       idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
>> >
>> >         /*
>> >          * Unlike SD, MMC cards dont have a configuration register to notify
>> > @@ -828,8 +906,7 @@ static int mmc_select_hs200(struct mmc_card *card)
>> >          * 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 >= 0; idx--) {
>> > -
>> > +       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
>> > @@ -844,25 +921,226 @@ static int mmc_select_hs200(struct mmc_card *card)
>> >                 if (err)
>> >                         continue;
>> >
>> > -               mmc_set_bus_width(card->host, bus_widths[idx]);
>> > +               bus_width = bus_widths[idx];
>> > +               mmc_set_bus_width(host, bus_width);
>> >
>> > +               /*
>> > +                * If controller can't handle bus width test,
>> > +                * compare ext_csd previously read in 1 bit mode
>> > +                * against ext_csd at new bus width
>> > +                */
>> >                 if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
>> > -                       err = mmc_compare_ext_csds(card, bus_widths[idx]);
>> > +                       err = mmc_compare_ext_csds(card, bus_width);
>> >                 else
>> > -                       err = mmc_bus_test(card, bus_widths[idx]);
>> > -               if (!err)
>> > +                       err = mmc_bus_test(card, bus_width);
>> > +
>> > +               if (!err) {
>> > +                       err = bus_width;
>> >                         break;
>> > +               } else {
>> > +                       pr_warn("%s: switch to bus width %d failed\n",
>> > +                               mmc_hostname(card->host), ext_csd_bits[idx]);
>> > +               }
>> >         }
>> >
>> > -       /* switch to HS200 mode if bus width set successfully */
>> > -       if (!err)
>> > +       return err;
>> > +}
>> > +
>> > +/*
>> > + * Switch to the high-speed mode
>> > + */
>> > +static int mmc_select_hs(struct mmc_card *card)
>> > +{
>> > +       int err;
>> > +
>> > +       BUG_ON(!card);
>> > +
>> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
>> > +                        card->ext_csd.generic_cmd6_time);
>> > +       if (!err) {
>> > +               mmc_card_set_highspeed(card);
>> > +               mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> > +       }
>> > +
>> > +       return err;
>> > +}
>> > +
>> > +/*
>> > + * Activate wide bus and DDR if supported.
>> > + */
>> > +static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
>> > +{
>> > +       struct mmc_host *host;
>> > +       u32 bus_width, ext_csd_bits;
>> > +       int err = 0, ddr;
>> > +
>> > +       BUG_ON(!card);
>> > +
>> > +       ddr = mmc_snoop_ddr(card);
>> > +       if (!(ddr & EXT_CSD_CARD_TYPE_DDR_52))
>> > +               return 0;
>> > +
>> > +       host = card->host;
>> > +       bus_width = host->ios.bus_width;
>> > +       if (bus_width == MMC_BUS_WIDTH_1)
>> > +               return 0;
>> > +
>> > +       ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
>> > +               EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
>> > +
>> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> > +                       EXT_CSD_BUS_WIDTH,
>> > +                       ext_csd_bits,
>> > +                       card->ext_csd.generic_cmd6_time);
>> > +       if (err) {
>> > +               pr_warn("%s: switch to bus width %d ddr failed\n",
>> > +                       mmc_hostname(host), 1 << bus_width);
>> > +               return err;
>> > +       }
>> > +
>> > +       /*
>> > +        * eMMC cards can support 3.3V to 1.2V i/o (vccq)
>> > +        * signaling.
>> > +        *
>> > +        * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
>> > +        *
>> > +        * 1.8V vccq at 3.3V core voltage (vcc) is not required
>> > +        * in the JEDEC spec for DDR.
>> > +        *
>> > +        * Do not force change in vccq since we are obviously
>> > +        * working and no change to vccq is needed.
>> > +        *
>> > +        * WARNING: eMMC rules are NOT the same as SD DDR
>> > +        */
>> > +       if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
>> > +               err = __mmc_set_signal_voltage(host,
>> > +                               MMC_SIGNAL_VOLTAGE_120);
>> > +               if (err)
>> > +                       return err;
>> > +       }
>> > +
>> > +       mmc_card_set_ddr_mode(card);
>> > +       mmc_set_timing(host, MMC_TIMING_UHS_DDR50);
>> > +
>> > +       return err;
>> > +}
>> > +
>> > +/*
>> > + * For device supporting HS200 mode, the following sequence
>> > + * should be done before executing the tuning process.
>> > + * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
>> > + * 2. switch to HS200 mode
>> > + * 3. set the clock to > 52Mhz and <=200MHz
>> > + */
>> > +static int mmc_select_hs200(struct mmc_card *card)
>> > +{
>> > +       int err = -EINVAL;
>> > +       struct mmc_host *host;
>> > +
>> > +       BUG_ON(!card);
>> > +
>> > +       host = card->host;
>> > +
>> > +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_SDR_1_2V)
>> > +               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
>> > +
>> > +       if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_SDR_1_8V)
>> > +               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
>> > +
>> > +       /* If fails try again during next card power cycle */
>> > +       if (err)
>> > +               goto err;
>> > +
>> > +       /*
>> > +        * Set the bus width(4 or 8) with host's support and
>> > +        * switch to HS200 mode if bus width is set successfully.
>> > +        */
>> > +       err = mmc_select_bus_width(card);
>> > +       if (!IS_ERR_VALUE(err)) {
>> >                 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> > -                                EXT_CSD_HS_TIMING, 2, 0);
>> > +                                EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
>> > +                                card->ext_csd.generic_cmd6_time);
>> > +               if (!err) {
>> > +                       mmc_card_set_hs200(card);
>> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS200);
>> > +               }
>> > +       }
>> >  err:
>> >         return err;
>> >  }
>> >
>> >  /*
>> > + * Activate High Speed or HS200 mode if supported.
>> > + */
>> > +static int mmc_select_timing(struct mmc_card *card)
>> > +{
>> > +       struct mmc_host *host;
>> > +       int err = 0;
>> > +
>> > +       BUG_ON(!card);
>> > +
>> > +       host = card->host;
>> > +
>> > +       if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
>> > +            card->ext_csd.hs_max_dtr == 0))
>> > +               goto bus_speed;
>> > +
>> > +       if (card->ext_csd.hs200_max_dtr > 52000000 &&
>> > +                       host->caps2 & MMC_CAP2_HS200)
>> > +               err = mmc_select_hs200(card);
>> > +       else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
>> > +               err = mmc_select_hs(card);
>> > +
>> > +       if (err && err != -EBADMSG)
>> > +               return err;
>> > +
>> > +       if (err) {
>> > +               pr_warn("%s: switch to %s failed\n",
>> > +                       mmc_card_highspeed(card) ? "high-speed" :
>> > +                       (mmc_card_hs200(card) ? "hs200" : ""),
>> > +                       mmc_hostname(card->host));
>> > +               err = 0;
>> > +       }
>> > +
>> > +bus_speed:
>> > +       /*
>> > +        * Set the bus speed to the selected bus timing.
>> > +        * If timing is not selected, backward compatible is the default.
>> > +        */
>> > +       mmc_set_bus_speed(card);
>> > +       return err;
>> > +}
>> > +
>> > +/*
>> > + * Execute tuning sequence to seek the proper bus operating
>> > + * conditions for HS200, which sends CMD21 to the device.
>> > + */
>> > +static int mmc_hs200_tuning(struct mmc_card *card)
>> > +{
>> > +       int err = 0;
>> > +       struct mmc_host *host;
>> > +
>> > +       BUG_ON(!card);
>> > +
>> > +       host = card->host;
>> > +
>> > +       if (host->caps2 & MMC_CAP2_HS200 &&
>> > +           card->host->ops->execute_tuning) {
>> > +               mmc_host_clk_hold(card->host);
>> > +               err = card->host->ops->execute_tuning(card->host,
>> > +                               MMC_SEND_TUNING_BLOCK_HS200);
>> > +               mmc_host_clk_release(card->host);
>> > +
>> > +               if (err)
>> > +                       pr_warn("%s: tuning execution failed\n",
>> > +                               mmc_hostname(card->host));
>> > +       }
>> > +
>> > +       return err;
>> > +}
>> > +
>> > +/*
>> >   * Handle the detection and initialisation of a card.
>> >   *
>> >   * In the case of a resume, "oldcard" will contain the card
>> > @@ -872,9 +1150,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >         struct mmc_card *oldcard)
>> >  {
>> >         struct mmc_card *card;
>> > -       int err, ddr = 0;
>> > +       int err;
>> >         u32 cid[4];
>> > -       unsigned int max_dtr;
>> >         u32 rocr;
>> >         u8 *ext_csd = NULL;
>> >
>> > @@ -1066,209 +1343,30 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >         }
>> >
>> >         /*
>> > -        * Activate high speed (if supported)
>> > -        */
>> > -       if (card->ext_csd.hs_max_dtr != 0) {
>> > -               err = 0;
>> > -               if (card->ext_csd.hs_max_dtr > 52000000 &&
>> > -                   host->caps2 & MMC_CAP2_HS200)
>> > -                       err = mmc_select_hs200(card);
>> > -               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
>> > -                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> > -                                        EXT_CSD_HS_TIMING, 1,
>> > -                                        card->ext_csd.generic_cmd6_time);
>> > -
>> > -               if (err && err != -EBADMSG)
>> > -                       goto free_card;
>> > -
>> > -               if (err) {
>> > -                       pr_warning("%s: switch to highspeed failed\n",
>> > -                              mmc_hostname(card->host));
>> > -                       err = 0;
>> > -               } else {
>> > -                       if (card->ext_csd.hs_max_dtr > 52000000 &&
>> > -                           host->caps2 & MMC_CAP2_HS200) {
>> > -                               mmc_card_set_hs200(card);
>> > -                               mmc_set_timing(card->host,
>> > -                                              MMC_TIMING_MMC_HS200);
>> > -                       } else {
>> > -                               mmc_card_set_highspeed(card);
>> > -                               mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> > -                       }
>> > -               }
>> > -       }
>> > -
>> > -       /*
>> > -        * Compute bus speed.
>> > -        */
>> > -       max_dtr = (unsigned int)-1;
>> > -
>> > -       if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
>> > -               if (max_dtr > card->ext_csd.hs_max_dtr)
>> > -                       max_dtr = card->ext_csd.hs_max_dtr;
>> > -               if (mmc_card_highspeed(card) && (max_dtr > 52000000))
>> > -                       max_dtr = 52000000;
>> > -       } else if (max_dtr > card->csd.max_dtr) {
>> > -               max_dtr = card->csd.max_dtr;
>> > -       }
>> > -
>> > -       mmc_set_clock(host, max_dtr);
>> > -
>> > -       /*
>> > -        * Indicate DDR mode (if supported).
>> > +        * Select timing interface
>> >          */
>> > -       if (mmc_card_highspeed(card)) {
>> > -               if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
>> > -                       && ((host->caps & (MMC_CAP_1_8V_DDR |
>> > -                            MMC_CAP_UHS_DDR50))
>> > -                               == (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
>> > -                               ddr = MMC_1_8V_DDR_MODE;
>> > -               else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
>> > -                       && ((host->caps & (MMC_CAP_1_2V_DDR |
>> > -                            MMC_CAP_UHS_DDR50))
>> > -                               == (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
>> > -                               ddr = MMC_1_2V_DDR_MODE;
>> > -       }
>> > +       err = mmc_select_timing(card);
>> > +       if (err)
>> > +               goto free_card;
>> >
>> > -       /*
>> > -        * Indicate HS200 SDR mode (if supported).
>> > -        */
>> >         if (mmc_card_hs200(card)) {
>> > -               u32 ext_csd_bits;
>> > -               u32 bus_width = card->host->ios.bus_width;
>> > -
>> > -               /*
>> > -                * For devices supporting HS200 mode, the bus width has
>> > -                * to be set before executing the tuning function. If
>> > -                * set before tuning, then device will respond with CRC
>> > -                * errors for responses on CMD line. So for HS200 the
>> > -                * sequence will be
>> > -                * 1. set bus width 4bit / 8 bit (1 bit not supported)
>> > -                * 2. switch to HS200 mode
>> > -                * 3. set the clock to > 52Mhz <=200MHz and
>> > -                * 4. execute tuning for HS200
>> > -                */
>> > -               if ((host->caps2 & MMC_CAP2_HS200) &&
>> > -                   card->host->ops->execute_tuning) {
>> > -                       mmc_host_clk_hold(card->host);
>> > -                       err = card->host->ops->execute_tuning(card->host,
>> > -                               MMC_SEND_TUNING_BLOCK_HS200);
>> > -                       mmc_host_clk_release(card->host);
>> > -               }
>> > -               if (err) {
>> > -                       pr_warning("%s: tuning execution failed\n",
>> > -                                  mmc_hostname(card->host));
>> > +               err = mmc_hs200_tuning(card);
>> > +               if (err)
>> >                         goto err;
>> > +       } else if (mmc_card_highspeed(card)) {
>> > +               /* Select the desired bus width optionally */
>> > +               err = mmc_select_bus_width(card);
>> > +               if (!IS_ERR_VALUE(err)) {
>> > +                       err = mmc_select_hs_ddr(card, ext_csd);
>> > +                       if (err)
>> > +                               goto err;
>> >                 }
>> > -
>> > -               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
>> > -                               EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
>> > -               err = mmc_select_powerclass(card, ext_csd_bits);
>> > -               if (err)
>> > -                       pr_warning("%s: power class selection to bus width %d"
>> > -                                  " failed\n", mmc_hostname(card->host),
>> > -                                  1 << bus_width);
>> >         }
>> >
>> >         /*
>> > -        * Activate wide bus and DDR (if supported).
>> > +        * Choose the power calss with selected bus interface
>> >          */
>> > -       if (!mmc_card_hs200(card) &&
>> > -           (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
>> > -           (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
>> > -               static unsigned ext_csd_bits[][2] = {
>> > -                       { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
>> > -                       { EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
>> > -                       { EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
>> > -               };
>> > -               static unsigned bus_widths[] = {
>> > -                       MMC_BUS_WIDTH_8,
>> > -                       MMC_BUS_WIDTH_4,
>> > -                       MMC_BUS_WIDTH_1
>> > -               };
>> > -               unsigned idx, bus_width = 0;
>> > -
>> > -               if (host->caps & MMC_CAP_8_BIT_DATA)
>> > -                       idx = 0;
>> > -               else
>> > -                       idx = 1;
>> > -               for (; idx < ARRAY_SIZE(bus_widths); idx++) {
>> > -                       bus_width = bus_widths[idx];
>> > -                       if (bus_width == MMC_BUS_WIDTH_1)
>> > -                               ddr = 0; /* no DDR for 1-bit width */
>> > -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
>> > -                       if (err)
>> > -                               pr_warning("%s: power class selection to "
>> > -                                          "bus width %d failed\n",
>> > -                                          mmc_hostname(card->host),
>> > -                                          1 << bus_width);
>> > -
>> > -                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> > -                                        EXT_CSD_BUS_WIDTH,
>> > -                                        ext_csd_bits[idx][0],
>> > -                                        card->ext_csd.generic_cmd6_time);
>> > -                       if (!err) {
>> > -                               mmc_set_bus_width(card->host, bus_width);
>> > -
>> > -                               /*
>> > -                                * If controller can't handle bus width test,
>> > -                                * compare ext_csd previously read in 1 bit mode
>> > -                                * against ext_csd at new bus width
>> > -                                */
>> > -                               if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
>> > -                                       err = mmc_compare_ext_csds(card,
>> > -                                               bus_width);
>> > -                               else
>> > -                                       err = mmc_bus_test(card, bus_width);
>> > -                               if (!err)
>> > -                                       break;
>> > -                       }
>> > -               }
>> > -
>> > -               if (!err && ddr) {
>> > -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
>> > -                       if (err)
>> > -                               pr_warning("%s: power class selection to "
>> > -                                          "bus width %d ddr %d failed\n",
>> > -                                          mmc_hostname(card->host),
>> > -                                          1 << bus_width, ddr);
>> > -
>> > -                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> > -                                        EXT_CSD_BUS_WIDTH,
>> > -                                        ext_csd_bits[idx][1],
>> > -                                        card->ext_csd.generic_cmd6_time);
>> > -               }
>> > -               if (err) {
>> > -                       pr_warning("%s: switch to bus width %d ddr %d "
>> > -                               "failed\n", mmc_hostname(card->host),
>> > -                               1 << bus_width, ddr);
>> > -                       goto free_card;
>> > -               } else if (ddr) {
>> > -                       /*
>> > -                        * eMMC cards can support 3.3V to 1.2V i/o (vccq)
>> > -                        * signaling.
>> > -                        *
>> > -                        * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
>> > -                        *
>> > -                        * 1.8V vccq at 3.3V core voltage (vcc) is not required
>> > -                        * in the JEDEC spec for DDR.
>> > -                        *
>> > -                        * Do not force change in vccq since we are obviously
>> > -                        * working and no change to vccq is needed.
>> > -                        *
>> > -                        * WARNING: eMMC rules are NOT the same as SD DDR
>> > -                        */
>> > -                       if (ddr == MMC_1_2V_DDR_MODE) {
>> > -                               err = __mmc_set_signal_voltage(host,
>> > -                                       MMC_SIGNAL_VOLTAGE_120);
>> > -                               if (err)
>> > -                                       goto err;
>> > -                       }
>> > -                       mmc_card_set_ddr_mode(card);
>> > -                       mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
>> > -                       mmc_set_bus_width(card->host, bus_width);
>> > -               }
>> > -       }
>> > +       mmc_select_powerclass(card, ext_csd);
>> >
>> >         /*
>> >          * Enable HPI feature (if supported)
>> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> > index 176fdf8..c119735 100644
>> > --- a/include/linux/mmc/card.h
>> > +++ b/include/linux/mmc/card.h
>> > @@ -63,6 +63,7 @@ struct mmc_ext_csd {
>> >         unsigned int            power_off_longtime;     /* Units: ms */
>> >         u8                      power_off_notification; /* state */
>> >         unsigned int            hs_max_dtr;
>> > +       unsigned int            hs200_max_dtr;
>> >  #define MMC_HIGH_26_MAX_DTR    26000000
>> >  #define MMC_HIGH_52_MAX_DTR    52000000
>> >  #define MMC_HIGH_DDR_MAX_DTR   52000000
>> > @@ -299,7 +300,10 @@ struct mmc_card {
>> >         const char              **info;         /* info strings */
>> >         struct sdio_func_tuple  *tuples;        /* unknown common tuples */
>> >
>> > -       unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
>> > +       union {
>> > +               unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
>> > +               unsigned int            mmc_avail_type; /* supported device type by both host and card */
>> > +       };
>> >
>> >         struct dentry           *debugfs_root;
>> >         struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
>> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> > index 99f5709..69d58b1 100644
>> > --- a/include/linux/mmc/host.h
>> > +++ b/include/linux/mmc/host.h
>> > @@ -60,12 +60,6 @@ struct mmc_ios {
>> >  #define MMC_TIMING_UHS_DDR50   7
>> >  #define MMC_TIMING_MMC_HS200   8
>> >
>> > -#define MMC_SDR_MODE           0
>> > -#define MMC_1_2V_DDR_MODE      1
>> > -#define MMC_1_8V_DDR_MODE      2
>> > -#define MMC_1_2V_SDR_MODE      3
>> > -#define MMC_1_8V_SDR_MODE      4
>> > -
>> >         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
>> >
>> >  #define MMC_SIGNAL_VOLTAGE_330 0
>> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> > index 50bcde3..87df508 100644
>> > --- a/include/linux/mmc/mmc.h
>> > +++ b/include/linux/mmc/mmc.h
>> > @@ -373,6 +373,10 @@ struct _mmc_csd {
>> >  #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_SEC_ER_EN      BIT(0)
>> >  #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
>> >  #define EXT_CSD_SEC_GB_CL_EN   BIT(4)
>> > --
>> > 1.7.0.4
>> >
>> >
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH 2/3] mmc: correct some exclusive card state to clear
  2013-11-06 10:38       ` Ulf Hansson
@ 2013-11-07  3:51         ` Seungwon Jeon
  0 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2013-11-07  3:51 UTC (permalink / raw)
  To: 'Ulf Hansson'; +Cc: 'Chris Ball', 'linux-mmc'

On Wed, November 06, 2013, Ulf Hansson wrote:
> On 6 November 2013 10:35, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > On Tue, November 05, 2013, Ulf Hansson wrote:
> >> Hi Seungwon,
> >>
> >>
> >> On 5 November 2013 14:27, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> > Card state related to speed mode should be in non-overlapped.
> >> > Consideration for all cases is required when being cleared.
> >> > Also, MMC_STATE_PRESENT and MMC_STATE_REMOVED are same.
> >> > It's exclusive state which cannot be set at the same time.
> >> >
> >> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> >> > ---
> >> >  drivers/mmc/core/core.c  |    1 -
> >> >  drivers/mmc/core/mmc.c   |    4 ++--
> >> >  drivers/mmc/core/sd.c    |    5 +++--
> >> >  drivers/mmc/core/sdio.c  |    5 ++++-
> >> >  include/linux/mmc/card.h |   37 +++++++++++++++++++++++++++++++------
> >> >  5 files changed, 40 insertions(+), 12 deletions(-)
> >> >
> >> > diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> >> > index 57a2b40..b183d56 100644
> >> > --- a/drivers/mmc/core/core.c
> >> > +++ b/drivers/mmc/core/core.c
> >> > @@ -2281,7 +2281,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
> >> >                 }
> >> >         }
> >> >
> >> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
> >> >         if (mmc_host_is_spi(host)) {
> >> >                 host->ios.chip_select = MMC_CS_HIGH;
> >> >                 host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
> >> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >> > index f4f8991..1668ea4 100644
> >> > --- a/drivers/mmc/core/mmc.c
> >> > +++ b/drivers/mmc/core/mmc.c
> >> > @@ -1597,11 +1597,11 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
> >> >                 err = mmc_sleep(host);
> >> >         else if (!mmc_host_is_spi(host))
> >> >                 err = mmc_deselect_cards(host);
> >> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
> >> >
> >> >         if (!err) {
> >> >                 mmc_power_off(host);
> >> >                 mmc_card_set_suspended(host->card);
> >> > +               mmc_card_set_ds(host->card);
> >> >         }
> >> >  out:
> >> >         mmc_release_host(host);
> >> > @@ -1727,8 +1727,8 @@ static int mmc_power_restore(struct mmc_host *host)
> >> >  {
> >> >         int ret;
> >> >
> >> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
> >> >         mmc_claim_host(host);
> >> > +       mmc_card_set_ds(host->card);
> >> >         ret = mmc_init_card(host, host->card->ocr, host->card);
> >> >         mmc_release_host(host);
> >> >
> >> > diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> >> > index 6f42050..b19a8f4 100644
> >> > --- a/drivers/mmc/core/sd.c
> >> > +++ b/drivers/mmc/core/sd.c
> >> > @@ -1082,10 +1082,11 @@ static int _mmc_sd_suspend(struct mmc_host *host)
> >> >
> >> >         if (!mmc_host_is_spi(host))
> >> >                 err = mmc_deselect_cards(host);
> >> > -       host->card->state &= ~MMC_STATE_HIGHSPEED;
> >> > +
> >> >         if (!err) {
> >> >                 mmc_power_off(host);
> >> >                 mmc_card_set_suspended(host->card);
> >> > +               mmc_card_set_ds(host->card);
> >> >         }
> >> >
> >> >  out:
> >> > @@ -1191,8 +1192,8 @@ static int mmc_sd_power_restore(struct mmc_host *host)
> >> >  {
> >> >         int ret;
> >> >
> >> > -       host->card->state &= ~MMC_STATE_HIGHSPEED;
> >> >         mmc_claim_host(host);
> >> > +       mmc_card_set_ds(host->card);
> >> >         ret = mmc_sd_init_card(host, host->card->ocr, host->card);
> >> >         mmc_release_host(host);
> >> >
> >> > diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> >> > index 4d721c6..7c6c43c 100644
> >> > --- a/drivers/mmc/core/sdio.c
> >> > +++ b/drivers/mmc/core/sdio.c
> >> > @@ -968,8 +968,10 @@ static int mmc_sdio_suspend(struct mmc_host *host)
> >> >                 mmc_release_host(host);
> >> >         }
> >> >
> >> > -       if (!err && !mmc_card_keep_power(host))
> >> > +       if (!err && !mmc_card_keep_power(host)) {
> >> >                 mmc_power_off(host);
> >> > +               mmc_card_set_ds(host->card);
> >> > +       }
> >> >
> >> >         return err;
> >> >  }
> >> > @@ -1075,6 +1077,7 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
> >> >         if (ret)
> >> >                 goto out;
> >> >
> >> > +       mmc_card_set_ds(host->card);
> >> >         ret = mmc_sdio_init_card(host, host->card->ocr, host->card,
> >> >                                 mmc_card_keep_power(host));
> >> >         if (!ret && host->sdio_irqs)
> >> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> >> > index c119735..f2c2620 100644
> >> > --- a/include/linux/mmc/card.h
> >> > +++ b/include/linux/mmc/card.h
> >> > @@ -260,6 +260,11 @@ struct mmc_card {
> >> >  #define MMC_STATE_HIGHSPEED_200        (1<<8)          /* card is in HS200 mode */
> >> >  #define MMC_STATE_DOING_BKOPS  (1<<10)         /* card is doing BKOPS */
> >> >  #define MMC_STATE_SUSPENDED    (1<<11)         /* card is suspended */
> >> > +#define MMC_STATE_SPEED_MASK   (MMC_STATE_HIGHSPEED | \
> >> > +                                MMC_STATE_HIGHSPEED_DDR | \
> >> > +                                MMC_STATE_ULTRAHIGHSPEED | \
> >> > +                                MMC_STATE_HIGHSPEED_200)
> >> > +                                               /* Mask for default speed(DS) */
> >> >         unsigned int            quirks;         /* card quirks */
> >> >  #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR
> range
> >> */
> >> >  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
> >> > @@ -431,19 +436,39 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int
> data)
> >> >  #define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
> >> >  #define mmc_card_suspended(c)  ((c)->state & MMC_STATE_SUSPENDED)
> >> >
> >> > -#define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
> >> > +
> >> >  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
> >> > -#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
> >> > -#define mmc_card_set_hs200(c)  ((c)->state |= MMC_STATE_HIGHSPEED_200)
> >> >  #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
> >> > -#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
> >> > -#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
> >> >  #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
> >> > -#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
> >> >  #define mmc_card_set_doing_bkops(c)    ((c)->state |= MMC_STATE_DOING_BKOPS)
> >> >  #define mmc_card_clr_doing_bkops(c)    ((c)->state &= ~MMC_STATE_DOING_BKOPS)
> >> >  #define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
> >> >  #define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
> >> > +#define mmc_card_set_highspeed(c) \
> >> > +                       ((c)->state = \
> >> > +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> >> > +                        MMC_STATE_HIGHSPEED)
> >> > +#define mmc_card_set_ddr_mode(c) \
> >> > +                       ((c)->state = \
> >> > +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> >> > +                        MMC_STATE_HIGHSPEED_DDR)
> >> > +#define mmc_card_set_hs200(c) \
> >> > +                       ((c)->state = \
> >> > +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> >> > +                        MMC_STATE_HIGHSPEED_200)
> >> > +#define mmc_card_set_uhs(c) \
> >> > +                       ((c)->state = \
> >> > +                        ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> >> > +                        MMC_STATE_ULTRAHIGHSPEED)
> >> > +#define mmc_card_set_present(c) \
> >> > +                       ((c)->state = \
> >> > +                        ((c)->state & ~MMC_CARD_REMOVED) | \
> >> > +                        MMC_STATE_PRESENT)
> >> > +#define mmc_card_set_removed(c) \
> >> > +                       ((c)->state = \
> >> > +                        ((c)->state & ~MMC_STATE_PRESENT) | \
> >> > +                        MMC_CARD_REMOVED)
> >> > +#define mmc_card_set_ds(c)     ((c)->state &= ~MMC_STATE_SPEED_MASK)
> >>
> >> I have a feeling of that this "card->state" has become a container for
> >> a lot of mixed stuff. So your clean up is definitely justified.
> >>
> >> I have a suggestion for how we can improve simplicity, how about
> >> dividing the state into two variables instead:
> >>
> >> -> One part are actually used in the mmc core code to track a state
> >> and to make certain decisions during execution, like
> >> MMC_STATE_SUSPENDED, MMC_STATE_PRESENT, MMC_CARD_REMOVED.
> >>
> >> -> The other part is more to be considered as the current operational
> >> state, for example the bus speed mode. The information in this "state
> >> variable" will be re-negotiated as a part of mmc_sd|sdio_init_card and
> >> can therefore always be reset in the beginning of these functions.
> >>
> >> Does it make sense?
> > Thank you for suggestion. I also feel that.
> > Hmm, but when considering there is no case we access 'card->sate' directly,
> > splitting into two types of state doesn't seem to give much.
> 
> Actually, on a second thought, why are we even caching the bus speeds
> in the card state? The bus speeds are already reflected in the
> "ios->timing" struct, which moreover also is available through
> debugfs. Can we remove the bus speeds entirely from the card state
> instead?
You point out redundancy of existing state for speed mode.
Yes, I agree with you on that point. It could be replaced.
I will consider for next.

Thanks,
Seungwon Jeon


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

* RE: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0
  2013-11-05 13:28 ` [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0 Seungwon Jeon
@ 2013-11-07  7:38   ` Shen, Jackey
  2013-11-07 11:38     ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Shen, Jackey @ 2013-11-07  7:38 UTC (permalink / raw)
  To: Seungwon Jeon, 'Chris Ball', 'Ulf Hansson'; +Cc: linux-mmc

Hi Seungwon,

> -----Original Message-----
> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-owner@vger.kernel.org]
> On Behalf Of Seungwon Jeon
> Sent: Tuesday, November 05, 2013 9:28 PM
> To: 'Chris Ball'; 'Ulf Hansson'
> Cc: linux-mmc@vger.kernel.org
> Subject: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0
> 
> This patch adds HS400 mode support for eMMC5.0 device.
> HS400 mode is high speed DDDR interface timing from HS200.

DDDR should be DDR.

> 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: Seungwon Jeon <tgih.jun@samsung.com>
> ---
>  drivers/mmc/core/bus.c   |    3 +-
>  drivers/mmc/core/mmc.c   |  128 +++++++++++++++++++++++++++++++++++++++++++--
> -
>  include/linux/mmc/card.h |   10 +++-
>  include/linux/mmc/host.h |    6 ++
>  include/linux/mmc/mmc.h  |    8 +++-
>  5 files changed, 144 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index cdca8a7..fd4ba2b 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -351,10 +351,11 @@ int mmc_add_card(struct mmc_card *card)
>  			mmc_card_ddr_mode(card) ? "DDR " : "",
>  			type);
>  	} else {
> -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
> +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>  			mmc_hostname(card->host),
>  			mmc_card_uhs(card) ? "ultra high speed " :
>  			(mmc_card_highspeed(card) ? "high speed " : ""),
> +			mmc_card_hs400(card) ? "HS400 " : "",

I think the following line will be better:
			mmc_card_hs400(card) ? "HS400 " :

>  			(mmc_card_hs200(card) ? "HS200 " : ""),
>  			mmc_card_ddr_mode(card) ? "DDR " : "",
>  			uhs_bus_speed_mode, type, card->rca);
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 1668ea4..7c23b67 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -280,6 +280,18 @@ static void mmc_select_card_type(struct mmc_card *card)
>  		avail_type |= EXT_CSD_CARD_TYPE_SDR_1_2V;
>  	}
> 
> +	if (caps2 & MMC_CAP2_HS400_1_8V &&
> +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {

Only 1 byte for ext_csd.raw_card_type as per eMMC spec, so I suggest:
1. remove EXT_CSD_CARD_TYPE_MASK
2. card_type is initialized as:
   u8 card_type = card->ext_csd.raw_card_type;

> +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> +	}
> +
> +	if (caps2 & MMC_CAP2_HS400_1_2V &&
> +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {

See above comments.

> +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> +	}
> +
>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>  	card->ext_csd.card_type = card_type;
> @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8
> *ext_csd)
>  			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
>  		card->ext_csd.raw_pwr_cl_ddr_52_360 =
>  			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> +		card->ext_csd.raw_pwr_cl_ddr_200_360 =
> +			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
>  	}
> 
>  	if (card->ext_csd.rev >= 5) {
> @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card,
> unsigned bus_width)
>  		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
>  			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
>  		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> -			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> +		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> +
>  	if (err)
>  		err = -EINVAL;
> 
> @@ -780,7 +797,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
>  				card->ext_csd.raw_pwr_cl_52_360 :
>  				card->ext_csd.raw_pwr_cl_ddr_52_360;
>  		else if (host->ios.clock <= 200000000)
> -			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
> +			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> +				card->ext_csd.raw_pwr_cl_ddr_200_360 :
> +				card->ext_csd.raw_pwr_cl_200_360;
>  		break;
>  	default:
>  		pr_warning("%s: Voltage range not supported "
> @@ -808,7 +827,8 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> 
>  static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
>  {
> -	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> +	return card->mmc_avail_type &
> +		(EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_HS400);
>  }
> 
>  static int mmc_select_powerclass(struct mmc_card *card, u8 *ext_csd)
> @@ -858,7 +878,7 @@ static void mmc_set_bus_speed(struct mmc_card *card)
> 
>  	BUG_ON(!card);
> 
> -	if (mmc_card_hs200(card)) {
> +	if (mmc_card_hs200(card) || mmc_card_hs400(card)) {
>  		if (max_dtr > card->ext_csd.hs200_max_dtr)
>  			max_dtr = card->ext_csd.hs200_max_dtr;
>  	} else if (mmc_card_highspeed(card)) {
> @@ -967,6 +987,31 @@ static int mmc_select_hs(struct mmc_card *card)
>  }
> 
>  /*
> + * Revert to the high-speed mode from above speed
> + */
> +static int mmc_revert_to_hs(struct mmc_card *card)
> +{
> +	BUG_ON(!card);
> +
> +	/*
> +	 * CMD13, which is used to confirm the completion of timing
> +	 * change, will be issued at higher speed timing condtion
> +	 * rather than high-speed. If device has completed the change
> +	 * to high-speed mode, it may not be proper timing to issue
> +	 * command. Low speed supplies better timing margin than high
> +	 * speed. Accordingly clock rate & timging should be chagned
> +	 * ahead before actual switch.
> +	 */
> +	mmc_card_set_highspeed(card);
> +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> +	mmc_set_bus_speed(card);
> +
> +	return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> +			  card->ext_csd.generic_cmd6_time);
> +}
> +
> +/*
>   * Activate wide bus and DDR if supported.
>   */
>  static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
> @@ -1026,6 +1071,61 @@ static int mmc_select_hs_ddr(struct mmc_card *card, u8
> *ext_csd)
>  	return err;
>  }
> 
> +static int mmc_select_hs400(struct mmc_card *card, u8 *ext_csd)
> +{
> +	struct mmc_host *host;
> +	int err = 0, ddr;
> +
> +	BUG_ON(!card);
> +
> +	host = card->host;
> +
> +	ddr = mmc_snoop_ddr(card);
> +
> +	/*
> +	 * The bus width is set to only 8 DDR in HS400 mode
> +	 */
> +	if (!(ddr & EXT_CSD_CARD_TYPE_HS400 &&
> +	      card->host->ios.bus_width == MMC_BUS_WIDTH_8))
> +		return 0;
> +
> +	/*
> +	 * Before setting BUS_WIDTH for dual data rate operation,
> +	 * HS_TIMING must be set to High Speed(0x1)

This rule is defined by eMMC spec as we know.
Does eMMC card you're testing support to switch to HS400 timing directly?

> +	 */
> +	err = mmc_revert_to_hs(card);
> +	if (err) {
> +		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> +			mmc_hostname(card->host), err);
> +		return err;
> +	}
> +
> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			 EXT_CSD_BUS_WIDTH,
> +			 EXT_CSD_DDR_BUS_WIDTH_8,
> +			 card->ext_csd.generic_cmd6_time);
> +	if (err) {
> +		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> +			mmc_hostname(card->host), err);
> +		return err;
> +	}
> +
> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> +			 card->ext_csd.generic_cmd6_time);
> +	if (err) {
> +		pr_warn("%s: switch to hs400 failed, err:%d\n",
> +			 mmc_hostname(card->host), err);
> +		return err;
> +	}
> +
> +	mmc_card_set_hs400(card);
> +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS400);
> +	mmc_set_bus_speed(card);

There is no code in your patch set to do this work (set timing and bus width)
for MMC host controller. Is this controller Synopsys DesignWare MMC host controller?
As we know, DesignWare MMC host controller is used in Exynos 5420 (SMDK5420),
which supports eMMC 5.0 card.
Will you submit these patches later?

> +
> +	return 0;
> +}
> +
>  /*
>   * For device supporting HS200 mode, the following sequence
>   * should be done before executing the tuning process.
> @@ -1061,10 +1161,19 @@ static int mmc_select_hs200(struct mmc_card *card)
>  		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>  				 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
>  				 card->ext_csd.generic_cmd6_time);
> -		if (!err) {
> -			mmc_card_set_hs200(card);
> +		if (err)
> +			goto err;
> +
> +		mmc_card_set_hs200(card);
> +
> +		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> +			/*
> +			 * Timing should be adjusted to the HS400 target
> +			 * operation frequency for tuning process
> +			 */
> +			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> +		else
>  			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> -		}
>  	}
>  err:
>  	return err;
> @@ -1114,7 +1223,7 @@ bus_speed:
> 
>  /*
>   * Execute tuning sequence to seek the proper bus operating
> - * conditions for HS200, which sends CMD21 to the device.
> + * conditions for HS200 and HS400, which sends CMD21 to the device.
>   */
>  static int mmc_hs200_tuning(struct mmc_card *card)
>  {
> @@ -1353,6 +1462,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>  		err = mmc_hs200_tuning(card);
>  		if (err)
>  			goto err;
> +		err = mmc_select_hs400(card, ext_csd);
> +		if (err)
> +			goto err;
>  	} else if (mmc_card_highspeed(card)) {
>  		/* Select the desired bus width optionally */
>  		err = mmc_select_bus_width(card);
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index f2c2620..3d41869 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -111,6 +111,7 @@ struct mmc_ext_csd {
>  	u8			raw_pwr_cl_200_360;	/* 237 */
>  	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
>  	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
> +	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
>  	u8			raw_bkops_status;	/* 246 */
>  	u8			raw_sectors[4];		/* 212 - 4 bytes */
> 
> @@ -258,12 +259,14 @@ struct mmc_card {
>  #define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
>  #define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
>  #define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
> +#define MMC_STATE_HIGHSPEED_400	(1<<9)		/* card is in HS400 mode */
>  #define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
>  #define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
>  #define MMC_STATE_SPEED_MASK	(MMC_STATE_HIGHSPEED | \
>  				 MMC_STATE_HIGHSPEED_DDR | \
>  				 MMC_STATE_ULTRAHIGHSPEED | \
> -				 MMC_STATE_HIGHSPEED_200)
> +				 MMC_STATE_HIGHSPEED_200 | \
> +				 MMC_STATE_HIGHSPEED_400)
>  						/* Mask for default speed(DS) */
>  	unsigned int		quirks; 	/* card quirks */
>  #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside
> of the VS CCCR range */
> @@ -428,6 +431,7 @@ static inline void __maybe_unused remove_quirk(struct
> mmc_card *card, int data)
>  #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
>  #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
>  #define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
> +#define mmc_card_hs400(c)	((c)->state & MMC_STATE_HIGHSPEED_400)
>  #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
>  #define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
>  #define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
> @@ -456,6 +460,10 @@ static inline void __maybe_unused remove_quirk(struct
> mmc_card *card, int data)
>  			((c)->state = \
>  			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
>  			 MMC_STATE_HIGHSPEED_200)
> +#define mmc_card_set_hs400(c) \
> +			((c)->state = \
> +			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> +			 MMC_STATE_HIGHSPEED_400)
>  #define mmc_card_set_uhs(c) \
>  			((c)->state = \
>  			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 69d58b1..8e66f4d 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -59,6 +59,8 @@ struct mmc_ios {
>  #define MMC_TIMING_UHS_SDR104	6
>  #define MMC_TIMING_UHS_DDR50	7
>  #define MMC_TIMING_MMC_HS200	8
> +#define MMC_TIMING_MMC_HS400	9
> +#define MMC_TIMING_MMC_HS400_TUNING 10
> 
>  	unsigned char	signal_voltage;		/* signalling voltage (1.8V or
> 3.3V) */
> 
> @@ -276,6 +278,10 @@ struct mmc_host {
>  				 MMC_CAP2_PACKED_WR)
>  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
>  #define MMC_CAP2_SANITIZE	(1 << 15)		/* Support Sanitize */
> +#define MMC_CAP2_HS400_1_8V	(1 << 16)	/* Can support HS400 1.8V */
> +#define MMC_CAP2_HS400_1_2V	(1 << 17)	/* Can support HS400 1.2V */
> +#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
> +				 MMC_CAP2_HS400_1_2V)
> 
>  	mmc_pm_flag_t		pm_caps;	/* supported pm features */
> 
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 87df508..7d5c27d 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -325,6 +325,7 @@ struct _mmc_csd {
>  #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
>  #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
>  #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
> +#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
>  #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
>  #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
>  #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
> @@ -356,7 +357,7 @@ struct _mmc_csd {
> 
>  #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_MASK	0x3F	/* Mask out reserved bits */
> +#define EXT_CSD_CARD_TYPE_MASK	0xFF	/* Mask out reserved bits */
>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
>  					     /* DDR mode @1.8V or 3V I/O */
>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
> @@ -366,6 +367,10 @@ struct _mmc_csd {
>  #define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
>  #define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
>  						/* SDR mode @1.2V I/O */
> +#define EXT_CSD_CARD_TYPE_HS400_1_8V	(1<<6)	/* Card can run at 200MHz DDR,
> 1.8V */
> +#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
> @@ -376,6 +381,7 @@ struct _mmc_csd {
>  #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_SEC_ER_EN	BIT(0)
>  #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
> --
> 1.7.0.4
> 

In addition, for debug purpose for HS400, the following patch segment should be added in debugfs.c:

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 54829c0..e1f075c 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -138,6 +138,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_MMC_HS200:
 		str = "mmc high-speed SDR200";
 		break;
+	case MMC_TIMING_MMC_HS400:
+		str = "mmc high-speed DDR200";
+		break;
 	default:
 		str = "invalid";
 		break;

Besides, may I venture to ask that whether you test on specified hardware and pass test cases?

Thanks,
Jackey

> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



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

* RE: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0
  2013-11-07  7:38   ` Shen, Jackey
@ 2013-11-07 11:38     ` Seungwon Jeon
  2013-11-08  9:05       ` Jackey Shen
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2013-11-07 11:38 UTC (permalink / raw)
  To: 'Shen, Jackey', 'Chris Ball', 'Ulf Hansson'
  Cc: linux-mmc

Hi Jackey,

On Thur, November 07, 2013, Shen, Jackey wrote
> Hi Seungwon,
> 
> > -----Original Message-----
> > From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-owner@vger.kernel.org]
> > On Behalf Of Seungwon Jeon
> > Sent: Tuesday, November 05, 2013 9:28 PM
> > To: 'Chris Ball'; 'Ulf Hansson'
> > Cc: linux-mmc@vger.kernel.org
> > Subject: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0
> >
> > This patch adds HS400 mode support for eMMC5.0 device.
> > HS400 mode is high speed DDDR interface timing from HS200.
> 
> DDDR should be DDR.
Ok. Thanks.

> 
> > 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: Seungwon Jeon <tgih.jun@samsung.com>
> > ---
> >  drivers/mmc/core/bus.c   |    3 +-
> >  drivers/mmc/core/mmc.c   |  128 +++++++++++++++++++++++++++++++++++++++++++--
> > -
> >  include/linux/mmc/card.h |   10 +++-
> >  include/linux/mmc/host.h |    6 ++
> >  include/linux/mmc/mmc.h  |    8 +++-
> >  5 files changed, 144 insertions(+), 11 deletions(-)
> >
> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> > index cdca8a7..fd4ba2b 100644
> > --- a/drivers/mmc/core/bus.c
> > +++ b/drivers/mmc/core/bus.c
> > @@ -351,10 +351,11 @@ int mmc_add_card(struct mmc_card *card)
> >  			mmc_card_ddr_mode(card) ? "DDR " : "",
> >  			type);
> >  	} else {
> > -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
> > +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
> >  			mmc_hostname(card->host),
> >  			mmc_card_uhs(card) ? "ultra high speed " :
> >  			(mmc_card_highspeed(card) ? "high speed " : ""),
> > +			mmc_card_hs400(card) ? "HS400 " : "",
> 
> I think the following line will be better:
> 			mmc_card_hs400(card) ? "HS400 " :
Ok.

> 
> >  			(mmc_card_hs200(card) ? "HS200 " : ""),
> >  			mmc_card_ddr_mode(card) ? "DDR " : "",
> >  			uhs_bus_speed_mode, type, card->rca);
> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > index 1668ea4..7c23b67 100644
> > --- a/drivers/mmc/core/mmc.c
> > +++ b/drivers/mmc/core/mmc.c
> > @@ -280,6 +280,18 @@ static void mmc_select_card_type(struct mmc_card *card)
> >  		avail_type |= EXT_CSD_CARD_TYPE_SDR_1_2V;
> >  	}
> >
> > +	if (caps2 & MMC_CAP2_HS400_1_8V &&
> > +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> 
> Only 1 byte for ext_csd.raw_card_type as per eMMC spec, so I suggest:
> 1. remove EXT_CSD_CARD_TYPE_MASK
> 2. card_type is initialized as:
>    u8 card_type = card->ext_csd.raw_card_type;
Yes. It seems no more need.

> 
> > +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> > +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> > +	}
> > +
> > +	if (caps2 & MMC_CAP2_HS400_1_2V &&
> > +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> 
> See above comments.
> 
> > +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> > +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> > +	}
> > +
> >  	card->ext_csd.hs_max_dtr = hs_max_dtr;
> >  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
> >  	card->ext_csd.card_type = card_type;
> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8
> > *ext_csd)
> >  			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
> >  		card->ext_csd.raw_pwr_cl_ddr_52_360 =
> >  			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> > +		card->ext_csd.raw_pwr_cl_ddr_200_360 =
> > +			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
> >  	}
> >
> >  	if (card->ext_csd.rev >= 5) {
> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card,
> > unsigned bus_width)
> >  		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
> >  			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
> >  		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> > -			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> > +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> > +		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> > +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> > +
> >  	if (err)
> >  		err = -EINVAL;
> >
> > @@ -780,7 +797,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> >  				card->ext_csd.raw_pwr_cl_52_360 :
> >  				card->ext_csd.raw_pwr_cl_ddr_52_360;
> >  		else if (host->ios.clock <= 200000000)
> > -			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
> > +			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> > +				card->ext_csd.raw_pwr_cl_ddr_200_360 :
> > +				card->ext_csd.raw_pwr_cl_200_360;
> >  		break;
> >  	default:
> >  		pr_warning("%s: Voltage range not supported "
> > @@ -808,7 +827,8 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> >
> >  static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> >  {
> > -	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> > +	return card->mmc_avail_type &
> > +		(EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_HS400);
> >  }
> >
> >  static int mmc_select_powerclass(struct mmc_card *card, u8 *ext_csd)
> > @@ -858,7 +878,7 @@ static void mmc_set_bus_speed(struct mmc_card *card)
> >
> >  	BUG_ON(!card);
> >
> > -	if (mmc_card_hs200(card)) {
> > +	if (mmc_card_hs200(card) || mmc_card_hs400(card)) {
> >  		if (max_dtr > card->ext_csd.hs200_max_dtr)
> >  			max_dtr = card->ext_csd.hs200_max_dtr;
> >  	} else if (mmc_card_highspeed(card)) {
> > @@ -967,6 +987,31 @@ static int mmc_select_hs(struct mmc_card *card)
> >  }
> >
> >  /*
> > + * Revert to the high-speed mode from above speed
> > + */
> > +static int mmc_revert_to_hs(struct mmc_card *card)
> > +{
> > +	BUG_ON(!card);
> > +
> > +	/*
> > +	 * CMD13, which is used to confirm the completion of timing
> > +	 * change, will be issued at higher speed timing condtion
> > +	 * rather than high-speed. If device has completed the change
> > +	 * to high-speed mode, it may not be proper timing to issue
> > +	 * command. Low speed supplies better timing margin than high
> > +	 * speed. Accordingly clock rate & timging should be chagned
> > +	 * ahead before actual switch.
> > +	 */
> > +	mmc_card_set_highspeed(card);
> > +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> > +	mmc_set_bus_speed(card);
> > +
> > +	return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +			  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> > +			  card->ext_csd.generic_cmd6_time);
> > +}
> > +
> > +/*
> >   * Activate wide bus and DDR if supported.
> >   */
> >  static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
> > @@ -1026,6 +1071,61 @@ static int mmc_select_hs_ddr(struct mmc_card *card, u8
> > *ext_csd)
> >  	return err;
> >  }
> >
> > +static int mmc_select_hs400(struct mmc_card *card, u8 *ext_csd)
> > +{
> > +	struct mmc_host *host;
> > +	int err = 0, ddr;
> > +
> > +	BUG_ON(!card);
> > +
> > +	host = card->host;
> > +
> > +	ddr = mmc_snoop_ddr(card);
> > +
> > +	/*
> > +	 * The bus width is set to only 8 DDR in HS400 mode
> > +	 */
> > +	if (!(ddr & EXT_CSD_CARD_TYPE_HS400 &&
> > +	      card->host->ios.bus_width == MMC_BUS_WIDTH_8))
> > +		return 0;
> > +
> > +	/*
> > +	 * Before setting BUS_WIDTH for dual data rate operation,
> > +	 * HS_TIMING must be set to High Speed(0x1)
> 
> This rule is defined by eMMC spec as we know.
> Does eMMC card you're testing support to switch to HS400 timing directly?
If you mean switch to HS400 from power-on, it doesn't support.

> 
> > +	 */
> > +	err = mmc_revert_to_hs(card);
> > +	if (err) {
> > +		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> > +			mmc_hostname(card->host), err);
> > +		return err;
> > +	}
> > +
> > +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +			 EXT_CSD_BUS_WIDTH,
> > +			 EXT_CSD_DDR_BUS_WIDTH_8,
> > +			 card->ext_csd.generic_cmd6_time);
> > +	if (err) {
> > +		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> > +			mmc_hostname(card->host), err);
> > +		return err;
> > +	}
> > +
> > +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> > +			 card->ext_csd.generic_cmd6_time);
> > +	if (err) {
> > +		pr_warn("%s: switch to hs400 failed, err:%d\n",
> > +			 mmc_hostname(card->host), err);
> > +		return err;
> > +	}
> > +
> > +	mmc_card_set_hs400(card);
> > +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS400);
> > +	mmc_set_bus_speed(card);
> 
> There is no code in your patch set to do this work (set timing and bus width)
> for MMC host controller. Is this controller Synopsys DesignWare MMC host controller?
> As we know, DesignWare MMC host controller is used in Exynos 5420 (SMDK5420),
> which supports eMMC 5.0 card.
> Will you submit these patches later?
Sure, I could send before not long before.
I already have completed to test.

> 
> > +
> > +	return 0;
> > +}
> > +
> >  /*
> >   * For device supporting HS200 mode, the following sequence
> >   * should be done before executing the tuning process.
> > @@ -1061,10 +1161,19 @@ static int mmc_select_hs200(struct mmc_card *card)
> >  		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >  				 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> >  				 card->ext_csd.generic_cmd6_time);
> > -		if (!err) {
> > -			mmc_card_set_hs200(card);
> > +		if (err)
> > +			goto err;
> > +
> > +		mmc_card_set_hs200(card);
> > +
> > +		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> > +			/*
> > +			 * Timing should be adjusted to the HS400 target
> > +			 * operation frequency for tuning process
> > +			 */
> > +			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> > +		else
> >  			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> > -		}
> >  	}
> >  err:
> >  	return err;
> > @@ -1114,7 +1223,7 @@ bus_speed:
> >
> >  /*
> >   * Execute tuning sequence to seek the proper bus operating
> > - * conditions for HS200, which sends CMD21 to the device.
> > + * conditions for HS200 and HS400, which sends CMD21 to the device.
> >   */
> >  static int mmc_hs200_tuning(struct mmc_card *card)
> >  {
> > @@ -1353,6 +1462,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >  		err = mmc_hs200_tuning(card);
> >  		if (err)
> >  			goto err;
> > +		err = mmc_select_hs400(card, ext_csd);
> > +		if (err)
> > +			goto err;
> >  	} else if (mmc_card_highspeed(card)) {
> >  		/* Select the desired bus width optionally */
> >  		err = mmc_select_bus_width(card);
> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > index f2c2620..3d41869 100644
> > --- a/include/linux/mmc/card.h
> > +++ b/include/linux/mmc/card.h
> > @@ -111,6 +111,7 @@ struct mmc_ext_csd {
> >  	u8			raw_pwr_cl_200_360;	/* 237 */
> >  	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
> >  	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
> > +	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
> >  	u8			raw_bkops_status;	/* 246 */
> >  	u8			raw_sectors[4];		/* 212 - 4 bytes */
> >
> > @@ -258,12 +259,14 @@ struct mmc_card {
> >  #define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
> >  #define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
> >  #define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
> > +#define MMC_STATE_HIGHSPEED_400	(1<<9)		/* card is in HS400 mode */
> >  #define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
> >  #define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
> >  #define MMC_STATE_SPEED_MASK	(MMC_STATE_HIGHSPEED | \
> >  				 MMC_STATE_HIGHSPEED_DDR | \
> >  				 MMC_STATE_ULTRAHIGHSPEED | \
> > -				 MMC_STATE_HIGHSPEED_200)
> > +				 MMC_STATE_HIGHSPEED_200 | \
> > +				 MMC_STATE_HIGHSPEED_400)
> >  						/* Mask for default speed(DS) */
> >  	unsigned int		quirks; 	/* card quirks */
> >  #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside
> > of the VS CCCR range */
> > @@ -428,6 +431,7 @@ static inline void __maybe_unused remove_quirk(struct
> > mmc_card *card, int data)
> >  #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
> >  #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
> >  #define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
> > +#define mmc_card_hs400(c)	((c)->state & MMC_STATE_HIGHSPEED_400)
> >  #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
> >  #define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
> >  #define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
> > @@ -456,6 +460,10 @@ static inline void __maybe_unused remove_quirk(struct
> > mmc_card *card, int data)
> >  			((c)->state = \
> >  			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> >  			 MMC_STATE_HIGHSPEED_200)
> > +#define mmc_card_set_hs400(c) \
> > +			((c)->state = \
> > +			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> > +			 MMC_STATE_HIGHSPEED_400)
> >  #define mmc_card_set_uhs(c) \
> >  			((c)->state = \
> >  			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > index 69d58b1..8e66f4d 100644
> > --- a/include/linux/mmc/host.h
> > +++ b/include/linux/mmc/host.h
> > @@ -59,6 +59,8 @@ struct mmc_ios {
> >  #define MMC_TIMING_UHS_SDR104	6
> >  #define MMC_TIMING_UHS_DDR50	7
> >  #define MMC_TIMING_MMC_HS200	8
> > +#define MMC_TIMING_MMC_HS400	9
> > +#define MMC_TIMING_MMC_HS400_TUNING 10
> >
> >  	unsigned char	signal_voltage;		/* signalling voltage (1.8V or
> > 3.3V) */
> >
> > @@ -276,6 +278,10 @@ struct mmc_host {
> >  				 MMC_CAP2_PACKED_WR)
> >  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
> >  #define MMC_CAP2_SANITIZE	(1 << 15)		/* Support Sanitize */
> > +#define MMC_CAP2_HS400_1_8V	(1 << 16)	/* Can support HS400 1.8V */
> > +#define MMC_CAP2_HS400_1_2V	(1 << 17)	/* Can support HS400 1.2V */
> > +#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
> > +				 MMC_CAP2_HS400_1_2V)
> >
> >  	mmc_pm_flag_t		pm_caps;	/* supported pm features */
> >
> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> > index 87df508..7d5c27d 100644
> > --- a/include/linux/mmc/mmc.h
> > +++ b/include/linux/mmc/mmc.h
> > @@ -325,6 +325,7 @@ struct _mmc_csd {
> >  #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
> >  #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
> >  #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
> > +#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
> >  #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
> >  #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
> >  #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
> > @@ -356,7 +357,7 @@ struct _mmc_csd {
> >
> >  #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_MASK	0x3F	/* Mask out reserved bits */
> > +#define EXT_CSD_CARD_TYPE_MASK	0xFF	/* Mask out reserved bits */
> >  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
> >  					     /* DDR mode @1.8V or 3V I/O */
> >  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
> > @@ -366,6 +367,10 @@ struct _mmc_csd {
> >  #define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
> >  #define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
> >  						/* SDR mode @1.2V I/O */
> > +#define EXT_CSD_CARD_TYPE_HS400_1_8V	(1<<6)	/* Card can run at 200MHz DDR,
> > 1.8V */
> > +#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
> >  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
> > @@ -376,6 +381,7 @@ struct _mmc_csd {
> >  #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_SEC_ER_EN	BIT(0)
> >  #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
> > --
> > 1.7.0.4
> >
> 
> In addition, for debug purpose for HS400, the following patch segment should be added in debugfs.c:
> 
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index 54829c0..e1f075c 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -138,6 +138,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>  	case MMC_TIMING_MMC_HS200:
>  		str = "mmc high-speed SDR200";
>  		break;
> +	case MMC_TIMING_MMC_HS400:
> +		str = "mmc high-speed DDR200";
> +		break;
>  	default:
>  		str = "invalid";
>  		break;
Ok. I'll add.

> 
> Besides, may I venture to ask that whether you test on specified hardware and pass test cases?
As you asked above, I tested it with exynos5420.

Thanks,
Seungwon Jeon


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

* Re: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0
  2013-11-07 11:38     ` Seungwon Jeon
@ 2013-11-08  9:05       ` Jackey Shen
  2013-11-11 12:51         ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Jackey Shen @ 2013-11-08  9:05 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: 'Chris Ball', 'Ulf Hansson', linux-mmc

Hi Seungwon,

Another a little suggestion:
It would be better that "hs400" in comments is updated to "HS400",
since the symbol is a special one.

Does you test this feature on eMMC 5.0 card from
http://www.samsung.com/global/business/semiconductor/product/flash-emmc/overview?

Thanks,
Jackey

On Thu, Nov 07, 2013 at 08:38:33PM +0900, Seungwon Jeon wrote:
> Hi Jackey,
> 
> On Thur, November 07, 2013, Shen, Jackey wrote
> > Hi Seungwon,
> > 
> > > -----Original Message-----
> > > From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-owner@vger.kernel.org]
> > > On Behalf Of Seungwon Jeon
> > > Sent: Tuesday, November 05, 2013 9:28 PM
> > > To: 'Chris Ball'; 'Ulf Hansson'
> > > Cc: linux-mmc@vger.kernel.org
> > > Subject: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0
> > >
> > > This patch adds HS400 mode support for eMMC5.0 device.
> > > HS400 mode is high speed DDDR interface timing from HS200.
> > 
> > DDDR should be DDR.
> Ok. Thanks.
> 
> > 
> > > 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: Seungwon Jeon <tgih.jun@samsung.com>
> > > ---
> > >  drivers/mmc/core/bus.c   |    3 +-
> > >  drivers/mmc/core/mmc.c   |  128 +++++++++++++++++++++++++++++++++++++++++++--
> > > -
> > >  include/linux/mmc/card.h |   10 +++-
> > >  include/linux/mmc/host.h |    6 ++
> > >  include/linux/mmc/mmc.h  |    8 +++-
> > >  5 files changed, 144 insertions(+), 11 deletions(-)
> > >
> > > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> > > index cdca8a7..fd4ba2b 100644
> > > --- a/drivers/mmc/core/bus.c
> > > +++ b/drivers/mmc/core/bus.c
> > > @@ -351,10 +351,11 @@ int mmc_add_card(struct mmc_card *card)
> > >  			mmc_card_ddr_mode(card) ? "DDR " : "",
> > >  			type);
> > >  	} else {
> > > -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
> > > +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
> > >  			mmc_hostname(card->host),
> > >  			mmc_card_uhs(card) ? "ultra high speed " :
> > >  			(mmc_card_highspeed(card) ? "high speed " : ""),
> > > +			mmc_card_hs400(card) ? "HS400 " : "",
> > 
> > I think the following line will be better:
> > 			mmc_card_hs400(card) ? "HS400 " :
> Ok.
> 
> > 
> > >  			(mmc_card_hs200(card) ? "HS200 " : ""),
> > >  			mmc_card_ddr_mode(card) ? "DDR " : "",
> > >  			uhs_bus_speed_mode, type, card->rca);
> > > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > > index 1668ea4..7c23b67 100644
> > > --- a/drivers/mmc/core/mmc.c
> > > +++ b/drivers/mmc/core/mmc.c
> > > @@ -280,6 +280,18 @@ static void mmc_select_card_type(struct mmc_card *card)
> > >  		avail_type |= EXT_CSD_CARD_TYPE_SDR_1_2V;
> > >  	}
> > >
> > > +	if (caps2 & MMC_CAP2_HS400_1_8V &&
> > > +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> > 
> > Only 1 byte for ext_csd.raw_card_type as per eMMC spec, so I suggest:
> > 1. remove EXT_CSD_CARD_TYPE_MASK
> > 2. card_type is initialized as:
> >    u8 card_type = card->ext_csd.raw_card_type;
> Yes. It seems no more need.
> 
> > 
> > > +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> > > +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> > > +	}
> > > +
> > > +	if (caps2 & MMC_CAP2_HS400_1_2V &&
> > > +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> > 
> > See above comments.
> > 
> > > +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> > > +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> > > +	}
> > > +
> > >  	card->ext_csd.hs_max_dtr = hs_max_dtr;
> > >  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
> > >  	card->ext_csd.card_type = card_type;
> > > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8
> > > *ext_csd)
> > >  			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
> > >  		card->ext_csd.raw_pwr_cl_ddr_52_360 =
> > >  			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> > > +		card->ext_csd.raw_pwr_cl_ddr_200_360 =
> > > +			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
> > >  	}
> > >
> > >  	if (card->ext_csd.rev >= 5) {
> > > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card,
> > > unsigned bus_width)
> > >  		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
> > >  			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
> > >  		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> > > -			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> > > +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> > > +		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> > > +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> > > +
> > >  	if (err)
> > >  		err = -EINVAL;
> > >
> > > @@ -780,7 +797,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> > >  				card->ext_csd.raw_pwr_cl_52_360 :
> > >  				card->ext_csd.raw_pwr_cl_ddr_52_360;
> > >  		else if (host->ios.clock <= 200000000)
> > > -			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
> > > +			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> > > +				card->ext_csd.raw_pwr_cl_ddr_200_360 :
> > > +				card->ext_csd.raw_pwr_cl_200_360;
> > >  		break;
> > >  	default:
> > >  		pr_warning("%s: Voltage range not supported "
> > > @@ -808,7 +827,8 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> > >
> > >  static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> > >  {
> > > -	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> > > +	return card->mmc_avail_type &
> > > +		(EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_HS400);
> > >  }
> > >
> > >  static int mmc_select_powerclass(struct mmc_card *card, u8 *ext_csd)
> > > @@ -858,7 +878,7 @@ static void mmc_set_bus_speed(struct mmc_card *card)
> > >
> > >  	BUG_ON(!card);
> > >
> > > -	if (mmc_card_hs200(card)) {
> > > +	if (mmc_card_hs200(card) || mmc_card_hs400(card)) {
> > >  		if (max_dtr > card->ext_csd.hs200_max_dtr)
> > >  			max_dtr = card->ext_csd.hs200_max_dtr;
> > >  	} else if (mmc_card_highspeed(card)) {
> > > @@ -967,6 +987,31 @@ static int mmc_select_hs(struct mmc_card *card)
> > >  }
> > >
> > >  /*
> > > + * Revert to the high-speed mode from above speed
> > > + */
> > > +static int mmc_revert_to_hs(struct mmc_card *card)
> > > +{
> > > +	BUG_ON(!card);
> > > +
> > > +	/*
> > > +	 * CMD13, which is used to confirm the completion of timing
> > > +	 * change, will be issued at higher speed timing condtion
> > > +	 * rather than high-speed. If device has completed the change
> > > +	 * to high-speed mode, it may not be proper timing to issue
> > > +	 * command. Low speed supplies better timing margin than high
> > > +	 * speed. Accordingly clock rate & timging should be chagned
> > > +	 * ahead before actual switch.
> > > +	 */
> > > +	mmc_card_set_highspeed(card);
> > > +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> > > +	mmc_set_bus_speed(card);
> > > +
> > > +	return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > > +			  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> > > +			  card->ext_csd.generic_cmd6_time);
> > > +}
> > > +
> > > +/*
> > >   * Activate wide bus and DDR if supported.
> > >   */
> > >  static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
> > > @@ -1026,6 +1071,61 @@ static int mmc_select_hs_ddr(struct mmc_card *card, u8
> > > *ext_csd)
> > >  	return err;
> > >  }
> > >
> > > +static int mmc_select_hs400(struct mmc_card *card, u8 *ext_csd)
> > > +{
> > > +	struct mmc_host *host;
> > > +	int err = 0, ddr;
> > > +
> > > +	BUG_ON(!card);
> > > +
> > > +	host = card->host;
> > > +
> > > +	ddr = mmc_snoop_ddr(card);
> > > +
> > > +	/*
> > > +	 * The bus width is set to only 8 DDR in HS400 mode
> > > +	 */
> > > +	if (!(ddr & EXT_CSD_CARD_TYPE_HS400 &&
> > > +	      card->host->ios.bus_width == MMC_BUS_WIDTH_8))
> > > +		return 0;
> > > +
> > > +	/*
> > > +	 * Before setting BUS_WIDTH for dual data rate operation,
> > > +	 * HS_TIMING must be set to High Speed(0x1)
> > 
> > This rule is defined by eMMC spec as we know.
> > Does eMMC card you're testing support to switch to HS400 timing directly?
> If you mean switch to HS400 from power-on, it doesn't support.
> 
> > 
> > > +	 */
> > > +	err = mmc_revert_to_hs(card);
> > > +	if (err) {
> > > +		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> > > +			mmc_hostname(card->host), err);
> > > +		return err;
> > > +	}
> > > +
> > > +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > > +			 EXT_CSD_BUS_WIDTH,
> > > +			 EXT_CSD_DDR_BUS_WIDTH_8,
> > > +			 card->ext_csd.generic_cmd6_time);
> > > +	if (err) {
> > > +		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> > > +			mmc_hostname(card->host), err);
> > > +		return err;
> > > +	}
> > > +
> > > +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > > +			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> > > +			 card->ext_csd.generic_cmd6_time);
> > > +	if (err) {
> > > +		pr_warn("%s: switch to hs400 failed, err:%d\n",
> > > +			 mmc_hostname(card->host), err);
> > > +		return err;
> > > +	}
> > > +
> > > +	mmc_card_set_hs400(card);
> > > +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS400);
> > > +	mmc_set_bus_speed(card);
> > 
> > There is no code in your patch set to do this work (set timing and bus width)
> > for MMC host controller. Is this controller Synopsys DesignWare MMC host controller?
> > As we know, DesignWare MMC host controller is used in Exynos 5420 (SMDK5420),
> > which supports eMMC 5.0 card.
> > Will you submit these patches later?
> Sure, I could send before not long before.
> I already have completed to test.
> 
> > 
> > > +
> > > +	return 0;
> > > +}
> > > +
> > >  /*
> > >   * For device supporting HS200 mode, the following sequence
> > >   * should be done before executing the tuning process.
> > > @@ -1061,10 +1161,19 @@ static int mmc_select_hs200(struct mmc_card *card)
> > >  		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > >  				 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> > >  				 card->ext_csd.generic_cmd6_time);
> > > -		if (!err) {
> > > -			mmc_card_set_hs200(card);
> > > +		if (err)
> > > +			goto err;
> > > +
> > > +		mmc_card_set_hs200(card);
> > > +
> > > +		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> > > +			/*
> > > +			 * Timing should be adjusted to the HS400 target
> > > +			 * operation frequency for tuning process
> > > +			 */
> > > +			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> > > +		else
> > >  			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> > > -		}
> > >  	}
> > >  err:
> > >  	return err;
> > > @@ -1114,7 +1223,7 @@ bus_speed:
> > >
> > >  /*
> > >   * Execute tuning sequence to seek the proper bus operating
> > > - * conditions for HS200, which sends CMD21 to the device.
> > > + * conditions for HS200 and HS400, which sends CMD21 to the device.
> > >   */
> > >  static int mmc_hs200_tuning(struct mmc_card *card)
> > >  {
> > > @@ -1353,6 +1462,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> > >  		err = mmc_hs200_tuning(card);
> > >  		if (err)
> > >  			goto err;
> > > +		err = mmc_select_hs400(card, ext_csd);
> > > +		if (err)
> > > +			goto err;
> > >  	} else if (mmc_card_highspeed(card)) {
> > >  		/* Select the desired bus width optionally */
> > >  		err = mmc_select_bus_width(card);
> > > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > > index f2c2620..3d41869 100644
> > > --- a/include/linux/mmc/card.h
> > > +++ b/include/linux/mmc/card.h
> > > @@ -111,6 +111,7 @@ struct mmc_ext_csd {
> > >  	u8			raw_pwr_cl_200_360;	/* 237 */
> > >  	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
> > >  	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
> > > +	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
> > >  	u8			raw_bkops_status;	/* 246 */
> > >  	u8			raw_sectors[4];		/* 212 - 4 bytes */
> > >
> > > @@ -258,12 +259,14 @@ struct mmc_card {
> > >  #define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
> > >  #define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
> > >  #define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
> > > +#define MMC_STATE_HIGHSPEED_400	(1<<9)		/* card is in HS400 mode */
> > >  #define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
> > >  #define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
> > >  #define MMC_STATE_SPEED_MASK	(MMC_STATE_HIGHSPEED | \
> > >  				 MMC_STATE_HIGHSPEED_DDR | \
> > >  				 MMC_STATE_ULTRAHIGHSPEED | \
> > > -				 MMC_STATE_HIGHSPEED_200)
> > > +				 MMC_STATE_HIGHSPEED_200 | \
> > > +				 MMC_STATE_HIGHSPEED_400)
> > >  						/* Mask for default speed(DS) */
> > >  	unsigned int		quirks; 	/* card quirks */
> > >  #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside
> > > of the VS CCCR range */
> > > @@ -428,6 +431,7 @@ static inline void __maybe_unused remove_quirk(struct
> > > mmc_card *card, int data)
> > >  #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
> > >  #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
> > >  #define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
> > > +#define mmc_card_hs400(c)	((c)->state & MMC_STATE_HIGHSPEED_400)
> > >  #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
> > >  #define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
> > >  #define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
> > > @@ -456,6 +460,10 @@ static inline void __maybe_unused remove_quirk(struct
> > > mmc_card *card, int data)
> > >  			((c)->state = \
> > >  			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> > >  			 MMC_STATE_HIGHSPEED_200)
> > > +#define mmc_card_set_hs400(c) \
> > > +			((c)->state = \
> > > +			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> > > +			 MMC_STATE_HIGHSPEED_400)
> > >  #define mmc_card_set_uhs(c) \
> > >  			((c)->state = \
> > >  			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> > > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > > index 69d58b1..8e66f4d 100644
> > > --- a/include/linux/mmc/host.h
> > > +++ b/include/linux/mmc/host.h
> > > @@ -59,6 +59,8 @@ struct mmc_ios {
> > >  #define MMC_TIMING_UHS_SDR104	6
> > >  #define MMC_TIMING_UHS_DDR50	7
> > >  #define MMC_TIMING_MMC_HS200	8
> > > +#define MMC_TIMING_MMC_HS400	9
> > > +#define MMC_TIMING_MMC_HS400_TUNING 10
> > >
> > >  	unsigned char	signal_voltage;		/* signalling voltage (1.8V or
> > > 3.3V) */
> > >
> > > @@ -276,6 +278,10 @@ struct mmc_host {
> > >  				 MMC_CAP2_PACKED_WR)
> > >  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
> > >  #define MMC_CAP2_SANITIZE	(1 << 15)		/* Support Sanitize */
> > > +#define MMC_CAP2_HS400_1_8V	(1 << 16)	/* Can support HS400 1.8V */
> > > +#define MMC_CAP2_HS400_1_2V	(1 << 17)	/* Can support HS400 1.2V */
> > > +#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
> > > +				 MMC_CAP2_HS400_1_2V)
> > >
> > >  	mmc_pm_flag_t		pm_caps;	/* supported pm features */
> > >
> > > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> > > index 87df508..7d5c27d 100644
> > > --- a/include/linux/mmc/mmc.h
> > > +++ b/include/linux/mmc/mmc.h
> > > @@ -325,6 +325,7 @@ struct _mmc_csd {
> > >  #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
> > >  #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
> > >  #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
> > > +#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
> > >  #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
> > >  #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
> > >  #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
> > > @@ -356,7 +357,7 @@ struct _mmc_csd {
> > >
> > >  #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_MASK	0x3F	/* Mask out reserved bits */
> > > +#define EXT_CSD_CARD_TYPE_MASK	0xFF	/* Mask out reserved bits */
> > >  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
> > >  					     /* DDR mode @1.8V or 3V I/O */
> > >  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
> > > @@ -366,6 +367,10 @@ struct _mmc_csd {
> > >  #define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
> > >  #define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
> > >  						/* SDR mode @1.2V I/O */
> > > +#define EXT_CSD_CARD_TYPE_HS400_1_8V	(1<<6)	/* Card can run at 200MHz DDR,
> > > 1.8V */
> > > +#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
> > >  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
> > > @@ -376,6 +381,7 @@ struct _mmc_csd {
> > >  #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_SEC_ER_EN	BIT(0)
> > >  #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
> > > --
> > > 1.7.0.4
> > >
> > 
> > In addition, for debug purpose for HS400, the following patch segment should be added in debugfs.c:
> > 
> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> > index 54829c0..e1f075c 100644
> > --- a/drivers/mmc/core/debugfs.c
> > +++ b/drivers/mmc/core/debugfs.c
> > @@ -138,6 +138,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
> >  	case MMC_TIMING_MMC_HS200:
> >  		str = "mmc high-speed SDR200";
> >  		break;
> > +	case MMC_TIMING_MMC_HS400:
> > +		str = "mmc high-speed DDR200";
> > +		break;
> >  	default:
> >  		str = "invalid";
> >  		break;
> Ok. I'll add.
> 
> > 
> > Besides, may I venture to ask that whether you test on specified hardware and pass test cases?
> As you asked above, I tested it with exynos5420.
> 
> Thanks,
> Seungwon Jeon
> 
> 


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

* Re: [PATCH 0/3] mmc: tmio: Use modern PM ops
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (7 preceding siblings ...)
  2013-11-05 13:28 ` [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0 Seungwon Jeon
@ 2013-11-08 12:16 ` Guennadi Liakhovetski
  2013-11-11  9:24   ` Ulf Hansson
  2014-01-15 14:10 ` [PATCH 0/7] mmc: distinguish DDR timing mode for eMMC/UHS Seungwon Jeon
                   ` (27 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Guennadi Liakhovetski @ 2013-11-08 12:16 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: linux-mmc, Chris Ball, Ian Molton

Hi Ulf,

A general question concerning this your effort just occurred to me: what 
if runtime PM is disabled on a system? Will the clock(s) then at all be 
enabled? Doesn't one need for such a case either a fall-back to statically 
enable clock in .probe() and disable in .remove() or should such drivers 
select PM_RUNTIME?

Thanks
Guennadi

On Tue, 5 Nov 2013, Ulf Hansson wrote:

> This patchset converts tmio and sh_mobile_sdhi to use the modern PM ops.
> 
> Ulf Hansson (3):
>   mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks
>   mmc: tmio_mmc: Convert from legacy to modern PM ops
>   mmc: tmio: Adapt to proper PM configs for exported functions
> 
>  drivers/mmc/host/sh_mobile_sdhi.c |    8 ++++----
>  drivers/mmc/host/tmio_mmc.c       |   32 ++++++++++++++++++--------------
>  drivers/mmc/host/tmio_mmc.h       |    7 +++----
>  drivers/mmc/host/tmio_mmc_pio.c   |    7 ++++---
>  4 files changed, 29 insertions(+), 25 deletions(-)
> 
> -- 
> 1.7.9.5
> 

---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

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

* Re: [PATCH 0/3] mmc: tmio: Use modern PM ops
  2013-11-08 12:16 ` [PATCH 0/3] mmc: tmio: Use modern PM ops Guennadi Liakhovetski
@ 2013-11-11  9:24   ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2013-11-11  9:24 UTC (permalink / raw)
  To: Guennadi Liakhovetski; +Cc: linux-mmc, Chris Ball, Ian Molton

On 8 November 2013 13:16, Guennadi Liakhovetski <g.liakhovetski@gmx.de> wrote:
> Hi Ulf,
>
> A general question concerning this your effort just occurred to me: what
> if runtime PM is disabled on a system? Will the clock(s) then at all be
> enabled? Doesn't one need for such a case either a fall-back to statically
> enable clock in .probe() and disable in .remove() or should such drivers
> select PM_RUNTIME?
>

That is a quite interesting question, I would suggest you post this
one on linux-pm. :-)

Normally I would expect it to be convenient to enable clocks in .probe
and then use pm_runtime_set_active. So that will then work for both
scenarios.

A bit more tricky is the .remove. To make it work in both scenarios
you can do pm_runtime_get_sync, a then explicitly disable the clocks.

If the driver would select PM_RUNTIME, the code could likely be
simplified. In best cases the .remove callback should not even need to
exist since PM core will do it's best to put the device into
"inactive" state.

Kind regards
Uffe

> Thanks
> Guennadi
>
> On Tue, 5 Nov 2013, Ulf Hansson wrote:
>
>> This patchset converts tmio and sh_mobile_sdhi to use the modern PM ops.
>>
>> Ulf Hansson (3):
>>   mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks
>>   mmc: tmio_mmc: Convert from legacy to modern PM ops
>>   mmc: tmio: Adapt to proper PM configs for exported functions
>>
>>  drivers/mmc/host/sh_mobile_sdhi.c |    8 ++++----
>>  drivers/mmc/host/tmio_mmc.c       |   32 ++++++++++++++++++--------------
>>  drivers/mmc/host/tmio_mmc.h       |    7 +++----
>>  drivers/mmc/host/tmio_mmc_pio.c   |    7 ++++---
>>  4 files changed, 29 insertions(+), 25 deletions(-)
>>
>> --
>> 1.7.9.5
>>
>
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer
> http://www.open-technology.de/

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

* RE: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0
  2013-11-08  9:05       ` Jackey Shen
@ 2013-11-11 12:51         ` Seungwon Jeon
  2013-11-25  7:32           ` Jackey Shen
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2013-11-11 12:51 UTC (permalink / raw)
  To: 'Jackey Shen'
  Cc: 'Chris Ball', 'Ulf Hansson', linux-mmc

On Fri, November 08, 2013, Jackey Shen wrote:
> Hi Seungwon,
> 
> Another a little suggestion:
> It would be better that "hs400" in comments is updated to "HS400",
> since the symbol is a special one.
OK.

> 
> Does you test this feature on eMMC 5.0 card from
> http://www.samsung.com/global/business/semiconductor/product/flash-emmc/overview?

No, it seems not found in list.

Can you test eMMC5.0 in your side?


Thanks,
Seungwon Jeon

> 
> Thanks,
> Jackey
> 
> On Thu, Nov 07, 2013 at 08:38:33PM +0900, Seungwon Jeon wrote:
> > Hi Jackey,
> >
> > On Thur, November 07, 2013, Shen, Jackey wrote
> > > Hi Seungwon,
> > >
> > > > -----Original Message-----
> > > > From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-owner@vger.kernel.org]
> > > > On Behalf Of Seungwon Jeon
> > > > Sent: Tuesday, November 05, 2013 9:28 PM
> > > > To: 'Chris Ball'; 'Ulf Hansson'
> > > > Cc: linux-mmc@vger.kernel.org
> > > > Subject: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0
> > > >
> > > > This patch adds HS400 mode support for eMMC5.0 device.
> > > > HS400 mode is high speed DDDR interface timing from HS200.
> > >
> > > DDDR should be DDR.
> > Ok. Thanks.
> >
> > >
> > > > 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: Seungwon Jeon <tgih.jun@samsung.com>
> > > > ---
> > > >  drivers/mmc/core/bus.c   |    3 +-
> > > >  drivers/mmc/core/mmc.c   |  128 +++++++++++++++++++++++++++++++++++++++++++--
> > > > -
> > > >  include/linux/mmc/card.h |   10 +++-
> > > >  include/linux/mmc/host.h |    6 ++
> > > >  include/linux/mmc/mmc.h  |    8 +++-
> > > >  5 files changed, 144 insertions(+), 11 deletions(-)
> > > >
> > > > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> > > > index cdca8a7..fd4ba2b 100644
> > > > --- a/drivers/mmc/core/bus.c
> > > > +++ b/drivers/mmc/core/bus.c
> > > > @@ -351,10 +351,11 @@ int mmc_add_card(struct mmc_card *card)
> > > >  			mmc_card_ddr_mode(card) ? "DDR " : "",
> > > >  			type);
> > > >  	} else {
> > > > -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
> > > > +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
> > > >  			mmc_hostname(card->host),
> > > >  			mmc_card_uhs(card) ? "ultra high speed " :
> > > >  			(mmc_card_highspeed(card) ? "high speed " : ""),
> > > > +			mmc_card_hs400(card) ? "HS400 " : "",
> > >
> > > I think the following line will be better:
> > > 			mmc_card_hs400(card) ? "HS400 " :
> > Ok.
> >
> > >
> > > >  			(mmc_card_hs200(card) ? "HS200 " : ""),
> > > >  			mmc_card_ddr_mode(card) ? "DDR " : "",
> > > >  			uhs_bus_speed_mode, type, card->rca);
> > > > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > > > index 1668ea4..7c23b67 100644
> > > > --- a/drivers/mmc/core/mmc.c
> > > > +++ b/drivers/mmc/core/mmc.c
> > > > @@ -280,6 +280,18 @@ static void mmc_select_card_type(struct mmc_card *card)
> > > >  		avail_type |= EXT_CSD_CARD_TYPE_SDR_1_2V;
> > > >  	}
> > > >
> > > > +	if (caps2 & MMC_CAP2_HS400_1_8V &&
> > > > +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> > >
> > > Only 1 byte for ext_csd.raw_card_type as per eMMC spec, so I suggest:
> > > 1. remove EXT_CSD_CARD_TYPE_MASK
> > > 2. card_type is initialized as:
> > >    u8 card_type = card->ext_csd.raw_card_type;
> > Yes. It seems no more need.
> >
> > >
> > > > +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> > > > +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> > > > +	}
> > > > +
> > > > +	if (caps2 & MMC_CAP2_HS400_1_2V &&
> > > > +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> > >
> > > See above comments.
> > >
> > > > +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> > > > +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> > > > +	}
> > > > +
> > > >  	card->ext_csd.hs_max_dtr = hs_max_dtr;
> > > >  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
> > > >  	card->ext_csd.card_type = card_type;
> > > > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8
> > > > *ext_csd)
> > > >  			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
> > > >  		card->ext_csd.raw_pwr_cl_ddr_52_360 =
> > > >  			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> > > > +		card->ext_csd.raw_pwr_cl_ddr_200_360 =
> > > > +			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
> > > >  	}
> > > >
> > > >  	if (card->ext_csd.rev >= 5) {
> > > > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card,
> > > > unsigned bus_width)
> > > >  		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
> > > >  			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
> > > >  		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> > > > -			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> > > > +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> > > > +		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> > > > +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> > > > +
> > > >  	if (err)
> > > >  		err = -EINVAL;
> > > >
> > > > @@ -780,7 +797,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> > > >  				card->ext_csd.raw_pwr_cl_52_360 :
> > > >  				card->ext_csd.raw_pwr_cl_ddr_52_360;
> > > >  		else if (host->ios.clock <= 200000000)
> > > > -			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
> > > > +			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> > > > +				card->ext_csd.raw_pwr_cl_ddr_200_360 :
> > > > +				card->ext_csd.raw_pwr_cl_200_360;
> > > >  		break;
> > > >  	default:
> > > >  		pr_warning("%s: Voltage range not supported "
> > > > @@ -808,7 +827,8 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> > > >
> > > >  static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> > > >  {
> > > > -	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> > > > +	return card->mmc_avail_type &
> > > > +		(EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_HS400);
> > > >  }
> > > >
> > > >  static int mmc_select_powerclass(struct mmc_card *card, u8 *ext_csd)
> > > > @@ -858,7 +878,7 @@ static void mmc_set_bus_speed(struct mmc_card *card)
> > > >
> > > >  	BUG_ON(!card);
> > > >
> > > > -	if (mmc_card_hs200(card)) {
> > > > +	if (mmc_card_hs200(card) || mmc_card_hs400(card)) {
> > > >  		if (max_dtr > card->ext_csd.hs200_max_dtr)
> > > >  			max_dtr = card->ext_csd.hs200_max_dtr;
> > > >  	} else if (mmc_card_highspeed(card)) {
> > > > @@ -967,6 +987,31 @@ static int mmc_select_hs(struct mmc_card *card)
> > > >  }
> > > >
> > > >  /*
> > > > + * Revert to the high-speed mode from above speed
> > > > + */
> > > > +static int mmc_revert_to_hs(struct mmc_card *card)
> > > > +{
> > > > +	BUG_ON(!card);
> > > > +
> > > > +	/*
> > > > +	 * CMD13, which is used to confirm the completion of timing
> > > > +	 * change, will be issued at higher speed timing condtion
> > > > +	 * rather than high-speed. If device has completed the change
> > > > +	 * to high-speed mode, it may not be proper timing to issue
> > > > +	 * command. Low speed supplies better timing margin than high
> > > > +	 * speed. Accordingly clock rate & timging should be chagned
> > > > +	 * ahead before actual switch.
> > > > +	 */
> > > > +	mmc_card_set_highspeed(card);
> > > > +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> > > > +	mmc_set_bus_speed(card);
> > > > +
> > > > +	return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > > > +			  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> > > > +			  card->ext_csd.generic_cmd6_time);
> > > > +}
> > > > +
> > > > +/*
> > > >   * Activate wide bus and DDR if supported.
> > > >   */
> > > >  static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
> > > > @@ -1026,6 +1071,61 @@ static int mmc_select_hs_ddr(struct mmc_card *card, u8
> > > > *ext_csd)
> > > >  	return err;
> > > >  }
> > > >
> > > > +static int mmc_select_hs400(struct mmc_card *card, u8 *ext_csd)
> > > > +{
> > > > +	struct mmc_host *host;
> > > > +	int err = 0, ddr;
> > > > +
> > > > +	BUG_ON(!card);
> > > > +
> > > > +	host = card->host;
> > > > +
> > > > +	ddr = mmc_snoop_ddr(card);
> > > > +
> > > > +	/*
> > > > +	 * The bus width is set to only 8 DDR in HS400 mode
> > > > +	 */
> > > > +	if (!(ddr & EXT_CSD_CARD_TYPE_HS400 &&
> > > > +	      card->host->ios.bus_width == MMC_BUS_WIDTH_8))
> > > > +		return 0;
> > > > +
> > > > +	/*
> > > > +	 * Before setting BUS_WIDTH for dual data rate operation,
> > > > +	 * HS_TIMING must be set to High Speed(0x1)
> > >
> > > This rule is defined by eMMC spec as we know.
> > > Does eMMC card you're testing support to switch to HS400 timing directly?
> > If you mean switch to HS400 from power-on, it doesn't support.
> >
> > >
> > > > +	 */
> > > > +	err = mmc_revert_to_hs(card);
> > > > +	if (err) {
> > > > +		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> > > > +			mmc_hostname(card->host), err);
> > > > +		return err;
> > > > +	}
> > > > +
> > > > +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > > > +			 EXT_CSD_BUS_WIDTH,
> > > > +			 EXT_CSD_DDR_BUS_WIDTH_8,
> > > > +			 card->ext_csd.generic_cmd6_time);
> > > > +	if (err) {
> > > > +		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> > > > +			mmc_hostname(card->host), err);
> > > > +		return err;
> > > > +	}
> > > > +
> > > > +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > > > +			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> > > > +			 card->ext_csd.generic_cmd6_time);
> > > > +	if (err) {
> > > > +		pr_warn("%s: switch to hs400 failed, err:%d\n",
> > > > +			 mmc_hostname(card->host), err);
> > > > +		return err;
> > > > +	}
> > > > +
> > > > +	mmc_card_set_hs400(card);
> > > > +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS400);
> > > > +	mmc_set_bus_speed(card);
> > >
> > > There is no code in your patch set to do this work (set timing and bus width)
> > > for MMC host controller. Is this controller Synopsys DesignWare MMC host controller?
> > > As we know, DesignWare MMC host controller is used in Exynos 5420 (SMDK5420),
> > > which supports eMMC 5.0 card.
> > > Will you submit these patches later?
> > Sure, I could send before not long before.
> > I already have completed to test.
> >
> > >
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > >  /*
> > > >   * For device supporting HS200 mode, the following sequence
> > > >   * should be done before executing the tuning process.
> > > > @@ -1061,10 +1161,19 @@ static int mmc_select_hs200(struct mmc_card *card)
> > > >  		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > > >  				 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> > > >  				 card->ext_csd.generic_cmd6_time);
> > > > -		if (!err) {
> > > > -			mmc_card_set_hs200(card);
> > > > +		if (err)
> > > > +			goto err;
> > > > +
> > > > +		mmc_card_set_hs200(card);
> > > > +
> > > > +		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> > > > +			/*
> > > > +			 * Timing should be adjusted to the HS400 target
> > > > +			 * operation frequency for tuning process
> > > > +			 */
> > > > +			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> > > > +		else
> > > >  			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> > > > -		}
> > > >  	}
> > > >  err:
> > > >  	return err;
> > > > @@ -1114,7 +1223,7 @@ bus_speed:
> > > >
> > > >  /*
> > > >   * Execute tuning sequence to seek the proper bus operating
> > > > - * conditions for HS200, which sends CMD21 to the device.
> > > > + * conditions for HS200 and HS400, which sends CMD21 to the device.
> > > >   */
> > > >  static int mmc_hs200_tuning(struct mmc_card *card)
> > > >  {
> > > > @@ -1353,6 +1462,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> > > >  		err = mmc_hs200_tuning(card);
> > > >  		if (err)
> > > >  			goto err;
> > > > +		err = mmc_select_hs400(card, ext_csd);
> > > > +		if (err)
> > > > +			goto err;
> > > >  	} else if (mmc_card_highspeed(card)) {
> > > >  		/* Select the desired bus width optionally */
> > > >  		err = mmc_select_bus_width(card);
> > > > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > > > index f2c2620..3d41869 100644
> > > > --- a/include/linux/mmc/card.h
> > > > +++ b/include/linux/mmc/card.h
> > > > @@ -111,6 +111,7 @@ struct mmc_ext_csd {
> > > >  	u8			raw_pwr_cl_200_360;	/* 237 */
> > > >  	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
> > > >  	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
> > > > +	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
> > > >  	u8			raw_bkops_status;	/* 246 */
> > > >  	u8			raw_sectors[4];		/* 212 - 4 bytes */
> > > >
> > > > @@ -258,12 +259,14 @@ struct mmc_card {
> > > >  #define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
> > > >  #define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
> > > >  #define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
> > > > +#define MMC_STATE_HIGHSPEED_400	(1<<9)		/* card is in HS400 mode */
> > > >  #define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
> > > >  #define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
> > > >  #define MMC_STATE_SPEED_MASK	(MMC_STATE_HIGHSPEED | \
> > > >  				 MMC_STATE_HIGHSPEED_DDR | \
> > > >  				 MMC_STATE_ULTRAHIGHSPEED | \
> > > > -				 MMC_STATE_HIGHSPEED_200)
> > > > +				 MMC_STATE_HIGHSPEED_200 | \
> > > > +				 MMC_STATE_HIGHSPEED_400)
> > > >  						/* Mask for default speed(DS) */
> > > >  	unsigned int		quirks; 	/* card quirks */
> > > >  #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside
> > > > of the VS CCCR range */
> > > > @@ -428,6 +431,7 @@ static inline void __maybe_unused remove_quirk(struct
> > > > mmc_card *card, int data)
> > > >  #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
> > > >  #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
> > > >  #define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
> > > > +#define mmc_card_hs400(c)	((c)->state & MMC_STATE_HIGHSPEED_400)
> > > >  #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
> > > >  #define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
> > > >  #define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
> > > > @@ -456,6 +460,10 @@ static inline void __maybe_unused remove_quirk(struct
> > > > mmc_card *card, int data)
> > > >  			((c)->state = \
> > > >  			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> > > >  			 MMC_STATE_HIGHSPEED_200)
> > > > +#define mmc_card_set_hs400(c) \
> > > > +			((c)->state = \
> > > > +			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> > > > +			 MMC_STATE_HIGHSPEED_400)
> > > >  #define mmc_card_set_uhs(c) \
> > > >  			((c)->state = \
> > > >  			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
> > > > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > > > index 69d58b1..8e66f4d 100644
> > > > --- a/include/linux/mmc/host.h
> > > > +++ b/include/linux/mmc/host.h
> > > > @@ -59,6 +59,8 @@ struct mmc_ios {
> > > >  #define MMC_TIMING_UHS_SDR104	6
> > > >  #define MMC_TIMING_UHS_DDR50	7
> > > >  #define MMC_TIMING_MMC_HS200	8
> > > > +#define MMC_TIMING_MMC_HS400	9
> > > > +#define MMC_TIMING_MMC_HS400_TUNING 10
> > > >
> > > >  	unsigned char	signal_voltage;		/* signalling voltage (1.8V or
> > > > 3.3V) */
> > > >
> > > > @@ -276,6 +278,10 @@ struct mmc_host {
> > > >  				 MMC_CAP2_PACKED_WR)
> > > >  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
> > > >  #define MMC_CAP2_SANITIZE	(1 << 15)		/* Support Sanitize */
> > > > +#define MMC_CAP2_HS400_1_8V	(1 << 16)	/* Can support HS400 1.8V */
> > > > +#define MMC_CAP2_HS400_1_2V	(1 << 17)	/* Can support HS400 1.2V */
> > > > +#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
> > > > +				 MMC_CAP2_HS400_1_2V)
> > > >
> > > >  	mmc_pm_flag_t		pm_caps;	/* supported pm features */
> > > >
> > > > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> > > > index 87df508..7d5c27d 100644
> > > > --- a/include/linux/mmc/mmc.h
> > > > +++ b/include/linux/mmc/mmc.h
> > > > @@ -325,6 +325,7 @@ struct _mmc_csd {
> > > >  #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
> > > >  #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
> > > >  #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
> > > > +#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
> > > >  #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
> > > >  #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
> > > >  #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
> > > > @@ -356,7 +357,7 @@ struct _mmc_csd {
> > > >
> > > >  #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_MASK	0x3F	/* Mask out reserved bits */
> > > > +#define EXT_CSD_CARD_TYPE_MASK	0xFF	/* Mask out reserved bits */
> > > >  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
> > > >  					     /* DDR mode @1.8V or 3V I/O */
> > > >  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
> > > > @@ -366,6 +367,10 @@ struct _mmc_csd {
> > > >  #define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
> > > >  #define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
> > > >  						/* SDR mode @1.2V I/O */
> > > > +#define EXT_CSD_CARD_TYPE_HS400_1_8V	(1<<6)	/* Card can run at 200MHz DDR,
> > > > 1.8V */
> > > > +#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
> > > >  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
> > > > @@ -376,6 +381,7 @@ struct _mmc_csd {
> > > >  #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_SEC_ER_EN	BIT(0)
> > > >  #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
> > > > --
> > > > 1.7.0.4
> > > >
> > >
> > > In addition, for debug purpose for HS400, the following patch segment should be added in debugfs.c:
> > >
> > > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> > > index 54829c0..e1f075c 100644
> > > --- a/drivers/mmc/core/debugfs.c
> > > +++ b/drivers/mmc/core/debugfs.c
> > > @@ -138,6 +138,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
> > >  	case MMC_TIMING_MMC_HS200:
> > >  		str = "mmc high-speed SDR200";
> > >  		break;
> > > +	case MMC_TIMING_MMC_HS400:
> > > +		str = "mmc high-speed DDR200";
> > > +		break;
> > >  	default:
> > >  		str = "invalid";
> > >  		break;
> > Ok. I'll add.
> >
> > >
> > > Besides, may I venture to ask that whether you test on specified hardware and pass test cases?
> > As you asked above, I tested it with exynos5420.
> >
> > Thanks,
> > Seungwon Jeon
> >
> >
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0
  2013-11-11 12:51         ` Seungwon Jeon
@ 2013-11-25  7:32           ` Jackey Shen
  0 siblings, 0 replies; 182+ messages in thread
From: Jackey Shen @ 2013-11-25  7:32 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: 'Chris Ball', 'Ulf Hansson', linux-mmc

On Mon, Nov 11, 2013 at 09:51:16PM +0900, Seungwon Jeon wrote:
> On Fri, November 08, 2013, Jackey Shen wrote:
> > Hi Seungwon,
> > 
> > Another a little suggestion:
> > It would be better that "hs400" in comments is updated to "HS400",
> > since the symbol is a special one.
> OK.
> 
> > 
> > Does you test this feature on eMMC 5.0 card from
> > http://www.samsung.com/global/business/semiconductor/product/flash-emmc/overview?
> 
> No, it seems not found in list.
> 
> Can you test eMMC5.0 in your side?
Hi Seungwon,

Could you please tell what eMMC 5.0 cards are used for test?
I have not such device at present. I will test the patch once I get one.

BTW, does your eMMC card support "Extended Partitions Attribute" and
"Write Protect management"?

Thanks,
Jackey


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

* [PATCH 0/7] mmc: distinguish DDR timing mode for eMMC/UHS
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (8 preceding siblings ...)
  2013-11-08 12:16 ` [PATCH 0/3] mmc: tmio: Use modern PM ops Guennadi Liakhovetski
@ 2014-01-15 14:10 ` Seungwon Jeon
  2014-01-15 14:10 ` [PATCH 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC Seungwon Jeon
                   ` (26 subsequent siblings)
  36 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:10 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson',
	rickard.andersson, linux, balajitk, g.liakhovetski, wei_wang,
	sameo, jh80.chung
  Cc: linux-mmc

These changes intend to distinguish two DDR timing modes related to eMMC & UHS.
Even though two modes are different actually, UHS_DDR50 is used as eMMC DDR mode.
MMC_TIMING_MMC_DDR52 mode is added.

Seungwon Jeon (7):
  mmc: clarify DDR timing mode between SD-UHS and eMMC
  mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
  mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
  mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
  mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
  mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
  mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC

 drivers/mmc/core/debugfs.c        |    3 +++
 drivers/mmc/core/mmc.c            |    2 +-
 drivers/mmc/host/dw_mmc-exynos.c  |    3 +--
 drivers/mmc/host/dw_mmc.c         |    2 +-
 drivers/mmc/host/mmci.c           |    4 ++--
 drivers/mmc/host/omap_hsmmc.c     |    4 ++--
 drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
 drivers/mmc/host/sdhci.c          |    4 +++-
 drivers/mmc/host/sh_mmcif.c       |    9 +++++----
 include/linux/mmc/host.h          |    3 ++-
 10 files changed, 22 insertions(+), 14 deletions(-)



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

* [PATCH 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (9 preceding siblings ...)
  2014-01-15 14:10 ` [PATCH 0/7] mmc: distinguish DDR timing mode for eMMC/UHS Seungwon Jeon
@ 2014-01-15 14:10 ` Seungwon Jeon
  2014-01-16 10:50   ` Ulf Hansson
  2014-01-15 14:11 ` [PATCH 2/7] mmc: mmci: " Seungwon Jeon
                   ` (25 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:10 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson'; +Cc: linux-mmc

This change distinguishes DDR timing mode of current
mixed usage to clarify device type.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/debugfs.c |    3 +++
 drivers/mmc/core/mmc.c     |    2 +-
 include/linux/mmc/host.h   |    3 ++-
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 54829c0..509229b 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_UHS_DDR50:
 		str = "sd uhs DDR50";
 		break;
+	case MMC_TIMING_MMC_DDR52:
+		str = "mmc DDR52";
+		break;
 	case MMC_TIMING_MMC_HS200:
 		str = "mmc high-speed SDR200";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 98e9eb0..6d91ff7 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1261,7 +1261,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 					goto err;
 			}
 			mmc_card_set_ddr_mode(card);
-			mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
+			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
 			mmc_set_bus_width(card->host, bus_width);
 		}
 	}
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 99f5709..87b1f4f 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -58,7 +58,8 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_SDR50	5
 #define MMC_TIMING_UHS_SDR104	6
 #define MMC_TIMING_UHS_DDR50	7
-#define MMC_TIMING_MMC_HS200	8
+#define MMC_TIMING_MMC_DDR52	8
+#define MMC_TIMING_MMC_HS200	9
 
 #define MMC_SDR_MODE		0
 #define MMC_1_2V_DDR_MODE	1
-- 
1.7.0.4



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

* [PATCH 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (10 preceding siblings ...)
  2014-01-15 14:10 ` [PATCH 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC Seungwon Jeon
@ 2014-01-15 14:11 ` Seungwon Jeon
  2014-01-16 10:20   ` Ulf Hansson
  2014-01-15 14:11 ` [PATCH 3/7] mmc: omap: " Seungwon Jeon
                   ` (24 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:11 UTC (permalink / raw)
  To: 'Chris Ball', 'Rickard Andersson',
	'Russell King'
  Cc: linux-mmc

Replaced UHS_DDR50 with MMC_DDR52.

CC: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/mmci.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index f320579..c348427 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -299,7 +299,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
 	if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
 		clk |= MCI_ST_8BIT_BUS;
 
-	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+	if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
 		clk |= MCI_ST_UX500_NEG_EDGE;
 
 	mmci_write_clkreg(host, clk);
@@ -784,7 +784,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 			mmci_write_clkreg(host, clk);
 		}
 
-	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+	if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
 		datactrl |= MCI_ST_DPSM_DDRMODE;
 
 	/*
-- 
1.7.0.4



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

* [PATCH 3/7] mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (11 preceding siblings ...)
  2014-01-15 14:11 ` [PATCH 2/7] mmc: mmci: " Seungwon Jeon
@ 2014-01-15 14:11 ` Seungwon Jeon
  2014-01-16 10:49   ` Ulf Hansson
  2014-01-16 11:01   ` Balaji T K
  2014-01-15 14:12 ` [PATCH 4/7] mmc: sh_mmcif: " Seungwon Jeon
                   ` (23 subsequent siblings)
  36 siblings, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:11 UTC (permalink / raw)
  To: 'Chris Ball', 'Balaji T K'; +Cc: linux-mmc

Replaced UHS_DDR50 with MMC_DDR52.

CC: Balaji T K <balajitk@ti.com>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/omap_hsmmc.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index dbd32ad..cca397e 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -540,7 +540,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
 	 *	- MMC/SD clock coming out of controller > 25MHz
 	 */
 	if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
-	    (ios->timing != MMC_TIMING_UHS_DDR50) &&
+	    (ios->timing != MMC_TIMING_MMC_DDR52) &&
 	    ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
 		regval = OMAP_HSMMC_READ(host->base, HCTL);
 		if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
@@ -560,7 +560,7 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
 	u32 con;
 
 	con = OMAP_HSMMC_READ(host->base, CON);
-	if (ios->timing == MMC_TIMING_UHS_DDR50)
+	if (ios->timing == MMC_TIMING_MMC_DDR52)
 		con |= DDR;	/* configure in DDR mode */
 	else
 		con &= ~DDR;
-- 
1.7.0.4



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

* [PATCH 4/7] mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (12 preceding siblings ...)
  2014-01-15 14:11 ` [PATCH 3/7] mmc: omap: " Seungwon Jeon
@ 2014-01-15 14:12 ` Seungwon Jeon
  2014-01-16 10:22   ` Ulf Hansson
  2014-01-15 14:12 ` [PATCH 5/7] mmc: rtsx: " Seungwon Jeon
                   ` (22 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:12 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson',
	'Guennadi Liakhovetski'
  Cc: linux-mmc

Replaced UHS_DDR50 with MMC_DDR52.

CC: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/sh_mmcif.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 54730f4..656fbba 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -803,12 +803,13 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
 			break;
 		}
 		switch (host->timing) {
-		case MMC_TIMING_UHS_DDR50:
+		case MMC_TIMING_MMC_DDR52:
 			/*
 			 * MMC core will only set this timing, if the host
-			 * advertises the MMC_CAP_UHS_DDR50 capability. MMCIF
-			 * implementations with this capability, e.g. sh73a0,
-			 * will have to set it in their platform data.
+			 * advertises the MMC_CAP_1_8V_DDR/MMC_CAP_1_2V_DDR
+			 * capability. MMCIF implementations with this
+			 * capability, e.g. sh73a0, will have to set it
+			 * in their platform data.
 			 */
 			tmp |= CMD_SET_DARS;
 			break;
-- 
1.7.0.4



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

* [PATCH 5/7] mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (13 preceding siblings ...)
  2014-01-15 14:12 ` [PATCH 4/7] mmc: sh_mmcif: " Seungwon Jeon
@ 2014-01-15 14:12 ` Seungwon Jeon
  2014-01-16 10:51   ` Ulf Hansson
  2014-01-15 14:12 ` [PATCH 6/7] mmc: dw_mmc: " Seungwon Jeon
                   ` (21 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:12 UTC (permalink / raw)
  To: 'Chris Ball', 'Wei WANG', 'Samuel Ortiz'
  Cc: linux-mmc

Added MMC_DDR52 as eMMC's DDR mode distinguished from SD-UHS.

CC: Wei WANG <wei_wang@realsil.com.cn>
CC: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index c46feda..752f003 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -864,6 +864,7 @@ static int sd_set_timing(struct realtek_pci_sdmmc *host, unsigned char timing)
 		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0);
 		break;
 
+	case MMC_TIMING_MMC_DDR52:
 	case MMC_TIMING_UHS_DDR50:
 		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1,
 				0x0C | SD_ASYNC_FIFO_NOT_RST,
@@ -944,6 +945,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		host->vpclk = true;
 		host->double_clk = false;
 		break;
+	case MMC_TIMING_MMC_DDR52:
 	case MMC_TIMING_UHS_DDR50:
 	case MMC_TIMING_UHS_SDR25:
 		host->ssc_depth = RTSX_SSC_DEPTH_1M;
-- 
1.7.0.4



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

* [PATCH 6/7] mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (14 preceding siblings ...)
  2014-01-15 14:12 ` [PATCH 5/7] mmc: rtsx: " Seungwon Jeon
@ 2014-01-15 14:12 ` Seungwon Jeon
  2014-01-16 10:37   ` Ulf Hansson
  2014-01-15 14:12 ` [PATCH 7/7] mmc: sdhci: " Seungwon Jeon
                   ` (20 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:12 UTC (permalink / raw)
  To: 'Chris Ball', 'Jaehoon Chung'; +Cc: linux-mmc

Replaced UHS_DDR50 with MMC_DDR52. And MMC_CAP_UHS_DDR50
is removed because of non-implementation of UHS signaling.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/dw_mmc-exynos.c |    3 +--
 drivers/mmc/host/dw_mmc.c        |    2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 3423c5e..b5a36b1 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -386,8 +386,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
 
 /* Common capabilities of Exynos4/Exynos5 SoC */
 static unsigned long exynos_dwmmc_caps[4] = {
-	MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
-		MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
+	MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
 	MMC_CAP_CMD23,
 	MMC_CAP_CMD23,
 	MMC_CAP_CMD23,
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index a776f24..99390bb 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -962,7 +962,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	regs = mci_readl(slot->host, UHS_REG);
 
 	/* DDR mode set */
-	if (ios->timing == MMC_TIMING_UHS_DDR50)
+	if (ios->timing == MMC_TIMING_MMC_DDR52)
 		regs |= ((0x1 << slot->id) << 16);
 	else
 		regs &= ~((0x1 << slot->id) << 16);
-- 
1.7.0.4



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

* [PATCH 7/7] mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (15 preceding siblings ...)
  2014-01-15 14:12 ` [PATCH 6/7] mmc: dw_mmc: " Seungwon Jeon
@ 2014-01-15 14:12 ` Seungwon Jeon
  2014-01-16 10:25   ` Ulf Hansson
  2014-01-15 14:13 ` [PATCH 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                   ` (19 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:12 UTC (permalink / raw)
  To: 'Chris Ball'; +Cc: linux-mmc

Added MMC_DDR52 as eMMC's DDR mode distinguished from SD-UHS.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/sdhci.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ec3eb30..6c3482a 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1505,6 +1505,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 
 		/* In case of UHS-I modes, set High Speed Enable */
 		if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+		    (ios->timing == MMC_TIMING_MMC_DDR52) ||
 		    (ios->timing == MMC_TIMING_UHS_SDR50) ||
 		    (ios->timing == MMC_TIMING_UHS_SDR104) ||
 		    (ios->timing == MMC_TIMING_UHS_DDR50) ||
@@ -1565,7 +1566,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 				ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
 			else if (ios->timing == MMC_TIMING_UHS_SDR50)
 				ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
-			else if (ios->timing == MMC_TIMING_UHS_DDR50)
+			else if ((ios->timing == MMC_TIMING_UHS_DDR50) ||
+				 (ios->timing == MMC_TIMING_MMC_DDR52))
 				ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
 			sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
 		}
-- 
1.7.0.4



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

* [PATCH 0/5]  update selection of bus speed mode for eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (16 preceding siblings ...)
  2014-01-15 14:12 ` [PATCH 7/7] mmc: sdhci: " Seungwon Jeon
@ 2014-01-15 14:13 ` Seungwon Jeon
  2014-01-15 14:14 ` [PATCH 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
                   ` (18 subsequent siblings)
  36 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:13 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'
  Cc: linux-mmc

This series contains the change for selection of bus speed mode.
Previous implementation is complicated and some sequence is duplicated.
And specially, HS400 mode eMMC5.0 is introduced this time.

- Continued/Updated since "[PATCH 0/3] mmc: update bus speed mode" series.
 (Applied some comments from Ulf Hansson, Jackey Shen.)
- Tested at EXYNOS SOC.

Seungwon Jeon (5):
  mmc: drop the speed mode of card's state
  mmc: identify available device type to select
  mmc: step power class after final selection of bus mode
  mmc: rework selection of bus speed mode
  mmc: add support for HS400 mode of eMMC5.0

 drivers/mmc/core/bus.c     |   10 +-
 drivers/mmc/core/core.c    |    3 +-
 drivers/mmc/core/debugfs.c |    5 +-
 drivers/mmc/core/mmc.c     |  690 ++++++++++++++++++++++++++++----------------
 drivers/mmc/core/sd.c      |   16 +-
 drivers/mmc/core/sd.h      |    1 -
 drivers/mmc/core/sdio.c    |    8 +-
 include/linux/mmc/card.h   |   32 +--
 include/linux/mmc/host.h   |   42 +++-
 include/linux/mmc/mmc.h    |   23 ++-
 10 files changed, 529 insertions(+), 301 deletions(-)



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

* [PATCH 1/5] mmc: drop the speed mode of card's state
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (17 preceding siblings ...)
  2014-01-15 14:13 ` [PATCH 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
@ 2014-01-15 14:14 ` Seungwon Jeon
  2014-01-15 14:14 ` [PATCH 2/5] mmc: identify available device type to select Seungwon Jeon
                   ` (17 subsequent siblings)
  36 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:14 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'
  Cc: linux-mmc

Timing mode identifier has same role and can take the place
of speed mode. This change removes all related speed mode.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/bus.c   |    9 +++++----
 drivers/mmc/core/core.c  |    3 +--
 drivers/mmc/core/mmc.c   |   11 +++--------
 drivers/mmc/core/sd.c    |   16 +++-------------
 drivers/mmc/core/sd.h    |    1 -
 drivers/mmc/core/sdio.c  |    8 ++------
 include/linux/mmc/card.h |   24 +++++++-----------------
 include/linux/mmc/host.h |   23 +++++++++++++++++++++++
 8 files changed, 44 insertions(+), 51 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 64145a3..e8a21fb 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -286,6 +286,7 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
 		return ERR_PTR(-ENOMEM);
 
 	card->host = host;
+	card->ios = &host->ios;
 
 	device_initialize(&card->dev);
 
@@ -349,16 +350,16 @@ int mmc_add_card(struct mmc_card *card)
 	if (mmc_host_is_spi(card->host)) {
 		pr_info("%s: new %s%s%s card on SPI\n",
 			mmc_hostname(card->host),
-			mmc_card_highspeed(card) ? "high speed " : "",
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_hs(card) ? "high speed " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			type);
 	} else {
 		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
-			(mmc_card_highspeed(card) ? "high speed " : ""),
+			(mmc_card_hs(card) ? "high speed " : ""),
 			(mmc_card_hs200(card) ? "HS200 " : ""),
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
 	}
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 098374b..88433bd 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2198,7 +2198,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
 	struct mmc_command cmd = {0};
 
-	if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+	if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
 		return 0;
 
 	cmd.opcode = MMC_SET_BLOCKLEN;
@@ -2281,7 +2281,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
 		}
 	}
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
 	if (mmc_host_is_spi(host)) {
 		host->ios.chip_select = MMC_CS_HIGH;
 		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 6d91ff7..613e641 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1088,11 +1088,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		} else {
 			if (card->ext_csd.hs_max_dtr > 52000000 &&
 			    host->caps2 & MMC_CAP2_HS200) {
-				mmc_card_set_hs200(card);
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
 			} else {
-				mmc_card_set_highspeed(card);
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
 			}
 		}
@@ -1103,10 +1101,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
+	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
 		if (max_dtr > card->ext_csd.hs_max_dtr)
 			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_highspeed(card) && (max_dtr > 52000000))
+		if (mmc_card_hs(card) && (max_dtr > 52000000))
 			max_dtr = 52000000;
 	} else if (max_dtr > card->csd.max_dtr) {
 		max_dtr = card->csd.max_dtr;
@@ -1117,7 +1115,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
 			&& (host->caps & MMC_CAP_1_8V_DDR))
 				ddr = MMC_1_8V_DDR_MODE;
@@ -1260,7 +1258,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 				if (err)
 					goto err;
 			}
-			mmc_card_set_ddr_mode(card);
 			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
 			mmc_set_bus_width(card->host, bus_width);
 		}
@@ -1495,7 +1492,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 		err = mmc_sleep(host);
 	else if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 
 	if (!err) {
 		mmc_power_off(host);
@@ -1625,7 +1621,6 @@ static int mmc_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 	mmc_claim_host(host);
 	ret = mmc_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 692fdb1..54dd3d1 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -895,7 +895,7 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if (max_dtr > card->sw_caps.hs_max_dtr)
 			max_dtr = card->sw_caps.hs_max_dtr;
 	} else if (max_dtr > card->csd.max_dtr) {
@@ -905,12 +905,6 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 	return max_dtr;
 }
 
-void mmc_sd_go_highspeed(struct mmc_card *card)
-{
-	mmc_card_set_highspeed(card);
-	mmc_set_timing(card->host, MMC_TIMING_SD_HS);
-}
-
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -985,16 +979,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_sd_init_uhs_card(card);
 		if (err)
 			goto free_card;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Attempt to change to high-speed (if supported)
 		 */
 		err = mmc_sd_switch_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto free_card;
 
@@ -1089,7 +1080,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
 
 	if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
+
 	if (!err) {
 		mmc_power_off(host);
 		mmc_card_set_suspended(host->card);
@@ -1198,7 +1189,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
 	ret = mmc_sd_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
index 4b34b24..aab824a 100644
--- a/drivers/mmc/core/sd.h
+++ b/drivers/mmc/core/sd.h
@@ -12,6 +12,5 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 	bool reinit);
 unsigned mmc_sd_get_max_clock(struct mmc_card *card);
 int mmc_sd_switch_hs(struct mmc_card *card);
-void mmc_sd_go_highspeed(struct mmc_card *card);
 
 #endif
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4d721c6..ef57d2d 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		/*
 		 * The SDIO specification doesn't mention how
 		 * the CIS transfer speed register relates to
@@ -733,7 +733,6 @@ try_again:
 		mmc_set_clock(host, card->cis.max_dtr);
 
 		if (card->cccr.high_speed) {
-			mmc_card_set_highspeed(card);
 			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		}
 
@@ -792,16 +791,13 @@ try_again:
 		err = mmc_sdio_init_uhs_card(card);
 		if (err)
 			goto remove;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Switch to high-speed (if supported).
 		 */
 		err = sdio_enable_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto remove;
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 176fdf8..fb13bf9 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -194,6 +194,7 @@ struct sdio_cis {
 };
 
 struct mmc_host;
+struct mmc_ios;
 struct sdio_func;
 struct sdio_func_tuple;
 
@@ -239,6 +240,7 @@ struct mmc_part {
  */
 struct mmc_card {
 	struct mmc_host		*host;		/* the host this device belongs to */
+	struct mmc_ios		*ios;		/* bus settings of host */
 	struct device		dev;		/* the device */
 	u32			ocr;		/* the current OCR setting */
 	unsigned int		rca;		/* relative card address of device */
@@ -250,15 +252,11 @@ struct mmc_card {
 	unsigned int		state;		/* (our) card state */
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
 #define MMC_STATE_READONLY	(1<<1)		/* card is read-only */
-#define MMC_STATE_HIGHSPEED	(1<<2)		/* card is in high speed mode */
-#define MMC_STATE_BLOCKADDR	(1<<3)		/* card uses block-addressing */
-#define MMC_STATE_HIGHSPEED_DDR (1<<4)		/* card is in high speed mode */
-#define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra high speed mode */
-#define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
-#define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
-#define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
-#define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
-#define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
+#define MMC_STATE_BLOCKADDR	(1<<2)		/* card uses block-addressing */
+#define MMC_CARD_SDXC		(1<<3)		/* card is SDXC */
+#define MMC_CARD_REMOVED	(1<<4)		/* card has been removed */
+#define MMC_STATE_DOING_BKOPS	(1<<5)		/* card is doing BKOPS */
+#define MMC_STATE_SUSPENDED	(1<<6)		/* card is suspended */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -417,11 +415,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
-#define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
-#define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
-#define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
@@ -429,11 +423,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
-#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
-#define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
-#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_doing_bkops(c)	((c)->state |= MMC_STATE_DOING_BKOPS)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 87b1f4f..71977f4 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -17,6 +17,7 @@
 #include <linux/fault-inject.h>
 
 #include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -485,4 +486,26 @@ static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
 	return host->ios.clock;
 }
 #endif
+
+static inline int mmc_card_hs(struct mmc_card *card)
+{
+	return card->ios->timing == MMC_TIMING_SD_HS ||
+		card->ios->timing == MMC_TIMING_MMC_HS;
+}
+
+static inline int mmc_card_uhs(struct mmc_card *card)
+{
+	return card->ios->timing >= MMC_TIMING_UHS_SDR12 &&
+		card->ios->timing <= MMC_TIMING_UHS_DDR50;
+}
+
+static inline bool mmc_card_hs200(struct mmc_card *card)
+{
+	return card->ios->timing == MMC_TIMING_MMC_HS200;
+}
+
+static inline bool mmc_card_ddr52(struct mmc_card *card)
+{
+	return card->ios->timing == MMC_TIMING_MMC_DDR52;
+}
 #endif /* LINUX_MMC_HOST_H */
-- 
1.7.0.4



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

* [PATCH 2/5] mmc: identify available device type to select
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (18 preceding siblings ...)
  2014-01-15 14:14 ` [PATCH 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
@ 2014-01-15 14:14 ` Seungwon Jeon
  2014-01-15 14:14 ` [PATCH 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
                   ` (16 subsequent siblings)
  36 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:14 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'
  Cc: linux-mmc

Device types which are supported by both host and device
can be identified when EXT_CSD is read. There is no need to
check host's capability anymore.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
 include/linux/mmc/card.h |    6 ++-
 include/linux/mmc/host.h |    6 ---
 include/linux/mmc/mmc.h  |   12 +++++--
 4 files changed, 56 insertions(+), 45 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 613e641..1ea155a 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0;
+	unsigned int avail_type = 0;
 
-	if (card_type & EXT_CSD_CARD_TYPE_26)
+	if (caps & MMC_CAP_MMC_HIGHSPEED &&
+	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
 		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
+	}
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
-			card_type & EXT_CSD_CARD_TYPE_52)
+	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
 		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
+	}
 
-	if ((caps & MMC_CAP_1_8V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
-	    (caps & MMC_CAP_1_2V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
+	if (caps & MMC_CAP_1_8V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
 		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
+	}
 
-	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
-	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
+	if (caps & MMC_CAP_1_2V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
+	}
+
+	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
 		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
+		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
+	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
-	card->ext_csd.card_type = card_type;
+	card->mmc_avail_type = avail_type;
 }
 
 /*
@@ -708,6 +726,11 @@ static struct device_type mmc_type = {
 	.groups = mmc_attr_groups,
 };
 
+static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
+{
+	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+}
+
 /*
  * Select the PowerClass for the current bus width
  * If power class is defined for 4/8 bit bus in the
@@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
 
 	host = card->host;
 
-	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
-			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
 
-	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
-			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
 
 	/* If fails try again during next card power cycle */
@@ -1070,10 +1091,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	if (card->ext_csd.hs_max_dtr != 0) {
 		err = 0;
-		if (card->ext_csd.hs_max_dtr > 52000000 &&
-		    host->caps2 & MMC_CAP2_HS200)
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 			err = mmc_select_hs200(card);
-		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
+		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_HS_TIMING, 1,
 					 card->ext_csd.generic_cmd6_time);
@@ -1086,13 +1106,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			       mmc_hostname(card->host));
 			err = 0;
 		} else {
-			if (card->ext_csd.hs_max_dtr > 52000000 &&
-			    host->caps2 & MMC_CAP2_HS200) {
+			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
-			} else {
+			else
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-			}
 		}
 	}
 
@@ -1115,14 +1133,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_hs(card)) {
-		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-			&& (host->caps & MMC_CAP_1_8V_DDR))
-				ddr = MMC_1_8V_DDR_MODE;
-		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-			&& (host->caps & MMC_CAP_1_2V_DDR))
-				ddr = MMC_1_2V_DDR_MODE;
-	}
+	if (mmc_card_hs(card))
+		ddr = mmc_snoop_ddr(card);
 
 	/*
 	 * Indicate HS200 SDR mode (if supported).
@@ -1142,8 +1154,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		 * 3. set the clock to > 52Mhz <=200MHz and
 		 * 4. execute tuning for HS200
 		 */
-		if ((host->caps2 & MMC_CAP2_HS200) &&
-		    card->host->ops->execute_tuning) {
+		if (card->host->ops->execute_tuning) {
 			mmc_host_clk_hold(card->host);
 			err = card->host->ops->execute_tuning(card->host,
 				MMC_SEND_TUNING_BLOCK_HS200);
@@ -1252,7 +1263,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			 *
 			 * WARNING: eMMC rules are NOT the same as SD DDR
 			 */
-			if (ddr == MMC_1_2V_DDR_MODE) {
+			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
 				err = __mmc_set_signal_voltage(host,
 					MMC_SIGNAL_VOLTAGE_120);
 				if (err)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index fb13bf9..86d4572 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -68,7 +68,6 @@ struct mmc_ext_csd {
 #define MMC_HIGH_DDR_MAX_DTR	52000000
 #define MMC_HS200_MAX_DTR	200000000
 	unsigned int		sectors;
-	unsigned int		card_type;
 	unsigned int		hc_erase_size;		/* In sectors */
 	unsigned int		hc_erase_timeout;	/* In milliseconds */
 	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
@@ -297,7 +296,10 @@ struct mmc_card {
 	const char		**info;		/* info strings */
 	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
 
-	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+	union {
+		unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+		unsigned int		mmc_avail_type;	/* supported device type by both host and card */
+	};
 
 	struct dentry		*debugfs_root;
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 71977f4..66e632c 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -62,12 +62,6 @@ struct mmc_ios {
 #define MMC_TIMING_MMC_DDR52	8
 #define MMC_TIMING_MMC_HS200	9
 
-#define MMC_SDR_MODE		0
-#define MMC_1_2V_DDR_MODE	1
-#define MMC_1_8V_DDR_MODE	2
-#define MMC_1_2V_SDR_MODE	3
-#define MMC_1_8V_SDR_MODE	4
-
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
 #define MMC_SIGNAL_VOLTAGE_330	0
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 50bcde3..f734c0c 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -354,18 +354,22 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#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_MASK	0x3F	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
+				 EXT_CSD_CARD_TYPE_HS_52)
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
 					     /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
 					     /* DDR mode @1.2V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
 					| EXT_CSD_CARD_TYPE_DDR_1_2V)
-#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
-#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_8V	(1<<4)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_2V	(1<<5)	/* Card can run at 200MHz */
 						/* SDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS200_1_2V)
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
-- 
1.7.0.4



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

* [PATCH 3/5] mmc: step power class after final selection of bus mode
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (19 preceding siblings ...)
  2014-01-15 14:14 ` [PATCH 2/5] mmc: identify available device type to select Seungwon Jeon
@ 2014-01-15 14:14 ` Seungwon Jeon
  2014-01-15 14:15 ` [PATCH 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
                   ` (15 subsequent siblings)
  36 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:14 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'
  Cc: linux-mmc

Power class is changed once only after selection of bus modes
including speed and bus-width finishes finally.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/mmc.c |   77 +++++++++++++++++++++++++++++++----------------
 1 files changed, 51 insertions(+), 26 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 1ea155a..92aa004 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -737,8 +737,8 @@ static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
  * extended CSD register, select it by executing the
  * mmc_switch command.
  */
-static int mmc_select_powerclass(struct mmc_card *card,
-		unsigned int bus_width)
+static int __mmc_select_powerclass(struct mmc_card *card,
+				   unsigned int bus_width, u8 *ext_csd)
 {
 	int err = 0;
 	unsigned int pwrclass_val = 0;
@@ -759,13 +759,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
 
 	switch (1 << host->ios.vdd) {
 	case MMC_VDD_165_195:
-		if (host->ios.clock <= 26000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
 			pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
-		else if	(host->ios.clock <= 52000000)
+		else if	(host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
 				card->ext_csd.raw_pwr_cl_52_195 :
 				card->ext_csd.raw_pwr_cl_ddr_52_195;
-		else if (host->ios.clock <= 200000000)
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
 			pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
 		break;
 	case MMC_VDD_27_28:
@@ -777,13 +777,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	case MMC_VDD_33_34:
 	case MMC_VDD_34_35:
 	case MMC_VDD_35_36:
-		if (host->ios.clock <= 26000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
 			pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
-		else if	(host->ios.clock <= 52000000)
+		else if	(host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
 				card->ext_csd.raw_pwr_cl_52_360 :
 				card->ext_csd.raw_pwr_cl_ddr_52_360;
-		else if (host->ios.clock <= 200000000)
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
 			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
 		break;
 	default:
@@ -810,6 +810,44 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	return err;
 }
 
+static int mmc_select_powerclass(struct mmc_card *card, u8 *ext_csd)
+{
+	int err, ddr;
+	u32 bus_width, ext_csd_bits;
+	struct mmc_host *host;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if (!ext_csd)
+		return 0;
+
+	/* Power class selection is supported for versions >= 4.0 */
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	/* Power class values are defined only for 4/8 bit bus */
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ddr = mmc_snoop_ddr(card);
+	if (ddr)
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+	else
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
+
+	err = __mmc_select_powerclass(card, ext_csd_bits, ext_csd);
+	if (err)
+		pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
+			mmc_hostname(host), 1 << bus_width, ddr);
+
+	return err;
+}
+
 /*
  * Selects the desired buswidth and switch to the HS200 mode
  * if bus width set without error
@@ -1168,11 +1206,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
 		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
 				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-		err = mmc_select_powerclass(card, ext_csd_bits);
-		if (err)
-			pr_warning("%s: power class selection to bus width %d"
-				   " failed\n", mmc_hostname(card->host),
-				   1 << bus_width);
 	}
 
 	/*
@@ -1201,12 +1234,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			bus_width = bus_widths[idx];
 			if (bus_width == MMC_BUS_WIDTH_1)
 				ddr = 0; /* no DDR for 1-bit width */
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width);
 
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
@@ -1231,13 +1258,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		}
 
 		if (!err && ddr) {
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d ddr %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width, ddr);
-
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][1],
@@ -1275,6 +1295,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
+	 * Choose the power calss with selected bus interface
+	 */
+	mmc_select_powerclass(card, ext_csd);
+
+	/*
 	 * Enable HPI feature (if supported)
 	 */
 	if (card->ext_csd.hpi) {
-- 
1.7.0.4



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

* [PATCH 4/5] mmc: rework selection of bus speed mode
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (20 preceding siblings ...)
  2014-01-15 14:14 ` [PATCH 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
@ 2014-01-15 14:15 ` Seungwon Jeon
  2014-01-15 14:19 ` [PATCH 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
                   ` (14 subsequent siblings)
  36 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:15 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'
  Cc: linux-mmc

Current implementation for bus speed mode selection is too
complicated. This patch is to simplify the codes and remove
some duplicate parts.

The following changes are including:
* Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
* Rearranged the mode selection sequence with supported device type
* Adds maximum speed for HS200 mode(hs200_max_dtr)
* Adds field definition for HS_TIMING of EXT_CSD

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/debugfs.c |    2 +-
 drivers/mmc/core/mmc.c     |  443 +++++++++++++++++++++++++-------------------
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/mmc.h    |    4 +
 4 files changed, 257 insertions(+), 193 deletions(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 509229b..1f730db 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -139,7 +139,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 		str = "mmc DDR52";
 		break;
 	case MMC_TIMING_MMC_HS200:
-		str = "mmc high-speed SDR200";
+		str = "mmc HS200";
 		break;
 	default:
 		str = "invalid";
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 92aa004..6ce5ff3 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -242,7 +242,7 @@ static void mmc_select_card_type(struct mmc_card *card)
 	struct mmc_host *host = card->host;
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
-	unsigned int hs_max_dtr = 0;
+	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
@@ -271,17 +271,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 
 	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
 	}
 
 	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
+	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
 }
 
@@ -849,37 +850,52 @@ static int mmc_select_powerclass(struct mmc_card *card, u8 *ext_csd)
 }
 
 /*
- * Selects the desired buswidth and switch to the HS200 mode
- * if bus width set without error
+ * Set the bus speed for the selected speed mode.
  */
-static int mmc_select_hs200(struct mmc_card *card)
+static void mmc_set_bus_speed(struct mmc_card *card)
+{
+	unsigned int max_dtr = (unsigned int)-1;
+
+	BUG_ON(!card);
+
+	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+		max_dtr = card->ext_csd.hs200_max_dtr;
+	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
+		max_dtr = card->ext_csd.hs_max_dtr;
+	else if (max_dtr > card->csd.max_dtr)
+		max_dtr = card->csd.max_dtr;
+
+	mmc_set_clock(card->host, max_dtr);
+}
+
+/*
+ * Select the bus width amoung 4-bit and 8-bit(SDR).
+ * If the bus width is changed successfully, return the slected width value.
+ * Zero is returned instead of error value if the wide width is not supported.
+ */
+static int mmc_select_bus_width(struct mmc_card *card)
 {
-	int idx, err = -EINVAL;
-	struct mmc_host *host;
 	static unsigned ext_csd_bits[] = {
-		EXT_CSD_BUS_WIDTH_4,
 		EXT_CSD_BUS_WIDTH_8,
+		EXT_CSD_BUS_WIDTH_4,
 	};
 	static unsigned bus_widths[] = {
-		MMC_BUS_WIDTH_4,
 		MMC_BUS_WIDTH_8,
+		MMC_BUS_WIDTH_4,
 	};
+	struct mmc_host *host;
+	unsigned idx, bus_width = 0;
+	int err = 0;
 
 	BUG_ON(!card);
 
 	host = card->host;
 
-	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
-
-	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
-
-	/* If fails try again during next card power cycle */
-	if (err)
-		goto err;
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
+	    !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
+		return 0;
 
-	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
 
 	/*
 	 * Unlike SD, MMC cards dont have a configuration register to notify
@@ -887,8 +903,7 @@ static int mmc_select_hs200(struct mmc_card *card)
 	 * 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 >= 0; idx--) {
-
+	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
@@ -903,25 +918,219 @@ static int mmc_select_hs200(struct mmc_card *card)
 		if (err)
 			continue;
 
-		mmc_set_bus_width(card->host, bus_widths[idx]);
+		bus_width = bus_widths[idx];
+		mmc_set_bus_width(host, bus_width);
 
+		/*
+		 * If controller can't handle bus width test,
+		 * compare ext_csd previously read in 1 bit mode
+		 * against ext_csd at new bus width
+		 */
 		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-			err = mmc_compare_ext_csds(card, bus_widths[idx]);
+			err = mmc_compare_ext_csds(card, bus_width);
 		else
-			err = mmc_bus_test(card, bus_widths[idx]);
-		if (!err)
+			err = mmc_bus_test(card, bus_width);
+
+		if (!err) {
+			err = bus_width;
 			break;
+		} else {
+			pr_warn("%s: switch to bus width %d failed\n",
+				mmc_hostname(card->host), ext_csd_bits[idx]);
+		}
 	}
 
-	/* switch to HS200 mode if bus width set successfully */
+	return err;
+}
+
+/*
+ * Switch to the high-speed mode
+ */
+static int mmc_select_hs(struct mmc_card *card)
+{
+	int err;
+
+	BUG_ON(!card);
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			 card->ext_csd.generic_cmd6_time);
 	if (!err)
+		mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+
+	return err;
+}
+
+/*
+ * Activate wide bus and DDR if supported.
+ */
+static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
+{
+	struct mmc_host *host;
+	u32 bus_width, ext_csd_bits;
+	int err = 0, ddr;
+
+	BUG_ON(!card);
+
+	ddr = mmc_snoop_ddr(card);
+	if (!(ddr & EXT_CSD_CARD_TYPE_DDR_52))
+		return 0;
+
+	host = card->host;
+	bus_width = host->ios.bus_width;
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+		EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_BUS_WIDTH,
+			ext_csd_bits,
+			card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width %d ddr failed\n",
+			mmc_hostname(host), 1 << bus_width);
+		return err;
+	}
+
+	/*
+	 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+	 * signaling.
+	 *
+	 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+	 *
+	 * 1.8V vccq at 3.3V core voltage (vcc) is not required
+	 * in the JEDEC spec for DDR.
+	 *
+	 * Do not force change in vccq since we are obviously
+	 * working and no change to vccq is needed.
+	 *
+	 * WARNING: eMMC rules are NOT the same as SD DDR
+	 */
+	if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		err = __mmc_set_signal_voltage(host,
+				MMC_SIGNAL_VOLTAGE_120);
+		if (err)
+			return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
+
+	return err;
+}
+
+/*
+ * For device supporting HS200 mode, the following sequence
+ * should be done before executing the tuning process.
+ * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
+ * 2. switch to HS200 mode
+ * 3. set the clock to > 52Mhz and <=200MHz
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+	int err = -EINVAL;
+	struct mmc_host *host;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+
+	/* If fails try again during next card power cycle */
+	if (err)
+		goto err;
+
+	/*
+	 * Set the bus width(4 or 8) with host's support and
+	 * switch to HS200 mode if bus width is set successfully.
+	 */
+	err = mmc_select_bus_width(card);
+	if (!IS_ERR_VALUE(err)) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_HS_TIMING, 2, 0);
+				 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
+				 card->ext_csd.generic_cmd6_time);
+		if (!err)
+			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+	}
 err:
 	return err;
 }
 
 /*
+ * Activate High Speed or HS200 mode if supported.
+ */
+static int mmc_select_timing(struct mmc_card *card)
+{
+	struct mmc_host *host;
+	int err = 0;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
+	     card->ext_csd.hs_max_dtr == 0))
+		goto bus_speed;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+		err = mmc_select_hs200(card);
+	else if(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
+		err = mmc_select_hs(card);
+
+	if (err && err != -EBADMSG)
+		return err;
+
+	if (err) {
+		pr_warn("%s: switch to %s failed\n",
+			mmc_card_hs(card) ? "high-speed" :
+			(mmc_card_hs200(card) ? "hs200" : ""),
+			mmc_hostname(card->host));
+		err = 0;
+	}
+
+bus_speed:
+	/*
+	 * Set the bus speed to the selected bus timing.
+	 * If timing is not selected, backward compatible is the default.
+	 */
+	mmc_set_bus_speed(card);
+	return err;
+}
+
+/*
+ * Execute tuning sequence to seek the proper bus operating
+ * conditions for HS200, which sends CMD21 to the device.
+ */
+static int mmc_hs200_tuning(struct mmc_card *card)
+{
+	int err = 0;
+	struct mmc_host *host;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if (card->host->ops->execute_tuning) {
+		mmc_host_clk_hold(card->host);
+		err = card->host->ops->execute_tuning(card->host,
+				MMC_SEND_TUNING_BLOCK_HS200);
+		mmc_host_clk_release(card->host);
+
+		if (err)
+			pr_warn("%s: tuning execution failed\n",
+				mmc_hostname(card->host));
+	}
+
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -931,9 +1140,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	struct mmc_card *oldcard)
 {
 	struct mmc_card *card;
-	int err, ddr = 0;
+	int err;
 	u32 cid[4];
-	unsigned int max_dtr;
 	u32 rocr;
 	u8 *ext_csd = NULL;
 
@@ -1125,172 +1333,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
-	 * Activate high speed (if supported)
+	 * Select timing interface
 	 */
-	if (card->ext_csd.hs_max_dtr != 0) {
-		err = 0;
-		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-			err = mmc_select_hs200(card);
-		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_HS_TIMING, 1,
-					 card->ext_csd.generic_cmd6_time);
-
-		if (err && err != -EBADMSG)
-			goto free_card;
-
-		if (err) {
-			pr_warning("%s: switch to highspeed failed\n",
-			       mmc_hostname(card->host));
-			err = 0;
-		} else {
-			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-				mmc_set_timing(card->host,
-					       MMC_TIMING_MMC_HS200);
-			else
-				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-		}
-	}
-
-	/*
-	 * Compute bus speed.
-	 */
-	max_dtr = (unsigned int)-1;
-
-	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
-		if (max_dtr > card->ext_csd.hs_max_dtr)
-			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_hs(card) && (max_dtr > 52000000))
-			max_dtr = 52000000;
-	} else if (max_dtr > card->csd.max_dtr) {
-		max_dtr = card->csd.max_dtr;
-	}
-
-	mmc_set_clock(host, max_dtr);
-
-	/*
-	 * Indicate DDR mode (if supported).
-	 */
-	if (mmc_card_hs(card))
-		ddr = mmc_snoop_ddr(card);
+	err = mmc_select_timing(card);
+	if (err)
+		goto free_card;
 
-	/*
-	 * Indicate HS200 SDR mode (if supported).
-	 */
 	if (mmc_card_hs200(card)) {
-		u32 ext_csd_bits;
-		u32 bus_width = card->host->ios.bus_width;
-
-		/*
-		 * For devices supporting HS200 mode, the bus width has
-		 * to be set before executing the tuning function. If
-		 * set before tuning, then device will respond with CRC
-		 * errors for responses on CMD line. So for HS200 the
-		 * sequence will be
-		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
-		 * 2. switch to HS200 mode
-		 * 3. set the clock to > 52Mhz <=200MHz and
-		 * 4. execute tuning for HS200
-		 */
-		if (card->host->ops->execute_tuning) {
-			mmc_host_clk_hold(card->host);
-			err = card->host->ops->execute_tuning(card->host,
-				MMC_SEND_TUNING_BLOCK_HS200);
-			mmc_host_clk_release(card->host);
-		}
-		if (err) {
-			pr_warning("%s: tuning execution failed\n",
-				   mmc_hostname(card->host));
+		err = mmc_hs200_tuning(card);
+		if (err)
 			goto err;
-		}
-
-		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
-				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-	}
-
-	/*
-	 * Activate wide bus and DDR (if supported).
-	 */
-	if (!mmc_card_hs200(card) &&
-	    (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
-	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
-		static unsigned ext_csd_bits[][2] = {
-			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
-			{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
-			{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
-		};
-		static unsigned bus_widths[] = {
-			MMC_BUS_WIDTH_8,
-			MMC_BUS_WIDTH_4,
-			MMC_BUS_WIDTH_1
-		};
-		unsigned idx, bus_width = 0;
-
-		if (host->caps & MMC_CAP_8_BIT_DATA)
-			idx = 0;
-		else
-			idx = 1;
-		for (; idx < ARRAY_SIZE(bus_widths); idx++) {
-			bus_width = bus_widths[idx];
-			if (bus_width == MMC_BUS_WIDTH_1)
-				ddr = 0; /* no DDR for 1-bit width */
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][0],
-					 card->ext_csd.generic_cmd6_time);
-			if (!err) {
-				mmc_set_bus_width(card->host, bus_width);
-
-				/*
-				 * If controller can't handle bus width test,
-				 * compare ext_csd previously read in 1 bit mode
-				 * against ext_csd at new bus width
-				 */
-				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					err = mmc_compare_ext_csds(card,
-						bus_width);
-				else
-					err = mmc_bus_test(card, bus_width);
-				if (!err)
-					break;
-			}
-		}
-
-		if (!err && ddr) {
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][1],
-					 card->ext_csd.generic_cmd6_time);
-		}
-		if (err) {
-			pr_warning("%s: switch to bus width %d ddr %d "
-				"failed\n", mmc_hostname(card->host),
-				1 << bus_width, ddr);
-			goto free_card;
-		} else if (ddr) {
-			/*
-			 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
-			 * signaling.
-			 *
-			 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
-			 *
-			 * 1.8V vccq at 3.3V core voltage (vcc) is not required
-			 * in the JEDEC spec for DDR.
-			 *
-			 * Do not force change in vccq since we are obviously
-			 * working and no change to vccq is needed.
-			 *
-			 * WARNING: eMMC rules are NOT the same as SD DDR
-			 */
-			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
-				err = __mmc_set_signal_voltage(host,
-					MMC_SIGNAL_VOLTAGE_120);
-				if (err)
-					goto err;
-			}
-			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
-			mmc_set_bus_width(card->host, bus_width);
+	} else if (mmc_card_hs(card)) {
+		/* Select the desired bus width optionally */
+		err = mmc_select_bus_width(card);
+		if (!IS_ERR_VALUE(err)) {
+			err = mmc_select_hs_ddr(card, ext_csd);
+			if (err)
+				goto err;
 		}
 	}
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 86d4572..c278241 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -63,6 +63,7 @@ struct mmc_ext_csd {
 	unsigned int            power_off_longtime;     /* Units: ms */
 	u8			power_off_notification;	/* state */
 	unsigned int		hs_max_dtr;
+	unsigned int		hs200_max_dtr;
 #define MMC_HIGH_26_MAX_DTR	26000000
 #define MMC_HIGH_52_MAX_DTR	52000000
 #define MMC_HIGH_DDR_MAX_DTR	52000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f734c0c..f429f13 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -377,6 +377,10 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
 #define EXT_CSD_SEC_GB_CL_EN	BIT(4)
-- 
1.7.0.4



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

* [PATCH 5/5] mmc: add support for HS400 mode of eMMC5.0
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (21 preceding siblings ...)
  2014-01-15 14:15 ` [PATCH 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
@ 2014-01-15 14:19 ` Seungwon Jeon
  2014-02-18 10:24   ` Jackey Shen
  2014-02-15 14:08 ` [PATCH v2 0/7] mmc: distinguish DDR timing mode for eMMC/UHS Seungwon Jeon
                   ` (13 subsequent siblings)
  36 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-15 14:19 UTC (permalink / raw)
  To: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'
  Cc: linux-mmc

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: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/bus.c     |    1 +
 drivers/mmc/core/debugfs.c |    3 +
 drivers/mmc/core/mmc.c     |  126 +++++++++++++++++++++++++++++++++++++++++---
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/host.h   |   15 +++++-
 include/linux/mmc/mmc.h    |    7 ++-
 6 files changed, 144 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index e8a21fb..d28ecf1 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -358,6 +358,7 @@ int mmc_add_card(struct mmc_card *card)
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_hs(card) ? "high speed " : ""),
+			mmc_card_hs400(card) ? "HS400 " :
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 1f730db..91eb162 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_MMC_HS200:
 		str = "mmc HS200";
 		break;
+	case MMC_TIMING_MMC_HS400:
+		str = "mmc HS400";
+		break;
 	default:
 		str = "invalid";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 6ce5ff3..f3c899d 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 static void mmc_select_card_type(struct mmc_card *card)
 {
 	struct mmc_host *host = card->host;
-	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
+	u8 card_type = card->ext_csd.raw_card_type;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
@@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
+	if (caps2 & MMC_CAP2_HS400_1_8V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS400_1_2V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
+	}
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
@@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
 		card->ext_csd.raw_pwr_cl_ddr_52_360 =
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
+		card->ext_csd.raw_pwr_cl_ddr_200_360 =
+			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
 	}
 
 	if (card->ext_csd.rev >= 5) {
@@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
 		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
 			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
 		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
-			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
+		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
+
 	if (err)
 		err = -EINVAL;
 
@@ -729,7 +746,8 @@ static struct device_type mmc_type = {
 
 static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
 {
-	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	return card->mmc_avail_type &
+		(EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_HS400);
 }
 
 /*
@@ -785,7 +803,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
 				card->ext_csd.raw_pwr_cl_52_360 :
 				card->ext_csd.raw_pwr_cl_ddr_52_360;
 		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
+			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
+				card->ext_csd.raw_pwr_cl_ddr_200_360 :
+				card->ext_csd.raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -858,7 +878,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
 
 	BUG_ON(!card);
 
-	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+	if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
+	     max_dtr > card->ext_csd.hs200_max_dtr)
 		max_dtr = card->ext_csd.hs200_max_dtr;
 	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
 		max_dtr = card->ext_csd.hs_max_dtr;
@@ -962,6 +983,30 @@ static int mmc_select_hs(struct mmc_card *card)
 }
 
 /*
+ * Revert to the high-speed mode from above speed
+ */
+static int mmc_revert_to_hs(struct mmc_card *card)
+{
+	BUG_ON(!card);
+
+	/*
+	 * CMD13, which is used to confirm the completion of timing
+	 * change, will be issued at higher speed timing condtion
+	 * rather than high-speed. If device has completed the change
+	 * to high-speed mode, it may not be proper timing to issue
+	 * command. Low speed supplies better timing margin than high
+	 * speed. Accordingly clock rate & timging should be chagned
+	 * ahead before actual switch.
+	 */
+	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+	mmc_set_bus_speed(card);
+
+	return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			  card->ext_csd.generic_cmd6_time);
+}
+
+/*
  * Activate wide bus and DDR if supported.
  */
 static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
@@ -1020,6 +1065,60 @@ static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
 	return err;
 }
 
+static int mmc_select_hs400(struct mmc_card *card, u8 *ext_csd)
+{
+	struct mmc_host *host;
+	int err = 0, ddr;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	ddr = mmc_snoop_ddr(card);
+
+	/*
+	 * The bus width is set to only 8 DDR in HS400 mode
+	 */
+	if (!(ddr & EXT_CSD_CARD_TYPE_HS400 &&
+	      card->host->ios.bus_width == MMC_BUS_WIDTH_8))
+		return 0;
+
+	/*
+	 * Before setting BUS_WIDTH for dual data rate operation,
+	 * HS_TIMING must be set to High Speed(0x1)
+	 */
+	err = mmc_revert_to_hs(card);
+	if (err) {
+		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
+			mmc_hostname(card->host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_DDR_BUS_WIDTH_8,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
+			mmc_hostname(card->host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to hs400 failed, err:%d\n",
+			 mmc_hostname(card->host), err);
+		return err;
+	}
+
+	mmc_set_timing(card->host, MMC_TIMING_MMC_HS400);
+	mmc_set_bus_speed(card);
+
+	return 0;
+}
+
 /*
  * For device supporting HS200 mode, the following sequence
  * should be done before executing the tuning process.
@@ -1055,7 +1154,16 @@ static int mmc_select_hs200(struct mmc_card *card)
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
 				 card->ext_csd.generic_cmd6_time);
-		if (!err)
+		if (err)
+			goto err;
+
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
+			/*
+			 * Timing should be adjusted to the HS400 target
+			 * operation frequency for tuning process
+			 */
+			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
+		else
 			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
 	}
 err:
@@ -1105,7 +1213,7 @@ bus_speed:
 
 /*
  * Execute tuning sequence to seek the proper bus operating
- * conditions for HS200, which sends CMD21 to the device.
+ * conditions for HS200 and HS400, which sends CMD21 to the device.
  */
 static int mmc_hs200_tuning(struct mmc_card *card)
 {
@@ -1343,6 +1451,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_hs200_tuning(card);
 		if (err)
 			goto err;
+
+		err = mmc_select_hs400(card, ext_csd);
+		if (err)
+			goto err;
 	} else if (mmc_card_hs(card)) {
 		/* Select the desired bus width optionally */
 		err = mmc_select_bus_width(card);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c278241..eabddfb 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -110,6 +110,7 @@ struct mmc_ext_csd {
 	u8			raw_pwr_cl_200_360;	/* 237 */
 	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
 	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
+	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
 	u8			raw_bkops_status;	/* 246 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 66e632c..7c0e277 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -61,6 +61,8 @@ struct mmc_ios {
 #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_HS400_TUNING 11
 
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
@@ -278,6 +280,10 @@ struct mmc_host {
 				 MMC_CAP2_PACKED_WR)
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
 #define MMC_CAP2_SANITIZE	(1 << 15)		/* Support Sanitize */
+#define MMC_CAP2_HS400_1_8V	(1 << 16)	/* Can support HS400 1.8V */
+#define MMC_CAP2_HS400_1_2V	(1 << 17)	/* Can support HS400 1.2V */
+#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
+				 MMC_CAP2_HS400_1_2V)
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
@@ -495,11 +501,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
 
 static inline bool mmc_card_hs200(struct mmc_card *card)
 {
-	return card->ios->timing == MMC_TIMING_MMC_HS200;
+	return card->ios->timing == MMC_TIMING_MMC_HS200 ||
+		card->ios->timing == MMC_TIMING_MMC_HS400_TUNING;
 }
 
 static inline bool mmc_card_ddr52(struct mmc_card *card)
 {
 	return card->ios->timing == MMC_TIMING_MMC_DDR52;
 }
+
+static inline bool mmc_card_hs400(struct mmc_card *card)
+{
+	return card->ios->timing == MMC_TIMING_MMC_HS400;
+}
+
 #endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f429f13..64ec963 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -325,6 +325,7 @@ struct _mmc_csd {
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
 #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
 #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
 #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
@@ -354,7 +355,6 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
 #define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
@@ -370,6 +370,10 @@ struct _mmc_csd {
 						/* SDR mode @1.2V I/O */
 #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	(1<<6)	/* Card can run at 200MHz DDR, 1.8V */
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
@@ -380,6 +384,7 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
-- 
1.7.0.4



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

* Re: [PATCH 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-15 14:11 ` [PATCH 2/7] mmc: mmci: " Seungwon Jeon
@ 2014-01-16 10:20   ` Ulf Hansson
  2014-01-17 14:05     ` Seungwon Jeon
  2014-01-17 14:50     ` [PATCH v2 " Seungwon Jeon
  0 siblings, 2 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-01-16 10:20 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: Chris Ball, Rickard Andersson, Russell King, linux-mmc

On 15 January 2014 15:11, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Replaced UHS_DDR50 with MMC_DDR52.
>
> CC: Russell King <linux@arm.linux.org.uk>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
>  drivers/mmc/host/mmci.c |    4 ++--
>  1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
> index f320579..c348427 100644
> --- a/drivers/mmc/host/mmci.c
> +++ b/drivers/mmc/host/mmci.c
> @@ -299,7 +299,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
>         if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
>                 clk |= MCI_ST_8BIT_BUS;
>
> -       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
> +       if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)

This will break DDR mode for UHS SD-cards.

>                 clk |= MCI_ST_UX500_NEG_EDGE;
>
>         mmci_write_clkreg(host, clk);
> @@ -784,7 +784,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
>                         mmci_write_clkreg(host, clk);
>                 }
>
> -       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
> +       if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
>                 datactrl |= MCI_ST_DPSM_DDRMODE;

This will break DDR mode for UHS SD-cards.

Kind regards
Ulf Hansson


>
>         /*
> --
> 1.7.0.4
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 4/7] mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-15 14:12 ` [PATCH 4/7] mmc: sh_mmcif: " Seungwon Jeon
@ 2014-01-16 10:22   ` Ulf Hansson
  2014-01-17 14:36     ` Seungwon Jeon
  2014-01-28 13:08     ` Seungwon Jeon
  0 siblings, 2 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-01-16 10:22 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: Chris Ball, Guennadi Liakhovetski, linux-mmc

On 15 January 2014 15:12, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Replaced UHS_DDR50 with MMC_DDR52.
>
> CC: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
>  drivers/mmc/host/sh_mmcif.c |    9 +++++----
>  1 files changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
> index 54730f4..656fbba 100644
> --- a/drivers/mmc/host/sh_mmcif.c
> +++ b/drivers/mmc/host/sh_mmcif.c
> @@ -803,12 +803,13 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
>                         break;
>                 }
>                 switch (host->timing) {
> -               case MMC_TIMING_UHS_DDR50:
> +               case MMC_TIMING_MMC_DDR52:

What about UHS SD cards?

Kind regards
Ulf Hansson

>                         /*
>                          * MMC core will only set this timing, if the host
> -                        * advertises the MMC_CAP_UHS_DDR50 capability. MMCIF
> -                        * implementations with this capability, e.g. sh73a0,
> -                        * will have to set it in their platform data.
> +                        * advertises the MMC_CAP_1_8V_DDR/MMC_CAP_1_2V_DDR
> +                        * capability. MMCIF implementations with this
> +                        * capability, e.g. sh73a0, will have to set it
> +                        * in their platform data.
>                          */
>                         tmp |= CMD_SET_DARS;
>                         break;
> --
> 1.7.0.4
>
>

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

* Re: [PATCH 7/7] mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-15 14:12 ` [PATCH 7/7] mmc: sdhci: " Seungwon Jeon
@ 2014-01-16 10:25   ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-01-16 10:25 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: Chris Ball, linux-mmc

On 15 January 2014 15:12, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Added MMC_DDR52 as eMMC's DDR mode distinguished from SD-UHS.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

> ---
>  drivers/mmc/host/sdhci.c |    4 +++-
>  1 files changed, 3 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index ec3eb30..6c3482a 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -1505,6 +1505,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
>
>                 /* In case of UHS-I modes, set High Speed Enable */
>                 if ((ios->timing == MMC_TIMING_MMC_HS200) ||
> +                   (ios->timing == MMC_TIMING_MMC_DDR52) ||
>                     (ios->timing == MMC_TIMING_UHS_SDR50) ||
>                     (ios->timing == MMC_TIMING_UHS_SDR104) ||
>                     (ios->timing == MMC_TIMING_UHS_DDR50) ||
> @@ -1565,7 +1566,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
>                                 ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
>                         else if (ios->timing == MMC_TIMING_UHS_SDR50)
>                                 ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
> -                       else if (ios->timing == MMC_TIMING_UHS_DDR50)
> +                       else if ((ios->timing == MMC_TIMING_UHS_DDR50) ||
> +                                (ios->timing == MMC_TIMING_MMC_DDR52))
>                                 ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
>                         sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
>                 }
> --
> 1.7.0.4
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 6/7] mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-15 14:12 ` [PATCH 6/7] mmc: dw_mmc: " Seungwon Jeon
@ 2014-01-16 10:37   ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-01-16 10:37 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: Chris Ball, Jaehoon Chung, linux-mmc

On 15 January 2014 15:12, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Replaced UHS_DDR50 with MMC_DDR52. And MMC_CAP_UHS_DDR50
> is removed because of non-implementation of UHS signaling.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

> ---
>  drivers/mmc/host/dw_mmc-exynos.c |    3 +--
>  drivers/mmc/host/dw_mmc.c        |    2 +-
>  2 files changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
> index 3423c5e..b5a36b1 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.c
> +++ b/drivers/mmc/host/dw_mmc-exynos.c
> @@ -386,8 +386,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
>
>  /* Common capabilities of Exynos4/Exynos5 SoC */
>  static unsigned long exynos_dwmmc_caps[4] = {
> -       MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
> -               MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
> +       MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
>         MMC_CAP_CMD23,
>         MMC_CAP_CMD23,
>         MMC_CAP_CMD23,
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index a776f24..99390bb 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -962,7 +962,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>         regs = mci_readl(slot->host, UHS_REG);
>
>         /* DDR mode set */
> -       if (ios->timing == MMC_TIMING_UHS_DDR50)
> +       if (ios->timing == MMC_TIMING_MMC_DDR52)
>                 regs |= ((0x1 << slot->id) << 16);
>         else
>                 regs &= ~((0x1 << slot->id) << 16);
> --
> 1.7.0.4
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 3/7] mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-15 14:11 ` [PATCH 3/7] mmc: omap: " Seungwon Jeon
@ 2014-01-16 10:49   ` Ulf Hansson
  2014-01-16 11:07     ` Balaji T K
  2014-01-16 11:01   ` Balaji T K
  1 sibling, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-01-16 10:49 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: Chris Ball, Balaji T K, linux-mmc

On 15 January 2014 15:11, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Replaced UHS_DDR50 with MMC_DDR52.
>
> CC: Balaji T K <balajitk@ti.com>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
>  drivers/mmc/host/omap_hsmmc.c |    4 ++--
>  1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
> index dbd32ad..cca397e 100644
> --- a/drivers/mmc/host/omap_hsmmc.c
> +++ b/drivers/mmc/host/omap_hsmmc.c
> @@ -540,7 +540,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
>          *      - MMC/SD clock coming out of controller > 25MHz
>          */
>         if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
> -           (ios->timing != MMC_TIMING_UHS_DDR50) &&
> +           (ios->timing != MMC_TIMING_MMC_DDR52) &&

Even if I can't find anywhere that OMAP has enabled the corresponding
host caps for UHS SD cards, it still might be the case that OMAP
actually is able to handle the 1.8V I/O voltage switches and thus you
should like keep that.

You find the omap specific hack in omap_hsmmc_switch_opcond(). Ideally
the driver should be updated to implement the
host_ops->start_signal_voltage_switch and host_ops->card_busy instead.

Maybe some the OMAP guys can tell use more to be sure.

Kind regards
Ulf Hansson


>             ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
>                 regval = OMAP_HSMMC_READ(host->base, HCTL);
>                 if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
> @@ -560,7 +560,7 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
>         u32 con;
>
>         con = OMAP_HSMMC_READ(host->base, CON);
> -       if (ios->timing == MMC_TIMING_UHS_DDR50)
> +       if (ios->timing == MMC_TIMING_MMC_DDR52)
>                 con |= DDR;     /* configure in DDR mode */
>         else
>                 con &= ~DDR;
> --
> 1.7.0.4
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-15 14:10 ` [PATCH 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC Seungwon Jeon
@ 2014-01-16 10:50   ` Ulf Hansson
  2014-01-17 21:22     ` Ulf Hansson
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-01-16 10:50 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: Chris Ball, linux-mmc

On 15 January 2014 15:10, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> This change distinguishes DDR timing mode of current
> mixed usage to clarify device type.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>

Acked-by: Ulf Hansson <ulf.hansson@linaro.org>

> ---
>  drivers/mmc/core/debugfs.c |    3 +++
>  drivers/mmc/core/mmc.c     |    2 +-
>  include/linux/mmc/host.h   |    3 ++-
>  3 files changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index 54829c0..509229b 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>         case MMC_TIMING_UHS_DDR50:
>                 str = "sd uhs DDR50";
>                 break;
> +       case MMC_TIMING_MMC_DDR52:
> +               str = "mmc DDR52";
> +               break;
>         case MMC_TIMING_MMC_HS200:
>                 str = "mmc high-speed SDR200";
>                 break;
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 98e9eb0..6d91ff7 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -1261,7 +1261,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                                         goto err;
>                         }
>                         mmc_card_set_ddr_mode(card);
> -                       mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
> +                       mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
>                         mmc_set_bus_width(card->host, bus_width);
>                 }
>         }
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 99f5709..87b1f4f 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -58,7 +58,8 @@ struct mmc_ios {
>  #define MMC_TIMING_UHS_SDR50   5
>  #define MMC_TIMING_UHS_SDR104  6
>  #define MMC_TIMING_UHS_DDR50   7
> -#define MMC_TIMING_MMC_HS200   8
> +#define MMC_TIMING_MMC_DDR52   8
> +#define MMC_TIMING_MMC_HS200   9
>
>  #define MMC_SDR_MODE           0
>  #define MMC_1_2V_DDR_MODE      1
> --
> 1.7.0.4
>
>

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

* Re: [PATCH 5/7] mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-15 14:12 ` [PATCH 5/7] mmc: rtsx: " Seungwon Jeon
@ 2014-01-16 10:51   ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-01-16 10:51 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: Chris Ball, Wei WANG, Samuel Ortiz, linux-mmc

On 15 January 2014 15:12, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Added MMC_DDR52 as eMMC's DDR mode distinguished from SD-UHS.
>
> CC: Wei WANG <wei_wang@realsil.com.cn>
> CC: Samuel Ortiz <sameo@linux.intel.com>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

> ---
>  drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
>  1 files changed, 2 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
> index c46feda..752f003 100644
> --- a/drivers/mmc/host/rtsx_pci_sdmmc.c
> +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
> @@ -864,6 +864,7 @@ static int sd_set_timing(struct realtek_pci_sdmmc *host, unsigned char timing)
>                 rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0);
>                 break;
>
> +       case MMC_TIMING_MMC_DDR52:
>         case MMC_TIMING_UHS_DDR50:
>                 rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1,
>                                 0x0C | SD_ASYNC_FIFO_NOT_RST,
> @@ -944,6 +945,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>                 host->vpclk = true;
>                 host->double_clk = false;
>                 break;
> +       case MMC_TIMING_MMC_DDR52:
>         case MMC_TIMING_UHS_DDR50:
>         case MMC_TIMING_UHS_SDR25:
>                 host->ssc_depth = RTSX_SSC_DEPTH_1M;
> --
> 1.7.0.4
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 3/7] mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-15 14:11 ` [PATCH 3/7] mmc: omap: " Seungwon Jeon
  2014-01-16 10:49   ` Ulf Hansson
@ 2014-01-16 11:01   ` Balaji T K
  1 sibling, 0 replies; 182+ messages in thread
From: Balaji T K @ 2014-01-16 11:01 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: 'Chris Ball', linux-mmc

On Wednesday 15 January 2014 07:41 PM, Seungwon Jeon wrote:
> Replaced UHS_DDR50 with MMC_DDR52.
>
> CC: Balaji T K <balajitk@ti.com>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>

Looks good to me

Acked-by: Balaji T K <balajitk@ti.com>

> ---
>   drivers/mmc/host/omap_hsmmc.c |    4 ++--
>   1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
> index dbd32ad..cca397e 100644
> --- a/drivers/mmc/host/omap_hsmmc.c
> +++ b/drivers/mmc/host/omap_hsmmc.c
> @@ -540,7 +540,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
>   	 *	- MMC/SD clock coming out of controller > 25MHz
>   	 */
>   	if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
> -	    (ios->timing != MMC_TIMING_UHS_DDR50) &&
> +	    (ios->timing != MMC_TIMING_MMC_DDR52) &&
>   	    ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
>   		regval = OMAP_HSMMC_READ(host->base, HCTL);
>   		if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
> @@ -560,7 +560,7 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
>   	u32 con;
>
>   	con = OMAP_HSMMC_READ(host->base, CON);
> -	if (ios->timing == MMC_TIMING_UHS_DDR50)
> +	if (ios->timing == MMC_TIMING_MMC_DDR52)
>   		con |= DDR;	/* configure in DDR mode */
>   	else
>   		con &= ~DDR;
>


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

* Re: [PATCH 3/7] mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-16 10:49   ` Ulf Hansson
@ 2014-01-16 11:07     ` Balaji T K
  0 siblings, 0 replies; 182+ messages in thread
From: Balaji T K @ 2014-01-16 11:07 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: Seungwon Jeon, Chris Ball, linux-mmc

On Thursday 16 January 2014 04:19 PM, Ulf Hansson wrote:
> On 15 January 2014 15:11, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> Replaced UHS_DDR50 with MMC_DDR52.
>>
>> CC: Balaji T K <balajitk@ti.com>
>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> ---
>>   drivers/mmc/host/omap_hsmmc.c |    4 ++--
>>   1 files changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
>> index dbd32ad..cca397e 100644
>> --- a/drivers/mmc/host/omap_hsmmc.c
>> +++ b/drivers/mmc/host/omap_hsmmc.c
>> @@ -540,7 +540,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
>>           *      - MMC/SD clock coming out of controller > 25MHz
>>           */
>>          if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
>> -           (ios->timing != MMC_TIMING_UHS_DDR50) &&
>> +           (ios->timing != MMC_TIMING_MMC_DDR52) &&
>
> Even if I can't find anywhere that OMAP has enabled the corresponding
> host caps for UHS SD cards, it still might be the case that OMAP
> actually is able to handle the 1.8V I/O voltage switches and thus you
> should like keep that.
>
Hi,

Actually the ios->timing check currently there is for eMMC DDR,
So this change is needed.

> You find the omap specific hack in omap_hsmmc_switch_opcond(). Ideally

switch_opcond is for 1.8V MMC (MMC mobile) cards.

> the driver should be updated to implement the
> host_ops->start_signal_voltage_switch and host_ops->card_busy instead.
>

uhs support for sd card is not yet in mainline. voltage_switch and card_busy
ops will be get implemented for UHS sd card support.

Thanks and Regards,
Balaji T K

> Maybe some the OMAP guys can tell use more to be sure.
>
> Kind regards
> Ulf Hansson
>
>
>>              ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
>>                  regval = OMAP_HSMMC_READ(host->base, HCTL);
>>                  if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
>> @@ -560,7 +560,7 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
>>          u32 con;
>>
>>          con = OMAP_HSMMC_READ(host->base, CON);
>> -       if (ios->timing == MMC_TIMING_UHS_DDR50)
>> +       if (ios->timing == MMC_TIMING_MMC_DDR52)
>>                  con |= DDR;     /* configure in DDR mode */
>>          else
>>                  con &= ~DDR;
>> --
>> 1.7.0.4
>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* RE: [PATCH 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-16 10:20   ` Ulf Hansson
@ 2014-01-17 14:05     ` Seungwon Jeon
  2014-01-17 14:50     ` [PATCH v2 " Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-17 14:05 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'Chris Ball', 'Rickard Andersson',
	'Russell King', 'linux-mmc'

On Thu, January 16, 2014, Ulf Hansson wrote:
> On 15 January 2014 15:11, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Replaced UHS_DDR50 with MMC_DDR52.
> >
> > CC: Russell King <linux@arm.linux.org.uk>
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > ---
> >  drivers/mmc/host/mmci.c |    4 ++--
> >  1 files changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
> > index f320579..c348427 100644
> > --- a/drivers/mmc/host/mmci.c
> > +++ b/drivers/mmc/host/mmci.c
> > @@ -299,7 +299,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
> >         if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
> >                 clk |= MCI_ST_8BIT_BUS;
> >
> > -       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
> > +       if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
> 
> This will break DDR mode for UHS SD-cards.
> 
> >                 clk |= MCI_ST_UX500_NEG_EDGE;
> >
> >         mmci_write_clkreg(host, clk);
> > @@ -784,7 +784,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
> >                         mmci_write_clkreg(host, clk);
> >                 }
> >
> > -       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
> > +       if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
> >                 datactrl |= MCI_ST_DPSM_DDRMODE;
> 
> This will break DDR mode for UHS SD-cards.

Thank you for confirmation.
Will keep UHS mode and just add MMC's DDR52 mode.

Thanks,
Seungwon Jeon


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

* RE: [PATCH 4/7] mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-16 10:22   ` Ulf Hansson
@ 2014-01-17 14:36     ` Seungwon Jeon
  2014-01-28 13:08     ` Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-17 14:36 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'Chris Ball', 'Guennadi Liakhovetski',
	'linux-mmc'

On Thu, January 16, 2014, Ulf Hansson wrote:
> On 15 January 2014 15:12, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Replaced UHS_DDR50 with MMC_DDR52.
> >
> > CC: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > ---
> >  drivers/mmc/host/sh_mmcif.c |    9 +++++----
> >  1 files changed, 5 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
> > index 54730f4..656fbba 100644
> > --- a/drivers/mmc/host/sh_mmcif.c
> > +++ b/drivers/mmc/host/sh_mmcif.c
> > @@ -803,12 +803,13 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
> >                         break;
> >                 }
> >                 switch (host->timing) {
> > -               case MMC_TIMING_UHS_DDR50:
> > +               case MMC_TIMING_MMC_DDR52:
> 
> What about UHS SD cards?
I guess that there is no implementation related to voltage switch for UHS support.
MMC_TIMING_UHS_DDR50 looks like pointing eMMC's DDR.

Guennadi,
Can you check this more?

Thanks,
Seungwon Jeon

> 
> Kind regards
> Ulf Hansson
> 
> >                         /*
> >                          * MMC core will only set this timing, if the host
> > -                        * advertises the MMC_CAP_UHS_DDR50 capability. MMCIF
> > -                        * implementations with this capability, e.g. sh73a0,
> > -                        * will have to set it in their platform data.
> > +                        * advertises the MMC_CAP_1_8V_DDR/MMC_CAP_1_2V_DDR
> > +                        * capability. MMCIF implementations with this
> > +                        * capability, e.g. sh73a0, will have to set it
> > +                        * in their platform data.
> >                          */
> >                         tmp |= CMD_SET_DARS;
> >                         break;
> > --
> > 1.7.0.4
> >
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* [PATCH v2 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-16 10:20   ` Ulf Hansson
  2014-01-17 14:05     ` Seungwon Jeon
@ 2014-01-17 14:50     ` Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-17 14:50 UTC (permalink / raw)
  To: 'linux-mmc'
  Cc: 'Chris Ball', 'Rickard Andersson',
	'Russell King', 'Ulf Hansson'

Added MMC_DDR52 as eMMC's DDR mode distinguished from SD-UHS.

CC: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/mmci.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index f320579..92d40be 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -299,7 +299,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
 	if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
 		clk |= MCI_ST_8BIT_BUS;
 
-	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
+	    host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
 		clk |= MCI_ST_UX500_NEG_EDGE;
 
 	mmci_write_clkreg(host, clk);
@@ -784,7 +785,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 			mmci_write_clkreg(host, clk);
 		}
 
-	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
+	    host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
 		datactrl |= MCI_ST_DPSM_DDRMODE;
 
 	/*
-- 
1.7.0.4



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

* Re: [PATCH 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-16 10:50   ` Ulf Hansson
@ 2014-01-17 21:22     ` Ulf Hansson
  2014-01-20  3:55       ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-01-17 21:22 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: Chris Ball, linux-mmc

On 16 January 2014 11:50, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> On 15 January 2014 15:10, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> This change distinguishes DDR timing mode of current
>> mixed usage to clarify device type.
>>
>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>
> Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
>
>> ---
>>  drivers/mmc/core/debugfs.c |    3 +++
>>  drivers/mmc/core/mmc.c     |    2 +-
>>  include/linux/mmc/host.h   |    3 ++-
>>  3 files changed, 6 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
>> index 54829c0..509229b 100644
>> --- a/drivers/mmc/core/debugfs.c
>> +++ b/drivers/mmc/core/debugfs.c
>> @@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>>         case MMC_TIMING_UHS_DDR50:
>>                 str = "sd uhs DDR50";
>>                 break;
>> +       case MMC_TIMING_MMC_DDR52:
>> +               str = "mmc DDR52";

Just a minor thought. In the eMMC spec there are no such thing as
DDR52 mode. Only DDR is mentioned, should we maybe change to
"MMC_TIMING_MMC_DDR" to better reflect the spec?

Kind regards
Ulf Hansson

>> +               break;
>>         case MMC_TIMING_MMC_HS200:
>>                 str = "mmc high-speed SDR200";
>>                 break;
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index 98e9eb0..6d91ff7 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -1261,7 +1261,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>>                                         goto err;
>>                         }
>>                         mmc_card_set_ddr_mode(card);
>> -                       mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
>> +                       mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
>>                         mmc_set_bus_width(card->host, bus_width);
>>                 }
>>         }
>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> index 99f5709..87b1f4f 100644
>> --- a/include/linux/mmc/host.h
>> +++ b/include/linux/mmc/host.h
>> @@ -58,7 +58,8 @@ struct mmc_ios {
>>  #define MMC_TIMING_UHS_SDR50   5
>>  #define MMC_TIMING_UHS_SDR104  6
>>  #define MMC_TIMING_UHS_DDR50   7
>> -#define MMC_TIMING_MMC_HS200   8
>> +#define MMC_TIMING_MMC_DDR52   8
>> +#define MMC_TIMING_MMC_HS200   9
>>
>>  #define MMC_SDR_MODE           0
>>  #define MMC_1_2V_DDR_MODE      1
>> --
>> 1.7.0.4
>>
>>

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

* RE: [PATCH 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-17 21:22     ` Ulf Hansson
@ 2014-01-20  3:55       ` Seungwon Jeon
  2014-01-23  9:06         ` Ulf Hansson
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-20  3:55 UTC (permalink / raw)
  To: 'Ulf Hansson'; +Cc: 'Chris Ball', 'linux-mmc'

Hi Ulf,

On Sat, January 18, 2014, Ulf Hansson wrote:
> On 16 January 2014 11:50, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> > On 15 January 2014 15:10, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> This change distinguishes DDR timing mode of current
> >> mixed usage to clarify device type.
> >>
> >> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> >
> > Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
> >
> >> ---
> >>  drivers/mmc/core/debugfs.c |    3 +++
> >>  drivers/mmc/core/mmc.c     |    2 +-
> >>  include/linux/mmc/host.h   |    3 ++-
> >>  3 files changed, 6 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> >> index 54829c0..509229b 100644
> >> --- a/drivers/mmc/core/debugfs.c
> >> +++ b/drivers/mmc/core/debugfs.c
> >> @@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
> >>         case MMC_TIMING_UHS_DDR50:
> >>                 str = "sd uhs DDR50";
> >>                 break;
> >> +       case MMC_TIMING_MMC_DDR52:
> >> +               str = "mmc DDR52";
> 
> Just a minor thought. In the eMMC spec there are no such thing as
> DDR52 mode. Only DDR is mentioned, should we maybe change to
> "MMC_TIMING_MMC_DDR" to better reflect the spec?
In eMMC spec, DDR mode for high speed is up to 52MHz unlike SD.
Actually DDR52 is appeared in spec. And it helps to ensure the meaning.
Also, for distinguishing from HS200's DDR mode(HS400), it would be not bad to keep it.
It makes sense?

Thanks,
Seungwon Jeon

> 
> Kind regards
> Ulf Hansson
> 
> >> +               break;
> >>         case MMC_TIMING_MMC_HS200:
> >>                 str = "mmc high-speed SDR200";
> >>                 break;
> >> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >> index 98e9eb0..6d91ff7 100644
> >> --- a/drivers/mmc/core/mmc.c
> >> +++ b/drivers/mmc/core/mmc.c
> >> @@ -1261,7 +1261,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >>                                         goto err;
> >>                         }
> >>                         mmc_card_set_ddr_mode(card);
> >> -                       mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
> >> +                       mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
> >>                         mmc_set_bus_width(card->host, bus_width);
> >>                 }
> >>         }
> >> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> >> index 99f5709..87b1f4f 100644
> >> --- a/include/linux/mmc/host.h
> >> +++ b/include/linux/mmc/host.h
> >> @@ -58,7 +58,8 @@ struct mmc_ios {
> >>  #define MMC_TIMING_UHS_SDR50   5
> >>  #define MMC_TIMING_UHS_SDR104  6
> >>  #define MMC_TIMING_UHS_DDR50   7
> >> -#define MMC_TIMING_MMC_HS200   8
> >> +#define MMC_TIMING_MMC_DDR52   8
> >> +#define MMC_TIMING_MMC_HS200   9
> >>
> >>  #define MMC_SDR_MODE           0
> >>  #define MMC_1_2V_DDR_MODE      1
> >> --
> >> 1.7.0.4
> >>
> >>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-20  3:55       ` Seungwon Jeon
@ 2014-01-23  9:06         ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-01-23  9:06 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: Chris Ball, linux-mmc

On 20 January 2014 04:55, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Hi Ulf,
>
> On Sat, January 18, 2014, Ulf Hansson wrote:
>> On 16 January 2014 11:50, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>> > On 15 January 2014 15:10, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> >> This change distinguishes DDR timing mode of current
>> >> mixed usage to clarify device type.
>> >>
>> >> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> >
>> > Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
>> >
>> >> ---
>> >>  drivers/mmc/core/debugfs.c |    3 +++
>> >>  drivers/mmc/core/mmc.c     |    2 +-
>> >>  include/linux/mmc/host.h   |    3 ++-
>> >>  3 files changed, 6 insertions(+), 2 deletions(-)
>> >>
>> >> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
>> >> index 54829c0..509229b 100644
>> >> --- a/drivers/mmc/core/debugfs.c
>> >> +++ b/drivers/mmc/core/debugfs.c
>> >> @@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>> >>         case MMC_TIMING_UHS_DDR50:
>> >>                 str = "sd uhs DDR50";
>> >>                 break;
>> >> +       case MMC_TIMING_MMC_DDR52:
>> >> +               str = "mmc DDR52";
>>
>> Just a minor thought. In the eMMC spec there are no such thing as
>> DDR52 mode. Only DDR is mentioned, should we maybe change to
>> "MMC_TIMING_MMC_DDR" to better reflect the spec?
> In eMMC spec, DDR mode for high speed is up to 52MHz unlike SD.
> Actually DDR52 is appeared in spec. And it helps to ensure the meaning.
> Also, for distinguishing from HS200's DDR mode(HS400), it would be not bad to keep it.
> It makes sense?
>

Diving a bit deeper into the eMMC spec 5.0.

DDR52 is mentioned, you are correct, but it is not listed as a bus
speed mode. Have a look at chapter 5.3.2 Bus Speed Modes, there you
find the more correct name. "High Speed DDR".

"High Speed" indicates the interface can run up to 52 MHz. So maybe
the most proper name for this would be "MMC_TIMING_MMC_HS_DDR"? Still
I have no strong opinion, so if you favor MMC_TIMING_MMC_DDR52, I am
fine with it.

Kind regards
Ulf Hansson

> Thanks,
> Seungwon Jeon
>
>>
>> Kind regards
>> Ulf Hansson
>>
>> >> +               break;
>> >>         case MMC_TIMING_MMC_HS200:
>> >>                 str = "mmc high-speed SDR200";
>> >>                 break;
>> >> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> >> index 98e9eb0..6d91ff7 100644
>> >> --- a/drivers/mmc/core/mmc.c
>> >> +++ b/drivers/mmc/core/mmc.c
>> >> @@ -1261,7 +1261,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >>                                         goto err;
>> >>                         }
>> >>                         mmc_card_set_ddr_mode(card);
>> >> -                       mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
>> >> +                       mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
>> >>                         mmc_set_bus_width(card->host, bus_width);
>> >>                 }
>> >>         }
>> >> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> >> index 99f5709..87b1f4f 100644
>> >> --- a/include/linux/mmc/host.h
>> >> +++ b/include/linux/mmc/host.h
>> >> @@ -58,7 +58,8 @@ struct mmc_ios {
>> >>  #define MMC_TIMING_UHS_SDR50   5
>> >>  #define MMC_TIMING_UHS_SDR104  6
>> >>  #define MMC_TIMING_UHS_DDR50   7
>> >> -#define MMC_TIMING_MMC_HS200   8
>> >> +#define MMC_TIMING_MMC_DDR52   8
>> >> +#define MMC_TIMING_MMC_HS200   9
>> >>
>> >>  #define MMC_SDR_MODE           0
>> >>  #define MMC_1_2V_DDR_MODE      1
>> >> --
>> >> 1.7.0.4
>> >>
>> >>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

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

* RE: [PATCH 4/7] mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
  2014-01-16 10:22   ` Ulf Hansson
  2014-01-17 14:36     ` Seungwon Jeon
@ 2014-01-28 13:08     ` Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-01-28 13:08 UTC (permalink / raw)
  To: 'Guennadi Liakhovetski', 'Seungwon Jeon',
	'Ulf Hansson'
  Cc: 'Chris Ball', 'linux-mmc'

Hi Guennadi,

Do you have any idea for this change?
Could you check?

Thanks,
Seungwon Jeon

On Fri, January 17, 2014, Seungwon Jeon wrote:
> On Thu, January 16, 2014, Ulf Hansson wrote:
> > On 15 January 2014 15:12, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > > Replaced UHS_DDR50 with MMC_DDR52.
> > >
> > > CC: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > > ---
> > >  drivers/mmc/host/sh_mmcif.c |    9 +++++----
> > >  1 files changed, 5 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
> > > index 54730f4..656fbba 100644
> > > --- a/drivers/mmc/host/sh_mmcif.c
> > > +++ b/drivers/mmc/host/sh_mmcif.c
> > > @@ -803,12 +803,13 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
> > >                         break;
> > >                 }
> > >                 switch (host->timing) {
> > > -               case MMC_TIMING_UHS_DDR50:
> > > +               case MMC_TIMING_MMC_DDR52:
> >
> > What about UHS SD cards?
> I guess that there is no implementation related to voltage switch for UHS support.
> MMC_TIMING_UHS_DDR50 looks like pointing eMMC's DDR.
> 
> Guennadi,
> Can you check this more?
> 
> Thanks,
> Seungwon Jeon
> 
> >
> > Kind regards
> > Ulf Hansson
> >
> > >                         /*
> > >                          * MMC core will only set this timing, if the host
> > > -                        * advertises the MMC_CAP_UHS_DDR50 capability. MMCIF
> > > -                        * implementations with this capability, e.g. sh73a0,
> > > -                        * will have to set it in their platform data.
> > > +                        * advertises the MMC_CAP_1_8V_DDR/MMC_CAP_1_2V_DDR
> > > +                        * capability. MMCIF implementations with this
> > > +                        * capability, e.g. sh73a0, will have to set it
> > > +                        * in their platform data.
> > >                          */
> > >                         tmp |= CMD_SET_DARS;
> > >                         break;
> > > --
> > > 1.7.0.4
> > >
> > >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* [PATCH v2 0/7] mmc: distinguish DDR timing mode for eMMC/UHS
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (22 preceding siblings ...)
  2014-01-15 14:19 ` [PATCH 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
@ 2014-02-15 14:08 ` Seungwon Jeon
  2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
  2014-03-14 12:11   ` [PATCH RESEND " Seungwon Jeon
  2014-02-15 14:08 ` [PATCH v2 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC Seungwon Jeon
                   ` (12 subsequent siblings)
  36 siblings, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:08 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	rickard.andersson, linux, balajitk, g.liakhovetski, wei_wang,
	sameo, jh80.chung

These changes intend to distinguish two DDR timing modes related to eMMC & UHS.
Even though two modes are different actually, UHS_DDR50 is used as eMMC DDR mode.
MMC_TIMING_MMC_DDR52 mode is added.

Changes in V2:
	(2/7) Added MMC-DDR52 mode instead of replacing UHS-DDR50 in mmci

Seungwon Jeon (7):
  mmc: clarify DDR timing mode between SD-UHS and eMMC
  mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
  mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
  mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
  mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
  mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
  mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC

 drivers/mmc/core/debugfs.c        |    3 +++
 drivers/mmc/core/mmc.c            |    2 +-
 drivers/mmc/host/dw_mmc-exynos.c  |    3 +--
 drivers/mmc/host/dw_mmc.c         |    2 +-
 drivers/mmc/host/mmci.c           |    6 ++++--
 drivers/mmc/host/omap_hsmmc.c     |    4 ++--
 drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
 drivers/mmc/host/sdhci.c          |    4 +++-
 drivers/mmc/host/sh_mmcif.c       |    9 +++++----
 include/linux/mmc/host.h          |    3 ++-
 10 files changed, 24 insertions(+), 14 deletions(-)



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

* [PATCH v2 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (23 preceding siblings ...)
  2014-02-15 14:08 ` [PATCH v2 0/7] mmc: distinguish DDR timing mode for eMMC/UHS Seungwon Jeon
@ 2014-02-15 14:08 ` Seungwon Jeon
  2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
  2014-03-14 12:11   ` [PATCH RESEND " Seungwon Jeon
  2014-02-15 14:08 ` [PATCH v2 2/7] mmc: mmci: " Seungwon Jeon
                   ` (11 subsequent siblings)
  36 siblings, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:08 UTC (permalink / raw)
  To: linux-mmc; +Cc: 'Chris Ball', 'Ulf Hansson'

This change distinguishes DDR timing mode of current
mixed usage to clarify device type.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/debugfs.c |    3 +++
 drivers/mmc/core/mmc.c     |    2 +-
 include/linux/mmc/host.h   |    3 ++-
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 54829c0..509229b 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_UHS_DDR50:
 		str = "sd uhs DDR50";
 		break;
+	case MMC_TIMING_MMC_DDR52:
+		str = "mmc DDR52";
+		break;
 	case MMC_TIMING_MMC_HS200:
 		str = "mmc high-speed SDR200";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 98e9eb0..6d91ff7 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1261,7 +1261,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 					goto err;
 			}
 			mmc_card_set_ddr_mode(card);
-			mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
+			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
 			mmc_set_bus_width(card->host, bus_width);
 		}
 	}
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 99f5709..87b1f4f 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -58,7 +58,8 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_SDR50	5
 #define MMC_TIMING_UHS_SDR104	6
 #define MMC_TIMING_UHS_DDR50	7
-#define MMC_TIMING_MMC_HS200	8
+#define MMC_TIMING_MMC_DDR52	8
+#define MMC_TIMING_MMC_HS200	9
 
 #define MMC_SDR_MODE		0
 #define MMC_1_2V_DDR_MODE	1
-- 
1.7.0.4



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

* [PATCH v2 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (24 preceding siblings ...)
  2014-02-15 14:08 ` [PATCH v2 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC Seungwon Jeon
@ 2014-02-15 14:08 ` Seungwon Jeon
  2014-02-17 14:08   ` Ulf Hansson
                     ` (2 more replies)
  2014-02-15 14:09 ` [PATCH v2 3/7] mmc: omap: " Seungwon Jeon
                   ` (10 subsequent siblings)
  36 siblings, 3 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:08 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Russell King', 'Ulf Hansson',
	'Chris Ball', 'Rickard Andersson'

Added MMC_DDR52 as eMMC's DDR mode distinguished from SD-UHS.

CC: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/mmci.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index b931226..421d1fe 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -299,7 +299,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
 	if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
 		clk |= MCI_ST_8BIT_BUS;
 
-	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
+	    host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
 		clk |= MCI_ST_UX500_NEG_EDGE;
 
 	mmci_write_clkreg(host, clk);
@@ -784,7 +785,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 			mmci_write_clkreg(host, clk);
 		}
 
-	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
+	    host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
 		datactrl |= MCI_ST_DPSM_DDRMODE;
 
 	/*
-- 
1.7.0.4



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

* [PATCH v2 3/7] mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (25 preceding siblings ...)
  2014-02-15 14:08 ` [PATCH v2 2/7] mmc: mmci: " Seungwon Jeon
@ 2014-02-15 14:09 ` Seungwon Jeon
  2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
  2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
  2014-02-15 14:09 ` [PATCH v2 4/7] mmc: sh_mmcif: " Seungwon Jeon
                   ` (9 subsequent siblings)
  36 siblings, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:09 UTC (permalink / raw)
  To: linux-mmc; +Cc: 'Chris Ball', 'Balaji T K'

Replaced UHS_DDR50 with MMC_DDR52.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Balaji T K <balajitk@ti.com>
---
 drivers/mmc/host/omap_hsmmc.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index dbd32ad..cca397e 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -540,7 +540,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
 	 *	- MMC/SD clock coming out of controller > 25MHz
 	 */
 	if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
-	    (ios->timing != MMC_TIMING_UHS_DDR50) &&
+	    (ios->timing != MMC_TIMING_MMC_DDR52) &&
 	    ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
 		regval = OMAP_HSMMC_READ(host->base, HCTL);
 		if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
@@ -560,7 +560,7 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
 	u32 con;
 
 	con = OMAP_HSMMC_READ(host->base, CON);
-	if (ios->timing == MMC_TIMING_UHS_DDR50)
+	if (ios->timing == MMC_TIMING_MMC_DDR52)
 		con |= DDR;	/* configure in DDR mode */
 	else
 		con &= ~DDR;
-- 
1.7.0.4



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

* [PATCH v2 4/7] mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (26 preceding siblings ...)
  2014-02-15 14:09 ` [PATCH v2 3/7] mmc: omap: " Seungwon Jeon
@ 2014-02-15 14:09 ` Seungwon Jeon
  2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
  2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
  2014-02-15 14:09 ` [PATCH v2 5/7] mmc: rtsx: " Seungwon Jeon
                   ` (8 subsequent siblings)
  36 siblings, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:09 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Guennadi Liakhovetski'

Replaced UHS_DDR50 with MMC_DDR52.

CC: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/sh_mmcif.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 54730f4..656fbba 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -803,12 +803,13 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
 			break;
 		}
 		switch (host->timing) {
-		case MMC_TIMING_UHS_DDR50:
+		case MMC_TIMING_MMC_DDR52:
 			/*
 			 * MMC core will only set this timing, if the host
-			 * advertises the MMC_CAP_UHS_DDR50 capability. MMCIF
-			 * implementations with this capability, e.g. sh73a0,
-			 * will have to set it in their platform data.
+			 * advertises the MMC_CAP_1_8V_DDR/MMC_CAP_1_2V_DDR
+			 * capability. MMCIF implementations with this
+			 * capability, e.g. sh73a0, will have to set it
+			 * in their platform data.
 			 */
 			tmp |= CMD_SET_DARS;
 			break;
-- 
1.7.0.4



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

* [PATCH v2 5/7] mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (27 preceding siblings ...)
  2014-02-15 14:09 ` [PATCH v2 4/7] mmc: sh_mmcif: " Seungwon Jeon
@ 2014-02-15 14:09 ` Seungwon Jeon
  2014-03-07 13:31   ` [PATCH v3 " Seungwon Jeon
  2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
  2014-02-15 14:09 ` [PATCH v2 6/7] mmc: dw_mmc: " Seungwon Jeon
                   ` (7 subsequent siblings)
  36 siblings, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:09 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Wei WANG', 'Samuel Ortiz'

Added MMC_DDR52 as eMMC's DDR mode is distinguished from SD-UHS.

CC: Wei WANG <wei_wang@realsil.com.cn>
CC: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index c46feda..752f003 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -864,6 +864,7 @@ static int sd_set_timing(struct realtek_pci_sdmmc *host, unsigned char timing)
 		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0);
 		break;
 
+	case MMC_TIMING_MMC_DDR52:
 	case MMC_TIMING_UHS_DDR50:
 		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1,
 				0x0C | SD_ASYNC_FIFO_NOT_RST,
@@ -944,6 +945,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		host->vpclk = true;
 		host->double_clk = false;
 		break;
+	case MMC_TIMING_MMC_DDR52:
 	case MMC_TIMING_UHS_DDR50:
 	case MMC_TIMING_UHS_SDR25:
 		host->ssc_depth = RTSX_SSC_DEPTH_1M;
-- 
1.7.0.4



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

* [PATCH v2 6/7] mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (28 preceding siblings ...)
  2014-02-15 14:09 ` [PATCH v2 5/7] mmc: rtsx: " Seungwon Jeon
@ 2014-02-15 14:09 ` Seungwon Jeon
  2014-03-07 13:31   ` [PATCH v3 " Seungwon Jeon
  2014-03-14 12:12   ` [PATCH RESEMD " Seungwon Jeon
  2014-02-15 14:09 ` [PATCH v2 7/7] mmc: sdhci: " Seungwon Jeon
                   ` (6 subsequent siblings)
  36 siblings, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:09 UTC (permalink / raw)
  To: linux-mmc; +Cc: 'Chris Ball', 'Jaehoon Chung'

Replaced UHS_DDR50 with MMC_DDR52. And MMC_CAP_UHS_DDR50
is removed because of non-implementation of UHS signaling.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/dw_mmc-exynos.c |    3 +--
 drivers/mmc/host/dw_mmc.c        |    2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 3423c5e..b5a36b1 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -386,8 +386,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
 
 /* Common capabilities of Exynos4/Exynos5 SoC */
 static unsigned long exynos_dwmmc_caps[4] = {
-	MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
-		MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
+	MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
 	MMC_CAP_CMD23,
 	MMC_CAP_CMD23,
 	MMC_CAP_CMD23,
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 55cd110..7866d78 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -962,7 +962,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	regs = mci_readl(slot->host, UHS_REG);
 
 	/* DDR mode set */
-	if (ios->timing == MMC_TIMING_UHS_DDR50)
+	if (ios->timing == MMC_TIMING_MMC_DDR52)
 		regs |= ((0x1 << slot->id) << 16);
 	else
 		regs &= ~((0x1 << slot->id) << 16);
-- 
1.7.0.4



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

* [PATCH v2 7/7] mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (29 preceding siblings ...)
  2014-02-15 14:09 ` [PATCH v2 6/7] mmc: dw_mmc: " Seungwon Jeon
@ 2014-02-15 14:09 ` Seungwon Jeon
  2014-03-07 13:31   ` [PATCH v3 " Seungwon Jeon
  2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                   ` (5 subsequent siblings)
  36 siblings, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:09 UTC (permalink / raw)
  To: linux-mmc; +Cc: 'Chris Ball', 'Ulf Hansson'

Added MMC_DDR52 as eMMC's DDR mode is distinguished from SD-UHS.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/sdhci.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9ddef47..92e55dd 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1510,6 +1510,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 
 		/* In case of UHS-I modes, set High Speed Enable */
 		if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+		    (ios->timing == MMC_TIMING_MMC_DDR52) ||
 		    (ios->timing == MMC_TIMING_UHS_SDR50) ||
 		    (ios->timing == MMC_TIMING_UHS_SDR104) ||
 		    (ios->timing == MMC_TIMING_UHS_DDR50) ||
@@ -1570,7 +1571,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 				ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
 			else if (ios->timing == MMC_TIMING_UHS_SDR50)
 				ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
-			else if (ios->timing == MMC_TIMING_UHS_DDR50)
+			else if ((ios->timing == MMC_TIMING_UHS_DDR50) ||
+				 (ios->timing == MMC_TIMING_MMC_DDR52))
 				ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
 			sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
 		}
-- 
1.7.0.4



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

* [PATCH RESEND 0/5]  update selection of bus speed mode for eMMC
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (30 preceding siblings ...)
  2014-02-15 14:09 ` [PATCH v2 7/7] mmc: sdhci: " Seungwon Jeon
@ 2014-02-15 14:18 ` Seungwon Jeon
  2014-03-07 14:35   ` [PATCH v2 " Seungwon Jeon
                     ` (28 more replies)
  2014-02-15 14:18 ` [PATCH RESEND 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
                   ` (4 subsequent siblings)
  36 siblings, 29 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:18 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

This series contains the change for selection of bus speed mode.
Previous implementation is complicated and some sequence is duplicated.
And specially, HS400 mode eMMC5.0 is introduced this time.

- Continued/Updated since "[PATCH 0/3] mmc: update bus speed mode" series.
  (Applied some comments from Ulf Hansson, Jackey Shen.)
- Tested at EXYNOS SOC.

Seungwon Jeon (5):
  mmc: drop the speed mode of card's state
  mmc: identify available device type to select
  mmc: step power class after final selection of bus mode
  mmc: rework selection of bus speed mode
  mmc: add support for HS400 mode of eMMC5.0

 drivers/mmc/core/bus.c     |   10 +-
 drivers/mmc/core/core.c    |    3 +-
 drivers/mmc/core/debugfs.c |    5 +-
 drivers/mmc/core/mmc.c     |  690 ++++++++++++++++++++++++++++----------------
 drivers/mmc/core/sd.c      |   16 +-
 drivers/mmc/core/sd.h      |    1 -
 drivers/mmc/core/sdio.c    |    8 +-
 include/linux/mmc/card.h   |   32 +--
 include/linux/mmc/host.h   |   42 +++-
 include/linux/mmc/mmc.h    |   23 ++-
 10 files changed, 529 insertions(+), 301 deletions(-)



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

* [PATCH RESEND 1/5] mmc: drop the speed mode of card's state
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (31 preceding siblings ...)
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
@ 2014-02-15 14:18 ` Seungwon Jeon
  2014-02-17 14:38   ` Ulf Hansson
                     ` (2 more replies)
  2014-02-15 14:18 ` [PATCH RESEND 2/5] mmc: identify available device type to select Seungwon Jeon
                   ` (3 subsequent siblings)
  36 siblings, 3 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:18 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Timing mode identifier has same role and can take the place
of speed mode. This change removes all related speed mode.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/bus.c   |    9 +++++----
 drivers/mmc/core/core.c  |    3 +--
 drivers/mmc/core/mmc.c   |   11 +++--------
 drivers/mmc/core/sd.c    |   16 +++-------------
 drivers/mmc/core/sd.h    |    1 -
 drivers/mmc/core/sdio.c  |    8 ++------
 include/linux/mmc/card.h |   24 +++++++-----------------
 include/linux/mmc/host.h |   23 +++++++++++++++++++++++
 8 files changed, 44 insertions(+), 51 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 64145a3..e8a21fb 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -286,6 +286,7 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
 		return ERR_PTR(-ENOMEM);
 
 	card->host = host;
+	card->ios = &host->ios;
 
 	device_initialize(&card->dev);
 
@@ -349,16 +350,16 @@ int mmc_add_card(struct mmc_card *card)
 	if (mmc_host_is_spi(card->host)) {
 		pr_info("%s: new %s%s%s card on SPI\n",
 			mmc_hostname(card->host),
-			mmc_card_highspeed(card) ? "high speed " : "",
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_hs(card) ? "high speed " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			type);
 	} else {
 		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
-			(mmc_card_highspeed(card) ? "high speed " : ""),
+			(mmc_card_hs(card) ? "high speed " : ""),
 			(mmc_card_hs200(card) ? "HS200 " : ""),
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
 	}
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 098374b..88433bd 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2198,7 +2198,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
 	struct mmc_command cmd = {0};
 
-	if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+	if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
 		return 0;
 
 	cmd.opcode = MMC_SET_BLOCKLEN;
@@ -2281,7 +2281,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
 		}
 	}
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
 	if (mmc_host_is_spi(host)) {
 		host->ios.chip_select = MMC_CS_HIGH;
 		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 6d91ff7..613e641 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1088,11 +1088,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		} else {
 			if (card->ext_csd.hs_max_dtr > 52000000 &&
 			    host->caps2 & MMC_CAP2_HS200) {
-				mmc_card_set_hs200(card);
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
 			} else {
-				mmc_card_set_highspeed(card);
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
 			}
 		}
@@ -1103,10 +1101,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
+	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
 		if (max_dtr > card->ext_csd.hs_max_dtr)
 			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_highspeed(card) && (max_dtr > 52000000))
+		if (mmc_card_hs(card) && (max_dtr > 52000000))
 			max_dtr = 52000000;
 	} else if (max_dtr > card->csd.max_dtr) {
 		max_dtr = card->csd.max_dtr;
@@ -1117,7 +1115,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
 			&& (host->caps & MMC_CAP_1_8V_DDR))
 				ddr = MMC_1_8V_DDR_MODE;
@@ -1260,7 +1258,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 				if (err)
 					goto err;
 			}
-			mmc_card_set_ddr_mode(card);
 			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
 			mmc_set_bus_width(card->host, bus_width);
 		}
@@ -1495,7 +1492,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 		err = mmc_sleep(host);
 	else if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 
 	if (!err) {
 		mmc_power_off(host);
@@ -1625,7 +1621,6 @@ static int mmc_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 	mmc_claim_host(host);
 	ret = mmc_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 692fdb1..54dd3d1 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -895,7 +895,7 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if (max_dtr > card->sw_caps.hs_max_dtr)
 			max_dtr = card->sw_caps.hs_max_dtr;
 	} else if (max_dtr > card->csd.max_dtr) {
@@ -905,12 +905,6 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 	return max_dtr;
 }
 
-void mmc_sd_go_highspeed(struct mmc_card *card)
-{
-	mmc_card_set_highspeed(card);
-	mmc_set_timing(card->host, MMC_TIMING_SD_HS);
-}
-
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -985,16 +979,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_sd_init_uhs_card(card);
 		if (err)
 			goto free_card;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Attempt to change to high-speed (if supported)
 		 */
 		err = mmc_sd_switch_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto free_card;
 
@@ -1089,7 +1080,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
 
 	if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
+
 	if (!err) {
 		mmc_power_off(host);
 		mmc_card_set_suspended(host->card);
@@ -1198,7 +1189,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
 	ret = mmc_sd_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
index 4b34b24..aab824a 100644
--- a/drivers/mmc/core/sd.h
+++ b/drivers/mmc/core/sd.h
@@ -12,6 +12,5 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 	bool reinit);
 unsigned mmc_sd_get_max_clock(struct mmc_card *card);
 int mmc_sd_switch_hs(struct mmc_card *card);
-void mmc_sd_go_highspeed(struct mmc_card *card);
 
 #endif
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4d721c6..ef57d2d 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		/*
 		 * The SDIO specification doesn't mention how
 		 * the CIS transfer speed register relates to
@@ -733,7 +733,6 @@ try_again:
 		mmc_set_clock(host, card->cis.max_dtr);
 
 		if (card->cccr.high_speed) {
-			mmc_card_set_highspeed(card);
 			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		}
 
@@ -792,16 +791,13 @@ try_again:
 		err = mmc_sdio_init_uhs_card(card);
 		if (err)
 			goto remove;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Switch to high-speed (if supported).
 		 */
 		err = sdio_enable_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto remove;
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index b730272..e6ce178 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -194,6 +194,7 @@ struct sdio_cis {
 };
 
 struct mmc_host;
+struct mmc_ios;
 struct sdio_func;
 struct sdio_func_tuple;
 
@@ -239,6 +240,7 @@ struct mmc_part {
  */
 struct mmc_card {
 	struct mmc_host		*host;		/* the host this device belongs to */
+	struct mmc_ios		*ios;		/* bus settings of host */
 	struct device		dev;		/* the device */
 	u32			ocr;		/* the current OCR setting */
 	unsigned int		rca;		/* relative card address of device */
@@ -250,15 +252,11 @@ struct mmc_card {
 	unsigned int		state;		/* (our) card state */
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
 #define MMC_STATE_READONLY	(1<<1)		/* card is read-only */
-#define MMC_STATE_HIGHSPEED	(1<<2)		/* card is in high speed mode */
-#define MMC_STATE_BLOCKADDR	(1<<3)		/* card uses block-addressing */
-#define MMC_STATE_HIGHSPEED_DDR (1<<4)		/* card is in high speed mode */
-#define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra high speed mode */
-#define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
-#define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
-#define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
-#define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
-#define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
+#define MMC_STATE_BLOCKADDR	(1<<2)		/* card uses block-addressing */
+#define MMC_CARD_SDXC		(1<<3)		/* card is SDXC */
+#define MMC_CARD_REMOVED	(1<<4)		/* card has been removed */
+#define MMC_STATE_DOING_BKOPS	(1<<5)		/* card is doing BKOPS */
+#define MMC_STATE_SUSPENDED	(1<<6)		/* card is suspended */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -418,11 +416,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
-#define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
-#define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
-#define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
@@ -430,11 +424,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
-#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
-#define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
-#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_doing_bkops(c)	((c)->state |= MMC_STATE_DOING_BKOPS)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 87b1f4f..71977f4 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -17,6 +17,7 @@
 #include <linux/fault-inject.h>
 
 #include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -485,4 +486,26 @@ static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
 	return host->ios.clock;
 }
 #endif
+
+static inline int mmc_card_hs(struct mmc_card *card)
+{
+	return card->ios->timing == MMC_TIMING_SD_HS ||
+		card->ios->timing == MMC_TIMING_MMC_HS;
+}
+
+static inline int mmc_card_uhs(struct mmc_card *card)
+{
+	return card->ios->timing >= MMC_TIMING_UHS_SDR12 &&
+		card->ios->timing <= MMC_TIMING_UHS_DDR50;
+}
+
+static inline bool mmc_card_hs200(struct mmc_card *card)
+{
+	return card->ios->timing == MMC_TIMING_MMC_HS200;
+}
+
+static inline bool mmc_card_ddr52(struct mmc_card *card)
+{
+	return card->ios->timing == MMC_TIMING_MMC_DDR52;
+}
 #endif /* LINUX_MMC_HOST_H */
-- 
1.7.0.4



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

* [PATCH RESEND 2/5] mmc: identify available device type to select
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (32 preceding siblings ...)
  2014-02-15 14:18 ` [PATCH RESEND 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
@ 2014-02-15 14:18 ` Seungwon Jeon
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
  2014-02-15 14:23 ` [PATCH RESEND 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
                   ` (2 subsequent siblings)
  36 siblings, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:18 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Device types which are supported by both host and device
can be identified when EXT_CSD is read. There is no need to
check host's capability anymore.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
 include/linux/mmc/card.h |    6 ++-
 include/linux/mmc/host.h |    6 ---
 include/linux/mmc/mmc.h  |   12 +++++--
 4 files changed, 56 insertions(+), 45 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 613e641..1ea155a 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0;
+	unsigned int avail_type = 0;
 
-	if (card_type & EXT_CSD_CARD_TYPE_26)
+	if (caps & MMC_CAP_MMC_HIGHSPEED &&
+	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
 		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
+	}
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
-			card_type & EXT_CSD_CARD_TYPE_52)
+	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
 		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
+	}
 
-	if ((caps & MMC_CAP_1_8V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
-	    (caps & MMC_CAP_1_2V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
+	if (caps & MMC_CAP_1_8V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
 		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
+	}
 
-	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
-	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
+	if (caps & MMC_CAP_1_2V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
+	}
+
+	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
 		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
+		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
+	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
-	card->ext_csd.card_type = card_type;
+	card->mmc_avail_type = avail_type;
 }
 
 /*
@@ -708,6 +726,11 @@ static struct device_type mmc_type = {
 	.groups = mmc_attr_groups,
 };
 
+static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
+{
+	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+}
+
 /*
  * Select the PowerClass for the current bus width
  * If power class is defined for 4/8 bit bus in the
@@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
 
 	host = card->host;
 
-	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
-			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
 
-	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
-			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
 
 	/* If fails try again during next card power cycle */
@@ -1070,10 +1091,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	if (card->ext_csd.hs_max_dtr != 0) {
 		err = 0;
-		if (card->ext_csd.hs_max_dtr > 52000000 &&
-		    host->caps2 & MMC_CAP2_HS200)
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 			err = mmc_select_hs200(card);
-		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
+		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_HS_TIMING, 1,
 					 card->ext_csd.generic_cmd6_time);
@@ -1086,13 +1106,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			       mmc_hostname(card->host));
 			err = 0;
 		} else {
-			if (card->ext_csd.hs_max_dtr > 52000000 &&
-			    host->caps2 & MMC_CAP2_HS200) {
+			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
-			} else {
+			else
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-			}
 		}
 	}
 
@@ -1115,14 +1133,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_hs(card)) {
-		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-			&& (host->caps & MMC_CAP_1_8V_DDR))
-				ddr = MMC_1_8V_DDR_MODE;
-		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-			&& (host->caps & MMC_CAP_1_2V_DDR))
-				ddr = MMC_1_2V_DDR_MODE;
-	}
+	if (mmc_card_hs(card))
+		ddr = mmc_snoop_ddr(card);
 
 	/*
 	 * Indicate HS200 SDR mode (if supported).
@@ -1142,8 +1154,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		 * 3. set the clock to > 52Mhz <=200MHz and
 		 * 4. execute tuning for HS200
 		 */
-		if ((host->caps2 & MMC_CAP2_HS200) &&
-		    card->host->ops->execute_tuning) {
+		if (card->host->ops->execute_tuning) {
 			mmc_host_clk_hold(card->host);
 			err = card->host->ops->execute_tuning(card->host,
 				MMC_SEND_TUNING_BLOCK_HS200);
@@ -1252,7 +1263,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			 *
 			 * WARNING: eMMC rules are NOT the same as SD DDR
 			 */
-			if (ddr == MMC_1_2V_DDR_MODE) {
+			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
 				err = __mmc_set_signal_voltage(host,
 					MMC_SIGNAL_VOLTAGE_120);
 				if (err)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index e6ce178..c1ded09 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -68,7 +68,6 @@ struct mmc_ext_csd {
 #define MMC_HIGH_DDR_MAX_DTR	52000000
 #define MMC_HS200_MAX_DTR	200000000
 	unsigned int		sectors;
-	unsigned int		card_type;
 	unsigned int		hc_erase_size;		/* In sectors */
 	unsigned int		hc_erase_timeout;	/* In milliseconds */
 	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
@@ -298,7 +297,10 @@ struct mmc_card {
 	const char		**info;		/* info strings */
 	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
 
-	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+	union {
+		unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+		unsigned int		mmc_avail_type;	/* supported device type by both host and card */
+	};
 
 	struct dentry		*debugfs_root;
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 71977f4..66e632c 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -62,12 +62,6 @@ struct mmc_ios {
 #define MMC_TIMING_MMC_DDR52	8
 #define MMC_TIMING_MMC_HS200	9
 
-#define MMC_SDR_MODE		0
-#define MMC_1_2V_DDR_MODE	1
-#define MMC_1_8V_DDR_MODE	2
-#define MMC_1_2V_SDR_MODE	3
-#define MMC_1_8V_SDR_MODE	4
-
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
 #define MMC_SIGNAL_VOLTAGE_330	0
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 50bcde3..f734c0c 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -354,18 +354,22 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#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_MASK	0x3F	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
+				 EXT_CSD_CARD_TYPE_HS_52)
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
 					     /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
 					     /* DDR mode @1.2V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
 					| EXT_CSD_CARD_TYPE_DDR_1_2V)
-#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
-#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_8V	(1<<4)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_2V	(1<<5)	/* Card can run at 200MHz */
 						/* SDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS200_1_2V)
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
-- 
1.7.0.4



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

* [PATCH RESEND 3/5] mmc: step power class after final selection of bus mode
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (33 preceding siblings ...)
  2014-02-15 14:18 ` [PATCH RESEND 2/5] mmc: identify available device type to select Seungwon Jeon
@ 2014-02-15 14:23 ` Seungwon Jeon
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
  2014-02-15 14:24 ` [PATCH RESEND 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
  2014-02-15 14:24 ` [PATCH RESEND 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
  36 siblings, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:23 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Power class is changed once only after selection of bus modes
including speed and bus-width finishes finally.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/mmc.c |   77 +++++++++++++++++++++++++++++++----------------
 1 files changed, 51 insertions(+), 26 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 1ea155a..0d17395 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -737,8 +737,8 @@ static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
  * extended CSD register, select it by executing the
  * mmc_switch command.
  */
-static int mmc_select_powerclass(struct mmc_card *card,
-		unsigned int bus_width)
+static int __mmc_select_powerclass(struct mmc_card *card,
+				   unsigned int bus_width, u8 *ext_csd)
 {
 	int err = 0;
 	unsigned int pwrclass_val = 0;
@@ -759,13 +759,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
 
 	switch (1 << host->ios.vdd) {
 	case MMC_VDD_165_195:
-		if (host->ios.clock <= 26000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
 			pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
-		else if	(host->ios.clock <= 52000000)
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
 				card->ext_csd.raw_pwr_cl_52_195 :
 				card->ext_csd.raw_pwr_cl_ddr_52_195;
-		else if (host->ios.clock <= 200000000)
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
 			pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
 		break;
 	case MMC_VDD_27_28:
@@ -777,13 +777,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	case MMC_VDD_33_34:
 	case MMC_VDD_34_35:
 	case MMC_VDD_35_36:
-		if (host->ios.clock <= 26000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
 			pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
-		else if	(host->ios.clock <= 52000000)
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
 				card->ext_csd.raw_pwr_cl_52_360 :
 				card->ext_csd.raw_pwr_cl_ddr_52_360;
-		else if (host->ios.clock <= 200000000)
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
 			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
 		break;
 	default:
@@ -810,6 +810,44 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	return err;
 }
 
+static int mmc_select_powerclass(struct mmc_card *card, u8 *ext_csd)
+{
+	int err, ddr;
+	u32 bus_width, ext_csd_bits;
+	struct mmc_host *host;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if (!ext_csd)
+		return 0;
+
+	/* Power class selection is supported for versions >= 4.0 */
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	/* Power class values are defined only for 4/8 bit bus */
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ddr = mmc_snoop_ddr(card);
+	if (ddr)
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+	else
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
+
+	err = __mmc_select_powerclass(card, ext_csd_bits, ext_csd);
+	if (err)
+		pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
+			mmc_hostname(host), 1 << bus_width, ddr);
+
+	return err;
+}
+
 /*
  * Selects the desired buswidth and switch to the HS200 mode
  * if bus width set without error
@@ -1168,11 +1206,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
 		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
 				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-		err = mmc_select_powerclass(card, ext_csd_bits);
-		if (err)
-			pr_warning("%s: power class selection to bus width %d"
-				   " failed\n", mmc_hostname(card->host),
-				   1 << bus_width);
 	}
 
 	/*
@@ -1201,12 +1234,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			bus_width = bus_widths[idx];
 			if (bus_width == MMC_BUS_WIDTH_1)
 				ddr = 0; /* no DDR for 1-bit width */
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width);
 
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
@@ -1231,13 +1258,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		}
 
 		if (!err && ddr) {
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d ddr %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width, ddr);
-
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][1],
@@ -1275,6 +1295,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
+	 * Choose the power calss with selected bus interface
+	 */
+	mmc_select_powerclass(card, ext_csd);
+
+	/*
 	 * Enable HPI feature (if supported)
 	 */
 	if (card->ext_csd.hpi) {
-- 
1.7.0.4



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

* [PATCH RESEND 4/5] mmc: rework selection of bus speed mode
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (34 preceding siblings ...)
  2014-02-15 14:23 ` [PATCH RESEND 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
@ 2014-02-15 14:24 ` Seungwon Jeon
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
  2014-02-15 14:24 ` [PATCH RESEND 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
  36 siblings, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:24 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Current implementation for bus speed mode selection is too
complicated. This patch is to simplify the codes and remove
some duplicate parts.

The following changes are including:
* Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
* Rearranged the mode selection sequence with supported device type
* Adds maximum speed for HS200 mode(hs200_max_dtr)
* Adds field definition for HS_TIMING of EXT_CSD

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/debugfs.c |    2 +-
 drivers/mmc/core/mmc.c     |  443 +++++++++++++++++++++++++-------------------
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/mmc.h    |    4 +
 4 files changed, 257 insertions(+), 193 deletions(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 509229b..1f730db 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -139,7 +139,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 		str = "mmc DDR52";
 		break;
 	case MMC_TIMING_MMC_HS200:
-		str = "mmc high-speed SDR200";
+		str = "mmc HS200";
 		break;
 	default:
 		str = "invalid";
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0d17395..aa1441a 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -242,7 +242,7 @@ static void mmc_select_card_type(struct mmc_card *card)
 	struct mmc_host *host = card->host;
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
-	unsigned int hs_max_dtr = 0;
+	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
@@ -271,17 +271,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 
 	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
 	}
 
 	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
+	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
 }
 
@@ -849,37 +850,52 @@ static int mmc_select_powerclass(struct mmc_card *card, u8 *ext_csd)
 }
 
 /*
- * Selects the desired buswidth and switch to the HS200 mode
- * if bus width set without error
+ * Set the bus speed for the selected speed mode.
  */
-static int mmc_select_hs200(struct mmc_card *card)
+static void mmc_set_bus_speed(struct mmc_card *card)
+{
+	unsigned int max_dtr = (unsigned int)-1;
+
+	BUG_ON(!card);
+
+	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+		max_dtr = card->ext_csd.hs200_max_dtr;
+	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
+		max_dtr = card->ext_csd.hs_max_dtr;
+	else if (max_dtr > card->csd.max_dtr)
+		max_dtr = card->csd.max_dtr;
+
+	mmc_set_clock(card->host, max_dtr);
+}
+
+/*
+ * Select the bus width amoung 4-bit and 8-bit(SDR).
+ * If the bus width is changed successfully, return the slected width value.
+ * Zero is returned instead of error value if the wide width is not supported.
+ */
+static int mmc_select_bus_width(struct mmc_card *card)
 {
-	int idx, err = -EINVAL;
-	struct mmc_host *host;
 	static unsigned ext_csd_bits[] = {
-		EXT_CSD_BUS_WIDTH_4,
 		EXT_CSD_BUS_WIDTH_8,
+		EXT_CSD_BUS_WIDTH_4,
 	};
 	static unsigned bus_widths[] = {
-		MMC_BUS_WIDTH_4,
 		MMC_BUS_WIDTH_8,
+		MMC_BUS_WIDTH_4,
 	};
+	struct mmc_host *host;
+	unsigned idx, bus_width = 0;
+	int err = 0;
 
 	BUG_ON(!card);
 
 	host = card->host;
 
-	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
-
-	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
-
-	/* If fails try again during next card power cycle */
-	if (err)
-		goto err;
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
+	    !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
+		return 0;
 
-	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
 
 	/*
 	 * Unlike SD, MMC cards dont have a configuration register to notify
@@ -887,8 +903,7 @@ static int mmc_select_hs200(struct mmc_card *card)
 	 * 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 >= 0; idx--) {
-
+	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
@@ -903,25 +918,219 @@ static int mmc_select_hs200(struct mmc_card *card)
 		if (err)
 			continue;
 
-		mmc_set_bus_width(card->host, bus_widths[idx]);
+		bus_width = bus_widths[idx];
+		mmc_set_bus_width(host, bus_width);
 
+		/*
+		 * If controller can't handle bus width test,
+		 * compare ext_csd previously read in 1 bit mode
+		 * against ext_csd at new bus width
+		 */
 		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-			err = mmc_compare_ext_csds(card, bus_widths[idx]);
+			err = mmc_compare_ext_csds(card, bus_width);
 		else
-			err = mmc_bus_test(card, bus_widths[idx]);
-		if (!err)
+			err = mmc_bus_test(card, bus_width);
+
+		if (!err) {
+			err = bus_width;
 			break;
+		} else {
+			pr_warn("%s: switch to bus width %d failed\n",
+				mmc_hostname(card->host), ext_csd_bits[idx]);
+		}
 	}
 
-	/* switch to HS200 mode if bus width set successfully */
+	return err;
+}
+
+/*
+ * Switch to the high-speed mode
+ */
+static int mmc_select_hs(struct mmc_card *card)
+{
+	int err;
+
+	BUG_ON(!card);
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			 card->ext_csd.generic_cmd6_time);
 	if (!err)
+		mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+
+	return err;
+}
+
+/*
+ * Activate wide bus and DDR if supported.
+ */
+static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
+{
+	struct mmc_host *host;
+	u32 bus_width, ext_csd_bits;
+	int err = 0, ddr;
+
+	BUG_ON(!card);
+
+	ddr = mmc_snoop_ddr(card);
+	if (!(ddr & EXT_CSD_CARD_TYPE_DDR_52))
+		return 0;
+
+	host = card->host;
+	bus_width = host->ios.bus_width;
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+		EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_BUS_WIDTH,
+			ext_csd_bits,
+			card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width %d ddr failed\n",
+			mmc_hostname(host), 1 << bus_width);
+		return err;
+	}
+
+	/*
+	 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+	 * signaling.
+	 *
+	 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+	 *
+	 * 1.8V vccq at 3.3V core voltage (vcc) is not required
+	 * in the JEDEC spec for DDR.
+	 *
+	 * Do not force change in vccq since we are obviously
+	 * working and no change to vccq is needed.
+	 *
+	 * WARNING: eMMC rules are NOT the same as SD DDR
+	 */
+	if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		err = __mmc_set_signal_voltage(host,
+				MMC_SIGNAL_VOLTAGE_120);
+		if (err)
+			return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
+
+	return err;
+}
+
+/*
+ * For device supporting HS200 mode, the following sequence
+ * should be done before executing the tuning process.
+ * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
+ * 2. switch to HS200 mode
+ * 3. set the clock to > 52Mhz and <=200MHz
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+	int err = -EINVAL;
+	struct mmc_host *host;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+
+	/* If fails try again during next card power cycle */
+	if (err)
+		goto err;
+
+	/*
+	 * Set the bus width(4 or 8) with host's support and
+	 * switch to HS200 mode if bus width is set successfully.
+	 */
+	err = mmc_select_bus_width(card);
+	if (!IS_ERR_VALUE(err)) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_HS_TIMING, 2, 0);
+				 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
+				 card->ext_csd.generic_cmd6_time);
+		if (!err)
+			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+	}
 err:
 	return err;
 }
 
 /*
+ * Activate High Speed or HS200 mode if supported.
+ */
+static int mmc_select_timing(struct mmc_card *card)
+{
+	struct mmc_host *host;
+	int err = 0;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
+	     card->ext_csd.hs_max_dtr == 0))
+		goto bus_speed;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+		err = mmc_select_hs200(card);
+	else if(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
+		err = mmc_select_hs(card);
+
+	if (err && err != -EBADMSG)
+		return err;
+
+	if (err) {
+		pr_warn("%s: switch to %s failed\n",
+			mmc_card_hs(card) ? "high-speed" :
+			(mmc_card_hs200(card) ? "hs200" : ""),
+			mmc_hostname(card->host));
+		err = 0;
+	}
+
+bus_speed:
+	/*
+	 * Set the bus speed to the selected bus timing.
+	 * If timing is not selected, backward compatible is the default.
+	 */
+	mmc_set_bus_speed(card);
+	return err;
+}
+
+/*
+ * Execute tuning sequence to seek the proper bus operating
+ * conditions for HS200, which sends CMD21 to the device.
+ */
+static int mmc_hs200_tuning(struct mmc_card *card)
+{
+	int err = 0;
+	struct mmc_host *host;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if (card->host->ops->execute_tuning) {
+		mmc_host_clk_hold(card->host);
+		err = card->host->ops->execute_tuning(card->host,
+				MMC_SEND_TUNING_BLOCK_HS200);
+		mmc_host_clk_release(card->host);
+
+		if (err)
+			pr_warn("%s: tuning execution failed\n",
+				mmc_hostname(card->host));
+	}
+
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -931,9 +1140,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	struct mmc_card *oldcard)
 {
 	struct mmc_card *card;
-	int err, ddr = 0;
+	int err;
 	u32 cid[4];
-	unsigned int max_dtr;
 	u32 rocr;
 	u8 *ext_csd = NULL;
 
@@ -1125,172 +1333,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
-	 * Activate high speed (if supported)
+	 * Select timing interface
 	 */
-	if (card->ext_csd.hs_max_dtr != 0) {
-		err = 0;
-		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-			err = mmc_select_hs200(card);
-		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_HS_TIMING, 1,
-					 card->ext_csd.generic_cmd6_time);
-
-		if (err && err != -EBADMSG)
-			goto free_card;
-
-		if (err) {
-			pr_warning("%s: switch to highspeed failed\n",
-			       mmc_hostname(card->host));
-			err = 0;
-		} else {
-			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-				mmc_set_timing(card->host,
-					       MMC_TIMING_MMC_HS200);
-			else
-				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-		}
-	}
-
-	/*
-	 * Compute bus speed.
-	 */
-	max_dtr = (unsigned int)-1;
-
-	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
-		if (max_dtr > card->ext_csd.hs_max_dtr)
-			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_hs(card) && (max_dtr > 52000000))
-			max_dtr = 52000000;
-	} else if (max_dtr > card->csd.max_dtr) {
-		max_dtr = card->csd.max_dtr;
-	}
-
-	mmc_set_clock(host, max_dtr);
-
-	/*
-	 * Indicate DDR mode (if supported).
-	 */
-	if (mmc_card_hs(card))
-		ddr = mmc_snoop_ddr(card);
+	err = mmc_select_timing(card);
+	if (err)
+		goto free_card;
 
-	/*
-	 * Indicate HS200 SDR mode (if supported).
-	 */
 	if (mmc_card_hs200(card)) {
-		u32 ext_csd_bits;
-		u32 bus_width = card->host->ios.bus_width;
-
-		/*
-		 * For devices supporting HS200 mode, the bus width has
-		 * to be set before executing the tuning function. If
-		 * set before tuning, then device will respond with CRC
-		 * errors for responses on CMD line. So for HS200 the
-		 * sequence will be
-		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
-		 * 2. switch to HS200 mode
-		 * 3. set the clock to > 52Mhz <=200MHz and
-		 * 4. execute tuning for HS200
-		 */
-		if (card->host->ops->execute_tuning) {
-			mmc_host_clk_hold(card->host);
-			err = card->host->ops->execute_tuning(card->host,
-				MMC_SEND_TUNING_BLOCK_HS200);
-			mmc_host_clk_release(card->host);
-		}
-		if (err) {
-			pr_warning("%s: tuning execution failed\n",
-				   mmc_hostname(card->host));
+		err = mmc_hs200_tuning(card);
+		if (err)
 			goto err;
-		}
-
-		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
-				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-	}
-
-	/*
-	 * Activate wide bus and DDR (if supported).
-	 */
-	if (!mmc_card_hs200(card) &&
-	    (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
-	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
-		static unsigned ext_csd_bits[][2] = {
-			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
-			{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
-			{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
-		};
-		static unsigned bus_widths[] = {
-			MMC_BUS_WIDTH_8,
-			MMC_BUS_WIDTH_4,
-			MMC_BUS_WIDTH_1
-		};
-		unsigned idx, bus_width = 0;
-
-		if (host->caps & MMC_CAP_8_BIT_DATA)
-			idx = 0;
-		else
-			idx = 1;
-		for (; idx < ARRAY_SIZE(bus_widths); idx++) {
-			bus_width = bus_widths[idx];
-			if (bus_width == MMC_BUS_WIDTH_1)
-				ddr = 0; /* no DDR for 1-bit width */
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][0],
-					 card->ext_csd.generic_cmd6_time);
-			if (!err) {
-				mmc_set_bus_width(card->host, bus_width);
-
-				/*
-				 * If controller can't handle bus width test,
-				 * compare ext_csd previously read in 1 bit mode
-				 * against ext_csd at new bus width
-				 */
-				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					err = mmc_compare_ext_csds(card,
-						bus_width);
-				else
-					err = mmc_bus_test(card, bus_width);
-				if (!err)
-					break;
-			}
-		}
-
-		if (!err && ddr) {
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][1],
-					 card->ext_csd.generic_cmd6_time);
-		}
-		if (err) {
-			pr_warning("%s: switch to bus width %d ddr %d "
-				"failed\n", mmc_hostname(card->host),
-				1 << bus_width, ddr);
-			goto free_card;
-		} else if (ddr) {
-			/*
-			 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
-			 * signaling.
-			 *
-			 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
-			 *
-			 * 1.8V vccq at 3.3V core voltage (vcc) is not required
-			 * in the JEDEC spec for DDR.
-			 *
-			 * Do not force change in vccq since we are obviously
-			 * working and no change to vccq is needed.
-			 *
-			 * WARNING: eMMC rules are NOT the same as SD DDR
-			 */
-			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
-				err = __mmc_set_signal_voltage(host,
-					MMC_SIGNAL_VOLTAGE_120);
-				if (err)
-					goto err;
-			}
-			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
-			mmc_set_bus_width(card->host, bus_width);
+	} else if (mmc_card_hs(card)) {
+		/* Select the desired bus width optionally */
+		err = mmc_select_bus_width(card);
+		if (!IS_ERR_VALUE(err)) {
+			err = mmc_select_hs_ddr(card, ext_csd);
+			if (err)
+				goto err;
 		}
 	}
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c1ded09..974da1e 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -63,6 +63,7 @@ struct mmc_ext_csd {
 	unsigned int            power_off_longtime;     /* Units: ms */
 	u8			power_off_notification;	/* state */
 	unsigned int		hs_max_dtr;
+	unsigned int		hs200_max_dtr;
 #define MMC_HIGH_26_MAX_DTR	26000000
 #define MMC_HIGH_52_MAX_DTR	52000000
 #define MMC_HIGH_DDR_MAX_DTR	52000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f734c0c..f429f13 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -377,6 +377,10 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
 #define EXT_CSD_SEC_GB_CL_EN	BIT(4)
-- 
1.7.0.4



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

* [PATCH RESEND 5/5] mmc: add support for HS400 mode of eMMC5.0
  2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
                   ` (35 preceding siblings ...)
  2014-02-15 14:24 ` [PATCH RESEND 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
@ 2014-02-15 14:24 ` Seungwon Jeon
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
  36 siblings, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-15 14:24 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

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: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/core/bus.c     |    1 +
 drivers/mmc/core/debugfs.c |    3 +
 drivers/mmc/core/mmc.c     |  126 +++++++++++++++++++++++++++++++++++++++++---
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/host.h   |   15 +++++-
 include/linux/mmc/mmc.h    |    7 ++-
 6 files changed, 144 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index e8a21fb..d28ecf1 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -358,6 +358,7 @@ int mmc_add_card(struct mmc_card *card)
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_hs(card) ? "high speed " : ""),
+			mmc_card_hs400(card) ? "HS400 " :
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 1f730db..91eb162 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_MMC_HS200:
 		str = "mmc HS200";
 		break;
+	case MMC_TIMING_MMC_HS400:
+		str = "mmc HS400";
+		break;
 	default:
 		str = "invalid";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index aa1441a..62a900f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 static void mmc_select_card_type(struct mmc_card *card)
 {
 	struct mmc_host *host = card->host;
-	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
+	u8 card_type = card->ext_csd.raw_card_type;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
@@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
+	if (caps2 & MMC_CAP2_HS400_1_8V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS400_1_2V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
+	}
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
@@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
 		card->ext_csd.raw_pwr_cl_ddr_52_360 =
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
+		card->ext_csd.raw_pwr_cl_ddr_200_360 =
+			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
 	}
 
 	if (card->ext_csd.rev >= 5) {
@@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
 		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
 			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
 		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
-			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
+		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
+
 	if (err)
 		err = -EINVAL;
 
@@ -729,7 +746,8 @@ static struct device_type mmc_type = {
 
 static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
 {
-	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	return card->mmc_avail_type &
+		(EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_HS400);
 }
 
 /*
@@ -785,7 +803,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
 				card->ext_csd.raw_pwr_cl_52_360 :
 				card->ext_csd.raw_pwr_cl_ddr_52_360;
 		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
+			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
+				card->ext_csd.raw_pwr_cl_ddr_200_360 :
+				card->ext_csd.raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -858,7 +878,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
 
 	BUG_ON(!card);
 
-	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+	if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
+	     max_dtr > card->ext_csd.hs200_max_dtr)
 		max_dtr = card->ext_csd.hs200_max_dtr;
 	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
 		max_dtr = card->ext_csd.hs_max_dtr;
@@ -962,6 +983,30 @@ static int mmc_select_hs(struct mmc_card *card)
 }
 
 /*
+ * Revert to the high-speed mode from above speed
+ */
+static int mmc_revert_to_hs(struct mmc_card *card)
+{
+	BUG_ON(!card);
+
+	/*
+	 * CMD13, which is used to confirm the completion of timing
+	 * change, will be issued at higher speed timing condtion
+	 * rather than high-speed. If device has completed the change
+	 * to high-speed mode, it may not be proper timing to issue
+	 * command. Low speed supplies better timing margin than high
+	 * speed. Accordingly clock rate & timging should be chagned
+	 * ahead before actual switch.
+	 */
+	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+	mmc_set_bus_speed(card);
+
+	return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			  card->ext_csd.generic_cmd6_time);
+}
+
+/*
  * Activate wide bus and DDR if supported.
  */
 static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
@@ -1020,6 +1065,60 @@ static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
 	return err;
 }
 
+static int mmc_select_hs400(struct mmc_card *card, u8 *ext_csd)
+{
+	struct mmc_host *host;
+	int err = 0, ddr;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	ddr = mmc_snoop_ddr(card);
+
+	/*
+	 * The bus width is set to only 8 DDR in HS400 mode
+	 */
+	if (!(ddr & EXT_CSD_CARD_TYPE_HS400 &&
+	      card->host->ios.bus_width == MMC_BUS_WIDTH_8))
+		return 0;
+
+	/*
+	 * Before setting BUS_WIDTH for dual data rate operation,
+	 * HS_TIMING must be set to High Speed(0x1)
+	 */
+	err = mmc_revert_to_hs(card);
+	if (err) {
+		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
+			mmc_hostname(card->host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_DDR_BUS_WIDTH_8,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
+			mmc_hostname(card->host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to hs400 failed, err:%d\n",
+			 mmc_hostname(card->host), err);
+		return err;
+	}
+
+	mmc_set_timing(card->host, MMC_TIMING_MMC_HS400);
+	mmc_set_bus_speed(card);
+
+	return 0;
+}
+
 /*
  * For device supporting HS200 mode, the following sequence
  * should be done before executing the tuning process.
@@ -1055,7 +1154,16 @@ static int mmc_select_hs200(struct mmc_card *card)
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
 				 card->ext_csd.generic_cmd6_time);
-		if (!err)
+		if (err)
+			goto err;
+
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
+			/*
+			 * Timing should be adjusted to the HS400 target
+			 * operation frequency for tuning process
+			 */
+			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
+		else
 			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
 	}
 err:
@@ -1105,7 +1213,7 @@ bus_speed:
 
 /*
  * Execute tuning sequence to seek the proper bus operating
- * conditions for HS200, which sends CMD21 to the device.
+ * conditions for HS200 and HS400, which sends CMD21 to the device.
  */
 static int mmc_hs200_tuning(struct mmc_card *card)
 {
@@ -1343,6 +1451,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_hs200_tuning(card);
 		if (err)
 			goto err;
+
+		err = mmc_select_hs400(card, ext_csd);
+		if (err)
+			goto err;
 	} else if (mmc_card_hs(card)) {
 		/* Select the desired bus width optionally */
 		err = mmc_select_bus_width(card);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 974da1e..30a81dc 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -110,6 +110,7 @@ struct mmc_ext_csd {
 	u8			raw_pwr_cl_200_360;	/* 237 */
 	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
 	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
+	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
 	u8			raw_bkops_status;	/* 246 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 66e632c..7c0e277 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -61,6 +61,8 @@ struct mmc_ios {
 #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_HS400_TUNING 11
 
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
@@ -278,6 +280,10 @@ struct mmc_host {
 				 MMC_CAP2_PACKED_WR)
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
 #define MMC_CAP2_SANITIZE	(1 << 15)		/* Support Sanitize */
+#define MMC_CAP2_HS400_1_8V	(1 << 16)	/* Can support HS400 1.8V */
+#define MMC_CAP2_HS400_1_2V	(1 << 17)	/* Can support HS400 1.2V */
+#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
+				 MMC_CAP2_HS400_1_2V)
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
@@ -495,11 +501,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
 
 static inline bool mmc_card_hs200(struct mmc_card *card)
 {
-	return card->ios->timing == MMC_TIMING_MMC_HS200;
+	return card->ios->timing == MMC_TIMING_MMC_HS200 ||
+		card->ios->timing == MMC_TIMING_MMC_HS400_TUNING;
 }
 
 static inline bool mmc_card_ddr52(struct mmc_card *card)
 {
 	return card->ios->timing == MMC_TIMING_MMC_DDR52;
 }
+
+static inline bool mmc_card_hs400(struct mmc_card *card)
+{
+	return card->ios->timing == MMC_TIMING_MMC_HS400;
+}
+
 #endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f429f13..64ec963 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -325,6 +325,7 @@ struct _mmc_csd {
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
 #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
 #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
 #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
@@ -354,7 +355,6 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
 #define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
@@ -370,6 +370,10 @@ struct _mmc_csd {
 						/* SDR mode @1.2V I/O */
 #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	(1<<6)	/* Card can run at 200MHz DDR, 1.8V */
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
@@ -380,6 +384,7 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
-- 
1.7.0.4



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

* Re: [PATCH v2 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:08 ` [PATCH v2 2/7] mmc: mmci: " Seungwon Jeon
@ 2014-02-17 14:08   ` Ulf Hansson
  2014-02-18 13:34     ` Seungwon Jeon
  2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
  2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
  2 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-02-17 14:08 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: linux-mmc, Russell King, Chris Ball, Rickard Andersson

On 15 February 2014 15:08, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Added MMC_DDR52 as eMMC's DDR mode distinguished from SD-UHS.
>
> CC: Russell King <linux@arm.linux.org.uk>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>

Acked-by: Ulf Hansson <ulf.hansson@linaro.org>

Do note, normally Russell takes patches for mmci.

In this case I think it's important that the complete set gets merged
together. Especially since patch 1, on it's own, actually breaks
support for MMC DDR mode for some host drivers.

Kind regards
Ulf Hansson

> ---
>  drivers/mmc/host/mmci.c |    6 ++++--
>  1 files changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
> index b931226..421d1fe 100644
> --- a/drivers/mmc/host/mmci.c
> +++ b/drivers/mmc/host/mmci.c
> @@ -299,7 +299,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
>         if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
>                 clk |= MCI_ST_8BIT_BUS;
>
> -       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
> +       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
> +           host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
>                 clk |= MCI_ST_UX500_NEG_EDGE;
>
>         mmci_write_clkreg(host, clk);
> @@ -784,7 +785,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
>                         mmci_write_clkreg(host, clk);
>                 }
>
> -       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
> +       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
> +           host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
>                 datactrl |= MCI_ST_DPSM_DDRMODE;
>
>         /*
> --
> 1.7.0.4
>
>

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

* Re: [PATCH RESEND 1/5] mmc: drop the speed mode of card's state
  2014-02-15 14:18 ` [PATCH RESEND 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
@ 2014-02-17 14:38   ` Ulf Hansson
  2014-02-18 13:43     ` Seungwon Jeon
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
  2 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-02-17 14:38 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 15 February 2014 15:18, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Timing mode identifier has same role and can take the place
> of speed mode. This change removes all related speed mode.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
>  drivers/mmc/core/bus.c   |    9 +++++----
>  drivers/mmc/core/core.c  |    3 +--
>  drivers/mmc/core/mmc.c   |   11 +++--------
>  drivers/mmc/core/sd.c    |   16 +++-------------
>  drivers/mmc/core/sd.h    |    1 -
>  drivers/mmc/core/sdio.c  |    8 ++------
>  include/linux/mmc/card.h |   24 +++++++-----------------
>  include/linux/mmc/host.h |   23 +++++++++++++++++++++++
>  8 files changed, 44 insertions(+), 51 deletions(-)
>
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index 64145a3..e8a21fb 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -286,6 +286,7 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
>                 return ERR_PTR(-ENOMEM);
>
>         card->host = host;
> +       card->ios = &host->ios;

Please remove this. The ios is connected and controlled by the host.

Once you need the ios pointer I think it's better to reference it from
the card->host.

>
>         device_initialize(&card->dev);
>
> @@ -349,16 +350,16 @@ int mmc_add_card(struct mmc_card *card)
>         if (mmc_host_is_spi(card->host)) {
>                 pr_info("%s: new %s%s%s card on SPI\n",
>                         mmc_hostname(card->host),
> -                       mmc_card_highspeed(card) ? "high speed " : "",
> -                       mmc_card_ddr_mode(card) ? "DDR " : "",
> +                       mmc_card_hs(card) ? "high speed " : "",
> +                       mmc_card_ddr52(card) ? "DDR " : "",
>                         type);
>         } else {
>                 pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>                         mmc_hostname(card->host),
>                         mmc_card_uhs(card) ? "ultra high speed " :
> -                       (mmc_card_highspeed(card) ? "high speed " : ""),
> +                       (mmc_card_hs(card) ? "high speed " : ""),
>                         (mmc_card_hs200(card) ? "HS200 " : ""),
> -                       mmc_card_ddr_mode(card) ? "DDR " : "",
> +                       mmc_card_ddr52(card) ? "DDR " : "",
>                         uhs_bus_speed_mode, type, card->rca);
>         }
>
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 098374b..88433bd 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -2198,7 +2198,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
>  {
>         struct mmc_command cmd = {0};
>
> -       if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
> +       if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
>                 return 0;
>
>         cmd.opcode = MMC_SET_BLOCKLEN;
> @@ -2281,7 +2281,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
>                 }
>         }
>
> -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
>         if (mmc_host_is_spi(host)) {
>                 host->ios.chip_select = MMC_CS_HIGH;
>                 host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 6d91ff7..613e641 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -1088,11 +1088,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                 } else {
>                         if (card->ext_csd.hs_max_dtr > 52000000 &&
>                             host->caps2 & MMC_CAP2_HS200) {
> -                               mmc_card_set_hs200(card);
>                                 mmc_set_timing(card->host,
>                                                MMC_TIMING_MMC_HS200);
>                         } else {
> -                               mmc_card_set_highspeed(card);
>                                 mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>                         }
>                 }
> @@ -1103,10 +1101,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>          */
>         max_dtr = (unsigned int)-1;
>
> -       if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
> +       if (mmc_card_hs(card) || mmc_card_hs200(card)) {
>                 if (max_dtr > card->ext_csd.hs_max_dtr)
>                         max_dtr = card->ext_csd.hs_max_dtr;
> -               if (mmc_card_highspeed(card) && (max_dtr > 52000000))
> +               if (mmc_card_hs(card) && (max_dtr > 52000000))
>                         max_dtr = 52000000;
>         } else if (max_dtr > card->csd.max_dtr) {
>                 max_dtr = card->csd.max_dtr;
> @@ -1117,7 +1115,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>         /*
>          * Indicate DDR mode (if supported).
>          */
> -       if (mmc_card_highspeed(card)) {
> +       if (mmc_card_hs(card)) {
>                 if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
>                         && (host->caps & MMC_CAP_1_8V_DDR))
>                                 ddr = MMC_1_8V_DDR_MODE;
> @@ -1260,7 +1258,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                                 if (err)
>                                         goto err;
>                         }
> -                       mmc_card_set_ddr_mode(card);
>                         mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
>                         mmc_set_bus_width(card->host, bus_width);
>                 }
> @@ -1495,7 +1492,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
>                 err = mmc_sleep(host);
>         else if (!mmc_host_is_spi(host))
>                 err = mmc_deselect_cards(host);
> -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
>
>         if (!err) {
>                 mmc_power_off(host);
> @@ -1625,7 +1621,6 @@ static int mmc_power_restore(struct mmc_host *host)
>  {
>         int ret;
>
> -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
>         mmc_claim_host(host);
>         ret = mmc_init_card(host, host->card->ocr, host->card);
>         mmc_release_host(host);
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index 692fdb1..54dd3d1 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -895,7 +895,7 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
>  {
>         unsigned max_dtr = (unsigned int)-1;
>
> -       if (mmc_card_highspeed(card)) {
> +       if (mmc_card_hs(card)) {
>                 if (max_dtr > card->sw_caps.hs_max_dtr)
>                         max_dtr = card->sw_caps.hs_max_dtr;
>         } else if (max_dtr > card->csd.max_dtr) {
> @@ -905,12 +905,6 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
>         return max_dtr;
>  }
>
> -void mmc_sd_go_highspeed(struct mmc_card *card)
> -{
> -       mmc_card_set_highspeed(card);
> -       mmc_set_timing(card->host, MMC_TIMING_SD_HS);
> -}
> -
>  /*
>   * Handle the detection and initialisation of a card.
>   *
> @@ -985,16 +979,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
>                 err = mmc_sd_init_uhs_card(card);
>                 if (err)
>                         goto free_card;
> -
> -               /* Card is an ultra-high-speed card */
> -               mmc_card_set_uhs(card);
>         } else {
>                 /*
>                  * Attempt to change to high-speed (if supported)
>                  */
>                 err = mmc_sd_switch_hs(card);
>                 if (err > 0)
> -                       mmc_sd_go_highspeed(card);
> +                       mmc_set_timing(card->host, MMC_TIMING_SD_HS);
>                 else if (err)
>                         goto free_card;
>
> @@ -1089,7 +1080,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
>
>         if (!mmc_host_is_spi(host))
>                 err = mmc_deselect_cards(host);
> -       host->card->state &= ~MMC_STATE_HIGHSPEED;
> +
>         if (!err) {
>                 mmc_power_off(host);
>                 mmc_card_set_suspended(host->card);
> @@ -1198,7 +1189,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
>  {
>         int ret;
>
> -       host->card->state &= ~MMC_STATE_HIGHSPEED;
>         mmc_claim_host(host);
>         ret = mmc_sd_init_card(host, host->card->ocr, host->card);
>         mmc_release_host(host);
> diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
> index 4b34b24..aab824a 100644
> --- a/drivers/mmc/core/sd.h
> +++ b/drivers/mmc/core/sd.h
> @@ -12,6 +12,5 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
>         bool reinit);
>  unsigned mmc_sd_get_max_clock(struct mmc_card *card);
>  int mmc_sd_switch_hs(struct mmc_card *card);
> -void mmc_sd_go_highspeed(struct mmc_card *card);
>
>  #endif
> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> index 4d721c6..ef57d2d 100644
> --- a/drivers/mmc/core/sdio.c
> +++ b/drivers/mmc/core/sdio.c
> @@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
>  {
>         unsigned max_dtr;
>
> -       if (mmc_card_highspeed(card)) {
> +       if (mmc_card_hs(card)) {
>                 /*
>                  * The SDIO specification doesn't mention how
>                  * the CIS transfer speed register relates to
> @@ -733,7 +733,6 @@ try_again:
>                 mmc_set_clock(host, card->cis.max_dtr);
>
>                 if (card->cccr.high_speed) {
> -                       mmc_card_set_highspeed(card);
>                         mmc_set_timing(card->host, MMC_TIMING_SD_HS);
>                 }
>
> @@ -792,16 +791,13 @@ try_again:
>                 err = mmc_sdio_init_uhs_card(card);
>                 if (err)
>                         goto remove;
> -
> -               /* Card is an ultra-high-speed card */
> -               mmc_card_set_uhs(card);
>         } else {
>                 /*
>                  * Switch to high-speed (if supported).
>                  */
>                 err = sdio_enable_hs(card);
>                 if (err > 0)
> -                       mmc_sd_go_highspeed(card);
> +                       mmc_set_timing(card->host, MMC_TIMING_SD_HS);
>                 else if (err)
>                         goto remove;
>
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index b730272..e6ce178 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -194,6 +194,7 @@ struct sdio_cis {
>  };
>
>  struct mmc_host;
> +struct mmc_ios;
>  struct sdio_func;
>  struct sdio_func_tuple;
>
> @@ -239,6 +240,7 @@ struct mmc_part {
>   */
>  struct mmc_card {
>         struct mmc_host         *host;          /* the host this device belongs to */
> +       struct mmc_ios          *ios;           /* bus settings of host */

Please remove, see comment above.

>         struct device           dev;            /* the device */
>         u32                     ocr;            /* the current OCR setting */
>         unsigned int            rca;            /* relative card address of device */
> @@ -250,15 +252,11 @@ struct mmc_card {
>         unsigned int            state;          /* (our) card state */
>  #define MMC_STATE_PRESENT      (1<<0)          /* present in sysfs */
>  #define MMC_STATE_READONLY     (1<<1)          /* card is read-only */
> -#define MMC_STATE_HIGHSPEED    (1<<2)          /* card is in high speed mode */
> -#define MMC_STATE_BLOCKADDR    (1<<3)          /* card uses block-addressing */
> -#define MMC_STATE_HIGHSPEED_DDR (1<<4)         /* card is in high speed mode */
> -#define MMC_STATE_ULTRAHIGHSPEED (1<<5)                /* card is in ultra high speed mode */
> -#define MMC_CARD_SDXC          (1<<6)          /* card is SDXC */
> -#define MMC_CARD_REMOVED       (1<<7)          /* card has been removed */
> -#define MMC_STATE_HIGHSPEED_200        (1<<8)          /* card is in HS200 mode */
> -#define MMC_STATE_DOING_BKOPS  (1<<10)         /* card is doing BKOPS */
> -#define MMC_STATE_SUSPENDED    (1<<11)         /* card is suspended */
> +#define MMC_STATE_BLOCKADDR    (1<<2)          /* card uses block-addressing */
> +#define MMC_CARD_SDXC          (1<<3)          /* card is SDXC */
> +#define MMC_CARD_REMOVED       (1<<4)          /* card has been removed */
> +#define MMC_STATE_DOING_BKOPS  (1<<5)          /* card is doing BKOPS */
> +#define MMC_STATE_SUSPENDED    (1<<6)          /* card is suspended */
>         unsigned int            quirks;         /* card quirks */
>  #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
> @@ -418,11 +416,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
>
>  #define mmc_card_present(c)    ((c)->state & MMC_STATE_PRESENT)
>  #define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
> -#define mmc_card_highspeed(c)  ((c)->state & MMC_STATE_HIGHSPEED)
> -#define mmc_card_hs200(c)      ((c)->state & MMC_STATE_HIGHSPEED_200)
>  #define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
> -#define mmc_card_ddr_mode(c)   ((c)->state & MMC_STATE_HIGHSPEED_DDR)
> -#define mmc_card_uhs(c)                ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
>  #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
>  #define mmc_card_removed(c)    ((c) && ((c)->state & MMC_CARD_REMOVED))
>  #define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
> @@ -430,11 +424,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
>
>  #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
>  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
> -#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
> -#define mmc_card_set_hs200(c)  ((c)->state |= MMC_STATE_HIGHSPEED_200)
>  #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
> -#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
> -#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
>  #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
>  #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
>  #define mmc_card_set_doing_bkops(c)    ((c)->state |= MMC_STATE_DOING_BKOPS)
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 87b1f4f..71977f4 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -17,6 +17,7 @@
>  #include <linux/fault-inject.h>
>
>  #include <linux/mmc/core.h>
> +#include <linux/mmc/card.h>
>  #include <linux/mmc/pm.h>
>
>  struct mmc_ios {
> @@ -485,4 +486,26 @@ static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
>         return host->ios.clock;
>  }
>  #endif
> +
> +static inline int mmc_card_hs(struct mmc_card *card)
> +{
> +       return card->ios->timing == MMC_TIMING_SD_HS ||
> +               card->ios->timing == MMC_TIMING_MMC_HS;
> +}
> +
> +static inline int mmc_card_uhs(struct mmc_card *card)
> +{
> +       return card->ios->timing >= MMC_TIMING_UHS_SDR12 &&
> +               card->ios->timing <= MMC_TIMING_UHS_DDR50;
> +}
> +
> +static inline bool mmc_card_hs200(struct mmc_card *card)
> +{
> +       return card->ios->timing == MMC_TIMING_MMC_HS200;
> +}
> +
> +static inline bool mmc_card_ddr52(struct mmc_card *card)
> +{
> +       return card->ios->timing == MMC_TIMING_MMC_DDR52;
> +}
>  #endif /* LINUX_MMC_HOST_H */
> --
> 1.7.0.4
>
>

Nice clean-up!

Besides my minor comment above, you have my ack.

Kind regards
Ulf Hansson

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

* Re: [PATCH 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-01-15 14:19 ` [PATCH 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
@ 2014-02-18 10:24   ` Jackey Shen
  2014-02-18 13:31     ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Jackey Shen @ 2014-02-18 10:24 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Alim Akhtar',
	linux-mmc

On Wed, Jan 15, 2014 at 11:19:32PM +0900, Seungwon Jeon wrote:
> 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: Seungwon Jeon <tgih.jun@samsung.com>
> ---
>  drivers/mmc/core/bus.c     |    1 +
>  drivers/mmc/core/debugfs.c |    3 +
>  drivers/mmc/core/mmc.c     |  126 +++++++++++++++++++++++++++++++++++++++++---
>  include/linux/mmc/card.h   |    1 +
>  include/linux/mmc/host.h   |   15 +++++-
>  include/linux/mmc/mmc.h    |    7 ++-
>  6 files changed, 144 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index e8a21fb..d28ecf1 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -358,6 +358,7 @@ int mmc_add_card(struct mmc_card *card)
>  			mmc_hostname(card->host),
>  			mmc_card_uhs(card) ? "ultra high speed " :
>  			(mmc_card_hs(card) ? "high speed " : ""),
> +			mmc_card_hs400(card) ? "HS400 " :
>  			(mmc_card_hs200(card) ? "HS200 " : ""),
>  			mmc_card_ddr52(card) ? "DDR " : "",
>  			uhs_bus_speed_mode, type, card->rca);
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index 1f730db..91eb162 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>  	case MMC_TIMING_MMC_HS200:
>  		str = "mmc HS200";
>  		break;
> +	case MMC_TIMING_MMC_HS400:
> +		str = "mmc HS400";
> +		break;
>  	default:
>  		str = "invalid";
>  		break;
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 6ce5ff3..f3c899d 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
>  static void mmc_select_card_type(struct mmc_card *card)
>  {
>  	struct mmc_host *host = card->host;
> -	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> +	u8 card_type = card->ext_csd.raw_card_type;
>  	u32 caps = host->caps, caps2 = host->caps2;
>  	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>  	unsigned int avail_type = 0;
> @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
>  		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>  	}
>  
> +	if (caps2 & MMC_CAP2_HS400_1_8V &&
> +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> +	}
> +
> +	if (caps2 & MMC_CAP2_HS400_1_2V &&
> +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> +	}
> +
>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>  	card->mmc_avail_type = avail_type;
> @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>  			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
>  		card->ext_csd.raw_pwr_cl_ddr_52_360 =
>  			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> +		card->ext_csd.raw_pwr_cl_ddr_200_360 =
> +			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
>  	}
>  
>  	if (card->ext_csd.rev >= 5) {
> @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
>  		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
>  			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
>  		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> -			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> +		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> +
>  	if (err)
>  		err = -EINVAL;
>  
> @@ -729,7 +746,8 @@ static struct device_type mmc_type = {
>  
>  static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
>  {
> -	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> +	return card->mmc_avail_type &
> +		(EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_HS400);
>  }
>  
>  /*
> @@ -785,7 +803,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
>  				card->ext_csd.raw_pwr_cl_52_360 :
>  				card->ext_csd.raw_pwr_cl_ddr_52_360;
>  		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> -			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
> +			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> +				card->ext_csd.raw_pwr_cl_ddr_200_360 :
> +				card->ext_csd.raw_pwr_cl_200_360;
>  		break;
>  	default:
>  		pr_warning("%s: Voltage range not supported "
> @@ -858,7 +878,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
>  
>  	BUG_ON(!card);
>  
> -	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> +	if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
> +	     max_dtr > card->ext_csd.hs200_max_dtr)
>  		max_dtr = card->ext_csd.hs200_max_dtr;
>  	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
>  		max_dtr = card->ext_csd.hs_max_dtr;
> @@ -962,6 +983,30 @@ static int mmc_select_hs(struct mmc_card *card)
>  }
>  
>  /*
> + * Revert to the high-speed mode from above speed
> + */
> +static int mmc_revert_to_hs(struct mmc_card *card)
> +{
> +	BUG_ON(!card);
> +
> +	/*
> +	 * CMD13, which is used to confirm the completion of timing
> +	 * change, will be issued at higher speed timing condtion
> +	 * rather than high-speed. If device has completed the change
> +	 * to high-speed mode, it may not be proper timing to issue
> +	 * command. Low speed supplies better timing margin than high
> +	 * speed. Accordingly clock rate & timging should be chagned
> +	 * ahead before actual switch.
> +	 */
> +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> +	mmc_set_bus_speed(card);
> +
> +	return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> +			  card->ext_csd.generic_cmd6_time);
> +}
> +
> +/*
>   * Activate wide bus and DDR if supported.
>   */
>  static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
> @@ -1020,6 +1065,60 @@ static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
>  	return err;
>  }
>  
> +static int mmc_select_hs400(struct mmc_card *card, u8 *ext_csd)
Hi Seungwon,

The second parameter ext_csd is never used in this function, I suggest we remove it.

Thanks,
Jackey

> +{
> +	struct mmc_host *host;
> +	int err = 0, ddr;
> +
> +	BUG_ON(!card);
> +
> +	host = card->host;
> +
> +	ddr = mmc_snoop_ddr(card);
> +
> +	/*
> +	 * The bus width is set to only 8 DDR in HS400 mode
> +	 */
> +	if (!(ddr & EXT_CSD_CARD_TYPE_HS400 &&
> +	      card->host->ios.bus_width == MMC_BUS_WIDTH_8))
> +		return 0;
> +
> +	/*
> +	 * Before setting BUS_WIDTH for dual data rate operation,
> +	 * HS_TIMING must be set to High Speed(0x1)
> +	 */
> +	err = mmc_revert_to_hs(card);
> +	if (err) {
> +		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> +			mmc_hostname(card->host), err);
> +		return err;
> +	}
> +
> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			 EXT_CSD_BUS_WIDTH,
> +			 EXT_CSD_DDR_BUS_WIDTH_8,
> +			 card->ext_csd.generic_cmd6_time);
> +	if (err) {
> +		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> +			mmc_hostname(card->host), err);
> +		return err;
> +	}
> +
> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> +			 card->ext_csd.generic_cmd6_time);
> +	if (err) {
> +		pr_warn("%s: switch to hs400 failed, err:%d\n",
> +			 mmc_hostname(card->host), err);
> +		return err;
> +	}
> +
> +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS400);
> +	mmc_set_bus_speed(card);
> +
> +	return 0;
> +}
> +
>  /*
>   * For device supporting HS200 mode, the following sequence
>   * should be done before executing the tuning process.
> @@ -1055,7 +1154,16 @@ static int mmc_select_hs200(struct mmc_card *card)
>  		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>  				 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
>  				 card->ext_csd.generic_cmd6_time);
> -		if (!err)
> +		if (err)
> +			goto err;
> +
> +		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> +			/*
> +			 * Timing should be adjusted to the HS400 target
> +			 * operation frequency for tuning process
> +			 */
> +			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> +		else
>  			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
>  	}
>  err:
> @@ -1105,7 +1213,7 @@ bus_speed:
>  
>  /*
>   * Execute tuning sequence to seek the proper bus operating
> - * conditions for HS200, which sends CMD21 to the device.
> + * conditions for HS200 and HS400, which sends CMD21 to the device.
>   */
>  static int mmc_hs200_tuning(struct mmc_card *card)
>  {
> @@ -1343,6 +1451,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>  		err = mmc_hs200_tuning(card);
>  		if (err)
>  			goto err;
> +
> +		err = mmc_select_hs400(card, ext_csd);
> +		if (err)
> +			goto err;
>  	} else if (mmc_card_hs(card)) {
>  		/* Select the desired bus width optionally */
>  		err = mmc_select_bus_width(card);
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index c278241..eabddfb 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -110,6 +110,7 @@ struct mmc_ext_csd {
>  	u8			raw_pwr_cl_200_360;	/* 237 */
>  	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
>  	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
> +	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
>  	u8			raw_bkops_status;	/* 246 */
>  	u8			raw_sectors[4];		/* 212 - 4 bytes */
>  
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 66e632c..7c0e277 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -61,6 +61,8 @@ struct mmc_ios {
>  #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_HS400_TUNING 11
>  
>  	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
>  
> @@ -278,6 +280,10 @@ struct mmc_host {
>  				 MMC_CAP2_PACKED_WR)
>  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
>  #define MMC_CAP2_SANITIZE	(1 << 15)		/* Support Sanitize */
> +#define MMC_CAP2_HS400_1_8V	(1 << 16)	/* Can support HS400 1.8V */
> +#define MMC_CAP2_HS400_1_2V	(1 << 17)	/* Can support HS400 1.2V */
> +#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
> +				 MMC_CAP2_HS400_1_2V)
>  
>  	mmc_pm_flag_t		pm_caps;	/* supported pm features */
>  
> @@ -495,11 +501,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
>  
>  static inline bool mmc_card_hs200(struct mmc_card *card)
>  {
> -	return card->ios->timing == MMC_TIMING_MMC_HS200;
> +	return card->ios->timing == MMC_TIMING_MMC_HS200 ||
> +		card->ios->timing == MMC_TIMING_MMC_HS400_TUNING;
>  }
>  
>  static inline bool mmc_card_ddr52(struct mmc_card *card)
>  {
>  	return card->ios->timing == MMC_TIMING_MMC_DDR52;
>  }
> +
> +static inline bool mmc_card_hs400(struct mmc_card *card)
> +{
> +	return card->ios->timing == MMC_TIMING_MMC_HS400;
> +}
> +
>  #endif /* LINUX_MMC_HOST_H */
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index f429f13..64ec963 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -325,6 +325,7 @@ struct _mmc_csd {
>  #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
>  #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
>  #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
> +#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
>  #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
>  #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
>  #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
> @@ -354,7 +355,6 @@ struct _mmc_csd {
>  #define EXT_CSD_CMD_SET_SECURE		(1<<1)
>  #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
>  
> -#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
>  #define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
>  #define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
>  #define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
> @@ -370,6 +370,10 @@ struct _mmc_csd {
>  						/* SDR mode @1.2V I/O */
>  #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	(1<<6)	/* Card can run at 200MHz DDR, 1.8V */
> +#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
> @@ -380,6 +384,7 @@ struct _mmc_csd {
>  #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_SEC_ER_EN	BIT(0)
>  #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
> -- 
> 1.7.0.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


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

* RE: [PATCH 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-02-18 10:24   ` Jackey Shen
@ 2014-02-18 13:31     ` Seungwon Jeon
  0 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-18 13:31 UTC (permalink / raw)
  To: 'Jackey Shen'
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Alim Akhtar',
	linux-mmc

On Tue, February 18, 2014, Jackey Shen wrote:
> On Wed, Jan 15, 2014 at 11:19:32PM +0900, Seungwon Jeon wrote:
> > 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: Seungwon Jeon <tgih.jun@samsung.com>
> > ---
> >  drivers/mmc/core/bus.c     |    1 +
> >  drivers/mmc/core/debugfs.c |    3 +
> >  drivers/mmc/core/mmc.c     |  126 +++++++++++++++++++++++++++++++++++++++++---
> >  include/linux/mmc/card.h   |    1 +
> >  include/linux/mmc/host.h   |   15 +++++-
> >  include/linux/mmc/mmc.h    |    7 ++-
> >  6 files changed, 144 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> > index e8a21fb..d28ecf1 100644
> > --- a/drivers/mmc/core/bus.c
> > +++ b/drivers/mmc/core/bus.c
> > @@ -358,6 +358,7 @@ int mmc_add_card(struct mmc_card *card)
> >  			mmc_hostname(card->host),
> >  			mmc_card_uhs(card) ? "ultra high speed " :
> >  			(mmc_card_hs(card) ? "high speed " : ""),
> > +			mmc_card_hs400(card) ? "HS400 " :
> >  			(mmc_card_hs200(card) ? "HS200 " : ""),
> >  			mmc_card_ddr52(card) ? "DDR " : "",
> >  			uhs_bus_speed_mode, type, card->rca);
> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> > index 1f730db..91eb162 100644
> > --- a/drivers/mmc/core/debugfs.c
> > +++ b/drivers/mmc/core/debugfs.c
> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
> >  	case MMC_TIMING_MMC_HS200:
> >  		str = "mmc HS200";
> >  		break;
> > +	case MMC_TIMING_MMC_HS400:
> > +		str = "mmc HS400";
> > +		break;
> >  	default:
> >  		str = "invalid";
> >  		break;
> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > index 6ce5ff3..f3c899d 100644
> > --- a/drivers/mmc/core/mmc.c
> > +++ b/drivers/mmc/core/mmc.c
> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
> >  static void mmc_select_card_type(struct mmc_card *card)
> >  {
> >  	struct mmc_host *host = card->host;
> > -	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> > +	u8 card_type = card->ext_csd.raw_card_type;
> >  	u32 caps = host->caps, caps2 = host->caps2;
> >  	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
> >  	unsigned int avail_type = 0;
> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
> >  		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> >  	}
> >
> > +	if (caps2 & MMC_CAP2_HS400_1_8V &&
> > +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> > +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> > +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> > +	}
> > +
> > +	if (caps2 & MMC_CAP2_HS400_1_2V &&
> > +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> > +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> > +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> > +	}
> > +
> >  	card->ext_csd.hs_max_dtr = hs_max_dtr;
> >  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
> >  	card->mmc_avail_type = avail_type;
> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
> >  			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
> >  		card->ext_csd.raw_pwr_cl_ddr_52_360 =
> >  			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> > +		card->ext_csd.raw_pwr_cl_ddr_200_360 =
> > +			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
> >  	}
> >
> >  	if (card->ext_csd.rev >= 5) {
> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
> >  		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
> >  			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
> >  		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> > -			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> > +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> > +		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> > +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> > +
> >  	if (err)
> >  		err = -EINVAL;
> >
> > @@ -729,7 +746,8 @@ static struct device_type mmc_type = {
> >
> >  static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> >  {
> > -	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> > +	return card->mmc_avail_type &
> > +		(EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_HS400);
> >  }
> >
> >  /*
> > @@ -785,7 +803,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> >  				card->ext_csd.raw_pwr_cl_52_360 :
> >  				card->ext_csd.raw_pwr_cl_ddr_52_360;
> >  		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> > -			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
> > +			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> > +				card->ext_csd.raw_pwr_cl_ddr_200_360 :
> > +				card->ext_csd.raw_pwr_cl_200_360;
> >  		break;
> >  	default:
> >  		pr_warning("%s: Voltage range not supported "
> > @@ -858,7 +878,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
> >
> >  	BUG_ON(!card);
> >
> > -	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> > +	if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
> > +	     max_dtr > card->ext_csd.hs200_max_dtr)
> >  		max_dtr = card->ext_csd.hs200_max_dtr;
> >  	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
> >  		max_dtr = card->ext_csd.hs_max_dtr;
> > @@ -962,6 +983,30 @@ static int mmc_select_hs(struct mmc_card *card)
> >  }
> >
> >  /*
> > + * Revert to the high-speed mode from above speed
> > + */
> > +static int mmc_revert_to_hs(struct mmc_card *card)
> > +{
> > +	BUG_ON(!card);
> > +
> > +	/*
> > +	 * CMD13, which is used to confirm the completion of timing
> > +	 * change, will be issued at higher speed timing condtion
> > +	 * rather than high-speed. If device has completed the change
> > +	 * to high-speed mode, it may not be proper timing to issue
> > +	 * command. Low speed supplies better timing margin than high
> > +	 * speed. Accordingly clock rate & timging should be chagned
> > +	 * ahead before actual switch.
> > +	 */
> > +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> > +	mmc_set_bus_speed(card);
> > +
> > +	return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +			  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> > +			  card->ext_csd.generic_cmd6_time);
> > +}
> > +
> > +/*
> >   * Activate wide bus and DDR if supported.
> >   */
> >  static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
> > @@ -1020,6 +1065,60 @@ static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd)
> >  	return err;
> >  }
> >
> > +static int mmc_select_hs400(struct mmc_card *card, u8 *ext_csd)
> Hi Seungwon,
> 
> The second parameter ext_csd is never used in this function, I suggest we remove it.
> 

Thank you for check.
I'll address.

Thanks,
Seungwon Jeon

> Thanks,
> Jackey
> 
> > +{
> > +	struct mmc_host *host;
> > +	int err = 0, ddr;
> > +
> > +	BUG_ON(!card);
> > +
> > +	host = card->host;
> > +
> > +	ddr = mmc_snoop_ddr(card);
> > +
> > +	/*
> > +	 * The bus width is set to only 8 DDR in HS400 mode
> > +	 */
> > +	if (!(ddr & EXT_CSD_CARD_TYPE_HS400 &&
> > +	      card->host->ios.bus_width == MMC_BUS_WIDTH_8))
> > +		return 0;
> > +
> > +	/*
> > +	 * Before setting BUS_WIDTH for dual data rate operation,
> > +	 * HS_TIMING must be set to High Speed(0x1)
> > +	 */
> > +	err = mmc_revert_to_hs(card);
> > +	if (err) {
> > +		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> > +			mmc_hostname(card->host), err);
> > +		return err;
> > +	}
> > +
> > +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +			 EXT_CSD_BUS_WIDTH,
> > +			 EXT_CSD_DDR_BUS_WIDTH_8,
> > +			 card->ext_csd.generic_cmd6_time);
> > +	if (err) {
> > +		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> > +			mmc_hostname(card->host), err);
> > +		return err;
> > +	}
> > +
> > +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> > +			 card->ext_csd.generic_cmd6_time);
> > +	if (err) {
> > +		pr_warn("%s: switch to hs400 failed, err:%d\n",
> > +			 mmc_hostname(card->host), err);
> > +		return err;
> > +	}
> > +
> > +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS400);
> > +	mmc_set_bus_speed(card);
> > +
> > +	return 0;
> > +}
> > +
> >  /*
> >   * For device supporting HS200 mode, the following sequence
> >   * should be done before executing the tuning process.
> > @@ -1055,7 +1154,16 @@ static int mmc_select_hs200(struct mmc_card *card)
> >  		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >  				 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> >  				 card->ext_csd.generic_cmd6_time);
> > -		if (!err)
> > +		if (err)
> > +			goto err;
> > +
> > +		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> > +			/*
> > +			 * Timing should be adjusted to the HS400 target
> > +			 * operation frequency for tuning process
> > +			 */
> > +			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> > +		else
> >  			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> >  	}
> >  err:
> > @@ -1105,7 +1213,7 @@ bus_speed:
> >
> >  /*
> >   * Execute tuning sequence to seek the proper bus operating
> > - * conditions for HS200, which sends CMD21 to the device.
> > + * conditions for HS200 and HS400, which sends CMD21 to the device.
> >   */
> >  static int mmc_hs200_tuning(struct mmc_card *card)
> >  {
> > @@ -1343,6 +1451,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >  		err = mmc_hs200_tuning(card);
> >  		if (err)
> >  			goto err;
> > +
> > +		err = mmc_select_hs400(card, ext_csd);
> > +		if (err)
> > +			goto err;
> >  	} else if (mmc_card_hs(card)) {
> >  		/* Select the desired bus width optionally */
> >  		err = mmc_select_bus_width(card);
> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > index c278241..eabddfb 100644
> > --- a/include/linux/mmc/card.h
> > +++ b/include/linux/mmc/card.h
> > @@ -110,6 +110,7 @@ struct mmc_ext_csd {
> >  	u8			raw_pwr_cl_200_360;	/* 237 */
> >  	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
> >  	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
> > +	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
> >  	u8			raw_bkops_status;	/* 246 */
> >  	u8			raw_sectors[4];		/* 212 - 4 bytes */
> >
> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > index 66e632c..7c0e277 100644
> > --- a/include/linux/mmc/host.h
> > +++ b/include/linux/mmc/host.h
> > @@ -61,6 +61,8 @@ struct mmc_ios {
> >  #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_HS400_TUNING 11
> >
> >  	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
> >
> > @@ -278,6 +280,10 @@ struct mmc_host {
> >  				 MMC_CAP2_PACKED_WR)
> >  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
> >  #define MMC_CAP2_SANITIZE	(1 << 15)		/* Support Sanitize */
> > +#define MMC_CAP2_HS400_1_8V	(1 << 16)	/* Can support HS400 1.8V */
> > +#define MMC_CAP2_HS400_1_2V	(1 << 17)	/* Can support HS400 1.2V */
> > +#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
> > +				 MMC_CAP2_HS400_1_2V)
> >
> >  	mmc_pm_flag_t		pm_caps;	/* supported pm features */
> >
> > @@ -495,11 +501,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
> >
> >  static inline bool mmc_card_hs200(struct mmc_card *card)
> >  {
> > -	return card->ios->timing == MMC_TIMING_MMC_HS200;
> > +	return card->ios->timing == MMC_TIMING_MMC_HS200 ||
> > +		card->ios->timing == MMC_TIMING_MMC_HS400_TUNING;
> >  }
> >
> >  static inline bool mmc_card_ddr52(struct mmc_card *card)
> >  {
> >  	return card->ios->timing == MMC_TIMING_MMC_DDR52;
> >  }
> > +
> > +static inline bool mmc_card_hs400(struct mmc_card *card)
> > +{
> > +	return card->ios->timing == MMC_TIMING_MMC_HS400;
> > +}
> > +
> >  #endif /* LINUX_MMC_HOST_H */
> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> > index f429f13..64ec963 100644
> > --- a/include/linux/mmc/mmc.h
> > +++ b/include/linux/mmc/mmc.h
> > @@ -325,6 +325,7 @@ struct _mmc_csd {
> >  #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
> >  #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
> >  #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
> > +#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
> >  #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
> >  #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
> >  #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
> > @@ -354,7 +355,6 @@ struct _mmc_csd {
> >  #define EXT_CSD_CMD_SET_SECURE		(1<<1)
> >  #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
> >
> > -#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
> >  #define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
> >  #define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
> >  #define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
> > @@ -370,6 +370,10 @@ struct _mmc_csd {
> >  						/* SDR mode @1.2V I/O */
> >  #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	(1<<6)	/* Card can run at 200MHz DDR, 1.8V */
> > +#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
> >  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
> > @@ -380,6 +384,7 @@ struct _mmc_csd {
> >  #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_SEC_ER_EN	BIT(0)
> >  #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
> > --
> > 1.7.0.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* RE: [PATCH v2 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-17 14:08   ` Ulf Hansson
@ 2014-02-18 13:34     ` Seungwon Jeon
  0 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-18 13:34 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Russell King', 'Chris Ball',
	'Rickard Andersson'

On Mon, February 17, 2014, Ulf Hansson wrote:
> On 15 February 2014 15:08, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Added MMC_DDR52 as eMMC's DDR mode distinguished from SD-UHS.
> >
> > CC: Russell King <linux@arm.linux.org.uk>
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> 
> Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
> 
> Do note, normally Russell takes patches for mmci.
> 
> In this case I think it's important that the complete set gets merged
> together. Especially since patch 1, on it's own, actually breaks
> support for MMC DDR mode for some host drivers.

Thank you for your ack.
I also hope that.

Thanks,
Seungwon Jeon
> 
> Kind regards
> Ulf Hansson
> 
> > ---
> >  drivers/mmc/host/mmci.c |    6 ++++--
> >  1 files changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
> > index b931226..421d1fe 100644
> > --- a/drivers/mmc/host/mmci.c
> > +++ b/drivers/mmc/host/mmci.c
> > @@ -299,7 +299,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
> >         if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
> >                 clk |= MCI_ST_8BIT_BUS;
> >
> > -       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
> > +       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
> > +           host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
> >                 clk |= MCI_ST_UX500_NEG_EDGE;
> >
> >         mmci_write_clkreg(host, clk);
> > @@ -784,7 +785,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
> >                         mmci_write_clkreg(host, clk);
> >                 }
> >
> > -       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
> > +       if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
> > +           host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
> >                 datactrl |= MCI_ST_DPSM_DDRMODE;
> >
> >         /*
> > --
> > 1.7.0.4
> >
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* RE: [PATCH RESEND 1/5] mmc: drop the speed mode of card's state
  2014-02-17 14:38   ` Ulf Hansson
@ 2014-02-18 13:43     ` Seungwon Jeon
  2014-02-18 16:40       ` Ulf Hansson
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-02-18 13:43 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On Mon, February 17, 2014, Ulf Hansson wrote:
> On 15 February 2014 15:18, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Timing mode identifier has same role and can take the place
> > of speed mode. This change removes all related speed mode.
> >
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > ---
> >  drivers/mmc/core/bus.c   |    9 +++++----
> >  drivers/mmc/core/core.c  |    3 +--
> >  drivers/mmc/core/mmc.c   |   11 +++--------
> >  drivers/mmc/core/sd.c    |   16 +++-------------
> >  drivers/mmc/core/sd.h    |    1 -
> >  drivers/mmc/core/sdio.c  |    8 ++------
> >  include/linux/mmc/card.h |   24 +++++++-----------------
> >  include/linux/mmc/host.h |   23 +++++++++++++++++++++++
> >  8 files changed, 44 insertions(+), 51 deletions(-)
> >
> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> > index 64145a3..e8a21fb 100644
> > --- a/drivers/mmc/core/bus.c
> > +++ b/drivers/mmc/core/bus.c
> > @@ -286,6 +286,7 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
> >                 return ERR_PTR(-ENOMEM);
> >
> >         card->host = host;
> > +       card->ios = &host->ios;
> 
> Please remove this. The ios is connected and controlled by the host.
> 
> Once you need the ios pointer I think it's better to reference it from
> the card->host.
> 
> >
> >         device_initialize(&card->dev);
> >
> > @@ -349,16 +350,16 @@ int mmc_add_card(struct mmc_card *card)
> >         if (mmc_host_is_spi(card->host)) {
> >                 pr_info("%s: new %s%s%s card on SPI\n",
> >                         mmc_hostname(card->host),
> > -                       mmc_card_highspeed(card) ? "high speed " : "",
> > -                       mmc_card_ddr_mode(card) ? "DDR " : "",
> > +                       mmc_card_hs(card) ? "high speed " : "",
> > +                       mmc_card_ddr52(card) ? "DDR " : "",
> >                         type);
> >         } else {
> >                 pr_info("%s: new %s%s%s%s%s card at address %04x\n",
> >                         mmc_hostname(card->host),
> >                         mmc_card_uhs(card) ? "ultra high speed " :
> > -                       (mmc_card_highspeed(card) ? "high speed " : ""),
> > +                       (mmc_card_hs(card) ? "high speed " : ""),
> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
> > -                       mmc_card_ddr_mode(card) ? "DDR " : "",
> > +                       mmc_card_ddr52(card) ? "DDR " : "",
> >                         uhs_bus_speed_mode, type, card->rca);
> >         }
> >
> > diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> > index 098374b..88433bd 100644
> > --- a/drivers/mmc/core/core.c
> > +++ b/drivers/mmc/core/core.c
> > @@ -2198,7 +2198,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
> >  {
> >         struct mmc_command cmd = {0};
> >
> > -       if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
> > +       if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
> >                 return 0;
> >
> >         cmd.opcode = MMC_SET_BLOCKLEN;
> > @@ -2281,7 +2281,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
> >                 }
> >         }
> >
> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
> >         if (mmc_host_is_spi(host)) {
> >                 host->ios.chip_select = MMC_CS_HIGH;
> >                 host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > index 6d91ff7..613e641 100644
> > --- a/drivers/mmc/core/mmc.c
> > +++ b/drivers/mmc/core/mmc.c
> > @@ -1088,11 +1088,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >                 } else {
> >                         if (card->ext_csd.hs_max_dtr > 52000000 &&
> >                             host->caps2 & MMC_CAP2_HS200) {
> > -                               mmc_card_set_hs200(card);
> >                                 mmc_set_timing(card->host,
> >                                                MMC_TIMING_MMC_HS200);
> >                         } else {
> > -                               mmc_card_set_highspeed(card);
> >                                 mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> >                         }
> >                 }
> > @@ -1103,10 +1101,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >          */
> >         max_dtr = (unsigned int)-1;
> >
> > -       if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
> > +       if (mmc_card_hs(card) || mmc_card_hs200(card)) {
> >                 if (max_dtr > card->ext_csd.hs_max_dtr)
> >                         max_dtr = card->ext_csd.hs_max_dtr;
> > -               if (mmc_card_highspeed(card) && (max_dtr > 52000000))
> > +               if (mmc_card_hs(card) && (max_dtr > 52000000))
> >                         max_dtr = 52000000;
> >         } else if (max_dtr > card->csd.max_dtr) {
> >                 max_dtr = card->csd.max_dtr;
> > @@ -1117,7 +1115,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >         /*
> >          * Indicate DDR mode (if supported).
> >          */
> > -       if (mmc_card_highspeed(card)) {
> > +       if (mmc_card_hs(card)) {
> >                 if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
> >                         && (host->caps & MMC_CAP_1_8V_DDR))
> >                                 ddr = MMC_1_8V_DDR_MODE;
> > @@ -1260,7 +1258,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >                                 if (err)
> >                                         goto err;
> >                         }
> > -                       mmc_card_set_ddr_mode(card);
> >                         mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
> >                         mmc_set_bus_width(card->host, bus_width);
> >                 }
> > @@ -1495,7 +1492,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
> >                 err = mmc_sleep(host);
> >         else if (!mmc_host_is_spi(host))
> >                 err = mmc_deselect_cards(host);
> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
> >
> >         if (!err) {
> >                 mmc_power_off(host);
> > @@ -1625,7 +1621,6 @@ static int mmc_power_restore(struct mmc_host *host)
> >  {
> >         int ret;
> >
> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
> >         mmc_claim_host(host);
> >         ret = mmc_init_card(host, host->card->ocr, host->card);
> >         mmc_release_host(host);
> > diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> > index 692fdb1..54dd3d1 100644
> > --- a/drivers/mmc/core/sd.c
> > +++ b/drivers/mmc/core/sd.c
> > @@ -895,7 +895,7 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
> >  {
> >         unsigned max_dtr = (unsigned int)-1;
> >
> > -       if (mmc_card_highspeed(card)) {
> > +       if (mmc_card_hs(card)) {
> >                 if (max_dtr > card->sw_caps.hs_max_dtr)
> >                         max_dtr = card->sw_caps.hs_max_dtr;
> >         } else if (max_dtr > card->csd.max_dtr) {
> > @@ -905,12 +905,6 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
> >         return max_dtr;
> >  }
> >
> > -void mmc_sd_go_highspeed(struct mmc_card *card)
> > -{
> > -       mmc_card_set_highspeed(card);
> > -       mmc_set_timing(card->host, MMC_TIMING_SD_HS);
> > -}
> > -
> >  /*
> >   * Handle the detection and initialisation of a card.
> >   *
> > @@ -985,16 +979,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
> >                 err = mmc_sd_init_uhs_card(card);
> >                 if (err)
> >                         goto free_card;
> > -
> > -               /* Card is an ultra-high-speed card */
> > -               mmc_card_set_uhs(card);
> >         } else {
> >                 /*
> >                  * Attempt to change to high-speed (if supported)
> >                  */
> >                 err = mmc_sd_switch_hs(card);
> >                 if (err > 0)
> > -                       mmc_sd_go_highspeed(card);
> > +                       mmc_set_timing(card->host, MMC_TIMING_SD_HS);
> >                 else if (err)
> >                         goto free_card;
> >
> > @@ -1089,7 +1080,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
> >
> >         if (!mmc_host_is_spi(host))
> >                 err = mmc_deselect_cards(host);
> > -       host->card->state &= ~MMC_STATE_HIGHSPEED;
> > +
> >         if (!err) {
> >                 mmc_power_off(host);
> >                 mmc_card_set_suspended(host->card);
> > @@ -1198,7 +1189,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
> >  {
> >         int ret;
> >
> > -       host->card->state &= ~MMC_STATE_HIGHSPEED;
> >         mmc_claim_host(host);
> >         ret = mmc_sd_init_card(host, host->card->ocr, host->card);
> >         mmc_release_host(host);
> > diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
> > index 4b34b24..aab824a 100644
> > --- a/drivers/mmc/core/sd.h
> > +++ b/drivers/mmc/core/sd.h
> > @@ -12,6 +12,5 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
> >         bool reinit);
> >  unsigned mmc_sd_get_max_clock(struct mmc_card *card);
> >  int mmc_sd_switch_hs(struct mmc_card *card);
> > -void mmc_sd_go_highspeed(struct mmc_card *card);
> >
> >  #endif
> > diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> > index 4d721c6..ef57d2d 100644
> > --- a/drivers/mmc/core/sdio.c
> > +++ b/drivers/mmc/core/sdio.c
> > @@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
> >  {
> >         unsigned max_dtr;
> >
> > -       if (mmc_card_highspeed(card)) {
> > +       if (mmc_card_hs(card)) {
> >                 /*
> >                  * The SDIO specification doesn't mention how
> >                  * the CIS transfer speed register relates to
> > @@ -733,7 +733,6 @@ try_again:
> >                 mmc_set_clock(host, card->cis.max_dtr);
> >
> >                 if (card->cccr.high_speed) {
> > -                       mmc_card_set_highspeed(card);
> >                         mmc_set_timing(card->host, MMC_TIMING_SD_HS);
> >                 }
> >
> > @@ -792,16 +791,13 @@ try_again:
> >                 err = mmc_sdio_init_uhs_card(card);
> >                 if (err)
> >                         goto remove;
> > -
> > -               /* Card is an ultra-high-speed card */
> > -               mmc_card_set_uhs(card);
> >         } else {
> >                 /*
> >                  * Switch to high-speed (if supported).
> >                  */
> >                 err = sdio_enable_hs(card);
> >                 if (err > 0)
> > -                       mmc_sd_go_highspeed(card);
> > +                       mmc_set_timing(card->host, MMC_TIMING_SD_HS);
> >                 else if (err)
> >                         goto remove;
> >
> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > index b730272..e6ce178 100644
> > --- a/include/linux/mmc/card.h
> > +++ b/include/linux/mmc/card.h
> > @@ -194,6 +194,7 @@ struct sdio_cis {
> >  };
> >
> >  struct mmc_host;
> > +struct mmc_ios;
> >  struct sdio_func;
> >  struct sdio_func_tuple;
> >
> > @@ -239,6 +240,7 @@ struct mmc_part {
> >   */
> >  struct mmc_card {
> >         struct mmc_host         *host;          /* the host this device belongs to */
> > +       struct mmc_ios          *ios;           /* bus settings of host */
> 
> Please remove, see comment above.
> 
> >         struct device           dev;            /* the device */
> >         u32                     ocr;            /* the current OCR setting */
> >         unsigned int            rca;            /* relative card address of device */
> > @@ -250,15 +252,11 @@ struct mmc_card {
> >         unsigned int            state;          /* (our) card state */
> >  #define MMC_STATE_PRESENT      (1<<0)          /* present in sysfs */
> >  #define MMC_STATE_READONLY     (1<<1)          /* card is read-only */
> > -#define MMC_STATE_HIGHSPEED    (1<<2)          /* card is in high speed mode */
> > -#define MMC_STATE_BLOCKADDR    (1<<3)          /* card uses block-addressing */
> > -#define MMC_STATE_HIGHSPEED_DDR (1<<4)         /* card is in high speed mode */
> > -#define MMC_STATE_ULTRAHIGHSPEED (1<<5)                /* card is in ultra high speed mode */
> > -#define MMC_CARD_SDXC          (1<<6)          /* card is SDXC */
> > -#define MMC_CARD_REMOVED       (1<<7)          /* card has been removed */
> > -#define MMC_STATE_HIGHSPEED_200        (1<<8)          /* card is in HS200 mode */
> > -#define MMC_STATE_DOING_BKOPS  (1<<10)         /* card is doing BKOPS */
> > -#define MMC_STATE_SUSPENDED    (1<<11)         /* card is suspended */
> > +#define MMC_STATE_BLOCKADDR    (1<<2)          /* card uses block-addressing */
> > +#define MMC_CARD_SDXC          (1<<3)          /* card is SDXC */
> > +#define MMC_CARD_REMOVED       (1<<4)          /* card has been removed */
> > +#define MMC_STATE_DOING_BKOPS  (1<<5)          /* card is doing BKOPS */
> > +#define MMC_STATE_SUSPENDED    (1<<6)          /* card is suspended */
> >         unsigned int            quirks;         /* card quirks */
> >  #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range
> */
> >  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
> > @@ -418,11 +416,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
> >
> >  #define mmc_card_present(c)    ((c)->state & MMC_STATE_PRESENT)
> >  #define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
> > -#define mmc_card_highspeed(c)  ((c)->state & MMC_STATE_HIGHSPEED)
> > -#define mmc_card_hs200(c)      ((c)->state & MMC_STATE_HIGHSPEED_200)
> >  #define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
> > -#define mmc_card_ddr_mode(c)   ((c)->state & MMC_STATE_HIGHSPEED_DDR)
> > -#define mmc_card_uhs(c)                ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
> >  #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
> >  #define mmc_card_removed(c)    ((c) && ((c)->state & MMC_CARD_REMOVED))
> >  #define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
> > @@ -430,11 +424,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
> >
> >  #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
> >  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
> > -#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
> > -#define mmc_card_set_hs200(c)  ((c)->state |= MMC_STATE_HIGHSPEED_200)
> >  #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
> > -#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
> > -#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
> >  #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
> >  #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
> >  #define mmc_card_set_doing_bkops(c)    ((c)->state |= MMC_STATE_DOING_BKOPS)
> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > index 87b1f4f..71977f4 100644
> > --- a/include/linux/mmc/host.h
> > +++ b/include/linux/mmc/host.h
> > @@ -17,6 +17,7 @@
> >  #include <linux/fault-inject.h>
> >
> >  #include <linux/mmc/core.h>
> > +#include <linux/mmc/card.h>
> >  #include <linux/mmc/pm.h>
> >
> >  struct mmc_ios {
> > @@ -485,4 +486,26 @@ static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
> >         return host->ios.clock;
> >  }
> >  #endif
> > +
> > +static inline int mmc_card_hs(struct mmc_card *card)
> > +{
> > +       return card->ios->timing == MMC_TIMING_SD_HS ||
> > +               card->ios->timing == MMC_TIMING_MMC_HS;
> > +}
> > +
> > +static inline int mmc_card_uhs(struct mmc_card *card)
> > +{
> > +       return card->ios->timing >= MMC_TIMING_UHS_SDR12 &&
> > +               card->ios->timing <= MMC_TIMING_UHS_DDR50;
> > +}
> > +
> > +static inline bool mmc_card_hs200(struct mmc_card *card)
> > +{
> > +       return card->ios->timing == MMC_TIMING_MMC_HS200;
> > +}
> > +
> > +static inline bool mmc_card_ddr52(struct mmc_card *card)
> > +{
> > +       return card->ios->timing == MMC_TIMING_MMC_DDR52;
I just added another reference toward ios.
Do you expect like below?
return card->host->ios->timing == MMC_TIMING_MMC_DDR52;
I'm fine if you checked that.

Thanks,
Seungwon Jeon

> > +}
> >  #endif /* LINUX_MMC_HOST_H */
> > --
> > 1.7.0.4
> >
> >
> 
> Nice clean-up!
> 
> Besides my minor comment above, you have my ack.
> 
> Kind regards
> Ulf Hansson
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH RESEND 1/5] mmc: drop the speed mode of card's state
  2014-02-18 13:43     ` Seungwon Jeon
@ 2014-02-18 16:40       ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-02-18 16:40 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 18 February 2014 14:43, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> On Mon, February 17, 2014, Ulf Hansson wrote:
>> On 15 February 2014 15:18, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> > Timing mode identifier has same role and can take the place
>> > of speed mode. This change removes all related speed mode.
>> >
>> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> > ---
>> >  drivers/mmc/core/bus.c   |    9 +++++----
>> >  drivers/mmc/core/core.c  |    3 +--
>> >  drivers/mmc/core/mmc.c   |   11 +++--------
>> >  drivers/mmc/core/sd.c    |   16 +++-------------
>> >  drivers/mmc/core/sd.h    |    1 -
>> >  drivers/mmc/core/sdio.c  |    8 ++------
>> >  include/linux/mmc/card.h |   24 +++++++-----------------
>> >  include/linux/mmc/host.h |   23 +++++++++++++++++++++++
>> >  8 files changed, 44 insertions(+), 51 deletions(-)
>> >
>> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> > index 64145a3..e8a21fb 100644
>> > --- a/drivers/mmc/core/bus.c
>> > +++ b/drivers/mmc/core/bus.c
>> > @@ -286,6 +286,7 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
>> >                 return ERR_PTR(-ENOMEM);
>> >
>> >         card->host = host;
>> > +       card->ios = &host->ios;
>>
>> Please remove this. The ios is connected and controlled by the host.
>>
>> Once you need the ios pointer I think it's better to reference it from
>> the card->host.
>>
>> >
>> >         device_initialize(&card->dev);
>> >
>> > @@ -349,16 +350,16 @@ int mmc_add_card(struct mmc_card *card)
>> >         if (mmc_host_is_spi(card->host)) {
>> >                 pr_info("%s: new %s%s%s card on SPI\n",
>> >                         mmc_hostname(card->host),
>> > -                       mmc_card_highspeed(card) ? "high speed " : "",
>> > -                       mmc_card_ddr_mode(card) ? "DDR " : "",
>> > +                       mmc_card_hs(card) ? "high speed " : "",
>> > +                       mmc_card_ddr52(card) ? "DDR " : "",
>> >                         type);
>> >         } else {
>> >                 pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>> >                         mmc_hostname(card->host),
>> >                         mmc_card_uhs(card) ? "ultra high speed " :
>> > -                       (mmc_card_highspeed(card) ? "high speed " : ""),
>> > +                       (mmc_card_hs(card) ? "high speed " : ""),
>> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
>> > -                       mmc_card_ddr_mode(card) ? "DDR " : "",
>> > +                       mmc_card_ddr52(card) ? "DDR " : "",
>> >                         uhs_bus_speed_mode, type, card->rca);
>> >         }
>> >
>> > diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>> > index 098374b..88433bd 100644
>> > --- a/drivers/mmc/core/core.c
>> > +++ b/drivers/mmc/core/core.c
>> > @@ -2198,7 +2198,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
>> >  {
>> >         struct mmc_command cmd = {0};
>> >
>> > -       if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
>> > +       if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
>> >                 return 0;
>> >
>> >         cmd.opcode = MMC_SET_BLOCKLEN;
>> > @@ -2281,7 +2281,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
>> >                 }
>> >         }
>> >
>> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
>> >         if (mmc_host_is_spi(host)) {
>> >                 host->ios.chip_select = MMC_CS_HIGH;
>> >                 host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
>> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> > index 6d91ff7..613e641 100644
>> > --- a/drivers/mmc/core/mmc.c
>> > +++ b/drivers/mmc/core/mmc.c
>> > @@ -1088,11 +1088,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >                 } else {
>> >                         if (card->ext_csd.hs_max_dtr > 52000000 &&
>> >                             host->caps2 & MMC_CAP2_HS200) {
>> > -                               mmc_card_set_hs200(card);
>> >                                 mmc_set_timing(card->host,
>> >                                                MMC_TIMING_MMC_HS200);
>> >                         } else {
>> > -                               mmc_card_set_highspeed(card);
>> >                                 mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> >                         }
>> >                 }
>> > @@ -1103,10 +1101,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >          */
>> >         max_dtr = (unsigned int)-1;
>> >
>> > -       if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
>> > +       if (mmc_card_hs(card) || mmc_card_hs200(card)) {
>> >                 if (max_dtr > card->ext_csd.hs_max_dtr)
>> >                         max_dtr = card->ext_csd.hs_max_dtr;
>> > -               if (mmc_card_highspeed(card) && (max_dtr > 52000000))
>> > +               if (mmc_card_hs(card) && (max_dtr > 52000000))
>> >                         max_dtr = 52000000;
>> >         } else if (max_dtr > card->csd.max_dtr) {
>> >                 max_dtr = card->csd.max_dtr;
>> > @@ -1117,7 +1115,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >         /*
>> >          * Indicate DDR mode (if supported).
>> >          */
>> > -       if (mmc_card_highspeed(card)) {
>> > +       if (mmc_card_hs(card)) {
>> >                 if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
>> >                         && (host->caps & MMC_CAP_1_8V_DDR))
>> >                                 ddr = MMC_1_8V_DDR_MODE;
>> > @@ -1260,7 +1258,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >                                 if (err)
>> >                                         goto err;
>> >                         }
>> > -                       mmc_card_set_ddr_mode(card);
>> >                         mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
>> >                         mmc_set_bus_width(card->host, bus_width);
>> >                 }
>> > @@ -1495,7 +1492,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
>> >                 err = mmc_sleep(host);
>> >         else if (!mmc_host_is_spi(host))
>> >                 err = mmc_deselect_cards(host);
>> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
>> >
>> >         if (!err) {
>> >                 mmc_power_off(host);
>> > @@ -1625,7 +1621,6 @@ static int mmc_power_restore(struct mmc_host *host)
>> >  {
>> >         int ret;
>> >
>> > -       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
>> >         mmc_claim_host(host);
>> >         ret = mmc_init_card(host, host->card->ocr, host->card);
>> >         mmc_release_host(host);
>> > diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>> > index 692fdb1..54dd3d1 100644
>> > --- a/drivers/mmc/core/sd.c
>> > +++ b/drivers/mmc/core/sd.c
>> > @@ -895,7 +895,7 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
>> >  {
>> >         unsigned max_dtr = (unsigned int)-1;
>> >
>> > -       if (mmc_card_highspeed(card)) {
>> > +       if (mmc_card_hs(card)) {
>> >                 if (max_dtr > card->sw_caps.hs_max_dtr)
>> >                         max_dtr = card->sw_caps.hs_max_dtr;
>> >         } else if (max_dtr > card->csd.max_dtr) {
>> > @@ -905,12 +905,6 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
>> >         return max_dtr;
>> >  }
>> >
>> > -void mmc_sd_go_highspeed(struct mmc_card *card)
>> > -{
>> > -       mmc_card_set_highspeed(card);
>> > -       mmc_set_timing(card->host, MMC_TIMING_SD_HS);
>> > -}
>> > -
>> >  /*
>> >   * Handle the detection and initialisation of a card.
>> >   *
>> > @@ -985,16 +979,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
>> >                 err = mmc_sd_init_uhs_card(card);
>> >                 if (err)
>> >                         goto free_card;
>> > -
>> > -               /* Card is an ultra-high-speed card */
>> > -               mmc_card_set_uhs(card);
>> >         } else {
>> >                 /*
>> >                  * Attempt to change to high-speed (if supported)
>> >                  */
>> >                 err = mmc_sd_switch_hs(card);
>> >                 if (err > 0)
>> > -                       mmc_sd_go_highspeed(card);
>> > +                       mmc_set_timing(card->host, MMC_TIMING_SD_HS);
>> >                 else if (err)
>> >                         goto free_card;
>> >
>> > @@ -1089,7 +1080,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
>> >
>> >         if (!mmc_host_is_spi(host))
>> >                 err = mmc_deselect_cards(host);
>> > -       host->card->state &= ~MMC_STATE_HIGHSPEED;
>> > +
>> >         if (!err) {
>> >                 mmc_power_off(host);
>> >                 mmc_card_set_suspended(host->card);
>> > @@ -1198,7 +1189,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
>> >  {
>> >         int ret;
>> >
>> > -       host->card->state &= ~MMC_STATE_HIGHSPEED;
>> >         mmc_claim_host(host);
>> >         ret = mmc_sd_init_card(host, host->card->ocr, host->card);
>> >         mmc_release_host(host);
>> > diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
>> > index 4b34b24..aab824a 100644
>> > --- a/drivers/mmc/core/sd.h
>> > +++ b/drivers/mmc/core/sd.h
>> > @@ -12,6 +12,5 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
>> >         bool reinit);
>> >  unsigned mmc_sd_get_max_clock(struct mmc_card *card);
>> >  int mmc_sd_switch_hs(struct mmc_card *card);
>> > -void mmc_sd_go_highspeed(struct mmc_card *card);
>> >
>> >  #endif
>> > diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
>> > index 4d721c6..ef57d2d 100644
>> > --- a/drivers/mmc/core/sdio.c
>> > +++ b/drivers/mmc/core/sdio.c
>> > @@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
>> >  {
>> >         unsigned max_dtr;
>> >
>> > -       if (mmc_card_highspeed(card)) {
>> > +       if (mmc_card_hs(card)) {
>> >                 /*
>> >                  * The SDIO specification doesn't mention how
>> >                  * the CIS transfer speed register relates to
>> > @@ -733,7 +733,6 @@ try_again:
>> >                 mmc_set_clock(host, card->cis.max_dtr);
>> >
>> >                 if (card->cccr.high_speed) {
>> > -                       mmc_card_set_highspeed(card);
>> >                         mmc_set_timing(card->host, MMC_TIMING_SD_HS);
>> >                 }
>> >
>> > @@ -792,16 +791,13 @@ try_again:
>> >                 err = mmc_sdio_init_uhs_card(card);
>> >                 if (err)
>> >                         goto remove;
>> > -
>> > -               /* Card is an ultra-high-speed card */
>> > -               mmc_card_set_uhs(card);
>> >         } else {
>> >                 /*
>> >                  * Switch to high-speed (if supported).
>> >                  */
>> >                 err = sdio_enable_hs(card);
>> >                 if (err > 0)
>> > -                       mmc_sd_go_highspeed(card);
>> > +                       mmc_set_timing(card->host, MMC_TIMING_SD_HS);
>> >                 else if (err)
>> >                         goto remove;
>> >
>> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> > index b730272..e6ce178 100644
>> > --- a/include/linux/mmc/card.h
>> > +++ b/include/linux/mmc/card.h
>> > @@ -194,6 +194,7 @@ struct sdio_cis {
>> >  };
>> >
>> >  struct mmc_host;
>> > +struct mmc_ios;
>> >  struct sdio_func;
>> >  struct sdio_func_tuple;
>> >
>> > @@ -239,6 +240,7 @@ struct mmc_part {
>> >   */
>> >  struct mmc_card {
>> >         struct mmc_host         *host;          /* the host this device belongs to */
>> > +       struct mmc_ios          *ios;           /* bus settings of host */
>>
>> Please remove, see comment above.
>>
>> >         struct device           dev;            /* the device */
>> >         u32                     ocr;            /* the current OCR setting */
>> >         unsigned int            rca;            /* relative card address of device */
>> > @@ -250,15 +252,11 @@ struct mmc_card {
>> >         unsigned int            state;          /* (our) card state */
>> >  #define MMC_STATE_PRESENT      (1<<0)          /* present in sysfs */
>> >  #define MMC_STATE_READONLY     (1<<1)          /* card is read-only */
>> > -#define MMC_STATE_HIGHSPEED    (1<<2)          /* card is in high speed mode */
>> > -#define MMC_STATE_BLOCKADDR    (1<<3)          /* card uses block-addressing */
>> > -#define MMC_STATE_HIGHSPEED_DDR (1<<4)         /* card is in high speed mode */
>> > -#define MMC_STATE_ULTRAHIGHSPEED (1<<5)                /* card is in ultra high speed mode */
>> > -#define MMC_CARD_SDXC          (1<<6)          /* card is SDXC */
>> > -#define MMC_CARD_REMOVED       (1<<7)          /* card has been removed */
>> > -#define MMC_STATE_HIGHSPEED_200        (1<<8)          /* card is in HS200 mode */
>> > -#define MMC_STATE_DOING_BKOPS  (1<<10)         /* card is doing BKOPS */
>> > -#define MMC_STATE_SUSPENDED    (1<<11)         /* card is suspended */
>> > +#define MMC_STATE_BLOCKADDR    (1<<2)          /* card uses block-addressing */
>> > +#define MMC_CARD_SDXC          (1<<3)          /* card is SDXC */
>> > +#define MMC_CARD_REMOVED       (1<<4)          /* card has been removed */
>> > +#define MMC_STATE_DOING_BKOPS  (1<<5)          /* card is doing BKOPS */
>> > +#define MMC_STATE_SUSPENDED    (1<<6)          /* card is suspended */
>> >         unsigned int            quirks;         /* card quirks */
>> >  #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range
>> */
>> >  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
>> > @@ -418,11 +416,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
>> >
>> >  #define mmc_card_present(c)    ((c)->state & MMC_STATE_PRESENT)
>> >  #define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
>> > -#define mmc_card_highspeed(c)  ((c)->state & MMC_STATE_HIGHSPEED)
>> > -#define mmc_card_hs200(c)      ((c)->state & MMC_STATE_HIGHSPEED_200)
>> >  #define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
>> > -#define mmc_card_ddr_mode(c)   ((c)->state & MMC_STATE_HIGHSPEED_DDR)
>> > -#define mmc_card_uhs(c)                ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
>> >  #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
>> >  #define mmc_card_removed(c)    ((c) && ((c)->state & MMC_CARD_REMOVED))
>> >  #define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
>> > @@ -430,11 +424,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
>> >
>> >  #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
>> >  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
>> > -#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
>> > -#define mmc_card_set_hs200(c)  ((c)->state |= MMC_STATE_HIGHSPEED_200)
>> >  #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
>> > -#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
>> > -#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
>> >  #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
>> >  #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
>> >  #define mmc_card_set_doing_bkops(c)    ((c)->state |= MMC_STATE_DOING_BKOPS)
>> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> > index 87b1f4f..71977f4 100644
>> > --- a/include/linux/mmc/host.h
>> > +++ b/include/linux/mmc/host.h
>> > @@ -17,6 +17,7 @@
>> >  #include <linux/fault-inject.h>
>> >
>> >  #include <linux/mmc/core.h>
>> > +#include <linux/mmc/card.h>
>> >  #include <linux/mmc/pm.h>
>> >
>> >  struct mmc_ios {
>> > @@ -485,4 +486,26 @@ static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
>> >         return host->ios.clock;
>> >  }
>> >  #endif
>> > +
>> > +static inline int mmc_card_hs(struct mmc_card *card)
>> > +{
>> > +       return card->ios->timing == MMC_TIMING_SD_HS ||
>> > +               card->ios->timing == MMC_TIMING_MMC_HS;
>> > +}
>> > +
>> > +static inline int mmc_card_uhs(struct mmc_card *card)
>> > +{
>> > +       return card->ios->timing >= MMC_TIMING_UHS_SDR12 &&
>> > +               card->ios->timing <= MMC_TIMING_UHS_DDR50;
>> > +}
>> > +
>> > +static inline bool mmc_card_hs200(struct mmc_card *card)
>> > +{
>> > +       return card->ios->timing == MMC_TIMING_MMC_HS200;
>> > +}
>> > +
>> > +static inline bool mmc_card_ddr52(struct mmc_card *card)
>> > +{
>> > +       return card->ios->timing == MMC_TIMING_MMC_DDR52;
> I just added another reference toward ios.
> Do you expect like below?
> return card->host->ios->timing == MMC_TIMING_MMC_DDR52;
> I'm fine if you checked that.

That looks okay to me! Please adopt to this.

Kind regards
Uffe

>
> Thanks,
> Seungwon Jeon
>
>> > +}
>> >  #endif /* LINUX_MMC_HOST_H */
>> > --
>> > 1.7.0.4
>> >
>> >
>>
>> Nice clean-up!
>>
>> Besides my minor comment above, you have my ack.
>>
>> Kind regards
>> Ulf Hansson
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

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

* [PATCH v3 0/7] mmc: distinguish DDR timing mode for eMMC/UHS
  2014-02-15 14:08 ` [PATCH v2 0/7] mmc: distinguish DDR timing mode for eMMC/UHS Seungwon Jeon
@ 2014-03-07 13:30   ` Seungwon Jeon
  2014-03-14 12:11   ` [PATCH RESEND " Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 13:30 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	rickard.andersson, linux, balajitk, g.liakhovetski, wei_wang,
	sameo, jh80.chung

These changes intend to distinguish two DDR timing modes related to eMMC & UHS.
Even though two modes are different actually, UHS_DDR50 is used as eMMC DDR mode.
MMC_TIMING_MMC_DDR52 mode is added.

Changes in V3:
	(6/7) Added MMC-DDR52 mode instead of replacing UHS-DDR50 in dw_mmc-exynos

Changes in V2:
	(2/7) Added MMC-DDR52 mode instead of replacing UHS-DDR50 in mmci
 
Seungwon Jeon (7):
  mmc: clarify DDR timing mode between SD-UHS and eMMC
  mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
  mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
  mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
  mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
  mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
  mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC

 drivers/mmc/core/debugfs.c        |    3 +++
 drivers/mmc/core/mmc.c            |    2 +-
 drivers/mmc/host/dw_mmc-exynos.c  |    5 ++---
 drivers/mmc/host/dw_mmc.c         |    2 +-
 drivers/mmc/host/mmci.c           |    6 ++++--
 drivers/mmc/host/omap_hsmmc.c     |    4 ++--
 drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
 drivers/mmc/host/sdhci.c          |    4 +++-
 drivers/mmc/host/sh_mmcif.c       |    9 +++++----
 include/linux/mmc/host.h          |    3 ++-
 10 files changed, 25 insertions(+), 15 deletions(-)

Thanks,
sw-j


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

* [PATCH v3 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:08 ` [PATCH v2 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC Seungwon Jeon
@ 2014-03-07 13:30   ` Seungwon Jeon
  2014-03-07 13:42     ` Jaehoon Chung
  2014-03-14 12:11   ` [PATCH RESEND " Seungwon Jeon
  1 sibling, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 13:30 UTC (permalink / raw)
  To: linux-mmc; +Cc: 'Chris Ball', 'Ulf Hansson'

This change distinguishes DDR timing mode of current
mixed usage to clarify device type.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/debugfs.c |    3 +++
 drivers/mmc/core/mmc.c     |    2 +-
 include/linux/mmc/host.h   |    3 ++-
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 54829c0..509229b 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_UHS_DDR50:
 		str = "sd uhs DDR50";
 		break;
+	case MMC_TIMING_MMC_DDR52:
+		str = "mmc DDR52";
+		break;
 	case MMC_TIMING_MMC_HS200:
 		str = "mmc high-speed SDR200";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 1ab5f3a..e22d851 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1264,7 +1264,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 					goto err;
 			}
 			mmc_card_set_ddr_mode(card);
-			mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
+			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
 			mmc_set_bus_width(card->host, bus_width);
 		}
 	}
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index cb61ea4..3535420 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -58,7 +58,8 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_SDR50	5
 #define MMC_TIMING_UHS_SDR104	6
 #define MMC_TIMING_UHS_DDR50	7
-#define MMC_TIMING_MMC_HS200	8
+#define MMC_TIMING_MMC_DDR52	8
+#define MMC_TIMING_MMC_HS200	9
 
 #define MMC_SDR_MODE		0
 #define MMC_1_2V_DDR_MODE	1
-- 
1.7.0.4



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

* [PATCH v3 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:08 ` [PATCH v2 2/7] mmc: mmci: " Seungwon Jeon
  2014-02-17 14:08   ` Ulf Hansson
@ 2014-03-07 13:30   ` Seungwon Jeon
  2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
  2 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 13:30 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Russell King', 'Ulf Hansson',
	'Chris Ball', 'Rickard Andersson'

Added MMC_DDR52 as eMMC's DDR mode distinguished from SD-UHS.

CC: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/mmci.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 771c60a..7e85393 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -299,7 +299,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
 	if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
 		clk |= MCI_ST_8BIT_BUS;
 
-	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
+	    host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
 		clk |= MCI_ST_UX500_NEG_EDGE;
 
 	mmci_write_clkreg(host, clk);
@@ -784,7 +785,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 			mmci_write_clkreg(host, clk);
 		}
 
-	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
+	    host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
 		datactrl |= MCI_ST_DPSM_DDRMODE;
 
 	/*
-- 
1.7.0.4



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

* [PATCH v3 3/7] mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:09 ` [PATCH v2 3/7] mmc: omap: " Seungwon Jeon
@ 2014-03-07 13:30   ` Seungwon Jeon
  2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 13:30 UTC (permalink / raw)
  To: linux-mmc; +Cc: 'Chris Ball', 'Balaji T K'

Replaced UHS_DDR50 with MMC_DDR52.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Balaji T K <balajitk@ti.com>
---
 drivers/mmc/host/omap_hsmmc.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index e91ee21..b4de63b 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -582,7 +582,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
 	 *	- MMC/SD clock coming out of controller > 25MHz
 	 */
 	if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
-	    (ios->timing != MMC_TIMING_UHS_DDR50) &&
+	    (ios->timing != MMC_TIMING_MMC_DDR52) &&
 	    ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
 		regval = OMAP_HSMMC_READ(host->base, HCTL);
 		if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
@@ -602,7 +602,7 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
 	u32 con;
 
 	con = OMAP_HSMMC_READ(host->base, CON);
-	if (ios->timing == MMC_TIMING_UHS_DDR50)
+	if (ios->timing == MMC_TIMING_MMC_DDR52)
 		con |= DDR;	/* configure in DDR mode */
 	else
 		con &= ~DDR;
-- 
1.7.0.4



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

* [PATCH v3 4/7] mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:09 ` [PATCH v2 4/7] mmc: sh_mmcif: " Seungwon Jeon
@ 2014-03-07 13:30   ` Seungwon Jeon
  2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 13:30 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Guennadi Liakhovetski'

Replaced UHS_DDR50 with MMC_DDR52.

CC: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/sh_mmcif.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 54730f4..656fbba 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -803,12 +803,13 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
 			break;
 		}
 		switch (host->timing) {
-		case MMC_TIMING_UHS_DDR50:
+		case MMC_TIMING_MMC_DDR52:
 			/*
 			 * MMC core will only set this timing, if the host
-			 * advertises the MMC_CAP_UHS_DDR50 capability. MMCIF
-			 * implementations with this capability, e.g. sh73a0,
-			 * will have to set it in their platform data.
+			 * advertises the MMC_CAP_1_8V_DDR/MMC_CAP_1_2V_DDR
+			 * capability. MMCIF implementations with this
+			 * capability, e.g. sh73a0, will have to set it
+			 * in their platform data.
 			 */
 			tmp |= CMD_SET_DARS;
 			break;
-- 
1.7.0.4



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

* [PATCH v3 5/7] mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:09 ` [PATCH v2 5/7] mmc: rtsx: " Seungwon Jeon
@ 2014-03-07 13:31   ` Seungwon Jeon
  2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 13:31 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Wei WANG', 'Samuel Ortiz'

Added MMC_DDR52 as eMMC's DDR mode is distinguished from SD-UHS.

CC: Wei WANG <wei_wang@realsil.com.cn>
CC: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index 5fb994f..8c2dd30 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -1075,6 +1075,7 @@ static int sd_set_timing(struct realtek_pci_sdmmc *host, unsigned char timing)
 		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0);
 		break;
 
+	case MMC_TIMING_MMC_DDR52:
 	case MMC_TIMING_UHS_DDR50:
 		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1,
 				0x0C | SD_ASYNC_FIFO_NOT_RST,
@@ -1155,6 +1156,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		host->vpclk = true;
 		host->double_clk = false;
 		break;
+	case MMC_TIMING_MMC_DDR52:
 	case MMC_TIMING_UHS_DDR50:
 	case MMC_TIMING_UHS_SDR25:
 		host->ssc_depth = RTSX_SSC_DEPTH_1M;
-- 
1.7.0.4



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

* [PATCH v3 6/7] mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:09 ` [PATCH v2 6/7] mmc: dw_mmc: " Seungwon Jeon
@ 2014-03-07 13:31   ` Seungwon Jeon
  2014-03-07 13:43     ` Jaehoon Chung
  2014-03-14 12:12   ` [PATCH RESEMD " Seungwon Jeon
  1 sibling, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 13:31 UTC (permalink / raw)
  To: linux-mmc; +Cc: 'Chris Ball', 'Jaehoon Chung'

Replaced UHS_DDR50 with MMC_DDR52. And MMC_CAP_UHS_DDR50
is removed because of non-implementation of UHS signaling.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/dw_mmc-exynos.c |    5 ++---
 drivers/mmc/host/dw_mmc.c        |    2 +-
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 3423c5e..a67e784 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -187,7 +187,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
 	unsigned long actual;
 	u8 div = priv->ciu_div + 1;
 
-	if (ios->timing == MMC_TIMING_UHS_DDR50) {
+	if (ios->timing == MMC_TIMING_MMC_DDR52) {
 		mci_writel(host, CLKSEL, priv->ddr_timing);
 		/* Should be double rate for DDR mode */
 		if (ios->bus_width == MMC_BUS_WIDTH_8)
@@ -386,8 +386,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
 
 /* Common capabilities of Exynos4/Exynos5 SoC */
 static unsigned long exynos_dwmmc_caps[4] = {
-	MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
-		MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
+	MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
 	MMC_CAP_CMD23,
 	MMC_CAP_CMD23,
 	MMC_CAP_CMD23,
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 0c56faa..ab704d9 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -962,7 +962,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	regs = mci_readl(slot->host, UHS_REG);
 
 	/* DDR mode set */
-	if (ios->timing == MMC_TIMING_UHS_DDR50)
+	if (ios->timing == MMC_TIMING_MMC_DDR52)
 		regs |= ((0x1 << slot->id) << 16);
 	else
 		regs &= ~((0x1 << slot->id) << 16);
-- 
1.7.0.4



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

* [PATCH v3 7/7] mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:09 ` [PATCH v2 7/7] mmc: sdhci: " Seungwon Jeon
@ 2014-03-07 13:31   ` Seungwon Jeon
  2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 13:31 UTC (permalink / raw)
  To: linux-mmc; +Cc: 'Chris Ball', 'Ulf Hansson'

Added MMC_DDR52 as eMMC's DDR mode is distinguished from SD-UHS.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/sdhci.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 7f95211..6926b42 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1510,6 +1510,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 
 		/* In case of UHS-I modes, set High Speed Enable */
 		if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+		    (ios->timing == MMC_TIMING_MMC_DDR52) ||
 		    (ios->timing == MMC_TIMING_UHS_SDR50) ||
 		    (ios->timing == MMC_TIMING_UHS_SDR104) ||
 		    (ios->timing == MMC_TIMING_UHS_DDR50) ||
@@ -1570,7 +1571,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 				ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
 			else if (ios->timing == MMC_TIMING_UHS_SDR50)
 				ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
-			else if (ios->timing == MMC_TIMING_UHS_DDR50)
+			else if ((ios->timing == MMC_TIMING_UHS_DDR50) ||
+				 (ios->timing == MMC_TIMING_MMC_DDR52))
 				ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
 			sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
 		}
-- 
1.7.0.4



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

* Re: [PATCH v3 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC
  2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-07 13:42     ` Jaehoon Chung
  0 siblings, 0 replies; 182+ messages in thread
From: Jaehoon Chung @ 2014-03-07 13:42 UTC (permalink / raw)
  To: Seungwon Jeon, linux-mmc; +Cc: 'Chris Ball', 'Ulf Hansson'

Acked-by: Jaehoon Chung <jh80.chung@samsung.com>

Best Regards,
Jaehoon Chung

On 03/07/2014 10:30 PM, Seungwon Jeon wrote:
> This change distinguishes DDR timing mode of current
> mixed usage to clarify device type.
> 
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>  drivers/mmc/core/debugfs.c |    3 +++
>  drivers/mmc/core/mmc.c     |    2 +-
>  include/linux/mmc/host.h   |    3 ++-
>  3 files changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index 54829c0..509229b 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>  	case MMC_TIMING_UHS_DDR50:
>  		str = "sd uhs DDR50";
>  		break;
> +	case MMC_TIMING_MMC_DDR52:
> +		str = "mmc DDR52";
> +		break;
>  	case MMC_TIMING_MMC_HS200:
>  		str = "mmc high-speed SDR200";
>  		break;
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 1ab5f3a..e22d851 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -1264,7 +1264,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>  					goto err;
>  			}
>  			mmc_card_set_ddr_mode(card);
> -			mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
> +			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
>  			mmc_set_bus_width(card->host, bus_width);
>  		}
>  	}
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index cb61ea4..3535420 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -58,7 +58,8 @@ struct mmc_ios {
>  #define MMC_TIMING_UHS_SDR50	5
>  #define MMC_TIMING_UHS_SDR104	6
>  #define MMC_TIMING_UHS_DDR50	7
> -#define MMC_TIMING_MMC_HS200	8
> +#define MMC_TIMING_MMC_DDR52	8
> +#define MMC_TIMING_MMC_HS200	9
>  
>  #define MMC_SDR_MODE		0
>  #define MMC_1_2V_DDR_MODE	1
> 


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

* Re: [PATCH v3 6/7] mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
  2014-03-07 13:31   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-07 13:43     ` Jaehoon Chung
  0 siblings, 0 replies; 182+ messages in thread
From: Jaehoon Chung @ 2014-03-07 13:43 UTC (permalink / raw)
  To: Seungwon Jeon, linux-mmc; +Cc: 'Chris Ball', 'Jaehoon Chung'

Acked-by: Jaehoon Chung <jh80.chung@samsung.com>

Best Regards,
Jaehoon Chung

On 03/07/2014 10:31 PM, Seungwon Jeon wrote:
> Replaced UHS_DDR50 with MMC_DDR52. And MMC_CAP_UHS_DDR50
> is removed because of non-implementation of UHS signaling.
> 
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>  drivers/mmc/host/dw_mmc-exynos.c |    5 ++---
>  drivers/mmc/host/dw_mmc.c        |    2 +-
>  2 files changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
> index 3423c5e..a67e784 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.c
> +++ b/drivers/mmc/host/dw_mmc-exynos.c
> @@ -187,7 +187,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>  	unsigned long actual;
>  	u8 div = priv->ciu_div + 1;
>  
> -	if (ios->timing == MMC_TIMING_UHS_DDR50) {
> +	if (ios->timing == MMC_TIMING_MMC_DDR52) {
>  		mci_writel(host, CLKSEL, priv->ddr_timing);
>  		/* Should be double rate for DDR mode */
>  		if (ios->bus_width == MMC_BUS_WIDTH_8)
> @@ -386,8 +386,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
>  
>  /* Common capabilities of Exynos4/Exynos5 SoC */
>  static unsigned long exynos_dwmmc_caps[4] = {
> -	MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
> -		MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
> +	MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
>  	MMC_CAP_CMD23,
>  	MMC_CAP_CMD23,
>  	MMC_CAP_CMD23,
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 0c56faa..ab704d9 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -962,7 +962,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>  	regs = mci_readl(slot->host, UHS_REG);
>  
>  	/* DDR mode set */
> -	if (ios->timing == MMC_TIMING_UHS_DDR50)
> +	if (ios->timing == MMC_TIMING_MMC_DDR52)
>  		regs |= ((0x1 << slot->id) << 16);
>  	else
>  		regs &= ~((0x1 << slot->id) << 16);
> 


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

* [PATCH v2 0/5]  update selection of bus speed mode for eMMC
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
@ 2014-03-07 14:35   ` Seungwon Jeon
  2014-03-13 14:41     ` Ulf Hansson
  2014-03-13  9:52   ` [PATCH RESEND " Jaehoon Chung
                     ` (27 subsequent siblings)
  28 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 14:35 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

This series contains the change for selection of bus speed mode.
Previous implementation is complicated and some sequence is duplicated.
And specially, HS400 mode eMMC5.0 is introduced this time.

- Continued/Updated since "[PATCH 0/3] mmc: update bus speed mode" series.
  (Applied some comments from Ulf Hansson, Jackey Shen.)
- Tested at EXYNOS SOC.

Seungwon Jeon (5):
  mmc: drop the speed mode of card's state
  mmc: identify available device type to select
  mmc: step power class after final selection of bus mode
  mmc: rework selection of bus speed mode
  mmc: add support for HS400 mode of eMMC5.0

 drivers/mmc/core/bus.c     |    9 +-
 drivers/mmc/core/core.c    |    3 +-
 drivers/mmc/core/debugfs.c |    5 +-
 drivers/mmc/core/mmc.c     |  688 +++++++++++++++++++++++++++-----------------
 drivers/mmc/core/sd.c      |   16 +-
 drivers/mmc/core/sd.h      |    1 -
 drivers/mmc/core/sdio.c    |    8 +-
 include/linux/mmc/card.h   |   31 +--
 include/linux/mmc/host.h   |   42 +++-
 include/linux/mmc/mmc.h    |   23 ++-
 10 files changed, 505 insertions(+), 321 deletions(-)



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

* [PATCH v2 1/5] mmc: drop the speed mode of card's state
  2014-02-15 14:18 ` [PATCH RESEND 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
  2014-02-17 14:38   ` Ulf Hansson
@ 2014-03-07 14:36   ` Seungwon Jeon
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
  2 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 14:36 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Timing mode identifier has same role and can take the place
of speed mode. This change removes all related speed mode.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
Changes in v2:
	Removed reference pointer to 'ios'.

 drivers/mmc/core/bus.c   |    8 ++++----
 drivers/mmc/core/core.c  |    3 +--
 drivers/mmc/core/mmc.c   |   11 +++--------
 drivers/mmc/core/sd.c    |   16 +++-------------
 drivers/mmc/core/sd.h    |    1 -
 drivers/mmc/core/sdio.c  |    8 ++------
 include/linux/mmc/card.h |   23 ++++++-----------------
 include/linux/mmc/host.h |   23 +++++++++++++++++++++++
 8 files changed, 42 insertions(+), 51 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 8246448..f37e9d6 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -341,16 +341,16 @@ int mmc_add_card(struct mmc_card *card)
 	if (mmc_host_is_spi(card->host)) {
 		pr_info("%s: new %s%s%s card on SPI\n",
 			mmc_hostname(card->host),
-			mmc_card_highspeed(card) ? "high speed " : "",
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_hs(card) ? "high speed " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			type);
 	} else {
 		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
-			(mmc_card_highspeed(card) ? "high speed " : ""),
+			(mmc_card_hs(card) ? "high speed " : ""),
 			(mmc_card_hs200(card) ? "HS200 " : ""),
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
 	}
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index dc7a5fb..5967889 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2182,7 +2182,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
 	struct mmc_command cmd = {0};
 
-	if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+	if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
 		return 0;
 
 	cmd.opcode = MMC_SET_BLOCKLEN;
@@ -2262,7 +2262,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
 		}
 	}
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
 	if (mmc_host_is_spi(host)) {
 		host->ios.chip_select = MMC_CS_HIGH;
 		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e22d851..db9655f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1091,11 +1091,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		} else {
 			if (card->ext_csd.hs_max_dtr > 52000000 &&
 			    host->caps2 & MMC_CAP2_HS200) {
-				mmc_card_set_hs200(card);
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
 			} else {
-				mmc_card_set_highspeed(card);
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
 			}
 		}
@@ -1106,10 +1104,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
+	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
 		if (max_dtr > card->ext_csd.hs_max_dtr)
 			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_highspeed(card) && (max_dtr > 52000000))
+		if (mmc_card_hs(card) && (max_dtr > 52000000))
 			max_dtr = 52000000;
 	} else if (max_dtr > card->csd.max_dtr) {
 		max_dtr = card->csd.max_dtr;
@@ -1120,7 +1118,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
 			&& (host->caps & MMC_CAP_1_8V_DDR))
 				ddr = MMC_1_8V_DDR_MODE;
@@ -1263,7 +1261,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 				if (err)
 					goto err;
 			}
-			mmc_card_set_ddr_mode(card);
 			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
 			mmc_set_bus_width(card->host, bus_width);
 		}
@@ -1507,7 +1504,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 		err = mmc_sleep(host);
 	else if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 
 	if (!err) {
 		mmc_power_off(host);
@@ -1637,7 +1633,6 @@ static int mmc_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 	mmc_claim_host(host);
 	ret = mmc_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 2dd359d..9fc5b31 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -895,7 +895,7 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if (max_dtr > card->sw_caps.hs_max_dtr)
 			max_dtr = card->sw_caps.hs_max_dtr;
 	} else if (max_dtr > card->csd.max_dtr) {
@@ -905,12 +905,6 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 	return max_dtr;
 }
 
-void mmc_sd_go_highspeed(struct mmc_card *card)
-{
-	mmc_card_set_highspeed(card);
-	mmc_set_timing(card->host, MMC_TIMING_SD_HS);
-}
-
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -985,16 +979,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_sd_init_uhs_card(card);
 		if (err)
 			goto free_card;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Attempt to change to high-speed (if supported)
 		 */
 		err = mmc_sd_switch_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto free_card;
 
@@ -1089,7 +1080,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
 
 	if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
+
 	if (!err) {
 		mmc_power_off(host);
 		mmc_card_set_suspended(host->card);
@@ -1198,7 +1189,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
 	ret = mmc_sd_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
index 4b34b24..aab824a 100644
--- a/drivers/mmc/core/sd.h
+++ b/drivers/mmc/core/sd.h
@@ -12,6 +12,5 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 	bool reinit);
 unsigned mmc_sd_get_max_clock(struct mmc_card *card);
 int mmc_sd_switch_hs(struct mmc_card *card);
-void mmc_sd_go_highspeed(struct mmc_card *card);
 
 #endif
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4d721c6..ef57d2d 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		/*
 		 * The SDIO specification doesn't mention how
 		 * the CIS transfer speed register relates to
@@ -733,7 +733,6 @@ try_again:
 		mmc_set_clock(host, card->cis.max_dtr);
 
 		if (card->cccr.high_speed) {
-			mmc_card_set_highspeed(card);
 			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		}
 
@@ -792,16 +791,13 @@ try_again:
 		err = mmc_sdio_init_uhs_card(card);
 		if (err)
 			goto remove;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Switch to high-speed (if supported).
 		 */
 		err = sdio_enable_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto remove;
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index b730272..5473133 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -194,6 +194,7 @@ struct sdio_cis {
 };
 
 struct mmc_host;
+struct mmc_ios;
 struct sdio_func;
 struct sdio_func_tuple;
 
@@ -250,15 +251,11 @@ struct mmc_card {
 	unsigned int		state;		/* (our) card state */
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
 #define MMC_STATE_READONLY	(1<<1)		/* card is read-only */
-#define MMC_STATE_HIGHSPEED	(1<<2)		/* card is in high speed mode */
-#define MMC_STATE_BLOCKADDR	(1<<3)		/* card uses block-addressing */
-#define MMC_STATE_HIGHSPEED_DDR (1<<4)		/* card is in high speed mode */
-#define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra high speed mode */
-#define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
-#define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
-#define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
-#define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
-#define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
+#define MMC_STATE_BLOCKADDR	(1<<2)		/* card uses block-addressing */
+#define MMC_CARD_SDXC		(1<<3)		/* card is SDXC */
+#define MMC_CARD_REMOVED	(1<<4)		/* card has been removed */
+#define MMC_STATE_DOING_BKOPS	(1<<5)		/* card is doing BKOPS */
+#define MMC_STATE_SUSPENDED	(1<<6)		/* card is suspended */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -418,11 +415,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
-#define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
-#define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
-#define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
@@ -430,11 +423,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
-#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
-#define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
-#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_doing_bkops(c)	((c)->state |= MMC_STATE_DOING_BKOPS)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 3535420..2f263ae 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -17,6 +17,7 @@
 #include <linux/fault-inject.h>
 
 #include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -476,4 +477,26 @@ static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
 	return host->ios.clock;
 }
 #endif
+
+static inline int mmc_card_hs(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_SD_HS ||
+		card->host->ios.timing == MMC_TIMING_MMC_HS;
+}
+
+static inline int mmc_card_uhs(struct mmc_card *card)
+{
+	return card->host->ios.timing >= MMC_TIMING_UHS_SDR12 &&
+		card->host->ios.timing <= MMC_TIMING_UHS_DDR50;
+}
+
+static inline bool mmc_card_hs200(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_HS200;
+}
+
+static inline bool mmc_card_ddr52(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
+}
 #endif /* LINUX_MMC_HOST_H */
-- 
1.7.0.4



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

* [PATCH v2 2/5] mmc: identify available device type to select
  2014-02-15 14:18 ` [PATCH RESEND 2/5] mmc: identify available device type to select Seungwon Jeon
@ 2014-03-07 14:36   ` Seungwon Jeon
  2014-03-10 10:14     ` Jaehoon Chung
  2014-03-13 14:02     ` Ulf Hansson
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
  1 sibling, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 14:36 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Device types which are supported by both host and device
can be identified when EXT_CSD is read. There is no need to
check host's capability anymore.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
Changes in v2:
	Just rebased with latest one.

 drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
 include/linux/mmc/card.h |    6 ++-
 include/linux/mmc/host.h |    6 ---
 include/linux/mmc/mmc.h  |   12 +++++--
 4 files changed, 56 insertions(+), 45 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index db9655f..0abece0 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0;
+	unsigned int avail_type = 0;
 
-	if (card_type & EXT_CSD_CARD_TYPE_26)
+	if (caps & MMC_CAP_MMC_HIGHSPEED &&
+	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
 		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
+	}
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
-			card_type & EXT_CSD_CARD_TYPE_52)
+	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
 		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
+	}
 
-	if ((caps & MMC_CAP_1_8V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
-	    (caps & MMC_CAP_1_2V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
+	if (caps & MMC_CAP_1_8V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
 		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
+	}
 
-	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
-	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
+	if (caps & MMC_CAP_1_2V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
+	}
+
+	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
 		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
+		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
+	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
-	card->ext_csd.card_type = card_type;
+	card->mmc_avail_type = avail_type;
 }
 
 /*
@@ -708,6 +726,11 @@ static struct device_type mmc_type = {
 	.groups = mmc_attr_groups,
 };
 
+static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
+{
+	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+}
+
 /*
  * Select the PowerClass for the current bus width
  * If power class is defined for 4/8 bit bus in the
@@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
 
 	host = card->host;
 
-	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
-			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
 
-	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
-			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
 
 	/* If fails try again during next card power cycle */
@@ -1072,10 +1093,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	if (card->ext_csd.hs_max_dtr != 0) {
 		err = 0;
-		if (card->ext_csd.hs_max_dtr > 52000000 &&
-		    host->caps2 & MMC_CAP2_HS200)
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 			err = mmc_select_hs200(card);
-		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
+		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
 			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					EXT_CSD_HS_TIMING, 1,
 					card->ext_csd.generic_cmd6_time,
@@ -1089,13 +1109,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			       mmc_hostname(card->host));
 			err = 0;
 		} else {
-			if (card->ext_csd.hs_max_dtr > 52000000 &&
-			    host->caps2 & MMC_CAP2_HS200) {
+			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
-			} else {
+			else
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-			}
 		}
 	}
 
@@ -1118,14 +1136,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_hs(card)) {
-		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-			&& (host->caps & MMC_CAP_1_8V_DDR))
-				ddr = MMC_1_8V_DDR_MODE;
-		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-			&& (host->caps & MMC_CAP_1_2V_DDR))
-				ddr = MMC_1_2V_DDR_MODE;
-	}
+	if (mmc_card_hs(card))
+		ddr = mmc_snoop_ddr(card);
 
 	/*
 	 * Indicate HS200 SDR mode (if supported).
@@ -1145,8 +1157,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		 * 3. set the clock to > 52Mhz <=200MHz and
 		 * 4. execute tuning for HS200
 		 */
-		if ((host->caps2 & MMC_CAP2_HS200) &&
-		    card->host->ops->execute_tuning) {
+		if (card->host->ops->execute_tuning) {
 			mmc_host_clk_hold(card->host);
 			err = card->host->ops->execute_tuning(card->host,
 				MMC_SEND_TUNING_BLOCK_HS200);
@@ -1255,7 +1266,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			 *
 			 * WARNING: eMMC rules are NOT the same as SD DDR
 			 */
-			if (ddr == MMC_1_2V_DDR_MODE) {
+			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
 				err = __mmc_set_signal_voltage(host,
 					MMC_SIGNAL_VOLTAGE_120);
 				if (err)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 5473133..c232b10 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -68,7 +68,6 @@ struct mmc_ext_csd {
 #define MMC_HIGH_DDR_MAX_DTR	52000000
 #define MMC_HS200_MAX_DTR	200000000
 	unsigned int		sectors;
-	unsigned int		card_type;
 	unsigned int		hc_erase_size;		/* In sectors */
 	unsigned int		hc_erase_timeout;	/* In milliseconds */
 	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
@@ -297,7 +296,10 @@ struct mmc_card {
 	const char		**info;		/* info strings */
 	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
 
-	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+	union {
+		unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+		unsigned int		mmc_avail_type;	/* supported device type by both host and card */
+	};
 
 	struct dentry		*debugfs_root;
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 2f263ae..1ee3c10 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -62,12 +62,6 @@ struct mmc_ios {
 #define MMC_TIMING_MMC_DDR52	8
 #define MMC_TIMING_MMC_HS200	9
 
-#define MMC_SDR_MODE		0
-#define MMC_1_2V_DDR_MODE	1
-#define MMC_1_8V_DDR_MODE	2
-#define MMC_1_2V_SDR_MODE	3
-#define MMC_1_8V_SDR_MODE	4
-
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
 #define MMC_SIGNAL_VOLTAGE_330	0
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 50bcde3..f734c0c 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -354,18 +354,22 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#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_MASK	0x3F	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
+				 EXT_CSD_CARD_TYPE_HS_52)
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
 					     /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
 					     /* DDR mode @1.2V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
 					| EXT_CSD_CARD_TYPE_DDR_1_2V)
-#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
-#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_8V	(1<<4)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_2V	(1<<5)	/* Card can run at 200MHz */
 						/* SDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS200_1_2V)
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
-- 
1.7.0.4



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

* [PATCH v2 3/5] mmc: step power class after final selection of bus mode
  2014-02-15 14:23 ` [PATCH RESEND 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
@ 2014-03-07 14:36   ` Seungwon Jeon
  2014-03-13 14:28     ` Ulf Hansson
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
  1 sibling, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 14:36 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Power class is changed once only after selection of bus modes
including speed and bus-width finishes finally.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
Changes in v2:
	Cleaned up some unnecessary codes.

 drivers/mmc/core/mmc.c |   94 +++++++++++++++++++++++++++--------------------
 1 files changed, 54 insertions(+), 40 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0abece0..88ff217 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -737,17 +737,13 @@ static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
  * extended CSD register, select it by executing the
  * mmc_switch command.
  */
-static int mmc_select_powerclass(struct mmc_card *card,
-		unsigned int bus_width)
+static int __mmc_select_powerclass(struct mmc_card *card,
+				   unsigned int bus_width)
 {
 	int err = 0;
 	unsigned int pwrclass_val = 0;
-	struct mmc_host *host;
-
-	BUG_ON(!card);
-
-	host = card->host;
-	BUG_ON(!host);
+	struct mmc_host *host = card->host;
+	struct mmc_ext_csd *ext_csd = &card->ext_csd;
 
 	/* Power class selection is supported for versions >= 4.0 */
 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
@@ -759,14 +755,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
 
 	switch (1 << host->ios.vdd) {
 	case MMC_VDD_165_195:
-		if (host->ios.clock <= 26000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
-		else if	(host->ios.clock <= 52000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_26_195;
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-				card->ext_csd.raw_pwr_cl_52_195 :
-				card->ext_csd.raw_pwr_cl_ddr_52_195;
-		else if (host->ios.clock <= 200000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
+				ext_csd->raw_pwr_cl_52_195 :
+				ext_csd->raw_pwr_cl_ddr_52_195;
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_200_195;
 		break;
 	case MMC_VDD_27_28:
 	case MMC_VDD_28_29:
@@ -777,14 +773,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	case MMC_VDD_33_34:
 	case MMC_VDD_34_35:
 	case MMC_VDD_35_36:
-		if (host->ios.clock <= 26000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
-		else if	(host->ios.clock <= 52000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_26_360;
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-				card->ext_csd.raw_pwr_cl_52_360 :
-				card->ext_csd.raw_pwr_cl_ddr_52_360;
-		else if (host->ios.clock <= 200000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
+				ext_csd->raw_pwr_cl_52_360 :
+				ext_csd->raw_pwr_cl_ddr_52_360;
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -810,6 +806,37 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	return err;
 }
 
+static int mmc_select_powerclass(struct mmc_card *card)
+{
+	int err, ddr;
+	u32 bus_width, ext_csd_bits;
+	struct mmc_host *host = card->host;
+
+	/* Power class selection is supported for versions >= 4.0 */
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	/* Power class values are defined only for 4/8 bit bus */
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ddr = mmc_snoop_ddr(card);
+	if (ddr)
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+	else
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
+
+	err = __mmc_select_powerclass(card, ext_csd_bits);
+	if (err)
+		pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
+			mmc_hostname(host), 1 << bus_width, ddr);
+
+	return err;
+}
+
 /*
  * Selects the desired buswidth and switch to the HS200 mode
  * if bus width set without error
@@ -1171,11 +1198,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
 		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
 				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-		err = mmc_select_powerclass(card, ext_csd_bits);
-		if (err)
-			pr_warning("%s: power class selection to bus width %d"
-				   " failed\n", mmc_hostname(card->host),
-				   1 << bus_width);
 	}
 
 	/*
@@ -1204,12 +1226,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			bus_width = bus_widths[idx];
 			if (bus_width == MMC_BUS_WIDTH_1)
 				ddr = 0; /* no DDR for 1-bit width */
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width);
 
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
@@ -1234,13 +1250,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		}
 
 		if (!err && ddr) {
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d ddr %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width, ddr);
-
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][1],
@@ -1278,6 +1287,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
+	 * Choose the power calss with selected bus interface
+	 */
+	mmc_select_powerclass(card);
+
+	/*
 	 * Enable HPI feature (if supported)
 	 */
 	if (card->ext_csd.hpi) {
-- 
1.7.0.4



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

* [PATCH v2 4/5] mmc: rework selection of bus speed mode
  2014-02-15 14:24 ` [PATCH RESEND 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
@ 2014-03-07 14:36   ` Seungwon Jeon
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 14:36 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Current implementation for bus speed mode selection is too
complicated. This patch is to simplify the codes and remove
some duplicate parts.

The following changes are including:
* Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
* Rearranged the mode selection sequence with supported device type
* Adds maximum speed for HS200 mode(hs200_max_dtr)
* Adds field definition for HS_TIMING of EXT_CSD

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
Changes in v2:
	Cleaned up some unnecessary codes.

 drivers/mmc/core/debugfs.c |    2 +-
 drivers/mmc/core/mmc.c     |  432 ++++++++++++++++++++++++--------------------
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/mmc.h    |    4 +
 4 files changed, 239 insertions(+), 200 deletions(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 509229b..1f730db 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -139,7 +139,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 		str = "mmc DDR52";
 		break;
 	case MMC_TIMING_MMC_HS200:
-		str = "mmc high-speed SDR200";
+		str = "mmc HS200";
 		break;
 	default:
 		str = "invalid";
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 88ff217..e356a54 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -242,7 +242,7 @@ static void mmc_select_card_type(struct mmc_card *card)
 	struct mmc_host *host = card->host;
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
-	unsigned int hs_max_dtr = 0;
+	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
@@ -271,17 +271,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 
 	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
 	}
 
 	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
+	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
 }
 
@@ -838,37 +839,46 @@ static int mmc_select_powerclass(struct mmc_card *card)
 }
 
 /*
- * Selects the desired buswidth and switch to the HS200 mode
- * if bus width set without error
+ * Set the bus speed for the selected speed mode.
  */
-static int mmc_select_hs200(struct mmc_card *card)
+static void mmc_set_bus_speed(struct mmc_card *card)
+{
+	unsigned int max_dtr = (unsigned int)-1;
+
+	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+		max_dtr = card->ext_csd.hs200_max_dtr;
+	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
+		max_dtr = card->ext_csd.hs_max_dtr;
+	else if (max_dtr > card->csd.max_dtr)
+		max_dtr = card->csd.max_dtr;
+
+	mmc_set_clock(card->host, max_dtr);
+}
+
+/*
+ * Select the bus width amoung 4-bit and 8-bit(SDR).
+ * If the bus width is changed successfully, return the slected width value.
+ * Zero is returned instead of error value if the wide width is not supported.
+ */
+static int mmc_select_bus_width(struct mmc_card *card)
 {
-	int idx, err = -EINVAL;
-	struct mmc_host *host;
 	static unsigned ext_csd_bits[] = {
-		EXT_CSD_BUS_WIDTH_4,
 		EXT_CSD_BUS_WIDTH_8,
+		EXT_CSD_BUS_WIDTH_4,
 	};
 	static unsigned bus_widths[] = {
-		MMC_BUS_WIDTH_4,
 		MMC_BUS_WIDTH_8,
+		MMC_BUS_WIDTH_4,
 	};
+	struct mmc_host *host = card->host;
+	unsigned idx, bus_width = 0;
+	int err = 0;
 
-	BUG_ON(!card);
-
-	host = card->host;
-
-	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
-
-	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
-
-	/* If fails try again during next card power cycle */
-	if (err)
-		goto err;
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
+	    !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
+		return 0;
 
-	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
 
 	/*
 	 * Unlike SD, MMC cards dont have a configuration register to notify
@@ -876,8 +886,7 @@ static int mmc_select_hs200(struct mmc_card *card)
 	 * 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 >= 0; idx--) {
-
+	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
@@ -892,27 +901,203 @@ static int mmc_select_hs200(struct mmc_card *card)
 		if (err)
 			continue;
 
-		mmc_set_bus_width(card->host, bus_widths[idx]);
+		bus_width = bus_widths[idx];
+		mmc_set_bus_width(host, bus_width);
 
+		/*
+		 * If controller can't handle bus width test,
+		 * compare ext_csd previously read in 1 bit mode
+		 * against ext_csd at new bus width
+		 */
 		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-			err = mmc_compare_ext_csds(card, bus_widths[idx]);
+			err = mmc_compare_ext_csds(card, bus_width);
 		else
-			err = mmc_bus_test(card, bus_widths[idx]);
-		if (!err)
+			err = mmc_bus_test(card, bus_width);
+
+		if (!err) {
+			err = bus_width;
 			break;
+		} else {
+			pr_warn("%s: switch to bus width %d failed\n",
+				mmc_hostname(host), ext_csd_bits[idx]);
+		}
 	}
 
-	/* switch to HS200 mode if bus width set successfully */
+	return err;
+}
+
+/*
+ * Switch to the high-speed mode
+ */
+static int mmc_select_hs(struct mmc_card *card)
+{
+	int err;
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
 	if (!err)
+		mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+
+	return err;
+}
+
+/*
+ * Activate wide bus and DDR if supported.
+ */
+static int mmc_select_hs_ddr(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	u32 bus_width, ext_csd_bits;
+	int err = 0, ddr;
+
+	ddr = mmc_snoop_ddr(card);
+	if (!(ddr & EXT_CSD_CARD_TYPE_DDR_52))
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+		EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_BUS_WIDTH,
+			ext_csd_bits,
+			card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width %d ddr failed\n",
+			mmc_hostname(host), 1 << bus_width);
+		return err;
+	}
+
+	/*
+	 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+	 * signaling.
+	 *
+	 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+	 *
+	 * 1.8V vccq at 3.3V core voltage (vcc) is not required
+	 * in the JEDEC spec for DDR.
+	 *
+	 * Do not force change in vccq since we are obviously
+	 * working and no change to vccq is needed.
+	 *
+	 * WARNING: eMMC rules are NOT the same as SD DDR
+	 */
+	if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		err = __mmc_set_signal_voltage(host,
+				MMC_SIGNAL_VOLTAGE_120);
+		if (err)
+			return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
+
+	return err;
+}
+
+/*
+ * For device supporting HS200 mode, the following sequence
+ * should be done before executing the tuning process.
+ * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
+ * 2. switch to HS200 mode
+ * 3. set the clock to > 52Mhz and <=200MHz
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = -EINVAL;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+
+	/* If fails try again during next card power cycle */
+	if (err)
+		goto err;
+
+	/*
+	 * Set the bus width(4 or 8) with host's support and
+	 * switch to HS200 mode if bus width is set successfully.
+	 */
+	err = mmc_select_bus_width(card);
+	if (!IS_ERR_VALUE(err)) {
 		err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				EXT_CSD_HS_TIMING, 2,
-				card->ext_csd.generic_cmd6_time,
-				true, true, true);
+				   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
+				   card->ext_csd.generic_cmd6_time,
+				   true, true, true);
+		if (!err)
+			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+	}
 err:
 	return err;
 }
 
 /*
+ * Activate High Speed or HS200 mode if supported.
+ */
+static int mmc_select_timing(struct mmc_card *card)
+{
+	int err = 0;
+
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
+	     card->ext_csd.hs_max_dtr == 0))
+		goto bus_speed;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+		err = mmc_select_hs200(card);
+	else if(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
+		err = mmc_select_hs(card);
+
+	if (err && err != -EBADMSG)
+		return err;
+
+	if (err) {
+		pr_warn("%s: switch to %s failed\n",
+			mmc_card_hs(card) ? "high-speed" :
+			(mmc_card_hs200(card) ? "hs200" : ""),
+			mmc_hostname(card->host));
+		err = 0;
+	}
+
+bus_speed:
+	/*
+	 * Set the bus speed to the selected bus timing.
+	 * If timing is not selected, backward compatible is the default.
+	 */
+	mmc_set_bus_speed(card);
+	return err;
+}
+
+/*
+ * Execute tuning sequence to seek the proper bus operating
+ * conditions for HS200, which sends CMD21 to the device.
+ */
+static int mmc_hs200_tuning(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	if (host->ops->execute_tuning) {
+		mmc_host_clk_hold(host);
+		err = host->ops->execute_tuning(host,
+				MMC_SEND_TUNING_BLOCK_HS200);
+		mmc_host_clk_release(host);
+
+		if (err)
+			pr_warn("%s: tuning execution failed\n",
+				mmc_hostname(host));
+	}
+
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -922,9 +1107,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	struct mmc_card *oldcard)
 {
 	struct mmc_card *card;
-	int err, ddr = 0;
+	int err;
 	u32 cid[4];
-	unsigned int max_dtr;
 	u32 rocr;
 	u8 *ext_csd = NULL;
 
@@ -1116,173 +1300,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
-	 * Activate high speed (if supported)
-	 */
-	if (card->ext_csd.hs_max_dtr != 0) {
-		err = 0;
-		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-			err = mmc_select_hs200(card);
-		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
-			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					EXT_CSD_HS_TIMING, 1,
-					card->ext_csd.generic_cmd6_time,
-					true, true, true);
-
-		if (err && err != -EBADMSG)
-			goto free_card;
-
-		if (err) {
-			pr_warning("%s: switch to highspeed failed\n",
-			       mmc_hostname(card->host));
-			err = 0;
-		} else {
-			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-				mmc_set_timing(card->host,
-					       MMC_TIMING_MMC_HS200);
-			else
-				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-		}
-	}
-
-	/*
-	 * Compute bus speed.
-	 */
-	max_dtr = (unsigned int)-1;
-
-	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
-		if (max_dtr > card->ext_csd.hs_max_dtr)
-			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_hs(card) && (max_dtr > 52000000))
-			max_dtr = 52000000;
-	} else if (max_dtr > card->csd.max_dtr) {
-		max_dtr = card->csd.max_dtr;
-	}
-
-	mmc_set_clock(host, max_dtr);
-
-	/*
-	 * Indicate DDR mode (if supported).
+	 * Select timing interface
 	 */
-	if (mmc_card_hs(card))
-		ddr = mmc_snoop_ddr(card);
+	err = mmc_select_timing(card);
+	if (err)
+		goto free_card;
 
-	/*
-	 * Indicate HS200 SDR mode (if supported).
-	 */
 	if (mmc_card_hs200(card)) {
-		u32 ext_csd_bits;
-		u32 bus_width = card->host->ios.bus_width;
-
-		/*
-		 * For devices supporting HS200 mode, the bus width has
-		 * to be set before executing the tuning function. If
-		 * set before tuning, then device will respond with CRC
-		 * errors for responses on CMD line. So for HS200 the
-		 * sequence will be
-		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
-		 * 2. switch to HS200 mode
-		 * 3. set the clock to > 52Mhz <=200MHz and
-		 * 4. execute tuning for HS200
-		 */
-		if (card->host->ops->execute_tuning) {
-			mmc_host_clk_hold(card->host);
-			err = card->host->ops->execute_tuning(card->host,
-				MMC_SEND_TUNING_BLOCK_HS200);
-			mmc_host_clk_release(card->host);
-		}
-		if (err) {
-			pr_warning("%s: tuning execution failed\n",
-				   mmc_hostname(card->host));
+		err = mmc_hs200_tuning(card);
+		if (err)
 			goto err;
-		}
-
-		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
-				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-	}
-
-	/*
-	 * Activate wide bus and DDR (if supported).
-	 */
-	if (!mmc_card_hs200(card) &&
-	    (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
-	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
-		static unsigned ext_csd_bits[][2] = {
-			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
-			{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
-			{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
-		};
-		static unsigned bus_widths[] = {
-			MMC_BUS_WIDTH_8,
-			MMC_BUS_WIDTH_4,
-			MMC_BUS_WIDTH_1
-		};
-		unsigned idx, bus_width = 0;
-
-		if (host->caps & MMC_CAP_8_BIT_DATA)
-			idx = 0;
-		else
-			idx = 1;
-		for (; idx < ARRAY_SIZE(bus_widths); idx++) {
-			bus_width = bus_widths[idx];
-			if (bus_width == MMC_BUS_WIDTH_1)
-				ddr = 0; /* no DDR for 1-bit width */
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][0],
-					 card->ext_csd.generic_cmd6_time);
-			if (!err) {
-				mmc_set_bus_width(card->host, bus_width);
-
-				/*
-				 * If controller can't handle bus width test,
-				 * compare ext_csd previously read in 1 bit mode
-				 * against ext_csd at new bus width
-				 */
-				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					err = mmc_compare_ext_csds(card,
-						bus_width);
-				else
-					err = mmc_bus_test(card, bus_width);
-				if (!err)
-					break;
-			}
-		}
-
-		if (!err && ddr) {
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][1],
-					 card->ext_csd.generic_cmd6_time);
-		}
-		if (err) {
-			pr_warning("%s: switch to bus width %d ddr %d "
-				"failed\n", mmc_hostname(card->host),
-				1 << bus_width, ddr);
-			goto free_card;
-		} else if (ddr) {
-			/*
-			 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
-			 * signaling.
-			 *
-			 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
-			 *
-			 * 1.8V vccq at 3.3V core voltage (vcc) is not required
-			 * in the JEDEC spec for DDR.
-			 *
-			 * Do not force change in vccq since we are obviously
-			 * working and no change to vccq is needed.
-			 *
-			 * WARNING: eMMC rules are NOT the same as SD DDR
-			 */
-			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
-				err = __mmc_set_signal_voltage(host,
-					MMC_SIGNAL_VOLTAGE_120);
-				if (err)
-					goto err;
-			}
-			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
-			mmc_set_bus_width(card->host, bus_width);
+	} else if (mmc_card_hs(card)) {
+		/* Select the desired bus width optionally */
+		err = mmc_select_bus_width(card);
+		if (!IS_ERR_VALUE(err)) {
+			err = mmc_select_hs_ddr(card);
+			if (err)
+				goto err;
 		}
 	}
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c232b10..def6814 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -63,6 +63,7 @@ struct mmc_ext_csd {
 	unsigned int            power_off_longtime;     /* Units: ms */
 	u8			power_off_notification;	/* state */
 	unsigned int		hs_max_dtr;
+	unsigned int		hs200_max_dtr;
 #define MMC_HIGH_26_MAX_DTR	26000000
 #define MMC_HIGH_52_MAX_DTR	52000000
 #define MMC_HIGH_DDR_MAX_DTR	52000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f734c0c..f429f13 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -377,6 +377,10 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
 #define EXT_CSD_SEC_GB_CL_EN	BIT(4)
-- 
1.7.0.4



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

* [PATCH v2 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-02-15 14:24 ` [PATCH RESEND 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
@ 2014-03-07 14:36   ` Seungwon Jeon
  2014-03-11  0:45     ` Jackey Shen
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
  1 sibling, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-07 14:36 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

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: Seungwon Jeon <tgih.jun@samsung.com>
---
Changes in v2:
	Cleaned up some unnecessary codes.

 drivers/mmc/core/bus.c     |    1 +
 drivers/mmc/core/debugfs.c |    3 +
 drivers/mmc/core/mmc.c     |  120 +++++++++++++++++++++++++++++++++++++++++---
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/host.h   |   15 +++++-
 include/linux/mmc/mmc.h    |    7 ++-
 6 files changed, 138 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index f37e9d6..d2dbf02 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_hs(card) ? "high speed " : ""),
+			mmc_card_hs400(card) ? "HS400 " :
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 1f730db..91eb162 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_MMC_HS200:
 		str = "mmc HS200";
 		break;
+	case MMC_TIMING_MMC_HS400:
+		str = "mmc HS400";
+		break;
 	default:
 		str = "invalid";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e356a54..998b0af 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 static void mmc_select_card_type(struct mmc_card *card)
 {
 	struct mmc_host *host = card->host;
-	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
+	u8 card_type = card->ext_csd.raw_card_type;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
@@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
+	if (caps2 & MMC_CAP2_HS400_1_8V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS400_1_2V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
+	}
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
@@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
 		card->ext_csd.raw_pwr_cl_ddr_52_360 =
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
+		card->ext_csd.raw_pwr_cl_ddr_200_360 =
+			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
 	}
 
 	if (card->ext_csd.rev >= 5) {
@@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
 		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
 			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
 		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
-			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
+		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
+
 	if (err)
 		err = -EINVAL;
 
@@ -729,7 +746,8 @@ static struct device_type mmc_type = {
 
 static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
 {
-	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	return card->mmc_avail_type &
+		(EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_HS400);
 }
 
 /*
@@ -781,7 +799,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
 				ext_csd->raw_pwr_cl_52_360 :
 				ext_csd->raw_pwr_cl_ddr_52_360;
 		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
-			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
+			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
+				ext_csd->raw_pwr_cl_ddr_200_360 :
+				ext_csd->raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -845,7 +865,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
 {
 	unsigned int max_dtr = (unsigned int)-1;
 
-	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+	if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
+	     max_dtr > card->ext_csd.hs200_max_dtr)
 		max_dtr = card->ext_csd.hs200_max_dtr;
 	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
 		max_dtr = card->ext_csd.hs_max_dtr;
@@ -944,6 +965,28 @@ static int mmc_select_hs(struct mmc_card *card)
 }
 
 /*
+ * Revert to the high-speed mode from above speed
+ */
+static int mmc_revert_to_hs(struct mmc_card *card)
+{
+	/*
+	 * CMD13, which is used to confirm the completion of timing
+	 * change, will be issued at higher speed timing condtion
+	 * rather than high-speed. If device has completed the change
+	 * to high-speed mode, it may not be proper timing to issue
+	 * command. Low speed supplies better timing margin than high
+	 * speed. Accordingly clock rate & timging should be chagned
+	 * ahead before actual switch.
+	 */
+	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+	mmc_set_bus_speed(card);
+
+	return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			  card->ext_csd.generic_cmd6_time);
+}
+
+/*
  * Activate wide bus and DDR if supported.
  */
 static int mmc_select_hs_ddr(struct mmc_card *card)
@@ -999,6 +1042,56 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
 	return err;
 }
 
+static int mmc_select_hs400(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0, ddr;
+
+	ddr = mmc_snoop_ddr(card);
+
+	/*
+	 * The bus width is set to only 8 DDR in HS400 mode
+	 */
+	if (!(ddr & EXT_CSD_CARD_TYPE_HS400 &&
+	      host->ios.bus_width == MMC_BUS_WIDTH_8))
+		return 0;
+
+	/*
+	 * Before setting BUS_WIDTH for dual data rate operation,
+	 * HS_TIMING must be set to High Speed(0x1)
+	 */
+	err = mmc_revert_to_hs(card);
+	if (err) {
+		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
+			mmc_hostname(host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_DDR_BUS_WIDTH_8,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
+			mmc_hostname(host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to hs400 failed, err:%d\n",
+			 mmc_hostname(host), err);
+		return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+	mmc_set_bus_speed(card);
+
+	return 0;
+}
+
 /*
  * For device supporting HS200 mode, the following sequence
  * should be done before executing the tuning process.
@@ -1031,7 +1124,16 @@ static int mmc_select_hs200(struct mmc_card *card)
 				   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
 				   card->ext_csd.generic_cmd6_time,
 				   true, true, true);
-		if (!err)
+		if (err)
+			goto err;
+
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
+			/*
+			 * Timing should be adjusted to the HS400 target
+			 * operation frequency for tuning process
+			 */
+			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
+		else
 			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
 	}
 err:
@@ -1076,7 +1178,7 @@ bus_speed:
 
 /*
  * Execute tuning sequence to seek the proper bus operating
- * conditions for HS200, which sends CMD21 to the device.
+ * conditions for HS200 and HS400, which sends CMD21 to the device.
  */
 static int mmc_hs200_tuning(struct mmc_card *card)
 {
@@ -1310,6 +1412,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_hs200_tuning(card);
 		if (err)
 			goto err;
+
+		err = mmc_select_hs400(card);
+		if (err)
+			goto err;
 	} else if (mmc_card_hs(card)) {
 		/* Select the desired bus width optionally */
 		err = mmc_select_bus_width(card);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index def6814..2b24c36 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -110,6 +110,7 @@ struct mmc_ext_csd {
 	u8			raw_pwr_cl_200_360;	/* 237 */
 	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
 	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
+	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
 	u8			raw_bkops_status;	/* 246 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 1ee3c10..cc716e4 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -61,6 +61,8 @@ struct mmc_ios {
 #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_HS400_TUNING 11
 
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
@@ -274,6 +276,10 @@ struct mmc_host {
 #define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
 				 MMC_CAP2_PACKED_WR)
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
+#define MMC_CAP2_HS400_1_8V	(1 << 15)	/* Can support HS400 1.8V */
+#define MMC_CAP2_HS400_1_2V	(1 << 16)	/* Can support HS400 1.2V */
+#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
+				 MMC_CAP2_HS400_1_2V)
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
@@ -486,11 +492,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
 
 static inline bool mmc_card_hs200(struct mmc_card *card)
 {
-	return card->host->ios.timing == MMC_TIMING_MMC_HS200;
+	return card->host->ios.timing == MMC_TIMING_MMC_HS200 ||
+		card->host->ios.timing == MMC_TIMING_MMC_HS400_TUNING;
 }
 
 static inline bool mmc_card_ddr52(struct mmc_card *card)
 {
 	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
 }
+
+static inline bool mmc_card_hs400(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
+}
+
 #endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f429f13..64ec963 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -325,6 +325,7 @@ struct _mmc_csd {
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
 #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
 #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
 #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
@@ -354,7 +355,6 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
 #define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
@@ -370,6 +370,10 @@ struct _mmc_csd {
 						/* SDR mode @1.2V I/O */
 #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	(1<<6)	/* Card can run at 200MHz DDR, 1.8V */
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
@@ -380,6 +384,7 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
-- 
1.7.0.4



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

* Re: [PATCH v2 2/5] mmc: identify available device type to select
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
@ 2014-03-10 10:14     ` Jaehoon Chung
  2014-03-10 11:59       ` Seungwon Jeon
  2014-03-13 14:02     ` Ulf Hansson
  1 sibling, 1 reply; 182+ messages in thread
From: Jaehoon Chung @ 2014-03-10 10:14 UTC (permalink / raw)
  To: Seungwon Jeon, linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On 03/07/2014 11:36 PM, Seungwon Jeon wrote:
> Device types which are supported by both host and device
> can be identified when EXT_CSD is read. There is no need to
> check host's capability anymore.
> 
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
> Changes in v2:
> 	Just rebased with latest one.
> 
>  drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
>  include/linux/mmc/card.h |    6 ++-
>  include/linux/mmc/host.h |    6 ---
>  include/linux/mmc/mmc.h  |   12 +++++--
>  4 files changed, 56 insertions(+), 45 deletions(-)
> 
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index db9655f..0abece0 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
>  	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>  	u32 caps = host->caps, caps2 = host->caps2;
>  	unsigned int hs_max_dtr = 0;
> +	unsigned int avail_type = 0;
>  
> -	if (card_type & EXT_CSD_CARD_TYPE_26)
> +	if (caps & MMC_CAP_MMC_HIGHSPEED &&
> +	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
>  		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
> +		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
> +	}
>  
>  	if (caps & MMC_CAP_MMC_HIGHSPEED &&
> -			card_type & EXT_CSD_CARD_TYPE_52)
> +	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
>  		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
> +		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
> +	}
Can it bind with "caps & MMC_CAP_MMC_HIGHSPEED"?
if (caps & MMC_CAP_MMC_HIGH_SPEED) {
	if (card_type & EXT_CSD_CARD_TYPE_HS_26) {
		...
	}
	if (card_type & EXT_CSD_CARD_TYPE_HS_52) {
		...
	}
}
>  
> -	if ((caps & MMC_CAP_1_8V_DDR &&
> -			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
> -	    (caps & MMC_CAP_1_2V_DDR &&
> -			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
> +	if (caps & MMC_CAP_1_8V_DDR &&
> +	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
>  		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> +		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
> +	}
>  
> -	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> -			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
> -	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> -			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
> +	if (caps & MMC_CAP_1_2V_DDR &&
> +	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> +		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> +		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
> +	}
> +
> +	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> +	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
>  		hs_max_dtr = MMC_HS200_MAX_DTR;
> +		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
> +	}
> +
> +	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> +	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
> +		hs_max_dtr = MMC_HS200_MAX_DTR;
> +		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> +	}
>  
>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
> -	card->ext_csd.card_type = card_type;
> +	card->mmc_avail_type = avail_type;
>  }
>  
>  /*
> @@ -708,6 +726,11 @@ static struct device_type mmc_type = {
>  	.groups = mmc_attr_groups,
>  };
>  
> +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> +{
> +	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> +}
> +
>  /*
>   * Select the PowerClass for the current bus width
>   * If power class is defined for 4/8 bit bus in the
> @@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
>  
>  	host = card->host;
>  
> -	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
> -			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
>  		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
>  
> -	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
> -			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
> +	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
>  		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
>  
>  	/* If fails try again during next card power cycle */
> @@ -1072,10 +1093,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>  	 */
>  	if (card->ext_csd.hs_max_dtr != 0) {
>  		err = 0;
> -		if (card->ext_csd.hs_max_dtr > 52000000 &&
> -		    host->caps2 & MMC_CAP2_HS200)
MMC_CAP2_HS200 need no more, doesn't?

> +		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>  			err = mmc_select_hs200(card);
> -		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
> +		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>  			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>  					EXT_CSD_HS_TIMING, 1,
>  					card->ext_csd.generic_cmd6_time,
> @@ -1089,13 +1109,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>  			       mmc_hostname(card->host));
>  			err = 0;
>  		} else {
> -			if (card->ext_csd.hs_max_dtr > 52000000 &&
> -			    host->caps2 & MMC_CAP2_HS200) {
> +			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>  				mmc_set_timing(card->host,
>  					       MMC_TIMING_MMC_HS200);
> -			} else {
> +			else
>  				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> -			}
>  		}
>  	}
>  
> @@ -1118,14 +1136,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>  	/*
>  	 * Indicate DDR mode (if supported).
>  	 */
> -	if (mmc_card_hs(card)) {
> -		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
> -			&& (host->caps & MMC_CAP_1_8V_DDR))
> -				ddr = MMC_1_8V_DDR_MODE;
> -		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
> -			&& (host->caps & MMC_CAP_1_2V_DDR))
> -				ddr = MMC_1_2V_DDR_MODE;
> -	}
> +	if (mmc_card_hs(card))
> +		ddr = mmc_snoop_ddr(card);
>  
>  	/*
>  	 * Indicate HS200 SDR mode (if supported).
> @@ -1145,8 +1157,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>  		 * 3. set the clock to > 52Mhz <=200MHz and
>  		 * 4. execute tuning for HS200
>  		 */
> -		if ((host->caps2 & MMC_CAP2_HS200) &&
> -		    card->host->ops->execute_tuning) {
> +		if (card->host->ops->execute_tuning) {
>  			mmc_host_clk_hold(card->host);
>  			err = card->host->ops->execute_tuning(card->host,
>  				MMC_SEND_TUNING_BLOCK_HS200);
> @@ -1255,7 +1266,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>  			 *
>  			 * WARNING: eMMC rules are NOT the same as SD DDR
>  			 */
> -			if (ddr == MMC_1_2V_DDR_MODE) {
> +			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
>  				err = __mmc_set_signal_voltage(host,
>  					MMC_SIGNAL_VOLTAGE_120);
>  				if (err)
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 5473133..c232b10 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -68,7 +68,6 @@ struct mmc_ext_csd {
>  #define MMC_HIGH_DDR_MAX_DTR	52000000
>  #define MMC_HS200_MAX_DTR	200000000
>  	unsigned int		sectors;
> -	unsigned int		card_type;
>  	unsigned int		hc_erase_size;		/* In sectors */
>  	unsigned int		hc_erase_timeout;	/* In milliseconds */
>  	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
> @@ -297,7 +296,10 @@ struct mmc_card {
>  	const char		**info;		/* info strings */
>  	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
>  
> -	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
> +	union {
> +		unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
> +		unsigned int		mmc_avail_type;	/* supported device type by both host and card */
> +	};
>  
>  	struct dentry		*debugfs_root;
>  	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 2f263ae..1ee3c10 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -62,12 +62,6 @@ struct mmc_ios {
>  #define MMC_TIMING_MMC_DDR52	8
>  #define MMC_TIMING_MMC_HS200	9
>  
> -#define MMC_SDR_MODE		0
> -#define MMC_1_2V_DDR_MODE	1
> -#define MMC_1_8V_DDR_MODE	2
> -#define MMC_1_2V_SDR_MODE	3
> -#define MMC_1_8V_SDR_MODE	4
> -
>  	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
>  
>  #define MMC_SIGNAL_VOLTAGE_330	0
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 50bcde3..f734c0c 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -354,18 +354,22 @@ struct _mmc_csd {
>  #define EXT_CSD_CMD_SET_SECURE		(1<<1)
>  #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
>  
> -#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_MASK	0x3F	/* Mask out reserved bits */
> +#define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
> +#define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
> +#define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
> +				 EXT_CSD_CARD_TYPE_HS_52)
>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
>  					     /* DDR mode @1.8V or 3V I/O */
>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
>  					     /* DDR mode @1.2V I/O */
>  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
>  					| EXT_CSD_CARD_TYPE_DDR_1_2V)
> -#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
> -#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
> +#define EXT_CSD_CARD_TYPE_HS200_1_8V	(1<<4)	/* Card can run at 200MHz */
> +#define EXT_CSD_CARD_TYPE_HS200_1_2V	(1<<5)	/* Card can run at 200MHz */
>  						/* SDR mode @1.2V I/O */
> +#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
> +					 EXT_CSD_CARD_TYPE_HS200_1_2V)
>  
>  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
> 


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

* RE: [PATCH v2 2/5] mmc: identify available device type to select
  2014-03-10 10:14     ` Jaehoon Chung
@ 2014-03-10 11:59       ` Seungwon Jeon
  2014-03-13  5:37         ` Jaehoon Chung
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-10 11:59 UTC (permalink / raw)
  To: 'Jaehoon Chung', linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jackey Shen', 'Alim Akhtar'

On Mon, March 10, 2014, Jaehoon Chung wrote:
> On 03/07/2014 11:36 PM, Seungwon Jeon wrote:
> > Device types which are supported by both host and device
> > can be identified when EXT_CSD is read. There is no need to
> > check host's capability anymore.
> >
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > ---
> > Changes in v2:
> > 	Just rebased with latest one.
> >
> >  drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
> >  include/linux/mmc/card.h |    6 ++-
> >  include/linux/mmc/host.h |    6 ---
> >  include/linux/mmc/mmc.h  |   12 +++++--
> >  4 files changed, 56 insertions(+), 45 deletions(-)
> >
> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > index db9655f..0abece0 100644
> > --- a/drivers/mmc/core/mmc.c
> > +++ b/drivers/mmc/core/mmc.c
> > @@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
> >  	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> >  	u32 caps = host->caps, caps2 = host->caps2;
> >  	unsigned int hs_max_dtr = 0;
> > +	unsigned int avail_type = 0;
> >
> > -	if (card_type & EXT_CSD_CARD_TYPE_26)
> > +	if (caps & MMC_CAP_MMC_HIGHSPEED &&
> > +	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
> >  		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
> > +		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
> > +	}
> >
> >  	if (caps & MMC_CAP_MMC_HIGHSPEED &&
> > -			card_type & EXT_CSD_CARD_TYPE_52)
> > +	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
> >  		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
> > +		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
> > +	}
> Can it bind with "caps & MMC_CAP_MMC_HIGHSPEED"?
Yes, 'nested if' may be possible here.
I just think current style is more harmonious though.

> if (caps & MMC_CAP_MMC_HIGH_SPEED) {
> 	if (card_type & EXT_CSD_CARD_TYPE_HS_26) {
> 		...
> 	}
> 	if (card_type & EXT_CSD_CARD_TYPE_HS_52) {
> 		...
> 	}
> }
> >
> > -	if ((caps & MMC_CAP_1_8V_DDR &&
> > -			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
> > -	    (caps & MMC_CAP_1_2V_DDR &&
> > -			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
> > +	if (caps & MMC_CAP_1_8V_DDR &&
> > +	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
> >  		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> > +		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
> > +	}
> >
> > -	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> > -			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
> > -	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> > -			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
> > +	if (caps & MMC_CAP_1_2V_DDR &&
> > +	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> > +		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> > +		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
> > +	}
> > +
> > +	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> > +	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
> >  		hs_max_dtr = MMC_HS200_MAX_DTR;
> > +		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
> > +	}
> > +
> > +	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> > +	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
> > +		hs_max_dtr = MMC_HS200_MAX_DTR;
> > +		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> > +	}
> >
> >  	card->ext_csd.hs_max_dtr = hs_max_dtr;
> > -	card->ext_csd.card_type = card_type;
> > +	card->mmc_avail_type = avail_type;
> >  }
> >
> >  /*
> > @@ -708,6 +726,11 @@ static struct device_type mmc_type = {
> >  	.groups = mmc_attr_groups,
> >  };
> >
> > +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> > +{
> > +	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> > +}
> > +
> >  /*
> >   * Select the PowerClass for the current bus width
> >   * If power class is defined for 4/8 bit bus in the
> > @@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
> >
> >  	host = card->host;
> >
> > -	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
> > -			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
> > +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
> >  		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
> >
> > -	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
> > -			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
> > +	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
> >  		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
> >
> >  	/* If fails try again during next card power cycle */
> > @@ -1072,10 +1093,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >  	 */
> >  	if (card->ext_csd.hs_max_dtr != 0) {
> >  		err = 0;
> > -		if (card->ext_csd.hs_max_dtr > 52000000 &&
> > -		    host->caps2 & MMC_CAP2_HS200)
> MMC_CAP2_HS200 need no more, doesn't?
If you mean to remove 'MMC_CAP2_HS200' definition, it is currently used in sdhci.c

Thanks,
Seungwon Jeon

> 
> > +		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> >  			err = mmc_select_hs200(card);
> > -		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
> > +		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
> >  			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >  					EXT_CSD_HS_TIMING, 1,
> >  					card->ext_csd.generic_cmd6_time,
> > @@ -1089,13 +1109,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >  			       mmc_hostname(card->host));
> >  			err = 0;
> >  		} else {
> > -			if (card->ext_csd.hs_max_dtr > 52000000 &&
> > -			    host->caps2 & MMC_CAP2_HS200) {
> > +			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> >  				mmc_set_timing(card->host,
> >  					       MMC_TIMING_MMC_HS200);
> > -			} else {
> > +			else
> >  				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> > -			}
> >  		}
> >  	}
> >
> > @@ -1118,14 +1136,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >  	/*
> >  	 * Indicate DDR mode (if supported).
> >  	 */
> > -	if (mmc_card_hs(card)) {
> > -		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
> > -			&& (host->caps & MMC_CAP_1_8V_DDR))
> > -				ddr = MMC_1_8V_DDR_MODE;
> > -		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
> > -			&& (host->caps & MMC_CAP_1_2V_DDR))
> > -				ddr = MMC_1_2V_DDR_MODE;
> > -	}
> > +	if (mmc_card_hs(card))
> > +		ddr = mmc_snoop_ddr(card);
> >
> >  	/*
> >  	 * Indicate HS200 SDR mode (if supported).
> > @@ -1145,8 +1157,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >  		 * 3. set the clock to > 52Mhz <=200MHz and
> >  		 * 4. execute tuning for HS200
> >  		 */
> > -		if ((host->caps2 & MMC_CAP2_HS200) &&
> > -		    card->host->ops->execute_tuning) {
> > +		if (card->host->ops->execute_tuning) {
> >  			mmc_host_clk_hold(card->host);
> >  			err = card->host->ops->execute_tuning(card->host,
> >  				MMC_SEND_TUNING_BLOCK_HS200);
> > @@ -1255,7 +1266,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >  			 *
> >  			 * WARNING: eMMC rules are NOT the same as SD DDR
> >  			 */
> > -			if (ddr == MMC_1_2V_DDR_MODE) {
> > +			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> >  				err = __mmc_set_signal_voltage(host,
> >  					MMC_SIGNAL_VOLTAGE_120);
> >  				if (err)
> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > index 5473133..c232b10 100644
> > --- a/include/linux/mmc/card.h
> > +++ b/include/linux/mmc/card.h
> > @@ -68,7 +68,6 @@ struct mmc_ext_csd {
> >  #define MMC_HIGH_DDR_MAX_DTR	52000000
> >  #define MMC_HS200_MAX_DTR	200000000
> >  	unsigned int		sectors;
> > -	unsigned int		card_type;
> >  	unsigned int		hc_erase_size;		/* In sectors */
> >  	unsigned int		hc_erase_timeout;	/* In milliseconds */
> >  	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
> > @@ -297,7 +296,10 @@ struct mmc_card {
> >  	const char		**info;		/* info strings */
> >  	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
> >
> > -	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
> > +	union {
> > +		unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
> > +		unsigned int		mmc_avail_type;	/* supported device type by both host and card */
> > +	};
> >
> >  	struct dentry		*debugfs_root;
> >  	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > index 2f263ae..1ee3c10 100644
> > --- a/include/linux/mmc/host.h
> > +++ b/include/linux/mmc/host.h
> > @@ -62,12 +62,6 @@ struct mmc_ios {
> >  #define MMC_TIMING_MMC_DDR52	8
> >  #define MMC_TIMING_MMC_HS200	9
> >
> > -#define MMC_SDR_MODE		0
> > -#define MMC_1_2V_DDR_MODE	1
> > -#define MMC_1_8V_DDR_MODE	2
> > -#define MMC_1_2V_SDR_MODE	3
> > -#define MMC_1_8V_SDR_MODE	4
> > -
> >  	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
> >
> >  #define MMC_SIGNAL_VOLTAGE_330	0
> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> > index 50bcde3..f734c0c 100644
> > --- a/include/linux/mmc/mmc.h
> > +++ b/include/linux/mmc/mmc.h
> > @@ -354,18 +354,22 @@ struct _mmc_csd {
> >  #define EXT_CSD_CMD_SET_SECURE		(1<<1)
> >  #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
> >
> > -#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_MASK	0x3F	/* Mask out reserved bits */
> > +#define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
> > +#define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
> > +#define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
> > +				 EXT_CSD_CARD_TYPE_HS_52)
> >  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
> >  					     /* DDR mode @1.8V or 3V I/O */
> >  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
> >  					     /* DDR mode @1.2V I/O */
> >  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
> >  					| EXT_CSD_CARD_TYPE_DDR_1_2V)
> > -#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
> > -#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
> > +#define EXT_CSD_CARD_TYPE_HS200_1_8V	(1<<4)	/* Card can run at 200MHz */
> > +#define EXT_CSD_CARD_TYPE_HS200_1_2V	(1<<5)	/* Card can run at 200MHz */
> >  						/* SDR mode @1.2V I/O */
> > +#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
> > +					 EXT_CSD_CARD_TYPE_HS200_1_2V)
> >
> >  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
> >  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
> >
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v2 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
@ 2014-03-11  0:45     ` Jackey Shen
  2014-03-14 11:34       ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Jackey Shen @ 2014-03-11  0:45 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Alim Akhtar'

Signed-off-by: Jackey Shen <jackey.shen@amd.com>

Thanks,
Jackey

On Fri, Mar 07, 2014 at 11:36:43PM +0900, Seungwon Jeon wrote:
> 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: Seungwon Jeon <tgih.jun@samsung.com>
> ---
> Changes in v2:
> 	Cleaned up some unnecessary codes.
> 
>  drivers/mmc/core/bus.c     |    1 +
>  drivers/mmc/core/debugfs.c |    3 +
>  drivers/mmc/core/mmc.c     |  120 +++++++++++++++++++++++++++++++++++++++++---
>  include/linux/mmc/card.h   |    1 +
>  include/linux/mmc/host.h   |   15 +++++-
>  include/linux/mmc/mmc.h    |    7 ++-
>  6 files changed, 138 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index f37e9d6..d2dbf02 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
>  			mmc_hostname(card->host),
>  			mmc_card_uhs(card) ? "ultra high speed " :
>  			(mmc_card_hs(card) ? "high speed " : ""),
> +			mmc_card_hs400(card) ? "HS400 " :
>  			(mmc_card_hs200(card) ? "HS200 " : ""),
>  			mmc_card_ddr52(card) ? "DDR " : "",
>  			uhs_bus_speed_mode, type, card->rca);
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index 1f730db..91eb162 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>  	case MMC_TIMING_MMC_HS200:
>  		str = "mmc HS200";
>  		break;
> +	case MMC_TIMING_MMC_HS400:
> +		str = "mmc HS400";
> +		break;
>  	default:
>  		str = "invalid";
>  		break;
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index e356a54..998b0af 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
>  static void mmc_select_card_type(struct mmc_card *card)
>  {
>  	struct mmc_host *host = card->host;
> -	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> +	u8 card_type = card->ext_csd.raw_card_type;
>  	u32 caps = host->caps, caps2 = host->caps2;
>  	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>  	unsigned int avail_type = 0;
> @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
>  		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>  	}
>  
> +	if (caps2 & MMC_CAP2_HS400_1_8V &&
> +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> +	}
> +
> +	if (caps2 & MMC_CAP2_HS400_1_2V &&
> +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> +	}
> +
>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>  	card->mmc_avail_type = avail_type;
> @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>  			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
>  		card->ext_csd.raw_pwr_cl_ddr_52_360 =
>  			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> +		card->ext_csd.raw_pwr_cl_ddr_200_360 =
> +			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
>  	}
>  
>  	if (card->ext_csd.rev >= 5) {
> @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
>  		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
>  			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
>  		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> -			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> +		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> +
>  	if (err)
>  		err = -EINVAL;
>  
> @@ -729,7 +746,8 @@ static struct device_type mmc_type = {
>  
>  static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
>  {
> -	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> +	return card->mmc_avail_type &
> +		(EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_HS400);
>  }
>  
>  /*
> @@ -781,7 +799,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
>  				ext_csd->raw_pwr_cl_52_360 :
>  				ext_csd->raw_pwr_cl_ddr_52_360;
>  		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> -			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
> +			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> +				ext_csd->raw_pwr_cl_ddr_200_360 :
> +				ext_csd->raw_pwr_cl_200_360;
>  		break;
>  	default:
>  		pr_warning("%s: Voltage range not supported "
> @@ -845,7 +865,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
>  {
>  	unsigned int max_dtr = (unsigned int)-1;
>  
> -	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> +	if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
> +	     max_dtr > card->ext_csd.hs200_max_dtr)
>  		max_dtr = card->ext_csd.hs200_max_dtr;
>  	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
>  		max_dtr = card->ext_csd.hs_max_dtr;
> @@ -944,6 +965,28 @@ static int mmc_select_hs(struct mmc_card *card)
>  }
>  
>  /*
> + * Revert to the high-speed mode from above speed
> + */
> +static int mmc_revert_to_hs(struct mmc_card *card)
> +{
> +	/*
> +	 * CMD13, which is used to confirm the completion of timing
> +	 * change, will be issued at higher speed timing condtion
> +	 * rather than high-speed. If device has completed the change
> +	 * to high-speed mode, it may not be proper timing to issue
> +	 * command. Low speed supplies better timing margin than high
> +	 * speed. Accordingly clock rate & timging should be chagned
> +	 * ahead before actual switch.
> +	 */
> +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> +	mmc_set_bus_speed(card);
> +
> +	return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> +			  card->ext_csd.generic_cmd6_time);
> +}
> +
> +/*
>   * Activate wide bus and DDR if supported.
>   */
>  static int mmc_select_hs_ddr(struct mmc_card *card)
> @@ -999,6 +1042,56 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
>  	return err;
>  }
>  
> +static int mmc_select_hs400(struct mmc_card *card)
> +{
> +	struct mmc_host *host = card->host;
> +	int err = 0, ddr;
> +
> +	ddr = mmc_snoop_ddr(card);
> +
> +	/*
> +	 * The bus width is set to only 8 DDR in HS400 mode
> +	 */
> +	if (!(ddr & EXT_CSD_CARD_TYPE_HS400 &&
> +	      host->ios.bus_width == MMC_BUS_WIDTH_8))
> +		return 0;
> +
> +	/*
> +	 * Before setting BUS_WIDTH for dual data rate operation,
> +	 * HS_TIMING must be set to High Speed(0x1)
> +	 */
> +	err = mmc_revert_to_hs(card);
> +	if (err) {
> +		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		return err;
> +	}
> +
> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			 EXT_CSD_BUS_WIDTH,
> +			 EXT_CSD_DDR_BUS_WIDTH_8,
> +			 card->ext_csd.generic_cmd6_time);
> +	if (err) {
> +		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		return err;
> +	}
> +
> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> +			 card->ext_csd.generic_cmd6_time);
> +	if (err) {
> +		pr_warn("%s: switch to hs400 failed, err:%d\n",
> +			 mmc_hostname(host), err);
> +		return err;
> +	}
> +
> +	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> +	mmc_set_bus_speed(card);
> +
> +	return 0;
> +}
> +
>  /*
>   * For device supporting HS200 mode, the following sequence
>   * should be done before executing the tuning process.
> @@ -1031,7 +1124,16 @@ static int mmc_select_hs200(struct mmc_card *card)
>  				   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
>  				   card->ext_csd.generic_cmd6_time,
>  				   true, true, true);
> -		if (!err)
> +		if (err)
> +			goto err;
> +
> +		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> +			/*
> +			 * Timing should be adjusted to the HS400 target
> +			 * operation frequency for tuning process
> +			 */
> +			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> +		else
>  			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
>  	}
>  err:
> @@ -1076,7 +1178,7 @@ bus_speed:
>  
>  /*
>   * Execute tuning sequence to seek the proper bus operating
> - * conditions for HS200, which sends CMD21 to the device.
> + * conditions for HS200 and HS400, which sends CMD21 to the device.
>   */
>  static int mmc_hs200_tuning(struct mmc_card *card)
>  {
> @@ -1310,6 +1412,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>  		err = mmc_hs200_tuning(card);
>  		if (err)
>  			goto err;
> +
> +		err = mmc_select_hs400(card);
> +		if (err)
> +			goto err;
>  	} else if (mmc_card_hs(card)) {
>  		/* Select the desired bus width optionally */
>  		err = mmc_select_bus_width(card);
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index def6814..2b24c36 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -110,6 +110,7 @@ struct mmc_ext_csd {
>  	u8			raw_pwr_cl_200_360;	/* 237 */
>  	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
>  	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
> +	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
>  	u8			raw_bkops_status;	/* 246 */
>  	u8			raw_sectors[4];		/* 212 - 4 bytes */
>  
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 1ee3c10..cc716e4 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -61,6 +61,8 @@ struct mmc_ios {
>  #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_HS400_TUNING 11
>  
>  	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
>  
> @@ -274,6 +276,10 @@ struct mmc_host {
>  #define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
>  				 MMC_CAP2_PACKED_WR)
>  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
> +#define MMC_CAP2_HS400_1_8V	(1 << 15)	/* Can support HS400 1.8V */
> +#define MMC_CAP2_HS400_1_2V	(1 << 16)	/* Can support HS400 1.2V */
> +#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
> +				 MMC_CAP2_HS400_1_2V)
>  
>  	mmc_pm_flag_t		pm_caps;	/* supported pm features */
>  
> @@ -486,11 +492,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
>  
>  static inline bool mmc_card_hs200(struct mmc_card *card)
>  {
> -	return card->host->ios.timing == MMC_TIMING_MMC_HS200;
> +	return card->host->ios.timing == MMC_TIMING_MMC_HS200 ||
> +		card->host->ios.timing == MMC_TIMING_MMC_HS400_TUNING;
>  }
>  
>  static inline bool mmc_card_ddr52(struct mmc_card *card)
>  {
>  	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
>  }
> +
> +static inline bool mmc_card_hs400(struct mmc_card *card)
> +{
> +	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
> +}
> +
>  #endif /* LINUX_MMC_HOST_H */
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index f429f13..64ec963 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -325,6 +325,7 @@ struct _mmc_csd {
>  #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
>  #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
>  #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
> +#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
>  #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
>  #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
>  #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
> @@ -354,7 +355,6 @@ struct _mmc_csd {
>  #define EXT_CSD_CMD_SET_SECURE		(1<<1)
>  #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
>  
> -#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
>  #define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
>  #define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
>  #define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
> @@ -370,6 +370,10 @@ struct _mmc_csd {
>  						/* SDR mode @1.2V I/O */
>  #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	(1<<6)	/* Card can run at 200MHz DDR, 1.8V */
> +#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
> @@ -380,6 +384,7 @@ struct _mmc_csd {
>  #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_SEC_ER_EN	BIT(0)
>  #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
> -- 
> 1.7.0.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


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

* Re: [PATCH v2 2/5] mmc: identify available device type to select
  2014-03-10 11:59       ` Seungwon Jeon
@ 2014-03-13  5:37         ` Jaehoon Chung
  2014-03-13  8:37           ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Jaehoon Chung @ 2014-03-13  5:37 UTC (permalink / raw)
  To: Seungwon Jeon, 'Jaehoon Chung', linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jackey Shen', 'Alim Akhtar'

Dear, Seungwon.

On 03/10/2014 08:59 PM, Seungwon Jeon wrote:
> On Mon, March 10, 2014, Jaehoon Chung wrote:
>> On 03/07/2014 11:36 PM, Seungwon Jeon wrote:
>>> Device types which are supported by both host and device
>>> can be identified when EXT_CSD is read. There is no need to
>>> check host's capability anymore.
>>>
>>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>>> ---
>>> Changes in v2:
>>> 	Just rebased with latest one.
>>>
>>>  drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
>>>  include/linux/mmc/card.h |    6 ++-
>>>  include/linux/mmc/host.h |    6 ---
>>>  include/linux/mmc/mmc.h  |   12 +++++--
>>>  4 files changed, 56 insertions(+), 45 deletions(-)
>>>
>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>>> index db9655f..0abece0 100644
>>> --- a/drivers/mmc/core/mmc.c
>>> +++ b/drivers/mmc/core/mmc.c
>>> @@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
>>>  	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>>>  	u32 caps = host->caps, caps2 = host->caps2;
>>>  	unsigned int hs_max_dtr = 0;
>>> +	unsigned int avail_type = 0;
>>>
>>> -	if (card_type & EXT_CSD_CARD_TYPE_26)
>>> +	if (caps & MMC_CAP_MMC_HIGHSPEED &&
>>> +	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
>>>  		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
>>> +		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
>>> +	}
>>>
>>>  	if (caps & MMC_CAP_MMC_HIGHSPEED &&
>>> -			card_type & EXT_CSD_CARD_TYPE_52)
>>> +	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
>>>  		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
>>> +		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
>>> +	}
>> Can it bind with "caps & MMC_CAP_MMC_HIGHSPEED"?
> Yes, 'nested if' may be possible here.
> I just think current style is more harmonious though.
Don't mind. it's ok. :)

> 
>> if (caps & MMC_CAP_MMC_HIGH_SPEED) {
>> 	if (card_type & EXT_CSD_CARD_TYPE_HS_26) {
>> 		...
>> 	}
>> 	if (card_type & EXT_CSD_CARD_TYPE_HS_52) {
>> 		...
>> 	}
>> }
>>>
>>> -	if ((caps & MMC_CAP_1_8V_DDR &&
>>> -			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
>>> -	    (caps & MMC_CAP_1_2V_DDR &&
>>> -			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
>>> +	if (caps & MMC_CAP_1_8V_DDR &&
>>> +	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
>>>  		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
>>> +		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
>>> +	}
>>>
>>> -	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
>>> -			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
>>> -	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
>>> -			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
>>> +	if (caps & MMC_CAP_1_2V_DDR &&
>>> +	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
>>> +		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
>>> +		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
>>> +	}
>>> +
>>> +	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
>>> +	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
>>>  		hs_max_dtr = MMC_HS200_MAX_DTR;
>>> +		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
>>> +	}
>>> +
>>> +	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
>>> +	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
>>> +		hs_max_dtr = MMC_HS200_MAX_DTR;
>>> +		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>>> +	}
>>>
>>>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>>> -	card->ext_csd.card_type = card_type;
>>> +	card->mmc_avail_type = avail_type;
>>>  }
>>>
>>>  /*
>>> @@ -708,6 +726,11 @@ static struct device_type mmc_type = {
>>>  	.groups = mmc_attr_groups,
>>>  };
>>>
>>> +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
>>> +{
>>> +	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
>>> +}
>>> +
>>>  /*
>>>   * Select the PowerClass for the current bus width
>>>   * If power class is defined for 4/8 bit bus in the
>>> @@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
>>>
>>>  	host = card->host;
>>>
>>> -	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
>>> -			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
>>> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
>>>  		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
>>>
>>> -	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
>>> -			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
>>> +	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
>>>  		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
>>>
>>>  	/* If fails try again during next card power cycle */
>>> @@ -1072,10 +1093,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>>>  	 */
>>>  	if (card->ext_csd.hs_max_dtr != 0) {
>>>  		err = 0;
>>> -		if (card->ext_csd.hs_max_dtr > 52000000 &&
>>> -		    host->caps2 & MMC_CAP2_HS200)
>> MMC_CAP2_HS200 need no more, doesn't?
> If you mean to remove 'MMC_CAP2_HS200' definition, it is currently used in sdhci.c
I have also checked that it is used in sdhci.c.
but I think that capability like MMC_CAP2_HS200 was defined to use for core, not controller.
It can be changed other quirks instead of MMC_CAP2_HS200 into sdhci.c
how about?

Best Regards,
Jaehoon Chung

> 
> Thanks,
> Seungwon Jeon
> 
>>
>>> +		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>>  			err = mmc_select_hs200(card);
>>> -		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
>>> +		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>>>  			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>>  					EXT_CSD_HS_TIMING, 1,
>>>  					card->ext_csd.generic_cmd6_time,
>>> @@ -1089,13 +1109,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>>>  			       mmc_hostname(card->host));
>>>  			err = 0;
>>>  		} else {
>>> -			if (card->ext_csd.hs_max_dtr > 52000000 &&
>>> -			    host->caps2 & MMC_CAP2_HS200) {
>>> +			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>>  				mmc_set_timing(card->host,
>>>  					       MMC_TIMING_MMC_HS200);
>>> -			} else {
>>> +			else
>>>  				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>>> -			}
>>>  		}
>>>  	}
>>>
>>> @@ -1118,14 +1136,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>>>  	/*
>>>  	 * Indicate DDR mode (if supported).
>>>  	 */
>>> -	if (mmc_card_hs(card)) {
>>> -		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
>>> -			&& (host->caps & MMC_CAP_1_8V_DDR))
>>> -				ddr = MMC_1_8V_DDR_MODE;
>>> -		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
>>> -			&& (host->caps & MMC_CAP_1_2V_DDR))
>>> -				ddr = MMC_1_2V_DDR_MODE;
>>> -	}
>>> +	if (mmc_card_hs(card))
>>> +		ddr = mmc_snoop_ddr(card);
>>>
>>>  	/*
>>>  	 * Indicate HS200 SDR mode (if supported).
>>> @@ -1145,8 +1157,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>>>  		 * 3. set the clock to > 52Mhz <=200MHz and
>>>  		 * 4. execute tuning for HS200
>>>  		 */
>>> -		if ((host->caps2 & MMC_CAP2_HS200) &&
>>> -		    card->host->ops->execute_tuning) {
>>> +		if (card->host->ops->execute_tuning) {
>>>  			mmc_host_clk_hold(card->host);
>>>  			err = card->host->ops->execute_tuning(card->host,
>>>  				MMC_SEND_TUNING_BLOCK_HS200);
>>> @@ -1255,7 +1266,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>>>  			 *
>>>  			 * WARNING: eMMC rules are NOT the same as SD DDR
>>>  			 */
>>> -			if (ddr == MMC_1_2V_DDR_MODE) {
>>> +			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
>>>  				err = __mmc_set_signal_voltage(host,
>>>  					MMC_SIGNAL_VOLTAGE_120);
>>>  				if (err)
>>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>>> index 5473133..c232b10 100644
>>> --- a/include/linux/mmc/card.h
>>> +++ b/include/linux/mmc/card.h
>>> @@ -68,7 +68,6 @@ struct mmc_ext_csd {
>>>  #define MMC_HIGH_DDR_MAX_DTR	52000000
>>>  #define MMC_HS200_MAX_DTR	200000000
>>>  	unsigned int		sectors;
>>> -	unsigned int		card_type;
>>>  	unsigned int		hc_erase_size;		/* In sectors */
>>>  	unsigned int		hc_erase_timeout;	/* In milliseconds */
>>>  	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
>>> @@ -297,7 +296,10 @@ struct mmc_card {
>>>  	const char		**info;		/* info strings */
>>>  	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
>>>
>>> -	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
>>> +	union {
>>> +		unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
>>> +		unsigned int		mmc_avail_type;	/* supported device type by both host and card */
>>> +	};
>>>
>>>  	struct dentry		*debugfs_root;
>>>  	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
>>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>>> index 2f263ae..1ee3c10 100644
>>> --- a/include/linux/mmc/host.h
>>> +++ b/include/linux/mmc/host.h
>>> @@ -62,12 +62,6 @@ struct mmc_ios {
>>>  #define MMC_TIMING_MMC_DDR52	8
>>>  #define MMC_TIMING_MMC_HS200	9
>>>
>>> -#define MMC_SDR_MODE		0
>>> -#define MMC_1_2V_DDR_MODE	1
>>> -#define MMC_1_8V_DDR_MODE	2
>>> -#define MMC_1_2V_SDR_MODE	3
>>> -#define MMC_1_8V_SDR_MODE	4
>>> -
>>>  	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
>>>
>>>  #define MMC_SIGNAL_VOLTAGE_330	0
>>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>>> index 50bcde3..f734c0c 100644
>>> --- a/include/linux/mmc/mmc.h
>>> +++ b/include/linux/mmc/mmc.h
>>> @@ -354,18 +354,22 @@ struct _mmc_csd {
>>>  #define EXT_CSD_CMD_SET_SECURE		(1<<1)
>>>  #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
>>>
>>> -#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_MASK	0x3F	/* Mask out reserved bits */
>>> +#define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
>>> +#define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
>>> +#define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
>>> +				 EXT_CSD_CARD_TYPE_HS_52)
>>>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
>>>  					     /* DDR mode @1.8V or 3V I/O */
>>>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
>>>  					     /* DDR mode @1.2V I/O */
>>>  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
>>>  					| EXT_CSD_CARD_TYPE_DDR_1_2V)
>>> -#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
>>> -#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
>>> +#define EXT_CSD_CARD_TYPE_HS200_1_8V	(1<<4)	/* Card can run at 200MHz */
>>> +#define EXT_CSD_CARD_TYPE_HS200_1_2V	(1<<5)	/* Card can run at 200MHz */
>>>  						/* SDR mode @1.2V I/O */
>>> +#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
>>> +					 EXT_CSD_CARD_TYPE_HS200_1_2V)
>>>
>>>  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>>>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
>>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


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

* RE: [PATCH v2 2/5] mmc: identify available device type to select
  2014-03-13  5:37         ` Jaehoon Chung
@ 2014-03-13  8:37           ` Seungwon Jeon
  2014-03-13  9:51             ` Jaehoon Chung
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-13  8:37 UTC (permalink / raw)
  To: 'Jaehoon Chung', linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jackey Shen', 'Alim Akhtar'

On Thu, March 13, 2014, Jaehoon Chung wrote:
> Dear, Seungwon.
> 
> On 03/10/2014 08:59 PM, Seungwon Jeon wrote:
> > On Mon, March 10, 2014, Jaehoon Chung wrote:
> >> On 03/07/2014 11:36 PM, Seungwon Jeon wrote:
> >>> Device types which are supported by both host and device
> >>> can be identified when EXT_CSD is read. There is no need to
> >>> check host's capability anymore.
> >>>
> >>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> >>> ---
> >>> Changes in v2:
> >>> 	Just rebased with latest one.
> >>>
> >>>  drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
> >>>  include/linux/mmc/card.h |    6 ++-
> >>>  include/linux/mmc/host.h |    6 ---
> >>>  include/linux/mmc/mmc.h  |   12 +++++--
> >>>  4 files changed, 56 insertions(+), 45 deletions(-)
> >>>
> >>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >>> index db9655f..0abece0 100644
> >>> --- a/drivers/mmc/core/mmc.c
> >>> +++ b/drivers/mmc/core/mmc.c
> >>> @@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
> >>>  	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> >>>  	u32 caps = host->caps, caps2 = host->caps2;
> >>>  	unsigned int hs_max_dtr = 0;
> >>> +	unsigned int avail_type = 0;
> >>>
> >>> -	if (card_type & EXT_CSD_CARD_TYPE_26)
> >>> +	if (caps & MMC_CAP_MMC_HIGHSPEED &&
> >>> +	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
> >>>  		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
> >>> +		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
> >>> +	}
> >>>
> >>>  	if (caps & MMC_CAP_MMC_HIGHSPEED &&
> >>> -			card_type & EXT_CSD_CARD_TYPE_52)
> >>> +	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
> >>>  		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
> >>> +		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
> >>> +	}
> >> Can it bind with "caps & MMC_CAP_MMC_HIGHSPEED"?
> > Yes, 'nested if' may be possible here.
> > I just think current style is more harmonious though.
> Don't mind. it's ok. :)
> 
> >
> >> if (caps & MMC_CAP_MMC_HIGH_SPEED) {
> >> 	if (card_type & EXT_CSD_CARD_TYPE_HS_26) {
> >> 		...
> >> 	}
> >> 	if (card_type & EXT_CSD_CARD_TYPE_HS_52) {
> >> 		...
> >> 	}
> >> }
> >>>
> >>> -	if ((caps & MMC_CAP_1_8V_DDR &&
> >>> -			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
> >>> -	    (caps & MMC_CAP_1_2V_DDR &&
> >>> -			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
> >>> +	if (caps & MMC_CAP_1_8V_DDR &&
> >>> +	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
> >>>  		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> >>> +		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
> >>> +	}
> >>>
> >>> -	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> >>> -			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
> >>> -	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> >>> -			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
> >>> +	if (caps & MMC_CAP_1_2V_DDR &&
> >>> +	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> >>> +		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> >>> +		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
> >>> +	}
> >>> +
> >>> +	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> >>> +	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
> >>>  		hs_max_dtr = MMC_HS200_MAX_DTR;
> >>> +		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
> >>> +	}
> >>> +
> >>> +	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> >>> +	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
> >>> +		hs_max_dtr = MMC_HS200_MAX_DTR;
> >>> +		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> >>> +	}
> >>>
> >>>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
> >>> -	card->ext_csd.card_type = card_type;
> >>> +	card->mmc_avail_type = avail_type;
> >>>  }
> >>>
> >>>  /*
> >>> @@ -708,6 +726,11 @@ static struct device_type mmc_type = {
> >>>  	.groups = mmc_attr_groups,
> >>>  };
> >>>
> >>> +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> >>> +{
> >>> +	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> >>> +}
> >>> +
> >>>  /*
> >>>   * Select the PowerClass for the current bus width
> >>>   * If power class is defined for 4/8 bit bus in the
> >>> @@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
> >>>
> >>>  	host = card->host;
> >>>
> >>> -	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
> >>> -			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
> >>> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
> >>>  		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
> >>>
> >>> -	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
> >>> -			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
> >>> +	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
> >>>  		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
> >>>
> >>>  	/* If fails try again during next card power cycle */
> >>> @@ -1072,10 +1093,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >>>  	 */
> >>>  	if (card->ext_csd.hs_max_dtr != 0) {
> >>>  		err = 0;
> >>> -		if (card->ext_csd.hs_max_dtr > 52000000 &&
> >>> -		    host->caps2 & MMC_CAP2_HS200)
> >> MMC_CAP2_HS200 need no more, doesn't?
> > If you mean to remove 'MMC_CAP2_HS200' definition, it is currently used in sdhci.c
> I have also checked that it is used in sdhci.c.
> but I think that capability like MMC_CAP2_HS200 was defined to use for core, not controller.
> It can be changed other quirks instead of MMC_CAP2_HS200 into sdhci.c
> how about?
Hmm.
I feel like current way is not bad in sdhci.c, but if you have an idea, it would be different patch.

Thanks,
Seungwon Jeon 


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

* Re: [PATCH v2 2/5] mmc: identify available device type to select
  2014-03-13  8:37           ` Seungwon Jeon
@ 2014-03-13  9:51             ` Jaehoon Chung
  0 siblings, 0 replies; 182+ messages in thread
From: Jaehoon Chung @ 2014-03-13  9:51 UTC (permalink / raw)
  To: Seungwon Jeon, 'Jaehoon Chung', linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jackey Shen', 'Alim Akhtar'

On 03/13/2014 05:37 PM, Seungwon Jeon wrote:
> On Thu, March 13, 2014, Jaehoon Chung wrote:
>> Dear, Seungwon.
>>
>> On 03/10/2014 08:59 PM, Seungwon Jeon wrote:
>>> On Mon, March 10, 2014, Jaehoon Chung wrote:
>>>> On 03/07/2014 11:36 PM, Seungwon Jeon wrote:
>>>>> Device types which are supported by both host and device
>>>>> can be identified when EXT_CSD is read. There is no need to
>>>>> check host's capability anymore.
>>>>>
>>>>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>>>>> ---
>>>>> Changes in v2:
>>>>> 	Just rebased with latest one.
>>>>>
>>>>>  drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
>>>>>  include/linux/mmc/card.h |    6 ++-
>>>>>  include/linux/mmc/host.h |    6 ---
>>>>>  include/linux/mmc/mmc.h  |   12 +++++--
>>>>>  4 files changed, 56 insertions(+), 45 deletions(-)
>>>>>
>>>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>>>>> index db9655f..0abece0 100644
>>>>> --- a/drivers/mmc/core/mmc.c
>>>>> +++ b/drivers/mmc/core/mmc.c
>>>>> @@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
>>>>>  	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>>>>>  	u32 caps = host->caps, caps2 = host->caps2;
>>>>>  	unsigned int hs_max_dtr = 0;
>>>>> +	unsigned int avail_type = 0;
>>>>>
>>>>> -	if (card_type & EXT_CSD_CARD_TYPE_26)
>>>>> +	if (caps & MMC_CAP_MMC_HIGHSPEED &&
>>>>> +	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
>>>>>  		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
>>>>> +		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
>>>>> +	}
>>>>>
>>>>>  	if (caps & MMC_CAP_MMC_HIGHSPEED &&
>>>>> -			card_type & EXT_CSD_CARD_TYPE_52)
>>>>> +	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
>>>>>  		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
>>>>> +		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
>>>>> +	}
>>>> Can it bind with "caps & MMC_CAP_MMC_HIGHSPEED"?
>>> Yes, 'nested if' may be possible here.
>>> I just think current style is more harmonious though.
>> Don't mind. it's ok. :)
>>
>>>
>>>> if (caps & MMC_CAP_MMC_HIGH_SPEED) {
>>>> 	if (card_type & EXT_CSD_CARD_TYPE_HS_26) {
>>>> 		...
>>>> 	}
>>>> 	if (card_type & EXT_CSD_CARD_TYPE_HS_52) {
>>>> 		...
>>>> 	}
>>>> }
>>>>>
>>>>> -	if ((caps & MMC_CAP_1_8V_DDR &&
>>>>> -			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
>>>>> -	    (caps & MMC_CAP_1_2V_DDR &&
>>>>> -			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
>>>>> +	if (caps & MMC_CAP_1_8V_DDR &&
>>>>> +	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
>>>>>  		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
>>>>> +		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
>>>>> +	}
>>>>>
>>>>> -	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
>>>>> -			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
>>>>> -	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
>>>>> -			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
>>>>> +	if (caps & MMC_CAP_1_2V_DDR &&
>>>>> +	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
>>>>> +		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
>>>>> +		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
>>>>> +	}
>>>>> +
>>>>> +	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
>>>>> +	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
>>>>>  		hs_max_dtr = MMC_HS200_MAX_DTR;
>>>>> +		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
>>>>> +	}
>>>>> +
>>>>> +	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
>>>>> +	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
>>>>> +		hs_max_dtr = MMC_HS200_MAX_DTR;
>>>>> +		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>>>>> +	}
>>>>>
>>>>>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>>>>> -	card->ext_csd.card_type = card_type;
>>>>> +	card->mmc_avail_type = avail_type;
>>>>>  }
>>>>>
>>>>>  /*
>>>>> @@ -708,6 +726,11 @@ static struct device_type mmc_type = {
>>>>>  	.groups = mmc_attr_groups,
>>>>>  };
>>>>>
>>>>> +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
>>>>> +{
>>>>> +	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
>>>>> +}
>>>>> +
>>>>>  /*
>>>>>   * Select the PowerClass for the current bus width
>>>>>   * If power class is defined for 4/8 bit bus in the
>>>>> @@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
>>>>>
>>>>>  	host = card->host;
>>>>>
>>>>> -	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
>>>>> -			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
>>>>> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
>>>>>  		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
>>>>>
>>>>> -	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
>>>>> -			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
>>>>> +	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
>>>>>  		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
>>>>>
>>>>>  	/* If fails try again during next card power cycle */
>>>>> @@ -1072,10 +1093,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>>>>>  	 */
>>>>>  	if (card->ext_csd.hs_max_dtr != 0) {
>>>>>  		err = 0;
>>>>> -		if (card->ext_csd.hs_max_dtr > 52000000 &&
>>>>> -		    host->caps2 & MMC_CAP2_HS200)
>>>> MMC_CAP2_HS200 need no more, doesn't?
>>> If you mean to remove 'MMC_CAP2_HS200' definition, it is currently used in sdhci.c
>> I have also checked that it is used in sdhci.c.
>> but I think that capability like MMC_CAP2_HS200 was defined to use for core, not controller.
>> It can be changed other quirks instead of MMC_CAP2_HS200 into sdhci.c
>> how about?
> Hmm.
> I feel like current way is not bad in sdhci.c, but if you have an idea, it would be different patch.
Sure..Then when your patch-set is merged, i will send the other patch.

Best Regards,
Jaehoon Chung
> 
> Thanks,
> Seungwon Jeon 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


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

* Re: [PATCH RESEND 0/5]  update selection of bus speed mode for eMMC
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
  2014-03-07 14:35   ` [PATCH v2 " Seungwon Jeon
@ 2014-03-13  9:52   ` Jaehoon Chung
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
                     ` (26 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Jaehoon Chung @ 2014-03-13  9:52 UTC (permalink / raw)
  To: Seungwon Jeon, linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

I have tested with Exynos5. It's working fine.

Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>

On 02/15/2014 11:18 PM, Seungwon Jeon wrote:
> This series contains the change for selection of bus speed mode.
> Previous implementation is complicated and some sequence is duplicated.
> And specially, HS400 mode eMMC5.0 is introduced this time.
> 
> - Continued/Updated since "[PATCH 0/3] mmc: update bus speed mode" series.
>   (Applied some comments from Ulf Hansson, Jackey Shen.)
> - Tested at EXYNOS SOC.
> 
> Seungwon Jeon (5):
>   mmc: drop the speed mode of card's state
>   mmc: identify available device type to select
>   mmc: step power class after final selection of bus mode
>   mmc: rework selection of bus speed mode
>   mmc: add support for HS400 mode of eMMC5.0
> 
>  drivers/mmc/core/bus.c     |   10 +-
>  drivers/mmc/core/core.c    |    3 +-
>  drivers/mmc/core/debugfs.c |    5 +-
>  drivers/mmc/core/mmc.c     |  690 ++++++++++++++++++++++++++++----------------
>  drivers/mmc/core/sd.c      |   16 +-
>  drivers/mmc/core/sd.h      |    1 -
>  drivers/mmc/core/sdio.c    |    8 +-
>  include/linux/mmc/card.h   |   32 +--
>  include/linux/mmc/host.h   |   42 +++-
>  include/linux/mmc/mmc.h    |   23 ++-
>  10 files changed, 529 insertions(+), 301 deletions(-)
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


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

* Re: [PATCH v2 2/5] mmc: identify available device type to select
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
  2014-03-10 10:14     ` Jaehoon Chung
@ 2014-03-13 14:02     ` Ulf Hansson
  2014-03-14  2:49       ` Seungwon Jeon
  1 sibling, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-03-13 14:02 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 7 March 2014 15:36, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Device types which are supported by both host and device
> can be identified when EXT_CSD is read. There is no need to
> check host's capability anymore.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
> Changes in v2:
>         Just rebased with latest one.
>
>  drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
>  include/linux/mmc/card.h |    6 ++-
>  include/linux/mmc/host.h |    6 ---
>  include/linux/mmc/mmc.h  |   12 +++++--
>  4 files changed, 56 insertions(+), 45 deletions(-)
>
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index db9655f..0abece0 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
>         u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>         u32 caps = host->caps, caps2 = host->caps2;
>         unsigned int hs_max_dtr = 0;
> +       unsigned int avail_type = 0;
>
> -       if (card_type & EXT_CSD_CARD_TYPE_26)
> +       if (caps & MMC_CAP_MMC_HIGHSPEED &&
> +           card_type & EXT_CSD_CARD_TYPE_HS_26) {
>                 hs_max_dtr = MMC_HIGH_26_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_HS_26;
> +       }
>
>         if (caps & MMC_CAP_MMC_HIGHSPEED &&
> -                       card_type & EXT_CSD_CARD_TYPE_52)
> +           card_type & EXT_CSD_CARD_TYPE_HS_52) {
>                 hs_max_dtr = MMC_HIGH_52_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_HS_52;
> +       }
>
> -       if ((caps & MMC_CAP_1_8V_DDR &&
> -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
> -           (caps & MMC_CAP_1_2V_DDR &&
> -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
> +       if (caps & MMC_CAP_1_8V_DDR &&
> +           card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
>                 hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
> +       }
>
> -       if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
> -           (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
> +       if (caps & MMC_CAP_1_2V_DDR &&
> +           card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> +               hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
> +       }
> +
> +       if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> +           card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
>                 hs_max_dtr = MMC_HS200_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
> +       }
> +
> +       if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> +           card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
> +               hs_max_dtr = MMC_HS200_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> +       }
>
>         card->ext_csd.hs_max_dtr = hs_max_dtr;
> -       card->ext_csd.card_type = card_type;
> +       card->mmc_avail_type = avail_type;
>  }
>
>  /*
> @@ -708,6 +726,11 @@ static struct device_type mmc_type = {
>         .groups = mmc_attr_groups,
>  };
>
> +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> +{
> +       return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> +}
> +

Having a separate function for this seem a bit silly. Similar checks
is performed all over the code. I suggest you remove this.

>  /*
>   * Select the PowerClass for the current bus width
>   * If power class is defined for 4/8 bit bus in the
> @@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
>
>         host = card->host;
>
> -       if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
> -                       host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
>                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
>
> -       if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
> -                       host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
> +       if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
>                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
>
>         /* If fails try again during next card power cycle */
> @@ -1072,10 +1093,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>          */
>         if (card->ext_csd.hs_max_dtr != 0) {
>                 err = 0;
> -               if (card->ext_csd.hs_max_dtr > 52000000 &&
> -                   host->caps2 & MMC_CAP2_HS200)
> +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>                         err = mmc_select_hs200(card);
> -               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> +               else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>                         err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>                                         EXT_CSD_HS_TIMING, 1,
>                                         card->ext_csd.generic_cmd6_time,
> @@ -1089,13 +1109,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                                mmc_hostname(card->host));
>                         err = 0;
>                 } else {
> -                       if (card->ext_csd.hs_max_dtr > 52000000 &&
> -                           host->caps2 & MMC_CAP2_HS200) {
> +                       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>                                 mmc_set_timing(card->host,
>                                                MMC_TIMING_MMC_HS200);
> -                       } else {
> +                       else
>                                 mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> -                       }
>                 }
>         }
>
> @@ -1118,14 +1136,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>         /*
>          * Indicate DDR mode (if supported).
>          */
> -       if (mmc_card_hs(card)) {
> -               if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
> -                       && (host->caps & MMC_CAP_1_8V_DDR))
> -                               ddr = MMC_1_8V_DDR_MODE;
> -               else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
> -                       && (host->caps & MMC_CAP_1_2V_DDR))
> -                               ddr = MMC_1_2V_DDR_MODE;
> -       }
> +       if (mmc_card_hs(card))
> +               ddr = mmc_snoop_ddr(card);
>
>         /*
>          * Indicate HS200 SDR mode (if supported).
> @@ -1145,8 +1157,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                  * 3. set the clock to > 52Mhz <=200MHz and
>                  * 4. execute tuning for HS200
>                  */
> -               if ((host->caps2 & MMC_CAP2_HS200) &&
> -                   card->host->ops->execute_tuning) {
> +               if (card->host->ops->execute_tuning) {
>                         mmc_host_clk_hold(card->host);
>                         err = card->host->ops->execute_tuning(card->host,
>                                 MMC_SEND_TUNING_BLOCK_HS200);
> @@ -1255,7 +1266,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                          *
>                          * WARNING: eMMC rules are NOT the same as SD DDR
>                          */
> -                       if (ddr == MMC_1_2V_DDR_MODE) {
> +                       if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
>                                 err = __mmc_set_signal_voltage(host,
>                                         MMC_SIGNAL_VOLTAGE_120);
>                                 if (err)
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 5473133..c232b10 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -68,7 +68,6 @@ struct mmc_ext_csd {
>  #define MMC_HIGH_DDR_MAX_DTR   52000000
>  #define MMC_HS200_MAX_DTR      200000000
>         unsigned int            sectors;
> -       unsigned int            card_type;
>         unsigned int            hc_erase_size;          /* In sectors */
>         unsigned int            hc_erase_timeout;       /* In milliseconds */
>         unsigned int            sec_trim_mult;  /* Secure trim multiplier  */
> @@ -297,7 +296,10 @@ struct mmc_card {
>         const char              **info;         /* info strings */
>         struct sdio_func_tuple  *tuples;        /* unknown common tuples */
>
> -       unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
> +       union {
> +               unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
> +               unsigned int            mmc_avail_type; /* supported device type by both host and card */

Using a union here won't be that much of a gain since there are only
few instances of the struct. Please remove.

> +       };
>
>         struct dentry           *debugfs_root;
>         struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 2f263ae..1ee3c10 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -62,12 +62,6 @@ struct mmc_ios {
>  #define MMC_TIMING_MMC_DDR52   8
>  #define MMC_TIMING_MMC_HS200   9
>
> -#define MMC_SDR_MODE           0
> -#define MMC_1_2V_DDR_MODE      1
> -#define MMC_1_8V_DDR_MODE      2
> -#define MMC_1_2V_SDR_MODE      3
> -#define MMC_1_8V_SDR_MODE      4
> -
>         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
>
>  #define MMC_SIGNAL_VOLTAGE_330 0
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 50bcde3..f734c0c 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -354,18 +354,22 @@ struct _mmc_csd {
>  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
>  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
>
> -#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_MASK 0x3F    /* Mask out reserved bits */
> +#define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
> +#define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
> +#define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
> +                                EXT_CSD_CARD_TYPE_HS_52)
>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
>                                              /* DDR mode @1.8V or 3V I/O */
>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
>                                              /* DDR mode @1.2V I/O */
>  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
>                                         | EXT_CSD_CARD_TYPE_DDR_1_2V)
> -#define EXT_CSD_CARD_TYPE_SDR_1_8V     (1<<4)  /* Card can run at 200MHz */
> -#define EXT_CSD_CARD_TYPE_SDR_1_2V     (1<<5)  /* Card can run at 200MHz */
> +#define EXT_CSD_CARD_TYPE_HS200_1_8V   (1<<4)  /* Card can run at 200MHz */
> +#define EXT_CSD_CARD_TYPE_HS200_1_2V   (1<<5)  /* Card can run at 200MHz */
>                                                 /* SDR mode @1.2V I/O */
> +#define EXT_CSD_CARD_TYPE_HS200                (EXT_CSD_CARD_TYPE_HS200_1_8V | \
> +                                        EXT_CSD_CARD_TYPE_HS200_1_2V)
>
>  #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
> --
> 1.7.0.4
>
>

Besides the minor stuff, looks good.

Kind regards
Ulf Hansson

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

* Re: [PATCH v2 3/5] mmc: step power class after final selection of bus mode
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
@ 2014-03-13 14:28     ` Ulf Hansson
  2014-03-14  2:49       ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-03-13 14:28 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 7 March 2014 15:36, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Power class is changed once only after selection of bus modes
> including speed and bus-width finishes finally.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
> Changes in v2:
>         Cleaned up some unnecessary codes.
>
>  drivers/mmc/core/mmc.c |   94 +++++++++++++++++++++++++++--------------------
>  1 files changed, 54 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 0abece0..88ff217 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -737,17 +737,13 @@ static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
>   * extended CSD register, select it by executing the
>   * mmc_switch command.
>   */
> -static int mmc_select_powerclass(struct mmc_card *card,
> -               unsigned int bus_width)
> +static int __mmc_select_powerclass(struct mmc_card *card,
> +                                  unsigned int bus_width)
>  {
>         int err = 0;
>         unsigned int pwrclass_val = 0;
> -       struct mmc_host *host;
> -
> -       BUG_ON(!card);
> -
> -       host = card->host;
> -       BUG_ON(!host);
> +       struct mmc_host *host = card->host;
> +       struct mmc_ext_csd *ext_csd = &card->ext_csd;
>
>         /* Power class selection is supported for versions >= 4.0 */
>         if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
> @@ -759,14 +755,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
>
>         switch (1 << host->ios.vdd) {
>         case MMC_VDD_165_195:
> -               if (host->ios.clock <= 26000000)
> -                       pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
> -               else if (host->ios.clock <= 52000000)
> +               if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
> +                       pwrclass_val = ext_csd->raw_pwr_cl_26_195;
> +               else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
>                         pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
> -                               card->ext_csd.raw_pwr_cl_52_195 :
> -                               card->ext_csd.raw_pwr_cl_ddr_52_195;
> -               else if (host->ios.clock <= 200000000)
> -                       pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
> +                               ext_csd->raw_pwr_cl_52_195 :
> +                               ext_csd->raw_pwr_cl_ddr_52_195;
> +               else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> +                       pwrclass_val = ext_csd->raw_pwr_cl_200_195;
>                 break;
>         case MMC_VDD_27_28:
>         case MMC_VDD_28_29:
> @@ -777,14 +773,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
>         case MMC_VDD_33_34:
>         case MMC_VDD_34_35:
>         case MMC_VDD_35_36:
> -               if (host->ios.clock <= 26000000)
> -                       pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
> -               else if (host->ios.clock <= 52000000)
> +               if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
> +                       pwrclass_val = ext_csd->raw_pwr_cl_26_360;
> +               else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
>                         pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
> -                               card->ext_csd.raw_pwr_cl_52_360 :
> -                               card->ext_csd.raw_pwr_cl_ddr_52_360;
> -               else if (host->ios.clock <= 200000000)
> -                       pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
> +                               ext_csd->raw_pwr_cl_52_360 :
> +                               ext_csd->raw_pwr_cl_ddr_52_360;
> +               else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> +                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
>                 break;
>         default:
>                 pr_warning("%s: Voltage range not supported "
> @@ -810,6 +806,37 @@ static int mmc_select_powerclass(struct mmc_card *card,
>         return err;
>  }
>
> +static int mmc_select_powerclass(struct mmc_card *card)
> +{
> +       int err, ddr;
> +       u32 bus_width, ext_csd_bits;
> +       struct mmc_host *host = card->host;
> +
> +       /* Power class selection is supported for versions >= 4.0 */
> +       if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
> +               return 0;
> +
> +       bus_width = host->ios.bus_width;
> +       /* Power class values are defined only for 4/8 bit bus */
> +       if (bus_width == MMC_BUS_WIDTH_1)
> +               return 0;
> +
> +       ddr = mmc_snoop_ddr(card);
> +       if (ddr)
> +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> +                       EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
> +       else
> +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> +                       EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
> +
> +       err = __mmc_select_powerclass(card, ext_csd_bits);
> +       if (err)
> +               pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
> +                       mmc_hostname(host), 1 << bus_width, ddr);
> +
> +       return err;
> +}
> +
>  /*
>   * Selects the desired buswidth and switch to the HS200 mode
>   * if bus width set without error
> @@ -1171,11 +1198,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>
>                 ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
>                                 EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
> -               err = mmc_select_powerclass(card, ext_csd_bits);
> -               if (err)
> -                       pr_warning("%s: power class selection to bus width %d"
> -                                  " failed\n", mmc_hostname(card->host),
> -                                  1 << bus_width);
>         }
>
>         /*
> @@ -1204,12 +1226,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                         bus_width = bus_widths[idx];
>                         if (bus_width == MMC_BUS_WIDTH_1)
>                                 ddr = 0; /* no DDR for 1-bit width */
> -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
> -                       if (err)
> -                               pr_warning("%s: power class selection to "
> -                                          "bus width %d failed\n",
> -                                          mmc_hostname(card->host),
> -                                          1 << bus_width);
>
>                         err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>                                          EXT_CSD_BUS_WIDTH,
> @@ -1234,13 +1250,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                 }
>
>                 if (!err && ddr) {
> -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
> -                       if (err)
> -                               pr_warning("%s: power class selection to "
> -                                          "bus width %d ddr %d failed\n",
> -                                          mmc_hostname(card->host),
> -                                          1 << bus_width, ddr);
> -
>                         err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>                                          EXT_CSD_BUS_WIDTH,
>                                          ext_csd_bits[idx][1],
> @@ -1278,6 +1287,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>         }
>
>         /*
> +        * Choose the power calss with selected bus interface

One line of comment is enough.

"calss" -> "class".

> +        */
> +       mmc_select_powerclass(card);
> +
> +       /*
>          * Enable HPI feature (if supported)
>          */
>         if (card->ext_csd.hpi) {
> --
> 1.7.0.4
>
>

You should run checkpatch as well.

Besides these minor things, looks good - nice clean up!

Kind regards
Ulf Hansson

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

* Re: [PATCH v2 0/5] update selection of bus speed mode for eMMC
  2014-03-07 14:35   ` [PATCH v2 " Seungwon Jeon
@ 2014-03-13 14:41     ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-03-13 14:41 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 7 March 2014 15:35, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> This series contains the change for selection of bus speed mode.
> Previous implementation is complicated and some sequence is duplicated.
> And specially, HS400 mode eMMC5.0 is introduced this time.
>
> - Continued/Updated since "[PATCH 0/3] mmc: update bus speed mode" series.
>   (Applied some comments from Ulf Hansson, Jackey Shen.)
> - Tested at EXYNOS SOC.
>
> Seungwon Jeon (5):
>   mmc: drop the speed mode of card's state
>   mmc: identify available device type to select
>   mmc: step power class after final selection of bus mode
>   mmc: rework selection of bus speed mode
>   mmc: add support for HS400 mode of eMMC5.0
>

Could you please rebase your patches on latest mmc-next, and please
run checkpatch for all of them.

Kind regards
Ulf Hansson


>  drivers/mmc/core/bus.c     |    9 +-
>  drivers/mmc/core/core.c    |    3 +-
>  drivers/mmc/core/debugfs.c |    5 +-
>  drivers/mmc/core/mmc.c     |  688 +++++++++++++++++++++++++++-----------------
>  drivers/mmc/core/sd.c      |   16 +-
>  drivers/mmc/core/sd.h      |    1 -
>  drivers/mmc/core/sdio.c    |    8 +-
>  include/linux/mmc/card.h   |   31 +--
>  include/linux/mmc/host.h   |   42 +++-
>  include/linux/mmc/mmc.h    |   23 ++-
>  10 files changed, 505 insertions(+), 321 deletions(-)
>
>

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

* RE: [PATCH v2 2/5] mmc: identify available device type to select
  2014-03-13 14:02     ` Ulf Hansson
@ 2014-03-14  2:49       ` Seungwon Jeon
  2014-03-14  7:34         ` Ulf Hansson
  2014-03-28  8:31         ` Ulf Hansson
  0 siblings, 2 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14  2:49 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On Thu, March 13, 2014, Ulf Hansson wrote:
> On 7 March 2014 15:36, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Device types which are supported by both host and device
> > can be identified when EXT_CSD is read. There is no need to
> > check host's capability anymore.
> >
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > ---
> > Changes in v2:
> >         Just rebased with latest one.
> >
> >  drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
> >  include/linux/mmc/card.h |    6 ++-
> >  include/linux/mmc/host.h |    6 ---
> >  include/linux/mmc/mmc.h  |   12 +++++--
> >  4 files changed, 56 insertions(+), 45 deletions(-)
> >
> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > index db9655f..0abece0 100644
> > --- a/drivers/mmc/core/mmc.c
> > +++ b/drivers/mmc/core/mmc.c
> > @@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
> >         u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> >         u32 caps = host->caps, caps2 = host->caps2;
> >         unsigned int hs_max_dtr = 0;
> > +       unsigned int avail_type = 0;
> >
> > -       if (card_type & EXT_CSD_CARD_TYPE_26)
> > +       if (caps & MMC_CAP_MMC_HIGHSPEED &&
> > +           card_type & EXT_CSD_CARD_TYPE_HS_26) {
> >                 hs_max_dtr = MMC_HIGH_26_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_HS_26;
> > +       }
> >
> >         if (caps & MMC_CAP_MMC_HIGHSPEED &&
> > -                       card_type & EXT_CSD_CARD_TYPE_52)
> > +           card_type & EXT_CSD_CARD_TYPE_HS_52) {
> >                 hs_max_dtr = MMC_HIGH_52_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_HS_52;
> > +       }
> >
> > -       if ((caps & MMC_CAP_1_8V_DDR &&
> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
> > -           (caps & MMC_CAP_1_2V_DDR &&
> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
> > +       if (caps & MMC_CAP_1_8V_DDR &&
> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
> >                 hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
> > +       }
> >
> > -       if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
> > -           (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
> > +       if (caps & MMC_CAP_1_2V_DDR &&
> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> > +               hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
> > +       }
> > +
> > +       if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> > +           card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
> >                 hs_max_dtr = MMC_HS200_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
> > +       }
> > +
> > +       if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> > +           card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
> > +               hs_max_dtr = MMC_HS200_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> > +       }
> >
> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
> > -       card->ext_csd.card_type = card_type;
> > +       card->mmc_avail_type = avail_type;
> >  }
> >
> >  /*
> > @@ -708,6 +726,11 @@ static struct device_type mmc_type = {
> >         .groups = mmc_attr_groups,
> >  };
> >
> > +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> > +{
> > +       return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> > +}
> > +
> 
> Having a separate function for this seem a bit silly. Similar checks
> is performed all over the code. I suggest you remove this.
I understand your meaning.
Yes, actually similar checking card type is done.
But checking DDR type is required several times unlike other type case.
I considered for that. I think it's pretty useful in terms of avoiding duplication and enhancement of readability.

> 
> >  /*
> >   * Select the PowerClass for the current bus width
> >   * If power class is defined for 4/8 bit bus in the
> > @@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
> >
> >         host = card->host;
> >
> > -       if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
> > -                       host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
> > +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
> >                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
> >
> > -       if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
> > -                       host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
> > +       if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
> >                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
> >
> >         /* If fails try again during next card power cycle */
> > @@ -1072,10 +1093,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >          */
> >         if (card->ext_csd.hs_max_dtr != 0) {
> >                 err = 0;
> > -               if (card->ext_csd.hs_max_dtr > 52000000 &&
> > -                   host->caps2 & MMC_CAP2_HS200)
> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> >                         err = mmc_select_hs200(card);
> > -               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> > +               else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
> >                         err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >                                         EXT_CSD_HS_TIMING, 1,
> >                                         card->ext_csd.generic_cmd6_time,
> > @@ -1089,13 +1109,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >                                mmc_hostname(card->host));
> >                         err = 0;
> >                 } else {
> > -                       if (card->ext_csd.hs_max_dtr > 52000000 &&
> > -                           host->caps2 & MMC_CAP2_HS200) {
> > +                       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> >                                 mmc_set_timing(card->host,
> >                                                MMC_TIMING_MMC_HS200);
> > -                       } else {
> > +                       else
> >                                 mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> > -                       }
> >                 }
> >         }
> >
> > @@ -1118,14 +1136,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >         /*
> >          * Indicate DDR mode (if supported).
> >          */
> > -       if (mmc_card_hs(card)) {
> > -               if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
> > -                       && (host->caps & MMC_CAP_1_8V_DDR))
> > -                               ddr = MMC_1_8V_DDR_MODE;
> > -               else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
> > -                       && (host->caps & MMC_CAP_1_2V_DDR))
> > -                               ddr = MMC_1_2V_DDR_MODE;
> > -       }
> > +       if (mmc_card_hs(card))
> > +               ddr = mmc_snoop_ddr(card);
> >
> >         /*
> >          * Indicate HS200 SDR mode (if supported).
> > @@ -1145,8 +1157,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >                  * 3. set the clock to > 52Mhz <=200MHz and
> >                  * 4. execute tuning for HS200
> >                  */
> > -               if ((host->caps2 & MMC_CAP2_HS200) &&
> > -                   card->host->ops->execute_tuning) {
> > +               if (card->host->ops->execute_tuning) {
> >                         mmc_host_clk_hold(card->host);
> >                         err = card->host->ops->execute_tuning(card->host,
> >                                 MMC_SEND_TUNING_BLOCK_HS200);
> > @@ -1255,7 +1266,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >                          *
> >                          * WARNING: eMMC rules are NOT the same as SD DDR
> >                          */
> > -                       if (ddr == MMC_1_2V_DDR_MODE) {
> > +                       if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> >                                 err = __mmc_set_signal_voltage(host,
> >                                         MMC_SIGNAL_VOLTAGE_120);
> >                                 if (err)
> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > index 5473133..c232b10 100644
> > --- a/include/linux/mmc/card.h
> > +++ b/include/linux/mmc/card.h
> > @@ -68,7 +68,6 @@ struct mmc_ext_csd {
> >  #define MMC_HIGH_DDR_MAX_DTR   52000000
> >  #define MMC_HS200_MAX_DTR      200000000
> >         unsigned int            sectors;
> > -       unsigned int            card_type;
> >         unsigned int            hc_erase_size;          /* In sectors */
> >         unsigned int            hc_erase_timeout;       /* In milliseconds */
> >         unsigned int            sec_trim_mult;  /* Secure trim multiplier  */
> > @@ -297,7 +296,10 @@ struct mmc_card {
> >         const char              **info;         /* info strings */
> >         struct sdio_func_tuple  *tuples;        /* unknown common tuples */
> >
> > -       unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
> > +       union {
> > +               unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
> > +               unsigned int            mmc_avail_type; /* supported device type by both host and card */
> 
> Using a union here won't be that much of a gain since there are only
> few instances of the struct. Please remove.
Yes, you're right. It's not much in gain.
I intended to distinguish these two similar members respectively.
It's used only in each specific type domain and not used at the same time.
If no meaningful, I can remove as your suggestion.

Thanks,
Seungwon Jeon

> 
> > +       };
> >
> >         struct dentry           *debugfs_root;
> >         struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > index 2f263ae..1ee3c10 100644
> > --- a/include/linux/mmc/host.h
> > +++ b/include/linux/mmc/host.h
> > @@ -62,12 +62,6 @@ struct mmc_ios {
> >  #define MMC_TIMING_MMC_DDR52   8
> >  #define MMC_TIMING_MMC_HS200   9
> >
> > -#define MMC_SDR_MODE           0
> > -#define MMC_1_2V_DDR_MODE      1
> > -#define MMC_1_8V_DDR_MODE      2
> > -#define MMC_1_2V_SDR_MODE      3
> > -#define MMC_1_8V_SDR_MODE      4
> > -
> >         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
> >
> >  #define MMC_SIGNAL_VOLTAGE_330 0
> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> > index 50bcde3..f734c0c 100644
> > --- a/include/linux/mmc/mmc.h
> > +++ b/include/linux/mmc/mmc.h
> > @@ -354,18 +354,22 @@ struct _mmc_csd {
> >  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
> >  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
> >
> > -#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_MASK 0x3F    /* Mask out reserved bits */
> > +#define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
> > +#define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
> > +#define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
> > +                                EXT_CSD_CARD_TYPE_HS_52)
> >  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
> >                                              /* DDR mode @1.8V or 3V I/O */
> >  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
> >                                              /* DDR mode @1.2V I/O */
> >  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
> >                                         | EXT_CSD_CARD_TYPE_DDR_1_2V)
> > -#define EXT_CSD_CARD_TYPE_SDR_1_8V     (1<<4)  /* Card can run at 200MHz */
> > -#define EXT_CSD_CARD_TYPE_SDR_1_2V     (1<<5)  /* Card can run at 200MHz */
> > +#define EXT_CSD_CARD_TYPE_HS200_1_8V   (1<<4)  /* Card can run at 200MHz */
> > +#define EXT_CSD_CARD_TYPE_HS200_1_2V   (1<<5)  /* Card can run at 200MHz */
> >                                                 /* SDR mode @1.2V I/O */
> > +#define EXT_CSD_CARD_TYPE_HS200                (EXT_CSD_CARD_TYPE_HS200_1_8V | \
> > +                                        EXT_CSD_CARD_TYPE_HS200_1_2V)
> >
> >  #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
> >  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
> > --
> > 1.7.0.4
> >
> >
> 
> Besides the minor stuff, looks good.
> 
> Kind regards
> Ulf Hansson


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

* RE: [PATCH v2 3/5] mmc: step power class after final selection of bus mode
  2014-03-13 14:28     ` Ulf Hansson
@ 2014-03-14  2:49       ` Seungwon Jeon
  2014-03-14  7:31         ` Ulf Hansson
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14  2:49 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On Thu, March 13, 2014, Ulf Hansson wrote:
> On 7 March 2014 15:36, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Power class is changed once only after selection of bus modes
> > including speed and bus-width finishes finally.
> >
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > ---
> > Changes in v2:
> >         Cleaned up some unnecessary codes.
> >
> >  drivers/mmc/core/mmc.c |   94 +++++++++++++++++++++++++++--------------------
> >  1 files changed, 54 insertions(+), 40 deletions(-)
> >
> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > index 0abece0..88ff217 100644
> > --- a/drivers/mmc/core/mmc.c
> > +++ b/drivers/mmc/core/mmc.c
> > @@ -737,17 +737,13 @@ static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> >   * extended CSD register, select it by executing the
> >   * mmc_switch command.
> >   */
> > -static int mmc_select_powerclass(struct mmc_card *card,
> > -               unsigned int bus_width)
> > +static int __mmc_select_powerclass(struct mmc_card *card,
> > +                                  unsigned int bus_width)
> >  {
> >         int err = 0;
> >         unsigned int pwrclass_val = 0;
> > -       struct mmc_host *host;
> > -
> > -       BUG_ON(!card);
> > -
> > -       host = card->host;
> > -       BUG_ON(!host);
> > +       struct mmc_host *host = card->host;
> > +       struct mmc_ext_csd *ext_csd = &card->ext_csd;
> >
> >         /* Power class selection is supported for versions >= 4.0 */
> >         if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
> > @@ -759,14 +755,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
> >
> >         switch (1 << host->ios.vdd) {
> >         case MMC_VDD_165_195:
> > -               if (host->ios.clock <= 26000000)
> > -                       pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
> > -               else if (host->ios.clock <= 52000000)
> > +               if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
> > +                       pwrclass_val = ext_csd->raw_pwr_cl_26_195;
> > +               else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
> >                         pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
> > -                               card->ext_csd.raw_pwr_cl_52_195 :
> > -                               card->ext_csd.raw_pwr_cl_ddr_52_195;
> > -               else if (host->ios.clock <= 200000000)
> > -                       pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
> > +                               ext_csd->raw_pwr_cl_52_195 :
> > +                               ext_csd->raw_pwr_cl_ddr_52_195;
> > +               else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> > +                       pwrclass_val = ext_csd->raw_pwr_cl_200_195;
> >                 break;
> >         case MMC_VDD_27_28:
> >         case MMC_VDD_28_29:
> > @@ -777,14 +773,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
> >         case MMC_VDD_33_34:
> >         case MMC_VDD_34_35:
> >         case MMC_VDD_35_36:
> > -               if (host->ios.clock <= 26000000)
> > -                       pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
> > -               else if (host->ios.clock <= 52000000)
> > +               if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
> > +                       pwrclass_val = ext_csd->raw_pwr_cl_26_360;
> > +               else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
> >                         pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
> > -                               card->ext_csd.raw_pwr_cl_52_360 :
> > -                               card->ext_csd.raw_pwr_cl_ddr_52_360;
> > -               else if (host->ios.clock <= 200000000)
> > -                       pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
> > +                               ext_csd->raw_pwr_cl_52_360 :
> > +                               ext_csd->raw_pwr_cl_ddr_52_360;
> > +               else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> > +                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
> >                 break;
> >         default:
> >                 pr_warning("%s: Voltage range not supported "
> > @@ -810,6 +806,37 @@ static int mmc_select_powerclass(struct mmc_card *card,
> >         return err;
> >  }
> >
> > +static int mmc_select_powerclass(struct mmc_card *card)
> > +{
> > +       int err, ddr;
> > +       u32 bus_width, ext_csd_bits;
> > +       struct mmc_host *host = card->host;
> > +
> > +       /* Power class selection is supported for versions >= 4.0 */
> > +       if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
> > +               return 0;
> > +
> > +       bus_width = host->ios.bus_width;
> > +       /* Power class values are defined only for 4/8 bit bus */
> > +       if (bus_width == MMC_BUS_WIDTH_1)
> > +               return 0;
> > +
> > +       ddr = mmc_snoop_ddr(card);
> > +       if (ddr)
> > +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> > +                       EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
> > +       else
> > +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> > +                       EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
> > +
> > +       err = __mmc_select_powerclass(card, ext_csd_bits);
> > +       if (err)
> > +               pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
> > +                       mmc_hostname(host), 1 << bus_width, ddr);
> > +
> > +       return err;
> > +}
> > +
> >  /*
> >   * Selects the desired buswidth and switch to the HS200 mode
> >   * if bus width set without error
> > @@ -1171,11 +1198,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >
> >                 ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> >                                 EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
> > -               err = mmc_select_powerclass(card, ext_csd_bits);
> > -               if (err)
> > -                       pr_warning("%s: power class selection to bus width %d"
> > -                                  " failed\n", mmc_hostname(card->host),
> > -                                  1 << bus_width);
> >         }
> >
> >         /*
> > @@ -1204,12 +1226,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >                         bus_width = bus_widths[idx];
> >                         if (bus_width == MMC_BUS_WIDTH_1)
> >                                 ddr = 0; /* no DDR for 1-bit width */
> > -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
> > -                       if (err)
> > -                               pr_warning("%s: power class selection to "
> > -                                          "bus width %d failed\n",
> > -                                          mmc_hostname(card->host),
> > -                                          1 << bus_width);
> >
> >                         err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >                                          EXT_CSD_BUS_WIDTH,
> > @@ -1234,13 +1250,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >                 }
> >
> >                 if (!err && ddr) {
> > -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
> > -                       if (err)
> > -                               pr_warning("%s: power class selection to "
> > -                                          "bus width %d ddr %d failed\n",
> > -                                          mmc_hostname(card->host),
> > -                                          1 << bus_width, ddr);
> > -
> >                         err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >                                          EXT_CSD_BUS_WIDTH,
> >                                          ext_csd_bits[idx][1],
> > @@ -1278,6 +1287,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >         }
> >
> >         /*
> > +        * Choose the power calss with selected bus interface
> 
> One line of comment is enough.
> 
> "calss" -> "class".
OK.

> 
> > +        */
> > +       mmc_select_powerclass(card);
> > +
> > +       /*
> >          * Enable HPI feature (if supported)
> >          */
> >         if (card->ext_csd.hpi) {
> > --
> > 1.7.0.4
> >
> >
> 
> You should run checkpatch as well.
It think there was no warning & error in 3/5.
Ok. Let me check more.

> 
> Besides these minor things, looks good - nice clean up!

Thanks,
Seungwon Jeon
> 
> Kind regards
> Ulf Hansson


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

* Re: [PATCH v2 3/5] mmc: step power class after final selection of bus mode
  2014-03-14  2:49       ` Seungwon Jeon
@ 2014-03-14  7:31         ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-03-14  7:31 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 14 March 2014 03:49, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> On Thu, March 13, 2014, Ulf Hansson wrote:
>> On 7 March 2014 15:36, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> > Power class is changed once only after selection of bus modes
>> > including speed and bus-width finishes finally.
>> >
>> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> > ---
>> > Changes in v2:
>> >         Cleaned up some unnecessary codes.
>> >
>> >  drivers/mmc/core/mmc.c |   94 +++++++++++++++++++++++++++--------------------
>> >  1 files changed, 54 insertions(+), 40 deletions(-)
>> >
>> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> > index 0abece0..88ff217 100644
>> > --- a/drivers/mmc/core/mmc.c
>> > +++ b/drivers/mmc/core/mmc.c
>> > @@ -737,17 +737,13 @@ static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
>> >   * extended CSD register, select it by executing the
>> >   * mmc_switch command.
>> >   */
>> > -static int mmc_select_powerclass(struct mmc_card *card,
>> > -               unsigned int bus_width)
>> > +static int __mmc_select_powerclass(struct mmc_card *card,
>> > +                                  unsigned int bus_width)
>> >  {
>> >         int err = 0;
>> >         unsigned int pwrclass_val = 0;
>> > -       struct mmc_host *host;
>> > -
>> > -       BUG_ON(!card);
>> > -
>> > -       host = card->host;
>> > -       BUG_ON(!host);
>> > +       struct mmc_host *host = card->host;
>> > +       struct mmc_ext_csd *ext_csd = &card->ext_csd;
>> >
>> >         /* Power class selection is supported for versions >= 4.0 */
>> >         if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
>> > @@ -759,14 +755,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
>> >
>> >         switch (1 << host->ios.vdd) {
>> >         case MMC_VDD_165_195:
>> > -               if (host->ios.clock <= 26000000)
>> > -                       pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
>> > -               else if (host->ios.clock <= 52000000)
>> > +               if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
>> > +                       pwrclass_val = ext_csd->raw_pwr_cl_26_195;
>> > +               else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
>> >                         pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
>> > -                               card->ext_csd.raw_pwr_cl_52_195 :
>> > -                               card->ext_csd.raw_pwr_cl_ddr_52_195;
>> > -               else if (host->ios.clock <= 200000000)
>> > -                       pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
>> > +                               ext_csd->raw_pwr_cl_52_195 :
>> > +                               ext_csd->raw_pwr_cl_ddr_52_195;
>> > +               else if (host->ios.clock <= MMC_HS200_MAX_DTR)
>> > +                       pwrclass_val = ext_csd->raw_pwr_cl_200_195;
>> >                 break;
>> >         case MMC_VDD_27_28:
>> >         case MMC_VDD_28_29:
>> > @@ -777,14 +773,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
>> >         case MMC_VDD_33_34:
>> >         case MMC_VDD_34_35:
>> >         case MMC_VDD_35_36:
>> > -               if (host->ios.clock <= 26000000)
>> > -                       pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
>> > -               else if (host->ios.clock <= 52000000)
>> > +               if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
>> > +                       pwrclass_val = ext_csd->raw_pwr_cl_26_360;
>> > +               else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
>> >                         pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
>> > -                               card->ext_csd.raw_pwr_cl_52_360 :
>> > -                               card->ext_csd.raw_pwr_cl_ddr_52_360;
>> > -               else if (host->ios.clock <= 200000000)
>> > -                       pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
>> > +                               ext_csd->raw_pwr_cl_52_360 :
>> > +                               ext_csd->raw_pwr_cl_ddr_52_360;
>> > +               else if (host->ios.clock <= MMC_HS200_MAX_DTR)
>> > +                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
>> >                 break;
>> >         default:
>> >                 pr_warning("%s: Voltage range not supported "
>> > @@ -810,6 +806,37 @@ static int mmc_select_powerclass(struct mmc_card *card,
>> >         return err;
>> >  }
>> >
>> > +static int mmc_select_powerclass(struct mmc_card *card)
>> > +{
>> > +       int err, ddr;
>> > +       u32 bus_width, ext_csd_bits;
>> > +       struct mmc_host *host = card->host;
>> > +
>> > +       /* Power class selection is supported for versions >= 4.0 */
>> > +       if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
>> > +               return 0;
>> > +
>> > +       bus_width = host->ios.bus_width;
>> > +       /* Power class values are defined only for 4/8 bit bus */
>> > +       if (bus_width == MMC_BUS_WIDTH_1)
>> > +               return 0;
>> > +
>> > +       ddr = mmc_snoop_ddr(card);
>> > +       if (ddr)
>> > +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
>> > +                       EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
>> > +       else
>> > +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
>> > +                       EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
>> > +
>> > +       err = __mmc_select_powerclass(card, ext_csd_bits);
>> > +       if (err)
>> > +               pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
>> > +                       mmc_hostname(host), 1 << bus_width, ddr);
>> > +
>> > +       return err;
>> > +}
>> > +
>> >  /*
>> >   * Selects the desired buswidth and switch to the HS200 mode
>> >   * if bus width set without error
>> > @@ -1171,11 +1198,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >
>> >                 ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
>> >                                 EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
>> > -               err = mmc_select_powerclass(card, ext_csd_bits);
>> > -               if (err)
>> > -                       pr_warning("%s: power class selection to bus width %d"
>> > -                                  " failed\n", mmc_hostname(card->host),
>> > -                                  1 << bus_width);
>> >         }
>> >
>> >         /*
>> > @@ -1204,12 +1226,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >                         bus_width = bus_widths[idx];
>> >                         if (bus_width == MMC_BUS_WIDTH_1)
>> >                                 ddr = 0; /* no DDR for 1-bit width */
>> > -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
>> > -                       if (err)
>> > -                               pr_warning("%s: power class selection to "
>> > -                                          "bus width %d failed\n",
>> > -                                          mmc_hostname(card->host),
>> > -                                          1 << bus_width);
>> >
>> >                         err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >                                          EXT_CSD_BUS_WIDTH,
>> > @@ -1234,13 +1250,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >                 }
>> >
>> >                 if (!err && ddr) {
>> > -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
>> > -                       if (err)
>> > -                               pr_warning("%s: power class selection to "
>> > -                                          "bus width %d ddr %d failed\n",
>> > -                                          mmc_hostname(card->host),
>> > -                                          1 << bus_width, ddr);
>> > -
>> >                         err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >                                          EXT_CSD_BUS_WIDTH,
>> >                                          ext_csd_bits[idx][1],
>> > @@ -1278,6 +1287,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >         }
>> >
>> >         /*
>> > +        * Choose the power calss with selected bus interface
>>
>> One line of comment is enough.
>>
>> "calss" -> "class".
> OK.
>
>>
>> > +        */
>> > +       mmc_select_powerclass(card);
>> > +
>> > +       /*
>> >          * Enable HPI feature (if supported)
>> >          */
>> >         if (card->ext_csd.hpi) {
>> > --
>> > 1.7.0.4
>> >
>> >
>>
>> You should run checkpatch as well.
> It think there was no warning & error in 3/5.
> Ok. Let me check more.
>

You are right, this patch didn't have checkpatch warnings or errors,
but some of the other in this patchset had. Sorry.

Kind regards
Ulf Hansson

>>
>> Besides these minor things, looks good - nice clean up!
>
> Thanks,
> Seungwon Jeon
>>
>> Kind regards
>> Ulf Hansson
>

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

* Re: [PATCH v2 2/5] mmc: identify available device type to select
  2014-03-14  2:49       ` Seungwon Jeon
@ 2014-03-14  7:34         ` Ulf Hansson
  2014-03-14 10:24           ` Seungwon Jeon
  2014-03-28  8:31         ` Ulf Hansson
  1 sibling, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-03-14  7:34 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 14 March 2014 03:49, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> On Thu, March 13, 2014, Ulf Hansson wrote:
>> On 7 March 2014 15:36, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> > Device types which are supported by both host and device
>> > can be identified when EXT_CSD is read. There is no need to
>> > check host's capability anymore.
>> >
>> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> > ---
>> > Changes in v2:
>> >         Just rebased with latest one.
>> >
>> >  drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
>> >  include/linux/mmc/card.h |    6 ++-
>> >  include/linux/mmc/host.h |    6 ---
>> >  include/linux/mmc/mmc.h  |   12 +++++--
>> >  4 files changed, 56 insertions(+), 45 deletions(-)
>> >
>> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> > index db9655f..0abece0 100644
>> > --- a/drivers/mmc/core/mmc.c
>> > +++ b/drivers/mmc/core/mmc.c
>> > @@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
>> >         u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>> >         u32 caps = host->caps, caps2 = host->caps2;
>> >         unsigned int hs_max_dtr = 0;
>> > +       unsigned int avail_type = 0;
>> >
>> > -       if (card_type & EXT_CSD_CARD_TYPE_26)
>> > +       if (caps & MMC_CAP_MMC_HIGHSPEED &&
>> > +           card_type & EXT_CSD_CARD_TYPE_HS_26) {
>> >                 hs_max_dtr = MMC_HIGH_26_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_HS_26;
>> > +       }
>> >
>> >         if (caps & MMC_CAP_MMC_HIGHSPEED &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_52)
>> > +           card_type & EXT_CSD_CARD_TYPE_HS_52) {
>> >                 hs_max_dtr = MMC_HIGH_52_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_HS_52;
>> > +       }
>> >
>> > -       if ((caps & MMC_CAP_1_8V_DDR &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
>> > -           (caps & MMC_CAP_1_2V_DDR &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
>> > +       if (caps & MMC_CAP_1_8V_DDR &&
>> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
>> >                 hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
>> > +       }
>> >
>> > -       if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
>> > -           (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
>> > +       if (caps & MMC_CAP_1_2V_DDR &&
>> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
>> > +               hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
>> > +       }
>> > +
>> > +       if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
>> > +           card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
>> >                 hs_max_dtr = MMC_HS200_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
>> > +       }
>> > +
>> > +       if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
>> > +           card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
>> > +               hs_max_dtr = MMC_HS200_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>> > +       }
>> >
>> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
>> > -       card->ext_csd.card_type = card_type;
>> > +       card->mmc_avail_type = avail_type;
>> >  }
>> >
>> >  /*
>> > @@ -708,6 +726,11 @@ static struct device_type mmc_type = {
>> >         .groups = mmc_attr_groups,
>> >  };
>> >
>> > +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
>> > +{
>> > +       return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
>> > +}
>> > +
>>
>> Having a separate function for this seem a bit silly. Similar checks
>> is performed all over the code. I suggest you remove this.
> I understand your meaning.
> Yes, actually similar checking card type is done.
> But checking DDR type is required several times unlike other type case.
> I considered for that. I think it's pretty useful in terms of avoiding duplication and enhancement of readability.
>

As we don't have functions that performs the similar check for
"mmc_avail_type", I don't think we should have it for ddr either. I
prefer the symmetry in the code, so please remove.

Kind regards
Ulf Hansson

>>
>> >  /*
>> >   * Select the PowerClass for the current bus width
>> >   * If power class is defined for 4/8 bit bus in the
>> > @@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
>> >
>> >         host = card->host;
>> >
>> > -       if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
>> > -                       host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
>> > +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
>> >                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
>> >
>> > -       if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
>> > -                       host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
>> > +       if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
>> >                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
>> >
>> >         /* If fails try again during next card power cycle */
>> > @@ -1072,10 +1093,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >          */
>> >         if (card->ext_csd.hs_max_dtr != 0) {
>> >                 err = 0;
>> > -               if (card->ext_csd.hs_max_dtr > 52000000 &&
>> > -                   host->caps2 & MMC_CAP2_HS200)
>> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>> >                         err = mmc_select_hs200(card);
>> > -               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
>> > +               else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>> >                         err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >                                         EXT_CSD_HS_TIMING, 1,
>> >                                         card->ext_csd.generic_cmd6_time,
>> > @@ -1089,13 +1109,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >                                mmc_hostname(card->host));
>> >                         err = 0;
>> >                 } else {
>> > -                       if (card->ext_csd.hs_max_dtr > 52000000 &&
>> > -                           host->caps2 & MMC_CAP2_HS200) {
>> > +                       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>> >                                 mmc_set_timing(card->host,
>> >                                                MMC_TIMING_MMC_HS200);
>> > -                       } else {
>> > +                       else
>> >                                 mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> > -                       }
>> >                 }
>> >         }
>> >
>> > @@ -1118,14 +1136,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >         /*
>> >          * Indicate DDR mode (if supported).
>> >          */
>> > -       if (mmc_card_hs(card)) {
>> > -               if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
>> > -                       && (host->caps & MMC_CAP_1_8V_DDR))
>> > -                               ddr = MMC_1_8V_DDR_MODE;
>> > -               else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
>> > -                       && (host->caps & MMC_CAP_1_2V_DDR))
>> > -                               ddr = MMC_1_2V_DDR_MODE;
>> > -       }
>> > +       if (mmc_card_hs(card))
>> > +               ddr = mmc_snoop_ddr(card);
>> >
>> >         /*
>> >          * Indicate HS200 SDR mode (if supported).
>> > @@ -1145,8 +1157,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >                  * 3. set the clock to > 52Mhz <=200MHz and
>> >                  * 4. execute tuning for HS200
>> >                  */
>> > -               if ((host->caps2 & MMC_CAP2_HS200) &&
>> > -                   card->host->ops->execute_tuning) {
>> > +               if (card->host->ops->execute_tuning) {
>> >                         mmc_host_clk_hold(card->host);
>> >                         err = card->host->ops->execute_tuning(card->host,
>> >                                 MMC_SEND_TUNING_BLOCK_HS200);
>> > @@ -1255,7 +1266,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >                          *
>> >                          * WARNING: eMMC rules are NOT the same as SD DDR
>> >                          */
>> > -                       if (ddr == MMC_1_2V_DDR_MODE) {
>> > +                       if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
>> >                                 err = __mmc_set_signal_voltage(host,
>> >                                         MMC_SIGNAL_VOLTAGE_120);
>> >                                 if (err)
>> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> > index 5473133..c232b10 100644
>> > --- a/include/linux/mmc/card.h
>> > +++ b/include/linux/mmc/card.h
>> > @@ -68,7 +68,6 @@ struct mmc_ext_csd {
>> >  #define MMC_HIGH_DDR_MAX_DTR   52000000
>> >  #define MMC_HS200_MAX_DTR      200000000
>> >         unsigned int            sectors;
>> > -       unsigned int            card_type;
>> >         unsigned int            hc_erase_size;          /* In sectors */
>> >         unsigned int            hc_erase_timeout;       /* In milliseconds */
>> >         unsigned int            sec_trim_mult;  /* Secure trim multiplier  */
>> > @@ -297,7 +296,10 @@ struct mmc_card {
>> >         const char              **info;         /* info strings */
>> >         struct sdio_func_tuple  *tuples;        /* unknown common tuples */
>> >
>> > -       unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
>> > +       union {
>> > +               unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
>> > +               unsigned int            mmc_avail_type; /* supported device type by both host and card */
>>
>> Using a union here won't be that much of a gain since there are only
>> few instances of the struct. Please remove.
> Yes, you're right. It's not much in gain.
> I intended to distinguish these two similar members respectively.
> It's used only in each specific type domain and not used at the same time.
> If no meaningful, I can remove as your suggestion.
>
> Thanks,
> Seungwon Jeon
>
>>
>> > +       };
>> >
>> >         struct dentry           *debugfs_root;
>> >         struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
>> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> > index 2f263ae..1ee3c10 100644
>> > --- a/include/linux/mmc/host.h
>> > +++ b/include/linux/mmc/host.h
>> > @@ -62,12 +62,6 @@ struct mmc_ios {
>> >  #define MMC_TIMING_MMC_DDR52   8
>> >  #define MMC_TIMING_MMC_HS200   9
>> >
>> > -#define MMC_SDR_MODE           0
>> > -#define MMC_1_2V_DDR_MODE      1
>> > -#define MMC_1_8V_DDR_MODE      2
>> > -#define MMC_1_2V_SDR_MODE      3
>> > -#define MMC_1_8V_SDR_MODE      4
>> > -
>> >         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
>> >
>> >  #define MMC_SIGNAL_VOLTAGE_330 0
>> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> > index 50bcde3..f734c0c 100644
>> > --- a/include/linux/mmc/mmc.h
>> > +++ b/include/linux/mmc/mmc.h
>> > @@ -354,18 +354,22 @@ struct _mmc_csd {
>> >  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
>> >  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
>> >
>> > -#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_MASK 0x3F    /* Mask out reserved bits */
>> > +#define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
>> > +#define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
>> > +#define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
>> > +                                EXT_CSD_CARD_TYPE_HS_52)
>> >  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
>> >                                              /* DDR mode @1.8V or 3V I/O */
>> >  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
>> >                                              /* DDR mode @1.2V I/O */
>> >  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
>> >                                         | EXT_CSD_CARD_TYPE_DDR_1_2V)
>> > -#define EXT_CSD_CARD_TYPE_SDR_1_8V     (1<<4)  /* Card can run at 200MHz */
>> > -#define EXT_CSD_CARD_TYPE_SDR_1_2V     (1<<5)  /* Card can run at 200MHz */
>> > +#define EXT_CSD_CARD_TYPE_HS200_1_8V   (1<<4)  /* Card can run at 200MHz */
>> > +#define EXT_CSD_CARD_TYPE_HS200_1_2V   (1<<5)  /* Card can run at 200MHz */
>> >                                                 /* SDR mode @1.2V I/O */
>> > +#define EXT_CSD_CARD_TYPE_HS200                (EXT_CSD_CARD_TYPE_HS200_1_8V | \
>> > +                                        EXT_CSD_CARD_TYPE_HS200_1_2V)
>> >
>> >  #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>> >  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
>> > --
>> > 1.7.0.4
>> >
>> >
>>
>> Besides the minor stuff, looks good.
>>
>> Kind regards
>> Ulf Hansson
>

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

* RE: [PATCH v2 2/5] mmc: identify available device type to select
  2014-03-14  7:34         ` Ulf Hansson
@ 2014-03-14 10:24           ` Seungwon Jeon
  0 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 10:24 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On Fri, March 14, 2014, Ulf Hansson wrote:
> On 14 March 2014 03:49, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > On Thu, March 13, 2014, Ulf Hansson wrote:
> >> On 7 March 2014 15:36, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> > Device types which are supported by both host and device
> >> > can be identified when EXT_CSD is read. There is no need to
> >> > check host's capability anymore.
> >> >
> >> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> >> > ---
> >> > Changes in v2:
> >> >         Just rebased with latest one.
> >> >
> >> >  drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
> >> >  include/linux/mmc/card.h |    6 ++-
> >> >  include/linux/mmc/host.h |    6 ---
> >> >  include/linux/mmc/mmc.h  |   12 +++++--
> >> >  4 files changed, 56 insertions(+), 45 deletions(-)
> >> >
> >> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >> > index db9655f..0abece0 100644
> >> > --- a/drivers/mmc/core/mmc.c
> >> > +++ b/drivers/mmc/core/mmc.c
> >> > @@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
> >> >         u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> >> >         u32 caps = host->caps, caps2 = host->caps2;
> >> >         unsigned int hs_max_dtr = 0;
> >> > +       unsigned int avail_type = 0;
> >> >
> >> > -       if (card_type & EXT_CSD_CARD_TYPE_26)
> >> > +       if (caps & MMC_CAP_MMC_HIGHSPEED &&
> >> > +           card_type & EXT_CSD_CARD_TYPE_HS_26) {
> >> >                 hs_max_dtr = MMC_HIGH_26_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS_26;
> >> > +       }
> >> >
> >> >         if (caps & MMC_CAP_MMC_HIGHSPEED &&
> >> > -                       card_type & EXT_CSD_CARD_TYPE_52)
> >> > +           card_type & EXT_CSD_CARD_TYPE_HS_52) {
> >> >                 hs_max_dtr = MMC_HIGH_52_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS_52;
> >> > +       }
> >> >
> >> > -       if ((caps & MMC_CAP_1_8V_DDR &&
> >> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
> >> > -           (caps & MMC_CAP_1_2V_DDR &&
> >> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
> >> > +       if (caps & MMC_CAP_1_8V_DDR &&
> >> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
> >> >                 hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
> >> > +       }
> >> >
> >> > -       if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> >> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
> >> > -           (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> >> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
> >> > +       if (caps & MMC_CAP_1_2V_DDR &&
> >> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> >> > +               hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
> >> > +       }
> >> > +
> >> > +       if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> >> > +           card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
> >> >                 hs_max_dtr = MMC_HS200_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
> >> > +       }
> >> > +
> >> > +       if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> >> > +           card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
> >> > +               hs_max_dtr = MMC_HS200_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> >> > +       }
> >> >
> >> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
> >> > -       card->ext_csd.card_type = card_type;
> >> > +       card->mmc_avail_type = avail_type;
> >> >  }
> >> >
> >> >  /*
> >> > @@ -708,6 +726,11 @@ static struct device_type mmc_type = {
> >> >         .groups = mmc_attr_groups,
> >> >  };
> >> >
> >> > +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> >> > +{
> >> > +       return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> >> > +}
> >> > +
> >>
> >> Having a separate function for this seem a bit silly. Similar checks
> >> is performed all over the code. I suggest you remove this.
> > I understand your meaning.
> > Yes, actually similar checking card type is done.
> > But checking DDR type is required several times unlike other type case.
> > I considered for that. I think it's pretty useful in terms of avoiding duplication and enhancement
> of readability.
> >
> 
> As we don't have functions that performs the similar check for
> "mmc_avail_type", I don't think we should have it for ddr either. I
> prefer the symmetry in the code, so please remove.
OK. I'll try to adjust.

Thanks,
Seungwon Jeon

> 
> Kind regards
> Ulf Hansson
> 
> >>
> >> >  /*
> >> >   * Select the PowerClass for the current bus width
> >> >   * If power class is defined for 4/8 bit bus in the
> >> > @@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
> >> >
> >> >         host = card->host;
> >> >
> >> > -       if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
> >> > -                       host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
> >> > +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
> >> >                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
> >> >
> >> > -       if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
> >> > -                       host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
> >> > +       if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
> >> >                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
> >> >
> >> >         /* If fails try again during next card power cycle */
> >> > @@ -1072,10 +1093,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >> >          */
> >> >         if (card->ext_csd.hs_max_dtr != 0) {
> >> >                 err = 0;
> >> > -               if (card->ext_csd.hs_max_dtr > 52000000 &&
> >> > -                   host->caps2 & MMC_CAP2_HS200)
> >> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> >> >                         err = mmc_select_hs200(card);
> >> > -               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> >> > +               else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
> >> >                         err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >                                         EXT_CSD_HS_TIMING, 1,
> >> >                                         card->ext_csd.generic_cmd6_time,
> >> > @@ -1089,13 +1109,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >> >                                mmc_hostname(card->host));
> >> >                         err = 0;
> >> >                 } else {
> >> > -                       if (card->ext_csd.hs_max_dtr > 52000000 &&
> >> > -                           host->caps2 & MMC_CAP2_HS200) {
> >> > +                       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> >> >                                 mmc_set_timing(card->host,
> >> >                                                MMC_TIMING_MMC_HS200);
> >> > -                       } else {
> >> > +                       else
> >> >                                 mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> >> > -                       }
> >> >                 }
> >> >         }
> >> >
> >> > @@ -1118,14 +1136,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >> >         /*
> >> >          * Indicate DDR mode (if supported).
> >> >          */
> >> > -       if (mmc_card_hs(card)) {
> >> > -               if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
> >> > -                       && (host->caps & MMC_CAP_1_8V_DDR))
> >> > -                               ddr = MMC_1_8V_DDR_MODE;
> >> > -               else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
> >> > -                       && (host->caps & MMC_CAP_1_2V_DDR))
> >> > -                               ddr = MMC_1_2V_DDR_MODE;
> >> > -       }
> >> > +       if (mmc_card_hs(card))
> >> > +               ddr = mmc_snoop_ddr(card);
> >> >
> >> >         /*
> >> >          * Indicate HS200 SDR mode (if supported).
> >> > @@ -1145,8 +1157,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >> >                  * 3. set the clock to > 52Mhz <=200MHz and
> >> >                  * 4. execute tuning for HS200
> >> >                  */
> >> > -               if ((host->caps2 & MMC_CAP2_HS200) &&
> >> > -                   card->host->ops->execute_tuning) {
> >> > +               if (card->host->ops->execute_tuning) {
> >> >                         mmc_host_clk_hold(card->host);
> >> >                         err = card->host->ops->execute_tuning(card->host,
> >> >                                 MMC_SEND_TUNING_BLOCK_HS200);
> >> > @@ -1255,7 +1266,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >> >                          *
> >> >                          * WARNING: eMMC rules are NOT the same as SD DDR
> >> >                          */
> >> > -                       if (ddr == MMC_1_2V_DDR_MODE) {
> >> > +                       if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> >> >                                 err = __mmc_set_signal_voltage(host,
> >> >                                         MMC_SIGNAL_VOLTAGE_120);
> >> >                                 if (err)
> >> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> >> > index 5473133..c232b10 100644
> >> > --- a/include/linux/mmc/card.h
> >> > +++ b/include/linux/mmc/card.h
> >> > @@ -68,7 +68,6 @@ struct mmc_ext_csd {
> >> >  #define MMC_HIGH_DDR_MAX_DTR   52000000
> >> >  #define MMC_HS200_MAX_DTR      200000000
> >> >         unsigned int            sectors;
> >> > -       unsigned int            card_type;
> >> >         unsigned int            hc_erase_size;          /* In sectors */
> >> >         unsigned int            hc_erase_timeout;       /* In milliseconds */
> >> >         unsigned int            sec_trim_mult;  /* Secure trim multiplier  */
> >> > @@ -297,7 +296,10 @@ struct mmc_card {
> >> >         const char              **info;         /* info strings */
> >> >         struct sdio_func_tuple  *tuples;        /* unknown common tuples */
> >> >
> >> > -       unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
> >> > +       union {
> >> > +               unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
> >> > +               unsigned int            mmc_avail_type; /* supported device type by both host and card
> */
> >>
> >> Using a union here won't be that much of a gain since there are only
> >> few instances of the struct. Please remove.
> > Yes, you're right. It's not much in gain.
> > I intended to distinguish these two similar members respectively.
> > It's used only in each specific type domain and not used at the same time.
> > If no meaningful, I can remove as your suggestion.
> >
> > Thanks,
> > Seungwon Jeon
> >
> >>
> >> > +       };
> >> >
> >> >         struct dentry           *debugfs_root;
> >> >         struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
> >> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> >> > index 2f263ae..1ee3c10 100644
> >> > --- a/include/linux/mmc/host.h
> >> > +++ b/include/linux/mmc/host.h
> >> > @@ -62,12 +62,6 @@ struct mmc_ios {
> >> >  #define MMC_TIMING_MMC_DDR52   8
> >> >  #define MMC_TIMING_MMC_HS200   9
> >> >
> >> > -#define MMC_SDR_MODE           0
> >> > -#define MMC_1_2V_DDR_MODE      1
> >> > -#define MMC_1_8V_DDR_MODE      2
> >> > -#define MMC_1_2V_SDR_MODE      3
> >> > -#define MMC_1_8V_SDR_MODE      4
> >> > -
> >> >         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
> >> >
> >> >  #define MMC_SIGNAL_VOLTAGE_330 0
> >> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> >> > index 50bcde3..f734c0c 100644
> >> > --- a/include/linux/mmc/mmc.h
> >> > +++ b/include/linux/mmc/mmc.h
> >> > @@ -354,18 +354,22 @@ struct _mmc_csd {
> >> >  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
> >> >  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
> >> >
> >> > -#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_MASK 0x3F    /* Mask out reserved bits */
> >> > +#define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
> >> > +#define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
> >> > +#define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
> >> > +                                EXT_CSD_CARD_TYPE_HS_52)
> >> >  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
> >> >                                              /* DDR mode @1.8V or 3V I/O */
> >> >  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
> >> >                                              /* DDR mode @1.2V I/O */
> >> >  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
> >> >                                         | EXT_CSD_CARD_TYPE_DDR_1_2V)
> >> > -#define EXT_CSD_CARD_TYPE_SDR_1_8V     (1<<4)  /* Card can run at 200MHz */
> >> > -#define EXT_CSD_CARD_TYPE_SDR_1_2V     (1<<5)  /* Card can run at 200MHz */
> >> > +#define EXT_CSD_CARD_TYPE_HS200_1_8V   (1<<4)  /* Card can run at 200MHz */
> >> > +#define EXT_CSD_CARD_TYPE_HS200_1_2V   (1<<5)  /* Card can run at 200MHz */
> >> >                                                 /* SDR mode @1.2V I/O */
> >> > +#define EXT_CSD_CARD_TYPE_HS200                (EXT_CSD_CARD_TYPE_HS200_1_8V | \
> >> > +                                        EXT_CSD_CARD_TYPE_HS200_1_2V)
> >> >
> >> >  #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
> >> >  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
> >> > --
> >> > 1.7.0.4
> >> >
> >> >
> >>
> >> Besides the minor stuff, looks good.
> >>
> >> Kind regards
> >> Ulf Hansson
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* RE: [PATCH v2 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-03-11  0:45     ` Jackey Shen
@ 2014-03-14 11:34       ` Seungwon Jeon
  0 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 11:34 UTC (permalink / raw)
  To: 'Jackey Shen'
  Cc: linux-mmc, 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Alim Akhtar'

Tuesday, March 11, 2014, Jackey Shen wrote:
> Signed-off-by: Jackey Shen <jackey.shen@amd.com>
I'll send next version with adding your Reviewed-by.

Thanks,
Seungwon Jeon

> 
> Thanks,
> Jackey
> 
> On Fri, Mar 07, 2014 at 11:36:43PM +0900, Seungwon Jeon wrote:
> > 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: Seungwon Jeon <tgih.jun@samsung.com>
> > ---
> > Changes in v2:
> > 	Cleaned up some unnecessary codes.
> >
> >  drivers/mmc/core/bus.c     |    1 +
> >  drivers/mmc/core/debugfs.c |    3 +
> >  drivers/mmc/core/mmc.c     |  120 +++++++++++++++++++++++++++++++++++++++++---
> >  include/linux/mmc/card.h   |    1 +
> >  include/linux/mmc/host.h   |   15 +++++-
> >  include/linux/mmc/mmc.h    |    7 ++-
> >  6 files changed, 138 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> > index f37e9d6..d2dbf02 100644
> > --- a/drivers/mmc/core/bus.c
> > +++ b/drivers/mmc/core/bus.c
> > @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
> >  			mmc_hostname(card->host),
> >  			mmc_card_uhs(card) ? "ultra high speed " :
> >  			(mmc_card_hs(card) ? "high speed " : ""),
> > +			mmc_card_hs400(card) ? "HS400 " :
> >  			(mmc_card_hs200(card) ? "HS200 " : ""),
> >  			mmc_card_ddr52(card) ? "DDR " : "",
> >  			uhs_bus_speed_mode, type, card->rca);
> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> > index 1f730db..91eb162 100644
> > --- a/drivers/mmc/core/debugfs.c
> > +++ b/drivers/mmc/core/debugfs.c
> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
> >  	case MMC_TIMING_MMC_HS200:
> >  		str = "mmc HS200";
> >  		break;
> > +	case MMC_TIMING_MMC_HS400:
> > +		str = "mmc HS400";
> > +		break;
> >  	default:
> >  		str = "invalid";
> >  		break;
> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > index e356a54..998b0af 100644
> > --- a/drivers/mmc/core/mmc.c
> > +++ b/drivers/mmc/core/mmc.c
> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
> >  static void mmc_select_card_type(struct mmc_card *card)
> >  {
> >  	struct mmc_host *host = card->host;
> > -	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> > +	u8 card_type = card->ext_csd.raw_card_type;
> >  	u32 caps = host->caps, caps2 = host->caps2;
> >  	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
> >  	unsigned int avail_type = 0;
> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
> >  		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> >  	}
> >
> > +	if (caps2 & MMC_CAP2_HS400_1_8V &&
> > +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> > +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> > +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> > +	}
> > +
> > +	if (caps2 & MMC_CAP2_HS400_1_2V &&
> > +	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> > +		hs200_max_dtr = MMC_HS200_MAX_DTR;
> > +		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> > +	}
> > +
> >  	card->ext_csd.hs_max_dtr = hs_max_dtr;
> >  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
> >  	card->mmc_avail_type = avail_type;
> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
> >  			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
> >  		card->ext_csd.raw_pwr_cl_ddr_52_360 =
> >  			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> > +		card->ext_csd.raw_pwr_cl_ddr_200_360 =
> > +			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
> >  	}
> >
> >  	if (card->ext_csd.rev >= 5) {
> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
> >  		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
> >  			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
> >  		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> > -			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> > +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> > +		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> > +			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> > +
> >  	if (err)
> >  		err = -EINVAL;
> >
> > @@ -729,7 +746,8 @@ static struct device_type mmc_type = {
> >
> >  static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> >  {
> > -	return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> > +	return card->mmc_avail_type &
> > +		(EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_HS400);
> >  }
> >
> >  /*
> > @@ -781,7 +799,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> >  				ext_csd->raw_pwr_cl_52_360 :
> >  				ext_csd->raw_pwr_cl_ddr_52_360;
> >  		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> > -			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
> > +			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> > +				ext_csd->raw_pwr_cl_ddr_200_360 :
> > +				ext_csd->raw_pwr_cl_200_360;
> >  		break;
> >  	default:
> >  		pr_warning("%s: Voltage range not supported "
> > @@ -845,7 +865,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
> >  {
> >  	unsigned int max_dtr = (unsigned int)-1;
> >
> > -	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> > +	if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
> > +	     max_dtr > card->ext_csd.hs200_max_dtr)
> >  		max_dtr = card->ext_csd.hs200_max_dtr;
> >  	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
> >  		max_dtr = card->ext_csd.hs_max_dtr;
> > @@ -944,6 +965,28 @@ static int mmc_select_hs(struct mmc_card *card)
> >  }
> >
> >  /*
> > + * Revert to the high-speed mode from above speed
> > + */
> > +static int mmc_revert_to_hs(struct mmc_card *card)
> > +{
> > +	/*
> > +	 * CMD13, which is used to confirm the completion of timing
> > +	 * change, will be issued at higher speed timing condtion
> > +	 * rather than high-speed. If device has completed the change
> > +	 * to high-speed mode, it may not be proper timing to issue
> > +	 * command. Low speed supplies better timing margin than high
> > +	 * speed. Accordingly clock rate & timging should be chagned
> > +	 * ahead before actual switch.
> > +	 */
> > +	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> > +	mmc_set_bus_speed(card);
> > +
> > +	return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +			  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> > +			  card->ext_csd.generic_cmd6_time);
> > +}
> > +
> > +/*
> >   * Activate wide bus and DDR if supported.
> >   */
> >  static int mmc_select_hs_ddr(struct mmc_card *card)
> > @@ -999,6 +1042,56 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
> >  	return err;
> >  }
> >
> > +static int mmc_select_hs400(struct mmc_card *card)
> > +{
> > +	struct mmc_host *host = card->host;
> > +	int err = 0, ddr;
> > +
> > +	ddr = mmc_snoop_ddr(card);
> > +
> > +	/*
> > +	 * The bus width is set to only 8 DDR in HS400 mode
> > +	 */
> > +	if (!(ddr & EXT_CSD_CARD_TYPE_HS400 &&
> > +	      host->ios.bus_width == MMC_BUS_WIDTH_8))
> > +		return 0;
> > +
> > +	/*
> > +	 * Before setting BUS_WIDTH for dual data rate operation,
> > +	 * HS_TIMING must be set to High Speed(0x1)
> > +	 */
> > +	err = mmc_revert_to_hs(card);
> > +	if (err) {
> > +		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> > +			mmc_hostname(host), err);
> > +		return err;
> > +	}
> > +
> > +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +			 EXT_CSD_BUS_WIDTH,
> > +			 EXT_CSD_DDR_BUS_WIDTH_8,
> > +			 card->ext_csd.generic_cmd6_time);
> > +	if (err) {
> > +		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> > +			mmc_hostname(host), err);
> > +		return err;
> > +	}
> > +
> > +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> > +			 card->ext_csd.generic_cmd6_time);
> > +	if (err) {
> > +		pr_warn("%s: switch to hs400 failed, err:%d\n",
> > +			 mmc_hostname(host), err);
> > +		return err;
> > +	}
> > +
> > +	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> > +	mmc_set_bus_speed(card);
> > +
> > +	return 0;
> > +}
> > +
> >  /*
> >   * For device supporting HS200 mode, the following sequence
> >   * should be done before executing the tuning process.
> > @@ -1031,7 +1124,16 @@ static int mmc_select_hs200(struct mmc_card *card)
> >  				   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> >  				   card->ext_csd.generic_cmd6_time,
> >  				   true, true, true);
> > -		if (!err)
> > +		if (err)
> > +			goto err;
> > +
> > +		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> > +			/*
> > +			 * Timing should be adjusted to the HS400 target
> > +			 * operation frequency for tuning process
> > +			 */
> > +			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> > +		else
> >  			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> >  	}
> >  err:
> > @@ -1076,7 +1178,7 @@ bus_speed:
> >
> >  /*
> >   * Execute tuning sequence to seek the proper bus operating
> > - * conditions for HS200, which sends CMD21 to the device.
> > + * conditions for HS200 and HS400, which sends CMD21 to the device.
> >   */
> >  static int mmc_hs200_tuning(struct mmc_card *card)
> >  {
> > @@ -1310,6 +1412,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >  		err = mmc_hs200_tuning(card);
> >  		if (err)
> >  			goto err;
> > +
> > +		err = mmc_select_hs400(card);
> > +		if (err)
> > +			goto err;
> >  	} else if (mmc_card_hs(card)) {
> >  		/* Select the desired bus width optionally */
> >  		err = mmc_select_bus_width(card);
> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > index def6814..2b24c36 100644
> > --- a/include/linux/mmc/card.h
> > +++ b/include/linux/mmc/card.h
> > @@ -110,6 +110,7 @@ struct mmc_ext_csd {
> >  	u8			raw_pwr_cl_200_360;	/* 237 */
> >  	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
> >  	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
> > +	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
> >  	u8			raw_bkops_status;	/* 246 */
> >  	u8			raw_sectors[4];		/* 212 - 4 bytes */
> >
> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > index 1ee3c10..cc716e4 100644
> > --- a/include/linux/mmc/host.h
> > +++ b/include/linux/mmc/host.h
> > @@ -61,6 +61,8 @@ struct mmc_ios {
> >  #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_HS400_TUNING 11
> >
> >  	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
> >
> > @@ -274,6 +276,10 @@ struct mmc_host {
> >  #define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
> >  				 MMC_CAP2_PACKED_WR)
> >  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
> > +#define MMC_CAP2_HS400_1_8V	(1 << 15)	/* Can support HS400 1.8V */
> > +#define MMC_CAP2_HS400_1_2V	(1 << 16)	/* Can support HS400 1.2V */
> > +#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
> > +				 MMC_CAP2_HS400_1_2V)
> >
> >  	mmc_pm_flag_t		pm_caps;	/* supported pm features */
> >
> > @@ -486,11 +492,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
> >
> >  static inline bool mmc_card_hs200(struct mmc_card *card)
> >  {
> > -	return card->host->ios.timing == MMC_TIMING_MMC_HS200;
> > +	return card->host->ios.timing == MMC_TIMING_MMC_HS200 ||
> > +		card->host->ios.timing == MMC_TIMING_MMC_HS400_TUNING;
> >  }
> >
> >  static inline bool mmc_card_ddr52(struct mmc_card *card)
> >  {
> >  	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
> >  }
> > +
> > +static inline bool mmc_card_hs400(struct mmc_card *card)
> > +{
> > +	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
> > +}
> > +
> >  #endif /* LINUX_MMC_HOST_H */
> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> > index f429f13..64ec963 100644
> > --- a/include/linux/mmc/mmc.h
> > +++ b/include/linux/mmc/mmc.h
> > @@ -325,6 +325,7 @@ struct _mmc_csd {
> >  #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
> >  #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
> >  #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
> > +#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
> >  #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
> >  #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
> >  #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
> > @@ -354,7 +355,6 @@ struct _mmc_csd {
> >  #define EXT_CSD_CMD_SET_SECURE		(1<<1)
> >  #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
> >
> > -#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
> >  #define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
> >  #define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
> >  #define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
> > @@ -370,6 +370,10 @@ struct _mmc_csd {
> >  						/* SDR mode @1.2V I/O */
> >  #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	(1<<6)	/* Card can run at 200MHz DDR, 1.8V */
> > +#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
> >  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
> > @@ -380,6 +384,7 @@ struct _mmc_csd {
> >  #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_SEC_ER_EN	BIT(0)
> >  #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
> > --
> > 1.7.0.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* [PATCH RESEND v3 0/7] mmc: distinguish DDR timing mode for eMMC/UHS
  2014-02-15 14:08 ` [PATCH v2 0/7] mmc: distinguish DDR timing mode for eMMC/UHS Seungwon Jeon
  2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-14 12:11   ` Seungwon Jeon
  2014-04-02 11:50     ` Ulf Hansson
  1 sibling, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:11 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	rickard.andersson, linux, balajitk, g.liakhovetski, wei_wang,
	sameo, jh80.chung

These changes intend to distinguish two DDR timing modes related to eMMC & UHS.
Even though two modes are different actually, UHS_DDR50 is used as eMMC DDR mode.
MMC_TIMING_MMC_DDR52 mode is added.

Changes in V3:
 	(6/7) Added MMC-DDR52 mode instead of replacing UHS-DDR50 in dw_mmc-exynos
 
Changes in V2:
 	(2/7) Added MMC-DDR52 mode instead of replacing UHS-DDR50 in mmci
 
Seungwon Jeon (7):
  mmc: clarify DDR timing mode between SD-UHS and eMMC
  mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
  mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
  mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
  mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
  mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
  mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC

 drivers/mmc/core/debugfs.c        |    3 +++
 drivers/mmc/core/mmc.c            |    2 +-
 drivers/mmc/host/dw_mmc-exynos.c  |    5 ++---
 drivers/mmc/host/dw_mmc.c         |    2 +-
 drivers/mmc/host/mmci.c           |    6 ++++--
 drivers/mmc/host/omap_hsmmc.c     |    4 ++--
 drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
 drivers/mmc/host/sdhci.c          |    4 +++-
 drivers/mmc/host/sh_mmcif.c       |    9 +++++----
 include/linux/mmc/host.h          |    3 ++-
 10 files changed, 25 insertions(+), 15 deletions(-)> 


Thanks,
sw-j


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

* [PATCH RESEND v3 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:08 ` [PATCH v2 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC Seungwon Jeon
  2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-14 12:11   ` Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:11 UTC (permalink / raw)
  To: linux-mmc; +Cc: 'Chris Ball', 'Ulf Hansson'

This change distinguishes DDR timing mode of current
mixed usage to clarify device type.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/debugfs.c |    3 +++
 drivers/mmc/core/mmc.c     |    2 +-
 include/linux/mmc/host.h   |    3 ++-
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 54829c0..509229b 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_UHS_DDR50:
 		str = "sd uhs DDR50";
 		break;
+	case MMC_TIMING_MMC_DDR52:
+		str = "mmc DDR52";
+		break;
 	case MMC_TIMING_MMC_HS200:
 		str = "mmc high-speed SDR200";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 1ab5f3a..e22d851 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1264,7 +1264,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 					goto err;
 			}
 			mmc_card_set_ddr_mode(card);
-			mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
+			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
 			mmc_set_bus_width(card->host, bus_width);
 		}
 	}
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index cb61ea4..3535420 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -58,7 +58,8 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_SDR50	5
 #define MMC_TIMING_UHS_SDR104	6
 #define MMC_TIMING_UHS_DDR50	7
-#define MMC_TIMING_MMC_HS200	8
+#define MMC_TIMING_MMC_DDR52	8
+#define MMC_TIMING_MMC_HS200	9
 
 #define MMC_SDR_MODE		0
 #define MMC_1_2V_DDR_MODE	1
-- 
1.7.0.4



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

* [PATCH RESEND v3 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:08 ` [PATCH v2 2/7] mmc: mmci: " Seungwon Jeon
  2014-02-17 14:08   ` Ulf Hansson
  2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-14 12:12   ` Seungwon Jeon
  2 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:12 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Russell King', 'Ulf Hansson',
	'Chris Ball', 'Rickard Andersson'

Added MMC_DDR52 as eMMC's DDR mode distinguished from SD-UHS.

CC: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/mmci.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 771c60a..7e85393 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -299,7 +299,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
 	if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
 		clk |= MCI_ST_8BIT_BUS;
 
-	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
+	    host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
 		clk |= MCI_ST_UX500_NEG_EDGE;
 
 	mmci_write_clkreg(host, clk);
@@ -784,7 +785,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 			mmci_write_clkreg(host, clk);
 		}
 
-	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
+	    host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
 		datactrl |= MCI_ST_DPSM_DDRMODE;
 
 	/*
-- 
1.7.0.4



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

* [PATCH RESEND v3 3/7] mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:09 ` [PATCH v2 3/7] mmc: omap: " Seungwon Jeon
  2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-14 12:12   ` Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:12 UTC (permalink / raw)
  To: linux-mmc; +Cc: 'Chris Ball', 'Balaji T K'

Replaced UHS_DDR50 with MMC_DDR52.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Balaji T K <balajitk@ti.com>
---
 drivers/mmc/host/omap_hsmmc.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index e91ee21..b4de63b 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -582,7 +582,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
 	 *	- MMC/SD clock coming out of controller > 25MHz
 	 */
 	if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
-	    (ios->timing != MMC_TIMING_UHS_DDR50) &&
+	    (ios->timing != MMC_TIMING_MMC_DDR52) &&
 	    ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
 		regval = OMAP_HSMMC_READ(host->base, HCTL);
 		if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
@@ -602,7 +602,7 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
 	u32 con;
 
 	con = OMAP_HSMMC_READ(host->base, CON);
-	if (ios->timing == MMC_TIMING_UHS_DDR50)
+	if (ios->timing == MMC_TIMING_MMC_DDR52)
 		con |= DDR;	/* configure in DDR mode */
 	else
 		con &= ~DDR;
-- 
1.7.0.4



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

* [PATCH RESEND v3 4/7] mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:09 ` [PATCH v2 4/7] mmc: sh_mmcif: " Seungwon Jeon
  2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-14 12:12   ` Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:12 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Guennadi Liakhovetski'

Replaced UHS_DDR50 with MMC_DDR52.

CC: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/sh_mmcif.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 54730f4..656fbba 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -803,12 +803,13 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
 			break;
 		}
 		switch (host->timing) {
-		case MMC_TIMING_UHS_DDR50:
+		case MMC_TIMING_MMC_DDR52:
 			/*
 			 * MMC core will only set this timing, if the host
-			 * advertises the MMC_CAP_UHS_DDR50 capability. MMCIF
-			 * implementations with this capability, e.g. sh73a0,
-			 * will have to set it in their platform data.
+			 * advertises the MMC_CAP_1_8V_DDR/MMC_CAP_1_2V_DDR
+			 * capability. MMCIF implementations with this
+			 * capability, e.g. sh73a0, will have to set it
+			 * in their platform data.
 			 */
 			tmp |= CMD_SET_DARS;
 			break;
-- 
1.7.0.4



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

* [PATCH RESEND v3 5/7] mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:09 ` [PATCH v2 5/7] mmc: rtsx: " Seungwon Jeon
  2014-03-07 13:31   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-14 12:12   ` Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:12 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Wei WANG', 'Samuel Ortiz'

Added MMC_DDR52 as eMMC's DDR mode is distinguished from SD-UHS.

CC: Wei WANG <wei_wang@realsil.com.cn>
CC: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index 5fb994f..8c2dd30 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -1075,6 +1075,7 @@ static int sd_set_timing(struct realtek_pci_sdmmc *host, unsigned char timing)
 		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0);
 		break;
 
+	case MMC_TIMING_MMC_DDR52:
 	case MMC_TIMING_UHS_DDR50:
 		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1,
 				0x0C | SD_ASYNC_FIFO_NOT_RST,
@@ -1155,6 +1156,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		host->vpclk = true;
 		host->double_clk = false;
 		break;
+	case MMC_TIMING_MMC_DDR52:
 	case MMC_TIMING_UHS_DDR50:
 	case MMC_TIMING_UHS_SDR25:
 		host->ssc_depth = RTSX_SSC_DEPTH_1M;
-- 
1.7.0.4



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

* [PATCH RESEMD v3 6/7] mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:09 ` [PATCH v2 6/7] mmc: dw_mmc: " Seungwon Jeon
  2014-03-07 13:31   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-14 12:12   ` Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:12 UTC (permalink / raw)
  To: linux-mmc; +Cc: 'Chris Ball', 'Jaehoon Chung'

Replaced UHS_DDR50 with MMC_DDR52. And MMC_CAP_UHS_DDR50
is removed because of non-implementation of UHS signaling.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/host/dw_mmc-exynos.c |    5 ++---
 drivers/mmc/host/dw_mmc.c        |    2 +-
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 3423c5e..a67e784 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -187,7 +187,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
 	unsigned long actual;
 	u8 div = priv->ciu_div + 1;
 
-	if (ios->timing == MMC_TIMING_UHS_DDR50) {
+	if (ios->timing == MMC_TIMING_MMC_DDR52) {
 		mci_writel(host, CLKSEL, priv->ddr_timing);
 		/* Should be double rate for DDR mode */
 		if (ios->bus_width == MMC_BUS_WIDTH_8)
@@ -386,8 +386,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
 
 /* Common capabilities of Exynos4/Exynos5 SoC */
 static unsigned long exynos_dwmmc_caps[4] = {
-	MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
-		MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
+	MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
 	MMC_CAP_CMD23,
 	MMC_CAP_CMD23,
 	MMC_CAP_CMD23,
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 0c56faa..ab704d9 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -962,7 +962,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	regs = mci_readl(slot->host, UHS_REG);
 
 	/* DDR mode set */
-	if (ios->timing == MMC_TIMING_UHS_DDR50)
+	if (ios->timing == MMC_TIMING_MMC_DDR52)
 		regs |= ((0x1 << slot->id) << 16);
 	else
 		regs &= ~((0x1 << slot->id) << 16);
-- 
1.7.0.4



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

* [PATCH RESEND v3 7/7] mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC
  2014-02-15 14:09 ` [PATCH v2 7/7] mmc: sdhci: " Seungwon Jeon
  2014-03-07 13:31   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-14 12:12   ` Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:12 UTC (permalink / raw)
  To: linux-mmc; +Cc: 'Chris Ball', 'Ulf Hansson'

Added MMC_DDR52 as eMMC's DDR mode is distinguished from SD-UHS.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/sdhci.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 7f95211..6926b42 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1510,6 +1510,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 
 		/* In case of UHS-I modes, set High Speed Enable */
 		if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+		    (ios->timing == MMC_TIMING_MMC_DDR52) ||
 		    (ios->timing == MMC_TIMING_UHS_SDR50) ||
 		    (ios->timing == MMC_TIMING_UHS_SDR104) ||
 		    (ios->timing == MMC_TIMING_UHS_DDR50) ||
@@ -1570,7 +1571,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 				ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
 			else if (ios->timing == MMC_TIMING_UHS_SDR50)
 				ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
-			else if (ios->timing == MMC_TIMING_UHS_DDR50)
+			else if ((ios->timing == MMC_TIMING_UHS_DDR50) ||
+				 (ios->timing == MMC_TIMING_MMC_DDR52))
 				ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
 			sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
 		}
-- 
1.7.0.4



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

* [PATCH v3 0/5]  update selection of bus speed mode for eMMC
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
  2014-03-07 14:35   ` [PATCH v2 " Seungwon Jeon
  2014-03-13  9:52   ` [PATCH RESEND " Jaehoon Chung
@ 2014-03-14 12:16   ` Seungwon Jeon
  2014-03-17  8:47     ` Ulf Hansson
  2014-03-26 10:59   ` [PATCH v4 " Seungwon Jeon
                     ` (25 subsequent siblings)
  28 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:16 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

This series contains the change for selection of bus speed mode.
Previous implementation is complicated and some sequence is duplicated.
And specially, HS400 mode eMMC5.0 is introduced this time.
This patch-set has been tested in Exynos SoC.

Changes in v3:
	Removed the function to check DDR type(mmc_snoop_ddr).
	Rebased with the latest branch.

Seungwon Jeon (5):
  mmc: drop the speed mode of card's state
  mmc: identify available device type to select
  mmc: step power class after final selection of bus mode
  mmc: rework selection of bus speed mode
  mmc: add support for HS400 mode of eMMC5.0

 drivers/mmc/core/bus.c     |    9 +-
 drivers/mmc/core/core.c    |    3 +-
 drivers/mmc/core/debugfs.c |    5 +-
 drivers/mmc/core/mmc.c     |  681 +++++++++++++++++++++++++++-----------------
 drivers/mmc/core/sd.c      |   16 +-
 drivers/mmc/core/sd.h      |    1 -
 drivers/mmc/core/sdio.c    |    8 +-
 include/linux/mmc/card.h   |   31 +--
 include/linux/mmc/host.h   |   42 +++-
 include/linux/mmc/mmc.h    |   23 ++-
 10 files changed, 497 insertions(+), 322 deletions(-)

Thanks,
Sw-j


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

* [PATCH v3 1/5] mmc: drop the speed mode of card's state
  2014-02-15 14:18 ` [PATCH RESEND 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
  2014-02-17 14:38   ` Ulf Hansson
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
@ 2014-03-14 12:16   ` Seungwon Jeon
  2 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:16 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Timing mode identifier has same role and can take the place
of speed mode. This change removes all related speed mode.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/bus.c   |    8 ++++----
 drivers/mmc/core/core.c  |    3 +--
 drivers/mmc/core/mmc.c   |   11 +++--------
 drivers/mmc/core/sd.c    |   16 +++-------------
 drivers/mmc/core/sd.h    |    1 -
 drivers/mmc/core/sdio.c  |    8 ++------
 include/linux/mmc/card.h |   23 ++++++-----------------
 include/linux/mmc/host.h |   23 +++++++++++++++++++++++
 8 files changed, 42 insertions(+), 51 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 8246448..f37e9d6 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -341,16 +341,16 @@ int mmc_add_card(struct mmc_card *card)
 	if (mmc_host_is_spi(card->host)) {
 		pr_info("%s: new %s%s%s card on SPI\n",
 			mmc_hostname(card->host),
-			mmc_card_highspeed(card) ? "high speed " : "",
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_hs(card) ? "high speed " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			type);
 	} else {
 		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
-			(mmc_card_highspeed(card) ? "high speed " : ""),
+			(mmc_card_hs(card) ? "high speed " : ""),
 			(mmc_card_hs200(card) ? "HS200 " : ""),
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
 	}
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index dc7a5fb..5967889 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2182,7 +2182,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
 	struct mmc_command cmd = {0};
 
-	if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+	if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
 		return 0;
 
 	cmd.opcode = MMC_SET_BLOCKLEN;
@@ -2262,7 +2262,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
 		}
 	}
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
 	if (mmc_host_is_spi(host)) {
 		host->ios.chip_select = MMC_CS_HIGH;
 		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e22d851..db9655f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1091,11 +1091,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		} else {
 			if (card->ext_csd.hs_max_dtr > 52000000 &&
 			    host->caps2 & MMC_CAP2_HS200) {
-				mmc_card_set_hs200(card);
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
 			} else {
-				mmc_card_set_highspeed(card);
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
 			}
 		}
@@ -1106,10 +1104,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
+	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
 		if (max_dtr > card->ext_csd.hs_max_dtr)
 			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_highspeed(card) && (max_dtr > 52000000))
+		if (mmc_card_hs(card) && (max_dtr > 52000000))
 			max_dtr = 52000000;
 	} else if (max_dtr > card->csd.max_dtr) {
 		max_dtr = card->csd.max_dtr;
@@ -1120,7 +1118,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
 			&& (host->caps & MMC_CAP_1_8V_DDR))
 				ddr = MMC_1_8V_DDR_MODE;
@@ -1263,7 +1261,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 				if (err)
 					goto err;
 			}
-			mmc_card_set_ddr_mode(card);
 			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
 			mmc_set_bus_width(card->host, bus_width);
 		}
@@ -1507,7 +1504,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 		err = mmc_sleep(host);
 	else if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 
 	if (!err) {
 		mmc_power_off(host);
@@ -1637,7 +1633,6 @@ static int mmc_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 	mmc_claim_host(host);
 	ret = mmc_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 2dd359d..9fc5b31 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -895,7 +895,7 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if (max_dtr > card->sw_caps.hs_max_dtr)
 			max_dtr = card->sw_caps.hs_max_dtr;
 	} else if (max_dtr > card->csd.max_dtr) {
@@ -905,12 +905,6 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 	return max_dtr;
 }
 
-void mmc_sd_go_highspeed(struct mmc_card *card)
-{
-	mmc_card_set_highspeed(card);
-	mmc_set_timing(card->host, MMC_TIMING_SD_HS);
-}
-
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -985,16 +979,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_sd_init_uhs_card(card);
 		if (err)
 			goto free_card;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Attempt to change to high-speed (if supported)
 		 */
 		err = mmc_sd_switch_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto free_card;
 
@@ -1089,7 +1080,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
 
 	if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
+
 	if (!err) {
 		mmc_power_off(host);
 		mmc_card_set_suspended(host->card);
@@ -1198,7 +1189,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
 	ret = mmc_sd_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
index 4b34b24..aab824a 100644
--- a/drivers/mmc/core/sd.h
+++ b/drivers/mmc/core/sd.h
@@ -12,6 +12,5 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 	bool reinit);
 unsigned mmc_sd_get_max_clock(struct mmc_card *card);
 int mmc_sd_switch_hs(struct mmc_card *card);
-void mmc_sd_go_highspeed(struct mmc_card *card);
 
 #endif
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4d721c6..ef57d2d 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		/*
 		 * The SDIO specification doesn't mention how
 		 * the CIS transfer speed register relates to
@@ -733,7 +733,6 @@ try_again:
 		mmc_set_clock(host, card->cis.max_dtr);
 
 		if (card->cccr.high_speed) {
-			mmc_card_set_highspeed(card);
 			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		}
 
@@ -792,16 +791,13 @@ try_again:
 		err = mmc_sdio_init_uhs_card(card);
 		if (err)
 			goto remove;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Switch to high-speed (if supported).
 		 */
 		err = sdio_enable_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto remove;
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index b730272..5473133 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -194,6 +194,7 @@ struct sdio_cis {
 };
 
 struct mmc_host;
+struct mmc_ios;
 struct sdio_func;
 struct sdio_func_tuple;
 
@@ -250,15 +251,11 @@ struct mmc_card {
 	unsigned int		state;		/* (our) card state */
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
 #define MMC_STATE_READONLY	(1<<1)		/* card is read-only */
-#define MMC_STATE_HIGHSPEED	(1<<2)		/* card is in high speed mode */
-#define MMC_STATE_BLOCKADDR	(1<<3)		/* card uses block-addressing */
-#define MMC_STATE_HIGHSPEED_DDR (1<<4)		/* card is in high speed mode */
-#define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra high speed mode */
-#define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
-#define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
-#define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
-#define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
-#define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
+#define MMC_STATE_BLOCKADDR	(1<<2)		/* card uses block-addressing */
+#define MMC_CARD_SDXC		(1<<3)		/* card is SDXC */
+#define MMC_CARD_REMOVED	(1<<4)		/* card has been removed */
+#define MMC_STATE_DOING_BKOPS	(1<<5)		/* card is doing BKOPS */
+#define MMC_STATE_SUSPENDED	(1<<6)		/* card is suspended */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -418,11 +415,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
-#define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
-#define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
-#define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
@@ -430,11 +423,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
-#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
-#define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
-#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_doing_bkops(c)	((c)->state |= MMC_STATE_DOING_BKOPS)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 3535420..2f263ae 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -17,6 +17,7 @@
 #include <linux/fault-inject.h>
 
 #include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -476,4 +477,26 @@ static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
 	return host->ios.clock;
 }
 #endif
+
+static inline int mmc_card_hs(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_SD_HS ||
+		card->host->ios.timing == MMC_TIMING_MMC_HS;
+}
+
+static inline int mmc_card_uhs(struct mmc_card *card)
+{
+	return card->host->ios.timing >= MMC_TIMING_UHS_SDR12 &&
+		card->host->ios.timing <= MMC_TIMING_UHS_DDR50;
+}
+
+static inline bool mmc_card_hs200(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_HS200;
+}
+
+static inline bool mmc_card_ddr52(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
+}
 #endif /* LINUX_MMC_HOST_H */
-- 
1.7.0.4



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

* [PATCH v3 2/5] mmc: identify available device type to select
  2014-02-15 14:18 ` [PATCH RESEND 2/5] mmc: identify available device type to select Seungwon Jeon
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
@ 2014-03-14 12:16   ` Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:16 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Device types which are supported by both host and device
can be identified when EXT_CSD is read. There is no need to
check host's capability anymore.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/mmc.c   |   72 +++++++++++++++++++++++++---------------------
 include/linux/mmc/card.h |    6 ++-
 include/linux/mmc/host.h |    6 ----
 include/linux/mmc/mmc.h  |   12 +++++--
 4 files changed, 51 insertions(+), 45 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index db9655f..97f1912 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0;
+	unsigned int avail_type = 0;
 
-	if (card_type & EXT_CSD_CARD_TYPE_26)
+	if (caps & MMC_CAP_MMC_HIGHSPEED &&
+	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
 		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
+	}
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
-			card_type & EXT_CSD_CARD_TYPE_52)
+	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
 		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
+	}
 
-	if ((caps & MMC_CAP_1_8V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
-	    (caps & MMC_CAP_1_2V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
+	if (caps & MMC_CAP_1_8V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
 		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
+	}
+
+	if (caps & MMC_CAP_1_2V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
+	}
 
-	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
-	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
+	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
 		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
+		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
+	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
-	card->ext_csd.card_type = card_type;
+	card->mmc_avail_type = avail_type;
 }
 
 /*
@@ -808,12 +826,10 @@ static int mmc_select_hs200(struct mmc_card *card)
 
 	host = card->host;
 
-	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
-			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
 
-	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
-			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
 
 	/* If fails try again during next card power cycle */
@@ -1072,10 +1088,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	if (card->ext_csd.hs_max_dtr != 0) {
 		err = 0;
-		if (card->ext_csd.hs_max_dtr > 52000000 &&
-		    host->caps2 & MMC_CAP2_HS200)
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 			err = mmc_select_hs200(card);
-		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
+		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
 			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					EXT_CSD_HS_TIMING, 1,
 					card->ext_csd.generic_cmd6_time,
@@ -1089,13 +1104,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			       mmc_hostname(card->host));
 			err = 0;
 		} else {
-			if (card->ext_csd.hs_max_dtr > 52000000 &&
-			    host->caps2 & MMC_CAP2_HS200) {
+			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
-			} else {
+			else
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-			}
 		}
 	}
 
@@ -1118,14 +1131,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_hs(card)) {
-		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-			&& (host->caps & MMC_CAP_1_8V_DDR))
-				ddr = MMC_1_8V_DDR_MODE;
-		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-			&& (host->caps & MMC_CAP_1_2V_DDR))
-				ddr = MMC_1_2V_DDR_MODE;
-	}
+	if (mmc_card_hs(card))
+		ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
 
 	/*
 	 * Indicate HS200 SDR mode (if supported).
@@ -1145,8 +1152,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		 * 3. set the clock to > 52Mhz <=200MHz and
 		 * 4. execute tuning for HS200
 		 */
-		if ((host->caps2 & MMC_CAP2_HS200) &&
-		    card->host->ops->execute_tuning) {
+		if (card->host->ops->execute_tuning) {
 			mmc_host_clk_hold(card->host);
 			err = card->host->ops->execute_tuning(card->host,
 				MMC_SEND_TUNING_BLOCK_HS200);
@@ -1255,7 +1261,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			 *
 			 * WARNING: eMMC rules are NOT the same as SD DDR
 			 */
-			if (ddr == MMC_1_2V_DDR_MODE) {
+			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
 				err = __mmc_set_signal_voltage(host,
 					MMC_SIGNAL_VOLTAGE_120);
 				if (err)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 5473133..c232b10 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -68,7 +68,6 @@ struct mmc_ext_csd {
 #define MMC_HIGH_DDR_MAX_DTR	52000000
 #define MMC_HS200_MAX_DTR	200000000
 	unsigned int		sectors;
-	unsigned int		card_type;
 	unsigned int		hc_erase_size;		/* In sectors */
 	unsigned int		hc_erase_timeout;	/* In milliseconds */
 	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
@@ -297,7 +296,10 @@ struct mmc_card {
 	const char		**info;		/* info strings */
 	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
 
-	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+	union {
+		unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+		unsigned int		mmc_avail_type;	/* supported device type by both host and card */
+	};
 
 	struct dentry		*debugfs_root;
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 2f263ae..1ee3c10 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -62,12 +62,6 @@ struct mmc_ios {
 #define MMC_TIMING_MMC_DDR52	8
 #define MMC_TIMING_MMC_HS200	9
 
-#define MMC_SDR_MODE		0
-#define MMC_1_2V_DDR_MODE	1
-#define MMC_1_8V_DDR_MODE	2
-#define MMC_1_2V_SDR_MODE	3
-#define MMC_1_8V_SDR_MODE	4
-
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
 #define MMC_SIGNAL_VOLTAGE_330	0
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 50bcde3..f734c0c 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -354,18 +354,22 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#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_MASK	0x3F	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
+				 EXT_CSD_CARD_TYPE_HS_52)
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
 					     /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
 					     /* DDR mode @1.2V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
 					| EXT_CSD_CARD_TYPE_DDR_1_2V)
-#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
-#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_8V	(1<<4)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_2V	(1<<5)	/* Card can run at 200MHz */
 						/* SDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS200_1_2V)
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
-- 
1.7.0.4



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

* [PATCH v3 3/5] mmc: step power class after final selection of bus mode
  2014-02-15 14:23 ` [PATCH RESEND 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
@ 2014-03-14 12:16   ` Seungwon Jeon
  1 sibling, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:16 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Power class is changed once only after selection of bus modes
including speed and bus-width finishes finally.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/mmc.c |   96 +++++++++++++++++++++++++++--------------------
 1 files changed, 55 insertions(+), 41 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 97f1912..480c100 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -732,17 +732,13 @@ static struct device_type mmc_type = {
  * extended CSD register, select it by executing the
  * mmc_switch command.
  */
-static int mmc_select_powerclass(struct mmc_card *card,
-		unsigned int bus_width)
+static int __mmc_select_powerclass(struct mmc_card *card,
+				   unsigned int bus_width)
 {
-	int err = 0;
+	struct mmc_host *host = card->host;
+	struct mmc_ext_csd *ext_csd = &card->ext_csd;
 	unsigned int pwrclass_val = 0;
-	struct mmc_host *host;
-
-	BUG_ON(!card);
-
-	host = card->host;
-	BUG_ON(!host);
+	int err = 0;
 
 	/* Power class selection is supported for versions >= 4.0 */
 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
@@ -754,14 +750,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
 
 	switch (1 << host->ios.vdd) {
 	case MMC_VDD_165_195:
-		if (host->ios.clock <= 26000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
-		else if	(host->ios.clock <= 52000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_26_195;
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-				card->ext_csd.raw_pwr_cl_52_195 :
-				card->ext_csd.raw_pwr_cl_ddr_52_195;
-		else if (host->ios.clock <= 200000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
+				ext_csd->raw_pwr_cl_52_195 :
+				ext_csd->raw_pwr_cl_ddr_52_195;
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_200_195;
 		break;
 	case MMC_VDD_27_28:
 	case MMC_VDD_28_29:
@@ -772,14 +768,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	case MMC_VDD_33_34:
 	case MMC_VDD_34_35:
 	case MMC_VDD_35_36:
-		if (host->ios.clock <= 26000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
-		else if	(host->ios.clock <= 52000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_26_360;
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-				card->ext_csd.raw_pwr_cl_52_360 :
-				card->ext_csd.raw_pwr_cl_ddr_52_360;
-		else if (host->ios.clock <= 200000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
+				ext_csd->raw_pwr_cl_52_360 :
+				ext_csd->raw_pwr_cl_ddr_52_360;
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -805,6 +801,37 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	return err;
 }
 
+static int mmc_select_powerclass(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	u32 bus_width, ext_csd_bits;
+	int err, ddr;
+
+	/* Power class selection is supported for versions >= 4.0 */
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	/* Power class values are defined only for 4/8 bit bus */
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	if (ddr)
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+	else
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
+
+	err = __mmc_select_powerclass(card, ext_csd_bits);
+	if (err)
+		pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
+			mmc_hostname(host), 1 << bus_width, ddr);
+
+	return err;
+}
+
 /*
  * Selects the desired buswidth and switch to the HS200 mode
  * if bus width set without error
@@ -1166,11 +1193,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
 		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
 				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-		err = mmc_select_powerclass(card, ext_csd_bits);
-		if (err)
-			pr_warning("%s: power class selection to bus width %d"
-				   " failed\n", mmc_hostname(card->host),
-				   1 << bus_width);
 	}
 
 	/*
@@ -1199,12 +1221,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			bus_width = bus_widths[idx];
 			if (bus_width == MMC_BUS_WIDTH_1)
 				ddr = 0; /* no DDR for 1-bit width */
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width);
 
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
@@ -1229,13 +1245,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		}
 
 		if (!err && ddr) {
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d ddr %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width, ddr);
-
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][1],
@@ -1273,6 +1282,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
+	 * Choose the power class with selected bus interface
+	 */
+	mmc_select_powerclass(card);
+
+	/*
 	 * Enable HPI feature (if supported)
 	 */
 	if (card->ext_csd.hpi) {
-- 
1.7.0.4



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

* [PATCH v3 4/5] mmc: rework selection of bus speed mode
  2014-02-15 14:24 ` [PATCH RESEND 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
@ 2014-03-14 12:16   ` Seungwon Jeon
  2014-03-21 13:01     ` Ulf Hansson
  1 sibling, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:16 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Current implementation for bus speed mode selection is too
complicated. This patch is to simplify the codes and remove
some duplicate parts.

The following changes are including:
* Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
* Rearranged the mode selection sequence with supported device type
* Adds maximum speed for HS200 mode(hs200_max_dtr)
* Adds field definition for HS_TIMING of EXT_CSD

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/debugfs.c |    2 +-
 drivers/mmc/core/mmc.c     |  431 ++++++++++++++++++++++++--------------------
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/mmc.h    |    4 +
 4 files changed, 238 insertions(+), 200 deletions(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 509229b..1f730db 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -139,7 +139,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 		str = "mmc DDR52";
 		break;
 	case MMC_TIMING_MMC_HS200:
-		str = "mmc high-speed SDR200";
+		str = "mmc HS200";
 		break;
 	default:
 		str = "invalid";
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 480c100..6dd68e6 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -242,7 +242,7 @@ static void mmc_select_card_type(struct mmc_card *card)
 	struct mmc_host *host = card->host;
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
-	unsigned int hs_max_dtr = 0;
+	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
@@ -271,17 +271,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 
 	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
 	}
 
 	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
+	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
 }
 
@@ -833,37 +834,46 @@ static int mmc_select_powerclass(struct mmc_card *card)
 }
 
 /*
- * Selects the desired buswidth and switch to the HS200 mode
- * if bus width set without error
+ * Set the bus speed for the selected speed mode.
  */
-static int mmc_select_hs200(struct mmc_card *card)
+static void mmc_set_bus_speed(struct mmc_card *card)
+{
+	unsigned int max_dtr = (unsigned int)-1;
+
+	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+		max_dtr = card->ext_csd.hs200_max_dtr;
+	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
+		max_dtr = card->ext_csd.hs_max_dtr;
+	else if (max_dtr > card->csd.max_dtr)
+		max_dtr = card->csd.max_dtr;
+
+	mmc_set_clock(card->host, max_dtr);
+}
+
+/*
+ * Select the bus width amoung 4-bit and 8-bit(SDR).
+ * If the bus width is changed successfully, return the slected width value.
+ * Zero is returned instead of error value if the wide width is not supported.
+ */
+static int mmc_select_bus_width(struct mmc_card *card)
 {
-	int idx, err = -EINVAL;
-	struct mmc_host *host;
 	static unsigned ext_csd_bits[] = {
-		EXT_CSD_BUS_WIDTH_4,
 		EXT_CSD_BUS_WIDTH_8,
+		EXT_CSD_BUS_WIDTH_4,
 	};
 	static unsigned bus_widths[] = {
-		MMC_BUS_WIDTH_4,
 		MMC_BUS_WIDTH_8,
+		MMC_BUS_WIDTH_4,
 	};
+	struct mmc_host *host = card->host;
+	unsigned idx, bus_width = 0;
+	int err = 0;
 
-	BUG_ON(!card);
-
-	host = card->host;
-
-	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
-
-	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
-
-	/* If fails try again during next card power cycle */
-	if (err)
-		goto err;
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
+	    !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
+		return 0;
 
-	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
 
 	/*
 	 * Unlike SD, MMC cards dont have a configuration register to notify
@@ -871,8 +881,7 @@ static int mmc_select_hs200(struct mmc_card *card)
 	 * 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 >= 0; idx--) {
-
+	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
@@ -887,27 +896,202 @@ static int mmc_select_hs200(struct mmc_card *card)
 		if (err)
 			continue;
 
-		mmc_set_bus_width(card->host, bus_widths[idx]);
+		bus_width = bus_widths[idx];
+		mmc_set_bus_width(host, bus_width);
 
+		/*
+		 * If controller can't handle bus width test,
+		 * compare ext_csd previously read in 1 bit mode
+		 * against ext_csd at new bus width
+		 */
 		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-			err = mmc_compare_ext_csds(card, bus_widths[idx]);
+			err = mmc_compare_ext_csds(card, bus_width);
 		else
-			err = mmc_bus_test(card, bus_widths[idx]);
-		if (!err)
+			err = mmc_bus_test(card, bus_width);
+
+		if (!err) {
+			err = bus_width;
 			break;
+		} else {
+			pr_warn("%s: switch to bus width %d failed\n",
+				mmc_hostname(host), ext_csd_bits[idx]);
+		}
 	}
 
-	/* switch to HS200 mode if bus width set successfully */
+	return err;
+}
+
+/*
+ * Switch to the high-speed mode
+ */
+static int mmc_select_hs(struct mmc_card *card)
+{
+	int err;
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
 	if (!err)
+		mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+
+	return err;
+}
+
+/*
+ * Activate wide bus and DDR if supported.
+ */
+static int mmc_select_hs_ddr(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	u32 bus_width, ext_csd_bits;
+	int err = 0;
+
+	if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52))
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+		EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_BUS_WIDTH,
+			ext_csd_bits,
+			card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width %d ddr failed\n",
+			mmc_hostname(host), 1 << bus_width);
+		return err;
+	}
+
+	/*
+	 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+	 * signaling.
+	 *
+	 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+	 *
+	 * 1.8V vccq at 3.3V core voltage (vcc) is not required
+	 * in the JEDEC spec for DDR.
+	 *
+	 * Do not force change in vccq since we are obviously
+	 * working and no change to vccq is needed.
+	 *
+	 * WARNING: eMMC rules are NOT the same as SD DDR
+	 */
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		err = __mmc_set_signal_voltage(host,
+				MMC_SIGNAL_VOLTAGE_120);
+		if (err)
+			return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
+
+	return err;
+}
+
+/*
+ * For device supporting HS200 mode, the following sequence
+ * should be done before executing the tuning process.
+ * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
+ * 2. switch to HS200 mode
+ * 3. set the clock to > 52Mhz and <=200MHz
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = -EINVAL;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+
+	/* If fails try again during next card power cycle */
+	if (err)
+		goto err;
+
+	/*
+	 * Set the bus width(4 or 8) with host's support and
+	 * switch to HS200 mode if bus width is set successfully.
+	 */
+	err = mmc_select_bus_width(card);
+	if (!IS_ERR_VALUE(err)) {
 		err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				EXT_CSD_HS_TIMING, 2,
-				card->ext_csd.generic_cmd6_time,
-				true, true, true);
+				   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
+				   card->ext_csd.generic_cmd6_time,
+				   true, true, true);
+		if (!err)
+			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+	}
 err:
 	return err;
 }
 
 /*
+ * Activate High Speed or HS200 mode if supported.
+ */
+static int mmc_select_timing(struct mmc_card *card)
+{
+	int err = 0;
+
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
+	     card->ext_csd.hs_max_dtr == 0))
+		goto bus_speed;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+		err = mmc_select_hs200(card);
+	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
+		err = mmc_select_hs(card);
+
+	if (err && err != -EBADMSG)
+		return err;
+
+	if (err) {
+		pr_warn("%s: switch to %s failed\n",
+			mmc_card_hs(card) ? "high-speed" :
+			(mmc_card_hs200(card) ? "hs200" : ""),
+			mmc_hostname(card->host));
+		err = 0;
+	}
+
+bus_speed:
+	/*
+	 * Set the bus speed to the selected bus timing.
+	 * If timing is not selected, backward compatible is the default.
+	 */
+	mmc_set_bus_speed(card);
+	return err;
+}
+
+/*
+ * Execute tuning sequence to seek the proper bus operating
+ * conditions for HS200, which sends CMD21 to the device.
+ */
+static int mmc_hs200_tuning(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	if (host->ops->execute_tuning) {
+		mmc_host_clk_hold(host);
+		err = host->ops->execute_tuning(host,
+				MMC_SEND_TUNING_BLOCK_HS200);
+		mmc_host_clk_release(host);
+
+		if (err)
+			pr_warn("%s: tuning execution failed\n",
+				mmc_hostname(host));
+	}
+
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -917,9 +1101,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	struct mmc_card *oldcard)
 {
 	struct mmc_card *card;
-	int err, ddr = 0;
+	int err;
 	u32 cid[4];
-	unsigned int max_dtr;
 	u32 rocr;
 	u8 *ext_csd = NULL;
 
@@ -1111,173 +1294,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
-	 * Activate high speed (if supported)
-	 */
-	if (card->ext_csd.hs_max_dtr != 0) {
-		err = 0;
-		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-			err = mmc_select_hs200(card);
-		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
-			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					EXT_CSD_HS_TIMING, 1,
-					card->ext_csd.generic_cmd6_time,
-					true, true, true);
-
-		if (err && err != -EBADMSG)
-			goto free_card;
-
-		if (err) {
-			pr_warning("%s: switch to highspeed failed\n",
-			       mmc_hostname(card->host));
-			err = 0;
-		} else {
-			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-				mmc_set_timing(card->host,
-					       MMC_TIMING_MMC_HS200);
-			else
-				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-		}
-	}
-
-	/*
-	 * Compute bus speed.
-	 */
-	max_dtr = (unsigned int)-1;
-
-	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
-		if (max_dtr > card->ext_csd.hs_max_dtr)
-			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_hs(card) && (max_dtr > 52000000))
-			max_dtr = 52000000;
-	} else if (max_dtr > card->csd.max_dtr) {
-		max_dtr = card->csd.max_dtr;
-	}
-
-	mmc_set_clock(host, max_dtr);
-
-	/*
-	 * Indicate DDR mode (if supported).
+	 * Select timing interface
 	 */
-	if (mmc_card_hs(card))
-		ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	err = mmc_select_timing(card);
+	if (err)
+		goto free_card;
 
-	/*
-	 * Indicate HS200 SDR mode (if supported).
-	 */
 	if (mmc_card_hs200(card)) {
-		u32 ext_csd_bits;
-		u32 bus_width = card->host->ios.bus_width;
-
-		/*
-		 * For devices supporting HS200 mode, the bus width has
-		 * to be set before executing the tuning function. If
-		 * set before tuning, then device will respond with CRC
-		 * errors for responses on CMD line. So for HS200 the
-		 * sequence will be
-		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
-		 * 2. switch to HS200 mode
-		 * 3. set the clock to > 52Mhz <=200MHz and
-		 * 4. execute tuning for HS200
-		 */
-		if (card->host->ops->execute_tuning) {
-			mmc_host_clk_hold(card->host);
-			err = card->host->ops->execute_tuning(card->host,
-				MMC_SEND_TUNING_BLOCK_HS200);
-			mmc_host_clk_release(card->host);
-		}
-		if (err) {
-			pr_warning("%s: tuning execution failed\n",
-				   mmc_hostname(card->host));
+		err = mmc_hs200_tuning(card);
+		if (err)
 			goto err;
-		}
-
-		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
-				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-	}
-
-	/*
-	 * Activate wide bus and DDR (if supported).
-	 */
-	if (!mmc_card_hs200(card) &&
-	    (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
-	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
-		static unsigned ext_csd_bits[][2] = {
-			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
-			{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
-			{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
-		};
-		static unsigned bus_widths[] = {
-			MMC_BUS_WIDTH_8,
-			MMC_BUS_WIDTH_4,
-			MMC_BUS_WIDTH_1
-		};
-		unsigned idx, bus_width = 0;
-
-		if (host->caps & MMC_CAP_8_BIT_DATA)
-			idx = 0;
-		else
-			idx = 1;
-		for (; idx < ARRAY_SIZE(bus_widths); idx++) {
-			bus_width = bus_widths[idx];
-			if (bus_width == MMC_BUS_WIDTH_1)
-				ddr = 0; /* no DDR for 1-bit width */
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][0],
-					 card->ext_csd.generic_cmd6_time);
-			if (!err) {
-				mmc_set_bus_width(card->host, bus_width);
-
-				/*
-				 * If controller can't handle bus width test,
-				 * compare ext_csd previously read in 1 bit mode
-				 * against ext_csd at new bus width
-				 */
-				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					err = mmc_compare_ext_csds(card,
-						bus_width);
-				else
-					err = mmc_bus_test(card, bus_width);
-				if (!err)
-					break;
-			}
-		}
-
-		if (!err && ddr) {
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][1],
-					 card->ext_csd.generic_cmd6_time);
-		}
-		if (err) {
-			pr_warning("%s: switch to bus width %d ddr %d "
-				"failed\n", mmc_hostname(card->host),
-				1 << bus_width, ddr);
-			goto free_card;
-		} else if (ddr) {
-			/*
-			 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
-			 * signaling.
-			 *
-			 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
-			 *
-			 * 1.8V vccq at 3.3V core voltage (vcc) is not required
-			 * in the JEDEC spec for DDR.
-			 *
-			 * Do not force change in vccq since we are obviously
-			 * working and no change to vccq is needed.
-			 *
-			 * WARNING: eMMC rules are NOT the same as SD DDR
-			 */
-			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
-				err = __mmc_set_signal_voltage(host,
-					MMC_SIGNAL_VOLTAGE_120);
-				if (err)
-					goto err;
-			}
-			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
-			mmc_set_bus_width(card->host, bus_width);
+	} else if (mmc_card_hs(card)) {
+		/* Select the desired bus width optionally */
+		err = mmc_select_bus_width(card);
+		if (!IS_ERR_VALUE(err)) {
+			err = mmc_select_hs_ddr(card);
+			if (err)
+				goto err;
 		}
 	}
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c232b10..def6814 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -63,6 +63,7 @@ struct mmc_ext_csd {
 	unsigned int            power_off_longtime;     /* Units: ms */
 	u8			power_off_notification;	/* state */
 	unsigned int		hs_max_dtr;
+	unsigned int		hs200_max_dtr;
 #define MMC_HIGH_26_MAX_DTR	26000000
 #define MMC_HIGH_52_MAX_DTR	52000000
 #define MMC_HIGH_DDR_MAX_DTR	52000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f734c0c..f429f13 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -377,6 +377,10 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
 #define EXT_CSD_SEC_GB_CL_EN	BIT(4)
-- 
1.7.0.4



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

* [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-02-15 14:24 ` [PATCH RESEND 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
  2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
@ 2014-03-14 12:16   ` Seungwon Jeon
  2014-03-24 15:41     ` Ulf Hansson
  1 sibling, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-14 12:16 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

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: Seungwon Jeon <tgih.jun@samsung.com>
Reviewed-by: Jackey Shen <jackey.shen@amd.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/bus.c     |    1 +
 drivers/mmc/core/debugfs.c |    3 +
 drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/host.h   |   15 +++++-
 include/linux/mmc/mmc.h    |    7 ++-
 6 files changed, 134 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index f37e9d6..d2dbf02 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_hs(card) ? "high speed " : ""),
+			mmc_card_hs400(card) ? "HS400 " :
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 1f730db..91eb162 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_MMC_HS200:
 		str = "mmc HS200";
 		break;
+	case MMC_TIMING_MMC_HS400:
+		str = "mmc HS400";
+		break;
 	default:
 		str = "invalid";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 6dd68e6..969d595 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 static void mmc_select_card_type(struct mmc_card *card)
 {
 	struct mmc_host *host = card->host;
-	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
+	u8 card_type = card->ext_csd.raw_card_type;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
@@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
+	if (caps2 & MMC_CAP2_HS400_1_8V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS400_1_2V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
+	}
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
@@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
 		card->ext_csd.raw_pwr_cl_ddr_52_360 =
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
+		card->ext_csd.raw_pwr_cl_ddr_200_360 =
+			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
 	}
 
 	if (card->ext_csd.rev >= 5) {
@@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
 		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
 			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
 		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
-			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
+		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
+
 	if (err)
 		err = -EINVAL;
 
@@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
 				ext_csd->raw_pwr_cl_52_360 :
 				ext_csd->raw_pwr_cl_ddr_52_360;
 		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
-			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
+			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
+				ext_csd->raw_pwr_cl_ddr_200_360 :
+				ext_csd->raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
 {
 	unsigned int max_dtr = (unsigned int)-1;
 
-	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+	if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
+	     max_dtr > card->ext_csd.hs200_max_dtr)
 		max_dtr = card->ext_csd.hs200_max_dtr;
 	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
 		max_dtr = card->ext_csd.hs_max_dtr;
@@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
 }
 
 /*
+ * Revert to the high-speed mode from above speed
+ */
+static int mmc_revert_to_hs(struct mmc_card *card)
+{
+	/*
+	 * CMD13, which is used to confirm the completion of timing
+	 * change, will be issued at higher speed timing condtion
+	 * rather than high-speed. If device has completed the change
+	 * to high-speed mode, it may not be proper timing to issue
+	 * command. Low speed supplies better timing margin than high
+	 * speed. Accordingly clock rate & timging should be chagned
+	 * ahead before actual switch.
+	 */
+	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+	mmc_set_bus_speed(card);
+
+	return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			  card->ext_csd.generic_cmd6_time);
+}
+
+/*
  * Activate wide bus and DDR if supported.
  */
 static int mmc_select_hs_ddr(struct mmc_card *card)
@@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
 	return err;
 }
 
+static int mmc_select_hs400(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	/*
+	 * The bus width is set to only 8 DDR in HS400 mode
+	 */
+	if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
+	      host->ios.bus_width == MMC_BUS_WIDTH_8))
+		return 0;
+
+	/*
+	 * Before setting BUS_WIDTH for dual data rate operation,
+	 * HS_TIMING must be set to High Speed(0x1)
+	 */
+	err = mmc_revert_to_hs(card);
+	if (err) {
+		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
+			mmc_hostname(host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_DDR_BUS_WIDTH_8,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
+			mmc_hostname(host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to hs400 failed, err:%d\n",
+			 mmc_hostname(host), err);
+		return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+	mmc_set_bus_speed(card);
+
+	return 0;
+}
+
 /*
  * For device supporting HS200 mode, the following sequence
  * should be done before executing the tuning process.
@@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
 				   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
 				   card->ext_csd.generic_cmd6_time,
 				   true, true, true);
-		if (!err)
+		if (err)
+			goto err;
+
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
+			/*
+			 * Timing should be adjusted to the HS400 target
+			 * operation frequency for tuning process
+			 */
+			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
+		else
 			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
 	}
 err:
@@ -1070,7 +1169,7 @@ bus_speed:
 
 /*
  * Execute tuning sequence to seek the proper bus operating
- * conditions for HS200, which sends CMD21 to the device.
+ * conditions for HS200 and HS400, which sends CMD21 to the device.
  */
 static int mmc_hs200_tuning(struct mmc_card *card)
 {
@@ -1304,6 +1403,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_hs200_tuning(card);
 		if (err)
 			goto err;
+
+		err = mmc_select_hs400(card);
+		if (err)
+			goto err;
 	} else if (mmc_card_hs(card)) {
 		/* Select the desired bus width optionally */
 		err = mmc_select_bus_width(card);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index def6814..2b24c36 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -110,6 +110,7 @@ struct mmc_ext_csd {
 	u8			raw_pwr_cl_200_360;	/* 237 */
 	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
 	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
+	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
 	u8			raw_bkops_status;	/* 246 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 1ee3c10..cc716e4 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -61,6 +61,8 @@ struct mmc_ios {
 #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_HS400_TUNING 11
 
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
@@ -274,6 +276,10 @@ struct mmc_host {
 #define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
 				 MMC_CAP2_PACKED_WR)
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
+#define MMC_CAP2_HS400_1_8V	(1 << 15)	/* Can support HS400 1.8V */
+#define MMC_CAP2_HS400_1_2V	(1 << 16)	/* Can support HS400 1.2V */
+#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
+				 MMC_CAP2_HS400_1_2V)
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
@@ -486,11 +492,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
 
 static inline bool mmc_card_hs200(struct mmc_card *card)
 {
-	return card->host->ios.timing == MMC_TIMING_MMC_HS200;
+	return card->host->ios.timing == MMC_TIMING_MMC_HS200 ||
+		card->host->ios.timing == MMC_TIMING_MMC_HS400_TUNING;
 }
 
 static inline bool mmc_card_ddr52(struct mmc_card *card)
 {
 	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
 }
+
+static inline bool mmc_card_hs400(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
+}
+
 #endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f429f13..64ec963 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -325,6 +325,7 @@ struct _mmc_csd {
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
 #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
 #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
 #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
@@ -354,7 +355,6 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
 #define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
@@ -370,6 +370,10 @@ struct _mmc_csd {
 						/* SDR mode @1.2V I/O */
 #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	(1<<6)	/* Card can run at 200MHz DDR, 1.8V */
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
@@ -380,6 +384,7 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
-- 
1.7.0.4



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

* Re: [PATCH v3 0/5] update selection of bus speed mode for eMMC
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-17  8:47     ` Ulf Hansson
  2014-03-18  1:43       ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-03-17  8:47 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> This series contains the change for selection of bus speed mode.
> Previous implementation is complicated and some sequence is duplicated.
> And specially, HS400 mode eMMC5.0 is introduced this time.
> This patch-set has been tested in Exynos SoC.
>
> Changes in v3:
>         Removed the function to check DDR type(mmc_snoop_ddr).
>         Rebased with the latest branch.

I tried to apply patch 1 for Chris' mmc-next branch, but it failed.
Please have a look.

Kind regards
Ulf Hansson

>
> Seungwon Jeon (5):
>   mmc: drop the speed mode of card's state
>   mmc: identify available device type to select
>   mmc: step power class after final selection of bus mode
>   mmc: rework selection of bus speed mode
>   mmc: add support for HS400 mode of eMMC5.0
>
>  drivers/mmc/core/bus.c     |    9 +-
>  drivers/mmc/core/core.c    |    3 +-
>  drivers/mmc/core/debugfs.c |    5 +-
>  drivers/mmc/core/mmc.c     |  681 +++++++++++++++++++++++++++-----------------
>  drivers/mmc/core/sd.c      |   16 +-
>  drivers/mmc/core/sd.h      |    1 -
>  drivers/mmc/core/sdio.c    |    8 +-
>  include/linux/mmc/card.h   |   31 +--
>  include/linux/mmc/host.h   |   42 +++-
>  include/linux/mmc/mmc.h    |   23 ++-
>  10 files changed, 497 insertions(+), 322 deletions(-)
>
> Thanks,
> Sw-j
>

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

* RE: [PATCH v3 0/5] update selection of bus speed mode for eMMC
  2014-03-17  8:47     ` Ulf Hansson
@ 2014-03-18  1:43       ` Seungwon Jeon
  2014-03-18  4:20         ` Jaehoon Chung
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-18  1:43 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On Mon, March 17, 2014, Ulf Hansson wrote:
> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > This series contains the change for selection of bus speed mode.
> > Previous implementation is complicated and some sequence is duplicated.
> > And specially, HS400 mode eMMC5.0 is introduced this time.
> > This patch-set has been tested in Exynos SoC.
> >
> > Changes in v3:
> >         Removed the function to check DDR type(mmc_snoop_ddr).
> >         Rebased with the latest branch.
> 
> I tried to apply patch 1 for Chris' mmc-next branch, but it failed.
> Please have a look.

It depends on the following patch.
Please could you check?
[PATCH RESEND v3 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC

Thanks,
Seungwon Jeon

> 
> Kind regards
> Ulf Hansson
> 
> >
> > Seungwon Jeon (5):
> >   mmc: drop the speed mode of card's state
> >   mmc: identify available device type to select
> >   mmc: step power class after final selection of bus mode
> >   mmc: rework selection of bus speed mode
> >   mmc: add support for HS400 mode of eMMC5.0
> >
> >  drivers/mmc/core/bus.c     |    9 +-
> >  drivers/mmc/core/core.c    |    3 +-
> >  drivers/mmc/core/debugfs.c |    5 +-
> >  drivers/mmc/core/mmc.c     |  681 +++++++++++++++++++++++++++-----------------
> >  drivers/mmc/core/sd.c      |   16 +-
> >  drivers/mmc/core/sd.h      |    1 -
> >  drivers/mmc/core/sdio.c    |    8 +-
> >  include/linux/mmc/card.h   |   31 +--
> >  include/linux/mmc/host.h   |   42 +++-
> >  include/linux/mmc/mmc.h    |   23 ++-
> >  10 files changed, 497 insertions(+), 322 deletions(-)
> >
> > Thanks,
> > Sw-j
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v3 0/5] update selection of bus speed mode for eMMC
  2014-03-18  1:43       ` Seungwon Jeon
@ 2014-03-18  4:20         ` Jaehoon Chung
  2014-03-18  8:01           ` Ulf Hansson
  0 siblings, 1 reply; 182+ messages in thread
From: Jaehoon Chung @ 2014-03-18  4:20 UTC (permalink / raw)
  To: Seungwon Jeon, 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball', 'Jackey Shen',
	'Alim Akhtar'

On 03/18/2014 10:43 AM, Seungwon Jeon wrote:
> On Mon, March 17, 2014, Ulf Hansson wrote:
>> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>>> This series contains the change for selection of bus speed mode.
>>> Previous implementation is complicated and some sequence is duplicated.
>>> And specially, HS400 mode eMMC5.0 is introduced this time.
>>> This patch-set has been tested in Exynos SoC.
>>>
>>> Changes in v3:
>>>         Removed the function to check DDR type(mmc_snoop_ddr).
>>>         Rebased with the latest branch.
>>
>> I tried to apply patch 1 for Chris' mmc-next branch, but it failed.
>> Please have a look.
> 
> It depends on the following patch.
> Please could you check?
> [PATCH RESEND v3 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC

I have checked these after applied above patch-set. It's applied fine.

Best Regards,
Jaehoon Chung
> 
> Thanks,
> Seungwon Jeon
> 
>>
>> Kind regards
>> Ulf Hansson
>>
>>>
>>> Seungwon Jeon (5):
>>>   mmc: drop the speed mode of card's state
>>>   mmc: identify available device type to select
>>>   mmc: step power class after final selection of bus mode
>>>   mmc: rework selection of bus speed mode
>>>   mmc: add support for HS400 mode of eMMC5.0
>>>
>>>  drivers/mmc/core/bus.c     |    9 +-
>>>  drivers/mmc/core/core.c    |    3 +-
>>>  drivers/mmc/core/debugfs.c |    5 +-
>>>  drivers/mmc/core/mmc.c     |  681 +++++++++++++++++++++++++++-----------------
>>>  drivers/mmc/core/sd.c      |   16 +-
>>>  drivers/mmc/core/sd.h      |    1 -
>>>  drivers/mmc/core/sdio.c    |    8 +-
>>>  include/linux/mmc/card.h   |   31 +--
>>>  include/linux/mmc/host.h   |   42 +++-
>>>  include/linux/mmc/mmc.h    |   23 ++-
>>>  10 files changed, 497 insertions(+), 322 deletions(-)
>>>
>>> Thanks,
>>> Sw-j
>>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 


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

* Re: [PATCH v3 0/5] update selection of bus speed mode for eMMC
  2014-03-18  4:20         ` Jaehoon Chung
@ 2014-03-18  8:01           ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-03-18  8:01 UTC (permalink / raw)
  To: Jaehoon Chung
  Cc: Seungwon Jeon, linux-mmc, Chris Ball, Jackey Shen, Alim Akhtar

On 18 March 2014 05:20, Jaehoon Chung <jh80.chung@samsung.com> wrote:
> On 03/18/2014 10:43 AM, Seungwon Jeon wrote:
>> On Mon, March 17, 2014, Ulf Hansson wrote:
>>> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>>>> This series contains the change for selection of bus speed mode.
>>>> Previous implementation is complicated and some sequence is duplicated.
>>>> And specially, HS400 mode eMMC5.0 is introduced this time.
>>>> This patch-set has been tested in Exynos SoC.
>>>>
>>>> Changes in v3:
>>>>         Removed the function to check DDR type(mmc_snoop_ddr).
>>>>         Rebased with the latest branch.
>>>
>>> I tried to apply patch 1 for Chris' mmc-next branch, but it failed.
>>> Please have a look.
>>
>> It depends on the following patch.
>> Please could you check?
>> [PATCH RESEND v3 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC

I see, that wasn't obvious since that patch comes from a different patchset.

I would future-wise prefer if you could keep dependencies encapsulated
within a single patchset (unless you explicitly states else,
somewhere). That means one patchset won't prevent another one from
being applied, which is good. :-)

Anyway, I will try it out this time.

Kind regards
Ulf Hansson

>
> I have checked these after applied above patch-set. It's applied fine.
>
> Best Regards,
> Jaehoon Chung
>>
>> Thanks,
>> Seungwon Jeon
>>
>>>
>>> Kind regards
>>> Ulf Hansson
>>>
>>>>
>>>> Seungwon Jeon (5):
>>>>   mmc: drop the speed mode of card's state
>>>>   mmc: identify available device type to select
>>>>   mmc: step power class after final selection of bus mode
>>>>   mmc: rework selection of bus speed mode
>>>>   mmc: add support for HS400 mode of eMMC5.0
>>>>
>>>>  drivers/mmc/core/bus.c     |    9 +-
>>>>  drivers/mmc/core/core.c    |    3 +-
>>>>  drivers/mmc/core/debugfs.c |    5 +-
>>>>  drivers/mmc/core/mmc.c     |  681 +++++++++++++++++++++++++++-----------------
>>>>  drivers/mmc/core/sd.c      |   16 +-
>>>>  drivers/mmc/core/sd.h      |    1 -
>>>>  drivers/mmc/core/sdio.c    |    8 +-
>>>>  include/linux/mmc/card.h   |   31 +--
>>>>  include/linux/mmc/host.h   |   42 +++-
>>>>  include/linux/mmc/mmc.h    |   23 ++-
>>>>  10 files changed, 497 insertions(+), 322 deletions(-)
>>>>
>>>> Thanks,
>>>> Sw-j
>>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>>
>

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

* Re: [PATCH v3 4/5] mmc: rework selection of bus speed mode
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-21 13:01     ` Ulf Hansson
  2014-03-22 12:04       ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-03-21 13:01 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Current implementation for bus speed mode selection is too
> complicated. This patch is to simplify the codes and remove
> some duplicate parts.

Really appreciate you taking on this task!

>
> The following changes are including:
> * Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
> * Rearranged the mode selection sequence with supported device type
> * Adds maximum speed for HS200 mode(hs200_max_dtr)
> * Adds field definition for HS_TIMING of EXT_CSD
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
> ---
>  drivers/mmc/core/debugfs.c |    2 +-
>  drivers/mmc/core/mmc.c     |  431 ++++++++++++++++++++++++--------------------
>  include/linux/mmc/card.h   |    1 +
>  include/linux/mmc/mmc.h    |    4 +
>  4 files changed, 238 insertions(+), 200 deletions(-)
>
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index 509229b..1f730db 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -139,7 +139,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>                 str = "mmc DDR52";
>                 break;
>         case MMC_TIMING_MMC_HS200:
> -               str = "mmc high-speed SDR200";
> +               str = "mmc HS200";
>                 break;
>         default:
>                 str = "invalid";
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 480c100..6dd68e6 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -242,7 +242,7 @@ static void mmc_select_card_type(struct mmc_card *card)
>         struct mmc_host *host = card->host;
>         u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>         u32 caps = host->caps, caps2 = host->caps2;
> -       unsigned int hs_max_dtr = 0;
> +       unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>         unsigned int avail_type = 0;
>
>         if (caps & MMC_CAP_MMC_HIGHSPEED &&
> @@ -271,17 +271,18 @@ static void mmc_select_card_type(struct mmc_card *card)
>
>         if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
>             card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
> -               hs_max_dtr = MMC_HS200_MAX_DTR;
> +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
>         }
>
>         if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
>             card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
> -               hs_max_dtr = MMC_HS200_MAX_DTR;
> +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>         }
>
>         card->ext_csd.hs_max_dtr = hs_max_dtr;
> +       card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>         card->mmc_avail_type = avail_type;
>  }
>
> @@ -833,37 +834,46 @@ static int mmc_select_powerclass(struct mmc_card *card)
>  }
>
>  /*
> - * Selects the desired buswidth and switch to the HS200 mode
> - * if bus width set without error
> + * Set the bus speed for the selected speed mode.
>   */
> -static int mmc_select_hs200(struct mmc_card *card)
> +static void mmc_set_bus_speed(struct mmc_card *card)
> +{
> +       unsigned int max_dtr = (unsigned int)-1;

I guess this is to silence compile warnings? Why not just:
unsigned int max_dtr = 0;

> +
> +       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> +               max_dtr = card->ext_csd.hs200_max_dtr;
> +       else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
> +               max_dtr = card->ext_csd.hs_max_dtr;
> +       else if (max_dtr > card->csd.max_dtr)
> +               max_dtr = card->csd.max_dtr;
> +
> +       mmc_set_clock(card->host, max_dtr);
> +}
> +
> +/*
> + * Select the bus width amoung 4-bit and 8-bit(SDR).
> + * If the bus width is changed successfully, return the slected width value.
> + * Zero is returned instead of error value if the wide width is not supported.
> + */
> +static int mmc_select_bus_width(struct mmc_card *card)
>  {
> -       int idx, err = -EINVAL;
> -       struct mmc_host *host;
>         static unsigned ext_csd_bits[] = {
> -               EXT_CSD_BUS_WIDTH_4,
>                 EXT_CSD_BUS_WIDTH_8,
> +               EXT_CSD_BUS_WIDTH_4,
>         };
>         static unsigned bus_widths[] = {
> -               MMC_BUS_WIDTH_4,
>                 MMC_BUS_WIDTH_8,
> +               MMC_BUS_WIDTH_4,
>         };

Do we really need to keep these arrays? The only contain only two values.

Can't we just try with 8-bit, if supported, and if it fails try with
4-bit. Would that further simplify the code?

> +       struct mmc_host *host = card->host;
> +       unsigned idx, bus_width = 0;
> +       int err = 0;
>
> -       BUG_ON(!card);
> -
> -       host = card->host;
> -
> -       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
> -               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
> -
> -       if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
> -               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
> -
> -       /* If fails try again during next card power cycle */
> -       if (err)
> -               goto err;
> +       if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
> +           !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
> +               return 0;
>
> -       idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
> +       idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
>
>         /*
>          * Unlike SD, MMC cards dont have a configuration register to notify
> @@ -871,8 +881,7 @@ static int mmc_select_hs200(struct mmc_card *card)
>          * 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 >= 0; idx--) {
> -
> +       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
> @@ -887,27 +896,202 @@ static int mmc_select_hs200(struct mmc_card *card)
>                 if (err)
>                         continue;
>
> -               mmc_set_bus_width(card->host, bus_widths[idx]);
> +               bus_width = bus_widths[idx];
> +               mmc_set_bus_width(host, bus_width);
>
> +               /*
> +                * If controller can't handle bus width test,
> +                * compare ext_csd previously read in 1 bit mode
> +                * against ext_csd at new bus width
> +                */
>                 if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
> -                       err = mmc_compare_ext_csds(card, bus_widths[idx]);
> +                       err = mmc_compare_ext_csds(card, bus_width);
>                 else
> -                       err = mmc_bus_test(card, bus_widths[idx]);
> -               if (!err)
> +                       err = mmc_bus_test(card, bus_width);
> +
> +               if (!err) {
> +                       err = bus_width;
>                         break;
> +               } else {
> +                       pr_warn("%s: switch to bus width %d failed\n",
> +                               mmc_hostname(host), ext_csd_bits[idx]);
> +               }
>         }
>
> -       /* switch to HS200 mode if bus width set successfully */
> +       return err;
> +}
> +
> +/*
> + * Switch to the high-speed mode
> + */
> +static int mmc_select_hs(struct mmc_card *card)
> +{
> +       int err;
> +
> +       err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                          EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> +                          card->ext_csd.generic_cmd6_time,
> +                          true, true, true);
>         if (!err)
> +               mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> +
> +       return err;
> +}
> +
> +/*
> + * Activate wide bus and DDR if supported.
> + */
> +static int mmc_select_hs_ddr(struct mmc_card *card)
> +{
> +       struct mmc_host *host = card->host;
> +       u32 bus_width, ext_csd_bits;
> +       int err = 0;
> +
> +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52))
> +               return 0;
> +
> +       bus_width = host->ios.bus_width;
> +       if (bus_width == MMC_BUS_WIDTH_1)
> +               return 0;
> +
> +       ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> +               EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
> +
> +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                       EXT_CSD_BUS_WIDTH,
> +                       ext_csd_bits,
> +                       card->ext_csd.generic_cmd6_time);
> +       if (err) {
> +               pr_warn("%s: switch to bus width %d ddr failed\n",
> +                       mmc_hostname(host), 1 << bus_width);
> +               return err;
> +       }
> +
> +       /*
> +        * eMMC cards can support 3.3V to 1.2V i/o (vccq)
> +        * signaling.
> +        *
> +        * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
> +        *
> +        * 1.8V vccq at 3.3V core voltage (vcc) is not required
> +        * in the JEDEC spec for DDR.
> +        *
> +        * Do not force change in vccq since we are obviously
> +        * working and no change to vccq is needed.
> +        *
> +        * WARNING: eMMC rules are NOT the same as SD DDR
> +        */
> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> +               err = __mmc_set_signal_voltage(host,
> +                               MMC_SIGNAL_VOLTAGE_120);
> +               if (err)
> +                       return err;
> +       }
> +
> +       mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
> +
> +       return err;
> +}
> +
> +/*
> + * For device supporting HS200 mode, the following sequence
> + * should be done before executing the tuning process.
> + * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
> + * 2. switch to HS200 mode
> + * 3. set the clock to > 52Mhz and <=200MHz
> + */
> +static int mmc_select_hs200(struct mmc_card *card)
> +{
> +       struct mmc_host *host = card->host;
> +       int err = -EINVAL;
> +
> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
> +               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
> +
> +       if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
> +               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
> +
> +       /* If fails try again during next card power cycle */
> +       if (err)
> +               goto err;
> +
> +       /*
> +        * Set the bus width(4 or 8) with host's support and
> +        * switch to HS200 mode if bus width is set successfully.
> +        */
> +       err = mmc_select_bus_width(card);
> +       if (!IS_ERR_VALUE(err)) {
>                 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> -                               EXT_CSD_HS_TIMING, 2,
> -                               card->ext_csd.generic_cmd6_time,
> -                               true, true, true);
> +                                  EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> +                                  card->ext_csd.generic_cmd6_time,
> +                                  true, true, true);
> +               if (!err)
> +                       mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> +       }
>  err:
>         return err;
>  }
>
>  /*
> + * Activate High Speed or HS200 mode if supported.
> + */
> +static int mmc_select_timing(struct mmc_card *card)
> +{
> +       int err = 0;
> +
> +       if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
> +            card->ext_csd.hs_max_dtr == 0))
> +               goto bus_speed;
> +
> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> +               err = mmc_select_hs200(card);
> +       else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
> +               err = mmc_select_hs(card);
> +
> +       if (err && err != -EBADMSG)
> +               return err;
> +
> +       if (err) {
> +               pr_warn("%s: switch to %s failed\n",
> +                       mmc_card_hs(card) ? "high-speed" :
> +                       (mmc_card_hs200(card) ? "hs200" : ""),
> +                       mmc_hostname(card->host));
> +               err = 0;
> +       }
> +
> +bus_speed:
> +       /*
> +        * Set the bus speed to the selected bus timing.
> +        * If timing is not selected, backward compatible is the default.
> +        */
> +       mmc_set_bus_speed(card);
> +       return err;
> +}
> +
> +/*
> + * Execute tuning sequence to seek the proper bus operating
> + * conditions for HS200, which sends CMD21 to the device.
> + */
> +static int mmc_hs200_tuning(struct mmc_card *card)
> +{
> +       struct mmc_host *host = card->host;
> +       int err = 0;
> +
> +       if (host->ops->execute_tuning) {
> +               mmc_host_clk_hold(host);
> +               err = host->ops->execute_tuning(host,
> +                               MMC_SEND_TUNING_BLOCK_HS200);
> +               mmc_host_clk_release(host);
> +
> +               if (err)
> +                       pr_warn("%s: tuning execution failed\n",
> +                               mmc_hostname(host));
> +       }
> +
> +       return err;
> +}
> +
> +/*
>   * Handle the detection and initialisation of a card.
>   *
>   * In the case of a resume, "oldcard" will contain the card
> @@ -917,9 +1101,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>         struct mmc_card *oldcard)
>  {
>         struct mmc_card *card;
> -       int err, ddr = 0;
> +       int err;
>         u32 cid[4];
> -       unsigned int max_dtr;
>         u32 rocr;
>         u8 *ext_csd = NULL;
>
> @@ -1111,173 +1294,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>         }
>
>         /*
> -        * Activate high speed (if supported)
> -        */
> -       if (card->ext_csd.hs_max_dtr != 0) {
> -               err = 0;
> -               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> -                       err = mmc_select_hs200(card);
> -               else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
> -                       err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> -                                       EXT_CSD_HS_TIMING, 1,
> -                                       card->ext_csd.generic_cmd6_time,
> -                                       true, true, true);
> -
> -               if (err && err != -EBADMSG)
> -                       goto free_card;
> -
> -               if (err) {
> -                       pr_warning("%s: switch to highspeed failed\n",
> -                              mmc_hostname(card->host));
> -                       err = 0;
> -               } else {
> -                       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> -                               mmc_set_timing(card->host,
> -                                              MMC_TIMING_MMC_HS200);
> -                       else
> -                               mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> -               }
> -       }
> -
> -       /*
> -        * Compute bus speed.
> -        */
> -       max_dtr = (unsigned int)-1;
> -
> -       if (mmc_card_hs(card) || mmc_card_hs200(card)) {
> -               if (max_dtr > card->ext_csd.hs_max_dtr)
> -                       max_dtr = card->ext_csd.hs_max_dtr;
> -               if (mmc_card_hs(card) && (max_dtr > 52000000))
> -                       max_dtr = 52000000;
> -       } else if (max_dtr > card->csd.max_dtr) {
> -               max_dtr = card->csd.max_dtr;
> -       }
> -
> -       mmc_set_clock(host, max_dtr);
> -
> -       /*
> -        * Indicate DDR mode (if supported).
> +        * Select timing interface
>          */
> -       if (mmc_card_hs(card))
> -               ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> +       err = mmc_select_timing(card);
> +       if (err)
> +               goto free_card;
>
> -       /*
> -        * Indicate HS200 SDR mode (if supported).
> -        */
>         if (mmc_card_hs200(card)) {
> -               u32 ext_csd_bits;
> -               u32 bus_width = card->host->ios.bus_width;
> -
> -               /*
> -                * For devices supporting HS200 mode, the bus width has
> -                * to be set before executing the tuning function. If
> -                * set before tuning, then device will respond with CRC
> -                * errors for responses on CMD line. So for HS200 the
> -                * sequence will be
> -                * 1. set bus width 4bit / 8 bit (1 bit not supported)
> -                * 2. switch to HS200 mode
> -                * 3. set the clock to > 52Mhz <=200MHz and
> -                * 4. execute tuning for HS200
> -                */
> -               if (card->host->ops->execute_tuning) {
> -                       mmc_host_clk_hold(card->host);
> -                       err = card->host->ops->execute_tuning(card->host,
> -                               MMC_SEND_TUNING_BLOCK_HS200);
> -                       mmc_host_clk_release(card->host);
> -               }
> -               if (err) {
> -                       pr_warning("%s: tuning execution failed\n",
> -                                  mmc_hostname(card->host));
> +               err = mmc_hs200_tuning(card);
> +               if (err)
>                         goto err;
> -               }
> -
> -               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> -                               EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
> -       }
> -
> -       /*
> -        * Activate wide bus and DDR (if supported).
> -        */
> -       if (!mmc_card_hs200(card) &&
> -           (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
> -           (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
> -               static unsigned ext_csd_bits[][2] = {
> -                       { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
> -                       { EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
> -                       { EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
> -               };
> -               static unsigned bus_widths[] = {
> -                       MMC_BUS_WIDTH_8,
> -                       MMC_BUS_WIDTH_4,
> -                       MMC_BUS_WIDTH_1
> -               };
> -               unsigned idx, bus_width = 0;
> -
> -               if (host->caps & MMC_CAP_8_BIT_DATA)
> -                       idx = 0;
> -               else
> -                       idx = 1;
> -               for (; idx < ARRAY_SIZE(bus_widths); idx++) {
> -                       bus_width = bus_widths[idx];
> -                       if (bus_width == MMC_BUS_WIDTH_1)
> -                               ddr = 0; /* no DDR for 1-bit width */
> -
> -                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> -                                        EXT_CSD_BUS_WIDTH,
> -                                        ext_csd_bits[idx][0],
> -                                        card->ext_csd.generic_cmd6_time);
> -                       if (!err) {
> -                               mmc_set_bus_width(card->host, bus_width);
> -
> -                               /*
> -                                * If controller can't handle bus width test,
> -                                * compare ext_csd previously read in 1 bit mode
> -                                * against ext_csd at new bus width
> -                                */
> -                               if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
> -                                       err = mmc_compare_ext_csds(card,
> -                                               bus_width);
> -                               else
> -                                       err = mmc_bus_test(card, bus_width);
> -                               if (!err)
> -                                       break;
> -                       }
> -               }
> -
> -               if (!err && ddr) {
> -                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> -                                        EXT_CSD_BUS_WIDTH,
> -                                        ext_csd_bits[idx][1],
> -                                        card->ext_csd.generic_cmd6_time);
> -               }
> -               if (err) {
> -                       pr_warning("%s: switch to bus width %d ddr %d "
> -                               "failed\n", mmc_hostname(card->host),
> -                               1 << bus_width, ddr);
> -                       goto free_card;
> -               } else if (ddr) {
> -                       /*
> -                        * eMMC cards can support 3.3V to 1.2V i/o (vccq)
> -                        * signaling.
> -                        *
> -                        * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
> -                        *
> -                        * 1.8V vccq at 3.3V core voltage (vcc) is not required
> -                        * in the JEDEC spec for DDR.
> -                        *
> -                        * Do not force change in vccq since we are obviously
> -                        * working and no change to vccq is needed.
> -                        *
> -                        * WARNING: eMMC rules are NOT the same as SD DDR
> -                        */
> -                       if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> -                               err = __mmc_set_signal_voltage(host,
> -                                       MMC_SIGNAL_VOLTAGE_120);
> -                               if (err)
> -                                       goto err;
> -                       }
> -                       mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
> -                       mmc_set_bus_width(card->host, bus_width);
> +       } else if (mmc_card_hs(card)) {
> +               /* Select the desired bus width optionally */
> +               err = mmc_select_bus_width(card);
> +               if (!IS_ERR_VALUE(err)) {
> +                       err = mmc_select_hs_ddr(card);
> +                       if (err)
> +                               goto err;
>                 }
>         }
>
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index c232b10..def6814 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -63,6 +63,7 @@ struct mmc_ext_csd {
>         unsigned int            power_off_longtime;     /* Units: ms */
>         u8                      power_off_notification; /* state */
>         unsigned int            hs_max_dtr;
> +       unsigned int            hs200_max_dtr;
>  #define MMC_HIGH_26_MAX_DTR    26000000
>  #define MMC_HIGH_52_MAX_DTR    52000000
>  #define MMC_HIGH_DDR_MAX_DTR   52000000
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index f734c0c..f429f13 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -377,6 +377,10 @@ struct _mmc_csd {
>  #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_SEC_ER_EN      BIT(0)
>  #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
>  #define EXT_CSD_SEC_GB_CL_EN   BIT(4)
> --
> 1.7.0.4
>
>

Overall looks good to me, besides the minor comments above.

Since this kind of touches quite old code, I would appreciate if it
could go though some more testing in linux next, thus it's material
for early queueing to 3.16.

But before we go on, I would like to know if you managed to test all
the different variants of buswidth/speedmode and the bus width test?
If there is any specific test would like to get help to run, just tell
me.

Nice work!

Kind regards
Ulf Hansson

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

* RE: [PATCH v3 4/5] mmc: rework selection of bus speed mode
  2014-03-21 13:01     ` Ulf Hansson
@ 2014-03-22 12:04       ` Seungwon Jeon
  2014-03-24 13:11         ` Ulf Hansson
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-22 12:04 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On Fri, March 21, 2014, Ulf Hansson wrote:
> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Current implementation for bus speed mode selection is too
> > complicated. This patch is to simplify the codes and remove
> > some duplicate parts.
> 
> Really appreciate you taking on this task!
> 
> >
> > The following changes are including:
> > * Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
> > * Rearranged the mode selection sequence with supported device type
> > * Adds maximum speed for HS200 mode(hs200_max_dtr)
> > * Adds field definition for HS_TIMING of EXT_CSD
> >
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
> > Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
> > ---
> >  drivers/mmc/core/debugfs.c |    2 +-
> >  drivers/mmc/core/mmc.c     |  431 ++++++++++++++++++++++++--------------------
> >  include/linux/mmc/card.h   |    1 +
> >  include/linux/mmc/mmc.h    |    4 +
> >  4 files changed, 238 insertions(+), 200 deletions(-)
> >
> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> > index 509229b..1f730db 100644
> > --- a/drivers/mmc/core/debugfs.c
> > +++ b/drivers/mmc/core/debugfs.c
> > @@ -139,7 +139,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
> >                 str = "mmc DDR52";
> >                 break;
> >         case MMC_TIMING_MMC_HS200:
> > -               str = "mmc high-speed SDR200";
> > +               str = "mmc HS200";
> >                 break;
> >         default:
> >                 str = "invalid";
> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > index 480c100..6dd68e6 100644
> > --- a/drivers/mmc/core/mmc.c
> > +++ b/drivers/mmc/core/mmc.c
> > @@ -242,7 +242,7 @@ static void mmc_select_card_type(struct mmc_card *card)
> >         struct mmc_host *host = card->host;
> >         u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> >         u32 caps = host->caps, caps2 = host->caps2;
> > -       unsigned int hs_max_dtr = 0;
> > +       unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
> >         unsigned int avail_type = 0;
> >
> >         if (caps & MMC_CAP_MMC_HIGHSPEED &&
> > @@ -271,17 +271,18 @@ static void mmc_select_card_type(struct mmc_card *card)
> >
> >         if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> >             card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
> > -               hs_max_dtr = MMC_HS200_MAX_DTR;
> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
> >         }
> >
> >         if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> >             card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
> > -               hs_max_dtr = MMC_HS200_MAX_DTR;
> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> >         }
> >
> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
> > +       card->ext_csd.hs200_max_dtr = hs200_max_dtr;
> >         card->mmc_avail_type = avail_type;
> >  }
> >
> > @@ -833,37 +834,46 @@ static int mmc_select_powerclass(struct mmc_card *card)
> >  }
> >
> >  /*
> > - * Selects the desired buswidth and switch to the HS200 mode
> > - * if bus width set without error
> > + * Set the bus speed for the selected speed mode.
> >   */
> > -static int mmc_select_hs200(struct mmc_card *card)
> > +static void mmc_set_bus_speed(struct mmc_card *card)
> > +{
> > +       unsigned int max_dtr = (unsigned int)-1;
> 
> I guess this is to silence compile warnings? Why not just:
> unsigned int max_dtr = 0;
Basically, I made an effort to keep the previous codes if it's not a problem.
If you found something wrong, please let me know.

> 
> > +
> > +       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> > +               max_dtr = card->ext_csd.hs200_max_dtr;
> > +       else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
> > +               max_dtr = card->ext_csd.hs_max_dtr;
> > +       else if (max_dtr > card->csd.max_dtr)
> > +               max_dtr = card->csd.max_dtr;
> > +
> > +       mmc_set_clock(card->host, max_dtr);
> > +}
> > +
> > +/*
> > + * Select the bus width amoung 4-bit and 8-bit(SDR).
> > + * If the bus width is changed successfully, return the slected width value.
> > + * Zero is returned instead of error value if the wide width is not supported.
> > + */
> > +static int mmc_select_bus_width(struct mmc_card *card)
> >  {
> > -       int idx, err = -EINVAL;
> > -       struct mmc_host *host;
> >         static unsigned ext_csd_bits[] = {
> > -               EXT_CSD_BUS_WIDTH_4,
> >                 EXT_CSD_BUS_WIDTH_8,
> > +               EXT_CSD_BUS_WIDTH_4,
> >         };
> >         static unsigned bus_widths[] = {
> > -               MMC_BUS_WIDTH_4,
> >                 MMC_BUS_WIDTH_8,
> > +               MMC_BUS_WIDTH_4,
> >         };
> 
> Do we really need to keep these arrays? The only contain only two values.
> 
> Can't we just try with 8-bit, if supported, and if it fails try with
> 4-bit. Would that further simplify the code?
Yes, current implementation does that.
First,  it tries with 8-bit if supported, and if failed, it will be tried with 4-bit.
And I think using array can make simple retry coding if considering failure case.
I intended to keep original way.

> 
> Overall looks good to me, besides the minor comments above.
> 
> Since this kind of touches quite old code, I would appreciate if it
> could go though some more testing in linux next, thus it's material
> for early queueing to 3.16.
> 
> But before we go on, I would like to know if you managed to test all
> the different variants of buswidth/speedmode and the bus width test?
> If there is any specific test would like to get help to run, just tell
> me.
> 
> Nice work!
It would be nice if it's picked for 3.15.
As I mentioned above, I basically kept the original flow and way.

This change applies only to eMMC type and participates only in card initialization's process.
I tested on the following various mode and detection is performed successfully.

- HS400	w/ 8-bit
- HS400	w/ 4-bit	: HS200 mode is selected(Because HS400 is possible with 8-bit)
- HS200	w/ 4-bit or 8-bit 
- DDR52	w/ 4-bit or 8-bit
- High speed	w/ 1-bit, 4-bit or 8-bit
- Backwards	w/ 1-bit, 4-bit or 8-bit

I really appreciate your deep reviews.

Thanks,
Seungwon Jeon


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

* Re: [PATCH v3 4/5] mmc: rework selection of bus speed mode
  2014-03-22 12:04       ` Seungwon Jeon
@ 2014-03-24 13:11         ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-03-24 13:11 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 22 March 2014 13:04, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> On Fri, March 21, 2014, Ulf Hansson wrote:
>> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> > Current implementation for bus speed mode selection is too
>> > complicated. This patch is to simplify the codes and remove
>> > some duplicate parts.
>>
>> Really appreciate you taking on this task!
>>
>> >
>> > The following changes are including:
>> > * Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
>> > * Rearranged the mode selection sequence with supported device type
>> > * Adds maximum speed for HS200 mode(hs200_max_dtr)
>> > * Adds field definition for HS_TIMING of EXT_CSD
>> >
>> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
>> > Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
>> > ---
>> >  drivers/mmc/core/debugfs.c |    2 +-
>> >  drivers/mmc/core/mmc.c     |  431 ++++++++++++++++++++++++--------------------
>> >  include/linux/mmc/card.h   |    1 +
>> >  include/linux/mmc/mmc.h    |    4 +
>> >  4 files changed, 238 insertions(+), 200 deletions(-)
>> >
>> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
>> > index 509229b..1f730db 100644
>> > --- a/drivers/mmc/core/debugfs.c
>> > +++ b/drivers/mmc/core/debugfs.c
>> > @@ -139,7 +139,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>> >                 str = "mmc DDR52";
>> >                 break;
>> >         case MMC_TIMING_MMC_HS200:
>> > -               str = "mmc high-speed SDR200";
>> > +               str = "mmc HS200";
>> >                 break;
>> >         default:
>> >                 str = "invalid";
>> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> > index 480c100..6dd68e6 100644
>> > --- a/drivers/mmc/core/mmc.c
>> > +++ b/drivers/mmc/core/mmc.c
>> > @@ -242,7 +242,7 @@ static void mmc_select_card_type(struct mmc_card *card)
>> >         struct mmc_host *host = card->host;
>> >         u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>> >         u32 caps = host->caps, caps2 = host->caps2;
>> > -       unsigned int hs_max_dtr = 0;
>> > +       unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>> >         unsigned int avail_type = 0;
>> >
>> >         if (caps & MMC_CAP_MMC_HIGHSPEED &&
>> > @@ -271,17 +271,18 @@ static void mmc_select_card_type(struct mmc_card *card)
>> >
>> >         if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
>> >             card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
>> > -               hs_max_dtr = MMC_HS200_MAX_DTR;
>> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
>> >         }
>> >
>> >         if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
>> >             card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
>> > -               hs_max_dtr = MMC_HS200_MAX_DTR;
>> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>> >         }
>> >
>> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
>> > +       card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>> >         card->mmc_avail_type = avail_type;
>> >  }
>> >
>> > @@ -833,37 +834,46 @@ static int mmc_select_powerclass(struct mmc_card *card)
>> >  }
>> >
>> >  /*
>> > - * Selects the desired buswidth and switch to the HS200 mode
>> > - * if bus width set without error
>> > + * Set the bus speed for the selected speed mode.
>> >   */
>> > -static int mmc_select_hs200(struct mmc_card *card)
>> > +static void mmc_set_bus_speed(struct mmc_card *card)
>> > +{
>> > +       unsigned int max_dtr = (unsigned int)-1;
>>
>> I guess this is to silence compile warnings? Why not just:
>> unsigned int max_dtr = 0;
> Basically, I made an effort to keep the previous codes if it's not a problem.
> If you found something wrong, please let me know.

Got it, let's keep it as is then!

>
>>
>> > +
>> > +       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
>> > +               max_dtr = card->ext_csd.hs200_max_dtr;
>> > +       else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
>> > +               max_dtr = card->ext_csd.hs_max_dtr;
>> > +       else if (max_dtr > card->csd.max_dtr)
>> > +               max_dtr = card->csd.max_dtr;
>> > +
>> > +       mmc_set_clock(card->host, max_dtr);
>> > +}
>> > +
>> > +/*
>> > + * Select the bus width amoung 4-bit and 8-bit(SDR).
>> > + * If the bus width is changed successfully, return the slected width value.
>> > + * Zero is returned instead of error value if the wide width is not supported.
>> > + */
>> > +static int mmc_select_bus_width(struct mmc_card *card)
>> >  {
>> > -       int idx, err = -EINVAL;
>> > -       struct mmc_host *host;
>> >         static unsigned ext_csd_bits[] = {
>> > -               EXT_CSD_BUS_WIDTH_4,
>> >                 EXT_CSD_BUS_WIDTH_8,
>> > +               EXT_CSD_BUS_WIDTH_4,
>> >         };
>> >         static unsigned bus_widths[] = {
>> > -               MMC_BUS_WIDTH_4,
>> >                 MMC_BUS_WIDTH_8,
>> > +               MMC_BUS_WIDTH_4,
>> >         };
>>
>> Do we really need to keep these arrays? The only contain only two values.
>>
>> Can't we just try with 8-bit, if supported, and if it fails try with
>> 4-bit. Would that further simplify the code?
> Yes, current implementation does that.
> First,  it tries with 8-bit if supported, and if failed, it will be tried with 4-bit.
> And I think using array can make simple retry coding if considering failure case.
> I intended to keep original way.

I understand you want to make as small changes as possible, that's
good. So let's keep this as is then.

If we want to change this, we can do that in a follow up patch instead.

>
>>
>> Overall looks good to me, besides the minor comments above.
>>
>> Since this kind of touches quite old code, I would appreciate if it
>> could go though some more testing in linux next, thus it's material
>> for early queueing to 3.16.
>>
>> But before we go on, I would like to know if you managed to test all
>> the different variants of buswidth/speedmode and the bus width test?
>> If there is any specific test would like to get help to run, just tell
>> me.
>>
>> Nice work!
> It would be nice if it's picked for 3.15.
> As I mentioned above, I basically kept the original flow and way.

I leave the decision to Chris. Still I think some more testing in
linux-next would be nice.

Acked-by: Ulf Hansson <ulf.hansson@linaro.org>

>
> This change applies only to eMMC type and participates only in card initialization's process.
> I tested on the following various mode and detection is performed successfully.
>
> - HS400 w/ 8-bit
> - HS400 w/ 4-bit        : HS200 mode is selected(Because HS400 is possible with 8-bit)
> - HS200 w/ 4-bit or 8-bit
> - DDR52 w/ 4-bit or 8-bit
> - High speed    w/ 1-bit, 4-bit or 8-bit
> - Backwards     w/ 1-bit, 4-bit or 8-bit
>
> I really appreciate your deep reviews.
>
> Thanks,
> Seungwon Jeon
>

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

* Re: [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-24 15:41     ` Ulf Hansson
  2014-03-25  9:23       ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-03-24 15:41 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> 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: Seungwon Jeon <tgih.jun@samsung.com>
> Reviewed-by: Jackey Shen <jackey.shen@amd.com>
> Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
> ---
>  drivers/mmc/core/bus.c     |    1 +
>  drivers/mmc/core/debugfs.c |    3 +
>  drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
>  include/linux/mmc/card.h   |    1 +
>  include/linux/mmc/host.h   |   15 +++++-
>  include/linux/mmc/mmc.h    |    7 ++-
>  6 files changed, 134 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index f37e9d6..d2dbf02 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
>                         mmc_hostname(card->host),
>                         mmc_card_uhs(card) ? "ultra high speed " :
>                         (mmc_card_hs(card) ? "high speed " : ""),
> +                       mmc_card_hs400(card) ? "HS400 " :
>                         (mmc_card_hs200(card) ? "HS200 " : ""),
>                         mmc_card_ddr52(card) ? "DDR " : "",
>                         uhs_bus_speed_mode, type, card->rca);
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index 1f730db..91eb162 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>         case MMC_TIMING_MMC_HS200:
>                 str = "mmc HS200";
>                 break;
> +       case MMC_TIMING_MMC_HS400:
> +               str = "mmc HS400";
> +               break;
>         default:
>                 str = "invalid";
>                 break;
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 6dd68e6..969d595 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
>  static void mmc_select_card_type(struct mmc_card *card)
>  {
>         struct mmc_host *host = card->host;
> -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> +       u8 card_type = card->ext_csd.raw_card_type;
>         u32 caps = host->caps, caps2 = host->caps2;
>         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>         unsigned int avail_type = 0;
> @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
>                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>         }
>
> +       if (caps2 & MMC_CAP2_HS400_1_8V &&
> +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> +       }
> +
> +       if (caps2 & MMC_CAP2_HS400_1_2V &&
> +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> +       }
> +
>         card->ext_csd.hs_max_dtr = hs_max_dtr;
>         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>         card->mmc_avail_type = avail_type;
> @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
>                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
>                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
> +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
>         }
>
>         if (card->ext_csd.rev >= 5) {
> @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
>                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
>                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
>                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> +
>         if (err)
>                 err = -EINVAL;
>
> @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
>                                 ext_csd->raw_pwr_cl_52_360 :
>                                 ext_csd->raw_pwr_cl_ddr_52_360;
>                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
> +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> +                               ext_csd->raw_pwr_cl_ddr_200_360 :
> +                               ext_csd->raw_pwr_cl_200_360;
>                 break;
>         default:
>                 pr_warning("%s: Voltage range not supported "
> @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
>  {
>         unsigned int max_dtr = (unsigned int)-1;
>
> -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
> +            max_dtr > card->ext_csd.hs200_max_dtr)
>                 max_dtr = card->ext_csd.hs200_max_dtr;
>         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
>                 max_dtr = card->ext_csd.hs_max_dtr;
> @@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
>  }
>
>  /*
> + * Revert to the high-speed mode from above speed
> + */
> +static int mmc_revert_to_hs(struct mmc_card *card)
> +{
> +       /*
> +        * CMD13, which is used to confirm the completion of timing
> +        * change, will be issued at higher speed timing condtion
> +        * rather than high-speed. If device has completed the change
> +        * to high-speed mode, it may not be proper timing to issue
> +        * command. Low speed supplies better timing margin than high
> +        * speed. Accordingly clock rate & timging should be chagned
> +        * ahead before actual switch.

I have some problem to understand this comment. I guess you are trying
to provide the arguments to why it makes sense to perform the revert
to lower speed mode!?

This makes me wonder if this is not part of the spec? Could you try to clarify?

> +        */
> +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> +       mmc_set_bus_speed(card);
> +
> +       return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                         EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> +                         card->ext_csd.generic_cmd6_time);
> +}
> +
> +/*
>   * Activate wide bus and DDR if supported.
>   */
>  static int mmc_select_hs_ddr(struct mmc_card *card)
> @@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
>         return err;
>  }
>
> +static int mmc_select_hs400(struct mmc_card *card)
> +{
> +       struct mmc_host *host = card->host;
> +       int err = 0;
> +
> +       /*
> +        * The bus width is set to only 8 DDR in HS400 mode

Please rephrase the comment to something like:
"HS400 mode requires 8-bit bus width."

> +        */
> +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
> +             host->ios.bus_width == MMC_BUS_WIDTH_8))
> +               return 0;
> +
> +       /*
> +        * Before setting BUS_WIDTH for dual data rate operation,
> +        * HS_TIMING must be set to High Speed(0x1)
> +        */

Please rephrase comment:

"Before switching to dual data rate operation for HS400, we need
revert from HS200 timing to regular HS timing."

> +       err = mmc_revert_to_hs(card);

I don't think we need a separate function to handle the revert.
Please, just add the code here instead. While you do that, I suppose
we should combine the comment in that function into one comment here.

> +       if (err) {
> +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> +                       mmc_hostname(host), err);
> +               return err;
> +       }
> +
> +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                        EXT_CSD_BUS_WIDTH,
> +                        EXT_CSD_DDR_BUS_WIDTH_8,
> +                        card->ext_csd.generic_cmd6_time);
> +       if (err) {
> +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> +                       mmc_hostname(host), err);
> +               return err;
> +       }
> +
> +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> +                        card->ext_csd.generic_cmd6_time);
> +       if (err) {
> +               pr_warn("%s: switch to hs400 failed, err:%d\n",
> +                        mmc_hostname(host), err);
> +               return err;
> +       }
> +
> +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> +       mmc_set_bus_speed(card);
> +
> +       return 0;
> +}
> +
>  /*
>   * For device supporting HS200 mode, the following sequence
>   * should be done before executing the tuning process.
> @@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
>                                    EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
>                                    card->ext_csd.generic_cmd6_time,
>                                    true, true, true);
> -               if (!err)
> +               if (err)
> +                       goto err;
> +
> +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> +                       /*
> +                        * Timing should be adjusted to the HS400 target
> +                        * operation frequency for tuning process
> +                        */
> +                       mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);

This seems strange. Do we really need a separate
MMC_TIMING_MMC_HS400_TUNING value?

> +               else
>                         mmc_set_timing(host, MMC_TIMING_MMC_HS200);
>         }
>  err:
> @@ -1070,7 +1169,7 @@ bus_speed:
>
>  /*
>   * Execute tuning sequence to seek the proper bus operating
> - * conditions for HS200, which sends CMD21 to the device.
> + * conditions for HS200 and HS400, which sends CMD21 to the device.
>   */
>  static int mmc_hs200_tuning(struct mmc_card *card)
>  {
> @@ -1304,6 +1403,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                 err = mmc_hs200_tuning(card);
>                 if (err)
>                         goto err;
> +
> +               err = mmc_select_hs400(card);
> +               if (err)
> +                       goto err;
>         } else if (mmc_card_hs(card)) {
>                 /* Select the desired bus width optionally */
>                 err = mmc_select_bus_width(card);
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index def6814..2b24c36 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -110,6 +110,7 @@ struct mmc_ext_csd {
>         u8                      raw_pwr_cl_200_360;     /* 237 */
>         u8                      raw_pwr_cl_ddr_52_195;  /* 238 */
>         u8                      raw_pwr_cl_ddr_52_360;  /* 239 */
> +       u8                      raw_pwr_cl_ddr_200_360; /* 253 */
>         u8                      raw_bkops_status;       /* 246 */
>         u8                      raw_sectors[4];         /* 212 - 4 bytes */
>
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 1ee3c10..cc716e4 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -61,6 +61,8 @@ struct mmc_ios {
>  #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_HS400_TUNING 11

MMC_TIMING_MMC_HS400_TUNING ?

>
>         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
>
> @@ -274,6 +276,10 @@ struct mmc_host {
>  #define MMC_CAP2_PACKED_CMD    (MMC_CAP2_PACKED_RD | \
>                                  MMC_CAP2_PACKED_WR)
>  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)  /* Don't power up before scan */
> +#define MMC_CAP2_HS400_1_8V    (1 << 15)       /* Can support HS400 1.8V */
> +#define MMC_CAP2_HS400_1_2V    (1 << 16)       /* Can support HS400 1.2V */
> +#define MMC_CAP2_HS400         (MMC_CAP2_HS400_1_8V | \
> +                                MMC_CAP2_HS400_1_2V)
>
>         mmc_pm_flag_t           pm_caps;        /* supported pm features */
>
> @@ -486,11 +492,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
>
>  static inline bool mmc_card_hs200(struct mmc_card *card)
>  {
> -       return card->host->ios.timing == MMC_TIMING_MMC_HS200;
> +       return card->host->ios.timing == MMC_TIMING_MMC_HS200 ||
> +               card->host->ios.timing == MMC_TIMING_MMC_HS400_TUNING;

MMC_TIMING_MMC_HS400_TUNING ?

>  }
>
>  static inline bool mmc_card_ddr52(struct mmc_card *card)
>  {
>         return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
>  }
> +
> +static inline bool mmc_card_hs400(struct mmc_card *card)
> +{
> +       return card->host->ios.timing == MMC_TIMING_MMC_HS400;
> +}
> +
>  #endif /* LINUX_MMC_HOST_H */
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index f429f13..64ec963 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -325,6 +325,7 @@ struct _mmc_csd {
>  #define EXT_CSD_POWER_OFF_LONG_TIME    247     /* RO */
>  #define EXT_CSD_GENERIC_CMD6_TIME      248     /* RO */
>  #define EXT_CSD_CACHE_SIZE             249     /* RO, 4 bytes */
> +#define EXT_CSD_PWR_CL_DDR_200_360     253     /* RO */
>  #define EXT_CSD_TAG_UNIT_SIZE          498     /* RO */
>  #define EXT_CSD_DATA_TAG_SUPPORT       499     /* RO */
>  #define EXT_CSD_MAX_PACKED_WRITES      500     /* RO */
> @@ -354,7 +355,6 @@ struct _mmc_csd {
>  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
>  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
>
> -#define EXT_CSD_CARD_TYPE_MASK 0x3F    /* Mask out reserved bits */
>  #define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
>  #define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
>  #define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
> @@ -370,6 +370,10 @@ struct _mmc_csd {
>                                                 /* SDR mode @1.2V I/O */
>  #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   (1<<6)  /* Card can run at 200MHz DDR, 1.8V */
> +#define EXT_CSD_CARD_TYPE_HS400_1_2V   (1<<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_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
> @@ -380,6 +384,7 @@ struct _mmc_csd {
>  #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_SEC_ER_EN      BIT(0)
>  #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
> --
> 1.7.0.4
>
>

Kind regards
Ulf Hansson

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

* RE: [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-03-24 15:41     ` Ulf Hansson
@ 2014-03-25  9:23       ` Seungwon Jeon
  2014-03-28  9:57         ` Ulf Hansson
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-25  9:23 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Hi Ulf,

On Tue, March 25, 2014, Ulf Hansson wrote:
> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > 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: Seungwon Jeon <tgih.jun@samsung.com>
> > Reviewed-by: Jackey Shen <jackey.shen@amd.com>
> > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
> > Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
> > ---
> >  drivers/mmc/core/bus.c     |    1 +
> >  drivers/mmc/core/debugfs.c |    3 +
> >  drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
> >  include/linux/mmc/card.h   |    1 +
> >  include/linux/mmc/host.h   |   15 +++++-
> >  include/linux/mmc/mmc.h    |    7 ++-
> >  6 files changed, 134 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> > index f37e9d6..d2dbf02 100644
> > --- a/drivers/mmc/core/bus.c
> > +++ b/drivers/mmc/core/bus.c
> > @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
> >                         mmc_hostname(card->host),
> >                         mmc_card_uhs(card) ? "ultra high speed " :
> >                         (mmc_card_hs(card) ? "high speed " : ""),
> > +                       mmc_card_hs400(card) ? "HS400 " :
> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
> >                         mmc_card_ddr52(card) ? "DDR " : "",
> >                         uhs_bus_speed_mode, type, card->rca);
> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> > index 1f730db..91eb162 100644
> > --- a/drivers/mmc/core/debugfs.c
> > +++ b/drivers/mmc/core/debugfs.c
> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
> >         case MMC_TIMING_MMC_HS200:
> >                 str = "mmc HS200";
> >                 break;
> > +       case MMC_TIMING_MMC_HS400:
> > +               str = "mmc HS400";
> > +               break;
> >         default:
> >                 str = "invalid";
> >                 break;
> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > index 6dd68e6..969d595 100644
> > --- a/drivers/mmc/core/mmc.c
> > +++ b/drivers/mmc/core/mmc.c
> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
> >  static void mmc_select_card_type(struct mmc_card *card)
> >  {
> >         struct mmc_host *host = card->host;
> > -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> > +       u8 card_type = card->ext_csd.raw_card_type;
> >         u32 caps = host->caps, caps2 = host->caps2;
> >         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
> >         unsigned int avail_type = 0;
> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> >         }
> >
> > +       if (caps2 & MMC_CAP2_HS400_1_8V &&
> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> > +       }
> > +
> > +       if (caps2 & MMC_CAP2_HS400_1_2V &&
> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> > +       }
> > +
> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
> >         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
> >         card->mmc_avail_type = avail_type;
> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
> >                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> > +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
> > +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
> >         }
> >
> >         if (card->ext_csd.rev >= 5) {
> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
> >                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
> >                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
> >                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> > -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> > +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> > +
> >         if (err)
> >                 err = -EINVAL;
> >
> > @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> >                                 ext_csd->raw_pwr_cl_52_360 :
> >                                 ext_csd->raw_pwr_cl_ddr_52_360;
> >                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> > -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
> > +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> > +                               ext_csd->raw_pwr_cl_ddr_200_360 :
> > +                               ext_csd->raw_pwr_cl_200_360;
> >                 break;
> >         default:
> >                 pr_warning("%s: Voltage range not supported "
> > @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
> >  {
> >         unsigned int max_dtr = (unsigned int)-1;
> >
> > -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> > +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
> > +            max_dtr > card->ext_csd.hs200_max_dtr)
> >                 max_dtr = card->ext_csd.hs200_max_dtr;
> >         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
> >                 max_dtr = card->ext_csd.hs_max_dtr;
> > @@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
> >  }
> >
> >  /*
> > + * Revert to the high-speed mode from above speed
> > + */
> > +static int mmc_revert_to_hs(struct mmc_card *card)
> > +{
> > +       /*
> > +        * CMD13, which is used to confirm the completion of timing
> > +        * change, will be issued at higher speed timing condtion
> > +        * rather than high-speed. If device has completed the change
> > +        * to high-speed mode, it may not be proper timing to issue
> > +        * command. Low speed supplies better timing margin than high
> > +        * speed. Accordingly clock rate & timging should be chagned
> > +        * ahead before actual switch.
> 
> I have some problem to understand this comment. I guess you are trying
> to provide the arguments to why it makes sense to perform the revert
> to lower speed mode!?
> 
> This makes me wonder if this is not part of the spec? Could you try to clarify?
But specification says that "HS_TIMING must be set to “0x1” before setting BUS_WIDTH for dual data rate operation".
I think this sequence is not graceful.
I also commented why speed mode should be changed to high-speed mode from HS200 mode in the function-called part.
Because it is not possible to set 8-bit data bus for dual rate on HS200 mode, revert to high-speed from HS200 is needed.
If the above-commented point makes it confused, it could be removed.
Please let me know your opinion.

> 
> > +        */
> > +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> > +       mmc_set_bus_speed(card);
> > +
> > +       return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +                         EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> > +                         card->ext_csd.generic_cmd6_time);
> > +}
> > +
> > +/*
> >   * Activate wide bus and DDR if supported.
> >   */
> >  static int mmc_select_hs_ddr(struct mmc_card *card)
> > @@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
> >         return err;
> >  }
> >
> > +static int mmc_select_hs400(struct mmc_card *card)
> > +{
> > +       struct mmc_host *host = card->host;
> > +       int err = 0;
> > +
> > +       /*
> > +        * The bus width is set to only 8 DDR in HS400 mode
> 
> Please rephrase the comment to something like:
> "HS400 mode requires 8-bit bus width."
As it is, it was from spec's description.
But I think yours would be more clearable.

> 
> > +        */
> > +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
> > +             host->ios.bus_width == MMC_BUS_WIDTH_8))
> > +               return 0;
> > +
> > +       /*
> > +        * Before setting BUS_WIDTH for dual data rate operation,
> > +        * HS_TIMING must be set to High Speed(0x1)
> > +        */
> 
> Please rephrase comment:
> 
> "Before switching to dual data rate operation for HS400, we need
> revert from HS200 timing to regular HS timing."
Ok.

> 
> > +       err = mmc_revert_to_hs(card);
> 
> I don't think we need a separate function to handle the revert.
> Please, just add the code here instead. While you do that, I suppose
> we should combine the comment in that function into one comment here.
OK, I don't oppose that.

> 
> > +       if (err) {
> > +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> > +                       mmc_hostname(host), err);
> > +               return err;
> > +       }
> > +
> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +                        EXT_CSD_BUS_WIDTH,
> > +                        EXT_CSD_DDR_BUS_WIDTH_8,
> > +                        card->ext_csd.generic_cmd6_time);
> > +       if (err) {
> > +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> > +                       mmc_hostname(host), err);
> > +               return err;
> > +       }
> > +
> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> > +                        card->ext_csd.generic_cmd6_time);
> > +       if (err) {
> > +               pr_warn("%s: switch to hs400 failed, err:%d\n",
> > +                        mmc_hostname(host), err);
> > +               return err;
> > +       }
> > +
> > +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> > +       mmc_set_bus_speed(card);
> > +
> > +       return 0;
> > +}
> > +
> >  /*
> >   * For device supporting HS200 mode, the following sequence
> >   * should be done before executing the tuning process.
> > @@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
> >                                    EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> >                                    card->ext_csd.generic_cmd6_time,
> >                                    true, true, true);
> > -               if (!err)
> > +               if (err)
> > +                       goto err;
> > +
> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> > +                       /*
> > +                        * Timing should be adjusted to the HS400 target
> > +                        * operation frequency for tuning process
> > +                        */
> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> 
> This seems strange. Do we really need a separate
> MMC_TIMING_MMC_HS400_TUNING value?
Spec. describes the HS400 selection sequence like below.
<Quot>
...
6) Perform the Tuning Process at the HS400 target operating frequency
(Note: tuning process in HS200 mode is required to synchronize the command response on the CMD line to CLK for HS400 operation).
...
</Quot>
That means target clock rate for tuning sequence can be different with HS200.
Considering for that, it needs to distinguish.

> 
> > +               else
> >                         mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> >         }
> >  err:
> > @@ -1070,7 +1169,7 @@ bus_speed:
> >
> >  /*
> >   * Execute tuning sequence to seek the proper bus operating
> > - * conditions for HS200, which sends CMD21 to the device.
> > + * conditions for HS200 and HS400, which sends CMD21 to the device.
> >   */
> >  static int mmc_hs200_tuning(struct mmc_card *card)
> >  {
> > @@ -1304,6 +1403,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >                 err = mmc_hs200_tuning(card);
> >                 if (err)
> >                         goto err;
> > +
> > +               err = mmc_select_hs400(card);
> > +               if (err)
> > +                       goto err;
> >         } else if (mmc_card_hs(card)) {
> >                 /* Select the desired bus width optionally */
> >                 err = mmc_select_bus_width(card);
> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > index def6814..2b24c36 100644
> > --- a/include/linux/mmc/card.h
> > +++ b/include/linux/mmc/card.h
> > @@ -110,6 +110,7 @@ struct mmc_ext_csd {
> >         u8                      raw_pwr_cl_200_360;     /* 237 */
> >         u8                      raw_pwr_cl_ddr_52_195;  /* 238 */
> >         u8                      raw_pwr_cl_ddr_52_360;  /* 239 */
> > +       u8                      raw_pwr_cl_ddr_200_360; /* 253 */
> >         u8                      raw_bkops_status;       /* 246 */
> >         u8                      raw_sectors[4];         /* 212 - 4 bytes */
> >
> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > index 1ee3c10..cc716e4 100644
> > --- a/include/linux/mmc/host.h
> > +++ b/include/linux/mmc/host.h
> > @@ -61,6 +61,8 @@ struct mmc_ios {
> >  #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_HS400_TUNING 11
> 
> MMC_TIMING_MMC_HS400_TUNING ?
> 
> >
> >         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
> >
> > @@ -274,6 +276,10 @@ struct mmc_host {
> >  #define MMC_CAP2_PACKED_CMD    (MMC_CAP2_PACKED_RD | \
> >                                  MMC_CAP2_PACKED_WR)
> >  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)  /* Don't power up before scan */
> > +#define MMC_CAP2_HS400_1_8V    (1 << 15)       /* Can support HS400 1.8V */
> > +#define MMC_CAP2_HS400_1_2V    (1 << 16)       /* Can support HS400 1.2V */
> > +#define MMC_CAP2_HS400         (MMC_CAP2_HS400_1_8V | \
> > +                                MMC_CAP2_HS400_1_2V)
> >
> >         mmc_pm_flag_t           pm_caps;        /* supported pm features */
> >
> > @@ -486,11 +492,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
> >
> >  static inline bool mmc_card_hs200(struct mmc_card *card)
> >  {
> > -       return card->host->ios.timing == MMC_TIMING_MMC_HS200;
> > +       return card->host->ios.timing == MMC_TIMING_MMC_HS200 ||
> > +               card->host->ios.timing == MMC_TIMING_MMC_HS400_TUNING;
> 
> MMC_TIMING_MMC_HS400_TUNING ?
It also indicates that card is currently in HS200 mode with the result of setting HS_TIMING'.

Thanks,
Seungwon Jeon

> 
> >  }
> >
> >  static inline bool mmc_card_ddr52(struct mmc_card *card)
> >  {
> >         return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
> >  }
> > +
> > +static inline bool mmc_card_hs400(struct mmc_card *card)
> > +{
> > +       return card->host->ios.timing == MMC_TIMING_MMC_HS400;
> > +}
> > +
> >  #endif /* LINUX_MMC_HOST_H */
> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> > index f429f13..64ec963 100644
> > --- a/include/linux/mmc/mmc.h
> > +++ b/include/linux/mmc/mmc.h
> > @@ -325,6 +325,7 @@ struct _mmc_csd {
> >  #define EXT_CSD_POWER_OFF_LONG_TIME    247     /* RO */
> >  #define EXT_CSD_GENERIC_CMD6_TIME      248     /* RO */
> >  #define EXT_CSD_CACHE_SIZE             249     /* RO, 4 bytes */
> > +#define EXT_CSD_PWR_CL_DDR_200_360     253     /* RO */
> >  #define EXT_CSD_TAG_UNIT_SIZE          498     /* RO */
> >  #define EXT_CSD_DATA_TAG_SUPPORT       499     /* RO */
> >  #define EXT_CSD_MAX_PACKED_WRITES      500     /* RO */
> > @@ -354,7 +355,6 @@ struct _mmc_csd {
> >  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
> >  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
> >
> > -#define EXT_CSD_CARD_TYPE_MASK 0x3F    /* Mask out reserved bits */
> >  #define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
> >  #define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
> >  #define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
> > @@ -370,6 +370,10 @@ struct _mmc_csd {
> >                                                 /* SDR mode @1.2V I/O */
> >  #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   (1<<6)  /* Card can run at 200MHz DDR, 1.8V */
> > +#define EXT_CSD_CARD_TYPE_HS400_1_2V   (1<<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_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
> >  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
> > @@ -380,6 +384,7 @@ struct _mmc_csd {
> >  #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_SEC_ER_EN      BIT(0)
> >  #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
> > --
> > 1.7.0.4
> >
> >
> 
> Kind regards
> Ulf Hansson
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* [PATCH v4 0/5]  update selection of bus speed mode for eMMC
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (2 preceding siblings ...)
  2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
@ 2014-03-26 10:59   ` Seungwon Jeon
  2014-03-26 11:00   ` [PATCH v4 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
                     ` (24 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-26 10:59 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

This series contains the change for selection of bus speed mode.
Previous implementation is complicated and some sequence is duplicated.
And specially, HS400 mode eMMC5.0 is introduced this time.
This patch-set has been tested in Exynos SoC.

Note: 
This patch-set depends on "[PATCH RESEND v3 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC".

Changes in v4:
	(5/5)Reverting to HS mode is included in mmc_select_hs400() using __mmc_switch().

Changes in v3:
 	Removed the function to check DDR type(mmc_snoop_ddr).
 	Rebased with the latest branch.

Seungwon Jeon (5):
  mmc: drop the speed mode of card's state
  mmc: identify available device type to select
  mmc: step power class after final selection of bus mode
  mmc: rework selection of bus speed mode
  mmc: add support for HS400 mode of eMMC5.0

 drivers/mmc/core/bus.c     |    9 +-
 drivers/mmc/core/core.c    |    3 +-
 drivers/mmc/core/debugfs.c |    5 +-
 drivers/mmc/core/mmc.c     |  666 ++++++++++++++++++++++++++------------------
 drivers/mmc/core/sd.c      |   16 +-
 drivers/mmc/core/sd.h      |    1 -
 drivers/mmc/core/sdio.c    |    8 +-
 include/linux/mmc/card.h   |   31 +--
 include/linux/mmc/host.h   |   42 +++-
 include/linux/mmc/mmc.h    |   23 ++-
 10 files changed, 482 insertions(+), 322 deletions(-)

Thanks,
sw-j


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

* [PATCH v4 1/5] mmc: drop the speed mode of card's state
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (3 preceding siblings ...)
  2014-03-26 10:59   ` [PATCH v4 " Seungwon Jeon
@ 2014-03-26 11:00   ` Seungwon Jeon
  2014-03-26 11:00   ` [PATCH v4 2/5] mmc: identify available device type to select Seungwon Jeon
                     ` (23 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-26 11:00 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Timing mode identifier has same role and can take the place
of speed mode. This change removes all related speed mode.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/bus.c   |    8 ++++----
 drivers/mmc/core/core.c  |    3 +--
 drivers/mmc/core/mmc.c   |   11 +++--------
 drivers/mmc/core/sd.c    |   16 +++-------------
 drivers/mmc/core/sd.h    |    1 -
 drivers/mmc/core/sdio.c  |    8 ++------
 include/linux/mmc/card.h |   23 ++++++-----------------
 include/linux/mmc/host.h |   23 +++++++++++++++++++++++
 8 files changed, 42 insertions(+), 51 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 8246448..f37e9d6 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -341,16 +341,16 @@ int mmc_add_card(struct mmc_card *card)
 	if (mmc_host_is_spi(card->host)) {
 		pr_info("%s: new %s%s%s card on SPI\n",
 			mmc_hostname(card->host),
-			mmc_card_highspeed(card) ? "high speed " : "",
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_hs(card) ? "high speed " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			type);
 	} else {
 		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
-			(mmc_card_highspeed(card) ? "high speed " : ""),
+			(mmc_card_hs(card) ? "high speed " : ""),
 			(mmc_card_hs200(card) ? "HS200 " : ""),
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
 	}
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index acbc3f2..aa9f679 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2183,7 +2183,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
 	struct mmc_command cmd = {0};
 
-	if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+	if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
 		return 0;
 
 	cmd.opcode = MMC_SET_BLOCKLEN;
@@ -2263,7 +2263,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
 		}
 	}
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
 	if (mmc_host_is_spi(host)) {
 		host->ios.chip_select = MMC_CS_HIGH;
 		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e22d851..db9655f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1091,11 +1091,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		} else {
 			if (card->ext_csd.hs_max_dtr > 52000000 &&
 			    host->caps2 & MMC_CAP2_HS200) {
-				mmc_card_set_hs200(card);
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
 			} else {
-				mmc_card_set_highspeed(card);
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
 			}
 		}
@@ -1106,10 +1104,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
+	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
 		if (max_dtr > card->ext_csd.hs_max_dtr)
 			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_highspeed(card) && (max_dtr > 52000000))
+		if (mmc_card_hs(card) && (max_dtr > 52000000))
 			max_dtr = 52000000;
 	} else if (max_dtr > card->csd.max_dtr) {
 		max_dtr = card->csd.max_dtr;
@@ -1120,7 +1118,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
 			&& (host->caps & MMC_CAP_1_8V_DDR))
 				ddr = MMC_1_8V_DDR_MODE;
@@ -1263,7 +1261,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 				if (err)
 					goto err;
 			}
-			mmc_card_set_ddr_mode(card);
 			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
 			mmc_set_bus_width(card->host, bus_width);
 		}
@@ -1507,7 +1504,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 		err = mmc_sleep(host);
 	else if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 
 	if (!err) {
 		mmc_power_off(host);
@@ -1637,7 +1633,6 @@ static int mmc_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 	mmc_claim_host(host);
 	ret = mmc_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 2dd359d..9fc5b31 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -895,7 +895,7 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if (max_dtr > card->sw_caps.hs_max_dtr)
 			max_dtr = card->sw_caps.hs_max_dtr;
 	} else if (max_dtr > card->csd.max_dtr) {
@@ -905,12 +905,6 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 	return max_dtr;
 }
 
-void mmc_sd_go_highspeed(struct mmc_card *card)
-{
-	mmc_card_set_highspeed(card);
-	mmc_set_timing(card->host, MMC_TIMING_SD_HS);
-}
-
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -985,16 +979,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_sd_init_uhs_card(card);
 		if (err)
 			goto free_card;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Attempt to change to high-speed (if supported)
 		 */
 		err = mmc_sd_switch_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto free_card;
 
@@ -1089,7 +1080,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
 
 	if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
+
 	if (!err) {
 		mmc_power_off(host);
 		mmc_card_set_suspended(host->card);
@@ -1198,7 +1189,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
 	ret = mmc_sd_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
index 4b34b24..aab824a 100644
--- a/drivers/mmc/core/sd.h
+++ b/drivers/mmc/core/sd.h
@@ -12,6 +12,5 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 	bool reinit);
 unsigned mmc_sd_get_max_clock(struct mmc_card *card);
 int mmc_sd_switch_hs(struct mmc_card *card);
-void mmc_sd_go_highspeed(struct mmc_card *card);
 
 #endif
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4d721c6..ef57d2d 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		/*
 		 * The SDIO specification doesn't mention how
 		 * the CIS transfer speed register relates to
@@ -733,7 +733,6 @@ try_again:
 		mmc_set_clock(host, card->cis.max_dtr);
 
 		if (card->cccr.high_speed) {
-			mmc_card_set_highspeed(card);
 			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		}
 
@@ -792,16 +791,13 @@ try_again:
 		err = mmc_sdio_init_uhs_card(card);
 		if (err)
 			goto remove;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Switch to high-speed (if supported).
 		 */
 		err = sdio_enable_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto remove;
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index b730272..5473133 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -194,6 +194,7 @@ struct sdio_cis {
 };
 
 struct mmc_host;
+struct mmc_ios;
 struct sdio_func;
 struct sdio_func_tuple;
 
@@ -250,15 +251,11 @@ struct mmc_card {
 	unsigned int		state;		/* (our) card state */
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
 #define MMC_STATE_READONLY	(1<<1)		/* card is read-only */
-#define MMC_STATE_HIGHSPEED	(1<<2)		/* card is in high speed mode */
-#define MMC_STATE_BLOCKADDR	(1<<3)		/* card uses block-addressing */
-#define MMC_STATE_HIGHSPEED_DDR (1<<4)		/* card is in high speed mode */
-#define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra high speed mode */
-#define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
-#define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
-#define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
-#define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
-#define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
+#define MMC_STATE_BLOCKADDR	(1<<2)		/* card uses block-addressing */
+#define MMC_CARD_SDXC		(1<<3)		/* card is SDXC */
+#define MMC_CARD_REMOVED	(1<<4)		/* card has been removed */
+#define MMC_STATE_DOING_BKOPS	(1<<5)		/* card is doing BKOPS */
+#define MMC_STATE_SUSPENDED	(1<<6)		/* card is suspended */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -418,11 +415,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
-#define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
-#define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
-#define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
@@ -430,11 +423,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
-#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
-#define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
-#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_doing_bkops(c)	((c)->state |= MMC_STATE_DOING_BKOPS)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 3535420..2f263ae 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -17,6 +17,7 @@
 #include <linux/fault-inject.h>
 
 #include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -476,4 +477,26 @@ static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
 	return host->ios.clock;
 }
 #endif
+
+static inline int mmc_card_hs(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_SD_HS ||
+		card->host->ios.timing == MMC_TIMING_MMC_HS;
+}
+
+static inline int mmc_card_uhs(struct mmc_card *card)
+{
+	return card->host->ios.timing >= MMC_TIMING_UHS_SDR12 &&
+		card->host->ios.timing <= MMC_TIMING_UHS_DDR50;
+}
+
+static inline bool mmc_card_hs200(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_HS200;
+}
+
+static inline bool mmc_card_ddr52(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
+}
 #endif /* LINUX_MMC_HOST_H */
-- 
1.7.0.4



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

* [PATCH v4 2/5] mmc: identify available device type to select
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (4 preceding siblings ...)
  2014-03-26 11:00   ` [PATCH v4 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
@ 2014-03-26 11:00   ` Seungwon Jeon
  2014-03-26 11:00   ` [PATCH v4 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
                     ` (22 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-26 11:00 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Device types which are supported by both host and device
can be identified when EXT_CSD is read. There is no need to
check host's capability anymore.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/mmc.c   |   72 +++++++++++++++++++++++++---------------------
 include/linux/mmc/card.h |    6 ++-
 include/linux/mmc/host.h |    6 ----
 include/linux/mmc/mmc.h  |   12 +++++--
 4 files changed, 51 insertions(+), 45 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index db9655f..97f1912 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0;
+	unsigned int avail_type = 0;
 
-	if (card_type & EXT_CSD_CARD_TYPE_26)
+	if (caps & MMC_CAP_MMC_HIGHSPEED &&
+	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
 		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
+	}
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
-			card_type & EXT_CSD_CARD_TYPE_52)
+	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
 		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
+	}
 
-	if ((caps & MMC_CAP_1_8V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
-	    (caps & MMC_CAP_1_2V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
+	if (caps & MMC_CAP_1_8V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
 		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
+	}
+
+	if (caps & MMC_CAP_1_2V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
+	}
 
-	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
-	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
+	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
 		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
+		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
+	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
-	card->ext_csd.card_type = card_type;
+	card->mmc_avail_type = avail_type;
 }
 
 /*
@@ -808,12 +826,10 @@ static int mmc_select_hs200(struct mmc_card *card)
 
 	host = card->host;
 
-	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
-			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
 
-	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
-			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
 
 	/* If fails try again during next card power cycle */
@@ -1072,10 +1088,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	if (card->ext_csd.hs_max_dtr != 0) {
 		err = 0;
-		if (card->ext_csd.hs_max_dtr > 52000000 &&
-		    host->caps2 & MMC_CAP2_HS200)
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 			err = mmc_select_hs200(card);
-		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
+		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
 			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					EXT_CSD_HS_TIMING, 1,
 					card->ext_csd.generic_cmd6_time,
@@ -1089,13 +1104,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			       mmc_hostname(card->host));
 			err = 0;
 		} else {
-			if (card->ext_csd.hs_max_dtr > 52000000 &&
-			    host->caps2 & MMC_CAP2_HS200) {
+			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
-			} else {
+			else
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-			}
 		}
 	}
 
@@ -1118,14 +1131,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_hs(card)) {
-		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-			&& (host->caps & MMC_CAP_1_8V_DDR))
-				ddr = MMC_1_8V_DDR_MODE;
-		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-			&& (host->caps & MMC_CAP_1_2V_DDR))
-				ddr = MMC_1_2V_DDR_MODE;
-	}
+	if (mmc_card_hs(card))
+		ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
 
 	/*
 	 * Indicate HS200 SDR mode (if supported).
@@ -1145,8 +1152,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		 * 3. set the clock to > 52Mhz <=200MHz and
 		 * 4. execute tuning for HS200
 		 */
-		if ((host->caps2 & MMC_CAP2_HS200) &&
-		    card->host->ops->execute_tuning) {
+		if (card->host->ops->execute_tuning) {
 			mmc_host_clk_hold(card->host);
 			err = card->host->ops->execute_tuning(card->host,
 				MMC_SEND_TUNING_BLOCK_HS200);
@@ -1255,7 +1261,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			 *
 			 * WARNING: eMMC rules are NOT the same as SD DDR
 			 */
-			if (ddr == MMC_1_2V_DDR_MODE) {
+			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
 				err = __mmc_set_signal_voltage(host,
 					MMC_SIGNAL_VOLTAGE_120);
 				if (err)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 5473133..c232b10 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -68,7 +68,6 @@ struct mmc_ext_csd {
 #define MMC_HIGH_DDR_MAX_DTR	52000000
 #define MMC_HS200_MAX_DTR	200000000
 	unsigned int		sectors;
-	unsigned int		card_type;
 	unsigned int		hc_erase_size;		/* In sectors */
 	unsigned int		hc_erase_timeout;	/* In milliseconds */
 	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
@@ -297,7 +296,10 @@ struct mmc_card {
 	const char		**info;		/* info strings */
 	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
 
-	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+	union {
+		unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+		unsigned int		mmc_avail_type;	/* supported device type by both host and card */
+	};
 
 	struct dentry		*debugfs_root;
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 2f263ae..1ee3c10 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -62,12 +62,6 @@ struct mmc_ios {
 #define MMC_TIMING_MMC_DDR52	8
 #define MMC_TIMING_MMC_HS200	9
 
-#define MMC_SDR_MODE		0
-#define MMC_1_2V_DDR_MODE	1
-#define MMC_1_8V_DDR_MODE	2
-#define MMC_1_2V_SDR_MODE	3
-#define MMC_1_8V_SDR_MODE	4
-
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
 #define MMC_SIGNAL_VOLTAGE_330	0
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 50bcde3..f734c0c 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -354,18 +354,22 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#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_MASK	0x3F	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
+				 EXT_CSD_CARD_TYPE_HS_52)
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
 					     /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
 					     /* DDR mode @1.2V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
 					| EXT_CSD_CARD_TYPE_DDR_1_2V)
-#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
-#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_8V	(1<<4)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_2V	(1<<5)	/* Card can run at 200MHz */
 						/* SDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS200_1_2V)
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
-- 
1.7.0.4



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

* [PATCH v4 3/5] mmc: step power class after final selection of bus mode
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (5 preceding siblings ...)
  2014-03-26 11:00   ` [PATCH v4 2/5] mmc: identify available device type to select Seungwon Jeon
@ 2014-03-26 11:00   ` Seungwon Jeon
  2014-03-28  8:43     ` Ulf Hansson
  2014-03-26 11:00   ` [PATCH v4 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
                     ` (21 subsequent siblings)
  28 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-26 11:00 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Power class is changed once only after selection of bus modes
including speed and bus-width finishes finally.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/mmc.c |   96 +++++++++++++++++++++++++++--------------------
 1 files changed, 55 insertions(+), 41 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 97f1912..480c100 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -732,17 +732,13 @@ static struct device_type mmc_type = {
  * extended CSD register, select it by executing the
  * mmc_switch command.
  */
-static int mmc_select_powerclass(struct mmc_card *card,
-		unsigned int bus_width)
+static int __mmc_select_powerclass(struct mmc_card *card,
+				   unsigned int bus_width)
 {
-	int err = 0;
+	struct mmc_host *host = card->host;
+	struct mmc_ext_csd *ext_csd = &card->ext_csd;
 	unsigned int pwrclass_val = 0;
-	struct mmc_host *host;
-
-	BUG_ON(!card);
-
-	host = card->host;
-	BUG_ON(!host);
+	int err = 0;
 
 	/* Power class selection is supported for versions >= 4.0 */
 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
@@ -754,14 +750,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
 
 	switch (1 << host->ios.vdd) {
 	case MMC_VDD_165_195:
-		if (host->ios.clock <= 26000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
-		else if	(host->ios.clock <= 52000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_26_195;
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-				card->ext_csd.raw_pwr_cl_52_195 :
-				card->ext_csd.raw_pwr_cl_ddr_52_195;
-		else if (host->ios.clock <= 200000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
+				ext_csd->raw_pwr_cl_52_195 :
+				ext_csd->raw_pwr_cl_ddr_52_195;
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_200_195;
 		break;
 	case MMC_VDD_27_28:
 	case MMC_VDD_28_29:
@@ -772,14 +768,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	case MMC_VDD_33_34:
 	case MMC_VDD_34_35:
 	case MMC_VDD_35_36:
-		if (host->ios.clock <= 26000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
-		else if	(host->ios.clock <= 52000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_26_360;
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-				card->ext_csd.raw_pwr_cl_52_360 :
-				card->ext_csd.raw_pwr_cl_ddr_52_360;
-		else if (host->ios.clock <= 200000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
+				ext_csd->raw_pwr_cl_52_360 :
+				ext_csd->raw_pwr_cl_ddr_52_360;
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -805,6 +801,37 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	return err;
 }
 
+static int mmc_select_powerclass(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	u32 bus_width, ext_csd_bits;
+	int err, ddr;
+
+	/* Power class selection is supported for versions >= 4.0 */
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	/* Power class values are defined only for 4/8 bit bus */
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	if (ddr)
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+	else
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
+
+	err = __mmc_select_powerclass(card, ext_csd_bits);
+	if (err)
+		pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
+			mmc_hostname(host), 1 << bus_width, ddr);
+
+	return err;
+}
+
 /*
  * Selects the desired buswidth and switch to the HS200 mode
  * if bus width set without error
@@ -1166,11 +1193,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
 		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
 				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-		err = mmc_select_powerclass(card, ext_csd_bits);
-		if (err)
-			pr_warning("%s: power class selection to bus width %d"
-				   " failed\n", mmc_hostname(card->host),
-				   1 << bus_width);
 	}
 
 	/*
@@ -1199,12 +1221,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			bus_width = bus_widths[idx];
 			if (bus_width == MMC_BUS_WIDTH_1)
 				ddr = 0; /* no DDR for 1-bit width */
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width);
 
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
@@ -1229,13 +1245,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		}
 
 		if (!err && ddr) {
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d ddr %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width, ddr);
-
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][1],
@@ -1273,6 +1282,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
+	 * Choose the power class with selected bus interface
+	 */
+	mmc_select_powerclass(card);
+
+	/*
 	 * Enable HPI feature (if supported)
 	 */
 	if (card->ext_csd.hpi) {
-- 
1.7.0.4



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

* [PATCH v4 4/5] mmc: rework selection of bus speed mode
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (6 preceding siblings ...)
  2014-03-26 11:00   ` [PATCH v4 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
@ 2014-03-26 11:00   ` Seungwon Jeon
  2014-03-26 11:00   ` [PATCH v4 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
                     ` (20 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-26 11:00 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Current implementation for bus speed mode selection is too
complicated. This patch is to simplify the codes and remove
some duplicate parts.

The following changes are including:
* Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
* Rearranged the mode selection sequence with supported device type
* Adds maximum speed for HS200 mode(hs200_max_dtr)
* Adds field definition for HS_TIMING of EXT_CSD

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/debugfs.c |    2 +-
 drivers/mmc/core/mmc.c     |  431 ++++++++++++++++++++++++--------------------
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/mmc.h    |    4 +
 4 files changed, 238 insertions(+), 200 deletions(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 509229b..1f730db 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -139,7 +139,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 		str = "mmc DDR52";
 		break;
 	case MMC_TIMING_MMC_HS200:
-		str = "mmc high-speed SDR200";
+		str = "mmc HS200";
 		break;
 	default:
 		str = "invalid";
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 480c100..6dd68e6 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -242,7 +242,7 @@ static void mmc_select_card_type(struct mmc_card *card)
 	struct mmc_host *host = card->host;
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
-	unsigned int hs_max_dtr = 0;
+	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
@@ -271,17 +271,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 
 	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
 	}
 
 	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
+	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
 }
 
@@ -833,37 +834,46 @@ static int mmc_select_powerclass(struct mmc_card *card)
 }
 
 /*
- * Selects the desired buswidth and switch to the HS200 mode
- * if bus width set without error
+ * Set the bus speed for the selected speed mode.
  */
-static int mmc_select_hs200(struct mmc_card *card)
+static void mmc_set_bus_speed(struct mmc_card *card)
+{
+	unsigned int max_dtr = (unsigned int)-1;
+
+	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+		max_dtr = card->ext_csd.hs200_max_dtr;
+	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
+		max_dtr = card->ext_csd.hs_max_dtr;
+	else if (max_dtr > card->csd.max_dtr)
+		max_dtr = card->csd.max_dtr;
+
+	mmc_set_clock(card->host, max_dtr);
+}
+
+/*
+ * Select the bus width amoung 4-bit and 8-bit(SDR).
+ * If the bus width is changed successfully, return the slected width value.
+ * Zero is returned instead of error value if the wide width is not supported.
+ */
+static int mmc_select_bus_width(struct mmc_card *card)
 {
-	int idx, err = -EINVAL;
-	struct mmc_host *host;
 	static unsigned ext_csd_bits[] = {
-		EXT_CSD_BUS_WIDTH_4,
 		EXT_CSD_BUS_WIDTH_8,
+		EXT_CSD_BUS_WIDTH_4,
 	};
 	static unsigned bus_widths[] = {
-		MMC_BUS_WIDTH_4,
 		MMC_BUS_WIDTH_8,
+		MMC_BUS_WIDTH_4,
 	};
+	struct mmc_host *host = card->host;
+	unsigned idx, bus_width = 0;
+	int err = 0;
 
-	BUG_ON(!card);
-
-	host = card->host;
-
-	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
-
-	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
-
-	/* If fails try again during next card power cycle */
-	if (err)
-		goto err;
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
+	    !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
+		return 0;
 
-	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
 
 	/*
 	 * Unlike SD, MMC cards dont have a configuration register to notify
@@ -871,8 +881,7 @@ static int mmc_select_hs200(struct mmc_card *card)
 	 * 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 >= 0; idx--) {
-
+	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
@@ -887,27 +896,202 @@ static int mmc_select_hs200(struct mmc_card *card)
 		if (err)
 			continue;
 
-		mmc_set_bus_width(card->host, bus_widths[idx]);
+		bus_width = bus_widths[idx];
+		mmc_set_bus_width(host, bus_width);
 
+		/*
+		 * If controller can't handle bus width test,
+		 * compare ext_csd previously read in 1 bit mode
+		 * against ext_csd at new bus width
+		 */
 		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-			err = mmc_compare_ext_csds(card, bus_widths[idx]);
+			err = mmc_compare_ext_csds(card, bus_width);
 		else
-			err = mmc_bus_test(card, bus_widths[idx]);
-		if (!err)
+			err = mmc_bus_test(card, bus_width);
+
+		if (!err) {
+			err = bus_width;
 			break;
+		} else {
+			pr_warn("%s: switch to bus width %d failed\n",
+				mmc_hostname(host), ext_csd_bits[idx]);
+		}
 	}
 
-	/* switch to HS200 mode if bus width set successfully */
+	return err;
+}
+
+/*
+ * Switch to the high-speed mode
+ */
+static int mmc_select_hs(struct mmc_card *card)
+{
+	int err;
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
 	if (!err)
+		mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+
+	return err;
+}
+
+/*
+ * Activate wide bus and DDR if supported.
+ */
+static int mmc_select_hs_ddr(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	u32 bus_width, ext_csd_bits;
+	int err = 0;
+
+	if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52))
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+		EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_BUS_WIDTH,
+			ext_csd_bits,
+			card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width %d ddr failed\n",
+			mmc_hostname(host), 1 << bus_width);
+		return err;
+	}
+
+	/*
+	 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+	 * signaling.
+	 *
+	 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+	 *
+	 * 1.8V vccq at 3.3V core voltage (vcc) is not required
+	 * in the JEDEC spec for DDR.
+	 *
+	 * Do not force change in vccq since we are obviously
+	 * working and no change to vccq is needed.
+	 *
+	 * WARNING: eMMC rules are NOT the same as SD DDR
+	 */
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		err = __mmc_set_signal_voltage(host,
+				MMC_SIGNAL_VOLTAGE_120);
+		if (err)
+			return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
+
+	return err;
+}
+
+/*
+ * For device supporting HS200 mode, the following sequence
+ * should be done before executing the tuning process.
+ * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
+ * 2. switch to HS200 mode
+ * 3. set the clock to > 52Mhz and <=200MHz
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = -EINVAL;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+
+	/* If fails try again during next card power cycle */
+	if (err)
+		goto err;
+
+	/*
+	 * Set the bus width(4 or 8) with host's support and
+	 * switch to HS200 mode if bus width is set successfully.
+	 */
+	err = mmc_select_bus_width(card);
+	if (!IS_ERR_VALUE(err)) {
 		err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				EXT_CSD_HS_TIMING, 2,
-				card->ext_csd.generic_cmd6_time,
-				true, true, true);
+				   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
+				   card->ext_csd.generic_cmd6_time,
+				   true, true, true);
+		if (!err)
+			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+	}
 err:
 	return err;
 }
 
 /*
+ * Activate High Speed or HS200 mode if supported.
+ */
+static int mmc_select_timing(struct mmc_card *card)
+{
+	int err = 0;
+
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
+	     card->ext_csd.hs_max_dtr == 0))
+		goto bus_speed;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+		err = mmc_select_hs200(card);
+	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
+		err = mmc_select_hs(card);
+
+	if (err && err != -EBADMSG)
+		return err;
+
+	if (err) {
+		pr_warn("%s: switch to %s failed\n",
+			mmc_card_hs(card) ? "high-speed" :
+			(mmc_card_hs200(card) ? "hs200" : ""),
+			mmc_hostname(card->host));
+		err = 0;
+	}
+
+bus_speed:
+	/*
+	 * Set the bus speed to the selected bus timing.
+	 * If timing is not selected, backward compatible is the default.
+	 */
+	mmc_set_bus_speed(card);
+	return err;
+}
+
+/*
+ * Execute tuning sequence to seek the proper bus operating
+ * conditions for HS200, which sends CMD21 to the device.
+ */
+static int mmc_hs200_tuning(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	if (host->ops->execute_tuning) {
+		mmc_host_clk_hold(host);
+		err = host->ops->execute_tuning(host,
+				MMC_SEND_TUNING_BLOCK_HS200);
+		mmc_host_clk_release(host);
+
+		if (err)
+			pr_warn("%s: tuning execution failed\n",
+				mmc_hostname(host));
+	}
+
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -917,9 +1101,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	struct mmc_card *oldcard)
 {
 	struct mmc_card *card;
-	int err, ddr = 0;
+	int err;
 	u32 cid[4];
-	unsigned int max_dtr;
 	u32 rocr;
 	u8 *ext_csd = NULL;
 
@@ -1111,173 +1294,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
-	 * Activate high speed (if supported)
-	 */
-	if (card->ext_csd.hs_max_dtr != 0) {
-		err = 0;
-		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-			err = mmc_select_hs200(card);
-		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
-			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					EXT_CSD_HS_TIMING, 1,
-					card->ext_csd.generic_cmd6_time,
-					true, true, true);
-
-		if (err && err != -EBADMSG)
-			goto free_card;
-
-		if (err) {
-			pr_warning("%s: switch to highspeed failed\n",
-			       mmc_hostname(card->host));
-			err = 0;
-		} else {
-			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-				mmc_set_timing(card->host,
-					       MMC_TIMING_MMC_HS200);
-			else
-				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-		}
-	}
-
-	/*
-	 * Compute bus speed.
-	 */
-	max_dtr = (unsigned int)-1;
-
-	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
-		if (max_dtr > card->ext_csd.hs_max_dtr)
-			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_hs(card) && (max_dtr > 52000000))
-			max_dtr = 52000000;
-	} else if (max_dtr > card->csd.max_dtr) {
-		max_dtr = card->csd.max_dtr;
-	}
-
-	mmc_set_clock(host, max_dtr);
-
-	/*
-	 * Indicate DDR mode (if supported).
+	 * Select timing interface
 	 */
-	if (mmc_card_hs(card))
-		ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	err = mmc_select_timing(card);
+	if (err)
+		goto free_card;
 
-	/*
-	 * Indicate HS200 SDR mode (if supported).
-	 */
 	if (mmc_card_hs200(card)) {
-		u32 ext_csd_bits;
-		u32 bus_width = card->host->ios.bus_width;
-
-		/*
-		 * For devices supporting HS200 mode, the bus width has
-		 * to be set before executing the tuning function. If
-		 * set before tuning, then device will respond with CRC
-		 * errors for responses on CMD line. So for HS200 the
-		 * sequence will be
-		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
-		 * 2. switch to HS200 mode
-		 * 3. set the clock to > 52Mhz <=200MHz and
-		 * 4. execute tuning for HS200
-		 */
-		if (card->host->ops->execute_tuning) {
-			mmc_host_clk_hold(card->host);
-			err = card->host->ops->execute_tuning(card->host,
-				MMC_SEND_TUNING_BLOCK_HS200);
-			mmc_host_clk_release(card->host);
-		}
-		if (err) {
-			pr_warning("%s: tuning execution failed\n",
-				   mmc_hostname(card->host));
+		err = mmc_hs200_tuning(card);
+		if (err)
 			goto err;
-		}
-
-		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
-				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-	}
-
-	/*
-	 * Activate wide bus and DDR (if supported).
-	 */
-	if (!mmc_card_hs200(card) &&
-	    (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
-	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
-		static unsigned ext_csd_bits[][2] = {
-			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
-			{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
-			{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
-		};
-		static unsigned bus_widths[] = {
-			MMC_BUS_WIDTH_8,
-			MMC_BUS_WIDTH_4,
-			MMC_BUS_WIDTH_1
-		};
-		unsigned idx, bus_width = 0;
-
-		if (host->caps & MMC_CAP_8_BIT_DATA)
-			idx = 0;
-		else
-			idx = 1;
-		for (; idx < ARRAY_SIZE(bus_widths); idx++) {
-			bus_width = bus_widths[idx];
-			if (bus_width == MMC_BUS_WIDTH_1)
-				ddr = 0; /* no DDR for 1-bit width */
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][0],
-					 card->ext_csd.generic_cmd6_time);
-			if (!err) {
-				mmc_set_bus_width(card->host, bus_width);
-
-				/*
-				 * If controller can't handle bus width test,
-				 * compare ext_csd previously read in 1 bit mode
-				 * against ext_csd at new bus width
-				 */
-				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					err = mmc_compare_ext_csds(card,
-						bus_width);
-				else
-					err = mmc_bus_test(card, bus_width);
-				if (!err)
-					break;
-			}
-		}
-
-		if (!err && ddr) {
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][1],
-					 card->ext_csd.generic_cmd6_time);
-		}
-		if (err) {
-			pr_warning("%s: switch to bus width %d ddr %d "
-				"failed\n", mmc_hostname(card->host),
-				1 << bus_width, ddr);
-			goto free_card;
-		} else if (ddr) {
-			/*
-			 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
-			 * signaling.
-			 *
-			 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
-			 *
-			 * 1.8V vccq at 3.3V core voltage (vcc) is not required
-			 * in the JEDEC spec for DDR.
-			 *
-			 * Do not force change in vccq since we are obviously
-			 * working and no change to vccq is needed.
-			 *
-			 * WARNING: eMMC rules are NOT the same as SD DDR
-			 */
-			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
-				err = __mmc_set_signal_voltage(host,
-					MMC_SIGNAL_VOLTAGE_120);
-				if (err)
-					goto err;
-			}
-			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
-			mmc_set_bus_width(card->host, bus_width);
+	} else if (mmc_card_hs(card)) {
+		/* Select the desired bus width optionally */
+		err = mmc_select_bus_width(card);
+		if (!IS_ERR_VALUE(err)) {
+			err = mmc_select_hs_ddr(card);
+			if (err)
+				goto err;
 		}
 	}
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c232b10..def6814 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -63,6 +63,7 @@ struct mmc_ext_csd {
 	unsigned int            power_off_longtime;     /* Units: ms */
 	u8			power_off_notification;	/* state */
 	unsigned int		hs_max_dtr;
+	unsigned int		hs200_max_dtr;
 #define MMC_HIGH_26_MAX_DTR	26000000
 #define MMC_HIGH_52_MAX_DTR	52000000
 #define MMC_HIGH_DDR_MAX_DTR	52000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f734c0c..f429f13 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -377,6 +377,10 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
 #define EXT_CSD_SEC_GB_CL_EN	BIT(4)
-- 
1.7.0.4



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

* [PATCH v4 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (7 preceding siblings ...)
  2014-03-26 11:00   ` [PATCH v4 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
@ 2014-03-26 11:00   ` Seungwon Jeon
  2014-04-11 11:33   ` [PATCH v5 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (19 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-26 11:00 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

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: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/bus.c     |    1 +
 drivers/mmc/core/debugfs.c |    3 +
 drivers/mmc/core/mmc.c     |  100 +++++++++++++++++++++++++++++++++++++++++---
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/host.h   |   15 ++++++-
 include/linux/mmc/mmc.h    |    7 +++-
 6 files changed, 119 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index f37e9d6..d2dbf02 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_hs(card) ? "high speed " : ""),
+			mmc_card_hs400(card) ? "HS400 " :
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 1f730db..91eb162 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_MMC_HS200:
 		str = "mmc HS200";
 		break;
+	case MMC_TIMING_MMC_HS400:
+		str = "mmc HS400";
+		break;
 	default:
 		str = "invalid";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 6dd68e6..1a9cd9d 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 static void mmc_select_card_type(struct mmc_card *card)
 {
 	struct mmc_host *host = card->host;
-	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
+	u8 card_type = card->ext_csd.raw_card_type;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
@@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
+	if (caps2 & MMC_CAP2_HS400_1_8V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS400_1_2V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
+	}
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
@@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
 		card->ext_csd.raw_pwr_cl_ddr_52_360 =
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
+		card->ext_csd.raw_pwr_cl_ddr_200_360 =
+			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
 	}
 
 	if (card->ext_csd.rev >= 5) {
@@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
 		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
 			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
 		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
-			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
+		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
+
 	if (err)
 		err = -EINVAL;
 
@@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
 				ext_csd->raw_pwr_cl_52_360 :
 				ext_csd->raw_pwr_cl_ddr_52_360;
 		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
-			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
+			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
+				ext_csd->raw_pwr_cl_ddr_200_360 :
+				ext_csd->raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
 {
 	unsigned int max_dtr = (unsigned int)-1;
 
-	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+	if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
+	     max_dtr > card->ext_csd.hs200_max_dtr)
 		max_dtr = card->ext_csd.hs200_max_dtr;
 	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
 		max_dtr = card->ext_csd.hs_max_dtr;
@@ -993,6 +1013,61 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
 	return err;
 }
 
+static int mmc_select_hs400(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	/*
+	 * The bus width is set to only 8 DDR in HS400 mode
+	 */
+	if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
+	      host->ios.bus_width == MMC_BUS_WIDTH_8))
+		return 0;
+
+	/*
+	 * Before setting BUS_WIDTH for dual data rate operation,
+	 * HS_TIMING must be set to High Speed(0x1)
+	 */
+	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+	mmc_set_bus_speed(card);
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
+	if (err) {
+		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
+			mmc_hostname(host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_DDR_BUS_WIDTH_8,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
+			mmc_hostname(host), err);
+		return err;
+	}
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
+	if (err) {
+		pr_warn("%s: switch to hs400 failed, err:%d\n",
+			 mmc_hostname(host), err);
+		return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+	mmc_set_bus_speed(card);
+
+	return 0;
+}
+
 /*
  * For device supporting HS200 mode, the following sequence
  * should be done before executing the tuning process.
@@ -1025,7 +1100,16 @@ static int mmc_select_hs200(struct mmc_card *card)
 				   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
 				   card->ext_csd.generic_cmd6_time,
 				   true, true, true);
-		if (!err)
+		if (err)
+			goto err;
+
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
+			/*
+			 * Timing should be adjusted to the HS400 target
+			 * operation frequency for tuning process
+			 */
+			mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
+		else
 			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
 	}
 err:
@@ -1070,7 +1154,7 @@ bus_speed:
 
 /*
  * Execute tuning sequence to seek the proper bus operating
- * conditions for HS200, which sends CMD21 to the device.
+ * conditions for HS200 and HS400, which sends CMD21 to the device.
  */
 static int mmc_hs200_tuning(struct mmc_card *card)
 {
@@ -1304,6 +1388,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_hs200_tuning(card);
 		if (err)
 			goto err;
+
+		err = mmc_select_hs400(card);
+		if (err)
+			goto err;
 	} else if (mmc_card_hs(card)) {
 		/* Select the desired bus width optionally */
 		err = mmc_select_bus_width(card);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index def6814..2b24c36 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -110,6 +110,7 @@ struct mmc_ext_csd {
 	u8			raw_pwr_cl_200_360;	/* 237 */
 	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
 	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
+	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
 	u8			raw_bkops_status;	/* 246 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 1ee3c10..cc716e4 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -61,6 +61,8 @@ struct mmc_ios {
 #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_HS400_TUNING 11
 
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
@@ -274,6 +276,10 @@ struct mmc_host {
 #define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
 				 MMC_CAP2_PACKED_WR)
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
+#define MMC_CAP2_HS400_1_8V	(1 << 15)	/* Can support HS400 1.8V */
+#define MMC_CAP2_HS400_1_2V	(1 << 16)	/* Can support HS400 1.2V */
+#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
+				 MMC_CAP2_HS400_1_2V)
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
@@ -486,11 +492,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
 
 static inline bool mmc_card_hs200(struct mmc_card *card)
 {
-	return card->host->ios.timing == MMC_TIMING_MMC_HS200;
+	return card->host->ios.timing == MMC_TIMING_MMC_HS200 ||
+		card->host->ios.timing == MMC_TIMING_MMC_HS400_TUNING;
 }
 
 static inline bool mmc_card_ddr52(struct mmc_card *card)
 {
 	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
 }
+
+static inline bool mmc_card_hs400(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
+}
+
 #endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f429f13..64ec963 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -325,6 +325,7 @@ struct _mmc_csd {
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
 #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
 #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
 #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
@@ -354,7 +355,6 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
 #define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
@@ -370,6 +370,10 @@ struct _mmc_csd {
 						/* SDR mode @1.2V I/O */
 #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	(1<<6)	/* Card can run at 200MHz DDR, 1.8V */
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
@@ -380,6 +384,7 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
-- 
1.7.0.4



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

* Re: [PATCH v2 2/5] mmc: identify available device type to select
  2014-03-14  2:49       ` Seungwon Jeon
  2014-03-14  7:34         ` Ulf Hansson
@ 2014-03-28  8:31         ` Ulf Hansson
  2014-03-28 12:27           ` Seungwon Jeon
  1 sibling, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-03-28  8:31 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 14 March 2014 03:49, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> On Thu, March 13, 2014, Ulf Hansson wrote:
>> On 7 March 2014 15:36, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> > Device types which are supported by both host and device
>> > can be identified when EXT_CSD is read. There is no need to
>> > check host's capability anymore.
>> >
>> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> > ---
>> > Changes in v2:
>> >         Just rebased with latest one.
>> >
>> >  drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
>> >  include/linux/mmc/card.h |    6 ++-
>> >  include/linux/mmc/host.h |    6 ---
>> >  include/linux/mmc/mmc.h  |   12 +++++--
>> >  4 files changed, 56 insertions(+), 45 deletions(-)
>> >
>> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> > index db9655f..0abece0 100644
>> > --- a/drivers/mmc/core/mmc.c
>> > +++ b/drivers/mmc/core/mmc.c
>> > @@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
>> >         u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>> >         u32 caps = host->caps, caps2 = host->caps2;
>> >         unsigned int hs_max_dtr = 0;
>> > +       unsigned int avail_type = 0;
>> >
>> > -       if (card_type & EXT_CSD_CARD_TYPE_26)
>> > +       if (caps & MMC_CAP_MMC_HIGHSPEED &&
>> > +           card_type & EXT_CSD_CARD_TYPE_HS_26) {
>> >                 hs_max_dtr = MMC_HIGH_26_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_HS_26;
>> > +       }
>> >
>> >         if (caps & MMC_CAP_MMC_HIGHSPEED &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_52)
>> > +           card_type & EXT_CSD_CARD_TYPE_HS_52) {
>> >                 hs_max_dtr = MMC_HIGH_52_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_HS_52;
>> > +       }
>> >
>> > -       if ((caps & MMC_CAP_1_8V_DDR &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
>> > -           (caps & MMC_CAP_1_2V_DDR &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
>> > +       if (caps & MMC_CAP_1_8V_DDR &&
>> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
>> >                 hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
>> > +       }
>> >
>> > -       if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
>> > -           (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
>> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
>> > +       if (caps & MMC_CAP_1_2V_DDR &&
>> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
>> > +               hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
>> > +       }
>> > +
>> > +       if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
>> > +           card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
>> >                 hs_max_dtr = MMC_HS200_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
>> > +       }
>> > +
>> > +       if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
>> > +           card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
>> > +               hs_max_dtr = MMC_HS200_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>> > +       }
>> >
>> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
>> > -       card->ext_csd.card_type = card_type;
>> > +       card->mmc_avail_type = avail_type;
>> >  }
>> >
>> >  /*
>> > @@ -708,6 +726,11 @@ static struct device_type mmc_type = {
>> >         .groups = mmc_attr_groups,
>> >  };
>> >
>> > +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
>> > +{
>> > +       return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
>> > +}
>> > +
>>
>> Having a separate function for this seem a bit silly. Similar checks
>> is performed all over the code. I suggest you remove this.
> I understand your meaning.
> Yes, actually similar checking card type is done.
> But checking DDR type is required several times unlike other type case.
> I considered for that. I think it's pretty useful in terms of avoiding duplication and enhancement of readability.
>
>>
>> >  /*
>> >   * Select the PowerClass for the current bus width
>> >   * If power class is defined for 4/8 bit bus in the
>> > @@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
>> >
>> >         host = card->host;
>> >
>> > -       if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
>> > -                       host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
>> > +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
>> >                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
>> >
>> > -       if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
>> > -                       host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
>> > +       if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
>> >                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
>> >
>> >         /* If fails try again during next card power cycle */
>> > @@ -1072,10 +1093,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >          */
>> >         if (card->ext_csd.hs_max_dtr != 0) {
>> >                 err = 0;
>> > -               if (card->ext_csd.hs_max_dtr > 52000000 &&
>> > -                   host->caps2 & MMC_CAP2_HS200)
>> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>> >                         err = mmc_select_hs200(card);
>> > -               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
>> > +               else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>> >                         err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >                                         EXT_CSD_HS_TIMING, 1,
>> >                                         card->ext_csd.generic_cmd6_time,
>> > @@ -1089,13 +1109,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >                                mmc_hostname(card->host));
>> >                         err = 0;
>> >                 } else {
>> > -                       if (card->ext_csd.hs_max_dtr > 52000000 &&
>> > -                           host->caps2 & MMC_CAP2_HS200) {
>> > +                       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>> >                                 mmc_set_timing(card->host,
>> >                                                MMC_TIMING_MMC_HS200);
>> > -                       } else {
>> > +                       else
>> >                                 mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> > -                       }
>> >                 }
>> >         }
>> >
>> > @@ -1118,14 +1136,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >         /*
>> >          * Indicate DDR mode (if supported).
>> >          */
>> > -       if (mmc_card_hs(card)) {
>> > -               if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
>> > -                       && (host->caps & MMC_CAP_1_8V_DDR))
>> > -                               ddr = MMC_1_8V_DDR_MODE;
>> > -               else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
>> > -                       && (host->caps & MMC_CAP_1_2V_DDR))
>> > -                               ddr = MMC_1_2V_DDR_MODE;
>> > -       }
>> > +       if (mmc_card_hs(card))
>> > +               ddr = mmc_snoop_ddr(card);
>> >
>> >         /*
>> >          * Indicate HS200 SDR mode (if supported).
>> > @@ -1145,8 +1157,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >                  * 3. set the clock to > 52Mhz <=200MHz and
>> >                  * 4. execute tuning for HS200
>> >                  */
>> > -               if ((host->caps2 & MMC_CAP2_HS200) &&
>> > -                   card->host->ops->execute_tuning) {
>> > +               if (card->host->ops->execute_tuning) {
>> >                         mmc_host_clk_hold(card->host);
>> >                         err = card->host->ops->execute_tuning(card->host,
>> >                                 MMC_SEND_TUNING_BLOCK_HS200);
>> > @@ -1255,7 +1266,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >                          *
>> >                          * WARNING: eMMC rules are NOT the same as SD DDR
>> >                          */
>> > -                       if (ddr == MMC_1_2V_DDR_MODE) {
>> > +                       if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
>> >                                 err = __mmc_set_signal_voltage(host,
>> >                                         MMC_SIGNAL_VOLTAGE_120);
>> >                                 if (err)
>> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> > index 5473133..c232b10 100644
>> > --- a/include/linux/mmc/card.h
>> > +++ b/include/linux/mmc/card.h
>> > @@ -68,7 +68,6 @@ struct mmc_ext_csd {
>> >  #define MMC_HIGH_DDR_MAX_DTR   52000000
>> >  #define MMC_HS200_MAX_DTR      200000000
>> >         unsigned int            sectors;
>> > -       unsigned int            card_type;
>> >         unsigned int            hc_erase_size;          /* In sectors */
>> >         unsigned int            hc_erase_timeout;       /* In milliseconds */
>> >         unsigned int            sec_trim_mult;  /* Secure trim multiplier  */
>> > @@ -297,7 +296,10 @@ struct mmc_card {
>> >         const char              **info;         /* info strings */
>> >         struct sdio_func_tuple  *tuples;        /* unknown common tuples */
>> >
>> > -       unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
>> > +       union {
>> > +               unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
>> > +               unsigned int            mmc_avail_type; /* supported device type by both host and card */
>>
>> Using a union here won't be that much of a gain since there are only
>> few instances of the struct. Please remove.
> Yes, you're right. It's not much in gain.
> I intended to distinguish these two similar members respectively.
> It's used only in each specific type domain and not used at the same time.
> If no meaningful, I can remove as your suggestion.

Hi Seungwon,

I noticed in your latest version if this patch the "union" declaration
is still there. Could you please update and send a new version.

Kind regards
Ulf Hansson

>
> Thanks,
> Seungwon Jeon
>
>>
>> > +       };
>> >
>> >         struct dentry           *debugfs_root;
>> >         struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
>> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> > index 2f263ae..1ee3c10 100644
>> > --- a/include/linux/mmc/host.h
>> > +++ b/include/linux/mmc/host.h
>> > @@ -62,12 +62,6 @@ struct mmc_ios {
>> >  #define MMC_TIMING_MMC_DDR52   8
>> >  #define MMC_TIMING_MMC_HS200   9
>> >
>> > -#define MMC_SDR_MODE           0
>> > -#define MMC_1_2V_DDR_MODE      1
>> > -#define MMC_1_8V_DDR_MODE      2
>> > -#define MMC_1_2V_SDR_MODE      3
>> > -#define MMC_1_8V_SDR_MODE      4
>> > -
>> >         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
>> >
>> >  #define MMC_SIGNAL_VOLTAGE_330 0
>> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> > index 50bcde3..f734c0c 100644
>> > --- a/include/linux/mmc/mmc.h
>> > +++ b/include/linux/mmc/mmc.h
>> > @@ -354,18 +354,22 @@ struct _mmc_csd {
>> >  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
>> >  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
>> >
>> > -#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_MASK 0x3F    /* Mask out reserved bits */
>> > +#define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
>> > +#define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
>> > +#define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
>> > +                                EXT_CSD_CARD_TYPE_HS_52)
>> >  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
>> >                                              /* DDR mode @1.8V or 3V I/O */
>> >  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
>> >                                              /* DDR mode @1.2V I/O */
>> >  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
>> >                                         | EXT_CSD_CARD_TYPE_DDR_1_2V)
>> > -#define EXT_CSD_CARD_TYPE_SDR_1_8V     (1<<4)  /* Card can run at 200MHz */
>> > -#define EXT_CSD_CARD_TYPE_SDR_1_2V     (1<<5)  /* Card can run at 200MHz */
>> > +#define EXT_CSD_CARD_TYPE_HS200_1_8V   (1<<4)  /* Card can run at 200MHz */
>> > +#define EXT_CSD_CARD_TYPE_HS200_1_2V   (1<<5)  /* Card can run at 200MHz */
>> >                                                 /* SDR mode @1.2V I/O */
>> > +#define EXT_CSD_CARD_TYPE_HS200                (EXT_CSD_CARD_TYPE_HS200_1_8V | \
>> > +                                        EXT_CSD_CARD_TYPE_HS200_1_2V)
>> >
>> >  #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>> >  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
>> > --
>> > 1.7.0.4
>> >
>> >
>>
>> Besides the minor stuff, looks good.
>>
>> Kind regards
>> Ulf Hansson
>

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

* Re: [PATCH v4 3/5] mmc: step power class after final selection of bus mode
  2014-03-26 11:00   ` [PATCH v4 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
@ 2014-03-28  8:43     ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-03-28  8:43 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 26 March 2014 12:00, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Power class is changed once only after selection of bus modes
> including speed and bus-width finishes finally.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>

Acked-by: Ulf Hansson <ulf.hansson@linaro.org>

> ---
>  drivers/mmc/core/mmc.c |   96 +++++++++++++++++++++++++++--------------------
>  1 files changed, 55 insertions(+), 41 deletions(-)
>
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 97f1912..480c100 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -732,17 +732,13 @@ static struct device_type mmc_type = {
>   * extended CSD register, select it by executing the
>   * mmc_switch command.
>   */
> -static int mmc_select_powerclass(struct mmc_card *card,
> -               unsigned int bus_width)
> +static int __mmc_select_powerclass(struct mmc_card *card,
> +                                  unsigned int bus_width)
>  {
> -       int err = 0;
> +       struct mmc_host *host = card->host;
> +       struct mmc_ext_csd *ext_csd = &card->ext_csd;
>         unsigned int pwrclass_val = 0;
> -       struct mmc_host *host;
> -
> -       BUG_ON(!card);
> -
> -       host = card->host;
> -       BUG_ON(!host);
> +       int err = 0;
>
>         /* Power class selection is supported for versions >= 4.0 */
>         if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
> @@ -754,14 +750,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
>
>         switch (1 << host->ios.vdd) {
>         case MMC_VDD_165_195:
> -               if (host->ios.clock <= 26000000)
> -                       pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
> -               else if (host->ios.clock <= 52000000)
> +               if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
> +                       pwrclass_val = ext_csd->raw_pwr_cl_26_195;
> +               else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
>                         pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
> -                               card->ext_csd.raw_pwr_cl_52_195 :
> -                               card->ext_csd.raw_pwr_cl_ddr_52_195;
> -               else if (host->ios.clock <= 200000000)
> -                       pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
> +                               ext_csd->raw_pwr_cl_52_195 :
> +                               ext_csd->raw_pwr_cl_ddr_52_195;
> +               else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> +                       pwrclass_val = ext_csd->raw_pwr_cl_200_195;
>                 break;
>         case MMC_VDD_27_28:
>         case MMC_VDD_28_29:
> @@ -772,14 +768,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
>         case MMC_VDD_33_34:
>         case MMC_VDD_34_35:
>         case MMC_VDD_35_36:
> -               if (host->ios.clock <= 26000000)
> -                       pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
> -               else if (host->ios.clock <= 52000000)
> +               if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
> +                       pwrclass_val = ext_csd->raw_pwr_cl_26_360;
> +               else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
>                         pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
> -                               card->ext_csd.raw_pwr_cl_52_360 :
> -                               card->ext_csd.raw_pwr_cl_ddr_52_360;
> -               else if (host->ios.clock <= 200000000)
> -                       pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
> +                               ext_csd->raw_pwr_cl_52_360 :
> +                               ext_csd->raw_pwr_cl_ddr_52_360;
> +               else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> +                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
>                 break;
>         default:
>                 pr_warning("%s: Voltage range not supported "
> @@ -805,6 +801,37 @@ static int mmc_select_powerclass(struct mmc_card *card,
>         return err;
>  }
>
> +static int mmc_select_powerclass(struct mmc_card *card)
> +{
> +       struct mmc_host *host = card->host;
> +       u32 bus_width, ext_csd_bits;
> +       int err, ddr;
> +
> +       /* Power class selection is supported for versions >= 4.0 */
> +       if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
> +               return 0;
> +
> +       bus_width = host->ios.bus_width;
> +       /* Power class values are defined only for 4/8 bit bus */
> +       if (bus_width == MMC_BUS_WIDTH_1)
> +               return 0;
> +
> +       ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> +       if (ddr)
> +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> +                       EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
> +       else
> +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> +                       EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
> +
> +       err = __mmc_select_powerclass(card, ext_csd_bits);
> +       if (err)
> +               pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
> +                       mmc_hostname(host), 1 << bus_width, ddr);
> +
> +       return err;
> +}
> +
>  /*
>   * Selects the desired buswidth and switch to the HS200 mode
>   * if bus width set without error
> @@ -1166,11 +1193,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>
>                 ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
>                                 EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
> -               err = mmc_select_powerclass(card, ext_csd_bits);
> -               if (err)
> -                       pr_warning("%s: power class selection to bus width %d"
> -                                  " failed\n", mmc_hostname(card->host),
> -                                  1 << bus_width);
>         }
>
>         /*
> @@ -1199,12 +1221,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                         bus_width = bus_widths[idx];
>                         if (bus_width == MMC_BUS_WIDTH_1)
>                                 ddr = 0; /* no DDR for 1-bit width */
> -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
> -                       if (err)
> -                               pr_warning("%s: power class selection to "
> -                                          "bus width %d failed\n",
> -                                          mmc_hostname(card->host),
> -                                          1 << bus_width);
>
>                         err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>                                          EXT_CSD_BUS_WIDTH,
> @@ -1229,13 +1245,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                 }
>
>                 if (!err && ddr) {
> -                       err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
> -                       if (err)
> -                               pr_warning("%s: power class selection to "
> -                                          "bus width %d ddr %d failed\n",
> -                                          mmc_hostname(card->host),
> -                                          1 << bus_width, ddr);
> -
>                         err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>                                          EXT_CSD_BUS_WIDTH,
>                                          ext_csd_bits[idx][1],
> @@ -1273,6 +1282,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>         }
>
>         /*
> +        * Choose the power class with selected bus interface
> +        */
> +       mmc_select_powerclass(card);
> +
> +       /*
>          * Enable HPI feature (if supported)
>          */
>         if (card->ext_csd.hpi) {
> --
> 1.7.0.4
>
>

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

* Re: [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-03-25  9:23       ` Seungwon Jeon
@ 2014-03-28  9:57         ` Ulf Hansson
  2014-03-28 12:18           ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-03-28  9:57 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 25 March 2014 10:23, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Hi Ulf,
>
> On Tue, March 25, 2014, Ulf Hansson wrote:
>> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> > 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: Seungwon Jeon <tgih.jun@samsung.com>
>> > Reviewed-by: Jackey Shen <jackey.shen@amd.com>
>> > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
>> > Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
>> > ---
>> >  drivers/mmc/core/bus.c     |    1 +
>> >  drivers/mmc/core/debugfs.c |    3 +
>> >  drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
>> >  include/linux/mmc/card.h   |    1 +
>> >  include/linux/mmc/host.h   |   15 +++++-
>> >  include/linux/mmc/mmc.h    |    7 ++-
>> >  6 files changed, 134 insertions(+), 8 deletions(-)
>> >
>> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> > index f37e9d6..d2dbf02 100644
>> > --- a/drivers/mmc/core/bus.c
>> > +++ b/drivers/mmc/core/bus.c
>> > @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
>> >                         mmc_hostname(card->host),
>> >                         mmc_card_uhs(card) ? "ultra high speed " :
>> >                         (mmc_card_hs(card) ? "high speed " : ""),
>> > +                       mmc_card_hs400(card) ? "HS400 " :
>> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
>> >                         mmc_card_ddr52(card) ? "DDR " : "",
>> >                         uhs_bus_speed_mode, type, card->rca);
>> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
>> > index 1f730db..91eb162 100644
>> > --- a/drivers/mmc/core/debugfs.c
>> > +++ b/drivers/mmc/core/debugfs.c
>> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>> >         case MMC_TIMING_MMC_HS200:
>> >                 str = "mmc HS200";
>> >                 break;
>> > +       case MMC_TIMING_MMC_HS400:
>> > +               str = "mmc HS400";
>> > +               break;
>> >         default:
>> >                 str = "invalid";
>> >                 break;
>> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> > index 6dd68e6..969d595 100644
>> > --- a/drivers/mmc/core/mmc.c
>> > +++ b/drivers/mmc/core/mmc.c
>> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
>> >  static void mmc_select_card_type(struct mmc_card *card)
>> >  {
>> >         struct mmc_host *host = card->host;
>> > -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>> > +       u8 card_type = card->ext_csd.raw_card_type;
>> >         u32 caps = host->caps, caps2 = host->caps2;
>> >         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>> >         unsigned int avail_type = 0;
>> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
>> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>> >         }
>> >
>> > +       if (caps2 & MMC_CAP2_HS400_1_8V &&
>> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
>> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
>> > +       }
>> > +
>> > +       if (caps2 & MMC_CAP2_HS400_1_2V &&
>> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
>> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>> > +       }
>> > +
>> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
>> >         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>> >         card->mmc_avail_type = avail_type;
>> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
>> >                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
>> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
>> > +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
>> > +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
>> >         }
>> >
>> >         if (card->ext_csd.rev >= 5) {
>> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
>> >                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
>> >                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
>> >                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
>> > -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
>> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
>> > +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
>> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
>> > +
>> >         if (err)
>> >                 err = -EINVAL;
>> >
>> > @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
>> >                                 ext_csd->raw_pwr_cl_52_360 :
>> >                                 ext_csd->raw_pwr_cl_ddr_52_360;
>> >                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
>> > -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
>> > +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
>> > +                               ext_csd->raw_pwr_cl_ddr_200_360 :
>> > +                               ext_csd->raw_pwr_cl_200_360;
>> >                 break;
>> >         default:
>> >                 pr_warning("%s: Voltage range not supported "
>> > @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
>> >  {
>> >         unsigned int max_dtr = (unsigned int)-1;
>> >
>> > -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
>> > +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
>> > +            max_dtr > card->ext_csd.hs200_max_dtr)
>> >                 max_dtr = card->ext_csd.hs200_max_dtr;
>> >         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
>> >                 max_dtr = card->ext_csd.hs_max_dtr;
>> > @@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
>> >  }
>> >
>> >  /*
>> > + * Revert to the high-speed mode from above speed
>> > + */
>> > +static int mmc_revert_to_hs(struct mmc_card *card)
>> > +{
>> > +       /*
>> > +        * CMD13, which is used to confirm the completion of timing
>> > +        * change, will be issued at higher speed timing condtion
>> > +        * rather than high-speed. If device has completed the change
>> > +        * to high-speed mode, it may not be proper timing to issue
>> > +        * command. Low speed supplies better timing margin than high
>> > +        * speed. Accordingly clock rate & timging should be chagned
>> > +        * ahead before actual switch.
>>
>> I have some problem to understand this comment. I guess you are trying
>> to provide the arguments to why it makes sense to perform the revert
>> to lower speed mode!?
>>
>> This makes me wonder if this is not part of the spec? Could you try to clarify?
> But specification says that "HS_TIMING must be set to "0x1" before setting BUS_WIDTH for dual data rate operation".
> I think this sequence is not graceful.
> I also commented why speed mode should be changed to high-speed mode from HS200 mode in the function-called part.
> Because it is not possible to set 8-bit data bus for dual rate on HS200 mode, revert to high-speed from HS200 is needed.
> If the above-commented point makes it confused, it could be removed.
> Please let me know your opinion.
>
>>
>> > +        */
>> > +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> > +       mmc_set_bus_speed(card);
>> > +
>> > +       return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> > +                         EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
>> > +                         card->ext_csd.generic_cmd6_time);
>> > +}
>> > +
>> > +/*
>> >   * Activate wide bus and DDR if supported.
>> >   */
>> >  static int mmc_select_hs_ddr(struct mmc_card *card)
>> > @@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
>> >         return err;
>> >  }
>> >
>> > +static int mmc_select_hs400(struct mmc_card *card)
>> > +{
>> > +       struct mmc_host *host = card->host;
>> > +       int err = 0;
>> > +
>> > +       /*
>> > +        * The bus width is set to only 8 DDR in HS400 mode
>>
>> Please rephrase the comment to something like:
>> "HS400 mode requires 8-bit bus width."
> As it is, it was from spec's description.
> But I think yours would be more clearable.
>
>>
>> > +        */
>> > +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
>> > +             host->ios.bus_width == MMC_BUS_WIDTH_8))
>> > +               return 0;
>> > +
>> > +       /*
>> > +        * Before setting BUS_WIDTH for dual data rate operation,
>> > +        * HS_TIMING must be set to High Speed(0x1)
>> > +        */
>>
>> Please rephrase comment:
>>
>> "Before switching to dual data rate operation for HS400, we need
>> revert from HS200 timing to regular HS timing."
> Ok.
>
>>
>> > +       err = mmc_revert_to_hs(card);
>>
>> I don't think we need a separate function to handle the revert.
>> Please, just add the code here instead. While you do that, I suppose
>> we should combine the comment in that function into one comment here.
> OK, I don't oppose that.
>
>>
>> > +       if (err) {
>> > +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
>> > +                       mmc_hostname(host), err);
>> > +               return err;
>> > +       }
>> > +
>> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> > +                        EXT_CSD_BUS_WIDTH,
>> > +                        EXT_CSD_DDR_BUS_WIDTH_8,
>> > +                        card->ext_csd.generic_cmd6_time);
>> > +       if (err) {
>> > +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
>> > +                       mmc_hostname(host), err);
>> > +               return err;
>> > +       }
>> > +
>> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
>> > +                        card->ext_csd.generic_cmd6_time);
>> > +       if (err) {
>> > +               pr_warn("%s: switch to hs400 failed, err:%d\n",
>> > +                        mmc_hostname(host), err);
>> > +               return err;
>> > +       }
>> > +
>> > +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>> > +       mmc_set_bus_speed(card);
>> > +
>> > +       return 0;
>> > +}
>> > +
>> >  /*
>> >   * For device supporting HS200 mode, the following sequence
>> >   * should be done before executing the tuning process.
>> > @@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
>> >                                    EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
>> >                                    card->ext_csd.generic_cmd6_time,
>> >                                    true, true, true);
>> > -               if (!err)
>> > +               if (err)
>> > +                       goto err;
>> > +
>> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
>> > +                       /*
>> > +                        * Timing should be adjusted to the HS400 target
>> > +                        * operation frequency for tuning process
>> > +                        */
>> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
>>
>> This seems strange. Do we really need a separate
>> MMC_TIMING_MMC_HS400_TUNING value?
> Spec. describes the HS400 selection sequence like below.
> <Quot>
> ...
> 6) Perform the Tuning Process at the HS400 target operating frequency
> (Note: tuning process in HS200 mode is required to synchronize the command response on the CMD line to CLK for HS400 operation).
> ...
> </Quot>
> That means target clock rate for tuning sequence can be different with HS200.
> Considering for that, it needs to distinguish.

I understand the spec now, thanks.

Still, I am not convinced we should handle this through the
MMC_TIMING* field. That will leave host drivers to do some magic clock
frequency calculation from their ->set_ios callbacks, just depending
on the MMC_TIMING_MMC_HS400_TUNING value.

I am also a bit concerned how MMC_TIMING_MMC_HS400_TUNING, would work
if/when we implement periodic re-tuning - triggered from the mmc core
layer.

What we really want to do, is to pretend we were to operate in
MMC_TIMING_MMC_HS400 and ask the host driver what the target frequency
would be in this case. Then set this frequency through
mmc_set_clock().

Then how do we ask the host driver about this frequency? Let's add a
new host_ops callback. We want it to be generic, so provide the
MMC_TIMING bit as a parameter. Additionally we want it to be optional
to implement, thus for those host drivers that supports the same
target frequency for HS200 as for HS400, they don't need to implement
it.

Would this be a way forward?

Kind regards
Ulf Hansson

>
>>
>> > +               else
>> >                         mmc_set_timing(host, MMC_TIMING_MMC_HS200);
>> >         }
>> >  err:
>> > @@ -1070,7 +1169,7 @@ bus_speed:
>> >
>> >  /*
>> >   * Execute tuning sequence to seek the proper bus operating
>> > - * conditions for HS200, which sends CMD21 to the device.
>> > + * conditions for HS200 and HS400, which sends CMD21 to the device.
>> >   */
>> >  static int mmc_hs200_tuning(struct mmc_card *card)
>> >  {
>> > @@ -1304,6 +1403,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >                 err = mmc_hs200_tuning(card);
>> >                 if (err)
>> >                         goto err;
>> > +
>> > +               err = mmc_select_hs400(card);
>> > +               if (err)
>> > +                       goto err;
>> >         } else if (mmc_card_hs(card)) {
>> >                 /* Select the desired bus width optionally */
>> >                 err = mmc_select_bus_width(card);
>> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> > index def6814..2b24c36 100644
>> > --- a/include/linux/mmc/card.h
>> > +++ b/include/linux/mmc/card.h
>> > @@ -110,6 +110,7 @@ struct mmc_ext_csd {
>> >         u8                      raw_pwr_cl_200_360;     /* 237 */
>> >         u8                      raw_pwr_cl_ddr_52_195;  /* 238 */
>> >         u8                      raw_pwr_cl_ddr_52_360;  /* 239 */
>> > +       u8                      raw_pwr_cl_ddr_200_360; /* 253 */
>> >         u8                      raw_bkops_status;       /* 246 */
>> >         u8                      raw_sectors[4];         /* 212 - 4 bytes */
>> >
>> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> > index 1ee3c10..cc716e4 100644
>> > --- a/include/linux/mmc/host.h
>> > +++ b/include/linux/mmc/host.h
>> > @@ -61,6 +61,8 @@ struct mmc_ios {
>> >  #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_HS400_TUNING 11
>>
>> MMC_TIMING_MMC_HS400_TUNING ?
>>
>> >
>> >         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
>> >
>> > @@ -274,6 +276,10 @@ struct mmc_host {
>> >  #define MMC_CAP2_PACKED_CMD    (MMC_CAP2_PACKED_RD | \
>> >                                  MMC_CAP2_PACKED_WR)
>> >  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)  /* Don't power up before scan */
>> > +#define MMC_CAP2_HS400_1_8V    (1 << 15)       /* Can support HS400 1.8V */
>> > +#define MMC_CAP2_HS400_1_2V    (1 << 16)       /* Can support HS400 1.2V */
>> > +#define MMC_CAP2_HS400         (MMC_CAP2_HS400_1_8V | \
>> > +                                MMC_CAP2_HS400_1_2V)
>> >
>> >         mmc_pm_flag_t           pm_caps;        /* supported pm features */
>> >
>> > @@ -486,11 +492,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
>> >
>> >  static inline bool mmc_card_hs200(struct mmc_card *card)
>> >  {
>> > -       return card->host->ios.timing == MMC_TIMING_MMC_HS200;
>> > +       return card->host->ios.timing == MMC_TIMING_MMC_HS200 ||
>> > +               card->host->ios.timing == MMC_TIMING_MMC_HS400_TUNING;
>>
>> MMC_TIMING_MMC_HS400_TUNING ?
> It also indicates that card is currently in HS200 mode with the result of setting HS_TIMING'.
>
> Thanks,
> Seungwon Jeon
>
>>
>> >  }
>> >
>> >  static inline bool mmc_card_ddr52(struct mmc_card *card)
>> >  {
>> >         return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
>> >  }
>> > +
>> > +static inline bool mmc_card_hs400(struct mmc_card *card)
>> > +{
>> > +       return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>> > +}
>> > +
>> >  #endif /* LINUX_MMC_HOST_H */
>> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> > index f429f13..64ec963 100644
>> > --- a/include/linux/mmc/mmc.h
>> > +++ b/include/linux/mmc/mmc.h
>> > @@ -325,6 +325,7 @@ struct _mmc_csd {
>> >  #define EXT_CSD_POWER_OFF_LONG_TIME    247     /* RO */
>> >  #define EXT_CSD_GENERIC_CMD6_TIME      248     /* RO */
>> >  #define EXT_CSD_CACHE_SIZE             249     /* RO, 4 bytes */
>> > +#define EXT_CSD_PWR_CL_DDR_200_360     253     /* RO */
>> >  #define EXT_CSD_TAG_UNIT_SIZE          498     /* RO */
>> >  #define EXT_CSD_DATA_TAG_SUPPORT       499     /* RO */
>> >  #define EXT_CSD_MAX_PACKED_WRITES      500     /* RO */
>> > @@ -354,7 +355,6 @@ struct _mmc_csd {
>> >  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
>> >  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
>> >
>> > -#define EXT_CSD_CARD_TYPE_MASK 0x3F    /* Mask out reserved bits */
>> >  #define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
>> >  #define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
>> >  #define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
>> > @@ -370,6 +370,10 @@ struct _mmc_csd {
>> >                                                 /* SDR mode @1.2V I/O */
>> >  #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   (1<<6)  /* Card can run at 200MHz DDR, 1.8V */
>> > +#define EXT_CSD_CARD_TYPE_HS400_1_2V   (1<<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_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>> >  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
>> > @@ -380,6 +384,7 @@ struct _mmc_csd {
>> >  #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_SEC_ER_EN      BIT(0)
>> >  #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
>> > --
>> > 1.7.0.4
>> >
>> >
>>
>> Kind regards
>> Ulf Hansson
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

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

* RE: [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-03-28  9:57         ` Ulf Hansson
@ 2014-03-28 12:18           ` Seungwon Jeon
  2014-03-28 13:33             ` Ulf Hansson
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-28 12:18 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On Fri, March 28, 2014, Ulf Hansson wrote:
> On 25 March 2014 10:23, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Hi Ulf,
> >
> > On Tue, March 25, 2014, Ulf Hansson wrote:
> >> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> > 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: Seungwon Jeon <tgih.jun@samsung.com>
> >> > Reviewed-by: Jackey Shen <jackey.shen@amd.com>
> >> > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
> >> > Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
> >> > ---
> >> >  drivers/mmc/core/bus.c     |    1 +
> >> >  drivers/mmc/core/debugfs.c |    3 +
> >> >  drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
> >> >  include/linux/mmc/card.h   |    1 +
> >> >  include/linux/mmc/host.h   |   15 +++++-
> >> >  include/linux/mmc/mmc.h    |    7 ++-
> >> >  6 files changed, 134 insertions(+), 8 deletions(-)
> >> >
> >> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> >> > index f37e9d6..d2dbf02 100644
> >> > --- a/drivers/mmc/core/bus.c
> >> > +++ b/drivers/mmc/core/bus.c
> >> > @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
> >> >                         mmc_hostname(card->host),
> >> >                         mmc_card_uhs(card) ? "ultra high speed " :
> >> >                         (mmc_card_hs(card) ? "high speed " : ""),
> >> > +                       mmc_card_hs400(card) ? "HS400 " :
> >> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
> >> >                         mmc_card_ddr52(card) ? "DDR " : "",
> >> >                         uhs_bus_speed_mode, type, card->rca);
> >> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> >> > index 1f730db..91eb162 100644
> >> > --- a/drivers/mmc/core/debugfs.c
> >> > +++ b/drivers/mmc/core/debugfs.c
> >> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
> >> >         case MMC_TIMING_MMC_HS200:
> >> >                 str = "mmc HS200";
> >> >                 break;
> >> > +       case MMC_TIMING_MMC_HS400:
> >> > +               str = "mmc HS400";
> >> > +               break;
> >> >         default:
> >> >                 str = "invalid";
> >> >                 break;
> >> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >> > index 6dd68e6..969d595 100644
> >> > --- a/drivers/mmc/core/mmc.c
> >> > +++ b/drivers/mmc/core/mmc.c
> >> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
> >> >  static void mmc_select_card_type(struct mmc_card *card)
> >> >  {
> >> >         struct mmc_host *host = card->host;
> >> > -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> >> > +       u8 card_type = card->ext_csd.raw_card_type;
> >> >         u32 caps = host->caps, caps2 = host->caps2;
> >> >         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
> >> >         unsigned int avail_type = 0;
> >> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
> >> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> >> >         }
> >> >
> >> > +       if (caps2 & MMC_CAP2_HS400_1_8V &&
> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> >> > +       }
> >> > +
> >> > +       if (caps2 & MMC_CAP2_HS400_1_2V &&
> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> >> > +       }
> >> > +
> >> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
> >> >         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
> >> >         card->mmc_avail_type = avail_type;
> >> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
> >> >                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> >> > +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
> >> > +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
> >> >         }
> >> >
> >> >         if (card->ext_csd.rev >= 5) {
> >> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
> >> >                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> >> > -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> >> > +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> >> > +
> >> >         if (err)
> >> >                 err = -EINVAL;
> >> >
> >> > @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> >> >                                 ext_csd->raw_pwr_cl_52_360 :
> >> >                                 ext_csd->raw_pwr_cl_ddr_52_360;
> >> >                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> >> > -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
> >> > +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> >> > +                               ext_csd->raw_pwr_cl_ddr_200_360 :
> >> > +                               ext_csd->raw_pwr_cl_200_360;
> >> >                 break;
> >> >         default:
> >> >                 pr_warning("%s: Voltage range not supported "
> >> > @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
> >> >  {
> >> >         unsigned int max_dtr = (unsigned int)-1;
> >> >
> >> > -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> >> > +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
> >> > +            max_dtr > card->ext_csd.hs200_max_dtr)
> >> >                 max_dtr = card->ext_csd.hs200_max_dtr;
> >> >         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
> >> >                 max_dtr = card->ext_csd.hs_max_dtr;
> >> > @@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
> >> >  }
> >> >
> >> >  /*
> >> > + * Revert to the high-speed mode from above speed
> >> > + */
> >> > +static int mmc_revert_to_hs(struct mmc_card *card)
> >> > +{
> >> > +       /*
> >> > +        * CMD13, which is used to confirm the completion of timing
> >> > +        * change, will be issued at higher speed timing condtion
> >> > +        * rather than high-speed. If device has completed the change
> >> > +        * to high-speed mode, it may not be proper timing to issue
> >> > +        * command. Low speed supplies better timing margin than high
> >> > +        * speed. Accordingly clock rate & timging should be chagned
> >> > +        * ahead before actual switch.
> >>
> >> I have some problem to understand this comment. I guess you are trying
> >> to provide the arguments to why it makes sense to perform the revert
> >> to lower speed mode!?
> >>
> >> This makes me wonder if this is not part of the spec? Could you try to clarify?
> > But specification says that "HS_TIMING must be set to "0x1" before setting BUS_WIDTH for dual data
> rate operation".
> > I think this sequence is not graceful.
> > I also commented why speed mode should be changed to high-speed mode from HS200 mode in the
> function-called part.
> > Because it is not possible to set 8-bit data bus for dual rate on HS200 mode, revert to high-speed
> from HS200 is needed.
> > If the above-commented point makes it confused, it could be removed.
> > Please let me know your opinion.
> >
> >>
> >> > +        */
> >> > +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> >> > +       mmc_set_bus_speed(card);
> >> > +
> >> > +       return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> > +                         EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> >> > +                         card->ext_csd.generic_cmd6_time);
> >> > +}
> >> > +
> >> > +/*
> >> >   * Activate wide bus and DDR if supported.
> >> >   */
> >> >  static int mmc_select_hs_ddr(struct mmc_card *card)
> >> > @@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
> >> >         return err;
> >> >  }
> >> >
> >> > +static int mmc_select_hs400(struct mmc_card *card)
> >> > +{
> >> > +       struct mmc_host *host = card->host;
> >> > +       int err = 0;
> >> > +
> >> > +       /*
> >> > +        * The bus width is set to only 8 DDR in HS400 mode
> >>
> >> Please rephrase the comment to something like:
> >> "HS400 mode requires 8-bit bus width."
> > As it is, it was from spec's description.
> > But I think yours would be more clearable.
> >
> >>
> >> > +        */
> >> > +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
> >> > +             host->ios.bus_width == MMC_BUS_WIDTH_8))
> >> > +               return 0;
> >> > +
> >> > +       /*
> >> > +        * Before setting BUS_WIDTH for dual data rate operation,
> >> > +        * HS_TIMING must be set to High Speed(0x1)
> >> > +        */
> >>
> >> Please rephrase comment:
> >>
> >> "Before switching to dual data rate operation for HS400, we need
> >> revert from HS200 timing to regular HS timing."
> > Ok.
> >
> >>
> >> > +       err = mmc_revert_to_hs(card);
> >>
> >> I don't think we need a separate function to handle the revert.
> >> Please, just add the code here instead. While you do that, I suppose
> >> we should combine the comment in that function into one comment here.
> > OK, I don't oppose that.
> >
> >>
> >> > +       if (err) {
> >> > +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> >> > +                       mmc_hostname(host), err);
> >> > +               return err;
> >> > +       }
> >> > +
> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> > +                        EXT_CSD_BUS_WIDTH,
> >> > +                        EXT_CSD_DDR_BUS_WIDTH_8,
> >> > +                        card->ext_csd.generic_cmd6_time);
> >> > +       if (err) {
> >> > +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> >> > +                       mmc_hostname(host), err);
> >> > +               return err;
> >> > +       }
> >> > +
> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> >> > +                        card->ext_csd.generic_cmd6_time);
> >> > +       if (err) {
> >> > +               pr_warn("%s: switch to hs400 failed, err:%d\n",
> >> > +                        mmc_hostname(host), err);
> >> > +               return err;
> >> > +       }
> >> > +
> >> > +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> >> > +       mmc_set_bus_speed(card);
> >> > +
> >> > +       return 0;
> >> > +}
> >> > +
> >> >  /*
> >> >   * For device supporting HS200 mode, the following sequence
> >> >   * should be done before executing the tuning process.
> >> > @@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
> >> >                                    EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> >> >                                    card->ext_csd.generic_cmd6_time,
> >> >                                    true, true, true);
> >> > -               if (!err)
> >> > +               if (err)
> >> > +                       goto err;
> >> > +
> >> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> >> > +                       /*
> >> > +                        * Timing should be adjusted to the HS400 target
> >> > +                        * operation frequency for tuning process
> >> > +                        */
> >> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> >>
> >> This seems strange. Do we really need a separate
> >> MMC_TIMING_MMC_HS400_TUNING value?
> > Spec. describes the HS400 selection sequence like below.
> > <Quot>
> > ...
> > 6) Perform the Tuning Process at the HS400 target operating frequency
> > (Note: tuning process in HS200 mode is required to synchronize the command response on the CMD line
> to CLK for HS400 operation).
> > ...
> > </Quot>
> > That means target clock rate for tuning sequence can be different with HS200.
> > Considering for that, it needs to distinguish.
> 
> I understand the spec now, thanks.
> 
> Still, I am not convinced we should handle this through the
> MMC_TIMING* field. That will leave host drivers to do some magic clock
> frequency calculation from their ->set_ios callbacks, just depending
> on the MMC_TIMING_MMC_HS400_TUNING value.
> 
> I am also a bit concerned how MMC_TIMING_MMC_HS400_TUNING, would work
> if/when we implement periodic re-tuning - triggered from the mmc core
> layer.
> 
> What we really want to do, is to pretend we were to operate in
> MMC_TIMING_MMC_HS400 and ask the host driver what the target frequency
> would be in this case. Then set this frequency through
> mmc_set_clock().
> 
> Then how do we ask the host driver about this frequency? Let's add a
> new host_ops callback. We want it to be generic, so provide the
> MMC_TIMING bit as a parameter. Additionally we want it to be optional
> to implement, thus for those host drivers that supports the same
> target frequency for HS200 as for HS400, they don't need to implement
> it.
> 
> Would this be a way forward?

Thanks for your opinion.

IMO, in this case additional callback handling seems to cause the complication in host side.
I think we don't need to ask host driver about target frequency for HS400 in order to set specific frequency through
mmc_set_clock().
Target frequency which core layer requires for HS400 will be 200MHz and it is also mentioned in specification.
Host driver including actual controller just will effort to make DDR rate with 200MHz.
MMC_TIMING_MMC_HS400_TUNING may be used as notification for host to prepare HS400 tuning sequence.
If host driver doesn't need to care MMC_TIMING_MMC_HS400_TUNING, it can be ignored.
Perhaps, we may need other opinions.

Thanks,
Seungwon Jeon

> 
> Kind regards
> Ulf Hansson
> 
> >
> >>
> >> > +               else
> >> >                         mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> >> >         }
> >> >  err:
> >> > @@ -1070,7 +1169,7 @@ bus_speed:
> >> >
> >> >  /*
> >> >   * Execute tuning sequence to seek the proper bus operating
> >> > - * conditions for HS200, which sends CMD21 to the device.
> >> > + * conditions for HS200 and HS400, which sends CMD21 to the device.
> >> >   */
> >> >  static int mmc_hs200_tuning(struct mmc_card *card)
> >> >  {
> >> > @@ -1304,6 +1403,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >> >                 err = mmc_hs200_tuning(card);
> >> >                 if (err)
> >> >                         goto err;
> >> > +
> >> > +               err = mmc_select_hs400(card);
> >> > +               if (err)
> >> > +                       goto err;
> >> >         } else if (mmc_card_hs(card)) {
> >> >                 /* Select the desired bus width optionally */
> >> >                 err = mmc_select_bus_width(card);
> >> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> >> > index def6814..2b24c36 100644
> >> > --- a/include/linux/mmc/card.h
> >> > +++ b/include/linux/mmc/card.h
> >> > @@ -110,6 +110,7 @@ struct mmc_ext_csd {
> >> >         u8                      raw_pwr_cl_200_360;     /* 237 */
> >> >         u8                      raw_pwr_cl_ddr_52_195;  /* 238 */
> >> >         u8                      raw_pwr_cl_ddr_52_360;  /* 239 */
> >> > +       u8                      raw_pwr_cl_ddr_200_360; /* 253 */
> >> >         u8                      raw_bkops_status;       /* 246 */
> >> >         u8                      raw_sectors[4];         /* 212 - 4 bytes */
> >> >
> >> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> >> > index 1ee3c10..cc716e4 100644
> >> > --- a/include/linux/mmc/host.h
> >> > +++ b/include/linux/mmc/host.h
> >> > @@ -61,6 +61,8 @@ struct mmc_ios {
> >> >  #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_HS400_TUNING 11
> >>
> >> MMC_TIMING_MMC_HS400_TUNING ?
> >>
> >> >
> >> >         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
> >> >
> >> > @@ -274,6 +276,10 @@ struct mmc_host {
> >> >  #define MMC_CAP2_PACKED_CMD    (MMC_CAP2_PACKED_RD | \
> >> >                                  MMC_CAP2_PACKED_WR)
> >> >  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)  /* Don't power up before scan */
> >> > +#define MMC_CAP2_HS400_1_8V    (1 << 15)       /* Can support HS400 1.8V */
> >> > +#define MMC_CAP2_HS400_1_2V    (1 << 16)       /* Can support HS400 1.2V */
> >> > +#define MMC_CAP2_HS400         (MMC_CAP2_HS400_1_8V | \
> >> > +                                MMC_CAP2_HS400_1_2V)
> >> >
> >> >         mmc_pm_flag_t           pm_caps;        /* supported pm features */
> >> >
> >> > @@ -486,11 +492,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
> >> >
> >> >  static inline bool mmc_card_hs200(struct mmc_card *card)
> >> >  {
> >> > -       return card->host->ios.timing == MMC_TIMING_MMC_HS200;
> >> > +       return card->host->ios.timing == MMC_TIMING_MMC_HS200 ||
> >> > +               card->host->ios.timing == MMC_TIMING_MMC_HS400_TUNING;
> >>
> >> MMC_TIMING_MMC_HS400_TUNING ?
> > It also indicates that card is currently in HS200 mode with the result of setting HS_TIMING'.
> >
> > Thanks,
> > Seungwon Jeon
> >
> >>
> >> >  }
> >> >
> >> >  static inline bool mmc_card_ddr52(struct mmc_card *card)
> >> >  {
> >> >         return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
> >> >  }
> >> > +
> >> > +static inline bool mmc_card_hs400(struct mmc_card *card)
> >> > +{
> >> > +       return card->host->ios.timing == MMC_TIMING_MMC_HS400;
> >> > +}
> >> > +
> >> >  #endif /* LINUX_MMC_HOST_H */
> >> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> >> > index f429f13..64ec963 100644
> >> > --- a/include/linux/mmc/mmc.h
> >> > +++ b/include/linux/mmc/mmc.h
> >> > @@ -325,6 +325,7 @@ struct _mmc_csd {
> >> >  #define EXT_CSD_POWER_OFF_LONG_TIME    247     /* RO */
> >> >  #define EXT_CSD_GENERIC_CMD6_TIME      248     /* RO */
> >> >  #define EXT_CSD_CACHE_SIZE             249     /* RO, 4 bytes */
> >> > +#define EXT_CSD_PWR_CL_DDR_200_360     253     /* RO */
> >> >  #define EXT_CSD_TAG_UNIT_SIZE          498     /* RO */
> >> >  #define EXT_CSD_DATA_TAG_SUPPORT       499     /* RO */
> >> >  #define EXT_CSD_MAX_PACKED_WRITES      500     /* RO */
> >> > @@ -354,7 +355,6 @@ struct _mmc_csd {
> >> >  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
> >> >  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
> >> >
> >> > -#define EXT_CSD_CARD_TYPE_MASK 0x3F    /* Mask out reserved bits */
> >> >  #define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
> >> >  #define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
> >> >  #define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
> >> > @@ -370,6 +370,10 @@ struct _mmc_csd {
> >> >                                                 /* SDR mode @1.2V I/O */
> >> >  #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   (1<<6)  /* Card can run at 200MHz DDR, 1.8V */
> >> > +#define EXT_CSD_CARD_TYPE_HS400_1_2V   (1<<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_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
> >> >  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
> >> > @@ -380,6 +384,7 @@ struct _mmc_csd {
> >> >  #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_SEC_ER_EN      BIT(0)
> >> >  #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
> >> > --
> >> > 1.7.0.4
> >> >
> >> >
> >>
> >> Kind regards
> >> Ulf Hansson
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* RE: [PATCH v2 2/5] mmc: identify available device type to select
  2014-03-28  8:31         ` Ulf Hansson
@ 2014-03-28 12:27           ` Seungwon Jeon
  0 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-03-28 12:27 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On Fri, March 28, 2014, Ulf Hansson wrote:
> On 14 March 2014 03:49, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > On Thu, March 13, 2014, Ulf Hansson wrote:
> >> On 7 March 2014 15:36, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> > Device types which are supported by both host and device
> >> > can be identified when EXT_CSD is read. There is no need to
> >> > check host's capability anymore.
> >> >
> >> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> >> > ---
> >> > Changes in v2:
> >> >         Just rebased with latest one.
> >> >
> >> >  drivers/mmc/core/mmc.c   |   77 ++++++++++++++++++++++++++-------------------
> >> >  include/linux/mmc/card.h |    6 ++-
> >> >  include/linux/mmc/host.h |    6 ---
> >> >  include/linux/mmc/mmc.h  |   12 +++++--
> >> >  4 files changed, 56 insertions(+), 45 deletions(-)
> >> >
> >> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >> > index db9655f..0abece0 100644
> >> > --- a/drivers/mmc/core/mmc.c
> >> > +++ b/drivers/mmc/core/mmc.c
> >> > @@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
> >> >         u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> >> >         u32 caps = host->caps, caps2 = host->caps2;
> >> >         unsigned int hs_max_dtr = 0;
> >> > +       unsigned int avail_type = 0;
> >> >
> >> > -       if (card_type & EXT_CSD_CARD_TYPE_26)
> >> > +       if (caps & MMC_CAP_MMC_HIGHSPEED &&
> >> > +           card_type & EXT_CSD_CARD_TYPE_HS_26) {
> >> >                 hs_max_dtr = MMC_HIGH_26_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS_26;
> >> > +       }
> >> >
> >> >         if (caps & MMC_CAP_MMC_HIGHSPEED &&
> >> > -                       card_type & EXT_CSD_CARD_TYPE_52)
> >> > +           card_type & EXT_CSD_CARD_TYPE_HS_52) {
> >> >                 hs_max_dtr = MMC_HIGH_52_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS_52;
> >> > +       }
> >> >
> >> > -       if ((caps & MMC_CAP_1_8V_DDR &&
> >> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
> >> > -           (caps & MMC_CAP_1_2V_DDR &&
> >> > -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
> >> > +       if (caps & MMC_CAP_1_8V_DDR &&
> >> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
> >> >                 hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
> >> > +       }
> >> >
> >> > -       if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> >> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
> >> > -           (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> >> > -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
> >> > +       if (caps & MMC_CAP_1_2V_DDR &&
> >> > +           card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> >> > +               hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
> >> > +       }
> >> > +
> >> > +       if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> >> > +           card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
> >> >                 hs_max_dtr = MMC_HS200_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
> >> > +       }
> >> > +
> >> > +       if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> >> > +           card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
> >> > +               hs_max_dtr = MMC_HS200_MAX_DTR;
> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> >> > +       }
> >> >
> >> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
> >> > -       card->ext_csd.card_type = card_type;
> >> > +       card->mmc_avail_type = avail_type;
> >> >  }
> >> >
> >> >  /*
> >> > @@ -708,6 +726,11 @@ static struct device_type mmc_type = {
> >> >         .groups = mmc_attr_groups,
> >> >  };
> >> >
> >> > +static inline unsigned int mmc_snoop_ddr(struct mmc_card *card)
> >> > +{
> >> > +       return card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
> >> > +}
> >> > +
> >>
> >> Having a separate function for this seem a bit silly. Similar checks
> >> is performed all over the code. I suggest you remove this.
> > I understand your meaning.
> > Yes, actually similar checking card type is done.
> > But checking DDR type is required several times unlike other type case.
> > I considered for that. I think it's pretty useful in terms of avoiding duplication and enhancement
> of readability.
> >
> >>
> >> >  /*
> >> >   * Select the PowerClass for the current bus width
> >> >   * If power class is defined for 4/8 bit bus in the
> >> > @@ -808,12 +831,10 @@ static int mmc_select_hs200(struct mmc_card *card)
> >> >
> >> >         host = card->host;
> >> >
> >> > -       if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
> >> > -                       host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
> >> > +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
> >> >                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
> >> >
> >> > -       if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
> >> > -                       host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
> >> > +       if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
> >> >                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
> >> >
> >> >         /* If fails try again during next card power cycle */
> >> > @@ -1072,10 +1093,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >> >          */
> >> >         if (card->ext_csd.hs_max_dtr != 0) {
> >> >                 err = 0;
> >> > -               if (card->ext_csd.hs_max_dtr > 52000000 &&
> >> > -                   host->caps2 & MMC_CAP2_HS200)
> >> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> >> >                         err = mmc_select_hs200(card);
> >> > -               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> >> > +               else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
> >> >                         err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >                                         EXT_CSD_HS_TIMING, 1,
> >> >                                         card->ext_csd.generic_cmd6_time,
> >> > @@ -1089,13 +1109,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >> >                                mmc_hostname(card->host));
> >> >                         err = 0;
> >> >                 } else {
> >> > -                       if (card->ext_csd.hs_max_dtr > 52000000 &&
> >> > -                           host->caps2 & MMC_CAP2_HS200) {
> >> > +                       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> >> >                                 mmc_set_timing(card->host,
> >> >                                                MMC_TIMING_MMC_HS200);
> >> > -                       } else {
> >> > +                       else
> >> >                                 mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> >> > -                       }
> >> >                 }
> >> >         }
> >> >
> >> > @@ -1118,14 +1136,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >> >         /*
> >> >          * Indicate DDR mode (if supported).
> >> >          */
> >> > -       if (mmc_card_hs(card)) {
> >> > -               if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
> >> > -                       && (host->caps & MMC_CAP_1_8V_DDR))
> >> > -                               ddr = MMC_1_8V_DDR_MODE;
> >> > -               else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
> >> > -                       && (host->caps & MMC_CAP_1_2V_DDR))
> >> > -                               ddr = MMC_1_2V_DDR_MODE;
> >> > -       }
> >> > +       if (mmc_card_hs(card))
> >> > +               ddr = mmc_snoop_ddr(card);
> >> >
> >> >         /*
> >> >          * Indicate HS200 SDR mode (if supported).
> >> > @@ -1145,8 +1157,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >> >                  * 3. set the clock to > 52Mhz <=200MHz and
> >> >                  * 4. execute tuning for HS200
> >> >                  */
> >> > -               if ((host->caps2 & MMC_CAP2_HS200) &&
> >> > -                   card->host->ops->execute_tuning) {
> >> > +               if (card->host->ops->execute_tuning) {
> >> >                         mmc_host_clk_hold(card->host);
> >> >                         err = card->host->ops->execute_tuning(card->host,
> >> >                                 MMC_SEND_TUNING_BLOCK_HS200);
> >> > @@ -1255,7 +1266,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >> >                          *
> >> >                          * WARNING: eMMC rules are NOT the same as SD DDR
> >> >                          */
> >> > -                       if (ddr == MMC_1_2V_DDR_MODE) {
> >> > +                       if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> >> >                                 err = __mmc_set_signal_voltage(host,
> >> >                                         MMC_SIGNAL_VOLTAGE_120);
> >> >                                 if (err)
> >> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> >> > index 5473133..c232b10 100644
> >> > --- a/include/linux/mmc/card.h
> >> > +++ b/include/linux/mmc/card.h
> >> > @@ -68,7 +68,6 @@ struct mmc_ext_csd {
> >> >  #define MMC_HIGH_DDR_MAX_DTR   52000000
> >> >  #define MMC_HS200_MAX_DTR      200000000
> >> >         unsigned int            sectors;
> >> > -       unsigned int            card_type;
> >> >         unsigned int            hc_erase_size;          /* In sectors */
> >> >         unsigned int            hc_erase_timeout;       /* In milliseconds */
> >> >         unsigned int            sec_trim_mult;  /* Secure trim multiplier  */
> >> > @@ -297,7 +296,10 @@ struct mmc_card {
> >> >         const char              **info;         /* info strings */
> >> >         struct sdio_func_tuple  *tuples;        /* unknown common tuples */
> >> >
> >> > -       unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
> >> > +       union {
> >> > +               unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
> >> > +               unsigned int            mmc_avail_type; /* supported device type by both host and card
> */
> >>
> >> Using a union here won't be that much of a gain since there are only
> >> few instances of the struct. Please remove.
> > Yes, you're right. It's not much in gain.
> > I intended to distinguish these two similar members respectively.
> > It's used only in each specific type domain and not used at the same time.
> > If no meaningful, I can remove as your suggestion.
> 
> Hi Seungwon,
> 
> I noticed in your latest version if this patch the "union" declaration
> is still there. Could you please update and send a new version.
Oh, I was waiting your reply for my extra opinion :)
I don't like to hold this strongly.
I'll update next.

Thanks,
Seungwon Jeon

> 
> Kind regards
> Ulf Hansson
> 
> >
> > Thanks,
> > Seungwon Jeon
> >
> >>
> >> > +       };
> >> >
> >> >         struct dentry           *debugfs_root;
> >> >         struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
> >> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> >> > index 2f263ae..1ee3c10 100644
> >> > --- a/include/linux/mmc/host.h
> >> > +++ b/include/linux/mmc/host.h
> >> > @@ -62,12 +62,6 @@ struct mmc_ios {
> >> >  #define MMC_TIMING_MMC_DDR52   8
> >> >  #define MMC_TIMING_MMC_HS200   9
> >> >
> >> > -#define MMC_SDR_MODE           0
> >> > -#define MMC_1_2V_DDR_MODE      1
> >> > -#define MMC_1_8V_DDR_MODE      2
> >> > -#define MMC_1_2V_SDR_MODE      3
> >> > -#define MMC_1_8V_SDR_MODE      4
> >> > -
> >> >         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
> >> >
> >> >  #define MMC_SIGNAL_VOLTAGE_330 0
> >> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> >> > index 50bcde3..f734c0c 100644
> >> > --- a/include/linux/mmc/mmc.h
> >> > +++ b/include/linux/mmc/mmc.h
> >> > @@ -354,18 +354,22 @@ struct _mmc_csd {
> >> >  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
> >> >  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
> >> >
> >> > -#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_MASK 0x3F    /* Mask out reserved bits */
> >> > +#define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
> >> > +#define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
> >> > +#define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
> >> > +                                EXT_CSD_CARD_TYPE_HS_52)
> >> >  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
> >> >                                              /* DDR mode @1.8V or 3V I/O */
> >> >  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
> >> >                                              /* DDR mode @1.2V I/O */
> >> >  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
> >> >                                         | EXT_CSD_CARD_TYPE_DDR_1_2V)
> >> > -#define EXT_CSD_CARD_TYPE_SDR_1_8V     (1<<4)  /* Card can run at 200MHz */
> >> > -#define EXT_CSD_CARD_TYPE_SDR_1_2V     (1<<5)  /* Card can run at 200MHz */
> >> > +#define EXT_CSD_CARD_TYPE_HS200_1_8V   (1<<4)  /* Card can run at 200MHz */
> >> > +#define EXT_CSD_CARD_TYPE_HS200_1_2V   (1<<5)  /* Card can run at 200MHz */
> >> >                                                 /* SDR mode @1.2V I/O */
> >> > +#define EXT_CSD_CARD_TYPE_HS200                (EXT_CSD_CARD_TYPE_HS200_1_8V | \
> >> > +                                        EXT_CSD_CARD_TYPE_HS200_1_2V)
> >> >
> >> >  #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
> >> >  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
> >> > --
> >> > 1.7.0.4
> >> >
> >> >
> >>
> >> Besides the minor stuff, looks good.
> >>
> >> Kind regards
> >> Ulf Hansson
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-03-28 12:18           ` Seungwon Jeon
@ 2014-03-28 13:33             ` Ulf Hansson
  2014-04-02  1:15               ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-03-28 13:33 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 28 March 2014 13:18, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> On Fri, March 28, 2014, Ulf Hansson wrote:
>> On 25 March 2014 10:23, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> > Hi Ulf,
>> >
>> > On Tue, March 25, 2014, Ulf Hansson wrote:
>> >> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> >> > 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: Seungwon Jeon <tgih.jun@samsung.com>
>> >> > Reviewed-by: Jackey Shen <jackey.shen@amd.com>
>> >> > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
>> >> > Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
>> >> > ---
>> >> >  drivers/mmc/core/bus.c     |    1 +
>> >> >  drivers/mmc/core/debugfs.c |    3 +
>> >> >  drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
>> >> >  include/linux/mmc/card.h   |    1 +
>> >> >  include/linux/mmc/host.h   |   15 +++++-
>> >> >  include/linux/mmc/mmc.h    |    7 ++-
>> >> >  6 files changed, 134 insertions(+), 8 deletions(-)
>> >> >
>> >> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> >> > index f37e9d6..d2dbf02 100644
>> >> > --- a/drivers/mmc/core/bus.c
>> >> > +++ b/drivers/mmc/core/bus.c
>> >> > @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
>> >> >                         mmc_hostname(card->host),
>> >> >                         mmc_card_uhs(card) ? "ultra high speed " :
>> >> >                         (mmc_card_hs(card) ? "high speed " : ""),
>> >> > +                       mmc_card_hs400(card) ? "HS400 " :
>> >> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
>> >> >                         mmc_card_ddr52(card) ? "DDR " : "",
>> >> >                         uhs_bus_speed_mode, type, card->rca);
>> >> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
>> >> > index 1f730db..91eb162 100644
>> >> > --- a/drivers/mmc/core/debugfs.c
>> >> > +++ b/drivers/mmc/core/debugfs.c
>> >> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>> >> >         case MMC_TIMING_MMC_HS200:
>> >> >                 str = "mmc HS200";
>> >> >                 break;
>> >> > +       case MMC_TIMING_MMC_HS400:
>> >> > +               str = "mmc HS400";
>> >> > +               break;
>> >> >         default:
>> >> >                 str = "invalid";
>> >> >                 break;
>> >> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> >> > index 6dd68e6..969d595 100644
>> >> > --- a/drivers/mmc/core/mmc.c
>> >> > +++ b/drivers/mmc/core/mmc.c
>> >> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
>> >> >  static void mmc_select_card_type(struct mmc_card *card)
>> >> >  {
>> >> >         struct mmc_host *host = card->host;
>> >> > -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>> >> > +       u8 card_type = card->ext_csd.raw_card_type;
>> >> >         u32 caps = host->caps, caps2 = host->caps2;
>> >> >         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>> >> >         unsigned int avail_type = 0;
>> >> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
>> >> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>> >> >         }
>> >> >
>> >> > +       if (caps2 & MMC_CAP2_HS400_1_8V &&
>> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
>> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
>> >> > +       }
>> >> > +
>> >> > +       if (caps2 & MMC_CAP2_HS400_1_2V &&
>> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
>> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>> >> > +       }
>> >> > +
>> >> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
>> >> >         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>> >> >         card->mmc_avail_type = avail_type;
>> >> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
>> >> >                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
>> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
>> >> > +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
>> >> > +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
>> >> >         }
>> >> >
>> >> >         if (card->ext_csd.rev >= 5) {
>> >> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
>> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
>> >> >                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
>> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
>> >> > -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
>> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
>> >> > +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
>> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
>> >> > +
>> >> >         if (err)
>> >> >                 err = -EINVAL;
>> >> >
>> >> > @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
>> >> >                                 ext_csd->raw_pwr_cl_52_360 :
>> >> >                                 ext_csd->raw_pwr_cl_ddr_52_360;
>> >> >                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
>> >> > -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
>> >> > +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
>> >> > +                               ext_csd->raw_pwr_cl_ddr_200_360 :
>> >> > +                               ext_csd->raw_pwr_cl_200_360;
>> >> >                 break;
>> >> >         default:
>> >> >                 pr_warning("%s: Voltage range not supported "
>> >> > @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
>> >> >  {
>> >> >         unsigned int max_dtr = (unsigned int)-1;
>> >> >
>> >> > -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
>> >> > +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
>> >> > +            max_dtr > card->ext_csd.hs200_max_dtr)
>> >> >                 max_dtr = card->ext_csd.hs200_max_dtr;
>> >> >         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
>> >> >                 max_dtr = card->ext_csd.hs_max_dtr;
>> >> > @@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
>> >> >  }
>> >> >
>> >> >  /*
>> >> > + * Revert to the high-speed mode from above speed
>> >> > + */
>> >> > +static int mmc_revert_to_hs(struct mmc_card *card)
>> >> > +{
>> >> > +       /*
>> >> > +        * CMD13, which is used to confirm the completion of timing
>> >> > +        * change, will be issued at higher speed timing condtion
>> >> > +        * rather than high-speed. If device has completed the change
>> >> > +        * to high-speed mode, it may not be proper timing to issue
>> >> > +        * command. Low speed supplies better timing margin than high
>> >> > +        * speed. Accordingly clock rate & timging should be chagned
>> >> > +        * ahead before actual switch.
>> >>
>> >> I have some problem to understand this comment. I guess you are trying
>> >> to provide the arguments to why it makes sense to perform the revert
>> >> to lower speed mode!?
>> >>
>> >> This makes me wonder if this is not part of the spec? Could you try to clarify?
>> > But specification says that "HS_TIMING must be set to "0x1" before setting BUS_WIDTH for dual data
>> rate operation".
>> > I think this sequence is not graceful.
>> > I also commented why speed mode should be changed to high-speed mode from HS200 mode in the
>> function-called part.
>> > Because it is not possible to set 8-bit data bus for dual rate on HS200 mode, revert to high-speed
>> from HS200 is needed.
>> > If the above-commented point makes it confused, it could be removed.
>> > Please let me know your opinion.
>> >
>> >>
>> >> > +        */
>> >> > +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> >> > +       mmc_set_bus_speed(card);
>> >> > +
>> >> > +       return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> > +                         EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
>> >> > +                         card->ext_csd.generic_cmd6_time);
>> >> > +}
>> >> > +
>> >> > +/*
>> >> >   * Activate wide bus and DDR if supported.
>> >> >   */
>> >> >  static int mmc_select_hs_ddr(struct mmc_card *card)
>> >> > @@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
>> >> >         return err;
>> >> >  }
>> >> >
>> >> > +static int mmc_select_hs400(struct mmc_card *card)
>> >> > +{
>> >> > +       struct mmc_host *host = card->host;
>> >> > +       int err = 0;
>> >> > +
>> >> > +       /*
>> >> > +        * The bus width is set to only 8 DDR in HS400 mode
>> >>
>> >> Please rephrase the comment to something like:
>> >> "HS400 mode requires 8-bit bus width."
>> > As it is, it was from spec's description.
>> > But I think yours would be more clearable.
>> >
>> >>
>> >> > +        */
>> >> > +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
>> >> > +             host->ios.bus_width == MMC_BUS_WIDTH_8))
>> >> > +               return 0;
>> >> > +
>> >> > +       /*
>> >> > +        * Before setting BUS_WIDTH for dual data rate operation,
>> >> > +        * HS_TIMING must be set to High Speed(0x1)
>> >> > +        */
>> >>
>> >> Please rephrase comment:
>> >>
>> >> "Before switching to dual data rate operation for HS400, we need
>> >> revert from HS200 timing to regular HS timing."
>> > Ok.
>> >
>> >>
>> >> > +       err = mmc_revert_to_hs(card);
>> >>
>> >> I don't think we need a separate function to handle the revert.
>> >> Please, just add the code here instead. While you do that, I suppose
>> >> we should combine the comment in that function into one comment here.
>> > OK, I don't oppose that.
>> >
>> >>
>> >> > +       if (err) {
>> >> > +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
>> >> > +                       mmc_hostname(host), err);
>> >> > +               return err;
>> >> > +       }
>> >> > +
>> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> > +                        EXT_CSD_BUS_WIDTH,
>> >> > +                        EXT_CSD_DDR_BUS_WIDTH_8,
>> >> > +                        card->ext_csd.generic_cmd6_time);
>> >> > +       if (err) {
>> >> > +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
>> >> > +                       mmc_hostname(host), err);
>> >> > +               return err;
>> >> > +       }
>> >> > +
>> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
>> >> > +                        card->ext_csd.generic_cmd6_time);
>> >> > +       if (err) {
>> >> > +               pr_warn("%s: switch to hs400 failed, err:%d\n",
>> >> > +                        mmc_hostname(host), err);
>> >> > +               return err;
>> >> > +       }
>> >> > +
>> >> > +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>> >> > +       mmc_set_bus_speed(card);
>> >> > +
>> >> > +       return 0;
>> >> > +}
>> >> > +
>> >> >  /*
>> >> >   * For device supporting HS200 mode, the following sequence
>> >> >   * should be done before executing the tuning process.
>> >> > @@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
>> >> >                                    EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
>> >> >                                    card->ext_csd.generic_cmd6_time,
>> >> >                                    true, true, true);
>> >> > -               if (!err)
>> >> > +               if (err)
>> >> > +                       goto err;
>> >> > +
>> >> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
>> >> > +                       /*
>> >> > +                        * Timing should be adjusted to the HS400 target
>> >> > +                        * operation frequency for tuning process
>> >> > +                        */
>> >> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
>> >>
>> >> This seems strange. Do we really need a separate
>> >> MMC_TIMING_MMC_HS400_TUNING value?
>> > Spec. describes the HS400 selection sequence like below.
>> > <Quot>
>> > ...
>> > 6) Perform the Tuning Process at the HS400 target operating frequency
>> > (Note: tuning process in HS200 mode is required to synchronize the command response on the CMD line
>> to CLK for HS400 operation).
>> > ...
>> > </Quot>
>> > That means target clock rate for tuning sequence can be different with HS200.
>> > Considering for that, it needs to distinguish.
>>
>> I understand the spec now, thanks.
>>
>> Still, I am not convinced we should handle this through the
>> MMC_TIMING* field. That will leave host drivers to do some magic clock
>> frequency calculation from their ->set_ios callbacks, just depending
>> on the MMC_TIMING_MMC_HS400_TUNING value.
>>
>> I am also a bit concerned how MMC_TIMING_MMC_HS400_TUNING, would work
>> if/when we implement periodic re-tuning - triggered from the mmc core
>> layer.
>>
>> What we really want to do, is to pretend we were to operate in
>> MMC_TIMING_MMC_HS400 and ask the host driver what the target frequency
>> would be in this case. Then set this frequency through
>> mmc_set_clock().
>>
>> Then how do we ask the host driver about this frequency? Let's add a
>> new host_ops callback. We want it to be generic, so provide the
>> MMC_TIMING bit as a parameter. Additionally we want it to be optional
>> to implement, thus for those host drivers that supports the same
>> target frequency for HS200 as for HS400, they don't need to implement
>> it.
>>
>> Would this be a way forward?
>
> Thanks for your opinion.
>
> IMO, in this case additional callback handling seems to cause the complication in host side.
> I think we don't need to ask host driver about target frequency for HS400 in order to set specific frequency through
> mmc_set_clock().
> Target frequency which core layer requires for HS400 will be 200MHz and it is also mentioned in specification.
> Host driver including actual controller just will effort to make DDR rate with 200MHz.

What the mmc_set_clock() request is not the same as what the frequency
actually will be set to. That depends on the host controller/driver.

If for some reason the host controller/driver are not able to use the
same frequency for HS200 as for HS400, this should be possible to be
addressed in the way I suggested.

> MMC_TIMING_MMC_HS400_TUNING may be used as notification for host to prepare HS400 tuning sequence.

So, are you saying that your controller are have different tuning
methods for HS200 vs HS400? That's a different requirement, which of
course we need to handle.

> If host driver doesn't need to care MMC_TIMING_MMC_HS400_TUNING, it can be ignored.

It can't be ignored by host drivers, since drivers will need to cope
with it even if it means that it will actively ignore it.

Kind regards
Ulf Hanssson

> Perhaps, we may need other opinions.
>
> Thanks,
> Seungwon Jeon
>
>>
>> Kind regards
>> Ulf Hansson
>>
>> >
>> >>
>> >> > +               else
>> >> >                         mmc_set_timing(host, MMC_TIMING_MMC_HS200);
>> >> >         }
>> >> >  err:
>> >> > @@ -1070,7 +1169,7 @@ bus_speed:
>> >> >
>> >> >  /*
>> >> >   * Execute tuning sequence to seek the proper bus operating
>> >> > - * conditions for HS200, which sends CMD21 to the device.
>> >> > + * conditions for HS200 and HS400, which sends CMD21 to the device.
>> >> >   */
>> >> >  static int mmc_hs200_tuning(struct mmc_card *card)
>> >> >  {
>> >> > @@ -1304,6 +1403,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >> >                 err = mmc_hs200_tuning(card);
>> >> >                 if (err)
>> >> >                         goto err;
>> >> > +
>> >> > +               err = mmc_select_hs400(card);
>> >> > +               if (err)
>> >> > +                       goto err;
>> >> >         } else if (mmc_card_hs(card)) {
>> >> >                 /* Select the desired bus width optionally */
>> >> >                 err = mmc_select_bus_width(card);
>> >> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> >> > index def6814..2b24c36 100644
>> >> > --- a/include/linux/mmc/card.h
>> >> > +++ b/include/linux/mmc/card.h
>> >> > @@ -110,6 +110,7 @@ struct mmc_ext_csd {
>> >> >         u8                      raw_pwr_cl_200_360;     /* 237 */
>> >> >         u8                      raw_pwr_cl_ddr_52_195;  /* 238 */
>> >> >         u8                      raw_pwr_cl_ddr_52_360;  /* 239 */
>> >> > +       u8                      raw_pwr_cl_ddr_200_360; /* 253 */
>> >> >         u8                      raw_bkops_status;       /* 246 */
>> >> >         u8                      raw_sectors[4];         /* 212 - 4 bytes */
>> >> >
>> >> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> >> > index 1ee3c10..cc716e4 100644
>> >> > --- a/include/linux/mmc/host.h
>> >> > +++ b/include/linux/mmc/host.h
>> >> > @@ -61,6 +61,8 @@ struct mmc_ios {
>> >> >  #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_HS400_TUNING 11
>> >>
>> >> MMC_TIMING_MMC_HS400_TUNING ?
>> >>
>> >> >
>> >> >         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
>> >> >
>> >> > @@ -274,6 +276,10 @@ struct mmc_host {
>> >> >  #define MMC_CAP2_PACKED_CMD    (MMC_CAP2_PACKED_RD | \
>> >> >                                  MMC_CAP2_PACKED_WR)
>> >> >  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)  /* Don't power up before scan */
>> >> > +#define MMC_CAP2_HS400_1_8V    (1 << 15)       /* Can support HS400 1.8V */
>> >> > +#define MMC_CAP2_HS400_1_2V    (1 << 16)       /* Can support HS400 1.2V */
>> >> > +#define MMC_CAP2_HS400         (MMC_CAP2_HS400_1_8V | \
>> >> > +                                MMC_CAP2_HS400_1_2V)
>> >> >
>> >> >         mmc_pm_flag_t           pm_caps;        /* supported pm features */
>> >> >
>> >> > @@ -486,11 +492,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
>> >> >
>> >> >  static inline bool mmc_card_hs200(struct mmc_card *card)
>> >> >  {
>> >> > -       return card->host->ios.timing == MMC_TIMING_MMC_HS200;
>> >> > +       return card->host->ios.timing == MMC_TIMING_MMC_HS200 ||
>> >> > +               card->host->ios.timing == MMC_TIMING_MMC_HS400_TUNING;
>> >>
>> >> MMC_TIMING_MMC_HS400_TUNING ?
>> > It also indicates that card is currently in HS200 mode with the result of setting HS_TIMING'.
>> >
>> > Thanks,
>> > Seungwon Jeon
>> >
>> >>
>> >> >  }
>> >> >
>> >> >  static inline bool mmc_card_ddr52(struct mmc_card *card)
>> >> >  {
>> >> >         return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
>> >> >  }
>> >> > +
>> >> > +static inline bool mmc_card_hs400(struct mmc_card *card)
>> >> > +{
>> >> > +       return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>> >> > +}
>> >> > +
>> >> >  #endif /* LINUX_MMC_HOST_H */
>> >> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> >> > index f429f13..64ec963 100644
>> >> > --- a/include/linux/mmc/mmc.h
>> >> > +++ b/include/linux/mmc/mmc.h
>> >> > @@ -325,6 +325,7 @@ struct _mmc_csd {
>> >> >  #define EXT_CSD_POWER_OFF_LONG_TIME    247     /* RO */
>> >> >  #define EXT_CSD_GENERIC_CMD6_TIME      248     /* RO */
>> >> >  #define EXT_CSD_CACHE_SIZE             249     /* RO, 4 bytes */
>> >> > +#define EXT_CSD_PWR_CL_DDR_200_360     253     /* RO */
>> >> >  #define EXT_CSD_TAG_UNIT_SIZE          498     /* RO */
>> >> >  #define EXT_CSD_DATA_TAG_SUPPORT       499     /* RO */
>> >> >  #define EXT_CSD_MAX_PACKED_WRITES      500     /* RO */
>> >> > @@ -354,7 +355,6 @@ struct _mmc_csd {
>> >> >  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
>> >> >  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
>> >> >
>> >> > -#define EXT_CSD_CARD_TYPE_MASK 0x3F    /* Mask out reserved bits */
>> >> >  #define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
>> >> >  #define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
>> >> >  #define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
>> >> > @@ -370,6 +370,10 @@ struct _mmc_csd {
>> >> >                                                 /* SDR mode @1.2V I/O */
>> >> >  #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   (1<<6)  /* Card can run at 200MHz DDR, 1.8V */
>> >> > +#define EXT_CSD_CARD_TYPE_HS400_1_2V   (1<<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_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>> >> >  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
>> >> > @@ -380,6 +384,7 @@ struct _mmc_csd {
>> >> >  #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_SEC_ER_EN      BIT(0)
>> >> >  #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
>> >> > --
>> >> > 1.7.0.4
>> >> >
>> >> >
>> >>
>> >> Kind regards
>> >> Ulf Hansson
>> >> --
>> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> >> the body of a message to majordomo@vger.kernel.org
>> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> >
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

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

* RE: [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-03-28 13:33             ` Ulf Hansson
@ 2014-04-02  1:15               ` Seungwon Jeon
  2014-04-02  9:39                 ` Ulf Hansson
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-02  1:15 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On Fri, March 28, 2014, Ulf Hansson wrote:
> On 28 March 2014 13:18, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > On Fri, March 28, 2014, Ulf Hansson wrote:
> >> On 25 March 2014 10:23, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> > Hi Ulf,
> >> >
> >> > On Tue, March 25, 2014, Ulf Hansson wrote:
> >> >> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> >> > 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: Seungwon Jeon <tgih.jun@samsung.com>
> >> >> > Reviewed-by: Jackey Shen <jackey.shen@amd.com>
> >> >> > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
> >> >> > Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
> >> >> > ---
> >> >> >  drivers/mmc/core/bus.c     |    1 +
> >> >> >  drivers/mmc/core/debugfs.c |    3 +
> >> >> >  drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
> >> >> >  include/linux/mmc/card.h   |    1 +
> >> >> >  include/linux/mmc/host.h   |   15 +++++-
> >> >> >  include/linux/mmc/mmc.h    |    7 ++-
> >> >> >  6 files changed, 134 insertions(+), 8 deletions(-)
> >> >> >
> >> >> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> >> >> > index f37e9d6..d2dbf02 100644
> >> >> > --- a/drivers/mmc/core/bus.c
> >> >> > +++ b/drivers/mmc/core/bus.c
> >> >> > @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
> >> >> >                         mmc_hostname(card->host),
> >> >> >                         mmc_card_uhs(card) ? "ultra high speed " :
> >> >> >                         (mmc_card_hs(card) ? "high speed " : ""),
> >> >> > +                       mmc_card_hs400(card) ? "HS400 " :
> >> >> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
> >> >> >                         mmc_card_ddr52(card) ? "DDR " : "",
> >> >> >                         uhs_bus_speed_mode, type, card->rca);
> >> >> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> >> >> > index 1f730db..91eb162 100644
> >> >> > --- a/drivers/mmc/core/debugfs.c
> >> >> > +++ b/drivers/mmc/core/debugfs.c
> >> >> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
> >> >> >         case MMC_TIMING_MMC_HS200:
> >> >> >                 str = "mmc HS200";
> >> >> >                 break;
> >> >> > +       case MMC_TIMING_MMC_HS400:
> >> >> > +               str = "mmc HS400";
> >> >> > +               break;
> >> >> >         default:
> >> >> >                 str = "invalid";
> >> >> >                 break;
> >> >> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >> >> > index 6dd68e6..969d595 100644
> >> >> > --- a/drivers/mmc/core/mmc.c
> >> >> > +++ b/drivers/mmc/core/mmc.c
> >> >> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
> >> >> >  static void mmc_select_card_type(struct mmc_card *card)
> >> >> >  {
> >> >> >         struct mmc_host *host = card->host;
> >> >> > -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> >> >> > +       u8 card_type = card->ext_csd.raw_card_type;
> >> >> >         u32 caps = host->caps, caps2 = host->caps2;
> >> >> >         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
> >> >> >         unsigned int avail_type = 0;
> >> >> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
> >> >> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> >> >> >         }
> >> >> >
> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_8V &&
> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> >> >> > +       }
> >> >> > +
> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_2V &&
> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> >> >> > +       }
> >> >> > +
> >> >> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
> >> >> >         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
> >> >> >         card->mmc_avail_type = avail_type;
> >> >> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
> >> >> >                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> >> >> > +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
> >> >> > +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
> >> >> >         }
> >> >> >
> >> >> >         if (card->ext_csd.rev >= 5) {
> >> >> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
> >> >> >                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> >> >> > -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> >> >> > +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> >> >> > +
> >> >> >         if (err)
> >> >> >                 err = -EINVAL;
> >> >> >
> >> >> > @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> >> >> >                                 ext_csd->raw_pwr_cl_52_360 :
> >> >> >                                 ext_csd->raw_pwr_cl_ddr_52_360;
> >> >> >                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> >> >> > -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
> >> >> > +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> >> >> > +                               ext_csd->raw_pwr_cl_ddr_200_360 :
> >> >> > +                               ext_csd->raw_pwr_cl_200_360;
> >> >> >                 break;
> >> >> >         default:
> >> >> >                 pr_warning("%s: Voltage range not supported "
> >> >> > @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
> >> >> >  {
> >> >> >         unsigned int max_dtr = (unsigned int)-1;
> >> >> >
> >> >> > -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> >> >> > +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
> >> >> > +            max_dtr > card->ext_csd.hs200_max_dtr)
> >> >> >                 max_dtr = card->ext_csd.hs200_max_dtr;
> >> >> >         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
> >> >> >                 max_dtr = card->ext_csd.hs_max_dtr;
> >> >> > @@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
> >> >> >  }
> >> >> >
> >> >> >  /*
> >> >> > + * Revert to the high-speed mode from above speed
> >> >> > + */
> >> >> > +static int mmc_revert_to_hs(struct mmc_card *card)
> >> >> > +{
> >> >> > +       /*
> >> >> > +        * CMD13, which is used to confirm the completion of timing
> >> >> > +        * change, will be issued at higher speed timing condtion
> >> >> > +        * rather than high-speed. If device has completed the change
> >> >> > +        * to high-speed mode, it may not be proper timing to issue
> >> >> > +        * command. Low speed supplies better timing margin than high
> >> >> > +        * speed. Accordingly clock rate & timging should be chagned
> >> >> > +        * ahead before actual switch.
> >> >>
> >> >> I have some problem to understand this comment. I guess you are trying
> >> >> to provide the arguments to why it makes sense to perform the revert
> >> >> to lower speed mode!?
> >> >>
> >> >> This makes me wonder if this is not part of the spec? Could you try to clarify?
> >> > But specification says that "HS_TIMING must be set to "0x1" before setting BUS_WIDTH for dual
> data
> >> rate operation".
> >> > I think this sequence is not graceful.
> >> > I also commented why speed mode should be changed to high-speed mode from HS200 mode in the
> >> function-called part.
> >> > Because it is not possible to set 8-bit data bus for dual rate on HS200 mode, revert to high-
> speed
> >> from HS200 is needed.
> >> > If the above-commented point makes it confused, it could be removed.
> >> > Please let me know your opinion.
> >> >
> >> >>
> >> >> > +        */
> >> >> > +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> >> >> > +       mmc_set_bus_speed(card);
> >> >> > +
> >> >> > +       return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> > +                         EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> >> >> > +                         card->ext_csd.generic_cmd6_time);
> >> >> > +}
> >> >> > +
> >> >> > +/*
> >> >> >   * Activate wide bus and DDR if supported.
> >> >> >   */
> >> >> >  static int mmc_select_hs_ddr(struct mmc_card *card)
> >> >> > @@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
> >> >> >         return err;
> >> >> >  }
> >> >> >
> >> >> > +static int mmc_select_hs400(struct mmc_card *card)
> >> >> > +{
> >> >> > +       struct mmc_host *host = card->host;
> >> >> > +       int err = 0;
> >> >> > +
> >> >> > +       /*
> >> >> > +        * The bus width is set to only 8 DDR in HS400 mode
> >> >>
> >> >> Please rephrase the comment to something like:
> >> >> "HS400 mode requires 8-bit bus width."
> >> > As it is, it was from spec's description.
> >> > But I think yours would be more clearable.
> >> >
> >> >>
> >> >> > +        */
> >> >> > +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
> >> >> > +             host->ios.bus_width == MMC_BUS_WIDTH_8))
> >> >> > +               return 0;
> >> >> > +
> >> >> > +       /*
> >> >> > +        * Before setting BUS_WIDTH for dual data rate operation,
> >> >> > +        * HS_TIMING must be set to High Speed(0x1)
> >> >> > +        */
> >> >>
> >> >> Please rephrase comment:
> >> >>
> >> >> "Before switching to dual data rate operation for HS400, we need
> >> >> revert from HS200 timing to regular HS timing."
> >> > Ok.
> >> >
> >> >>
> >> >> > +       err = mmc_revert_to_hs(card);
> >> >>
> >> >> I don't think we need a separate function to handle the revert.
> >> >> Please, just add the code here instead. While you do that, I suppose
> >> >> we should combine the comment in that function into one comment here.
> >> > OK, I don't oppose that.
> >> >
> >> >>
> >> >> > +       if (err) {
> >> >> > +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> >> >> > +                       mmc_hostname(host), err);
> >> >> > +               return err;
> >> >> > +       }
> >> >> > +
> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> > +                        EXT_CSD_BUS_WIDTH,
> >> >> > +                        EXT_CSD_DDR_BUS_WIDTH_8,
> >> >> > +                        card->ext_csd.generic_cmd6_time);
> >> >> > +       if (err) {
> >> >> > +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> >> >> > +                       mmc_hostname(host), err);
> >> >> > +               return err;
> >> >> > +       }
> >> >> > +
> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> >> >> > +                        card->ext_csd.generic_cmd6_time);
> >> >> > +       if (err) {
> >> >> > +               pr_warn("%s: switch to hs400 failed, err:%d\n",
> >> >> > +                        mmc_hostname(host), err);
> >> >> > +               return err;
> >> >> > +       }
> >> >> > +
> >> >> > +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> >> >> > +       mmc_set_bus_speed(card);
> >> >> > +
> >> >> > +       return 0;
> >> >> > +}
> >> >> > +
> >> >> >  /*
> >> >> >   * For device supporting HS200 mode, the following sequence
> >> >> >   * should be done before executing the tuning process.
> >> >> > @@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
> >> >> >                                    EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> >> >> >                                    card->ext_csd.generic_cmd6_time,
> >> >> >                                    true, true, true);
> >> >> > -               if (!err)
> >> >> > +               if (err)
> >> >> > +                       goto err;
> >> >> > +
> >> >> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> >> >> > +                       /*
> >> >> > +                        * Timing should be adjusted to the HS400 target
> >> >> > +                        * operation frequency for tuning process
> >> >> > +                        */
> >> >> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> >> >>
> >> >> This seems strange. Do we really need a separate
> >> >> MMC_TIMING_MMC_HS400_TUNING value?
> >> > Spec. describes the HS400 selection sequence like below.
> >> > <Quot>
> >> > ...
> >> > 6) Perform the Tuning Process at the HS400 target operating frequency
> >> > (Note: tuning process in HS200 mode is required to synchronize the command response on the CMD
> line
> >> to CLK for HS400 operation).
> >> > ...
> >> > </Quot>
> >> > That means target clock rate for tuning sequence can be different with HS200.
> >> > Considering for that, it needs to distinguish.
> >>
> >> I understand the spec now, thanks.
> >>
> >> Still, I am not convinced we should handle this through the
> >> MMC_TIMING* field. That will leave host drivers to do some magic clock
> >> frequency calculation from their ->set_ios callbacks, just depending
> >> on the MMC_TIMING_MMC_HS400_TUNING value.
> >>
> >> I am also a bit concerned how MMC_TIMING_MMC_HS400_TUNING, would work
> >> if/when we implement periodic re-tuning - triggered from the mmc core
> >> layer.
> >>
> >> What we really want to do, is to pretend we were to operate in
> >> MMC_TIMING_MMC_HS400 and ask the host driver what the target frequency
> >> would be in this case. Then set this frequency through
> >> mmc_set_clock().
> >>
> >> Then how do we ask the host driver about this frequency? Let's add a
> >> new host_ops callback. We want it to be generic, so provide the
> >> MMC_TIMING bit as a parameter. Additionally we want it to be optional
> >> to implement, thus for those host drivers that supports the same
> >> target frequency for HS200 as for HS400, they don't need to implement
> >> it.
> >>
> >> Would this be a way forward?
> >
> > Thanks for your opinion.
> >
> > IMO, in this case additional callback handling seems to cause the complication in host side.
> > I think we don't need to ask host driver about target frequency for HS400 in order to set specific
> frequency through
> > mmc_set_clock().
> > Target frequency which core layer requires for HS400 will be 200MHz and it is also mentioned in
> specification.
> > Host driver including actual controller just will effort to make DDR rate with 200MHz.
> 
> What the mmc_set_clock() request is not the same as what the frequency
> actually will be set to. That depends on the host controller/driver.
> 
> If for some reason the host controller/driver are not able to use the
> same frequency for HS200 as for HS400, this should be possible to be
> addressed in the way I suggested.
I checked your sequence, but I'm not sure whether your suggestion is suitable for this.
As we know, in case of DDR52 clock rate requested by mmc_set_clock() is not different from High speed; Actually same 52Mhz is
requested.
It will be same in HS400 mode. Clock rate for mmc_set_clock() will be 200MHz in both HS200 and HS400.
Instead, host driver may control specific register for DDR rate output.
This is why core layer don't need call extra mmc_set_clock().
That means it doesn't need to ask host driver about frequency with using additional callback.
What core layer should do is to gives host driver timing information such as MMC_TIMING_MMC_HS400_TUNING.
Then, host can prepare specific timing setting for HS400 tuning.
As you mentioned, it depends on the host controller/driver.

> 
> > MMC_TIMING_MMC_HS400_TUNING may be used as notification for host to prepare HS400 tuning sequence.
> 
> So, are you saying that your controller are have different tuning
> methods for HS200 vs HS400? That's a different requirement, which of
> course we need to handle.
NO, tuning method is equal. I meant that host's setting for IO timing would be different.

> 
> > If host driver doesn't need to care MMC_TIMING_MMC_HS400_TUNING, it can be ignored.
> 
> It can't be ignored by host drivers, since drivers will need to cope
> with it even if it means that it will actively ignore it.
For this, you're right. Host driver may need to identify MMC_TIMING_MMC_HS400_TUNING.

Thanks,
Seungwon Jeon

> 
> Kind regards
> Ulf Hanssson
> 
> > Perhaps, we may need other opinions.
> >
> > Thanks,
> > Seungwon Jeon
> >
> >>
> >> Kind regards
> >> Ulf Hansson
> >>
> >> >
> >> >>
> >> >> > +               else
> >> >> >                         mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> >> >> >         }
> >> >> >  err:
> >> >> > @@ -1070,7 +1169,7 @@ bus_speed:
> >> >> >
> >> >> >  /*
> >> >> >   * Execute tuning sequence to seek the proper bus operating
> >> >> > - * conditions for HS200, which sends CMD21 to the device.
> >> >> > + * conditions for HS200 and HS400, which sends CMD21 to the device.
> >> >> >   */
> >> >> >  static int mmc_hs200_tuning(struct mmc_card *card)
> >> >> >  {
> >> >> > @@ -1304,6 +1403,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> >> >> >                 err = mmc_hs200_tuning(card);
> >> >> >                 if (err)
> >> >> >                         goto err;
> >> >> > +
> >> >> > +               err = mmc_select_hs400(card);
> >> >> > +               if (err)
> >> >> > +                       goto err;
> >> >> >         } else if (mmc_card_hs(card)) {
> >> >> >                 /* Select the desired bus width optionally */
> >> >> >                 err = mmc_select_bus_width(card);
> >> >> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> >> >> > index def6814..2b24c36 100644
> >> >> > --- a/include/linux/mmc/card.h
> >> >> > +++ b/include/linux/mmc/card.h
> >> >> > @@ -110,6 +110,7 @@ struct mmc_ext_csd {
> >> >> >         u8                      raw_pwr_cl_200_360;     /* 237 */
> >> >> >         u8                      raw_pwr_cl_ddr_52_195;  /* 238 */
> >> >> >         u8                      raw_pwr_cl_ddr_52_360;  /* 239 */
> >> >> > +       u8                      raw_pwr_cl_ddr_200_360; /* 253 */
> >> >> >         u8                      raw_bkops_status;       /* 246 */
> >> >> >         u8                      raw_sectors[4];         /* 212 - 4 bytes */
> >> >> >
> >> >> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> >> >> > index 1ee3c10..cc716e4 100644
> >> >> > --- a/include/linux/mmc/host.h
> >> >> > +++ b/include/linux/mmc/host.h
> >> >> > @@ -61,6 +61,8 @@ struct mmc_ios {
> >> >> >  #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_HS400_TUNING 11
> >> >>
> >> >> MMC_TIMING_MMC_HS400_TUNING ?
> >> >>
> >> >> >
> >> >> >         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
> >> >> >
> >> >> > @@ -274,6 +276,10 @@ struct mmc_host {
> >> >> >  #define MMC_CAP2_PACKED_CMD    (MMC_CAP2_PACKED_RD | \
> >> >> >                                  MMC_CAP2_PACKED_WR)
> >> >> >  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)  /* Don't power up before scan */
> >> >> > +#define MMC_CAP2_HS400_1_8V    (1 << 15)       /* Can support HS400 1.8V */
> >> >> > +#define MMC_CAP2_HS400_1_2V    (1 << 16)       /* Can support HS400 1.2V */
> >> >> > +#define MMC_CAP2_HS400         (MMC_CAP2_HS400_1_8V | \
> >> >> > +                                MMC_CAP2_HS400_1_2V)
> >> >> >
> >> >> >         mmc_pm_flag_t           pm_caps;        /* supported pm features */
> >> >> >
> >> >> > @@ -486,11 +492,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
> >> >> >
> >> >> >  static inline bool mmc_card_hs200(struct mmc_card *card)
> >> >> >  {
> >> >> > -       return card->host->ios.timing == MMC_TIMING_MMC_HS200;
> >> >> > +       return card->host->ios.timing == MMC_TIMING_MMC_HS200 ||
> >> >> > +               card->host->ios.timing == MMC_TIMING_MMC_HS400_TUNING;
> >> >>
> >> >> MMC_TIMING_MMC_HS400_TUNING ?
> >> > It also indicates that card is currently in HS200 mode with the result of setting HS_TIMING'.
> >> >
> >> > Thanks,
> >> > Seungwon Jeon
> >> >
> >> >>
> >> >> >  }
> >> >> >
> >> >> >  static inline bool mmc_card_ddr52(struct mmc_card *card)
> >> >> >  {
> >> >> >         return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
> >> >> >  }
> >> >> > +
> >> >> > +static inline bool mmc_card_hs400(struct mmc_card *card)
> >> >> > +{
> >> >> > +       return card->host->ios.timing == MMC_TIMING_MMC_HS400;
> >> >> > +}
> >> >> > +
> >> >> >  #endif /* LINUX_MMC_HOST_H */
> >> >> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> >> >> > index f429f13..64ec963 100644
> >> >> > --- a/include/linux/mmc/mmc.h
> >> >> > +++ b/include/linux/mmc/mmc.h
> >> >> > @@ -325,6 +325,7 @@ struct _mmc_csd {
> >> >> >  #define EXT_CSD_POWER_OFF_LONG_TIME    247     /* RO */
> >> >> >  #define EXT_CSD_GENERIC_CMD6_TIME      248     /* RO */
> >> >> >  #define EXT_CSD_CACHE_SIZE             249     /* RO, 4 bytes */
> >> >> > +#define EXT_CSD_PWR_CL_DDR_200_360     253     /* RO */
> >> >> >  #define EXT_CSD_TAG_UNIT_SIZE          498     /* RO */
> >> >> >  #define EXT_CSD_DATA_TAG_SUPPORT       499     /* RO */
> >> >> >  #define EXT_CSD_MAX_PACKED_WRITES      500     /* RO */
> >> >> > @@ -354,7 +355,6 @@ struct _mmc_csd {
> >> >> >  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
> >> >> >  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
> >> >> >
> >> >> > -#define EXT_CSD_CARD_TYPE_MASK 0x3F    /* Mask out reserved bits */
> >> >> >  #define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
> >> >> >  #define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
> >> >> >  #define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
> >> >> > @@ -370,6 +370,10 @@ struct _mmc_csd {
> >> >> >                                                 /* SDR mode @1.2V I/O */
> >> >> >  #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   (1<<6)  /* Card can run at 200MHz DDR, 1.8V */
> >> >> > +#define EXT_CSD_CARD_TYPE_HS400_1_2V   (1<<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_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
> >> >> >  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
> >> >> > @@ -380,6 +384,7 @@ struct _mmc_csd {
> >> >> >  #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_SEC_ER_EN      BIT(0)
> >> >> >  #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
> >> >> > --
> >> >> > 1.7.0.4
> >> >> >
> >> >> >
> >> >>
> >> >> Kind regards
> >> >> Ulf Hansson
> >> >> --
> >> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> >> >> the body of a message to majordomo@vger.kernel.org
> >> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >> >
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-04-02  1:15               ` Seungwon Jeon
@ 2014-04-02  9:39                 ` Ulf Hansson
  2014-04-03 11:53                   ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-04-02  9:39 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 2 April 2014 03:15, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> On Fri, March 28, 2014, Ulf Hansson wrote:
>> On 28 March 2014 13:18, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> > On Fri, March 28, 2014, Ulf Hansson wrote:
>> >> On 25 March 2014 10:23, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> >> > Hi Ulf,
>> >> >
>> >> > On Tue, March 25, 2014, Ulf Hansson wrote:
>> >> >> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> >> >> > 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: Seungwon Jeon <tgih.jun@samsung.com>
>> >> >> > Reviewed-by: Jackey Shen <jackey.shen@amd.com>
>> >> >> > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
>> >> >> > Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
>> >> >> > ---
>> >> >> >  drivers/mmc/core/bus.c     |    1 +
>> >> >> >  drivers/mmc/core/debugfs.c |    3 +
>> >> >> >  drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
>> >> >> >  include/linux/mmc/card.h   |    1 +
>> >> >> >  include/linux/mmc/host.h   |   15 +++++-
>> >> >> >  include/linux/mmc/mmc.h    |    7 ++-
>> >> >> >  6 files changed, 134 insertions(+), 8 deletions(-)
>> >> >> >
>> >> >> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> >> >> > index f37e9d6..d2dbf02 100644
>> >> >> > --- a/drivers/mmc/core/bus.c
>> >> >> > +++ b/drivers/mmc/core/bus.c
>> >> >> > @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
>> >> >> >                         mmc_hostname(card->host),
>> >> >> >                         mmc_card_uhs(card) ? "ultra high speed " :
>> >> >> >                         (mmc_card_hs(card) ? "high speed " : ""),
>> >> >> > +                       mmc_card_hs400(card) ? "HS400 " :
>> >> >> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
>> >> >> >                         mmc_card_ddr52(card) ? "DDR " : "",
>> >> >> >                         uhs_bus_speed_mode, type, card->rca);
>> >> >> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
>> >> >> > index 1f730db..91eb162 100644
>> >> >> > --- a/drivers/mmc/core/debugfs.c
>> >> >> > +++ b/drivers/mmc/core/debugfs.c
>> >> >> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>> >> >> >         case MMC_TIMING_MMC_HS200:
>> >> >> >                 str = "mmc HS200";
>> >> >> >                 break;
>> >> >> > +       case MMC_TIMING_MMC_HS400:
>> >> >> > +               str = "mmc HS400";
>> >> >> > +               break;
>> >> >> >         default:
>> >> >> >                 str = "invalid";
>> >> >> >                 break;
>> >> >> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> >> >> > index 6dd68e6..969d595 100644
>> >> >> > --- a/drivers/mmc/core/mmc.c
>> >> >> > +++ b/drivers/mmc/core/mmc.c
>> >> >> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
>> >> >> >  static void mmc_select_card_type(struct mmc_card *card)
>> >> >> >  {
>> >> >> >         struct mmc_host *host = card->host;
>> >> >> > -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>> >> >> > +       u8 card_type = card->ext_csd.raw_card_type;
>> >> >> >         u32 caps = host->caps, caps2 = host->caps2;
>> >> >> >         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>> >> >> >         unsigned int avail_type = 0;
>> >> >> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
>> >> >> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>> >> >> >         }
>> >> >> >
>> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_8V &&
>> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
>> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
>> >> >> > +       }
>> >> >> > +
>> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_2V &&
>> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
>> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>> >> >> > +       }
>> >> >> > +
>> >> >> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
>> >> >> >         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>> >> >> >         card->mmc_avail_type = avail_type;
>> >> >> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
>> >> >> >                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
>> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
>> >> >> > +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
>> >> >> > +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
>> >> >> >         }
>> >> >> >
>> >> >> >         if (card->ext_csd.rev >= 5) {
>> >> >> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
>> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
>> >> >> >                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
>> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
>> >> >> > -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
>> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
>> >> >> > +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
>> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
>> >> >> > +
>> >> >> >         if (err)
>> >> >> >                 err = -EINVAL;
>> >> >> >
>> >> >> > @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
>> >> >> >                                 ext_csd->raw_pwr_cl_52_360 :
>> >> >> >                                 ext_csd->raw_pwr_cl_ddr_52_360;
>> >> >> >                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
>> >> >> > -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
>> >> >> > +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
>> >> >> > +                               ext_csd->raw_pwr_cl_ddr_200_360 :
>> >> >> > +                               ext_csd->raw_pwr_cl_200_360;
>> >> >> >                 break;
>> >> >> >         default:
>> >> >> >                 pr_warning("%s: Voltage range not supported "
>> >> >> > @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
>> >> >> >  {
>> >> >> >         unsigned int max_dtr = (unsigned int)-1;
>> >> >> >
>> >> >> > -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
>> >> >> > +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
>> >> >> > +            max_dtr > card->ext_csd.hs200_max_dtr)
>> >> >> >                 max_dtr = card->ext_csd.hs200_max_dtr;
>> >> >> >         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
>> >> >> >                 max_dtr = card->ext_csd.hs_max_dtr;
>> >> >> > @@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
>> >> >> >  }
>> >> >> >
>> >> >> >  /*
>> >> >> > + * Revert to the high-speed mode from above speed
>> >> >> > + */
>> >> >> > +static int mmc_revert_to_hs(struct mmc_card *card)
>> >> >> > +{
>> >> >> > +       /*
>> >> >> > +        * CMD13, which is used to confirm the completion of timing
>> >> >> > +        * change, will be issued at higher speed timing condtion
>> >> >> > +        * rather than high-speed. If device has completed the change
>> >> >> > +        * to high-speed mode, it may not be proper timing to issue
>> >> >> > +        * command. Low speed supplies better timing margin than high
>> >> >> > +        * speed. Accordingly clock rate & timging should be chagned
>> >> >> > +        * ahead before actual switch.
>> >> >>
>> >> >> I have some problem to understand this comment. I guess you are trying
>> >> >> to provide the arguments to why it makes sense to perform the revert
>> >> >> to lower speed mode!?
>> >> >>
>> >> >> This makes me wonder if this is not part of the spec? Could you try to clarify?
>> >> > But specification says that "HS_TIMING must be set to "0x1" before setting BUS_WIDTH for dual
>> data
>> >> rate operation".
>> >> > I think this sequence is not graceful.
>> >> > I also commented why speed mode should be changed to high-speed mode from HS200 mode in the
>> >> function-called part.
>> >> > Because it is not possible to set 8-bit data bus for dual rate on HS200 mode, revert to high-
>> speed
>> >> from HS200 is needed.
>> >> > If the above-commented point makes it confused, it could be removed.
>> >> > Please let me know your opinion.
>> >> >
>> >> >>
>> >> >> > +        */
>> >> >> > +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> >> >> > +       mmc_set_bus_speed(card);
>> >> >> > +
>> >> >> > +       return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> > +                         EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
>> >> >> > +                         card->ext_csd.generic_cmd6_time);
>> >> >> > +}
>> >> >> > +
>> >> >> > +/*
>> >> >> >   * Activate wide bus and DDR if supported.
>> >> >> >   */
>> >> >> >  static int mmc_select_hs_ddr(struct mmc_card *card)
>> >> >> > @@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
>> >> >> >         return err;
>> >> >> >  }
>> >> >> >
>> >> >> > +static int mmc_select_hs400(struct mmc_card *card)
>> >> >> > +{
>> >> >> > +       struct mmc_host *host = card->host;
>> >> >> > +       int err = 0;
>> >> >> > +
>> >> >> > +       /*
>> >> >> > +        * The bus width is set to only 8 DDR in HS400 mode
>> >> >>
>> >> >> Please rephrase the comment to something like:
>> >> >> "HS400 mode requires 8-bit bus width."
>> >> > As it is, it was from spec's description.
>> >> > But I think yours would be more clearable.
>> >> >
>> >> >>
>> >> >> > +        */
>> >> >> > +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
>> >> >> > +             host->ios.bus_width == MMC_BUS_WIDTH_8))
>> >> >> > +               return 0;
>> >> >> > +
>> >> >> > +       /*
>> >> >> > +        * Before setting BUS_WIDTH for dual data rate operation,
>> >> >> > +        * HS_TIMING must be set to High Speed(0x1)
>> >> >> > +        */
>> >> >>
>> >> >> Please rephrase comment:
>> >> >>
>> >> >> "Before switching to dual data rate operation for HS400, we need
>> >> >> revert from HS200 timing to regular HS timing."
>> >> > Ok.
>> >> >
>> >> >>
>> >> >> > +       err = mmc_revert_to_hs(card);
>> >> >>
>> >> >> I don't think we need a separate function to handle the revert.
>> >> >> Please, just add the code here instead. While you do that, I suppose
>> >> >> we should combine the comment in that function into one comment here.
>> >> > OK, I don't oppose that.
>> >> >
>> >> >>
>> >> >> > +       if (err) {
>> >> >> > +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
>> >> >> > +                       mmc_hostname(host), err);
>> >> >> > +               return err;
>> >> >> > +       }
>> >> >> > +
>> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> > +                        EXT_CSD_BUS_WIDTH,
>> >> >> > +                        EXT_CSD_DDR_BUS_WIDTH_8,
>> >> >> > +                        card->ext_csd.generic_cmd6_time);
>> >> >> > +       if (err) {
>> >> >> > +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
>> >> >> > +                       mmc_hostname(host), err);
>> >> >> > +               return err;
>> >> >> > +       }
>> >> >> > +
>> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
>> >> >> > +                        card->ext_csd.generic_cmd6_time);
>> >> >> > +       if (err) {
>> >> >> > +               pr_warn("%s: switch to hs400 failed, err:%d\n",
>> >> >> > +                        mmc_hostname(host), err);
>> >> >> > +               return err;
>> >> >> > +       }
>> >> >> > +
>> >> >> > +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>> >> >> > +       mmc_set_bus_speed(card);
>> >> >> > +
>> >> >> > +       return 0;
>> >> >> > +}
>> >> >> > +
>> >> >> >  /*
>> >> >> >   * For device supporting HS200 mode, the following sequence
>> >> >> >   * should be done before executing the tuning process.
>> >> >> > @@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
>> >> >> >                                    EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
>> >> >> >                                    card->ext_csd.generic_cmd6_time,
>> >> >> >                                    true, true, true);
>> >> >> > -               if (!err)
>> >> >> > +               if (err)
>> >> >> > +                       goto err;
>> >> >> > +
>> >> >> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
>> >> >> > +                       /*
>> >> >> > +                        * Timing should be adjusted to the HS400 target
>> >> >> > +                        * operation frequency for tuning process
>> >> >> > +                        */
>> >> >> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
>> >> >>
>> >> >> This seems strange. Do we really need a separate
>> >> >> MMC_TIMING_MMC_HS400_TUNING value?
>> >> > Spec. describes the HS400 selection sequence like below.
>> >> > <Quot>
>> >> > ...
>> >> > 6) Perform the Tuning Process at the HS400 target operating frequency
>> >> > (Note: tuning process in HS200 mode is required to synchronize the command response on the CMD
>> line
>> >> to CLK for HS400 operation).
>> >> > ...
>> >> > </Quot>
>> >> > That means target clock rate for tuning sequence can be different with HS200.
>> >> > Considering for that, it needs to distinguish.
>> >>
>> >> I understand the spec now, thanks.
>> >>
>> >> Still, I am not convinced we should handle this through the
>> >> MMC_TIMING* field. That will leave host drivers to do some magic clock
>> >> frequency calculation from their ->set_ios callbacks, just depending
>> >> on the MMC_TIMING_MMC_HS400_TUNING value.
>> >>
>> >> I am also a bit concerned how MMC_TIMING_MMC_HS400_TUNING, would work
>> >> if/when we implement periodic re-tuning - triggered from the mmc core
>> >> layer.
>> >>
>> >> What we really want to do, is to pretend we were to operate in
>> >> MMC_TIMING_MMC_HS400 and ask the host driver what the target frequency
>> >> would be in this case. Then set this frequency through
>> >> mmc_set_clock().
>> >>
>> >> Then how do we ask the host driver about this frequency? Let's add a
>> >> new host_ops callback. We want it to be generic, so provide the
>> >> MMC_TIMING bit as a parameter. Additionally we want it to be optional
>> >> to implement, thus for those host drivers that supports the same
>> >> target frequency for HS200 as for HS400, they don't need to implement
>> >> it.
>> >>
>> >> Would this be a way forward?
>> >
>> > Thanks for your opinion.
>> >
>> > IMO, in this case additional callback handling seems to cause the complication in host side.
>> > I think we don't need to ask host driver about target frequency for HS400 in order to set specific
>> frequency through
>> > mmc_set_clock().
>> > Target frequency which core layer requires for HS400 will be 200MHz and it is also mentioned in
>> specification.
>> > Host driver including actual controller just will effort to make DDR rate with 200MHz.
>>
>> What the mmc_set_clock() request is not the same as what the frequency
>> actually will be set to. That depends on the host controller/driver.
>>
>> If for some reason the host controller/driver are not able to use the
>> same frequency for HS200 as for HS400, this should be possible to be
>> addressed in the way I suggested.
> I checked your sequence, but I'm not sure whether your suggestion is suitable for this.
> As we know, in case of DDR52 clock rate requested by mmc_set_clock() is not different from High speed; Actually same 52Mhz is
> requested.
> It will be same in HS400 mode. Clock rate for mmc_set_clock() will be 200MHz in both HS200 and HS400.
> Instead, host driver may control specific register for DDR rate output.
> This is why core layer don't need call extra mmc_set_clock().
> That means it doesn't need to ask host driver about frequency with using additional callback.
> What core layer should do is to gives host driver timing information such as MMC_TIMING_MMC_HS400_TUNING.
> Then, host can prepare specific timing setting for HS400 tuning.
> As you mentioned, it depends on the host controller/driver.

The reason why I suggested to add a new host_ops callback and to use
the mmc_set_clock() method was to address what's mentioned in the
spec, which you pointed me to.

So, now you are saying we don't need to consider this scenario,
because very likely we will be using the same frequency as for HS200.

Okay - let's leave this to be implemented if/when we see there is a need for it.

>
>>
>> > MMC_TIMING_MMC_HS400_TUNING may be used as notification for host to prepare HS400 tuning sequence.
>>
>> So, are you saying that your controller are have different tuning
>> methods for HS200 vs HS400? That's a different requirement, which of
>> course we need to handle.
> NO, tuning method is equal. I meant that host's setting for IO timing would be different.

I suppose this means the host don't need to bother about HS400 (at
all) during tuning sequence and thus we don't need the
MMC_TIMING_MMC_HS400_TUNING timing? Or am I missing your point?

While we are discussion this, what about re-tuning? Is that also
supposed to be done in HS200 mode?

Kind regards
Ulf Hansson

>
>>
>> > If host driver doesn't need to care MMC_TIMING_MMC_HS400_TUNING, it can be ignored.
>>
>> It can't be ignored by host drivers, since drivers will need to cope
>> with it even if it means that it will actively ignore it.
> For this, you're right. Host driver may need to identify MMC_TIMING_MMC_HS400_TUNING.
>
> Thanks,
> Seungwon Jeon
>
>>
>> Kind regards
>> Ulf Hanssson
>>
>> > Perhaps, we may need other opinions.
>> >
>> > Thanks,
>> > Seungwon Jeon
>> >
>> >>
>> >> Kind regards
>> >> Ulf Hansson
>> >>
>> >> >
>> >> >>
>> >> >> > +               else
>> >> >> >                         mmc_set_timing(host, MMC_TIMING_MMC_HS200);
>> >> >> >         }
>> >> >> >  err:
>> >> >> > @@ -1070,7 +1169,7 @@ bus_speed:
>> >> >> >
>> >> >> >  /*
>> >> >> >   * Execute tuning sequence to seek the proper bus operating
>> >> >> > - * conditions for HS200, which sends CMD21 to the device.
>> >> >> > + * conditions for HS200 and HS400, which sends CMD21 to the device.
>> >> >> >   */
>> >> >> >  static int mmc_hs200_tuning(struct mmc_card *card)
>> >> >> >  {
>> >> >> > @@ -1304,6 +1403,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>> >> >> >                 err = mmc_hs200_tuning(card);
>> >> >> >                 if (err)
>> >> >> >                         goto err;
>> >> >> > +
>> >> >> > +               err = mmc_select_hs400(card);
>> >> >> > +               if (err)
>> >> >> > +                       goto err;
>> >> >> >         } else if (mmc_card_hs(card)) {
>> >> >> >                 /* Select the desired bus width optionally */
>> >> >> >                 err = mmc_select_bus_width(card);
>> >> >> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> >> >> > index def6814..2b24c36 100644
>> >> >> > --- a/include/linux/mmc/card.h
>> >> >> > +++ b/include/linux/mmc/card.h
>> >> >> > @@ -110,6 +110,7 @@ struct mmc_ext_csd {
>> >> >> >         u8                      raw_pwr_cl_200_360;     /* 237 */
>> >> >> >         u8                      raw_pwr_cl_ddr_52_195;  /* 238 */
>> >> >> >         u8                      raw_pwr_cl_ddr_52_360;  /* 239 */
>> >> >> > +       u8                      raw_pwr_cl_ddr_200_360; /* 253 */
>> >> >> >         u8                      raw_bkops_status;       /* 246 */
>> >> >> >         u8                      raw_sectors[4];         /* 212 - 4 bytes */
>> >> >> >
>> >> >> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> >> >> > index 1ee3c10..cc716e4 100644
>> >> >> > --- a/include/linux/mmc/host.h
>> >> >> > +++ b/include/linux/mmc/host.h
>> >> >> > @@ -61,6 +61,8 @@ struct mmc_ios {
>> >> >> >  #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_HS400_TUNING 11
>> >> >>
>> >> >> MMC_TIMING_MMC_HS400_TUNING ?
>> >> >>
>> >> >> >
>> >> >> >         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
>> >> >> >
>> >> >> > @@ -274,6 +276,10 @@ struct mmc_host {
>> >> >> >  #define MMC_CAP2_PACKED_CMD    (MMC_CAP2_PACKED_RD | \
>> >> >> >                                  MMC_CAP2_PACKED_WR)
>> >> >> >  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)  /* Don't power up before scan */
>> >> >> > +#define MMC_CAP2_HS400_1_8V    (1 << 15)       /* Can support HS400 1.8V */
>> >> >> > +#define MMC_CAP2_HS400_1_2V    (1 << 16)       /* Can support HS400 1.2V */
>> >> >> > +#define MMC_CAP2_HS400         (MMC_CAP2_HS400_1_8V | \
>> >> >> > +                                MMC_CAP2_HS400_1_2V)
>> >> >> >
>> >> >> >         mmc_pm_flag_t           pm_caps;        /* supported pm features */
>> >> >> >
>> >> >> > @@ -486,11 +492,18 @@ static inline int mmc_card_uhs(struct mmc_card *card)
>> >> >> >
>> >> >> >  static inline bool mmc_card_hs200(struct mmc_card *card)
>> >> >> >  {
>> >> >> > -       return card->host->ios.timing == MMC_TIMING_MMC_HS200;
>> >> >> > +       return card->host->ios.timing == MMC_TIMING_MMC_HS200 ||
>> >> >> > +               card->host->ios.timing == MMC_TIMING_MMC_HS400_TUNING;
>> >> >>
>> >> >> MMC_TIMING_MMC_HS400_TUNING ?
>> >> > It also indicates that card is currently in HS200 mode with the result of setting HS_TIMING'.
>> >> >
>> >> > Thanks,
>> >> > Seungwon Jeon
>> >> >
>> >> >>
>> >> >> >  }
>> >> >> >
>> >> >> >  static inline bool mmc_card_ddr52(struct mmc_card *card)
>> >> >> >  {
>> >> >> >         return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
>> >> >> >  }
>> >> >> > +
>> >> >> > +static inline bool mmc_card_hs400(struct mmc_card *card)
>> >> >> > +{
>> >> >> > +       return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>> >> >> > +}
>> >> >> > +
>> >> >> >  #endif /* LINUX_MMC_HOST_H */
>> >> >> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> >> >> > index f429f13..64ec963 100644
>> >> >> > --- a/include/linux/mmc/mmc.h
>> >> >> > +++ b/include/linux/mmc/mmc.h
>> >> >> > @@ -325,6 +325,7 @@ struct _mmc_csd {
>> >> >> >  #define EXT_CSD_POWER_OFF_LONG_TIME    247     /* RO */
>> >> >> >  #define EXT_CSD_GENERIC_CMD6_TIME      248     /* RO */
>> >> >> >  #define EXT_CSD_CACHE_SIZE             249     /* RO, 4 bytes */
>> >> >> > +#define EXT_CSD_PWR_CL_DDR_200_360     253     /* RO */
>> >> >> >  #define EXT_CSD_TAG_UNIT_SIZE          498     /* RO */
>> >> >> >  #define EXT_CSD_DATA_TAG_SUPPORT       499     /* RO */
>> >> >> >  #define EXT_CSD_MAX_PACKED_WRITES      500     /* RO */
>> >> >> > @@ -354,7 +355,6 @@ struct _mmc_csd {
>> >> >> >  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
>> >> >> >  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
>> >> >> >
>> >> >> > -#define EXT_CSD_CARD_TYPE_MASK 0x3F    /* Mask out reserved bits */
>> >> >> >  #define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
>> >> >> >  #define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
>> >> >> >  #define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
>> >> >> > @@ -370,6 +370,10 @@ struct _mmc_csd {
>> >> >> >                                                 /* SDR mode @1.2V I/O */
>> >> >> >  #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   (1<<6)  /* Card can run at 200MHz DDR, 1.8V */
>> >> >> > +#define EXT_CSD_CARD_TYPE_HS400_1_2V   (1<<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_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>> >> >> >  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
>> >> >> > @@ -380,6 +384,7 @@ struct _mmc_csd {
>> >> >> >  #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_SEC_ER_EN      BIT(0)
>> >> >> >  #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
>> >> >> > --
>> >> >> > 1.7.0.4
>> >> >> >
>> >> >> >
>> >> >>
>> >> >> Kind regards
>> >> >> Ulf Hansson
>> >> >> --
>> >> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> >> >> the body of a message to majordomo@vger.kernel.org
>> >> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> >> >
>> >> --
>> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> >> the body of a message to majordomo@vger.kernel.org
>> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> >
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

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

* Re: [PATCH RESEND v3 0/7] mmc: distinguish DDR timing mode for eMMC/UHS
  2014-03-14 12:11   ` [PATCH RESEND " Seungwon Jeon
@ 2014-04-02 11:50     ` Ulf Hansson
  2014-04-03 11:56       ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-04-02 11:50 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Rickard Andersson,
	Russell King - ARM Linux, balajitk, Guennadi Liakhovetski,
	Wei WANG, Samuel Ortiz, Jaehoon Chung

On 14 March 2014 13:11, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> These changes intend to distinguish two DDR timing modes related to eMMC & UHS.
> Even though two modes are different actually, UHS_DDR50 is used as eMMC DDR mode.
> MMC_TIMING_MMC_DDR52 mode is added.

This will likely be one of first patchset applied to mmc-next when
next 3.15 rc[n] becomes available.

>From a bi-sectable point of view, we should squash the enrire patchset
into one patch. I hope you are fine with that Seungwon!? If some of
the host driver maintainers prefer another solution, also please tell
me.

Kind regards
Ulf Hansson

>
> Changes in V3:
>         (6/7) Added MMC-DDR52 mode instead of replacing UHS-DDR50 in dw_mmc-exynos
>
> Changes in V2:
>         (2/7) Added MMC-DDR52 mode instead of replacing UHS-DDR50 in mmci
>
> Seungwon Jeon (7):
>   mmc: clarify DDR timing mode between SD-UHS and eMMC
>   mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
>   mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
>   mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
>   mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
>   mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
>   mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC
>
>  drivers/mmc/core/debugfs.c        |    3 +++
>  drivers/mmc/core/mmc.c            |    2 +-
>  drivers/mmc/host/dw_mmc-exynos.c  |    5 ++---
>  drivers/mmc/host/dw_mmc.c         |    2 +-
>  drivers/mmc/host/mmci.c           |    6 ++++--
>  drivers/mmc/host/omap_hsmmc.c     |    4 ++--
>  drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
>  drivers/mmc/host/sdhci.c          |    4 +++-
>  drivers/mmc/host/sh_mmcif.c       |    9 +++++----
>  include/linux/mmc/host.h          |    3 ++-
>  10 files changed, 25 insertions(+), 15 deletions(-)>
>
>
> Thanks,
> sw-j
>

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

* RE: [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-04-02  9:39                 ` Ulf Hansson
@ 2014-04-03 11:53                   ` Seungwon Jeon
  2014-04-03 13:14                     ` Ulf Hansson
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-03 11:53 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On Wed, April 02, 2014, Ulf Hansson wrote:
> On 2 April 2014 03:15, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > On Fri, March 28, 2014, Ulf Hansson wrote:
> >> On 28 March 2014 13:18, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> > On Fri, March 28, 2014, Ulf Hansson wrote:
> >> >> On 25 March 2014 10:23, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> >> > Hi Ulf,
> >> >> >
> >> >> > On Tue, March 25, 2014, Ulf Hansson wrote:
> >> >> >> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> >> >> > 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: Seungwon Jeon <tgih.jun@samsung.com>
> >> >> >> > Reviewed-by: Jackey Shen <jackey.shen@amd.com>
> >> >> >> > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
> >> >> >> > Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
> >> >> >> > ---
> >> >> >> >  drivers/mmc/core/bus.c     |    1 +
> >> >> >> >  drivers/mmc/core/debugfs.c |    3 +
> >> >> >> >  drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
> >> >> >> >  include/linux/mmc/card.h   |    1 +
> >> >> >> >  include/linux/mmc/host.h   |   15 +++++-
> >> >> >> >  include/linux/mmc/mmc.h    |    7 ++-
> >> >> >> >  6 files changed, 134 insertions(+), 8 deletions(-)
> >> >> >> >
> >> >> >> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> >> >> >> > index f37e9d6..d2dbf02 100644
> >> >> >> > --- a/drivers/mmc/core/bus.c
> >> >> >> > +++ b/drivers/mmc/core/bus.c
> >> >> >> > @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
> >> >> >> >                         mmc_hostname(card->host),
> >> >> >> >                         mmc_card_uhs(card) ? "ultra high speed " :
> >> >> >> >                         (mmc_card_hs(card) ? "high speed " : ""),
> >> >> >> > +                       mmc_card_hs400(card) ? "HS400 " :
> >> >> >> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
> >> >> >> >                         mmc_card_ddr52(card) ? "DDR " : "",
> >> >> >> >                         uhs_bus_speed_mode, type, card->rca);
> >> >> >> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> >> >> >> > index 1f730db..91eb162 100644
> >> >> >> > --- a/drivers/mmc/core/debugfs.c
> >> >> >> > +++ b/drivers/mmc/core/debugfs.c
> >> >> >> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
> >> >> >> >         case MMC_TIMING_MMC_HS200:
> >> >> >> >                 str = "mmc HS200";
> >> >> >> >                 break;
> >> >> >> > +       case MMC_TIMING_MMC_HS400:
> >> >> >> > +               str = "mmc HS400";
> >> >> >> > +               break;
> >> >> >> >         default:
> >> >> >> >                 str = "invalid";
> >> >> >> >                 break;
> >> >> >> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >> >> >> > index 6dd68e6..969d595 100644
> >> >> >> > --- a/drivers/mmc/core/mmc.c
> >> >> >> > +++ b/drivers/mmc/core/mmc.c
> >> >> >> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
> >> >> >> >  static void mmc_select_card_type(struct mmc_card *card)
> >> >> >> >  {
> >> >> >> >         struct mmc_host *host = card->host;
> >> >> >> > -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> >> >> >> > +       u8 card_type = card->ext_csd.raw_card_type;
> >> >> >> >         u32 caps = host->caps, caps2 = host->caps2;
> >> >> >> >         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
> >> >> >> >         unsigned int avail_type = 0;
> >> >> >> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
> >> >> >> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> >> >> >> >         }
> >> >> >> >
> >> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_8V &&
> >> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> >> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> >> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> >> >> >> > +       }
> >> >> >> > +
> >> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_2V &&
> >> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> >> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> >> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> >> >> >> > +       }
> >> >> >> > +
> >> >> >> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
> >> >> >> >         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
> >> >> >> >         card->mmc_avail_type = avail_type;
> >> >> >> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
> >> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
> >> >> >> >                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
> >> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> >> >> >> > +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
> >> >> >> > +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
> >> >> >> >         }
> >> >> >> >
> >> >> >> >         if (card->ext_csd.rev >= 5) {
> >> >> >> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned
> bus_width)
> >> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
> >> >> >> >                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
> >> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> >> >> >> > -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> >> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> >> >> >> > +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> >> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> >> >> >> > +
> >> >> >> >         if (err)
> >> >> >> >                 err = -EINVAL;
> >> >> >> >
> >> >> >> > @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> >> >> >> >                                 ext_csd->raw_pwr_cl_52_360 :
> >> >> >> >                                 ext_csd->raw_pwr_cl_ddr_52_360;
> >> >> >> >                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> >> >> >> > -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
> >> >> >> > +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> >> >> >> > +                               ext_csd->raw_pwr_cl_ddr_200_360 :
> >> >> >> > +                               ext_csd->raw_pwr_cl_200_360;
> >> >> >> >                 break;
> >> >> >> >         default:
> >> >> >> >                 pr_warning("%s: Voltage range not supported "
> >> >> >> > @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
> >> >> >> >  {
> >> >> >> >         unsigned int max_dtr = (unsigned int)-1;
> >> >> >> >
> >> >> >> > -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> >> >> >> > +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
> >> >> >> > +            max_dtr > card->ext_csd.hs200_max_dtr)
> >> >> >> >                 max_dtr = card->ext_csd.hs200_max_dtr;
> >> >> >> >         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
> >> >> >> >                 max_dtr = card->ext_csd.hs_max_dtr;
> >> >> >> > @@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
> >> >> >> >  }
> >> >> >> >
> >> >> >> >  /*
> >> >> >> > + * Revert to the high-speed mode from above speed
> >> >> >> > + */
> >> >> >> > +static int mmc_revert_to_hs(struct mmc_card *card)
> >> >> >> > +{
> >> >> >> > +       /*
> >> >> >> > +        * CMD13, which is used to confirm the completion of timing
> >> >> >> > +        * change, will be issued at higher speed timing condtion
> >> >> >> > +        * rather than high-speed. If device has completed the change
> >> >> >> > +        * to high-speed mode, it may not be proper timing to issue
> >> >> >> > +        * command. Low speed supplies better timing margin than high
> >> >> >> > +        * speed. Accordingly clock rate & timging should be chagned
> >> >> >> > +        * ahead before actual switch.
> >> >> >>
> >> >> >> I have some problem to understand this comment. I guess you are trying
> >> >> >> to provide the arguments to why it makes sense to perform the revert
> >> >> >> to lower speed mode!?
> >> >> >>
> >> >> >> This makes me wonder if this is not part of the spec? Could you try to clarify?
> >> >> > But specification says that "HS_TIMING must be set to "0x1" before setting BUS_WIDTH for dual
> >> data
> >> >> rate operation".
> >> >> > I think this sequence is not graceful.
> >> >> > I also commented why speed mode should be changed to high-speed mode from HS200 mode in the
> >> >> function-called part.
> >> >> > Because it is not possible to set 8-bit data bus for dual rate on HS200 mode, revert to high-
> >> speed
> >> >> from HS200 is needed.
> >> >> > If the above-commented point makes it confused, it could be removed.
> >> >> > Please let me know your opinion.
> >> >> >
> >> >> >>
> >> >> >> > +        */
> >> >> >> > +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> >> >> >> > +       mmc_set_bus_speed(card);
> >> >> >> > +
> >> >> >> > +       return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> >> > +                         EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> >> >> >> > +                         card->ext_csd.generic_cmd6_time);
> >> >> >> > +}
> >> >> >> > +
> >> >> >> > +/*
> >> >> >> >   * Activate wide bus and DDR if supported.
> >> >> >> >   */
> >> >> >> >  static int mmc_select_hs_ddr(struct mmc_card *card)
> >> >> >> > @@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
> >> >> >> >         return err;
> >> >> >> >  }
> >> >> >> >
> >> >> >> > +static int mmc_select_hs400(struct mmc_card *card)
> >> >> >> > +{
> >> >> >> > +       struct mmc_host *host = card->host;
> >> >> >> > +       int err = 0;
> >> >> >> > +
> >> >> >> > +       /*
> >> >> >> > +        * The bus width is set to only 8 DDR in HS400 mode
> >> >> >>
> >> >> >> Please rephrase the comment to something like:
> >> >> >> "HS400 mode requires 8-bit bus width."
> >> >> > As it is, it was from spec's description.
> >> >> > But I think yours would be more clearable.
> >> >> >
> >> >> >>
> >> >> >> > +        */
> >> >> >> > +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
> >> >> >> > +             host->ios.bus_width == MMC_BUS_WIDTH_8))
> >> >> >> > +               return 0;
> >> >> >> > +
> >> >> >> > +       /*
> >> >> >> > +        * Before setting BUS_WIDTH for dual data rate operation,
> >> >> >> > +        * HS_TIMING must be set to High Speed(0x1)
> >> >> >> > +        */
> >> >> >>
> >> >> >> Please rephrase comment:
> >> >> >>
> >> >> >> "Before switching to dual data rate operation for HS400, we need
> >> >> >> revert from HS200 timing to regular HS timing."
> >> >> > Ok.
> >> >> >
> >> >> >>
> >> >> >> > +       err = mmc_revert_to_hs(card);
> >> >> >>
> >> >> >> I don't think we need a separate function to handle the revert.
> >> >> >> Please, just add the code here instead. While you do that, I suppose
> >> >> >> we should combine the comment in that function into one comment here.
> >> >> > OK, I don't oppose that.
> >> >> >
> >> >> >>
> >> >> >> > +       if (err) {
> >> >> >> > +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> >> >> >> > +                       mmc_hostname(host), err);
> >> >> >> > +               return err;
> >> >> >> > +       }
> >> >> >> > +
> >> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> >> > +                        EXT_CSD_BUS_WIDTH,
> >> >> >> > +                        EXT_CSD_DDR_BUS_WIDTH_8,
> >> >> >> > +                        card->ext_csd.generic_cmd6_time);
> >> >> >> > +       if (err) {
> >> >> >> > +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> >> >> >> > +                       mmc_hostname(host), err);
> >> >> >> > +               return err;
> >> >> >> > +       }
> >> >> >> > +
> >> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> >> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> >> >> >> > +                        card->ext_csd.generic_cmd6_time);
> >> >> >> > +       if (err) {
> >> >> >> > +               pr_warn("%s: switch to hs400 failed, err:%d\n",
> >> >> >> > +                        mmc_hostname(host), err);
> >> >> >> > +               return err;
> >> >> >> > +       }
> >> >> >> > +
> >> >> >> > +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> >> >> >> > +       mmc_set_bus_speed(card);
> >> >> >> > +
> >> >> >> > +       return 0;
> >> >> >> > +}
> >> >> >> > +
> >> >> >> >  /*
> >> >> >> >   * For device supporting HS200 mode, the following sequence
> >> >> >> >   * should be done before executing the tuning process.
> >> >> >> > @@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
> >> >> >> >                                    EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> >> >> >> >                                    card->ext_csd.generic_cmd6_time,
> >> >> >> >                                    true, true, true);
> >> >> >> > -               if (!err)
> >> >> >> > +               if (err)
> >> >> >> > +                       goto err;
> >> >> >> > +
> >> >> >> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> >> >> >> > +                       /*
> >> >> >> > +                        * Timing should be adjusted to the HS400 target
> >> >> >> > +                        * operation frequency for tuning process
> >> >> >> > +                        */
> >> >> >> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> >> >> >>
> >> >> >> This seems strange. Do we really need a separate
> >> >> >> MMC_TIMING_MMC_HS400_TUNING value?
> >> >> > Spec. describes the HS400 selection sequence like below.
> >> >> > <Quot>
> >> >> > ...
> >> >> > 6) Perform the Tuning Process at the HS400 target operating frequency
> >> >> > (Note: tuning process in HS200 mode is required to synchronize the command response on the CMD
> >> line
> >> >> to CLK for HS400 operation).
> >> >> > ...
> >> >> > </Quot>
> >> >> > That means target clock rate for tuning sequence can be different with HS200.
> >> >> > Considering for that, it needs to distinguish.
> >> >>
> >> >> I understand the spec now, thanks.
> >> >>
> >> >> Still, I am not convinced we should handle this through the
> >> >> MMC_TIMING* field. That will leave host drivers to do some magic clock
> >> >> frequency calculation from their ->set_ios callbacks, just depending
> >> >> on the MMC_TIMING_MMC_HS400_TUNING value.
> >> >>
> >> >> I am also a bit concerned how MMC_TIMING_MMC_HS400_TUNING, would work
> >> >> if/when we implement periodic re-tuning - triggered from the mmc core
> >> >> layer.
> >> >>
> >> >> What we really want to do, is to pretend we were to operate in
> >> >> MMC_TIMING_MMC_HS400 and ask the host driver what the target frequency
> >> >> would be in this case. Then set this frequency through
> >> >> mmc_set_clock().
> >> >>
> >> >> Then how do we ask the host driver about this frequency? Let's add a
> >> >> new host_ops callback. We want it to be generic, so provide the
> >> >> MMC_TIMING bit as a parameter. Additionally we want it to be optional
> >> >> to implement, thus for those host drivers that supports the same
> >> >> target frequency for HS200 as for HS400, they don't need to implement
> >> >> it.
> >> >>
> >> >> Would this be a way forward?
> >> >
> >> > Thanks for your opinion.
> >> >
> >> > IMO, in this case additional callback handling seems to cause the complication in host side.
> >> > I think we don't need to ask host driver about target frequency for HS400 in order to set
> specific
> >> frequency through
> >> > mmc_set_clock().
> >> > Target frequency which core layer requires for HS400 will be 200MHz and it is also mentioned in
> >> specification.
> >> > Host driver including actual controller just will effort to make DDR rate with 200MHz.
> >>
> >> What the mmc_set_clock() request is not the same as what the frequency
> >> actually will be set to. That depends on the host controller/driver.
> >>
> >> If for some reason the host controller/driver are not able to use the
> >> same frequency for HS200 as for HS400, this should be possible to be
> >> addressed in the way I suggested.
> > I checked your sequence, but I'm not sure whether your suggestion is suitable for this.
> > As we know, in case of DDR52 clock rate requested by mmc_set_clock() is not different from High
> speed; Actually same 52Mhz is
> > requested.
> > It will be same in HS400 mode. Clock rate for mmc_set_clock() will be 200MHz in both HS200 and HS400.
> > Instead, host driver may control specific register for DDR rate output.
> > This is why core layer don't need call extra mmc_set_clock().
> > That means it doesn't need to ask host driver about frequency with using additional callback.
> > What core layer should do is to gives host driver timing information such as
> MMC_TIMING_MMC_HS400_TUNING.
> > Then, host can prepare specific timing setting for HS400 tuning.
> > As you mentioned, it depends on the host controller/driver.
> 
> The reason why I suggested to add a new host_ops callback and to use
> the mmc_set_clock() method was to address what's mentioned in the
> spec, which you pointed me to.
> 
> So, now you are saying we don't need to consider this scenario,
> because very likely we will be using the same frequency as for HS200.
I didn't mean actual output clock frequency.
Just mentioned required clock rate through mmc_set_clock() in core layer.

I think clock generation depends on host controller.
For higher speed, some programmable setting will be needed.
Hopefully, you could find the following patch to check how HS400 is handled in host driver.
Exynos host changes internal clock rate for HS400 mode.
"[PATCH v2 5/7] mmc: dw_mmc: exynos: support eMMC's HS400 mode"

> 
> Okay - let's leave this to be implemented if/when we see there is a need for it.
> 
> >
> >>
> >> > MMC_TIMING_MMC_HS400_TUNING may be used as notification for host to prepare HS400 tuning sequence.
> >>
> >> So, are you saying that your controller are have different tuning
> >> methods for HS200 vs HS400? That's a different requirement, which of
> >> course we need to handle.
> > NO, tuning method is equal. I meant that host's setting for IO timing would be different.
> 
> I suppose this means the host don't need to bother about HS400 (at
> all) during tuning sequence and thus we don't need the
> MMC_TIMING_MMC_HS400_TUNING timing? Or am I missing your point?
Please check the patch I mentioned above.

> 
> While we are discussion this, what about re-tuning? Is that also
> supposed to be done in HS200 mode?
I guess re-tuning is not related to this patch.
OK, Can you say in more detail?
I didn't get your meaning.

Thanks,
Seungwon Jeon


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

* RE: [PATCH RESEND v3 0/7] mmc: distinguish DDR timing mode for eMMC/UHS
  2014-04-02 11:50     ` Ulf Hansson
@ 2014-04-03 11:56       ` Seungwon Jeon
  0 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-03 11:56 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Rickard Andersson', 'Russell King - ARM Linux',
	'balajitk', 'Guennadi Liakhovetski',
	'Wei WANG', 'Samuel Ortiz',
	'Jaehoon Chung'

On Wed, April 02, 2014, Ulf Hansson wrote:
> On 14 March 2014 13:11, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > These changes intend to distinguish two DDR timing modes related to eMMC & UHS.
> > Even though two modes are different actually, UHS_DDR50 is used as eMMC DDR mode.
> > MMC_TIMING_MMC_DDR52 mode is added.
> 
> This will likely be one of first patchset applied to mmc-next when
> next 3.15 rc[n] becomes available.
Hi Chris,

Do you have any plan to pick this patch-set for 3.15?
I think there is no functional change.

Thanks,
Seungwon Jeon

> 
> From a bi-sectable point of view, we should squash the enrire patchset
> into one patch. I hope you are fine with that Seungwon!? If some of
> the host driver maintainers prefer another solution, also please tell
> me.
> 
> Kind regards
> Ulf Hansson
> 
> >
> > Changes in V3:
> >         (6/7) Added MMC-DDR52 mode instead of replacing UHS-DDR50 in dw_mmc-exynos
> >
> > Changes in V2:
> >         (2/7) Added MMC-DDR52 mode instead of replacing UHS-DDR50 in mmci
> >
> > Seungwon Jeon (7):
> >   mmc: clarify DDR timing mode between SD-UHS and eMMC
> >   mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
> >   mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
> >   mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
> >   mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
> >   mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
> >   mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC
> >
> >  drivers/mmc/core/debugfs.c        |    3 +++
> >  drivers/mmc/core/mmc.c            |    2 +-
> >  drivers/mmc/host/dw_mmc-exynos.c  |    5 ++---
> >  drivers/mmc/host/dw_mmc.c         |    2 +-
> >  drivers/mmc/host/mmci.c           |    6 ++++--
> >  drivers/mmc/host/omap_hsmmc.c     |    4 ++--
> >  drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
> >  drivers/mmc/host/sdhci.c          |    4 +++-
> >  drivers/mmc/host/sh_mmcif.c       |    9 +++++----
> >  include/linux/mmc/host.h          |    3 ++-
> >  10 files changed, 25 insertions(+), 15 deletions(-)>
> >
> >
> > Thanks,
> > sw-j
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-04-03 11:53                   ` Seungwon Jeon
@ 2014-04-03 13:14                     ` Ulf Hansson
  2014-04-04 10:46                       ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-04-03 13:14 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 3 April 2014 13:53, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> On Wed, April 02, 2014, Ulf Hansson wrote:
>> On 2 April 2014 03:15, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> > On Fri, March 28, 2014, Ulf Hansson wrote:
>> >> On 28 March 2014 13:18, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> >> > On Fri, March 28, 2014, Ulf Hansson wrote:
>> >> >> On 25 March 2014 10:23, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> >> >> > Hi Ulf,
>> >> >> >
>> >> >> > On Tue, March 25, 2014, Ulf Hansson wrote:
>> >> >> >> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> >> >> >> > 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: Seungwon Jeon <tgih.jun@samsung.com>
>> >> >> >> > Reviewed-by: Jackey Shen <jackey.shen@amd.com>
>> >> >> >> > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
>> >> >> >> > Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
>> >> >> >> > ---
>> >> >> >> >  drivers/mmc/core/bus.c     |    1 +
>> >> >> >> >  drivers/mmc/core/debugfs.c |    3 +
>> >> >> >> >  drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
>> >> >> >> >  include/linux/mmc/card.h   |    1 +
>> >> >> >> >  include/linux/mmc/host.h   |   15 +++++-
>> >> >> >> >  include/linux/mmc/mmc.h    |    7 ++-
>> >> >> >> >  6 files changed, 134 insertions(+), 8 deletions(-)
>> >> >> >> >
>> >> >> >> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> >> >> >> > index f37e9d6..d2dbf02 100644
>> >> >> >> > --- a/drivers/mmc/core/bus.c
>> >> >> >> > +++ b/drivers/mmc/core/bus.c
>> >> >> >> > @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
>> >> >> >> >                         mmc_hostname(card->host),
>> >> >> >> >                         mmc_card_uhs(card) ? "ultra high speed " :
>> >> >> >> >                         (mmc_card_hs(card) ? "high speed " : ""),
>> >> >> >> > +                       mmc_card_hs400(card) ? "HS400 " :
>> >> >> >> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
>> >> >> >> >                         mmc_card_ddr52(card) ? "DDR " : "",
>> >> >> >> >                         uhs_bus_speed_mode, type, card->rca);
>> >> >> >> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
>> >> >> >> > index 1f730db..91eb162 100644
>> >> >> >> > --- a/drivers/mmc/core/debugfs.c
>> >> >> >> > +++ b/drivers/mmc/core/debugfs.c
>> >> >> >> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>> >> >> >> >         case MMC_TIMING_MMC_HS200:
>> >> >> >> >                 str = "mmc HS200";
>> >> >> >> >                 break;
>> >> >> >> > +       case MMC_TIMING_MMC_HS400:
>> >> >> >> > +               str = "mmc HS400";
>> >> >> >> > +               break;
>> >> >> >> >         default:
>> >> >> >> >                 str = "invalid";
>> >> >> >> >                 break;
>> >> >> >> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> >> >> >> > index 6dd68e6..969d595 100644
>> >> >> >> > --- a/drivers/mmc/core/mmc.c
>> >> >> >> > +++ b/drivers/mmc/core/mmc.c
>> >> >> >> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
>> >> >> >> >  static void mmc_select_card_type(struct mmc_card *card)
>> >> >> >> >  {
>> >> >> >> >         struct mmc_host *host = card->host;
>> >> >> >> > -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>> >> >> >> > +       u8 card_type = card->ext_csd.raw_card_type;
>> >> >> >> >         u32 caps = host->caps, caps2 = host->caps2;
>> >> >> >> >         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>> >> >> >> >         unsigned int avail_type = 0;
>> >> >> >> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
>> >> >> >> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>> >> >> >> >         }
>> >> >> >> >
>> >> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_8V &&
>> >> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
>> >> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> >> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
>> >> >> >> > +       }
>> >> >> >> > +
>> >> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_2V &&
>> >> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
>> >> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> >> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>> >> >> >> > +       }
>> >> >> >> > +
>> >> >> >> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
>> >> >> >> >         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>> >> >> >> >         card->mmc_avail_type = avail_type;
>> >> >> >> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>> >> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
>> >> >> >> >                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
>> >> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
>> >> >> >> > +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
>> >> >> >> > +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
>> >> >> >> >         }
>> >> >> >> >
>> >> >> >> >         if (card->ext_csd.rev >= 5) {
>> >> >> >> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned
>> bus_width)
>> >> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
>> >> >> >> >                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
>> >> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
>> >> >> >> > -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
>> >> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
>> >> >> >> > +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
>> >> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
>> >> >> >> > +
>> >> >> >> >         if (err)
>> >> >> >> >                 err = -EINVAL;
>> >> >> >> >
>> >> >> >> > @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
>> >> >> >> >                                 ext_csd->raw_pwr_cl_52_360 :
>> >> >> >> >                                 ext_csd->raw_pwr_cl_ddr_52_360;
>> >> >> >> >                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
>> >> >> >> > -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
>> >> >> >> > +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
>> >> >> >> > +                               ext_csd->raw_pwr_cl_ddr_200_360 :
>> >> >> >> > +                               ext_csd->raw_pwr_cl_200_360;
>> >> >> >> >                 break;
>> >> >> >> >         default:
>> >> >> >> >                 pr_warning("%s: Voltage range not supported "
>> >> >> >> > @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
>> >> >> >> >  {
>> >> >> >> >         unsigned int max_dtr = (unsigned int)-1;
>> >> >> >> >
>> >> >> >> > -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
>> >> >> >> > +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
>> >> >> >> > +            max_dtr > card->ext_csd.hs200_max_dtr)
>> >> >> >> >                 max_dtr = card->ext_csd.hs200_max_dtr;
>> >> >> >> >         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
>> >> >> >> >                 max_dtr = card->ext_csd.hs_max_dtr;
>> >> >> >> > @@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
>> >> >> >> >  }
>> >> >> >> >
>> >> >> >> >  /*
>> >> >> >> > + * Revert to the high-speed mode from above speed
>> >> >> >> > + */
>> >> >> >> > +static int mmc_revert_to_hs(struct mmc_card *card)
>> >> >> >> > +{
>> >> >> >> > +       /*
>> >> >> >> > +        * CMD13, which is used to confirm the completion of timing
>> >> >> >> > +        * change, will be issued at higher speed timing condtion
>> >> >> >> > +        * rather than high-speed. If device has completed the change
>> >> >> >> > +        * to high-speed mode, it may not be proper timing to issue
>> >> >> >> > +        * command. Low speed supplies better timing margin than high
>> >> >> >> > +        * speed. Accordingly clock rate & timging should be chagned
>> >> >> >> > +        * ahead before actual switch.
>> >> >> >>
>> >> >> >> I have some problem to understand this comment. I guess you are trying
>> >> >> >> to provide the arguments to why it makes sense to perform the revert
>> >> >> >> to lower speed mode!?
>> >> >> >>
>> >> >> >> This makes me wonder if this is not part of the spec? Could you try to clarify?
>> >> >> > But specification says that "HS_TIMING must be set to "0x1" before setting BUS_WIDTH for dual
>> >> data
>> >> >> rate operation".
>> >> >> > I think this sequence is not graceful.
>> >> >> > I also commented why speed mode should be changed to high-speed mode from HS200 mode in the
>> >> >> function-called part.
>> >> >> > Because it is not possible to set 8-bit data bus for dual rate on HS200 mode, revert to high-
>> >> speed
>> >> >> from HS200 is needed.
>> >> >> > If the above-commented point makes it confused, it could be removed.
>> >> >> > Please let me know your opinion.
>> >> >> >
>> >> >> >>
>> >> >> >> > +        */
>> >> >> >> > +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> >> >> >> > +       mmc_set_bus_speed(card);
>> >> >> >> > +
>> >> >> >> > +       return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> > +                         EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
>> >> >> >> > +                         card->ext_csd.generic_cmd6_time);
>> >> >> >> > +}
>> >> >> >> > +
>> >> >> >> > +/*
>> >> >> >> >   * Activate wide bus and DDR if supported.
>> >> >> >> >   */
>> >> >> >> >  static int mmc_select_hs_ddr(struct mmc_card *card)
>> >> >> >> > @@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
>> >> >> >> >         return err;
>> >> >> >> >  }
>> >> >> >> >
>> >> >> >> > +static int mmc_select_hs400(struct mmc_card *card)
>> >> >> >> > +{
>> >> >> >> > +       struct mmc_host *host = card->host;
>> >> >> >> > +       int err = 0;
>> >> >> >> > +
>> >> >> >> > +       /*
>> >> >> >> > +        * The bus width is set to only 8 DDR in HS400 mode
>> >> >> >>
>> >> >> >> Please rephrase the comment to something like:
>> >> >> >> "HS400 mode requires 8-bit bus width."
>> >> >> > As it is, it was from spec's description.
>> >> >> > But I think yours would be more clearable.
>> >> >> >
>> >> >> >>
>> >> >> >> > +        */
>> >> >> >> > +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
>> >> >> >> > +             host->ios.bus_width == MMC_BUS_WIDTH_8))
>> >> >> >> > +               return 0;
>> >> >> >> > +
>> >> >> >> > +       /*
>> >> >> >> > +        * Before setting BUS_WIDTH for dual data rate operation,
>> >> >> >> > +        * HS_TIMING must be set to High Speed(0x1)
>> >> >> >> > +        */
>> >> >> >>
>> >> >> >> Please rephrase comment:
>> >> >> >>
>> >> >> >> "Before switching to dual data rate operation for HS400, we need
>> >> >> >> revert from HS200 timing to regular HS timing."
>> >> >> > Ok.
>> >> >> >
>> >> >> >>
>> >> >> >> > +       err = mmc_revert_to_hs(card);
>> >> >> >>
>> >> >> >> I don't think we need a separate function to handle the revert.
>> >> >> >> Please, just add the code here instead. While you do that, I suppose
>> >> >> >> we should combine the comment in that function into one comment here.
>> >> >> > OK, I don't oppose that.
>> >> >> >
>> >> >> >>
>> >> >> >> > +       if (err) {
>> >> >> >> > +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
>> >> >> >> > +                       mmc_hostname(host), err);
>> >> >> >> > +               return err;
>> >> >> >> > +       }
>> >> >> >> > +
>> >> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> > +                        EXT_CSD_BUS_WIDTH,
>> >> >> >> > +                        EXT_CSD_DDR_BUS_WIDTH_8,
>> >> >> >> > +                        card->ext_csd.generic_cmd6_time);
>> >> >> >> > +       if (err) {
>> >> >> >> > +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
>> >> >> >> > +                       mmc_hostname(host), err);
>> >> >> >> > +               return err;
>> >> >> >> > +       }
>> >> >> >> > +
>> >> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
>> >> >> >> > +                        card->ext_csd.generic_cmd6_time);
>> >> >> >> > +       if (err) {
>> >> >> >> > +               pr_warn("%s: switch to hs400 failed, err:%d\n",
>> >> >> >> > +                        mmc_hostname(host), err);
>> >> >> >> > +               return err;
>> >> >> >> > +       }
>> >> >> >> > +
>> >> >> >> > +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>> >> >> >> > +       mmc_set_bus_speed(card);
>> >> >> >> > +
>> >> >> >> > +       return 0;
>> >> >> >> > +}
>> >> >> >> > +
>> >> >> >> >  /*
>> >> >> >> >   * For device supporting HS200 mode, the following sequence
>> >> >> >> >   * should be done before executing the tuning process.
>> >> >> >> > @@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
>> >> >> >> >                                    EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
>> >> >> >> >                                    card->ext_csd.generic_cmd6_time,
>> >> >> >> >                                    true, true, true);
>> >> >> >> > -               if (!err)
>> >> >> >> > +               if (err)
>> >> >> >> > +                       goto err;
>> >> >> >> > +
>> >> >> >> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
>> >> >> >> > +                       /*
>> >> >> >> > +                        * Timing should be adjusted to the HS400 target
>> >> >> >> > +                        * operation frequency for tuning process
>> >> >> >> > +                        */
>> >> >> >> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
>> >> >> >>
>> >> >> >> This seems strange. Do we really need a separate
>> >> >> >> MMC_TIMING_MMC_HS400_TUNING value?
>> >> >> > Spec. describes the HS400 selection sequence like below.
>> >> >> > <Quot>
>> >> >> > ...
>> >> >> > 6) Perform the Tuning Process at the HS400 target operating frequency
>> >> >> > (Note: tuning process in HS200 mode is required to synchronize the command response on the CMD
>> >> line
>> >> >> to CLK for HS400 operation).
>> >> >> > ...
>> >> >> > </Quot>
>> >> >> > That means target clock rate for tuning sequence can be different with HS200.
>> >> >> > Considering for that, it needs to distinguish.
>> >> >>
>> >> >> I understand the spec now, thanks.
>> >> >>
>> >> >> Still, I am not convinced we should handle this through the
>> >> >> MMC_TIMING* field. That will leave host drivers to do some magic clock
>> >> >> frequency calculation from their ->set_ios callbacks, just depending
>> >> >> on the MMC_TIMING_MMC_HS400_TUNING value.
>> >> >>
>> >> >> I am also a bit concerned how MMC_TIMING_MMC_HS400_TUNING, would work
>> >> >> if/when we implement periodic re-tuning - triggered from the mmc core
>> >> >> layer.
>> >> >>
>> >> >> What we really want to do, is to pretend we were to operate in
>> >> >> MMC_TIMING_MMC_HS400 and ask the host driver what the target frequency
>> >> >> would be in this case. Then set this frequency through
>> >> >> mmc_set_clock().
>> >> >>
>> >> >> Then how do we ask the host driver about this frequency? Let's add a
>> >> >> new host_ops callback. We want it to be generic, so provide the
>> >> >> MMC_TIMING bit as a parameter. Additionally we want it to be optional
>> >> >> to implement, thus for those host drivers that supports the same
>> >> >> target frequency for HS200 as for HS400, they don't need to implement
>> >> >> it.
>> >> >>
>> >> >> Would this be a way forward?
>> >> >
>> >> > Thanks for your opinion.
>> >> >
>> >> > IMO, in this case additional callback handling seems to cause the complication in host side.
>> >> > I think we don't need to ask host driver about target frequency for HS400 in order to set
>> specific
>> >> frequency through
>> >> > mmc_set_clock().
>> >> > Target frequency which core layer requires for HS400 will be 200MHz and it is also mentioned in
>> >> specification.
>> >> > Host driver including actual controller just will effort to make DDR rate with 200MHz.
>> >>
>> >> What the mmc_set_clock() request is not the same as what the frequency
>> >> actually will be set to. That depends on the host controller/driver.
>> >>
>> >> If for some reason the host controller/driver are not able to use the
>> >> same frequency for HS200 as for HS400, this should be possible to be
>> >> addressed in the way I suggested.
>> > I checked your sequence, but I'm not sure whether your suggestion is suitable for this.
>> > As we know, in case of DDR52 clock rate requested by mmc_set_clock() is not different from High
>> speed; Actually same 52Mhz is
>> > requested.
>> > It will be same in HS400 mode. Clock rate for mmc_set_clock() will be 200MHz in both HS200 and HS400.
>> > Instead, host driver may control specific register for DDR rate output.
>> > This is why core layer don't need call extra mmc_set_clock().
>> > That means it doesn't need to ask host driver about frequency with using additional callback.
>> > What core layer should do is to gives host driver timing information such as
>> MMC_TIMING_MMC_HS400_TUNING.
>> > Then, host can prepare specific timing setting for HS400 tuning.
>> > As you mentioned, it depends on the host controller/driver.
>>
>> The reason why I suggested to add a new host_ops callback and to use
>> the mmc_set_clock() method was to address what's mentioned in the
>> spec, which you pointed me to.
>>
>> So, now you are saying we don't need to consider this scenario,
>> because very likely we will be using the same frequency as for HS200.
> I didn't mean actual output clock frequency.
> Just mentioned required clock rate through mmc_set_clock() in core layer.
>
> I think clock generation depends on host controller.
> For higher speed, some programmable setting will be needed.
> Hopefully, you could find the following patch to check how HS400 is handled in host driver.
> Exynos host changes internal clock rate for HS400 mode.
> "[PATCH v2 5/7] mmc: dw_mmc: exynos: support eMMC's HS400 mode"
>
>>
>> Okay - let's leave this to be implemented if/when we see there is a need for it.
>>
>> >
>> >>
>> >> > MMC_TIMING_MMC_HS400_TUNING may be used as notification for host to prepare HS400 tuning sequence.
>> >>
>> >> So, are you saying that your controller are have different tuning
>> >> methods for HS200 vs HS400? That's a different requirement, which of
>> >> course we need to handle.
>> > NO, tuning method is equal. I meant that host's setting for IO timing would be different.
>>
>> I suppose this means the host don't need to bother about HS400 (at
>> all) during tuning sequence and thus we don't need the
>> MMC_TIMING_MMC_HS400_TUNING timing? Or am I missing your point?
> Please check the patch I mentioned above.

In the patch you refer to above, your ->set_ios callback takes
specific actions while "MMC_TIMING_MMC_HS400_TUNING".

Like this:
+       case MMC_TIMING_MMC_HS400_TUNING:
+               clksel = priv->hs400_timing;
+               wanted <<= 1;
+               break;

I don't think inventing MMC_TIMING_MMC_HS400_TUNING is the correct
approach to solve this. Instead, I believe we have these two options:

1. Let the host_ops->execute_tuning callback, notify the host about
HS400 tuning. Currently the "opcode" parameter is directly related to
the actual MMC command, but we could change that to have a different
meaning. Obviously you need to convert those host drivers implementing
the callback, but that should be quite simply I think.

2. Invent a new host_ops callback, like host_ops->execute_hs400_tuning.

>
>>
>> While we are discussion this, what about re-tuning? Is that also
>> supposed to be done in HS200 mode?
> I guess re-tuning is not related to this patch.
> OK, Can you say in more detail?
> I didn't get your meaning.

Currently sdhci performs re-tuning while a timer has elapsed, locally
implemented in the sdhci host.

Instead, I would like the re-tuning to be triggered from the mmc core
layer - thus all host drivers can benefit. Potentially the mmc core
would invoke the host_ops->execute_tuning callback to perform the
re-tuning. I just wanted you to keep this in mind, while implementing
1) or 2), sorry if it was too unclear.

Kind regards
Ulf Hansson

>
> Thanks,
> Seungwon Jeon
>

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

* RE: [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-04-03 13:14                     ` Ulf Hansson
@ 2014-04-04 10:46                       ` Seungwon Jeon
  2014-04-04 11:58                         ` Ulf Hansson
  0 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-04 10:46 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On Thu, April 03, 2014, Ulf Hansson wrote:
> On 3 April 2014 13:53, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > On Wed, April 02, 2014, Ulf Hansson wrote:
> >> On 2 April 2014 03:15, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> > On Fri, March 28, 2014, Ulf Hansson wrote:
> >> >> On 28 March 2014 13:18, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> >> > On Fri, March 28, 2014, Ulf Hansson wrote:
> >> >> >> On 25 March 2014 10:23, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> >> >> > Hi Ulf,
> >> >> >> >
> >> >> >> > On Tue, March 25, 2014, Ulf Hansson wrote:
> >> >> >> >> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> >> >> >> > 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: Seungwon Jeon <tgih.jun@samsung.com>
> >> >> >> >> > Reviewed-by: Jackey Shen <jackey.shen@amd.com>
> >> >> >> >> > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
> >> >> >> >> > Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
> >> >> >> >> > ---
> >> >> >> >> >  drivers/mmc/core/bus.c     |    1 +
> >> >> >> >> >  drivers/mmc/core/debugfs.c |    3 +
> >> >> >> >> >  drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
> >> >> >> >> >  include/linux/mmc/card.h   |    1 +
> >> >> >> >> >  include/linux/mmc/host.h   |   15 +++++-
> >> >> >> >> >  include/linux/mmc/mmc.h    |    7 ++-
> >> >> >> >> >  6 files changed, 134 insertions(+), 8 deletions(-)
> >> >> >> >> >
> >> >> >> >> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> >> >> >> >> > index f37e9d6..d2dbf02 100644
> >> >> >> >> > --- a/drivers/mmc/core/bus.c
> >> >> >> >> > +++ b/drivers/mmc/core/bus.c
> >> >> >> >> > @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
> >> >> >> >> >                         mmc_hostname(card->host),
> >> >> >> >> >                         mmc_card_uhs(card) ? "ultra high speed " :
> >> >> >> >> >                         (mmc_card_hs(card) ? "high speed " : ""),
> >> >> >> >> > +                       mmc_card_hs400(card) ? "HS400 " :
> >> >> >> >> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
> >> >> >> >> >                         mmc_card_ddr52(card) ? "DDR " : "",
> >> >> >> >> >                         uhs_bus_speed_mode, type, card->rca);
> >> >> >> >> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> >> >> >> >> > index 1f730db..91eb162 100644
> >> >> >> >> > --- a/drivers/mmc/core/debugfs.c
> >> >> >> >> > +++ b/drivers/mmc/core/debugfs.c
> >> >> >> >> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
> >> >> >> >> >         case MMC_TIMING_MMC_HS200:
> >> >> >> >> >                 str = "mmc HS200";
> >> >> >> >> >                 break;
> >> >> >> >> > +       case MMC_TIMING_MMC_HS400:
> >> >> >> >> > +               str = "mmc HS400";
> >> >> >> >> > +               break;
> >> >> >> >> >         default:
> >> >> >> >> >                 str = "invalid";
> >> >> >> >> >                 break;
> >> >> >> >> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >> >> >> >> > index 6dd68e6..969d595 100644
> >> >> >> >> > --- a/drivers/mmc/core/mmc.c
> >> >> >> >> > +++ b/drivers/mmc/core/mmc.c
> >> >> >> >> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
> >> >> >> >> >  static void mmc_select_card_type(struct mmc_card *card)
> >> >> >> >> >  {
> >> >> >> >> >         struct mmc_host *host = card->host;
> >> >> >> >> > -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> >> >> >> >> > +       u8 card_type = card->ext_csd.raw_card_type;
> >> >> >> >> >         u32 caps = host->caps, caps2 = host->caps2;
> >> >> >> >> >         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
> >> >> >> >> >         unsigned int avail_type = 0;
> >> >> >> >> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
> >> >> >> >> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> >> >> >> >> >         }
> >> >> >> >> >
> >> >> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_8V &&
> >> >> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> >> >> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> >> >> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> >> >> >> >> > +       }
> >> >> >> >> > +
> >> >> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_2V &&
> >> >> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> >> >> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> >> >> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> >> >> >> >> > +       }
> >> >> >> >> > +
> >> >> >> >> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
> >> >> >> >> >         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
> >> >> >> >> >         card->mmc_avail_type = avail_type;
> >> >> >> >> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
> >> >> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
> >> >> >> >> >                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
> >> >> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> >> >> >> >> > +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
> >> >> >> >> > +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
> >> >> >> >> >         }
> >> >> >> >> >
> >> >> >> >> >         if (card->ext_csd.rev >= 5) {
> >> >> >> >> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned
> >> bus_width)
> >> >> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
> >> >> >> >> >                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
> >> >> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> >> >> >> >> > -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> >> >> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> >> >> >> >> > +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> >> >> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> >> >> >> >> > +
> >> >> >> >> >         if (err)
> >> >> >> >> >                 err = -EINVAL;
> >> >> >> >> >
> >> >> >> >> > @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> >> >> >> >> >                                 ext_csd->raw_pwr_cl_52_360 :
> >> >> >> >> >                                 ext_csd->raw_pwr_cl_ddr_52_360;
> >> >> >> >> >                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> >> >> >> >> > -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
> >> >> >> >> > +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> >> >> >> >> > +                               ext_csd->raw_pwr_cl_ddr_200_360 :
> >> >> >> >> > +                               ext_csd->raw_pwr_cl_200_360;
> >> >> >> >> >                 break;
> >> >> >> >> >         default:
> >> >> >> >> >                 pr_warning("%s: Voltage range not supported "
> >> >> >> >> > @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
> >> >> >> >> >  {
> >> >> >> >> >         unsigned int max_dtr = (unsigned int)-1;
> >> >> >> >> >
> >> >> >> >> > -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> >> >> >> >> > +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
> >> >> >> >> > +            max_dtr > card->ext_csd.hs200_max_dtr)
> >> >> >> >> >                 max_dtr = card->ext_csd.hs200_max_dtr;
> >> >> >> >> >         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
> >> >> >> >> >                 max_dtr = card->ext_csd.hs_max_dtr;
> >> >> >> >> > @@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
> >> >> >> >> >  }
> >> >> >> >> >
> >> >> >> >> >  /*
> >> >> >> >> > + * Revert to the high-speed mode from above speed
> >> >> >> >> > + */
> >> >> >> >> > +static int mmc_revert_to_hs(struct mmc_card *card)
> >> >> >> >> > +{
> >> >> >> >> > +       /*
> >> >> >> >> > +        * CMD13, which is used to confirm the completion of timing
> >> >> >> >> > +        * change, will be issued at higher speed timing condtion
> >> >> >> >> > +        * rather than high-speed. If device has completed the change
> >> >> >> >> > +        * to high-speed mode, it may not be proper timing to issue
> >> >> >> >> > +        * command. Low speed supplies better timing margin than high
> >> >> >> >> > +        * speed. Accordingly clock rate & timging should be chagned
> >> >> >> >> > +        * ahead before actual switch.
> >> >> >> >>
> >> >> >> >> I have some problem to understand this comment. I guess you are trying
> >> >> >> >> to provide the arguments to why it makes sense to perform the revert
> >> >> >> >> to lower speed mode!?
> >> >> >> >>
> >> >> >> >> This makes me wonder if this is not part of the spec? Could you try to clarify?
> >> >> >> > But specification says that "HS_TIMING must be set to "0x1" before setting BUS_WIDTH for
> dual
> >> >> data
> >> >> >> rate operation".
> >> >> >> > I think this sequence is not graceful.
> >> >> >> > I also commented why speed mode should be changed to high-speed mode from HS200 mode in the
> >> >> >> function-called part.
> >> >> >> > Because it is not possible to set 8-bit data bus for dual rate on HS200 mode, revert to
> high-
> >> >> speed
> >> >> >> from HS200 is needed.
> >> >> >> > If the above-commented point makes it confused, it could be removed.
> >> >> >> > Please let me know your opinion.
> >> >> >> >
> >> >> >> >>
> >> >> >> >> > +        */
> >> >> >> >> > +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> >> >> >> >> > +       mmc_set_bus_speed(card);
> >> >> >> >> > +
> >> >> >> >> > +       return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> >> >> > +                         EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> >> >> >> >> > +                         card->ext_csd.generic_cmd6_time);
> >> >> >> >> > +}
> >> >> >> >> > +
> >> >> >> >> > +/*
> >> >> >> >> >   * Activate wide bus and DDR if supported.
> >> >> >> >> >   */
> >> >> >> >> >  static int mmc_select_hs_ddr(struct mmc_card *card)
> >> >> >> >> > @@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
> >> >> >> >> >         return err;
> >> >> >> >> >  }
> >> >> >> >> >
> >> >> >> >> > +static int mmc_select_hs400(struct mmc_card *card)
> >> >> >> >> > +{
> >> >> >> >> > +       struct mmc_host *host = card->host;
> >> >> >> >> > +       int err = 0;
> >> >> >> >> > +
> >> >> >> >> > +       /*
> >> >> >> >> > +        * The bus width is set to only 8 DDR in HS400 mode
> >> >> >> >>
> >> >> >> >> Please rephrase the comment to something like:
> >> >> >> >> "HS400 mode requires 8-bit bus width."
> >> >> >> > As it is, it was from spec's description.
> >> >> >> > But I think yours would be more clearable.
> >> >> >> >
> >> >> >> >>
> >> >> >> >> > +        */
> >> >> >> >> > +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
> >> >> >> >> > +             host->ios.bus_width == MMC_BUS_WIDTH_8))
> >> >> >> >> > +               return 0;
> >> >> >> >> > +
> >> >> >> >> > +       /*
> >> >> >> >> > +        * Before setting BUS_WIDTH for dual data rate operation,
> >> >> >> >> > +        * HS_TIMING must be set to High Speed(0x1)
> >> >> >> >> > +        */
> >> >> >> >>
> >> >> >> >> Please rephrase comment:
> >> >> >> >>
> >> >> >> >> "Before switching to dual data rate operation for HS400, we need
> >> >> >> >> revert from HS200 timing to regular HS timing."
> >> >> >> > Ok.
> >> >> >> >
> >> >> >> >>
> >> >> >> >> > +       err = mmc_revert_to_hs(card);
> >> >> >> >>
> >> >> >> >> I don't think we need a separate function to handle the revert.
> >> >> >> >> Please, just add the code here instead. While you do that, I suppose
> >> >> >> >> we should combine the comment in that function into one comment here.
> >> >> >> > OK, I don't oppose that.
> >> >> >> >
> >> >> >> >>
> >> >> >> >> > +       if (err) {
> >> >> >> >> > +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> >> >> >> >> > +                       mmc_hostname(host), err);
> >> >> >> >> > +               return err;
> >> >> >> >> > +       }
> >> >> >> >> > +
> >> >> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> >> >> > +                        EXT_CSD_BUS_WIDTH,
> >> >> >> >> > +                        EXT_CSD_DDR_BUS_WIDTH_8,
> >> >> >> >> > +                        card->ext_csd.generic_cmd6_time);
> >> >> >> >> > +       if (err) {
> >> >> >> >> > +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> >> >> >> >> > +                       mmc_hostname(host), err);
> >> >> >> >> > +               return err;
> >> >> >> >> > +       }
> >> >> >> >> > +
> >> >> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> >> >> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> >> >> >> >> > +                        card->ext_csd.generic_cmd6_time);
> >> >> >> >> > +       if (err) {
> >> >> >> >> > +               pr_warn("%s: switch to hs400 failed, err:%d\n",
> >> >> >> >> > +                        mmc_hostname(host), err);
> >> >> >> >> > +               return err;
> >> >> >> >> > +       }
> >> >> >> >> > +
> >> >> >> >> > +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> >> >> >> >> > +       mmc_set_bus_speed(card);
> >> >> >> >> > +
> >> >> >> >> > +       return 0;
> >> >> >> >> > +}
> >> >> >> >> > +
> >> >> >> >> >  /*
> >> >> >> >> >   * For device supporting HS200 mode, the following sequence
> >> >> >> >> >   * should be done before executing the tuning process.
> >> >> >> >> > @@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
> >> >> >> >> >                                    EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> >> >> >> >> >                                    card->ext_csd.generic_cmd6_time,
> >> >> >> >> >                                    true, true, true);
> >> >> >> >> > -               if (!err)
> >> >> >> >> > +               if (err)
> >> >> >> >> > +                       goto err;
> >> >> >> >> > +
> >> >> >> >> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> >> >> >> >> > +                       /*
> >> >> >> >> > +                        * Timing should be adjusted to the HS400 target
> >> >> >> >> > +                        * operation frequency for tuning process
> >> >> >> >> > +                        */
> >> >> >> >> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> >> >> >> >>
> >> >> >> >> This seems strange. Do we really need a separate
> >> >> >> >> MMC_TIMING_MMC_HS400_TUNING value?
> >> >> >> > Spec. describes the HS400 selection sequence like below.
> >> >> >> > <Quot>
> >> >> >> > ...
> >> >> >> > 6) Perform the Tuning Process at the HS400 target operating frequency
> >> >> >> > (Note: tuning process in HS200 mode is required to synchronize the command response on the
> CMD
> >> >> line
> >> >> >> to CLK for HS400 operation).
> >> >> >> > ...
> >> >> >> > </Quot>
> >> >> >> > That means target clock rate for tuning sequence can be different with HS200.
> >> >> >> > Considering for that, it needs to distinguish.
> >> >> >>
> >> >> >> I understand the spec now, thanks.
> >> >> >>
> >> >> >> Still, I am not convinced we should handle this through the
> >> >> >> MMC_TIMING* field. That will leave host drivers to do some magic clock
> >> >> >> frequency calculation from their ->set_ios callbacks, just depending
> >> >> >> on the MMC_TIMING_MMC_HS400_TUNING value.
> >> >> >>
> >> >> >> I am also a bit concerned how MMC_TIMING_MMC_HS400_TUNING, would work
> >> >> >> if/when we implement periodic re-tuning - triggered from the mmc core
> >> >> >> layer.
> >> >> >>
> >> >> >> What we really want to do, is to pretend we were to operate in
> >> >> >> MMC_TIMING_MMC_HS400 and ask the host driver what the target frequency
> >> >> >> would be in this case. Then set this frequency through
> >> >> >> mmc_set_clock().
> >> >> >>
> >> >> >> Then how do we ask the host driver about this frequency? Let's add a
> >> >> >> new host_ops callback. We want it to be generic, so provide the
> >> >> >> MMC_TIMING bit as a parameter. Additionally we want it to be optional
> >> >> >> to implement, thus for those host drivers that supports the same
> >> >> >> target frequency for HS200 as for HS400, they don't need to implement
> >> >> >> it.
> >> >> >>
> >> >> >> Would this be a way forward?
> >> >> >
> >> >> > Thanks for your opinion.
> >> >> >
> >> >> > IMO, in this case additional callback handling seems to cause the complication in host side.
> >> >> > I think we don't need to ask host driver about target frequency for HS400 in order to set
> >> specific
> >> >> frequency through
> >> >> > mmc_set_clock().
> >> >> > Target frequency which core layer requires for HS400 will be 200MHz and it is also mentioned
> in
> >> >> specification.
> >> >> > Host driver including actual controller just will effort to make DDR rate with 200MHz.
> >> >>
> >> >> What the mmc_set_clock() request is not the same as what the frequency
> >> >> actually will be set to. That depends on the host controller/driver.
> >> >>
> >> >> If for some reason the host controller/driver are not able to use the
> >> >> same frequency for HS200 as for HS400, this should be possible to be
> >> >> addressed in the way I suggested.
> >> > I checked your sequence, but I'm not sure whether your suggestion is suitable for this.
> >> > As we know, in case of DDR52 clock rate requested by mmc_set_clock() is not different from High
> >> speed; Actually same 52Mhz is
> >> > requested.
> >> > It will be same in HS400 mode. Clock rate for mmc_set_clock() will be 200MHz in both HS200 and
> HS400.
> >> > Instead, host driver may control specific register for DDR rate output.
> >> > This is why core layer don't need call extra mmc_set_clock().
> >> > That means it doesn't need to ask host driver about frequency with using additional callback.
> >> > What core layer should do is to gives host driver timing information such as
> >> MMC_TIMING_MMC_HS400_TUNING.
> >> > Then, host can prepare specific timing setting for HS400 tuning.
> >> > As you mentioned, it depends on the host controller/driver.
> >>
> >> The reason why I suggested to add a new host_ops callback and to use
> >> the mmc_set_clock() method was to address what's mentioned in the
> >> spec, which you pointed me to.
> >>
> >> So, now you are saying we don't need to consider this scenario,
> >> because very likely we will be using the same frequency as for HS200.
> > I didn't mean actual output clock frequency.
> > Just mentioned required clock rate through mmc_set_clock() in core layer.
> >
> > I think clock generation depends on host controller.
> > For higher speed, some programmable setting will be needed.
> > Hopefully, you could find the following patch to check how HS400 is handled in host driver.
> > Exynos host changes internal clock rate for HS400 mode.
> > "[PATCH v2 5/7] mmc: dw_mmc: exynos: support eMMC's HS400 mode"
> >
> >>
> >> Okay - let's leave this to be implemented if/when we see there is a need for it.
> >>
> >> >
> >> >>
> >> >> > MMC_TIMING_MMC_HS400_TUNING may be used as notification for host to prepare HS400 tuning
> sequence.
> >> >>
> >> >> So, are you saying that your controller are have different tuning
> >> >> methods for HS200 vs HS400? That's a different requirement, which of
> >> >> course we need to handle.
> >> > NO, tuning method is equal. I meant that host's setting for IO timing would be different.
> >>
> >> I suppose this means the host don't need to bother about HS400 (at
> >> all) during tuning sequence and thus we don't need the
> >> MMC_TIMING_MMC_HS400_TUNING timing? Or am I missing your point?
> > Please check the patch I mentioned above.
> 
> In the patch you refer to above, your ->set_ios callback takes
> specific actions while "MMC_TIMING_MMC_HS400_TUNING".
> 
> Like this:
> +       case MMC_TIMING_MMC_HS400_TUNING:
> +               clksel = priv->hs400_timing;
> +               wanted <<= 1;
> +               break;
> 
> I don't think inventing MMC_TIMING_MMC_HS400_TUNING is the correct
> approach to solve this. Instead, I believe we have these two options:
MMC_TIMING_MMC_HS400_TUNING can be recognized for specific timing identifier.
I think it is not different from other timings and set_ios() has a role to handle those. 
Could you please explain the reason why you don't think it's correct?

> 
> 1. Let the host_ops->execute_tuning callback, notify the host about
> HS400 tuning. Currently the "opcode" parameter is directly related to
> the actual MMC command, but we could change that to have a different
> meaning. Obviously you need to convert those host drivers implementing
> the callback, but that should be quite simply I think.
Currently, execute_tuning callback has been implemented in some host drivers.
I guess it may not simple way.

> 
> 2. Invent a new host_ops callback, like host_ops->execute_hs400_tuning.
I don't this way is proper. Tuning method is not different.

> 
> >
> >>
> >> While we are discussion this, what about re-tuning? Is that also
> >> supposed to be done in HS200 mode?
> > I guess re-tuning is not related to this patch.
> > OK, Can you say in more detail?
> > I didn't get your meaning.
> 
> Currently sdhci performs re-tuning while a timer has elapsed, locally
> implemented in the sdhci host.
> 
> Instead, I would like the re-tuning to be triggered from the mmc core
> layer - thus all host drivers can benefit. Potentially the mmc core
> would invoke the host_ops->execute_tuning callback to perform the
> re-tuning. I just wanted you to keep this in mind, while implementing
> 1) or 2), sorry if it was too unclear.
It's interesting to me.
Ok. If we need to consider re-tuning, it would be next time.

Thanks,
Seungwon Jeon


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

* Re: [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-04-04 10:46                       ` Seungwon Jeon
@ 2014-04-04 11:58                         ` Ulf Hansson
  2014-04-05 14:36                           ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-04-04 11:58 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 4 April 2014 12:46, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> On Thu, April 03, 2014, Ulf Hansson wrote:
>> On 3 April 2014 13:53, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> > On Wed, April 02, 2014, Ulf Hansson wrote:
>> >> On 2 April 2014 03:15, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> >> > On Fri, March 28, 2014, Ulf Hansson wrote:
>> >> >> On 28 March 2014 13:18, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> >> >> > On Fri, March 28, 2014, Ulf Hansson wrote:
>> >> >> >> On 25 March 2014 10:23, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> >> >> >> > Hi Ulf,
>> >> >> >> >
>> >> >> >> > On Tue, March 25, 2014, Ulf Hansson wrote:
>> >> >> >> >> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
>> >> >> >> >> > 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: Seungwon Jeon <tgih.jun@samsung.com>
>> >> >> >> >> > Reviewed-by: Jackey Shen <jackey.shen@amd.com>
>> >> >> >> >> > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
>> >> >> >> >> > Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
>> >> >> >> >> > ---
>> >> >> >> >> >  drivers/mmc/core/bus.c     |    1 +
>> >> >> >> >> >  drivers/mmc/core/debugfs.c |    3 +
>> >> >> >> >> >  drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
>> >> >> >> >> >  include/linux/mmc/card.h   |    1 +
>> >> >> >> >> >  include/linux/mmc/host.h   |   15 +++++-
>> >> >> >> >> >  include/linux/mmc/mmc.h    |    7 ++-
>> >> >> >> >> >  6 files changed, 134 insertions(+), 8 deletions(-)
>> >> >> >> >> >
>> >> >> >> >> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> >> >> >> >> > index f37e9d6..d2dbf02 100644
>> >> >> >> >> > --- a/drivers/mmc/core/bus.c
>> >> >> >> >> > +++ b/drivers/mmc/core/bus.c
>> >> >> >> >> > @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
>> >> >> >> >> >                         mmc_hostname(card->host),
>> >> >> >> >> >                         mmc_card_uhs(card) ? "ultra high speed " :
>> >> >> >> >> >                         (mmc_card_hs(card) ? "high speed " : ""),
>> >> >> >> >> > +                       mmc_card_hs400(card) ? "HS400 " :
>> >> >> >> >> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
>> >> >> >> >> >                         mmc_card_ddr52(card) ? "DDR " : "",
>> >> >> >> >> >                         uhs_bus_speed_mode, type, card->rca);
>> >> >> >> >> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
>> >> >> >> >> > index 1f730db..91eb162 100644
>> >> >> >> >> > --- a/drivers/mmc/core/debugfs.c
>> >> >> >> >> > +++ b/drivers/mmc/core/debugfs.c
>> >> >> >> >> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>> >> >> >> >> >         case MMC_TIMING_MMC_HS200:
>> >> >> >> >> >                 str = "mmc HS200";
>> >> >> >> >> >                 break;
>> >> >> >> >> > +       case MMC_TIMING_MMC_HS400:
>> >> >> >> >> > +               str = "mmc HS400";
>> >> >> >> >> > +               break;
>> >> >> >> >> >         default:
>> >> >> >> >> >                 str = "invalid";
>> >> >> >> >> >                 break;
>> >> >> >> >> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> >> >> >> >> > index 6dd68e6..969d595 100644
>> >> >> >> >> > --- a/drivers/mmc/core/mmc.c
>> >> >> >> >> > +++ b/drivers/mmc/core/mmc.c
>> >> >> >> >> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
>> >> >> >> >> >  static void mmc_select_card_type(struct mmc_card *card)
>> >> >> >> >> >  {
>> >> >> >> >> >         struct mmc_host *host = card->host;
>> >> >> >> >> > -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>> >> >> >> >> > +       u8 card_type = card->ext_csd.raw_card_type;
>> >> >> >> >> >         u32 caps = host->caps, caps2 = host->caps2;
>> >> >> >> >> >         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>> >> >> >> >> >         unsigned int avail_type = 0;
>> >> >> >> >> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
>> >> >> >> >> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>> >> >> >> >> >         }
>> >> >> >> >> >
>> >> >> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_8V &&
>> >> >> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
>> >> >> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> >> >> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
>> >> >> >> >> > +       }
>> >> >> >> >> > +
>> >> >> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_2V &&
>> >> >> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
>> >> >> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> >> >> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>> >> >> >> >> > +       }
>> >> >> >> >> > +
>> >> >> >> >> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
>> >> >> >> >> >         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>> >> >> >> >> >         card->mmc_avail_type = avail_type;
>> >> >> >> >> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>> >> >> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
>> >> >> >> >> >                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
>> >> >> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
>> >> >> >> >> > +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
>> >> >> >> >> > +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
>> >> >> >> >> >         }
>> >> >> >> >> >
>> >> >> >> >> >         if (card->ext_csd.rev >= 5) {
>> >> >> >> >> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned
>> >> bus_width)
>> >> >> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
>> >> >> >> >> >                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
>> >> >> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
>> >> >> >> >> > -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
>> >> >> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
>> >> >> >> >> > +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
>> >> >> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
>> >> >> >> >> > +
>> >> >> >> >> >         if (err)
>> >> >> >> >> >                 err = -EINVAL;
>> >> >> >> >> >
>> >> >> >> >> > @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
>> >> >> >> >> >                                 ext_csd->raw_pwr_cl_52_360 :
>> >> >> >> >> >                                 ext_csd->raw_pwr_cl_ddr_52_360;
>> >> >> >> >> >                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
>> >> >> >> >> > -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
>> >> >> >> >> > +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
>> >> >> >> >> > +                               ext_csd->raw_pwr_cl_ddr_200_360 :
>> >> >> >> >> > +                               ext_csd->raw_pwr_cl_200_360;
>> >> >> >> >> >                 break;
>> >> >> >> >> >         default:
>> >> >> >> >> >                 pr_warning("%s: Voltage range not supported "
>> >> >> >> >> > @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
>> >> >> >> >> >  {
>> >> >> >> >> >         unsigned int max_dtr = (unsigned int)-1;
>> >> >> >> >> >
>> >> >> >> >> > -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
>> >> >> >> >> > +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
>> >> >> >> >> > +            max_dtr > card->ext_csd.hs200_max_dtr)
>> >> >> >> >> >                 max_dtr = card->ext_csd.hs200_max_dtr;
>> >> >> >> >> >         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
>> >> >> >> >> >                 max_dtr = card->ext_csd.hs_max_dtr;
>> >> >> >> >> > @@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
>> >> >> >> >> >  }
>> >> >> >> >> >
>> >> >> >> >> >  /*
>> >> >> >> >> > + * Revert to the high-speed mode from above speed
>> >> >> >> >> > + */
>> >> >> >> >> > +static int mmc_revert_to_hs(struct mmc_card *card)
>> >> >> >> >> > +{
>> >> >> >> >> > +       /*
>> >> >> >> >> > +        * CMD13, which is used to confirm the completion of timing
>> >> >> >> >> > +        * change, will be issued at higher speed timing condtion
>> >> >> >> >> > +        * rather than high-speed. If device has completed the change
>> >> >> >> >> > +        * to high-speed mode, it may not be proper timing to issue
>> >> >> >> >> > +        * command. Low speed supplies better timing margin than high
>> >> >> >> >> > +        * speed. Accordingly clock rate & timging should be chagned
>> >> >> >> >> > +        * ahead before actual switch.
>> >> >> >> >>
>> >> >> >> >> I have some problem to understand this comment. I guess you are trying
>> >> >> >> >> to provide the arguments to why it makes sense to perform the revert
>> >> >> >> >> to lower speed mode!?
>> >> >> >> >>
>> >> >> >> >> This makes me wonder if this is not part of the spec? Could you try to clarify?
>> >> >> >> > But specification says that "HS_TIMING must be set to "0x1" before setting BUS_WIDTH for
>> dual
>> >> >> data
>> >> >> >> rate operation".
>> >> >> >> > I think this sequence is not graceful.
>> >> >> >> > I also commented why speed mode should be changed to high-speed mode from HS200 mode in the
>> >> >> >> function-called part.
>> >> >> >> > Because it is not possible to set 8-bit data bus for dual rate on HS200 mode, revert to
>> high-
>> >> >> speed
>> >> >> >> from HS200 is needed.
>> >> >> >> > If the above-commented point makes it confused, it could be removed.
>> >> >> >> > Please let me know your opinion.
>> >> >> >> >
>> >> >> >> >>
>> >> >> >> >> > +        */
>> >> >> >> >> > +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> >> >> >> >> > +       mmc_set_bus_speed(card);
>> >> >> >> >> > +
>> >> >> >> >> > +       return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> >> > +                         EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
>> >> >> >> >> > +                         card->ext_csd.generic_cmd6_time);
>> >> >> >> >> > +}
>> >> >> >> >> > +
>> >> >> >> >> > +/*
>> >> >> >> >> >   * Activate wide bus and DDR if supported.
>> >> >> >> >> >   */
>> >> >> >> >> >  static int mmc_select_hs_ddr(struct mmc_card *card)
>> >> >> >> >> > @@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
>> >> >> >> >> >         return err;
>> >> >> >> >> >  }
>> >> >> >> >> >
>> >> >> >> >> > +static int mmc_select_hs400(struct mmc_card *card)
>> >> >> >> >> > +{
>> >> >> >> >> > +       struct mmc_host *host = card->host;
>> >> >> >> >> > +       int err = 0;
>> >> >> >> >> > +
>> >> >> >> >> > +       /*
>> >> >> >> >> > +        * The bus width is set to only 8 DDR in HS400 mode
>> >> >> >> >>
>> >> >> >> >> Please rephrase the comment to something like:
>> >> >> >> >> "HS400 mode requires 8-bit bus width."
>> >> >> >> > As it is, it was from spec's description.
>> >> >> >> > But I think yours would be more clearable.
>> >> >> >> >
>> >> >> >> >>
>> >> >> >> >> > +        */
>> >> >> >> >> > +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
>> >> >> >> >> > +             host->ios.bus_width == MMC_BUS_WIDTH_8))
>> >> >> >> >> > +               return 0;
>> >> >> >> >> > +
>> >> >> >> >> > +       /*
>> >> >> >> >> > +        * Before setting BUS_WIDTH for dual data rate operation,
>> >> >> >> >> > +        * HS_TIMING must be set to High Speed(0x1)
>> >> >> >> >> > +        */
>> >> >> >> >>
>> >> >> >> >> Please rephrase comment:
>> >> >> >> >>
>> >> >> >> >> "Before switching to dual data rate operation for HS400, we need
>> >> >> >> >> revert from HS200 timing to regular HS timing."
>> >> >> >> > Ok.
>> >> >> >> >
>> >> >> >> >>
>> >> >> >> >> > +       err = mmc_revert_to_hs(card);
>> >> >> >> >>
>> >> >> >> >> I don't think we need a separate function to handle the revert.
>> >> >> >> >> Please, just add the code here instead. While you do that, I suppose
>> >> >> >> >> we should combine the comment in that function into one comment here.
>> >> >> >> > OK, I don't oppose that.
>> >> >> >> >
>> >> >> >> >>
>> >> >> >> >> > +       if (err) {
>> >> >> >> >> > +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
>> >> >> >> >> > +                       mmc_hostname(host), err);
>> >> >> >> >> > +               return err;
>> >> >> >> >> > +       }
>> >> >> >> >> > +
>> >> >> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> >> > +                        EXT_CSD_BUS_WIDTH,
>> >> >> >> >> > +                        EXT_CSD_DDR_BUS_WIDTH_8,
>> >> >> >> >> > +                        card->ext_csd.generic_cmd6_time);
>> >> >> >> >> > +       if (err) {
>> >> >> >> >> > +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
>> >> >> >> >> > +                       mmc_hostname(host), err);
>> >> >> >> >> > +               return err;
>> >> >> >> >> > +       }
>> >> >> >> >> > +
>> >> >> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> >> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
>> >> >> >> >> > +                        card->ext_csd.generic_cmd6_time);
>> >> >> >> >> > +       if (err) {
>> >> >> >> >> > +               pr_warn("%s: switch to hs400 failed, err:%d\n",
>> >> >> >> >> > +                        mmc_hostname(host), err);
>> >> >> >> >> > +               return err;
>> >> >> >> >> > +       }
>> >> >> >> >> > +
>> >> >> >> >> > +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>> >> >> >> >> > +       mmc_set_bus_speed(card);
>> >> >> >> >> > +
>> >> >> >> >> > +       return 0;
>> >> >> >> >> > +}
>> >> >> >> >> > +
>> >> >> >> >> >  /*
>> >> >> >> >> >   * For device supporting HS200 mode, the following sequence
>> >> >> >> >> >   * should be done before executing the tuning process.
>> >> >> >> >> > @@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
>> >> >> >> >> >                                    EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
>> >> >> >> >> >                                    card->ext_csd.generic_cmd6_time,
>> >> >> >> >> >                                    true, true, true);
>> >> >> >> >> > -               if (!err)
>> >> >> >> >> > +               if (err)
>> >> >> >> >> > +                       goto err;
>> >> >> >> >> > +
>> >> >> >> >> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
>> >> >> >> >> > +                       /*
>> >> >> >> >> > +                        * Timing should be adjusted to the HS400 target
>> >> >> >> >> > +                        * operation frequency for tuning process
>> >> >> >> >> > +                        */
>> >> >> >> >> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
>> >> >> >> >>
>> >> >> >> >> This seems strange. Do we really need a separate
>> >> >> >> >> MMC_TIMING_MMC_HS400_TUNING value?
>> >> >> >> > Spec. describes the HS400 selection sequence like below.
>> >> >> >> > <Quot>
>> >> >> >> > ...
>> >> >> >> > 6) Perform the Tuning Process at the HS400 target operating frequency
>> >> >> >> > (Note: tuning process in HS200 mode is required to synchronize the command response on the
>> CMD
>> >> >> line
>> >> >> >> to CLK for HS400 operation).
>> >> >> >> > ...
>> >> >> >> > </Quot>
>> >> >> >> > That means target clock rate for tuning sequence can be different with HS200.
>> >> >> >> > Considering for that, it needs to distinguish.
>> >> >> >>
>> >> >> >> I understand the spec now, thanks.
>> >> >> >>
>> >> >> >> Still, I am not convinced we should handle this through the
>> >> >> >> MMC_TIMING* field. That will leave host drivers to do some magic clock
>> >> >> >> frequency calculation from their ->set_ios callbacks, just depending
>> >> >> >> on the MMC_TIMING_MMC_HS400_TUNING value.
>> >> >> >>
>> >> >> >> I am also a bit concerned how MMC_TIMING_MMC_HS400_TUNING, would work
>> >> >> >> if/when we implement periodic re-tuning - triggered from the mmc core
>> >> >> >> layer.
>> >> >> >>
>> >> >> >> What we really want to do, is to pretend we were to operate in
>> >> >> >> MMC_TIMING_MMC_HS400 and ask the host driver what the target frequency
>> >> >> >> would be in this case. Then set this frequency through
>> >> >> >> mmc_set_clock().
>> >> >> >>
>> >> >> >> Then how do we ask the host driver about this frequency? Let's add a
>> >> >> >> new host_ops callback. We want it to be generic, so provide the
>> >> >> >> MMC_TIMING bit as a parameter. Additionally we want it to be optional
>> >> >> >> to implement, thus for those host drivers that supports the same
>> >> >> >> target frequency for HS200 as for HS400, they don't need to implement
>> >> >> >> it.
>> >> >> >>
>> >> >> >> Would this be a way forward?
>> >> >> >
>> >> >> > Thanks for your opinion.
>> >> >> >
>> >> >> > IMO, in this case additional callback handling seems to cause the complication in host side.
>> >> >> > I think we don't need to ask host driver about target frequency for HS400 in order to set
>> >> specific
>> >> >> frequency through
>> >> >> > mmc_set_clock().
>> >> >> > Target frequency which core layer requires for HS400 will be 200MHz and it is also mentioned
>> in
>> >> >> specification.
>> >> >> > Host driver including actual controller just will effort to make DDR rate with 200MHz.
>> >> >>
>> >> >> What the mmc_set_clock() request is not the same as what the frequency
>> >> >> actually will be set to. That depends on the host controller/driver.
>> >> >>
>> >> >> If for some reason the host controller/driver are not able to use the
>> >> >> same frequency for HS200 as for HS400, this should be possible to be
>> >> >> addressed in the way I suggested.
>> >> > I checked your sequence, but I'm not sure whether your suggestion is suitable for this.
>> >> > As we know, in case of DDR52 clock rate requested by mmc_set_clock() is not different from High
>> >> speed; Actually same 52Mhz is
>> >> > requested.
>> >> > It will be same in HS400 mode. Clock rate for mmc_set_clock() will be 200MHz in both HS200 and
>> HS400.
>> >> > Instead, host driver may control specific register for DDR rate output.
>> >> > This is why core layer don't need call extra mmc_set_clock().
>> >> > That means it doesn't need to ask host driver about frequency with using additional callback.
>> >> > What core layer should do is to gives host driver timing information such as
>> >> MMC_TIMING_MMC_HS400_TUNING.
>> >> > Then, host can prepare specific timing setting for HS400 tuning.
>> >> > As you mentioned, it depends on the host controller/driver.
>> >>
>> >> The reason why I suggested to add a new host_ops callback and to use
>> >> the mmc_set_clock() method was to address what's mentioned in the
>> >> spec, which you pointed me to.
>> >>
>> >> So, now you are saying we don't need to consider this scenario,
>> >> because very likely we will be using the same frequency as for HS200.
>> > I didn't mean actual output clock frequency.
>> > Just mentioned required clock rate through mmc_set_clock() in core layer.
>> >
>> > I think clock generation depends on host controller.
>> > For higher speed, some programmable setting will be needed.
>> > Hopefully, you could find the following patch to check how HS400 is handled in host driver.
>> > Exynos host changes internal clock rate for HS400 mode.
>> > "[PATCH v2 5/7] mmc: dw_mmc: exynos: support eMMC's HS400 mode"
>> >
>> >>
>> >> Okay - let's leave this to be implemented if/when we see there is a need for it.
>> >>
>> >> >
>> >> >>
>> >> >> > MMC_TIMING_MMC_HS400_TUNING may be used as notification for host to prepare HS400 tuning
>> sequence.
>> >> >>
>> >> >> So, are you saying that your controller are have different tuning
>> >> >> methods for HS200 vs HS400? That's a different requirement, which of
>> >> >> course we need to handle.
>> >> > NO, tuning method is equal. I meant that host's setting for IO timing would be different.
>> >>
>> >> I suppose this means the host don't need to bother about HS400 (at
>> >> all) during tuning sequence and thus we don't need the
>> >> MMC_TIMING_MMC_HS400_TUNING timing? Or am I missing your point?
>> > Please check the patch I mentioned above.
>>
>> In the patch you refer to above, your ->set_ios callback takes
>> specific actions while "MMC_TIMING_MMC_HS400_TUNING".
>>
>> Like this:
>> +       case MMC_TIMING_MMC_HS400_TUNING:
>> +               clksel = priv->hs400_timing;
>> +               wanted <<= 1;
>> +               break;
>>
>> I don't think inventing MMC_TIMING_MMC_HS400_TUNING is the correct
>> approach to solve this. Instead, I believe we have these two options:
> MMC_TIMING_MMC_HS400_TUNING can be recognized for specific timing identifier.
> I think it is not different from other timings and set_ios() has a role to handle those.
> Could you please explain the reason why you don't think it's correct?

The timings are directly related to bus speed modes from the
mmc/sd/sdio specs. There are no such thing as a "tuning" speed mode in
there. This is something that might be specific for your controller.

>
>>
>> 1. Let the host_ops->execute_tuning callback, notify the host about
>> HS400 tuning. Currently the "opcode" parameter is directly related to
>> the actual MMC command, but we could change that to have a different
>> meaning. Obviously you need to convert those host drivers implementing
>> the callback, but that should be quite simply I think.
> Currently, execute_tuning callback has been implemented in some host drivers.
> I guess it may not simple way.

Sure, just give it try and see what happens. :-)

>
>>
>> 2. Invent a new host_ops callback, like host_ops->execute_hs400_tuning.
> I don't this way is proper. Tuning method is not different.
>

If 1) becomes too complex, I am fine with option 2) as well.

Kind regards
Ulf Hansson

>>
>> >
>> >>
>> >> While we are discussion this, what about re-tuning? Is that also
>> >> supposed to be done in HS200 mode?
>> > I guess re-tuning is not related to this patch.
>> > OK, Can you say in more detail?
>> > I didn't get your meaning.
>>
>> Currently sdhci performs re-tuning while a timer has elapsed, locally
>> implemented in the sdhci host.
>>
>> Instead, I would like the re-tuning to be triggered from the mmc core
>> layer - thus all host drivers can benefit. Potentially the mmc core
>> would invoke the host_ops->execute_tuning callback to perform the
>> re-tuning. I just wanted you to keep this in mind, while implementing
>> 1) or 2), sorry if it was too unclear.
> It's interesting to me.
> Ok. If we need to consider re-tuning, it would be next time.
>
> Thanks,
> Seungwon Jeon
>

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

* RE: [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-04-04 11:58                         ` Ulf Hansson
@ 2014-04-05 14:36                           ` Seungwon Jeon
  0 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-05 14:36 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On Fri, April 04, 2014, Ulf Hansson wrote:
> On 4 April 2014 12:46, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > On Thu, April 03, 2014, Ulf Hansson wrote:
> >> On 3 April 2014 13:53, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> > On Wed, April 02, 2014, Ulf Hansson wrote:
> >> >> On 2 April 2014 03:15, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> >> > On Fri, March 28, 2014, Ulf Hansson wrote:
> >> >> >> On 28 March 2014 13:18, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> >> >> > On Fri, March 28, 2014, Ulf Hansson wrote:
> >> >> >> >> On 25 March 2014 10:23, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> >> >> >> > Hi Ulf,
> >> >> >> >> >
> >> >> >> >> > On Tue, March 25, 2014, Ulf Hansson wrote:
> >> >> >> >> >> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> >> >> >> >> >> > 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: Seungwon Jeon <tgih.jun@samsung.com>
> >> >> >> >> >> > Reviewed-by: Jackey Shen <jackey.shen@amd.com>
> >> >> >> >> >> > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
> >> >> >> >> >> > Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
> >> >> >> >> >> > ---
> >> >> >> >> >> >  drivers/mmc/core/bus.c     |    1 +
> >> >> >> >> >> >  drivers/mmc/core/debugfs.c |    3 +
> >> >> >> >> >> >  drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
> >> >> >> >> >> >  include/linux/mmc/card.h   |    1 +
> >> >> >> >> >> >  include/linux/mmc/host.h   |   15 +++++-
> >> >> >> >> >> >  include/linux/mmc/mmc.h    |    7 ++-
> >> >> >> >> >> >  6 files changed, 134 insertions(+), 8 deletions(-)
> >> >> >> >> >> >
> >> >> >> >> >> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> >> >> >> >> >> > index f37e9d6..d2dbf02 100644
> >> >> >> >> >> > --- a/drivers/mmc/core/bus.c
> >> >> >> >> >> > +++ b/drivers/mmc/core/bus.c
> >> >> >> >> >> > @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
> >> >> >> >> >> >                         mmc_hostname(card->host),
> >> >> >> >> >> >                         mmc_card_uhs(card) ? "ultra high speed " :
> >> >> >> >> >> >                         (mmc_card_hs(card) ? "high speed " : ""),
> >> >> >> >> >> > +                       mmc_card_hs400(card) ? "HS400 " :
> >> >> >> >> >> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
> >> >> >> >> >> >                         mmc_card_ddr52(card) ? "DDR " : "",
> >> >> >> >> >> >                         uhs_bus_speed_mode, type, card->rca);
> >> >> >> >> >> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> >> >> >> >> >> > index 1f730db..91eb162 100644
> >> >> >> >> >> > --- a/drivers/mmc/core/debugfs.c
> >> >> >> >> >> > +++ b/drivers/mmc/core/debugfs.c
> >> >> >> >> >> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
> >> >> >> >> >> >         case MMC_TIMING_MMC_HS200:
> >> >> >> >> >> >                 str = "mmc HS200";
> >> >> >> >> >> >                 break;
> >> >> >> >> >> > +       case MMC_TIMING_MMC_HS400:
> >> >> >> >> >> > +               str = "mmc HS400";
> >> >> >> >> >> > +               break;
> >> >> >> >> >> >         default:
> >> >> >> >> >> >                 str = "invalid";
> >> >> >> >> >> >                 break;
> >> >> >> >> >> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >> >> >> >> >> > index 6dd68e6..969d595 100644
> >> >> >> >> >> > --- a/drivers/mmc/core/mmc.c
> >> >> >> >> >> > +++ b/drivers/mmc/core/mmc.c
> >> >> >> >> >> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8
> **new_ext_csd)
> >> >> >> >> >> >  static void mmc_select_card_type(struct mmc_card *card)
> >> >> >> >> >> >  {
> >> >> >> >> >> >         struct mmc_host *host = card->host;
> >> >> >> >> >> > -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> >> >> >> >> >> > +       u8 card_type = card->ext_csd.raw_card_type;
> >> >> >> >> >> >         u32 caps = host->caps, caps2 = host->caps2;
> >> >> >> >> >> >         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
> >> >> >> >> >> >         unsigned int avail_type = 0;
> >> >> >> >> >> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
> >> >> >> >> >> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> >> >> >> >> >> >         }
> >> >> >> >> >> >
> >> >> >> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_8V &&
> >> >> >> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> >> >> >> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> >> >> >> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> >> >> >> >> >> > +       }
> >> >> >> >> >> > +
> >> >> >> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_2V &&
> >> >> >> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> >> >> >> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> >> >> >> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> >> >> >> >> >> > +       }
> >> >> >> >> >> > +
> >> >> >> >> >> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
> >> >> >> >> >> >         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
> >> >> >> >> >> >         card->mmc_avail_type = avail_type;
> >> >> >> >> >> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
> >> >> >> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
> >> >> >> >> >> >                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
> >> >> >> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> >> >> >> >> >> > +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
> >> >> >> >> >> > +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
> >> >> >> >> >> >         }
> >> >> >> >> >> >
> >> >> >> >> >> >         if (card->ext_csd.rev >= 5) {
> >> >> >> >> >> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned
> >> >> bus_width)
> >> >> >> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
> >> >> >> >> >> >                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
> >> >> >> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> >> >> >> >> >> > -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> >> >> >> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> >> >> >> >> >> > +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> >> >> >> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> >> >> >> >> >> > +
> >> >> >> >> >> >         if (err)
> >> >> >> >> >> >                 err = -EINVAL;
> >> >> >> >> >> >
> >> >> >> >> >> > @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
> >> >> >> >> >> >                                 ext_csd->raw_pwr_cl_52_360 :
> >> >> >> >> >> >                                 ext_csd->raw_pwr_cl_ddr_52_360;
> >> >> >> >> >> >                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> >> >> >> >> >> > -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
> >> >> >> >> >> > +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> >> >> >> >> >> > +                               ext_csd->raw_pwr_cl_ddr_200_360 :
> >> >> >> >> >> > +                               ext_csd->raw_pwr_cl_200_360;
> >> >> >> >> >> >                 break;
> >> >> >> >> >> >         default:
> >> >> >> >> >> >                 pr_warning("%s: Voltage range not supported "
> >> >> >> >> >> > @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
> >> >> >> >> >> >  {
> >> >> >> >> >> >         unsigned int max_dtr = (unsigned int)-1;
> >> >> >> >> >> >
> >> >> >> >> >> > -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> >> >> >> >> >> > +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
> >> >> >> >> >> > +            max_dtr > card->ext_csd.hs200_max_dtr)
> >> >> >> >> >> >                 max_dtr = card->ext_csd.hs200_max_dtr;
> >> >> >> >> >> >         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
> >> >> >> >> >> >                 max_dtr = card->ext_csd.hs_max_dtr;
> >> >> >> >> >> > @@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
> >> >> >> >> >> >  }
> >> >> >> >> >> >
> >> >> >> >> >> >  /*
> >> >> >> >> >> > + * Revert to the high-speed mode from above speed
> >> >> >> >> >> > + */
> >> >> >> >> >> > +static int mmc_revert_to_hs(struct mmc_card *card)
> >> >> >> >> >> > +{
> >> >> >> >> >> > +       /*
> >> >> >> >> >> > +        * CMD13, which is used to confirm the completion of timing
> >> >> >> >> >> > +        * change, will be issued at higher speed timing condtion
> >> >> >> >> >> > +        * rather than high-speed. If device has completed the change
> >> >> >> >> >> > +        * to high-speed mode, it may not be proper timing to issue
> >> >> >> >> >> > +        * command. Low speed supplies better timing margin than high
> >> >> >> >> >> > +        * speed. Accordingly clock rate & timging should be chagned
> >> >> >> >> >> > +        * ahead before actual switch.
> >> >> >> >> >>
> >> >> >> >> >> I have some problem to understand this comment. I guess you are trying
> >> >> >> >> >> to provide the arguments to why it makes sense to perform the revert
> >> >> >> >> >> to lower speed mode!?
> >> >> >> >> >>
> >> >> >> >> >> This makes me wonder if this is not part of the spec? Could you try to clarify?
> >> >> >> >> > But specification says that "HS_TIMING must be set to "0x1" before setting BUS_WIDTH for
> >> dual
> >> >> >> data
> >> >> >> >> rate operation".
> >> >> >> >> > I think this sequence is not graceful.
> >> >> >> >> > I also commented why speed mode should be changed to high-speed mode from HS200 mode in
> the
> >> >> >> >> function-called part.
> >> >> >> >> > Because it is not possible to set 8-bit data bus for dual rate on HS200 mode, revert to
> >> high-
> >> >> >> speed
> >> >> >> >> from HS200 is needed.
> >> >> >> >> > If the above-commented point makes it confused, it could be removed.
> >> >> >> >> > Please let me know your opinion.
> >> >> >> >> >
> >> >> >> >> >>
> >> >> >> >> >> > +        */
> >> >> >> >> >> > +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> >> >> >> >> >> > +       mmc_set_bus_speed(card);
> >> >> >> >> >> > +
> >> >> >> >> >> > +       return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> >> >> >> > +                         EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> >> >> >> >> >> > +                         card->ext_csd.generic_cmd6_time);
> >> >> >> >> >> > +}
> >> >> >> >> >> > +
> >> >> >> >> >> > +/*
> >> >> >> >> >> >   * Activate wide bus and DDR if supported.
> >> >> >> >> >> >   */
> >> >> >> >> >> >  static int mmc_select_hs_ddr(struct mmc_card *card)
> >> >> >> >> >> > @@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
> >> >> >> >> >> >         return err;
> >> >> >> >> >> >  }
> >> >> >> >> >> >
> >> >> >> >> >> > +static int mmc_select_hs400(struct mmc_card *card)
> >> >> >> >> >> > +{
> >> >> >> >> >> > +       struct mmc_host *host = card->host;
> >> >> >> >> >> > +       int err = 0;
> >> >> >> >> >> > +
> >> >> >> >> >> > +       /*
> >> >> >> >> >> > +        * The bus width is set to only 8 DDR in HS400 mode
> >> >> >> >> >>
> >> >> >> >> >> Please rephrase the comment to something like:
> >> >> >> >> >> "HS400 mode requires 8-bit bus width."
> >> >> >> >> > As it is, it was from spec's description.
> >> >> >> >> > But I think yours would be more clearable.
> >> >> >> >> >
> >> >> >> >> >>
> >> >> >> >> >> > +        */
> >> >> >> >> >> > +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
> >> >> >> >> >> > +             host->ios.bus_width == MMC_BUS_WIDTH_8))
> >> >> >> >> >> > +               return 0;
> >> >> >> >> >> > +
> >> >> >> >> >> > +       /*
> >> >> >> >> >> > +        * Before setting BUS_WIDTH for dual data rate operation,
> >> >> >> >> >> > +        * HS_TIMING must be set to High Speed(0x1)
> >> >> >> >> >> > +        */
> >> >> >> >> >>
> >> >> >> >> >> Please rephrase comment:
> >> >> >> >> >>
> >> >> >> >> >> "Before switching to dual data rate operation for HS400, we need
> >> >> >> >> >> revert from HS200 timing to regular HS timing."
> >> >> >> >> > Ok.
> >> >> >> >> >
> >> >> >> >> >>
> >> >> >> >> >> > +       err = mmc_revert_to_hs(card);
> >> >> >> >> >>
> >> >> >> >> >> I don't think we need a separate function to handle the revert.
> >> >> >> >> >> Please, just add the code here instead. While you do that, I suppose
> >> >> >> >> >> we should combine the comment in that function into one comment here.
> >> >> >> >> > OK, I don't oppose that.
> >> >> >> >> >
> >> >> >> >> >>
> >> >> >> >> >> > +       if (err) {
> >> >> >> >> >> > +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> >> >> >> >> >> > +                       mmc_hostname(host), err);
> >> >> >> >> >> > +               return err;
> >> >> >> >> >> > +       }
> >> >> >> >> >> > +
> >> >> >> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> >> >> >> > +                        EXT_CSD_BUS_WIDTH,
> >> >> >> >> >> > +                        EXT_CSD_DDR_BUS_WIDTH_8,
> >> >> >> >> >> > +                        card->ext_csd.generic_cmd6_time);
> >> >> >> >> >> > +       if (err) {
> >> >> >> >> >> > +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> >> >> >> >> >> > +                       mmc_hostname(host), err);
> >> >> >> >> >> > +               return err;
> >> >> >> >> >> > +       }
> >> >> >> >> >> > +
> >> >> >> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >> >> >> >> >> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> >> >> >> >> >> > +                        card->ext_csd.generic_cmd6_time);
> >> >> >> >> >> > +       if (err) {
> >> >> >> >> >> > +               pr_warn("%s: switch to hs400 failed, err:%d\n",
> >> >> >> >> >> > +                        mmc_hostname(host), err);
> >> >> >> >> >> > +               return err;
> >> >> >> >> >> > +       }
> >> >> >> >> >> > +
> >> >> >> >> >> > +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> >> >> >> >> >> > +       mmc_set_bus_speed(card);
> >> >> >> >> >> > +
> >> >> >> >> >> > +       return 0;
> >> >> >> >> >> > +}
> >> >> >> >> >> > +
> >> >> >> >> >> >  /*
> >> >> >> >> >> >   * For device supporting HS200 mode, the following sequence
> >> >> >> >> >> >   * should be done before executing the tuning process.
> >> >> >> >> >> > @@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
> >> >> >> >> >> >                                    EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
> >> >> >> >> >> >                                    card->ext_csd.generic_cmd6_time,
> >> >> >> >> >> >                                    true, true, true);
> >> >> >> >> >> > -               if (!err)
> >> >> >> >> >> > +               if (err)
> >> >> >> >> >> > +                       goto err;
> >> >> >> >> >> > +
> >> >> >> >> >> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
> >> >> >> >> >> > +                       /*
> >> >> >> >> >> > +                        * Timing should be adjusted to the HS400 target
> >> >> >> >> >> > +                        * operation frequency for tuning process
> >> >> >> >> >> > +                        */
> >> >> >> >> >> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
> >> >> >> >> >>
> >> >> >> >> >> This seems strange. Do we really need a separate
> >> >> >> >> >> MMC_TIMING_MMC_HS400_TUNING value?
> >> >> >> >> > Spec. describes the HS400 selection sequence like below.
> >> >> >> >> > <Quot>
> >> >> >> >> > ...
> >> >> >> >> > 6) Perform the Tuning Process at the HS400 target operating frequency
> >> >> >> >> > (Note: tuning process in HS200 mode is required to synchronize the command response on
> the
> >> CMD
> >> >> >> line
> >> >> >> >> to CLK for HS400 operation).
> >> >> >> >> > ...
> >> >> >> >> > </Quot>
> >> >> >> >> > That means target clock rate for tuning sequence can be different with HS200.
> >> >> >> >> > Considering for that, it needs to distinguish.
> >> >> >> >>
> >> >> >> >> I understand the spec now, thanks.
> >> >> >> >>
> >> >> >> >> Still, I am not convinced we should handle this through the
> >> >> >> >> MMC_TIMING* field. That will leave host drivers to do some magic clock
> >> >> >> >> frequency calculation from their ->set_ios callbacks, just depending
> >> >> >> >> on the MMC_TIMING_MMC_HS400_TUNING value.
> >> >> >> >>
> >> >> >> >> I am also a bit concerned how MMC_TIMING_MMC_HS400_TUNING, would work
> >> >> >> >> if/when we implement periodic re-tuning - triggered from the mmc core
> >> >> >> >> layer.
> >> >> >> >>
> >> >> >> >> What we really want to do, is to pretend we were to operate in
> >> >> >> >> MMC_TIMING_MMC_HS400 and ask the host driver what the target frequency
> >> >> >> >> would be in this case. Then set this frequency through
> >> >> >> >> mmc_set_clock().
> >> >> >> >>
> >> >> >> >> Then how do we ask the host driver about this frequency? Let's add a
> >> >> >> >> new host_ops callback. We want it to be generic, so provide the
> >> >> >> >> MMC_TIMING bit as a parameter. Additionally we want it to be optional
> >> >> >> >> to implement, thus for those host drivers that supports the same
> >> >> >> >> target frequency for HS200 as for HS400, they don't need to implement
> >> >> >> >> it.
> >> >> >> >>
> >> >> >> >> Would this be a way forward?
> >> >> >> >
> >> >> >> > Thanks for your opinion.
> >> >> >> >
> >> >> >> > IMO, in this case additional callback handling seems to cause the complication in host side.
> >> >> >> > I think we don't need to ask host driver about target frequency for HS400 in order to set
> >> >> specific
> >> >> >> frequency through
> >> >> >> > mmc_set_clock().
> >> >> >> > Target frequency which core layer requires for HS400 will be 200MHz and it is also
> mentioned
> >> in
> >> >> >> specification.
> >> >> >> > Host driver including actual controller just will effort to make DDR rate with 200MHz.
> >> >> >>
> >> >> >> What the mmc_set_clock() request is not the same as what the frequency
> >> >> >> actually will be set to. That depends on the host controller/driver.
> >> >> >>
> >> >> >> If for some reason the host controller/driver are not able to use the
> >> >> >> same frequency for HS200 as for HS400, this should be possible to be
> >> >> >> addressed in the way I suggested.
> >> >> > I checked your sequence, but I'm not sure whether your suggestion is suitable for this.
> >> >> > As we know, in case of DDR52 clock rate requested by mmc_set_clock() is not different from
> High
> >> >> speed; Actually same 52Mhz is
> >> >> > requested.
> >> >> > It will be same in HS400 mode. Clock rate for mmc_set_clock() will be 200MHz in both HS200 and
> >> HS400.
> >> >> > Instead, host driver may control specific register for DDR rate output.
> >> >> > This is why core layer don't need call extra mmc_set_clock().
> >> >> > That means it doesn't need to ask host driver about frequency with using additional callback.
> >> >> > What core layer should do is to gives host driver timing information such as
> >> >> MMC_TIMING_MMC_HS400_TUNING.
> >> >> > Then, host can prepare specific timing setting for HS400 tuning.
> >> >> > As you mentioned, it depends on the host controller/driver.
> >> >>
> >> >> The reason why I suggested to add a new host_ops callback and to use
> >> >> the mmc_set_clock() method was to address what's mentioned in the
> >> >> spec, which you pointed me to.
> >> >>
> >> >> So, now you are saying we don't need to consider this scenario,
> >> >> because very likely we will be using the same frequency as for HS200.
> >> > I didn't mean actual output clock frequency.
> >> > Just mentioned required clock rate through mmc_set_clock() in core layer.
> >> >
> >> > I think clock generation depends on host controller.
> >> > For higher speed, some programmable setting will be needed.
> >> > Hopefully, you could find the following patch to check how HS400 is handled in host driver.
> >> > Exynos host changes internal clock rate for HS400 mode.
> >> > "[PATCH v2 5/7] mmc: dw_mmc: exynos: support eMMC's HS400 mode"
> >> >
> >> >>
> >> >> Okay - let's leave this to be implemented if/when we see there is a need for it.
> >> >>
> >> >> >
> >> >> >>
> >> >> >> > MMC_TIMING_MMC_HS400_TUNING may be used as notification for host to prepare HS400 tuning
> >> sequence.
> >> >> >>
> >> >> >> So, are you saying that your controller are have different tuning
> >> >> >> methods for HS200 vs HS400? That's a different requirement, which of
> >> >> >> course we need to handle.
> >> >> > NO, tuning method is equal. I meant that host's setting for IO timing would be different.
> >> >>
> >> >> I suppose this means the host don't need to bother about HS400 (at
> >> >> all) during tuning sequence and thus we don't need the
> >> >> MMC_TIMING_MMC_HS400_TUNING timing? Or am I missing your point?
> >> > Please check the patch I mentioned above.
> >>
> >> In the patch you refer to above, your ->set_ios callback takes
> >> specific actions while "MMC_TIMING_MMC_HS400_TUNING".
> >>
> >> Like this:
> >> +       case MMC_TIMING_MMC_HS400_TUNING:
> >> +               clksel = priv->hs400_timing;
> >> +               wanted <<= 1;
> >> +               break;
> >>
> >> I don't think inventing MMC_TIMING_MMC_HS400_TUNING is the correct
> >> approach to solve this. Instead, I believe we have these two options:
> > MMC_TIMING_MMC_HS400_TUNING can be recognized for specific timing identifier.
> > I think it is not different from other timings and set_ios() has a role to handle those.
> > Could you please explain the reason why you don't think it's correct?
> 
> The timings are directly related to bus speed modes from the
> mmc/sd/sdio specs. There are no such thing as a "tuning" speed mode in
> there. This is something that might be specific for your controller.

Yes. We are talking about bus speed modes.
Those are nothing less than speed modes which host should adjust for specific operating mode.
I think that timing information is just for host side.
As spec says that tuning should be performed at the "HS400 target operating frequency",
MMC_TIMING_MMC_HS400_TUNING can be one of them, which host should work something finally.
We typically place set_ios() in charge of those things relevant to speed mode/timing.
(It also could be the reason why I didn't select specific callback function.)

Clearly, HS400's tuning is not performed at DDR 200(HS400 mode).
But that doesn't mean this tuning is targeting clock frequency for HS200.
If so, spec would not mention the "HS400 target operating frequency".
It comes from the fact CMD line is still synchronized at 200MHz even after HS400 mode.
MMC_TIMING_MMC_HS400_TUNING may be expected to indicate this timing mode distinguishing HS200's.
Although I hope it help to reach an agreement, I'll try to consider in your suggestion.
(Perhaps, if you introduce other controller case, it could be helpful.)

Let send the update version soon.

Thanks,
Seungwon Jeon
> 
> >
> >>
> >> 1. Let the host_ops->execute_tuning callback, notify the host about
> >> HS400 tuning. Currently the "opcode" parameter is directly related to
> >> the actual MMC command, but we could change that to have a different
> >> meaning. Obviously you need to convert those host drivers implementing
> >> the callback, but that should be quite simply I think.
> > Currently, execute_tuning callback has been implemented in some host drivers.
> > I guess it may not simple way.
> 
> Sure, just give it try and see what happens. :-)
> 
> >
> >>
> >> 2. Invent a new host_ops callback, like host_ops->execute_hs400_tuning.
> > I don't this way is proper. Tuning method is not different.
> >
> 
> If 1) becomes too complex, I am fine with option 2) as well.
> 
> Kind regards
> Ulf Hansson
> 
> >>
> >> >
> >> >>
> >> >> While we are discussion this, what about re-tuning? Is that also
> >> >> supposed to be done in HS200 mode?
> >> > I guess re-tuning is not related to this patch.
> >> > OK, Can you say in more detail?
> >> > I didn't get your meaning.
> >>
> >> Currently sdhci performs re-tuning while a timer has elapsed, locally
> >> implemented in the sdhci host.
> >>
> >> Instead, I would like the re-tuning to be triggered from the mmc core
> >> layer - thus all host drivers can benefit. Potentially the mmc core
> >> would invoke the host_ops->execute_tuning callback to perform the
> >> re-tuning. I just wanted you to keep this in mind, while implementing
> >> 1) or 2), sorry if it was too unclear.
> > It's interesting to me.
> > Ok. If we need to consider re-tuning, it would be next time.
> >
> > Thanks,
> > Seungwon Jeon
> >


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

* [PATCH v5 0/5] update selection of bus speed mode for eMMC
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (8 preceding siblings ...)
  2014-03-26 11:00   ` [PATCH v4 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
@ 2014-04-11 11:33   ` Seungwon Jeon
  2014-04-11 11:34   ` [PATCH v5 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
                     ` (18 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-11 11:33 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

This series contains the change for selection of bus speed mode.
Previous implementation is complicated and some sequence is duplicated.
And specially, HS400 mode eMMC5.0 is introduced this time.
This patch-set has been tested in Exynos SoC.

Note:
This patch-set depends on "[PATCH RESEND v3 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC".

Changes in v5:
	(5/5) Added callback operation for HS400 target operation frequency
	       instead of specific timing identifier.
	(2/5) Removed using union declaration.

Changes in v4:
	(5/5)Reverting to HS mode is included in mmc_select_hs400() using __mmc_switch().

Changes in v3:
 	Removed the function to check DDR type(mmc_snoop_ddr).
 	Rebased with the latest branch.

Seungwon Jeon (5):
  mmc: drop the speed mode of card's state
  mmc: identify available device type to select
  mmc: step power class after final selection of bus mode
  mmc: rework selection of bus speed mode
  mmc: add support for HS400 mode of eMMC5.0

 drivers/mmc/core/bus.c     |    9 +-
 drivers/mmc/core/core.c    |    3 +-
 drivers/mmc/core/debugfs.c |    5 +-
 drivers/mmc/core/mmc.c     |  666 ++++++++++++++++++++++++++------------------
 drivers/mmc/core/sd.c      |   16 +-
 drivers/mmc/core/sd.h      |    1 -
 drivers/mmc/core/sdio.c    |    8 +-
 include/linux/mmc/card.h   |   27 +--
 include/linux/mmc/host.h   |   43 +++-
 include/linux/mmc/mmc.h    |   23 ++-
 10 files changed, 480 insertions(+), 321 deletions(-)

 
Thanks,
sw-j


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

* [PATCH v5 1/5] mmc: drop the speed mode of card's state
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (9 preceding siblings ...)
  2014-04-11 11:33   ` [PATCH v5 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
@ 2014-04-11 11:34   ` Seungwon Jeon
  2014-04-11 11:34   ` [PATCH v5 2/5] mmc: identify available device type to select Seungwon Jeon
                     ` (17 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-11 11:34 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Timing mode identifier has same role and can take the place
of speed mode. This change removes all related speed mode.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/bus.c   |    8 ++++----
 drivers/mmc/core/core.c  |    3 +--
 drivers/mmc/core/mmc.c   |   11 +++--------
 drivers/mmc/core/sd.c    |   16 +++-------------
 drivers/mmc/core/sd.h    |    1 -
 drivers/mmc/core/sdio.c  |    8 ++------
 include/linux/mmc/card.h |   23 ++++++-----------------
 include/linux/mmc/host.h |   23 +++++++++++++++++++++++
 8 files changed, 42 insertions(+), 51 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 8246448..f37e9d6 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -341,16 +341,16 @@ int mmc_add_card(struct mmc_card *card)
 	if (mmc_host_is_spi(card->host)) {
 		pr_info("%s: new %s%s%s card on SPI\n",
 			mmc_hostname(card->host),
-			mmc_card_highspeed(card) ? "high speed " : "",
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_hs(card) ? "high speed " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			type);
 	} else {
 		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
-			(mmc_card_highspeed(card) ? "high speed " : ""),
+			(mmc_card_hs(card) ? "high speed " : ""),
 			(mmc_card_hs200(card) ? "HS200 " : ""),
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
 	}
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index acbc3f2..aa9f679 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2183,7 +2183,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
 	struct mmc_command cmd = {0};
 
-	if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+	if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
 		return 0;
 
 	cmd.opcode = MMC_SET_BLOCKLEN;
@@ -2263,7 +2263,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
 		}
 	}
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
 	if (mmc_host_is_spi(host)) {
 		host->ios.chip_select = MMC_CS_HIGH;
 		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e22d851..db9655f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1091,11 +1091,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		} else {
 			if (card->ext_csd.hs_max_dtr > 52000000 &&
 			    host->caps2 & MMC_CAP2_HS200) {
-				mmc_card_set_hs200(card);
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
 			} else {
-				mmc_card_set_highspeed(card);
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
 			}
 		}
@@ -1106,10 +1104,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
+	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
 		if (max_dtr > card->ext_csd.hs_max_dtr)
 			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_highspeed(card) && (max_dtr > 52000000))
+		if (mmc_card_hs(card) && (max_dtr > 52000000))
 			max_dtr = 52000000;
 	} else if (max_dtr > card->csd.max_dtr) {
 		max_dtr = card->csd.max_dtr;
@@ -1120,7 +1118,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
 			&& (host->caps & MMC_CAP_1_8V_DDR))
 				ddr = MMC_1_8V_DDR_MODE;
@@ -1263,7 +1261,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 				if (err)
 					goto err;
 			}
-			mmc_card_set_ddr_mode(card);
 			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
 			mmc_set_bus_width(card->host, bus_width);
 		}
@@ -1507,7 +1504,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 		err = mmc_sleep(host);
 	else if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 
 	if (!err) {
 		mmc_power_off(host);
@@ -1637,7 +1633,6 @@ static int mmc_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 	mmc_claim_host(host);
 	ret = mmc_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 2dd359d..9fc5b31 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -895,7 +895,7 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if (max_dtr > card->sw_caps.hs_max_dtr)
 			max_dtr = card->sw_caps.hs_max_dtr;
 	} else if (max_dtr > card->csd.max_dtr) {
@@ -905,12 +905,6 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 	return max_dtr;
 }
 
-void mmc_sd_go_highspeed(struct mmc_card *card)
-{
-	mmc_card_set_highspeed(card);
-	mmc_set_timing(card->host, MMC_TIMING_SD_HS);
-}
-
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -985,16 +979,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_sd_init_uhs_card(card);
 		if (err)
 			goto free_card;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Attempt to change to high-speed (if supported)
 		 */
 		err = mmc_sd_switch_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto free_card;
 
@@ -1089,7 +1080,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
 
 	if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
+
 	if (!err) {
 		mmc_power_off(host);
 		mmc_card_set_suspended(host->card);
@@ -1198,7 +1189,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
 	ret = mmc_sd_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
index 4b34b24..aab824a 100644
--- a/drivers/mmc/core/sd.h
+++ b/drivers/mmc/core/sd.h
@@ -12,6 +12,5 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 	bool reinit);
 unsigned mmc_sd_get_max_clock(struct mmc_card *card);
 int mmc_sd_switch_hs(struct mmc_card *card);
-void mmc_sd_go_highspeed(struct mmc_card *card);
 
 #endif
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4d721c6..ef57d2d 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		/*
 		 * The SDIO specification doesn't mention how
 		 * the CIS transfer speed register relates to
@@ -733,7 +733,6 @@ try_again:
 		mmc_set_clock(host, card->cis.max_dtr);
 
 		if (card->cccr.high_speed) {
-			mmc_card_set_highspeed(card);
 			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		}
 
@@ -792,16 +791,13 @@ try_again:
 		err = mmc_sdio_init_uhs_card(card);
 		if (err)
 			goto remove;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Switch to high-speed (if supported).
 		 */
 		err = sdio_enable_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto remove;
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index b730272..5473133 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -194,6 +194,7 @@ struct sdio_cis {
 };
 
 struct mmc_host;
+struct mmc_ios;
 struct sdio_func;
 struct sdio_func_tuple;
 
@@ -250,15 +251,11 @@ struct mmc_card {
 	unsigned int		state;		/* (our) card state */
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
 #define MMC_STATE_READONLY	(1<<1)		/* card is read-only */
-#define MMC_STATE_HIGHSPEED	(1<<2)		/* card is in high speed mode */
-#define MMC_STATE_BLOCKADDR	(1<<3)		/* card uses block-addressing */
-#define MMC_STATE_HIGHSPEED_DDR (1<<4)		/* card is in high speed mode */
-#define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra high speed mode */
-#define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
-#define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
-#define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
-#define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
-#define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
+#define MMC_STATE_BLOCKADDR	(1<<2)		/* card uses block-addressing */
+#define MMC_CARD_SDXC		(1<<3)		/* card is SDXC */
+#define MMC_CARD_REMOVED	(1<<4)		/* card has been removed */
+#define MMC_STATE_DOING_BKOPS	(1<<5)		/* card is doing BKOPS */
+#define MMC_STATE_SUSPENDED	(1<<6)		/* card is suspended */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -418,11 +415,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
-#define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
-#define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
-#define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
@@ -430,11 +423,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
-#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
-#define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
-#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_doing_bkops(c)	((c)->state |= MMC_STATE_DOING_BKOPS)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 3535420..2f263ae 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -17,6 +17,7 @@
 #include <linux/fault-inject.h>
 
 #include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -476,4 +477,26 @@ static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
 	return host->ios.clock;
 }
 #endif
+
+static inline int mmc_card_hs(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_SD_HS ||
+		card->host->ios.timing == MMC_TIMING_MMC_HS;
+}
+
+static inline int mmc_card_uhs(struct mmc_card *card)
+{
+	return card->host->ios.timing >= MMC_TIMING_UHS_SDR12 &&
+		card->host->ios.timing <= MMC_TIMING_UHS_DDR50;
+}
+
+static inline bool mmc_card_hs200(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_HS200;
+}
+
+static inline bool mmc_card_ddr52(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
+}
 #endif /* LINUX_MMC_HOST_H */
-- 
1.7.0.4



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

* [PATCH v5 2/5] mmc: identify available device type to select
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (10 preceding siblings ...)
  2014-04-11 11:34   ` [PATCH v5 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
@ 2014-04-11 11:34   ` Seungwon Jeon
  2014-04-11 11:47     ` Ulf Hansson
  2014-04-11 11:34   ` [PATCH v5 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
                     ` (16 subsequent siblings)
  28 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-11 11:34 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Device types which are supported by both host and device
can be identified when EXT_CSD is read. There is no need to
check host's capability anymore.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/mmc.c   |   72 +++++++++++++++++++++++++---------------------
 include/linux/mmc/card.h |    2 +-
 include/linux/mmc/host.h |    6 ----
 include/linux/mmc/mmc.h  |   12 +++++--
 4 files changed, 48 insertions(+), 44 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index db9655f..97f1912 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0;
+	unsigned int avail_type = 0;
 
-	if (card_type & EXT_CSD_CARD_TYPE_26)
+	if (caps & MMC_CAP_MMC_HIGHSPEED &&
+	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
 		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
+	}
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
-			card_type & EXT_CSD_CARD_TYPE_52)
+	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
 		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
+	}
 
-	if ((caps & MMC_CAP_1_8V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
-	    (caps & MMC_CAP_1_2V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
+	if (caps & MMC_CAP_1_8V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
 		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
+	}
+
+	if (caps & MMC_CAP_1_2V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
+	}
 
-	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
-	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
+	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
 		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
+		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
+	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
-	card->ext_csd.card_type = card_type;
+	card->mmc_avail_type = avail_type;
 }
 
 /*
@@ -808,12 +826,10 @@ static int mmc_select_hs200(struct mmc_card *card)
 
 	host = card->host;
 
-	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
-			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
 
-	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
-			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
 
 	/* If fails try again during next card power cycle */
@@ -1072,10 +1088,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	if (card->ext_csd.hs_max_dtr != 0) {
 		err = 0;
-		if (card->ext_csd.hs_max_dtr > 52000000 &&
-		    host->caps2 & MMC_CAP2_HS200)
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 			err = mmc_select_hs200(card);
-		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
+		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
 			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					EXT_CSD_HS_TIMING, 1,
 					card->ext_csd.generic_cmd6_time,
@@ -1089,13 +1104,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			       mmc_hostname(card->host));
 			err = 0;
 		} else {
-			if (card->ext_csd.hs_max_dtr > 52000000 &&
-			    host->caps2 & MMC_CAP2_HS200) {
+			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
-			} else {
+			else
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-			}
 		}
 	}
 
@@ -1118,14 +1131,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_hs(card)) {
-		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-			&& (host->caps & MMC_CAP_1_8V_DDR))
-				ddr = MMC_1_8V_DDR_MODE;
-		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-			&& (host->caps & MMC_CAP_1_2V_DDR))
-				ddr = MMC_1_2V_DDR_MODE;
-	}
+	if (mmc_card_hs(card))
+		ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
 
 	/*
 	 * Indicate HS200 SDR mode (if supported).
@@ -1145,8 +1152,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		 * 3. set the clock to > 52Mhz <=200MHz and
 		 * 4. execute tuning for HS200
 		 */
-		if ((host->caps2 & MMC_CAP2_HS200) &&
-		    card->host->ops->execute_tuning) {
+		if (card->host->ops->execute_tuning) {
 			mmc_host_clk_hold(card->host);
 			err = card->host->ops->execute_tuning(card->host,
 				MMC_SEND_TUNING_BLOCK_HS200);
@@ -1255,7 +1261,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			 *
 			 * WARNING: eMMC rules are NOT the same as SD DDR
 			 */
-			if (ddr == MMC_1_2V_DDR_MODE) {
+			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
 				err = __mmc_set_signal_voltage(host,
 					MMC_SIGNAL_VOLTAGE_120);
 				if (err)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 5473133..b9f194a 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -68,7 +68,6 @@ struct mmc_ext_csd {
 #define MMC_HIGH_DDR_MAX_DTR	52000000
 #define MMC_HS200_MAX_DTR	200000000
 	unsigned int		sectors;
-	unsigned int		card_type;
 	unsigned int		hc_erase_size;		/* In sectors */
 	unsigned int		hc_erase_timeout;	/* In milliseconds */
 	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
@@ -298,6 +297,7 @@ struct mmc_card {
 	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
 
 	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+	unsigned int		mmc_avail_type;	/* supported device type by both host and card */
 
 	struct dentry		*debugfs_root;
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 2f263ae..1ee3c10 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -62,12 +62,6 @@ struct mmc_ios {
 #define MMC_TIMING_MMC_DDR52	8
 #define MMC_TIMING_MMC_HS200	9
 
-#define MMC_SDR_MODE		0
-#define MMC_1_2V_DDR_MODE	1
-#define MMC_1_8V_DDR_MODE	2
-#define MMC_1_2V_SDR_MODE	3
-#define MMC_1_8V_SDR_MODE	4
-
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
 #define MMC_SIGNAL_VOLTAGE_330	0
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 50bcde3..f734c0c 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -354,18 +354,22 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#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_MASK	0x3F	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
+				 EXT_CSD_CARD_TYPE_HS_52)
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
 					     /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
 					     /* DDR mode @1.2V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
 					| EXT_CSD_CARD_TYPE_DDR_1_2V)
-#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
-#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_8V	(1<<4)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_2V	(1<<5)	/* Card can run at 200MHz */
 						/* SDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS200_1_2V)
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
-- 
1.7.0.4



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

* [PATCH v5 3/5] mmc: step power class after final selection of bus mode
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (11 preceding siblings ...)
  2014-04-11 11:34   ` [PATCH v5 2/5] mmc: identify available device type to select Seungwon Jeon
@ 2014-04-11 11:34   ` Seungwon Jeon
  2014-04-11 11:34   ` [PATCH v5 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
                     ` (15 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-11 11:34 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Power class is changed once only after selection of bus modes
including speed and bus-width finishes finally.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/mmc.c |   96 +++++++++++++++++++++++++++--------------------
 1 files changed, 55 insertions(+), 41 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 97f1912..480c100 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -732,17 +732,13 @@ static struct device_type mmc_type = {
  * extended CSD register, select it by executing the
  * mmc_switch command.
  */
-static int mmc_select_powerclass(struct mmc_card *card,
-		unsigned int bus_width)
+static int __mmc_select_powerclass(struct mmc_card *card,
+				   unsigned int bus_width)
 {
-	int err = 0;
+	struct mmc_host *host = card->host;
+	struct mmc_ext_csd *ext_csd = &card->ext_csd;
 	unsigned int pwrclass_val = 0;
-	struct mmc_host *host;
-
-	BUG_ON(!card);
-
-	host = card->host;
-	BUG_ON(!host);
+	int err = 0;
 
 	/* Power class selection is supported for versions >= 4.0 */
 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
@@ -754,14 +750,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
 
 	switch (1 << host->ios.vdd) {
 	case MMC_VDD_165_195:
-		if (host->ios.clock <= 26000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
-		else if	(host->ios.clock <= 52000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_26_195;
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-				card->ext_csd.raw_pwr_cl_52_195 :
-				card->ext_csd.raw_pwr_cl_ddr_52_195;
-		else if (host->ios.clock <= 200000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
+				ext_csd->raw_pwr_cl_52_195 :
+				ext_csd->raw_pwr_cl_ddr_52_195;
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_200_195;
 		break;
 	case MMC_VDD_27_28:
 	case MMC_VDD_28_29:
@@ -772,14 +768,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	case MMC_VDD_33_34:
 	case MMC_VDD_34_35:
 	case MMC_VDD_35_36:
-		if (host->ios.clock <= 26000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
-		else if	(host->ios.clock <= 52000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_26_360;
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-				card->ext_csd.raw_pwr_cl_52_360 :
-				card->ext_csd.raw_pwr_cl_ddr_52_360;
-		else if (host->ios.clock <= 200000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
+				ext_csd->raw_pwr_cl_52_360 :
+				ext_csd->raw_pwr_cl_ddr_52_360;
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -805,6 +801,37 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	return err;
 }
 
+static int mmc_select_powerclass(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	u32 bus_width, ext_csd_bits;
+	int err, ddr;
+
+	/* Power class selection is supported for versions >= 4.0 */
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	/* Power class values are defined only for 4/8 bit bus */
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	if (ddr)
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+	else
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
+
+	err = __mmc_select_powerclass(card, ext_csd_bits);
+	if (err)
+		pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
+			mmc_hostname(host), 1 << bus_width, ddr);
+
+	return err;
+}
+
 /*
  * Selects the desired buswidth and switch to the HS200 mode
  * if bus width set without error
@@ -1166,11 +1193,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
 		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
 				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-		err = mmc_select_powerclass(card, ext_csd_bits);
-		if (err)
-			pr_warning("%s: power class selection to bus width %d"
-				   " failed\n", mmc_hostname(card->host),
-				   1 << bus_width);
 	}
 
 	/*
@@ -1199,12 +1221,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			bus_width = bus_widths[idx];
 			if (bus_width == MMC_BUS_WIDTH_1)
 				ddr = 0; /* no DDR for 1-bit width */
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width);
 
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
@@ -1229,13 +1245,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		}
 
 		if (!err && ddr) {
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d ddr %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width, ddr);
-
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][1],
@@ -1273,6 +1282,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
+	 * Choose the power class with selected bus interface
+	 */
+	mmc_select_powerclass(card);
+
+	/*
 	 * Enable HPI feature (if supported)
 	 */
 	if (card->ext_csd.hpi) {
-- 
1.7.0.4



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

* [PATCH v5 4/5] mmc: rework selection of bus speed mode
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (12 preceding siblings ...)
  2014-04-11 11:34   ` [PATCH v5 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
@ 2014-04-11 11:34   ` Seungwon Jeon
  2014-04-11 11:34   ` [PATCH v5 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
                     ` (14 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-11 11:34 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Current implementation for bus speed mode selection is too
complicated. This patch is to simplify the codes and remove
some duplicate parts.

The following changes are including:
* Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
* Rearranged the mode selection sequence with supported device type
* Adds maximum speed for HS200 mode(hs200_max_dtr)
* Adds field definition for HS_TIMING of EXT_CSD

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/debugfs.c |    2 +-
 drivers/mmc/core/mmc.c     |  431 ++++++++++++++++++++++++--------------------
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/mmc.h    |    4 +
 4 files changed, 238 insertions(+), 200 deletions(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 509229b..1f730db 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -139,7 +139,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 		str = "mmc DDR52";
 		break;
 	case MMC_TIMING_MMC_HS200:
-		str = "mmc high-speed SDR200";
+		str = "mmc HS200";
 		break;
 	default:
 		str = "invalid";
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 480c100..7e9b424 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -242,7 +242,7 @@ static void mmc_select_card_type(struct mmc_card *card)
 	struct mmc_host *host = card->host;
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
-	unsigned int hs_max_dtr = 0;
+	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
@@ -271,17 +271,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 
 	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
 	}
 
 	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
+	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
 }
 
@@ -833,37 +834,46 @@ static int mmc_select_powerclass(struct mmc_card *card)
 }
 
 /*
- * Selects the desired buswidth and switch to the HS200 mode
- * if bus width set without error
+ * Set the bus speed for the selected speed mode.
  */
-static int mmc_select_hs200(struct mmc_card *card)
+static void mmc_set_bus_speed(struct mmc_card *card)
+{
+	unsigned int max_dtr = (unsigned int)-1;
+
+	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+		max_dtr = card->ext_csd.hs200_max_dtr;
+	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
+		max_dtr = card->ext_csd.hs_max_dtr;
+	else if (max_dtr > card->csd.max_dtr)
+		max_dtr = card->csd.max_dtr;
+
+	mmc_set_clock(card->host, max_dtr);
+}
+
+/*
+ * Select the bus width amoung 4-bit and 8-bit(SDR).
+ * If the bus width is changed successfully, return the selected width value.
+ * Zero is returned instead of error value if the wide width is not supported.
+ */
+static int mmc_select_bus_width(struct mmc_card *card)
 {
-	int idx, err = -EINVAL;
-	struct mmc_host *host;
 	static unsigned ext_csd_bits[] = {
-		EXT_CSD_BUS_WIDTH_4,
 		EXT_CSD_BUS_WIDTH_8,
+		EXT_CSD_BUS_WIDTH_4,
 	};
 	static unsigned bus_widths[] = {
-		MMC_BUS_WIDTH_4,
 		MMC_BUS_WIDTH_8,
+		MMC_BUS_WIDTH_4,
 	};
+	struct mmc_host *host = card->host;
+	unsigned idx, bus_width = 0;
+	int err = 0;
 
-	BUG_ON(!card);
-
-	host = card->host;
-
-	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
-
-	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
-
-	/* If fails try again during next card power cycle */
-	if (err)
-		goto err;
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
+	    !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
+		return 0;
 
-	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
 
 	/*
 	 * Unlike SD, MMC cards dont have a configuration register to notify
@@ -871,8 +881,7 @@ static int mmc_select_hs200(struct mmc_card *card)
 	 * 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 >= 0; idx--) {
-
+	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
@@ -887,27 +896,202 @@ static int mmc_select_hs200(struct mmc_card *card)
 		if (err)
 			continue;
 
-		mmc_set_bus_width(card->host, bus_widths[idx]);
+		bus_width = bus_widths[idx];
+		mmc_set_bus_width(host, bus_width);
 
+		/*
+		 * If controller can't handle bus width test,
+		 * compare ext_csd previously read in 1 bit mode
+		 * against ext_csd at new bus width
+		 */
 		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-			err = mmc_compare_ext_csds(card, bus_widths[idx]);
+			err = mmc_compare_ext_csds(card, bus_width);
 		else
-			err = mmc_bus_test(card, bus_widths[idx]);
-		if (!err)
+			err = mmc_bus_test(card, bus_width);
+
+		if (!err) {
+			err = bus_width;
 			break;
+		} else {
+			pr_warn("%s: switch to bus width %d failed\n",
+				mmc_hostname(host), ext_csd_bits[idx]);
+		}
 	}
 
-	/* switch to HS200 mode if bus width set successfully */
+	return err;
+}
+
+/*
+ * Switch to the high-speed mode
+ */
+static int mmc_select_hs(struct mmc_card *card)
+{
+	int err;
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
 	if (!err)
+		mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+
+	return err;
+}
+
+/*
+ * Activate wide bus and DDR if supported.
+ */
+static int mmc_select_hs_ddr(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	u32 bus_width, ext_csd_bits;
+	int err = 0;
+
+	if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52))
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+		EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_BUS_WIDTH,
+			ext_csd_bits,
+			card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width %d ddr failed\n",
+			mmc_hostname(host), 1 << bus_width);
+		return err;
+	}
+
+	/*
+	 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+	 * signaling.
+	 *
+	 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+	 *
+	 * 1.8V vccq at 3.3V core voltage (vcc) is not required
+	 * in the JEDEC spec for DDR.
+	 *
+	 * Do not force change in vccq since we are obviously
+	 * working and no change to vccq is needed.
+	 *
+	 * WARNING: eMMC rules are NOT the same as SD DDR
+	 */
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		err = __mmc_set_signal_voltage(host,
+				MMC_SIGNAL_VOLTAGE_120);
+		if (err)
+			return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
+
+	return err;
+}
+
+/*
+ * For device supporting HS200 mode, the following sequence
+ * should be done before executing the tuning process.
+ * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
+ * 2. switch to HS200 mode
+ * 3. set the clock to > 52Mhz and <=200MHz
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = -EINVAL;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+
+	/* If fails try again during next card power cycle */
+	if (err)
+		goto err;
+
+	/*
+	 * Set the bus width(4 or 8) with host's support and
+	 * switch to HS200 mode if bus width is set successfully.
+	 */
+	err = mmc_select_bus_width(card);
+	if (!IS_ERR_VALUE(err)) {
 		err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				EXT_CSD_HS_TIMING, 2,
-				card->ext_csd.generic_cmd6_time,
-				true, true, true);
+				   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
+				   card->ext_csd.generic_cmd6_time,
+				   true, true, true);
+		if (!err)
+			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+	}
 err:
 	return err;
 }
 
 /*
+ * Activate High Speed or HS200 mode if supported.
+ */
+static int mmc_select_timing(struct mmc_card *card)
+{
+	int err = 0;
+
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
+	     card->ext_csd.hs_max_dtr == 0))
+		goto bus_speed;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+		err = mmc_select_hs200(card);
+	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
+		err = mmc_select_hs(card);
+
+	if (err && err != -EBADMSG)
+		return err;
+
+	if (err) {
+		pr_warn("%s: switch to %s failed\n",
+			mmc_card_hs(card) ? "high-speed" :
+			(mmc_card_hs200(card) ? "hs200" : ""),
+			mmc_hostname(card->host));
+		err = 0;
+	}
+
+bus_speed:
+	/*
+	 * Set the bus speed to the selected bus timing.
+	 * If timing is not selected, backward compatible is the default.
+	 */
+	mmc_set_bus_speed(card);
+	return err;
+}
+
+/*
+ * Execute tuning sequence to seek the proper bus operating
+ * conditions for HS200, which sends CMD21 to the device.
+ */
+static int mmc_hs200_tuning(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	if (host->ops->execute_tuning) {
+		mmc_host_clk_hold(host);
+		err = host->ops->execute_tuning(host,
+				MMC_SEND_TUNING_BLOCK_HS200);
+		mmc_host_clk_release(host);
+
+		if (err)
+			pr_warn("%s: tuning execution failed\n",
+				mmc_hostname(host));
+	}
+
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -917,9 +1101,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	struct mmc_card *oldcard)
 {
 	struct mmc_card *card;
-	int err, ddr = 0;
+	int err;
 	u32 cid[4];
-	unsigned int max_dtr;
 	u32 rocr;
 	u8 *ext_csd = NULL;
 
@@ -1111,173 +1294,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
-	 * Activate high speed (if supported)
-	 */
-	if (card->ext_csd.hs_max_dtr != 0) {
-		err = 0;
-		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-			err = mmc_select_hs200(card);
-		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
-			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					EXT_CSD_HS_TIMING, 1,
-					card->ext_csd.generic_cmd6_time,
-					true, true, true);
-
-		if (err && err != -EBADMSG)
-			goto free_card;
-
-		if (err) {
-			pr_warning("%s: switch to highspeed failed\n",
-			       mmc_hostname(card->host));
-			err = 0;
-		} else {
-			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-				mmc_set_timing(card->host,
-					       MMC_TIMING_MMC_HS200);
-			else
-				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-		}
-	}
-
-	/*
-	 * Compute bus speed.
-	 */
-	max_dtr = (unsigned int)-1;
-
-	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
-		if (max_dtr > card->ext_csd.hs_max_dtr)
-			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_hs(card) && (max_dtr > 52000000))
-			max_dtr = 52000000;
-	} else if (max_dtr > card->csd.max_dtr) {
-		max_dtr = card->csd.max_dtr;
-	}
-
-	mmc_set_clock(host, max_dtr);
-
-	/*
-	 * Indicate DDR mode (if supported).
+	 * Select timing interface
 	 */
-	if (mmc_card_hs(card))
-		ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	err = mmc_select_timing(card);
+	if (err)
+		goto free_card;
 
-	/*
-	 * Indicate HS200 SDR mode (if supported).
-	 */
 	if (mmc_card_hs200(card)) {
-		u32 ext_csd_bits;
-		u32 bus_width = card->host->ios.bus_width;
-
-		/*
-		 * For devices supporting HS200 mode, the bus width has
-		 * to be set before executing the tuning function. If
-		 * set before tuning, then device will respond with CRC
-		 * errors for responses on CMD line. So for HS200 the
-		 * sequence will be
-		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
-		 * 2. switch to HS200 mode
-		 * 3. set the clock to > 52Mhz <=200MHz and
-		 * 4. execute tuning for HS200
-		 */
-		if (card->host->ops->execute_tuning) {
-			mmc_host_clk_hold(card->host);
-			err = card->host->ops->execute_tuning(card->host,
-				MMC_SEND_TUNING_BLOCK_HS200);
-			mmc_host_clk_release(card->host);
-		}
-		if (err) {
-			pr_warning("%s: tuning execution failed\n",
-				   mmc_hostname(card->host));
+		err = mmc_hs200_tuning(card);
+		if (err)
 			goto err;
-		}
-
-		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
-				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-	}
-
-	/*
-	 * Activate wide bus and DDR (if supported).
-	 */
-	if (!mmc_card_hs200(card) &&
-	    (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
-	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
-		static unsigned ext_csd_bits[][2] = {
-			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
-			{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
-			{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
-		};
-		static unsigned bus_widths[] = {
-			MMC_BUS_WIDTH_8,
-			MMC_BUS_WIDTH_4,
-			MMC_BUS_WIDTH_1
-		};
-		unsigned idx, bus_width = 0;
-
-		if (host->caps & MMC_CAP_8_BIT_DATA)
-			idx = 0;
-		else
-			idx = 1;
-		for (; idx < ARRAY_SIZE(bus_widths); idx++) {
-			bus_width = bus_widths[idx];
-			if (bus_width == MMC_BUS_WIDTH_1)
-				ddr = 0; /* no DDR for 1-bit width */
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][0],
-					 card->ext_csd.generic_cmd6_time);
-			if (!err) {
-				mmc_set_bus_width(card->host, bus_width);
-
-				/*
-				 * If controller can't handle bus width test,
-				 * compare ext_csd previously read in 1 bit mode
-				 * against ext_csd at new bus width
-				 */
-				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					err = mmc_compare_ext_csds(card,
-						bus_width);
-				else
-					err = mmc_bus_test(card, bus_width);
-				if (!err)
-					break;
-			}
-		}
-
-		if (!err && ddr) {
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][1],
-					 card->ext_csd.generic_cmd6_time);
-		}
-		if (err) {
-			pr_warning("%s: switch to bus width %d ddr %d "
-				"failed\n", mmc_hostname(card->host),
-				1 << bus_width, ddr);
-			goto free_card;
-		} else if (ddr) {
-			/*
-			 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
-			 * signaling.
-			 *
-			 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
-			 *
-			 * 1.8V vccq at 3.3V core voltage (vcc) is not required
-			 * in the JEDEC spec for DDR.
-			 *
-			 * Do not force change in vccq since we are obviously
-			 * working and no change to vccq is needed.
-			 *
-			 * WARNING: eMMC rules are NOT the same as SD DDR
-			 */
-			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
-				err = __mmc_set_signal_voltage(host,
-					MMC_SIGNAL_VOLTAGE_120);
-				if (err)
-					goto err;
-			}
-			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
-			mmc_set_bus_width(card->host, bus_width);
+	} else if (mmc_card_hs(card)) {
+		/* Select the desired bus width optionally */
+		err = mmc_select_bus_width(card);
+		if (!IS_ERR_VALUE(err)) {
+			err = mmc_select_hs_ddr(card);
+			if (err)
+				goto err;
 		}
 	}
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index b9f194a..c422349 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -63,6 +63,7 @@ struct mmc_ext_csd {
 	unsigned int            power_off_longtime;     /* Units: ms */
 	u8			power_off_notification;	/* state */
 	unsigned int		hs_max_dtr;
+	unsigned int		hs200_max_dtr;
 #define MMC_HIGH_26_MAX_DTR	26000000
 #define MMC_HIGH_52_MAX_DTR	52000000
 #define MMC_HIGH_DDR_MAX_DTR	52000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f734c0c..f429f13 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -377,6 +377,10 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
 #define EXT_CSD_SEC_GB_CL_EN	BIT(4)
-- 
1.7.0.4



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

* [PATCH v5 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (13 preceding siblings ...)
  2014-04-11 11:34   ` [PATCH v5 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
@ 2014-04-11 11:34   ` Seungwon Jeon
  2014-04-11 12:06     ` Ulf Hansson
  2014-04-18 13:36   ` [PATCH v6 0/6] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (13 subsequent siblings)
  28 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-11 11:34 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

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: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/bus.c     |    1 +
 drivers/mmc/core/debugfs.c |    3 +
 drivers/mmc/core/mmc.c     |   98 +++++++++++++++++++++++++++++++++++++++++--
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/host.h   |   14 ++++++
 include/linux/mmc/mmc.h    |    7 +++-
 6 files changed, 118 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index f37e9d6..d2dbf02 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_hs(card) ? "high speed " : ""),
+			mmc_card_hs400(card) ? "HS400 " :
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 1f730db..91eb162 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_MMC_HS200:
 		str = "mmc HS200";
 		break;
+	case MMC_TIMING_MMC_HS400:
+		str = "mmc HS400";
+		break;
 	default:
 		str = "invalid";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 7e9b424..c12e247 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 static void mmc_select_card_type(struct mmc_card *card)
 {
 	struct mmc_host *host = card->host;
-	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
+	u8 card_type = card->ext_csd.raw_card_type;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
@@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
+	if (caps2 & MMC_CAP2_HS400_1_8V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS400_1_2V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
+	}
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
@@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
 		card->ext_csd.raw_pwr_cl_ddr_52_360 =
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
+		card->ext_csd.raw_pwr_cl_ddr_200_360 =
+			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
 	}
 
 	if (card->ext_csd.rev >= 5) {
@@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
 		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
 			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
 		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
-			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
+		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
+
 	if (err)
 		err = -EINVAL;
 
@@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
 				ext_csd->raw_pwr_cl_52_360 :
 				ext_csd->raw_pwr_cl_ddr_52_360;
 		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
-			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
+			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
+				ext_csd->raw_pwr_cl_ddr_200_360 :
+				ext_csd->raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
 {
 	unsigned int max_dtr = (unsigned int)-1;
 
-	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+	if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
+	     max_dtr > card->ext_csd.hs200_max_dtr)
 		max_dtr = card->ext_csd.hs200_max_dtr;
 	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
 		max_dtr = card->ext_csd.hs_max_dtr;
@@ -993,6 +1013,61 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
 	return err;
 }
 
+static int mmc_select_hs400(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	/*
+	 * HS400 mode requires 8-bit bus width
+	 */
+	if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
+	      host->ios.bus_width == MMC_BUS_WIDTH_8))
+		return 0;
+
+	/*
+	 * Before switching to dual data rate operation for HS400,
+	 * it is required to convert from HS200 mode to HS mode.
+	 */
+	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+	mmc_set_bus_speed(card);
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
+	if (err) {
+		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
+			mmc_hostname(host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_DDR_BUS_WIDTH_8,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
+			mmc_hostname(host), err);
+		return err;
+	}
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
+	if (err) {
+		pr_warn("%s: switch to hs400 failed, err:%d\n",
+			 mmc_hostname(host), err);
+		return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+	mmc_set_bus_speed(card);
+
+	return 0;
+}
+
 /*
  * For device supporting HS200 mode, the following sequence
  * should be done before executing the tuning process.
@@ -1070,13 +1145,22 @@ bus_speed:
 
 /*
  * Execute tuning sequence to seek the proper bus operating
- * conditions for HS200, which sends CMD21 to the device.
+ * conditions for HS200 and HS400, which sends CMD21 to the device.
  */
 static int mmc_hs200_tuning(struct mmc_card *card)
 {
 	struct mmc_host *host = card->host;
 	int err = 0;
 
+	/*
+	 * Timing should be adjusted to the HS400 target
+	 * operation frequency for tuning process
+	 */
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
+	    host->ios.bus_width == MMC_BUS_WIDTH_8)
+		if (host->ops->prepare_hs400_tuning)
+			host->ops->prepare_hs400_tuning(host, &host->ios);
+
 	if (host->ops->execute_tuning) {
 		mmc_host_clk_hold(host);
 		err = host->ops->execute_tuning(host,
@@ -1304,6 +1388,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_hs200_tuning(card);
 		if (err)
 			goto err;
+
+		err = mmc_select_hs400(card);
+		if (err)
+			goto err;
 	} else if (mmc_card_hs(card)) {
 		/* Select the desired bus width optionally */
 		err = mmc_select_bus_width(card);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c422349..e68bbeb 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -110,6 +110,7 @@ struct mmc_ext_csd {
 	u8			raw_pwr_cl_200_360;	/* 237 */
 	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
 	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
+	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
 	u8			raw_bkops_status;	/* 246 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 1ee3c10..1a3ced2 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -61,6 +61,7 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_DDR50	7
 #define MMC_TIMING_MMC_DDR52	8
 #define MMC_TIMING_MMC_HS200	9
+#define MMC_TIMING_MMC_HS400	10
 
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
@@ -132,6 +133,9 @@ struct mmc_host_ops {
 
 	/* The tuning command opcode value is different for SD and eMMC cards */
 	int	(*execute_tuning)(struct mmc_host *host, u32 opcode);
+
+	/* Prepare HS400 target operating frequency depending host driver */
+	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
 	int	(*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
 	void	(*hw_reset)(struct mmc_host *host);
 	void	(*card_event)(struct mmc_host *host);
@@ -274,6 +278,10 @@ struct mmc_host {
 #define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
 				 MMC_CAP2_PACKED_WR)
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
+#define MMC_CAP2_HS400_1_8V	(1 << 15)	/* Can support HS400 1.8V */
+#define MMC_CAP2_HS400_1_2V	(1 << 16)	/* Can support HS400 1.2V */
+#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
+				 MMC_CAP2_HS400_1_2V)
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
@@ -493,4 +501,10 @@ static inline bool mmc_card_ddr52(struct mmc_card *card)
 {
 	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
 }
+
+static inline bool mmc_card_hs400(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
+}
+
 #endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f429f13..64ec963 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -325,6 +325,7 @@ struct _mmc_csd {
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
 #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
 #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
 #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
@@ -354,7 +355,6 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
 #define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
@@ -370,6 +370,10 @@ struct _mmc_csd {
 						/* SDR mode @1.2V I/O */
 #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	(1<<6)	/* Card can run at 200MHz DDR, 1.8V */
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
@@ -380,6 +384,7 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
-- 
1.7.0.4



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

* Re: [PATCH v5 2/5] mmc: identify available device type to select
  2014-04-11 11:34   ` [PATCH v5 2/5] mmc: identify available device type to select Seungwon Jeon
@ 2014-04-11 11:47     ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-04-11 11:47 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 11 April 2014 13:34, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Device types which are supported by both host and device
> can be identified when EXT_CSD is read. There is no need to
> check host's capability anymore.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>

Acked-by: Ulf Hansson <ulf.hansson@linaro.org>

> ---
>  drivers/mmc/core/mmc.c   |   72 +++++++++++++++++++++++++---------------------
>  include/linux/mmc/card.h |    2 +-
>  include/linux/mmc/host.h |    6 ----
>  include/linux/mmc/mmc.h  |   12 +++++--
>  4 files changed, 48 insertions(+), 44 deletions(-)
>
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index db9655f..97f1912 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
>         u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>         u32 caps = host->caps, caps2 = host->caps2;
>         unsigned int hs_max_dtr = 0;
> +       unsigned int avail_type = 0;
>
> -       if (card_type & EXT_CSD_CARD_TYPE_26)
> +       if (caps & MMC_CAP_MMC_HIGHSPEED &&
> +           card_type & EXT_CSD_CARD_TYPE_HS_26) {
>                 hs_max_dtr = MMC_HIGH_26_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_HS_26;
> +       }
>
>         if (caps & MMC_CAP_MMC_HIGHSPEED &&
> -                       card_type & EXT_CSD_CARD_TYPE_52)
> +           card_type & EXT_CSD_CARD_TYPE_HS_52) {
>                 hs_max_dtr = MMC_HIGH_52_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_HS_52;
> +       }
>
> -       if ((caps & MMC_CAP_1_8V_DDR &&
> -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
> -           (caps & MMC_CAP_1_2V_DDR &&
> -                       card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
> +       if (caps & MMC_CAP_1_8V_DDR &&
> +           card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
>                 hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
> +       }
> +
> +       if (caps & MMC_CAP_1_2V_DDR &&
> +           card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
> +               hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
> +       }
>
> -       if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
> -           (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> -                       card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
> +       if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
> +           card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
>                 hs_max_dtr = MMC_HS200_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
> +       }
> +
> +       if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
> +           card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
> +               hs_max_dtr = MMC_HS200_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
> +       }
>
>         card->ext_csd.hs_max_dtr = hs_max_dtr;
> -       card->ext_csd.card_type = card_type;
> +       card->mmc_avail_type = avail_type;
>  }
>
>  /*
> @@ -808,12 +826,10 @@ static int mmc_select_hs200(struct mmc_card *card)
>
>         host = card->host;
>
> -       if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
> -                       host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
>                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
>
> -       if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
> -                       host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
> +       if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
>                 err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
>
>         /* If fails try again during next card power cycle */
> @@ -1072,10 +1088,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>          */
>         if (card->ext_csd.hs_max_dtr != 0) {
>                 err = 0;
> -               if (card->ext_csd.hs_max_dtr > 52000000 &&
> -                   host->caps2 & MMC_CAP2_HS200)
> +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>                         err = mmc_select_hs200(card);
> -               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> +               else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>                         err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>                                         EXT_CSD_HS_TIMING, 1,
>                                         card->ext_csd.generic_cmd6_time,
> @@ -1089,13 +1104,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                                mmc_hostname(card->host));
>                         err = 0;
>                 } else {
> -                       if (card->ext_csd.hs_max_dtr > 52000000 &&
> -                           host->caps2 & MMC_CAP2_HS200) {
> +                       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>                                 mmc_set_timing(card->host,
>                                                MMC_TIMING_MMC_HS200);
> -                       } else {
> +                       else
>                                 mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> -                       }
>                 }
>         }
>
> @@ -1118,14 +1131,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>         /*
>          * Indicate DDR mode (if supported).
>          */
> -       if (mmc_card_hs(card)) {
> -               if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
> -                       && (host->caps & MMC_CAP_1_8V_DDR))
> -                               ddr = MMC_1_8V_DDR_MODE;
> -               else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
> -                       && (host->caps & MMC_CAP_1_2V_DDR))
> -                               ddr = MMC_1_2V_DDR_MODE;
> -       }
> +       if (mmc_card_hs(card))
> +               ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
>
>         /*
>          * Indicate HS200 SDR mode (if supported).
> @@ -1145,8 +1152,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                  * 3. set the clock to > 52Mhz <=200MHz and
>                  * 4. execute tuning for HS200
>                  */
> -               if ((host->caps2 & MMC_CAP2_HS200) &&
> -                   card->host->ops->execute_tuning) {
> +               if (card->host->ops->execute_tuning) {
>                         mmc_host_clk_hold(card->host);
>                         err = card->host->ops->execute_tuning(card->host,
>                                 MMC_SEND_TUNING_BLOCK_HS200);
> @@ -1255,7 +1261,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                          *
>                          * WARNING: eMMC rules are NOT the same as SD DDR
>                          */
> -                       if (ddr == MMC_1_2V_DDR_MODE) {
> +                       if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
>                                 err = __mmc_set_signal_voltage(host,
>                                         MMC_SIGNAL_VOLTAGE_120);
>                                 if (err)
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 5473133..b9f194a 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -68,7 +68,6 @@ struct mmc_ext_csd {
>  #define MMC_HIGH_DDR_MAX_DTR   52000000
>  #define MMC_HS200_MAX_DTR      200000000
>         unsigned int            sectors;
> -       unsigned int            card_type;
>         unsigned int            hc_erase_size;          /* In sectors */
>         unsigned int            hc_erase_timeout;       /* In milliseconds */
>         unsigned int            sec_trim_mult;  /* Secure trim multiplier  */
> @@ -298,6 +297,7 @@ struct mmc_card {
>         struct sdio_func_tuple  *tuples;        /* unknown common tuples */
>
>         unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
> +       unsigned int            mmc_avail_type; /* supported device type by both host and card */
>
>         struct dentry           *debugfs_root;
>         struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 2f263ae..1ee3c10 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -62,12 +62,6 @@ struct mmc_ios {
>  #define MMC_TIMING_MMC_DDR52   8
>  #define MMC_TIMING_MMC_HS200   9
>
> -#define MMC_SDR_MODE           0
> -#define MMC_1_2V_DDR_MODE      1
> -#define MMC_1_8V_DDR_MODE      2
> -#define MMC_1_2V_SDR_MODE      3
> -#define MMC_1_8V_SDR_MODE      4
> -
>         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
>
>  #define MMC_SIGNAL_VOLTAGE_330 0
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 50bcde3..f734c0c 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -354,18 +354,22 @@ struct _mmc_csd {
>  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
>  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
>
> -#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_MASK 0x3F    /* Mask out reserved bits */
> +#define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
> +#define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
> +#define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
> +                                EXT_CSD_CARD_TYPE_HS_52)
>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
>                                              /* DDR mode @1.8V or 3V I/O */
>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
>                                              /* DDR mode @1.2V I/O */
>  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
>                                         | EXT_CSD_CARD_TYPE_DDR_1_2V)
> -#define EXT_CSD_CARD_TYPE_SDR_1_8V     (1<<4)  /* Card can run at 200MHz */
> -#define EXT_CSD_CARD_TYPE_SDR_1_2V     (1<<5)  /* Card can run at 200MHz */
> +#define EXT_CSD_CARD_TYPE_HS200_1_8V   (1<<4)  /* Card can run at 200MHz */
> +#define EXT_CSD_CARD_TYPE_HS200_1_2V   (1<<5)  /* Card can run at 200MHz */
>                                                 /* SDR mode @1.2V I/O */
> +#define EXT_CSD_CARD_TYPE_HS200                (EXT_CSD_CARD_TYPE_HS200_1_8V | \
> +                                        EXT_CSD_CARD_TYPE_HS200_1_2V)
>
>  #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
> --
> 1.7.0.4
>
>

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

* Re: [PATCH v5 5/5] mmc: add support for HS400 mode of eMMC5.0
  2014-04-11 11:34   ` [PATCH v5 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
@ 2014-04-11 12:06     ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-04-11 12:06 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 11 April 2014 13:34, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> 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: Seungwon Jeon <tgih.jun@samsung.com>
> Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>

Acked-by: Ulf Hansson <ulf.hansson@linaro.org>

> ---
>  drivers/mmc/core/bus.c     |    1 +
>  drivers/mmc/core/debugfs.c |    3 +
>  drivers/mmc/core/mmc.c     |   98 +++++++++++++++++++++++++++++++++++++++++--
>  include/linux/mmc/card.h   |    1 +
>  include/linux/mmc/host.h   |   14 ++++++
>  include/linux/mmc/mmc.h    |    7 +++-
>  6 files changed, 118 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index f37e9d6..d2dbf02 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
>                         mmc_hostname(card->host),
>                         mmc_card_uhs(card) ? "ultra high speed " :
>                         (mmc_card_hs(card) ? "high speed " : ""),
> +                       mmc_card_hs400(card) ? "HS400 " :
>                         (mmc_card_hs200(card) ? "HS200 " : ""),
>                         mmc_card_ddr52(card) ? "DDR " : "",
>                         uhs_bus_speed_mode, type, card->rca);
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index 1f730db..91eb162 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>         case MMC_TIMING_MMC_HS200:
>                 str = "mmc HS200";
>                 break;
> +       case MMC_TIMING_MMC_HS400:
> +               str = "mmc HS400";
> +               break;
>         default:
>                 str = "invalid";
>                 break;
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 7e9b424..c12e247 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
>  static void mmc_select_card_type(struct mmc_card *card)
>  {
>         struct mmc_host *host = card->host;
> -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
> +       u8 card_type = card->ext_csd.raw_card_type;
>         u32 caps = host->caps, caps2 = host->caps2;
>         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>         unsigned int avail_type = 0;
> @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
>                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>         }
>
> +       if (caps2 & MMC_CAP2_HS400_1_8V &&
> +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
> +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
> +       }
> +
> +       if (caps2 & MMC_CAP2_HS400_1_2V &&
> +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
> +               hs200_max_dtr = MMC_HS200_MAX_DTR;
> +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
> +       }
> +
>         card->ext_csd.hs_max_dtr = hs_max_dtr;
>         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>         card->mmc_avail_type = avail_type;
> @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
>                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
>                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
> +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
> +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
>         }
>
>         if (card->ext_csd.rev >= 5) {
> @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
>                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
>                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
>                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
> -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
> +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
> +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
> +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
> +
>         if (err)
>                 err = -EINVAL;
>
> @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
>                                 ext_csd->raw_pwr_cl_52_360 :
>                                 ext_csd->raw_pwr_cl_ddr_52_360;
>                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
> -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
> +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
> +                               ext_csd->raw_pwr_cl_ddr_200_360 :
> +                               ext_csd->raw_pwr_cl_200_360;
>                 break;
>         default:
>                 pr_warning("%s: Voltage range not supported "
> @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
>  {
>         unsigned int max_dtr = (unsigned int)-1;
>
> -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
> +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
> +            max_dtr > card->ext_csd.hs200_max_dtr)
>                 max_dtr = card->ext_csd.hs200_max_dtr;
>         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
>                 max_dtr = card->ext_csd.hs_max_dtr;
> @@ -993,6 +1013,61 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
>         return err;
>  }
>
> +static int mmc_select_hs400(struct mmc_card *card)
> +{
> +       struct mmc_host *host = card->host;
> +       int err = 0;
> +
> +       /*
> +        * HS400 mode requires 8-bit bus width
> +        */
> +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
> +             host->ios.bus_width == MMC_BUS_WIDTH_8))
> +               return 0;
> +
> +       /*
> +        * Before switching to dual data rate operation for HS400,
> +        * it is required to convert from HS200 mode to HS mode.
> +        */
> +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> +       mmc_set_bus_speed(card);
> +
> +       err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                          EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
> +                          card->ext_csd.generic_cmd6_time,
> +                          true, true, true);
> +       if (err) {
> +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
> +                       mmc_hostname(host), err);
> +               return err;
> +       }
> +
> +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                        EXT_CSD_BUS_WIDTH,
> +                        EXT_CSD_DDR_BUS_WIDTH_8,
> +                        card->ext_csd.generic_cmd6_time);
> +       if (err) {
> +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
> +                       mmc_hostname(host), err);
> +               return err;
> +       }
> +
> +       err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                          EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
> +                          card->ext_csd.generic_cmd6_time,
> +                          true, true, true);
> +       if (err) {
> +               pr_warn("%s: switch to hs400 failed, err:%d\n",
> +                        mmc_hostname(host), err);
> +               return err;
> +       }
> +
> +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> +       mmc_set_bus_speed(card);
> +
> +       return 0;
> +}
> +
>  /*
>   * For device supporting HS200 mode, the following sequence
>   * should be done before executing the tuning process.
> @@ -1070,13 +1145,22 @@ bus_speed:
>
>  /*
>   * Execute tuning sequence to seek the proper bus operating
> - * conditions for HS200, which sends CMD21 to the device.
> + * conditions for HS200 and HS400, which sends CMD21 to the device.
>   */
>  static int mmc_hs200_tuning(struct mmc_card *card)
>  {
>         struct mmc_host *host = card->host;
>         int err = 0;
>
> +       /*
> +        * Timing should be adjusted to the HS400 target
> +        * operation frequency for tuning process
> +        */
> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
> +           host->ios.bus_width == MMC_BUS_WIDTH_8)
> +               if (host->ops->prepare_hs400_tuning)
> +                       host->ops->prepare_hs400_tuning(host, &host->ios);
> +
>         if (host->ops->execute_tuning) {
>                 mmc_host_clk_hold(host);
>                 err = host->ops->execute_tuning(host,
> @@ -1304,6 +1388,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                 err = mmc_hs200_tuning(card);
>                 if (err)
>                         goto err;
> +
> +               err = mmc_select_hs400(card);
> +               if (err)
> +                       goto err;
>         } else if (mmc_card_hs(card)) {
>                 /* Select the desired bus width optionally */
>                 err = mmc_select_bus_width(card);
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index c422349..e68bbeb 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -110,6 +110,7 @@ struct mmc_ext_csd {
>         u8                      raw_pwr_cl_200_360;     /* 237 */
>         u8                      raw_pwr_cl_ddr_52_195;  /* 238 */
>         u8                      raw_pwr_cl_ddr_52_360;  /* 239 */
> +       u8                      raw_pwr_cl_ddr_200_360; /* 253 */
>         u8                      raw_bkops_status;       /* 246 */
>         u8                      raw_sectors[4];         /* 212 - 4 bytes */
>
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 1ee3c10..1a3ced2 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -61,6 +61,7 @@ struct mmc_ios {
>  #define MMC_TIMING_UHS_DDR50   7
>  #define MMC_TIMING_MMC_DDR52   8
>  #define MMC_TIMING_MMC_HS200   9
> +#define MMC_TIMING_MMC_HS400   10
>
>         unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
>
> @@ -132,6 +133,9 @@ struct mmc_host_ops {
>
>         /* The tuning command opcode value is different for SD and eMMC cards */
>         int     (*execute_tuning)(struct mmc_host *host, u32 opcode);
> +
> +       /* Prepare HS400 target operating frequency depending host driver */
> +       int     (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
>         int     (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
>         void    (*hw_reset)(struct mmc_host *host);
>         void    (*card_event)(struct mmc_host *host);
> @@ -274,6 +278,10 @@ struct mmc_host {
>  #define MMC_CAP2_PACKED_CMD    (MMC_CAP2_PACKED_RD | \
>                                  MMC_CAP2_PACKED_WR)
>  #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)  /* Don't power up before scan */
> +#define MMC_CAP2_HS400_1_8V    (1 << 15)       /* Can support HS400 1.8V */
> +#define MMC_CAP2_HS400_1_2V    (1 << 16)       /* Can support HS400 1.2V */
> +#define MMC_CAP2_HS400         (MMC_CAP2_HS400_1_8V | \
> +                                MMC_CAP2_HS400_1_2V)
>
>         mmc_pm_flag_t           pm_caps;        /* supported pm features */
>
> @@ -493,4 +501,10 @@ static inline bool mmc_card_ddr52(struct mmc_card *card)
>  {
>         return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
>  }
> +
> +static inline bool mmc_card_hs400(struct mmc_card *card)
> +{
> +       return card->host->ios.timing == MMC_TIMING_MMC_HS400;
> +}
> +
>  #endif /* LINUX_MMC_HOST_H */
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index f429f13..64ec963 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -325,6 +325,7 @@ struct _mmc_csd {
>  #define EXT_CSD_POWER_OFF_LONG_TIME    247     /* RO */
>  #define EXT_CSD_GENERIC_CMD6_TIME      248     /* RO */
>  #define EXT_CSD_CACHE_SIZE             249     /* RO, 4 bytes */
> +#define EXT_CSD_PWR_CL_DDR_200_360     253     /* RO */
>  #define EXT_CSD_TAG_UNIT_SIZE          498     /* RO */
>  #define EXT_CSD_DATA_TAG_SUPPORT       499     /* RO */
>  #define EXT_CSD_MAX_PACKED_WRITES      500     /* RO */
> @@ -354,7 +355,6 @@ struct _mmc_csd {
>  #define EXT_CSD_CMD_SET_SECURE         (1<<1)
>  #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
>
> -#define EXT_CSD_CARD_TYPE_MASK 0x3F    /* Mask out reserved bits */
>  #define EXT_CSD_CARD_TYPE_HS_26        (1<<0)  /* Card can run at 26MHz */
>  #define EXT_CSD_CARD_TYPE_HS_52        (1<<1)  /* Card can run at 52MHz */
>  #define EXT_CSD_CARD_TYPE_HS   (EXT_CSD_CARD_TYPE_HS_26 | \
> @@ -370,6 +370,10 @@ struct _mmc_csd {
>                                                 /* SDR mode @1.2V I/O */
>  #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   (1<<6)  /* Card can run at 200MHz DDR, 1.8V */
> +#define EXT_CSD_CARD_TYPE_HS400_1_2V   (1<<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_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
> @@ -380,6 +384,7 @@ struct _mmc_csd {
>  #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_SEC_ER_EN      BIT(0)
>  #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
> --
> 1.7.0.4
>
>

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

* [PATCH v6 0/6] update selection of bus speed mode for eMMC
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (14 preceding siblings ...)
  2014-04-11 11:34   ` [PATCH v5 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
@ 2014-04-18 13:36   ` Seungwon Jeon
  2014-04-20  7:18     ` Ulf Hansson
  2014-04-18 13:36   ` [PATCH v6 1/6] mmc: drop the speed mode of card's state Seungwon Jeon
                     ` (12 subsequent siblings)
  28 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-18 13:36 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

This series contains the change for selection of bus speed mode.
Previous implementation is complicated and some sequence is duplicated.
And specially, HS400 mode eMMC5.0 is introduced this time.
This patch-set has been tested in Exynos SoC.

Note:
This patch-set depends on "[PATCH RESEND v3 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC".

Changes in v6:
	(6/6) Included "mmc: core: add DT bindings for eMMC HS400 1.8/1.2V" into this patch-set
	(5/6) Changed return type of prepare_hs400_tuning callback(int -> void)
Changes in v5:
	(5/5) Added callback operation for HS400 target operation frequency
	       instead of specific timing identifier.
	(2/5) Removed using union declaration.

Changes in v4:
	(5/5)Reverting to HS mode is included in mmc_select_hs400() using __mmc_switch().

Changes in v3:
 	Removed the function to check DDR type(mmc_snoop_ddr).
 	Rebased with the latest branch.

Seungwon Jeon (6):
  mmc: drop the speed mode of card's state
  mmc: identify available device type to select
  mmc: step power class after final selection of bus mode
  mmc: rework selection of bus speed mode
  mmc: add support for HS400 mode of eMMC5.0
  mmc: add DT bindings for eMMC HS400 1.8/1.2V

 Documentation/devicetree/bindings/mmc/mmc.txt |    2 +
 drivers/mmc/core/bus.c                        |    9 +-
 drivers/mmc/core/core.c                       |    3 +-
 drivers/mmc/core/debugfs.c                    |    5 +-
 drivers/mmc/core/host.c                       |    4 +
 drivers/mmc/core/mmc.c                        |  666 +++++++++++++++----------
 drivers/mmc/core/sd.c                         |   16 +-
 drivers/mmc/core/sd.h                         |    1 -
 drivers/mmc/core/sdio.c                       |    8 +-
 include/linux/mmc/card.h                      |   27 +-
 include/linux/mmc/host.h                      |   43 ++-
 include/linux/mmc/mmc.h                       |   23 +-
 12 files changed, 486 insertions(+), 321 deletions(-)

Thanks,
sw-j


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

* [PATCH v6 1/6] mmc: drop the speed mode of card's state
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (15 preceding siblings ...)
  2014-04-18 13:36   ` [PATCH v6 0/6] update selection of bus speed mode for eMMC Seungwon Jeon
@ 2014-04-18 13:36   ` Seungwon Jeon
  2014-04-18 13:36   ` [PATCH v6 2/6] mmc: identify available device type to select Seungwon Jeon
                     ` (11 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-18 13:36 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Timing mode identifier has same role and can take the place
of speed mode. This change removes all related speed mode.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
 drivers/mmc/core/bus.c   |    8 ++++----
 drivers/mmc/core/core.c  |    3 +--
 drivers/mmc/core/mmc.c   |   11 +++--------
 drivers/mmc/core/sd.c    |   16 +++-------------
 drivers/mmc/core/sd.h    |    1 -
 drivers/mmc/core/sdio.c  |    8 ++------
 include/linux/mmc/card.h |   23 ++++++-----------------
 include/linux/mmc/host.h |   23 +++++++++++++++++++++++
 8 files changed, 42 insertions(+), 51 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 8246448..f37e9d6 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -341,16 +341,16 @@ int mmc_add_card(struct mmc_card *card)
 	if (mmc_host_is_spi(card->host)) {
 		pr_info("%s: new %s%s%s card on SPI\n",
 			mmc_hostname(card->host),
-			mmc_card_highspeed(card) ? "high speed " : "",
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_hs(card) ? "high speed " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			type);
 	} else {
 		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
-			(mmc_card_highspeed(card) ? "high speed " : ""),
+			(mmc_card_hs(card) ? "high speed " : ""),
 			(mmc_card_hs200(card) ? "HS200 " : ""),
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
 	}
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index acbc3f2..aa9f679 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2183,7 +2183,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
 	struct mmc_command cmd = {0};
 
-	if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+	if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
 		return 0;
 
 	cmd.opcode = MMC_SET_BLOCKLEN;
@@ -2263,7 +2263,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
 		}
 	}
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
 	if (mmc_host_is_spi(host)) {
 		host->ios.chip_select = MMC_CS_HIGH;
 		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e22d851..db9655f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1091,11 +1091,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		} else {
 			if (card->ext_csd.hs_max_dtr > 52000000 &&
 			    host->caps2 & MMC_CAP2_HS200) {
-				mmc_card_set_hs200(card);
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
 			} else {
-				mmc_card_set_highspeed(card);
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
 			}
 		}
@@ -1106,10 +1104,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
+	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
 		if (max_dtr > card->ext_csd.hs_max_dtr)
 			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_highspeed(card) && (max_dtr > 52000000))
+		if (mmc_card_hs(card) && (max_dtr > 52000000))
 			max_dtr = 52000000;
 	} else if (max_dtr > card->csd.max_dtr) {
 		max_dtr = card->csd.max_dtr;
@@ -1120,7 +1118,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
 			&& (host->caps & MMC_CAP_1_8V_DDR))
 				ddr = MMC_1_8V_DDR_MODE;
@@ -1263,7 +1261,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 				if (err)
 					goto err;
 			}
-			mmc_card_set_ddr_mode(card);
 			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
 			mmc_set_bus_width(card->host, bus_width);
 		}
@@ -1507,7 +1504,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 		err = mmc_sleep(host);
 	else if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 
 	if (!err) {
 		mmc_power_off(host);
@@ -1637,7 +1633,6 @@ static int mmc_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 	mmc_claim_host(host);
 	ret = mmc_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 2dd359d..9fc5b31 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -895,7 +895,7 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if (max_dtr > card->sw_caps.hs_max_dtr)
 			max_dtr = card->sw_caps.hs_max_dtr;
 	} else if (max_dtr > card->csd.max_dtr) {
@@ -905,12 +905,6 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 	return max_dtr;
 }
 
-void mmc_sd_go_highspeed(struct mmc_card *card)
-{
-	mmc_card_set_highspeed(card);
-	mmc_set_timing(card->host, MMC_TIMING_SD_HS);
-}
-
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -985,16 +979,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_sd_init_uhs_card(card);
 		if (err)
 			goto free_card;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Attempt to change to high-speed (if supported)
 		 */
 		err = mmc_sd_switch_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto free_card;
 
@@ -1089,7 +1080,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
 
 	if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
+
 	if (!err) {
 		mmc_power_off(host);
 		mmc_card_set_suspended(host->card);
@@ -1198,7 +1189,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
 	ret = mmc_sd_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
index 4b34b24..aab824a 100644
--- a/drivers/mmc/core/sd.h
+++ b/drivers/mmc/core/sd.h
@@ -12,6 +12,5 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 	bool reinit);
 unsigned mmc_sd_get_max_clock(struct mmc_card *card);
 int mmc_sd_switch_hs(struct mmc_card *card);
-void mmc_sd_go_highspeed(struct mmc_card *card);
 
 #endif
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4d721c6..ef57d2d 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		/*
 		 * The SDIO specification doesn't mention how
 		 * the CIS transfer speed register relates to
@@ -733,7 +733,6 @@ try_again:
 		mmc_set_clock(host, card->cis.max_dtr);
 
 		if (card->cccr.high_speed) {
-			mmc_card_set_highspeed(card);
 			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		}
 
@@ -792,16 +791,13 @@ try_again:
 		err = mmc_sdio_init_uhs_card(card);
 		if (err)
 			goto remove;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Switch to high-speed (if supported).
 		 */
 		err = sdio_enable_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto remove;
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index b730272..5473133 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -194,6 +194,7 @@ struct sdio_cis {
 };
 
 struct mmc_host;
+struct mmc_ios;
 struct sdio_func;
 struct sdio_func_tuple;
 
@@ -250,15 +251,11 @@ struct mmc_card {
 	unsigned int		state;		/* (our) card state */
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
 #define MMC_STATE_READONLY	(1<<1)		/* card is read-only */
-#define MMC_STATE_HIGHSPEED	(1<<2)		/* card is in high speed mode */
-#define MMC_STATE_BLOCKADDR	(1<<3)		/* card uses block-addressing */
-#define MMC_STATE_HIGHSPEED_DDR (1<<4)		/* card is in high speed mode */
-#define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra high speed mode */
-#define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
-#define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
-#define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
-#define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
-#define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
+#define MMC_STATE_BLOCKADDR	(1<<2)		/* card uses block-addressing */
+#define MMC_CARD_SDXC		(1<<3)		/* card is SDXC */
+#define MMC_CARD_REMOVED	(1<<4)		/* card has been removed */
+#define MMC_STATE_DOING_BKOPS	(1<<5)		/* card is doing BKOPS */
+#define MMC_STATE_SUSPENDED	(1<<6)		/* card is suspended */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -418,11 +415,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
-#define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
-#define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
-#define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
@@ -430,11 +423,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
-#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
-#define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
-#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_doing_bkops(c)	((c)->state |= MMC_STATE_DOING_BKOPS)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 3535420..2f263ae 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -17,6 +17,7 @@
 #include <linux/fault-inject.h>
 
 #include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -476,4 +477,26 @@ static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
 	return host->ios.clock;
 }
 #endif
+
+static inline int mmc_card_hs(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_SD_HS ||
+		card->host->ios.timing == MMC_TIMING_MMC_HS;
+}
+
+static inline int mmc_card_uhs(struct mmc_card *card)
+{
+	return card->host->ios.timing >= MMC_TIMING_UHS_SDR12 &&
+		card->host->ios.timing <= MMC_TIMING_UHS_DDR50;
+}
+
+static inline bool mmc_card_hs200(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_HS200;
+}
+
+static inline bool mmc_card_ddr52(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
+}
 #endif /* LINUX_MMC_HOST_H */
-- 
1.7.0.4



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

* [PATCH v6 2/6] mmc: identify available device type to select
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (16 preceding siblings ...)
  2014-04-18 13:36   ` [PATCH v6 1/6] mmc: drop the speed mode of card's state Seungwon Jeon
@ 2014-04-18 13:36   ` Seungwon Jeon
  2014-04-18 13:36   ` [PATCH v6 3/6] mmc: step power class after final selection of bus mode Seungwon Jeon
                     ` (10 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-18 13:36 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Device types which are supported by both host and device
can be identified when EXT_CSD is read. There is no need to
check host's capability anymore.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/mmc.c   |   72 +++++++++++++++++++++++++---------------------
 include/linux/mmc/card.h |    2 +-
 include/linux/mmc/host.h |    6 ----
 include/linux/mmc/mmc.h  |   12 +++++--
 4 files changed, 48 insertions(+), 44 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index db9655f..97f1912 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0;
+	unsigned int avail_type = 0;
 
-	if (card_type & EXT_CSD_CARD_TYPE_26)
+	if (caps & MMC_CAP_MMC_HIGHSPEED &&
+	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
 		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
+	}
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
-			card_type & EXT_CSD_CARD_TYPE_52)
+	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
 		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
+	}
 
-	if ((caps & MMC_CAP_1_8V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
-	    (caps & MMC_CAP_1_2V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
+	if (caps & MMC_CAP_1_8V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
 		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
+	}
+
+	if (caps & MMC_CAP_1_2V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
+	}
 
-	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
-	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
+	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
 		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
+		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
+	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
-	card->ext_csd.card_type = card_type;
+	card->mmc_avail_type = avail_type;
 }
 
 /*
@@ -808,12 +826,10 @@ static int mmc_select_hs200(struct mmc_card *card)
 
 	host = card->host;
 
-	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
-			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
 
-	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
-			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
 
 	/* If fails try again during next card power cycle */
@@ -1072,10 +1088,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	if (card->ext_csd.hs_max_dtr != 0) {
 		err = 0;
-		if (card->ext_csd.hs_max_dtr > 52000000 &&
-		    host->caps2 & MMC_CAP2_HS200)
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 			err = mmc_select_hs200(card);
-		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
+		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
 			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					EXT_CSD_HS_TIMING, 1,
 					card->ext_csd.generic_cmd6_time,
@@ -1089,13 +1104,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			       mmc_hostname(card->host));
 			err = 0;
 		} else {
-			if (card->ext_csd.hs_max_dtr > 52000000 &&
-			    host->caps2 & MMC_CAP2_HS200) {
+			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
-			} else {
+			else
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-			}
 		}
 	}
 
@@ -1118,14 +1131,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_hs(card)) {
-		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-			&& (host->caps & MMC_CAP_1_8V_DDR))
-				ddr = MMC_1_8V_DDR_MODE;
-		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-			&& (host->caps & MMC_CAP_1_2V_DDR))
-				ddr = MMC_1_2V_DDR_MODE;
-	}
+	if (mmc_card_hs(card))
+		ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
 
 	/*
 	 * Indicate HS200 SDR mode (if supported).
@@ -1145,8 +1152,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		 * 3. set the clock to > 52Mhz <=200MHz and
 		 * 4. execute tuning for HS200
 		 */
-		if ((host->caps2 & MMC_CAP2_HS200) &&
-		    card->host->ops->execute_tuning) {
+		if (card->host->ops->execute_tuning) {
 			mmc_host_clk_hold(card->host);
 			err = card->host->ops->execute_tuning(card->host,
 				MMC_SEND_TUNING_BLOCK_HS200);
@@ -1255,7 +1261,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			 *
 			 * WARNING: eMMC rules are NOT the same as SD DDR
 			 */
-			if (ddr == MMC_1_2V_DDR_MODE) {
+			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
 				err = __mmc_set_signal_voltage(host,
 					MMC_SIGNAL_VOLTAGE_120);
 				if (err)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 5473133..b9f194a 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -68,7 +68,6 @@ struct mmc_ext_csd {
 #define MMC_HIGH_DDR_MAX_DTR	52000000
 #define MMC_HS200_MAX_DTR	200000000
 	unsigned int		sectors;
-	unsigned int		card_type;
 	unsigned int		hc_erase_size;		/* In sectors */
 	unsigned int		hc_erase_timeout;	/* In milliseconds */
 	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
@@ -298,6 +297,7 @@ struct mmc_card {
 	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
 
 	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+	unsigned int		mmc_avail_type;	/* supported device type by both host and card */
 
 	struct dentry		*debugfs_root;
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 2f263ae..1ee3c10 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -62,12 +62,6 @@ struct mmc_ios {
 #define MMC_TIMING_MMC_DDR52	8
 #define MMC_TIMING_MMC_HS200	9
 
-#define MMC_SDR_MODE		0
-#define MMC_1_2V_DDR_MODE	1
-#define MMC_1_8V_DDR_MODE	2
-#define MMC_1_2V_SDR_MODE	3
-#define MMC_1_8V_SDR_MODE	4
-
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
 #define MMC_SIGNAL_VOLTAGE_330	0
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 50bcde3..f734c0c 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -354,18 +354,22 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#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_MASK	0x3F	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
+				 EXT_CSD_CARD_TYPE_HS_52)
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
 					     /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
 					     /* DDR mode @1.2V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
 					| EXT_CSD_CARD_TYPE_DDR_1_2V)
-#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
-#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_8V	(1<<4)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_2V	(1<<5)	/* Card can run at 200MHz */
 						/* SDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS200_1_2V)
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
-- 
1.7.0.4



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

* [PATCH v6 3/6] mmc: step power class after final selection of bus mode
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (17 preceding siblings ...)
  2014-04-18 13:36   ` [PATCH v6 2/6] mmc: identify available device type to select Seungwon Jeon
@ 2014-04-18 13:36   ` Seungwon Jeon
  2014-04-18 13:36   ` [PATCH v6 4/6] mmc: rework selection of bus speed mode Seungwon Jeon
                     ` (9 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-18 13:36 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Power class is changed once only after selection of bus modes
including speed and bus-width finishes finally.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/mmc.c |   96 +++++++++++++++++++++++++++--------------------
 1 files changed, 55 insertions(+), 41 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 97f1912..480c100 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -732,17 +732,13 @@ static struct device_type mmc_type = {
  * extended CSD register, select it by executing the
  * mmc_switch command.
  */
-static int mmc_select_powerclass(struct mmc_card *card,
-		unsigned int bus_width)
+static int __mmc_select_powerclass(struct mmc_card *card,
+				   unsigned int bus_width)
 {
-	int err = 0;
+	struct mmc_host *host = card->host;
+	struct mmc_ext_csd *ext_csd = &card->ext_csd;
 	unsigned int pwrclass_val = 0;
-	struct mmc_host *host;
-
-	BUG_ON(!card);
-
-	host = card->host;
-	BUG_ON(!host);
+	int err = 0;
 
 	/* Power class selection is supported for versions >= 4.0 */
 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
@@ -754,14 +750,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
 
 	switch (1 << host->ios.vdd) {
 	case MMC_VDD_165_195:
-		if (host->ios.clock <= 26000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
-		else if	(host->ios.clock <= 52000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_26_195;
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-				card->ext_csd.raw_pwr_cl_52_195 :
-				card->ext_csd.raw_pwr_cl_ddr_52_195;
-		else if (host->ios.clock <= 200000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
+				ext_csd->raw_pwr_cl_52_195 :
+				ext_csd->raw_pwr_cl_ddr_52_195;
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_200_195;
 		break;
 	case MMC_VDD_27_28:
 	case MMC_VDD_28_29:
@@ -772,14 +768,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	case MMC_VDD_33_34:
 	case MMC_VDD_34_35:
 	case MMC_VDD_35_36:
-		if (host->ios.clock <= 26000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
-		else if	(host->ios.clock <= 52000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_26_360;
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-				card->ext_csd.raw_pwr_cl_52_360 :
-				card->ext_csd.raw_pwr_cl_ddr_52_360;
-		else if (host->ios.clock <= 200000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
+				ext_csd->raw_pwr_cl_52_360 :
+				ext_csd->raw_pwr_cl_ddr_52_360;
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -805,6 +801,37 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	return err;
 }
 
+static int mmc_select_powerclass(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	u32 bus_width, ext_csd_bits;
+	int err, ddr;
+
+	/* Power class selection is supported for versions >= 4.0 */
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	/* Power class values are defined only for 4/8 bit bus */
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	if (ddr)
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+	else
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
+
+	err = __mmc_select_powerclass(card, ext_csd_bits);
+	if (err)
+		pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
+			mmc_hostname(host), 1 << bus_width, ddr);
+
+	return err;
+}
+
 /*
  * Selects the desired buswidth and switch to the HS200 mode
  * if bus width set without error
@@ -1166,11 +1193,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
 		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
 				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-		err = mmc_select_powerclass(card, ext_csd_bits);
-		if (err)
-			pr_warning("%s: power class selection to bus width %d"
-				   " failed\n", mmc_hostname(card->host),
-				   1 << bus_width);
 	}
 
 	/*
@@ -1199,12 +1221,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			bus_width = bus_widths[idx];
 			if (bus_width == MMC_BUS_WIDTH_1)
 				ddr = 0; /* no DDR for 1-bit width */
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width);
 
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
@@ -1229,13 +1245,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		}
 
 		if (!err && ddr) {
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d ddr %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width, ddr);
-
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][1],
@@ -1273,6 +1282,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
+	 * Choose the power class with selected bus interface
+	 */
+	mmc_select_powerclass(card);
+
+	/*
 	 * Enable HPI feature (if supported)
 	 */
 	if (card->ext_csd.hpi) {
-- 
1.7.0.4



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

* [PATCH v6 4/6] mmc: rework selection of bus speed mode
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (18 preceding siblings ...)
  2014-04-18 13:36   ` [PATCH v6 3/6] mmc: step power class after final selection of bus mode Seungwon Jeon
@ 2014-04-18 13:36   ` Seungwon Jeon
  2014-04-18 13:37   ` [PATCH v6 5/6] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
                     ` (8 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-18 13:36 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Current implementation for bus speed mode selection is too
complicated. This patch is to simplify the codes and remove
some duplicate parts.

The following changes are including:
* Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
* Rearranged the mode selection sequence with supported device type
* Adds maximum speed for HS200 mode(hs200_max_dtr)
* Adds field definition for HS_TIMING of EXT_CSD

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/debugfs.c |    2 +-
 drivers/mmc/core/mmc.c     |  431 ++++++++++++++++++++++++--------------------
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/mmc.h    |    4 +
 4 files changed, 238 insertions(+), 200 deletions(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 509229b..1f730db 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -139,7 +139,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 		str = "mmc DDR52";
 		break;
 	case MMC_TIMING_MMC_HS200:
-		str = "mmc high-speed SDR200";
+		str = "mmc HS200";
 		break;
 	default:
 		str = "invalid";
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 480c100..7e9b424 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -242,7 +242,7 @@ static void mmc_select_card_type(struct mmc_card *card)
 	struct mmc_host *host = card->host;
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
-	unsigned int hs_max_dtr = 0;
+	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
@@ -271,17 +271,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 
 	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
 	}
 
 	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
+	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
 }
 
@@ -833,37 +834,46 @@ static int mmc_select_powerclass(struct mmc_card *card)
 }
 
 /*
- * Selects the desired buswidth and switch to the HS200 mode
- * if bus width set without error
+ * Set the bus speed for the selected speed mode.
  */
-static int mmc_select_hs200(struct mmc_card *card)
+static void mmc_set_bus_speed(struct mmc_card *card)
+{
+	unsigned int max_dtr = (unsigned int)-1;
+
+	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+		max_dtr = card->ext_csd.hs200_max_dtr;
+	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
+		max_dtr = card->ext_csd.hs_max_dtr;
+	else if (max_dtr > card->csd.max_dtr)
+		max_dtr = card->csd.max_dtr;
+
+	mmc_set_clock(card->host, max_dtr);
+}
+
+/*
+ * Select the bus width amoung 4-bit and 8-bit(SDR).
+ * If the bus width is changed successfully, return the selected width value.
+ * Zero is returned instead of error value if the wide width is not supported.
+ */
+static int mmc_select_bus_width(struct mmc_card *card)
 {
-	int idx, err = -EINVAL;
-	struct mmc_host *host;
 	static unsigned ext_csd_bits[] = {
-		EXT_CSD_BUS_WIDTH_4,
 		EXT_CSD_BUS_WIDTH_8,
+		EXT_CSD_BUS_WIDTH_4,
 	};
 	static unsigned bus_widths[] = {
-		MMC_BUS_WIDTH_4,
 		MMC_BUS_WIDTH_8,
+		MMC_BUS_WIDTH_4,
 	};
+	struct mmc_host *host = card->host;
+	unsigned idx, bus_width = 0;
+	int err = 0;
 
-	BUG_ON(!card);
-
-	host = card->host;
-
-	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
-
-	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
-
-	/* If fails try again during next card power cycle */
-	if (err)
-		goto err;
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
+	    !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
+		return 0;
 
-	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
 
 	/*
 	 * Unlike SD, MMC cards dont have a configuration register to notify
@@ -871,8 +881,7 @@ static int mmc_select_hs200(struct mmc_card *card)
 	 * 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 >= 0; idx--) {
-
+	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
@@ -887,27 +896,202 @@ static int mmc_select_hs200(struct mmc_card *card)
 		if (err)
 			continue;
 
-		mmc_set_bus_width(card->host, bus_widths[idx]);
+		bus_width = bus_widths[idx];
+		mmc_set_bus_width(host, bus_width);
 
+		/*
+		 * If controller can't handle bus width test,
+		 * compare ext_csd previously read in 1 bit mode
+		 * against ext_csd at new bus width
+		 */
 		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-			err = mmc_compare_ext_csds(card, bus_widths[idx]);
+			err = mmc_compare_ext_csds(card, bus_width);
 		else
-			err = mmc_bus_test(card, bus_widths[idx]);
-		if (!err)
+			err = mmc_bus_test(card, bus_width);
+
+		if (!err) {
+			err = bus_width;
 			break;
+		} else {
+			pr_warn("%s: switch to bus width %d failed\n",
+				mmc_hostname(host), ext_csd_bits[idx]);
+		}
 	}
 
-	/* switch to HS200 mode if bus width set successfully */
+	return err;
+}
+
+/*
+ * Switch to the high-speed mode
+ */
+static int mmc_select_hs(struct mmc_card *card)
+{
+	int err;
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
 	if (!err)
+		mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+
+	return err;
+}
+
+/*
+ * Activate wide bus and DDR if supported.
+ */
+static int mmc_select_hs_ddr(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	u32 bus_width, ext_csd_bits;
+	int err = 0;
+
+	if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52))
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+		EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_BUS_WIDTH,
+			ext_csd_bits,
+			card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width %d ddr failed\n",
+			mmc_hostname(host), 1 << bus_width);
+		return err;
+	}
+
+	/*
+	 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+	 * signaling.
+	 *
+	 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+	 *
+	 * 1.8V vccq at 3.3V core voltage (vcc) is not required
+	 * in the JEDEC spec for DDR.
+	 *
+	 * Do not force change in vccq since we are obviously
+	 * working and no change to vccq is needed.
+	 *
+	 * WARNING: eMMC rules are NOT the same as SD DDR
+	 */
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		err = __mmc_set_signal_voltage(host,
+				MMC_SIGNAL_VOLTAGE_120);
+		if (err)
+			return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
+
+	return err;
+}
+
+/*
+ * For device supporting HS200 mode, the following sequence
+ * should be done before executing the tuning process.
+ * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
+ * 2. switch to HS200 mode
+ * 3. set the clock to > 52Mhz and <=200MHz
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = -EINVAL;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+
+	/* If fails try again during next card power cycle */
+	if (err)
+		goto err;
+
+	/*
+	 * Set the bus width(4 or 8) with host's support and
+	 * switch to HS200 mode if bus width is set successfully.
+	 */
+	err = mmc_select_bus_width(card);
+	if (!IS_ERR_VALUE(err)) {
 		err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				EXT_CSD_HS_TIMING, 2,
-				card->ext_csd.generic_cmd6_time,
-				true, true, true);
+				   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
+				   card->ext_csd.generic_cmd6_time,
+				   true, true, true);
+		if (!err)
+			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+	}
 err:
 	return err;
 }
 
 /*
+ * Activate High Speed or HS200 mode if supported.
+ */
+static int mmc_select_timing(struct mmc_card *card)
+{
+	int err = 0;
+
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
+	     card->ext_csd.hs_max_dtr == 0))
+		goto bus_speed;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+		err = mmc_select_hs200(card);
+	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
+		err = mmc_select_hs(card);
+
+	if (err && err != -EBADMSG)
+		return err;
+
+	if (err) {
+		pr_warn("%s: switch to %s failed\n",
+			mmc_card_hs(card) ? "high-speed" :
+			(mmc_card_hs200(card) ? "hs200" : ""),
+			mmc_hostname(card->host));
+		err = 0;
+	}
+
+bus_speed:
+	/*
+	 * Set the bus speed to the selected bus timing.
+	 * If timing is not selected, backward compatible is the default.
+	 */
+	mmc_set_bus_speed(card);
+	return err;
+}
+
+/*
+ * Execute tuning sequence to seek the proper bus operating
+ * conditions for HS200, which sends CMD21 to the device.
+ */
+static int mmc_hs200_tuning(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	if (host->ops->execute_tuning) {
+		mmc_host_clk_hold(host);
+		err = host->ops->execute_tuning(host,
+				MMC_SEND_TUNING_BLOCK_HS200);
+		mmc_host_clk_release(host);
+
+		if (err)
+			pr_warn("%s: tuning execution failed\n",
+				mmc_hostname(host));
+	}
+
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -917,9 +1101,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	struct mmc_card *oldcard)
 {
 	struct mmc_card *card;
-	int err, ddr = 0;
+	int err;
 	u32 cid[4];
-	unsigned int max_dtr;
 	u32 rocr;
 	u8 *ext_csd = NULL;
 
@@ -1111,173 +1294,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
-	 * Activate high speed (if supported)
-	 */
-	if (card->ext_csd.hs_max_dtr != 0) {
-		err = 0;
-		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-			err = mmc_select_hs200(card);
-		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
-			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					EXT_CSD_HS_TIMING, 1,
-					card->ext_csd.generic_cmd6_time,
-					true, true, true);
-
-		if (err && err != -EBADMSG)
-			goto free_card;
-
-		if (err) {
-			pr_warning("%s: switch to highspeed failed\n",
-			       mmc_hostname(card->host));
-			err = 0;
-		} else {
-			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-				mmc_set_timing(card->host,
-					       MMC_TIMING_MMC_HS200);
-			else
-				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-		}
-	}
-
-	/*
-	 * Compute bus speed.
-	 */
-	max_dtr = (unsigned int)-1;
-
-	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
-		if (max_dtr > card->ext_csd.hs_max_dtr)
-			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_hs(card) && (max_dtr > 52000000))
-			max_dtr = 52000000;
-	} else if (max_dtr > card->csd.max_dtr) {
-		max_dtr = card->csd.max_dtr;
-	}
-
-	mmc_set_clock(host, max_dtr);
-
-	/*
-	 * Indicate DDR mode (if supported).
+	 * Select timing interface
 	 */
-	if (mmc_card_hs(card))
-		ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	err = mmc_select_timing(card);
+	if (err)
+		goto free_card;
 
-	/*
-	 * Indicate HS200 SDR mode (if supported).
-	 */
 	if (mmc_card_hs200(card)) {
-		u32 ext_csd_bits;
-		u32 bus_width = card->host->ios.bus_width;
-
-		/*
-		 * For devices supporting HS200 mode, the bus width has
-		 * to be set before executing the tuning function. If
-		 * set before tuning, then device will respond with CRC
-		 * errors for responses on CMD line. So for HS200 the
-		 * sequence will be
-		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
-		 * 2. switch to HS200 mode
-		 * 3. set the clock to > 52Mhz <=200MHz and
-		 * 4. execute tuning for HS200
-		 */
-		if (card->host->ops->execute_tuning) {
-			mmc_host_clk_hold(card->host);
-			err = card->host->ops->execute_tuning(card->host,
-				MMC_SEND_TUNING_BLOCK_HS200);
-			mmc_host_clk_release(card->host);
-		}
-		if (err) {
-			pr_warning("%s: tuning execution failed\n",
-				   mmc_hostname(card->host));
+		err = mmc_hs200_tuning(card);
+		if (err)
 			goto err;
-		}
-
-		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
-				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-	}
-
-	/*
-	 * Activate wide bus and DDR (if supported).
-	 */
-	if (!mmc_card_hs200(card) &&
-	    (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
-	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
-		static unsigned ext_csd_bits[][2] = {
-			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
-			{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
-			{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
-		};
-		static unsigned bus_widths[] = {
-			MMC_BUS_WIDTH_8,
-			MMC_BUS_WIDTH_4,
-			MMC_BUS_WIDTH_1
-		};
-		unsigned idx, bus_width = 0;
-
-		if (host->caps & MMC_CAP_8_BIT_DATA)
-			idx = 0;
-		else
-			idx = 1;
-		for (; idx < ARRAY_SIZE(bus_widths); idx++) {
-			bus_width = bus_widths[idx];
-			if (bus_width == MMC_BUS_WIDTH_1)
-				ddr = 0; /* no DDR for 1-bit width */
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][0],
-					 card->ext_csd.generic_cmd6_time);
-			if (!err) {
-				mmc_set_bus_width(card->host, bus_width);
-
-				/*
-				 * If controller can't handle bus width test,
-				 * compare ext_csd previously read in 1 bit mode
-				 * against ext_csd at new bus width
-				 */
-				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					err = mmc_compare_ext_csds(card,
-						bus_width);
-				else
-					err = mmc_bus_test(card, bus_width);
-				if (!err)
-					break;
-			}
-		}
-
-		if (!err && ddr) {
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][1],
-					 card->ext_csd.generic_cmd6_time);
-		}
-		if (err) {
-			pr_warning("%s: switch to bus width %d ddr %d "
-				"failed\n", mmc_hostname(card->host),
-				1 << bus_width, ddr);
-			goto free_card;
-		} else if (ddr) {
-			/*
-			 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
-			 * signaling.
-			 *
-			 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
-			 *
-			 * 1.8V vccq at 3.3V core voltage (vcc) is not required
-			 * in the JEDEC spec for DDR.
-			 *
-			 * Do not force change in vccq since we are obviously
-			 * working and no change to vccq is needed.
-			 *
-			 * WARNING: eMMC rules are NOT the same as SD DDR
-			 */
-			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
-				err = __mmc_set_signal_voltage(host,
-					MMC_SIGNAL_VOLTAGE_120);
-				if (err)
-					goto err;
-			}
-			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
-			mmc_set_bus_width(card->host, bus_width);
+	} else if (mmc_card_hs(card)) {
+		/* Select the desired bus width optionally */
+		err = mmc_select_bus_width(card);
+		if (!IS_ERR_VALUE(err)) {
+			err = mmc_select_hs_ddr(card);
+			if (err)
+				goto err;
 		}
 	}
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index b9f194a..c422349 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -63,6 +63,7 @@ struct mmc_ext_csd {
 	unsigned int            power_off_longtime;     /* Units: ms */
 	u8			power_off_notification;	/* state */
 	unsigned int		hs_max_dtr;
+	unsigned int		hs200_max_dtr;
 #define MMC_HIGH_26_MAX_DTR	26000000
 #define MMC_HIGH_52_MAX_DTR	52000000
 #define MMC_HIGH_DDR_MAX_DTR	52000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f734c0c..f429f13 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -377,6 +377,10 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
 #define EXT_CSD_SEC_GB_CL_EN	BIT(4)
-- 
1.7.0.4



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

* [PATCH v6 5/6] mmc: add support for HS400 mode of eMMC5.0
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (19 preceding siblings ...)
  2014-04-18 13:36   ` [PATCH v6 4/6] mmc: rework selection of bus speed mode Seungwon Jeon
@ 2014-04-18 13:37   ` Seungwon Jeon
  2014-04-18 13:37   ` [PATCH v6 6/6] mmc: core: add DT bindings for eMMC HS400 1.8/1.2V Seungwon Jeon
                     ` (7 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-18 13:37 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

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: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/bus.c     |    1 +
 drivers/mmc/core/debugfs.c |    3 +
 drivers/mmc/core/mmc.c     |   98 +++++++++++++++++++++++++++++++++++++++++--
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/host.h   |   14 ++++++
 include/linux/mmc/mmc.h    |    7 +++-
 6 files changed, 118 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index f37e9d6..d2dbf02 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_hs(card) ? "high speed " : ""),
+			mmc_card_hs400(card) ? "HS400 " :
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 1f730db..91eb162 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_MMC_HS200:
 		str = "mmc HS200";
 		break;
+	case MMC_TIMING_MMC_HS400:
+		str = "mmc HS400";
+		break;
 	default:
 		str = "invalid";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 7e9b424..c12e247 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 static void mmc_select_card_type(struct mmc_card *card)
 {
 	struct mmc_host *host = card->host;
-	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
+	u8 card_type = card->ext_csd.raw_card_type;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
@@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
+	if (caps2 & MMC_CAP2_HS400_1_8V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS400_1_2V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
+	}
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
@@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
 		card->ext_csd.raw_pwr_cl_ddr_52_360 =
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
+		card->ext_csd.raw_pwr_cl_ddr_200_360 =
+			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
 	}
 
 	if (card->ext_csd.rev >= 5) {
@@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
 		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
 			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
 		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
-			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
+		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
+
 	if (err)
 		err = -EINVAL;
 
@@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
 				ext_csd->raw_pwr_cl_52_360 :
 				ext_csd->raw_pwr_cl_ddr_52_360;
 		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
-			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
+			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
+				ext_csd->raw_pwr_cl_ddr_200_360 :
+				ext_csd->raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
 {
 	unsigned int max_dtr = (unsigned int)-1;
 
-	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+	if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
+	     max_dtr > card->ext_csd.hs200_max_dtr)
 		max_dtr = card->ext_csd.hs200_max_dtr;
 	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
 		max_dtr = card->ext_csd.hs_max_dtr;
@@ -993,6 +1013,61 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
 	return err;
 }
 
+static int mmc_select_hs400(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	/*
+	 * HS400 mode requires 8-bit bus width
+	 */
+	if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
+	      host->ios.bus_width == MMC_BUS_WIDTH_8))
+		return 0;
+
+	/*
+	 * Before switching to dual data rate operation for HS400,
+	 * it is required to convert from HS200 mode to HS mode.
+	 */
+	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+	mmc_set_bus_speed(card);
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
+	if (err) {
+		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
+			mmc_hostname(host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_DDR_BUS_WIDTH_8,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
+			mmc_hostname(host), err);
+		return err;
+	}
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
+	if (err) {
+		pr_warn("%s: switch to hs400 failed, err:%d\n",
+			 mmc_hostname(host), err);
+		return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+	mmc_set_bus_speed(card);
+
+	return 0;
+}
+
 /*
  * For device supporting HS200 mode, the following sequence
  * should be done before executing the tuning process.
@@ -1070,13 +1145,22 @@ bus_speed:
 
 /*
  * Execute tuning sequence to seek the proper bus operating
- * conditions for HS200, which sends CMD21 to the device.
+ * conditions for HS200 and HS400, which sends CMD21 to the device.
  */
 static int mmc_hs200_tuning(struct mmc_card *card)
 {
 	struct mmc_host *host = card->host;
 	int err = 0;
 
+	/*
+	 * Timing should be adjusted to the HS400 target
+	 * operation frequency for tuning process
+	 */
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
+	    host->ios.bus_width == MMC_BUS_WIDTH_8)
+		if (host->ops->prepare_hs400_tuning)
+			host->ops->prepare_hs400_tuning(host, &host->ios);
+
 	if (host->ops->execute_tuning) {
 		mmc_host_clk_hold(host);
 		err = host->ops->execute_tuning(host,
@@ -1304,6 +1388,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_hs200_tuning(card);
 		if (err)
 			goto err;
+
+		err = mmc_select_hs400(card);
+		if (err)
+			goto err;
 	} else if (mmc_card_hs(card)) {
 		/* Select the desired bus width optionally */
 		err = mmc_select_bus_width(card);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c422349..e68bbeb 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -110,6 +110,7 @@ struct mmc_ext_csd {
 	u8			raw_pwr_cl_200_360;	/* 237 */
 	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
 	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
+	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
 	u8			raw_bkops_status;	/* 246 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 1ee3c10..5664d57 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -61,6 +61,7 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_DDR50	7
 #define MMC_TIMING_MMC_DDR52	8
 #define MMC_TIMING_MMC_HS200	9
+#define MMC_TIMING_MMC_HS400	10
 
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
@@ -132,6 +133,9 @@ struct mmc_host_ops {
 
 	/* The tuning command opcode value is different for SD and eMMC cards */
 	int	(*execute_tuning)(struct mmc_host *host, u32 opcode);
+
+	/* Prepare HS400 target operating frequency depending host driver */
+	void	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
 	int	(*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
 	void	(*hw_reset)(struct mmc_host *host);
 	void	(*card_event)(struct mmc_host *host);
@@ -274,6 +278,10 @@ struct mmc_host {
 #define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
 				 MMC_CAP2_PACKED_WR)
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
+#define MMC_CAP2_HS400_1_8V	(1 << 15)	/* Can support HS400 1.8V */
+#define MMC_CAP2_HS400_1_2V	(1 << 16)	/* Can support HS400 1.2V */
+#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
+				 MMC_CAP2_HS400_1_2V)
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
@@ -493,4 +501,10 @@ static inline bool mmc_card_ddr52(struct mmc_card *card)
 {
 	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
 }
+
+static inline bool mmc_card_hs400(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
+}
+
 #endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f429f13..64ec963 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -325,6 +325,7 @@ struct _mmc_csd {
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
 #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
 #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
 #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
@@ -354,7 +355,6 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
 #define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
@@ -370,6 +370,10 @@ struct _mmc_csd {
 						/* SDR mode @1.2V I/O */
 #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	(1<<6)	/* Card can run at 200MHz DDR, 1.8V */
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
@@ -380,6 +384,7 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
-- 
1.7.0.4



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

* [PATCH v6 6/6] mmc: core: add DT bindings for eMMC HS400 1.8/1.2V
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (20 preceding siblings ...)
  2014-04-18 13:37   ` [PATCH v6 5/6] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
@ 2014-04-18 13:37   ` Seungwon Jeon
  2014-04-23  8:30     ` Ulf Hansson
  2014-04-23  8:07   ` [PATCH 0/6] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (6 subsequent siblings)
  28 siblings, 1 reply; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-18 13:37 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

Provide the option to configure these speed modes per host,
for those host driver's that can't distinguish this in runtime.
Specially, if host can support HS400, it means that host can also
support HS200.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 Documentation/devicetree/bindings/mmc/mmc.txt |    2 ++
 drivers/mmc/core/host.c                       |    4 ++++
 2 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index 9dce540..3c18001 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -38,6 +38,8 @@ Optional properties:
 - mmc-highspeed-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported
 - mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported
 - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
+- mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
+- mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
 
 *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
 polarity properties, we have to fix the meaning of the "normal" and "inverted"
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index fdea825..95cceae 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -447,6 +447,10 @@ int mmc_of_parse(struct mmc_host *host)
 		host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
 	if (of_find_property(np, "mmc-hs200-1_2v", &len))
 		host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
+	if (of_find_property(np, "mmc-hs400-1_8v", &len))
+		host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
+	if (of_find_property(np, "mmc-hs400-1_2v", &len))
+		host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
 
 	return 0;
 
-- 
1.7.0.4



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

* Re: [PATCH v6 0/6] update selection of bus speed mode for eMMC
  2014-04-18 13:36   ` [PATCH v6 0/6] update selection of bus speed mode for eMMC Seungwon Jeon
@ 2014-04-20  7:18     ` Ulf Hansson
  2014-04-21  3:55       ` Seungwon Jeon
  0 siblings, 1 reply; 182+ messages in thread
From: Ulf Hansson @ 2014-04-20  7:18 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

Hi Seungwon,

On 18 April 2014 15:36, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> This series contains the change for selection of bus speed mode.
> Previous implementation is complicated and some sequence is duplicated.
> And specially, HS400 mode eMMC5.0 is introduced this time.
> This patch-set has been tested in Exynos SoC.
>
> Note:
> This patch-set depends on "[PATCH RESEND v3 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC".
>
> Changes in v6:
>         (6/6) Included "mmc: core: add DT bindings for eMMC HS400 1.8/1.2V" into this patch-set
>         (5/6) Changed return type of prepare_hs400_tuning callback(int -> void)

I would favour the int return type, that leaves room for the
possibility of drivers to fail.

Moreover, I have already sent a pull request to Chris, with the v5
version of this patchset, which I think is fine.

Kind regards
Uffe


> Changes in v5:
>         (5/5) Added callback operation for HS400 target operation frequency
>                instead of specific timing identifier.
>         (2/5) Removed using union declaration.
>
> Changes in v4:
>         (5/5)Reverting to HS mode is included in mmc_select_hs400() using __mmc_switch().
>
> Changes in v3:
>         Removed the function to check DDR type(mmc_snoop_ddr).
>         Rebased with the latest branch.
>
> Seungwon Jeon (6):
>   mmc: drop the speed mode of card's state
>   mmc: identify available device type to select
>   mmc: step power class after final selection of bus mode
>   mmc: rework selection of bus speed mode
>   mmc: add support for HS400 mode of eMMC5.0
>   mmc: add DT bindings for eMMC HS400 1.8/1.2V
>
>  Documentation/devicetree/bindings/mmc/mmc.txt |    2 +
>  drivers/mmc/core/bus.c                        |    9 +-
>  drivers/mmc/core/core.c                       |    3 +-
>  drivers/mmc/core/debugfs.c                    |    5 +-
>  drivers/mmc/core/host.c                       |    4 +
>  drivers/mmc/core/mmc.c                        |  666 +++++++++++++++----------
>  drivers/mmc/core/sd.c                         |   16 +-
>  drivers/mmc/core/sd.h                         |    1 -
>  drivers/mmc/core/sdio.c                       |    8 +-
>  include/linux/mmc/card.h                      |   27 +-
>  include/linux/mmc/host.h                      |   43 ++-
>  include/linux/mmc/mmc.h                       |   23 +-
>  12 files changed, 486 insertions(+), 321 deletions(-)
>
> Thanks,
> sw-j
>

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

* RE: [PATCH v6 0/6] update selection of bus speed mode for eMMC
  2014-04-20  7:18     ` Ulf Hansson
@ 2014-04-21  3:55       ` Seungwon Jeon
  0 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-21  3:55 UTC (permalink / raw)
  To: 'Ulf Hansson'
  Cc: 'linux-mmc', 'Chris Ball',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar'

On Sun, April 20, 2014, Ulf Hansson wrote:
> Hi Seungwon,
> 
> On 18 April 2014 15:36, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > This series contains the change for selection of bus speed mode.
> > Previous implementation is complicated and some sequence is duplicated.
> > And specially, HS400 mode eMMC5.0 is introduced this time.
> > This patch-set has been tested in Exynos SoC.
> >
> > Note:
> > This patch-set depends on "[PATCH RESEND v3 1/7] mmc: clarify DDR timing mode between SD-UHS and
> eMMC".
> >
> > Changes in v6:
> >         (6/6) Included "mmc: core: add DT bindings for eMMC HS400 1.8/1.2V" into this patch-set
> >         (5/6) Changed return type of prepare_hs400_tuning callback(int -> void)
> 
> I would favour the int return type, that leaves room for the
> possibility of drivers to fail.
> 
> Moreover, I have already sent a pull request to Chris, with the v5
> version of this patchset, which I think is fine.
OK. It would be fine.

Thanks,
Seungwon Jeon



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

* [PATCH 0/6] update selection of bus speed mode for eMMC
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (21 preceding siblings ...)
  2014-04-18 13:37   ` [PATCH v6 6/6] mmc: core: add DT bindings for eMMC HS400 1.8/1.2V Seungwon Jeon
@ 2014-04-23  8:07   ` Seungwon Jeon
  2014-04-23  8:07     ` Seungwon Jeon
                     ` (5 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-23  8:07 UTC (permalink / raw)
  To: linux-mmc, linux-wireless
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar', 'Fariya Fatima',
	'John W. Linville'

This series contains the change for selection of bus speed mode.
Previous implementation is complicated and some sequence is duplicated.
And specially, HS400 mode eMMC5.0 is introduced this time.
This patch-set has been tested in Exynos SoC.

Note: 
	As RS9113 wireless driver has been introduced newly in Linux-3.15-rc1, we meet some dependency with this patch-set
         which has been in the works all the while.
	Thus, related modification is applied through " mmc: drop the speed mode of card's state" 
---
Changes in v6:
	(6/6) Included "mmc: core: add DT bindings for eMMC HS400 1.8/1.2V" into this patch-set
	
Changes in v5:
	(5/5) Added callback operation for HS400 target operation frequency
	       instead of specific timing identifier.
	(2/5) Removed using union declaration.

Changes in v4:
	(5/5)Reverting to HS mode is included in mmc_select_hs400() using __mmc_switch().

Changes in v3:
 	Removed the function to check DDR type(mmc_snoop_ddr).
 	Rebased with the latest branch.

Seungwon Jeon (6):
  mmc: drop the speed mode of card's state
  mmc: identify available device type to select
  mmc: step power class after final selection of bus mode
  mmc: rework selection of bus speed mode
  mmc: add support for HS400 mode of eMMC5.0
  mmc: add DT bindings for eMMC HS400 1.8/1.2V

 Documentation/devicetree/bindings/mmc/mmc.txt |    2 +
 drivers/mmc/core/bus.c                        |    9 +-
 drivers/mmc/core/core.c                       |    3 +-
 drivers/mmc/core/debugfs.c                    |    5 +-
 drivers/mmc/core/host.c                       |    4 +
 drivers/mmc/core/mmc.c                        |  666 +++++++++++++++----------
 drivers/mmc/core/sd.c                         |   16 +-
 drivers/mmc/core/sd.h                         |    1 -
 drivers/mmc/core/sdio.c                       |    8 +-
 drivers/net/wireless/rsi/rsi_91x_sdio.c       |    4 +-
 include/linux/mmc/card.h                      |   27 +-
 include/linux/mmc/host.h                      |   43 ++-
 include/linux/mmc/mmc.h                       |   23 +-
 13 files changed, 487 insertions(+), 324 deletions(-)

Thanks,
sw-j


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

* [PATCH 1/6] mmc: drop the speed mode of card's state
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
@ 2014-04-23  8:07     ` Seungwon Jeon
  2014-03-13  9:52   ` [PATCH RESEND " Jaehoon Chung
                       ` (27 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-23  8:07 UTC (permalink / raw)
  To: linux-mmc, linux-wireless
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar', 'Fariya Fatima',
	'John W. Linville'

Timing mode identifier has same role and can take the place
of speed mode. This change removes all related speed mode.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Chris Ball <chris@printf.net>
---
 drivers/mmc/core/bus.c                  |    8 ++++----
 drivers/mmc/core/core.c                 |    3 +--
 drivers/mmc/core/mmc.c                  |   11 +++--------
 drivers/mmc/core/sd.c                   |   16 +++-------------
 drivers/mmc/core/sd.h                   |    1 -
 drivers/mmc/core/sdio.c                 |    8 ++------
 drivers/net/wireless/rsi/rsi_91x_sdio.c |    4 +---
 include/linux/mmc/card.h                |   23 ++++++-----------------
 include/linux/mmc/host.h                |   23 +++++++++++++++++++++++
 9 files changed, 43 insertions(+), 54 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 8246448..f37e9d6 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -341,16 +341,16 @@ int mmc_add_card(struct mmc_card *card)
 	if (mmc_host_is_spi(card->host)) {
 		pr_info("%s: new %s%s%s card on SPI\n",
 			mmc_hostname(card->host),
-			mmc_card_highspeed(card) ? "high speed " : "",
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_hs(card) ? "high speed " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			type);
 	} else {
 		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
-			(mmc_card_highspeed(card) ? "high speed " : ""),
+			(mmc_card_hs(card) ? "high speed " : ""),
 			(mmc_card_hs200(card) ? "HS200 " : ""),
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
 	}
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 79ba3a5..4b058ae 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2187,7 +2187,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
 	struct mmc_command cmd = {0};
 
-	if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+	if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
 		return 0;
 
 	cmd.opcode = MMC_SET_BLOCKLEN;
@@ -2267,7 +2267,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
 		}
 	}
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
 	if (mmc_host_is_spi(host)) {
 		host->ios.chip_select = MMC_CS_HIGH;
 		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index fbcf93d..3122052 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1083,11 +1083,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		} else {
 			if (card->ext_csd.hs_max_dtr > 52000000 &&
 			    host->caps2 & MMC_CAP2_HS200) {
-				mmc_card_set_hs200(card);
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
 			} else {
-				mmc_card_set_highspeed(card);
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
 			}
 		}
@@ -1098,10 +1096,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
+	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
 		if (max_dtr > card->ext_csd.hs_max_dtr)
 			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_highspeed(card) && (max_dtr > 52000000))
+		if (mmc_card_hs(card) && (max_dtr > 52000000))
 			max_dtr = 52000000;
 	} else if (max_dtr > card->csd.max_dtr) {
 		max_dtr = card->csd.max_dtr;
@@ -1112,7 +1110,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
 			&& (host->caps & MMC_CAP_1_8V_DDR))
 				ddr = MMC_1_8V_DDR_MODE;
@@ -1255,7 +1253,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 				if (err)
 					goto err;
 			}
-			mmc_card_set_ddr_mode(card);
 			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
 			mmc_set_bus_width(card->host, bus_width);
 		}
@@ -1499,7 +1496,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 		err = mmc_sleep(host);
 	else if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 
 	if (!err) {
 		mmc_power_off(host);
@@ -1629,7 +1625,6 @@ static int mmc_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 	mmc_claim_host(host);
 	ret = mmc_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index aef5157..0c44510 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -887,7 +887,7 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if (max_dtr > card->sw_caps.hs_max_dtr)
 			max_dtr = card->sw_caps.hs_max_dtr;
 	} else if (max_dtr > card->csd.max_dtr) {
@@ -897,12 +897,6 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 	return max_dtr;
 }
 
-void mmc_sd_go_highspeed(struct mmc_card *card)
-{
-	mmc_card_set_highspeed(card);
-	mmc_set_timing(card->host, MMC_TIMING_SD_HS);
-}
-
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -977,16 +971,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_sd_init_uhs_card(card);
 		if (err)
 			goto free_card;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Attempt to change to high-speed (if supported)
 		 */
 		err = mmc_sd_switch_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto free_card;
 
@@ -1081,7 +1072,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
 
 	if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
+
 	if (!err) {
 		mmc_power_off(host);
 		mmc_card_set_suspended(host->card);
@@ -1190,7 +1181,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
 	ret = mmc_sd_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
index 4b34b24..aab824a 100644
--- a/drivers/mmc/core/sd.h
+++ b/drivers/mmc/core/sd.h
@@ -12,6 +12,5 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 	bool reinit);
 unsigned mmc_sd_get_max_clock(struct mmc_card *card);
 int mmc_sd_switch_hs(struct mmc_card *card);
-void mmc_sd_go_highspeed(struct mmc_card *card);
 
 #endif
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 9933e42..e636d9e 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		/*
 		 * The SDIO specification doesn't mention how
 		 * the CIS transfer speed register relates to
@@ -733,7 +733,6 @@ try_again:
 		mmc_set_clock(host, card->cis.max_dtr);
 
 		if (card->cccr.high_speed) {
-			mmc_card_set_highspeed(card);
 			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		}
 
@@ -792,16 +791,13 @@ try_again:
 		err = mmc_sdio_init_uhs_card(card);
 		if (err)
 			goto remove;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Switch to high-speed (if supported).
 		 */
 		err = sdio_enable_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto remove;
 
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index 2e39d38..46e7af4 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -285,7 +285,6 @@ static void rsi_reset_card(struct sdio_func *pfunction)
 		if (err) {
 			rsi_dbg(ERR_ZONE, "%s: CCCR speed reg read failed: %d\n",
 				__func__, err);
-			card->state &= ~MMC_STATE_HIGHSPEED;
 		} else {
 			err = rsi_cmd52writebyte(card,
 						 SDIO_CCCR_SPEED,
@@ -296,14 +295,13 @@ static void rsi_reset_card(struct sdio_func *pfunction)
 					__func__, err);
 				return;
 			}
-			mmc_card_set_highspeed(card);
 			host->ios.timing = MMC_TIMING_SD_HS;
 			host->ops->set_ios(host, &host->ios);
 		}
 	}
 
 	/* Set clock */
-	if (mmc_card_highspeed(card))
+	if (mmc_card_hs(card))
 		clock = 50000000;
 	else
 		clock = card->cis.max_dtr;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index aa7e57f..aadeaf1 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -194,6 +194,7 @@ struct sdio_cis {
 };
 
 struct mmc_host;
+struct mmc_ios;
 struct sdio_func;
 struct sdio_func_tuple;
 
@@ -250,15 +251,11 @@ struct mmc_card {
 	unsigned int		state;		/* (our) card state */
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
 #define MMC_STATE_READONLY	(1<<1)		/* card is read-only */
-#define MMC_STATE_HIGHSPEED	(1<<2)		/* card is in high speed mode */
-#define MMC_STATE_BLOCKADDR	(1<<3)		/* card uses block-addressing */
-#define MMC_STATE_HIGHSPEED_DDR (1<<4)		/* card is in high speed mode */
-#define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra high speed mode */
-#define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
-#define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
-#define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
-#define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
-#define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
+#define MMC_STATE_BLOCKADDR	(1<<2)		/* card uses block-addressing */
+#define MMC_CARD_SDXC		(1<<3)		/* card is SDXC */
+#define MMC_CARD_REMOVED	(1<<4)		/* card has been removed */
+#define MMC_STATE_DOING_BKOPS	(1<<5)		/* card is doing BKOPS */
+#define MMC_STATE_SUSPENDED	(1<<6)		/* card is suspended */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -418,11 +415,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
-#define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
-#define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
-#define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
@@ -430,11 +423,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
-#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
-#define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
-#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_doing_bkops(c)	((c)->state |= MMC_STATE_DOING_BKOPS)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 0cf705c..a438537 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -17,6 +17,7 @@
 #include <linux/fault-inject.h>
 
 #include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -478,4 +479,26 @@ static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
 	return host->ios.clock;
 }
 #endif
+
+static inline int mmc_card_hs(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_SD_HS ||
+		card->host->ios.timing == MMC_TIMING_MMC_HS;
+}
+
+static inline int mmc_card_uhs(struct mmc_card *card)
+{
+	return card->host->ios.timing >= MMC_TIMING_UHS_SDR12 &&
+		card->host->ios.timing <= MMC_TIMING_UHS_DDR50;
+}
+
+static inline bool mmc_card_hs200(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_HS200;
+}
+
+static inline bool mmc_card_ddr52(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
+}
 #endif /* LINUX_MMC_HOST_H */
-- 
1.7.0.4



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

* [PATCH 1/6] mmc: drop the speed mode of card's state
@ 2014-04-23  8:07     ` Seungwon Jeon
  0 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-23  8:07 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA, linux-wireless-u79uwXL29TY76Z2rM5mHXA
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar', 'Fariya Fatima',
	'John W. Linville'

Timing mode identifier has same role and can take the place
of speed mode. This change removes all related speed mode.

Signed-off-by: Seungwon Jeon <tgih.jun-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Tested-by: Jaehoon Chung <jh80.chung-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Acked-by: Jaehoon Chung <jh80.chung-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Ulf Hansson <ulf.hansson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Chris Ball <chris-OsFVWbfNK3isTnJN9+BGXg@public.gmane.org>
---
 drivers/mmc/core/bus.c                  |    8 ++++----
 drivers/mmc/core/core.c                 |    3 +--
 drivers/mmc/core/mmc.c                  |   11 +++--------
 drivers/mmc/core/sd.c                   |   16 +++-------------
 drivers/mmc/core/sd.h                   |    1 -
 drivers/mmc/core/sdio.c                 |    8 ++------
 drivers/net/wireless/rsi/rsi_91x_sdio.c |    4 +---
 include/linux/mmc/card.h                |   23 ++++++-----------------
 include/linux/mmc/host.h                |   23 +++++++++++++++++++++++
 9 files changed, 43 insertions(+), 54 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 8246448..f37e9d6 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -341,16 +341,16 @@ int mmc_add_card(struct mmc_card *card)
 	if (mmc_host_is_spi(card->host)) {
 		pr_info("%s: new %s%s%s card on SPI\n",
 			mmc_hostname(card->host),
-			mmc_card_highspeed(card) ? "high speed " : "",
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_hs(card) ? "high speed " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			type);
 	} else {
 		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
-			(mmc_card_highspeed(card) ? "high speed " : ""),
+			(mmc_card_hs(card) ? "high speed " : ""),
 			(mmc_card_hs200(card) ? "HS200 " : ""),
-			mmc_card_ddr_mode(card) ? "DDR " : "",
+			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
 	}
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 79ba3a5..4b058ae 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2187,7 +2187,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
 	struct mmc_command cmd = {0};
 
-	if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+	if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
 		return 0;
 
 	cmd.opcode = MMC_SET_BLOCKLEN;
@@ -2267,7 +2267,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
 		}
 	}
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
 	if (mmc_host_is_spi(host)) {
 		host->ios.chip_select = MMC_CS_HIGH;
 		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index fbcf93d..3122052 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1083,11 +1083,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		} else {
 			if (card->ext_csd.hs_max_dtr > 52000000 &&
 			    host->caps2 & MMC_CAP2_HS200) {
-				mmc_card_set_hs200(card);
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
 			} else {
-				mmc_card_set_highspeed(card);
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
 			}
 		}
@@ -1098,10 +1096,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
+	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
 		if (max_dtr > card->ext_csd.hs_max_dtr)
 			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_highspeed(card) && (max_dtr > 52000000))
+		if (mmc_card_hs(card) && (max_dtr > 52000000))
 			max_dtr = 52000000;
 	} else if (max_dtr > card->csd.max_dtr) {
 		max_dtr = card->csd.max_dtr;
@@ -1112,7 +1110,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
 			&& (host->caps & MMC_CAP_1_8V_DDR))
 				ddr = MMC_1_8V_DDR_MODE;
@@ -1255,7 +1253,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 				if (err)
 					goto err;
 			}
-			mmc_card_set_ddr_mode(card);
 			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
 			mmc_set_bus_width(card->host, bus_width);
 		}
@@ -1499,7 +1496,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 		err = mmc_sleep(host);
 	else if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 
 	if (!err) {
 		mmc_power_off(host);
@@ -1629,7 +1625,6 @@ static int mmc_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 	mmc_claim_host(host);
 	ret = mmc_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index aef5157..0c44510 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -887,7 +887,7 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		if (max_dtr > card->sw_caps.hs_max_dtr)
 			max_dtr = card->sw_caps.hs_max_dtr;
 	} else if (max_dtr > card->csd.max_dtr) {
@@ -897,12 +897,6 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 	return max_dtr;
 }
 
-void mmc_sd_go_highspeed(struct mmc_card *card)
-{
-	mmc_card_set_highspeed(card);
-	mmc_set_timing(card->host, MMC_TIMING_SD_HS);
-}
-
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -977,16 +971,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_sd_init_uhs_card(card);
 		if (err)
 			goto free_card;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Attempt to change to high-speed (if supported)
 		 */
 		err = mmc_sd_switch_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto free_card;
 
@@ -1081,7 +1072,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
 
 	if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
+
 	if (!err) {
 		mmc_power_off(host);
 		mmc_card_set_suspended(host->card);
@@ -1190,7 +1181,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
 {
 	int ret;
 
-	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
 	ret = mmc_sd_init_card(host, host->card->ocr, host->card);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
index 4b34b24..aab824a 100644
--- a/drivers/mmc/core/sd.h
+++ b/drivers/mmc/core/sd.h
@@ -12,6 +12,5 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 	bool reinit);
 unsigned mmc_sd_get_max_clock(struct mmc_card *card);
 int mmc_sd_switch_hs(struct mmc_card *card);
-void mmc_sd_go_highspeed(struct mmc_card *card);
 
 #endif
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 9933e42..e636d9e 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
 {
 	unsigned max_dtr;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_hs(card)) {
 		/*
 		 * The SDIO specification doesn't mention how
 		 * the CIS transfer speed register relates to
@@ -733,7 +733,6 @@ try_again:
 		mmc_set_clock(host, card->cis.max_dtr);
 
 		if (card->cccr.high_speed) {
-			mmc_card_set_highspeed(card);
 			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		}
 
@@ -792,16 +791,13 @@ try_again:
 		err = mmc_sdio_init_uhs_card(card);
 		if (err)
 			goto remove;
-
-		/* Card is an ultra-high-speed card */
-		mmc_card_set_uhs(card);
 	} else {
 		/*
 		 * Switch to high-speed (if supported).
 		 */
 		err = sdio_enable_hs(card);
 		if (err > 0)
-			mmc_sd_go_highspeed(card);
+			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 		else if (err)
 			goto remove;
 
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index 2e39d38..46e7af4 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -285,7 +285,6 @@ static void rsi_reset_card(struct sdio_func *pfunction)
 		if (err) {
 			rsi_dbg(ERR_ZONE, "%s: CCCR speed reg read failed: %d\n",
 				__func__, err);
-			card->state &= ~MMC_STATE_HIGHSPEED;
 		} else {
 			err = rsi_cmd52writebyte(card,
 						 SDIO_CCCR_SPEED,
@@ -296,14 +295,13 @@ static void rsi_reset_card(struct sdio_func *pfunction)
 					__func__, err);
 				return;
 			}
-			mmc_card_set_highspeed(card);
 			host->ios.timing = MMC_TIMING_SD_HS;
 			host->ops->set_ios(host, &host->ios);
 		}
 	}
 
 	/* Set clock */
-	if (mmc_card_highspeed(card))
+	if (mmc_card_hs(card))
 		clock = 50000000;
 	else
 		clock = card->cis.max_dtr;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index aa7e57f..aadeaf1 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -194,6 +194,7 @@ struct sdio_cis {
 };
 
 struct mmc_host;
+struct mmc_ios;
 struct sdio_func;
 struct sdio_func_tuple;
 
@@ -250,15 +251,11 @@ struct mmc_card {
 	unsigned int		state;		/* (our) card state */
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
 #define MMC_STATE_READONLY	(1<<1)		/* card is read-only */
-#define MMC_STATE_HIGHSPEED	(1<<2)		/* card is in high speed mode */
-#define MMC_STATE_BLOCKADDR	(1<<3)		/* card uses block-addressing */
-#define MMC_STATE_HIGHSPEED_DDR (1<<4)		/* card is in high speed mode */
-#define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra high speed mode */
-#define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
-#define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
-#define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
-#define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
-#define MMC_STATE_SUSPENDED	(1<<11)		/* card is suspended */
+#define MMC_STATE_BLOCKADDR	(1<<2)		/* card uses block-addressing */
+#define MMC_CARD_SDXC		(1<<3)		/* card is SDXC */
+#define MMC_CARD_REMOVED	(1<<4)		/* card has been removed */
+#define MMC_STATE_DOING_BKOPS	(1<<5)		/* card is doing BKOPS */
+#define MMC_STATE_SUSPENDED	(1<<6)		/* card is suspended */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -418,11 +415,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
-#define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
-#define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
-#define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
@@ -430,11 +423,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
-#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
-#define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
-#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
-#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_doing_bkops(c)	((c)->state |= MMC_STATE_DOING_BKOPS)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 0cf705c..a438537 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -17,6 +17,7 @@
 #include <linux/fault-inject.h>
 
 #include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -478,4 +479,26 @@ static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
 	return host->ios.clock;
 }
 #endif
+
+static inline int mmc_card_hs(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_SD_HS ||
+		card->host->ios.timing == MMC_TIMING_MMC_HS;
+}
+
+static inline int mmc_card_uhs(struct mmc_card *card)
+{
+	return card->host->ios.timing >= MMC_TIMING_UHS_SDR12 &&
+		card->host->ios.timing <= MMC_TIMING_UHS_DDR50;
+}
+
+static inline bool mmc_card_hs200(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_HS200;
+}
+
+static inline bool mmc_card_ddr52(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
+}
 #endif /* LINUX_MMC_HOST_H */
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 2/6] mmc: identify available device type to select
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (23 preceding siblings ...)
  2014-04-23  8:07     ` Seungwon Jeon
@ 2014-04-23  8:07   ` Seungwon Jeon
  2014-04-23  8:08   ` [PATCH 3/6] mmc: step power class after final selection of bus mode Seungwon Jeon
                     ` (3 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-23  8:07 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar', 'Fariya Fatima',
	'John W. Linville'

Device types which are supported by both host and device can be
identified when EXT_CSD is read. There is no need to check host's
capability anymore.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Chris Ball <chris@printf.net>
---
 drivers/mmc/core/mmc.c   |   72 +++++++++++++++++++++++++---------------------
 include/linux/mmc/card.h |    2 +-
 include/linux/mmc/host.h |    6 ----
 include/linux/mmc/mmc.h  |   12 +++++--
 4 files changed, 48 insertions(+), 44 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 3122052..b5691fe 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -243,28 +243,46 @@ static void mmc_select_card_type(struct mmc_card *card)
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0;
+	unsigned int avail_type = 0;
 
-	if (card_type & EXT_CSD_CARD_TYPE_26)
+	if (caps & MMC_CAP_MMC_HIGHSPEED &&
+	    card_type & EXT_CSD_CARD_TYPE_HS_26) {
 		hs_max_dtr = MMC_HIGH_26_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_26;
+	}
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
-			card_type & EXT_CSD_CARD_TYPE_52)
+	    card_type & EXT_CSD_CARD_TYPE_HS_52) {
 		hs_max_dtr = MMC_HIGH_52_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS_52;
+	}
 
-	if ((caps & MMC_CAP_1_8V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
-	    (caps & MMC_CAP_1_2V_DDR &&
-			card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
+	if (caps & MMC_CAP_1_8V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
 		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
+	}
+
+	if (caps & MMC_CAP_1_2V_DDR &&
+	    card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
+	}
 
-	if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
-	    (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
-			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
+	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
 		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
+	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
+		hs_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
+	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
-	card->ext_csd.card_type = card_type;
+	card->mmc_avail_type = avail_type;
 }
 
 /*
@@ -800,12 +818,10 @@ static int mmc_select_hs200(struct mmc_card *card)
 
 	host = card->host;
 
-	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
-			host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
 
-	if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
-			host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
 		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
 
 	/* If fails try again during next card power cycle */
@@ -1064,10 +1080,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	if (card->ext_csd.hs_max_dtr != 0) {
 		err = 0;
-		if (card->ext_csd.hs_max_dtr > 52000000 &&
-		    host->caps2 & MMC_CAP2_HS200)
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 			err = mmc_select_hs200(card);
-		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
+		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
 			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					EXT_CSD_HS_TIMING, 1,
 					card->ext_csd.generic_cmd6_time,
@@ -1081,13 +1096,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			       mmc_hostname(card->host));
 			err = 0;
 		} else {
-			if (card->ext_csd.hs_max_dtr > 52000000 &&
-			    host->caps2 & MMC_CAP2_HS200) {
+			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 				mmc_set_timing(card->host,
 					       MMC_TIMING_MMC_HS200);
-			} else {
+			else
 				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-			}
 		}
 	}
 
@@ -1110,14 +1123,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Indicate DDR mode (if supported).
 	 */
-	if (mmc_card_hs(card)) {
-		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-			&& (host->caps & MMC_CAP_1_8V_DDR))
-				ddr = MMC_1_8V_DDR_MODE;
-		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-			&& (host->caps & MMC_CAP_1_2V_DDR))
-				ddr = MMC_1_2V_DDR_MODE;
-	}
+	if (mmc_card_hs(card))
+		ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
 
 	/*
 	 * Indicate HS200 SDR mode (if supported).
@@ -1137,8 +1144,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		 * 3. set the clock to > 52Mhz <=200MHz and
 		 * 4. execute tuning for HS200
 		 */
-		if ((host->caps2 & MMC_CAP2_HS200) &&
-		    card->host->ops->execute_tuning) {
+		if (card->host->ops->execute_tuning) {
 			mmc_host_clk_hold(card->host);
 			err = card->host->ops->execute_tuning(card->host,
 				MMC_SEND_TUNING_BLOCK_HS200);
@@ -1247,7 +1253,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			 *
 			 * WARNING: eMMC rules are NOT the same as SD DDR
 			 */
-			if (ddr == MMC_1_2V_DDR_MODE) {
+			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
 				err = __mmc_set_signal_voltage(host,
 					MMC_SIGNAL_VOLTAGE_120);
 				if (err)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index aadeaf1..fe31f8d 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -68,7 +68,6 @@ struct mmc_ext_csd {
 #define MMC_HIGH_DDR_MAX_DTR	52000000
 #define MMC_HS200_MAX_DTR	200000000
 	unsigned int		sectors;
-	unsigned int		card_type;
 	unsigned int		hc_erase_size;		/* In sectors */
 	unsigned int		hc_erase_timeout;	/* In milliseconds */
 	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
@@ -298,6 +297,7 @@ struct mmc_card {
 	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
 
 	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
+	unsigned int		mmc_avail_type;	/* supported device type by both host and card */
 
 	struct dentry		*debugfs_root;
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index a438537..6b1e9ee 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -62,12 +62,6 @@ struct mmc_ios {
 #define MMC_TIMING_MMC_DDR52	8
 #define MMC_TIMING_MMC_HS200	9
 
-#define MMC_SDR_MODE		0
-#define MMC_1_2V_DDR_MODE	1
-#define MMC_1_8V_DDR_MODE	2
-#define MMC_1_2V_SDR_MODE	3
-#define MMC_1_8V_SDR_MODE	4
-
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
 #define MMC_SIGNAL_VOLTAGE_330	0
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 50bcde3..f734c0c 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -354,18 +354,22 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#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_MASK	0x3F	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
+				 EXT_CSD_CARD_TYPE_HS_52)
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
 					     /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
 					     /* DDR mode @1.2V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
 					| EXT_CSD_CARD_TYPE_DDR_1_2V)
-#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
-#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_8V	(1<<4)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_HS200_1_2V	(1<<5)	/* Card can run at 200MHz */
 						/* SDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_HS200_1_8V | \
+					 EXT_CSD_CARD_TYPE_HS200_1_2V)
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
-- 
1.7.0.4



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

* [PATCH 3/6] mmc: step power class after final selection of bus mode
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (24 preceding siblings ...)
  2014-04-23  8:07   ` [PATCH 2/6] mmc: identify available device type to select Seungwon Jeon
@ 2014-04-23  8:08   ` Seungwon Jeon
  2014-04-23  8:08   ` [PATCH 4/6] mmc: rework selection of bus speed mode Seungwon Jeon
                     ` (2 subsequent siblings)
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-23  8:08 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar', 'Fariya Fatima',
	'John W. Linville'

Power class is changed once only after selection of bus modes
including speed and bus-width finishes finally.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Chris Ball <chris@printf.net>
---
 drivers/mmc/core/mmc.c |   96 +++++++++++++++++++++++++++--------------------
 1 files changed, 55 insertions(+), 41 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index b5691fe..4538541 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -724,17 +724,13 @@ static struct device_type mmc_type = {
  * extended CSD register, select it by executing the
  * mmc_switch command.
  */
-static int mmc_select_powerclass(struct mmc_card *card,
-		unsigned int bus_width)
+static int __mmc_select_powerclass(struct mmc_card *card,
+				   unsigned int bus_width)
 {
-	int err = 0;
+	struct mmc_host *host = card->host;
+	struct mmc_ext_csd *ext_csd = &card->ext_csd;
 	unsigned int pwrclass_val = 0;
-	struct mmc_host *host;
-
-	BUG_ON(!card);
-
-	host = card->host;
-	BUG_ON(!host);
+	int err = 0;
 
 	/* Power class selection is supported for versions >= 4.0 */
 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
@@ -746,14 +742,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
 
 	switch (1 << host->ios.vdd) {
 	case MMC_VDD_165_195:
-		if (host->ios.clock <= 26000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
-		else if	(host->ios.clock <= 52000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_26_195;
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-				card->ext_csd.raw_pwr_cl_52_195 :
-				card->ext_csd.raw_pwr_cl_ddr_52_195;
-		else if (host->ios.clock <= 200000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
+				ext_csd->raw_pwr_cl_52_195 :
+				ext_csd->raw_pwr_cl_ddr_52_195;
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_200_195;
 		break;
 	case MMC_VDD_27_28:
 	case MMC_VDD_28_29:
@@ -764,14 +760,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	case MMC_VDD_33_34:
 	case MMC_VDD_34_35:
 	case MMC_VDD_35_36:
-		if (host->ios.clock <= 26000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
-		else if	(host->ios.clock <= 52000000)
+		if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_26_360;
+		else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
 			pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-				card->ext_csd.raw_pwr_cl_52_360 :
-				card->ext_csd.raw_pwr_cl_ddr_52_360;
-		else if (host->ios.clock <= 200000000)
-			pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
+				ext_csd->raw_pwr_cl_52_360 :
+				ext_csd->raw_pwr_cl_ddr_52_360;
+		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
+			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -797,6 +793,37 @@ static int mmc_select_powerclass(struct mmc_card *card,
 	return err;
 }
 
+static int mmc_select_powerclass(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	u32 bus_width, ext_csd_bits;
+	int err, ddr;
+
+	/* Power class selection is supported for versions >= 4.0 */
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	/* Power class values are defined only for 4/8 bit bus */
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	if (ddr)
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+	else
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+			EXT_CSD_BUS_WIDTH_8 :  EXT_CSD_BUS_WIDTH_4;
+
+	err = __mmc_select_powerclass(card, ext_csd_bits);
+	if (err)
+		pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
+			mmc_hostname(host), 1 << bus_width, ddr);
+
+	return err;
+}
+
 /*
  * Selects the desired buswidth and switch to the HS200 mode
  * if bus width set without error
@@ -1158,11 +1185,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
 		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
 				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-		err = mmc_select_powerclass(card, ext_csd_bits);
-		if (err)
-			pr_warning("%s: power class selection to bus width %d"
-				   " failed\n", mmc_hostname(card->host),
-				   1 << bus_width);
 	}
 
 	/*
@@ -1191,12 +1213,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			bus_width = bus_widths[idx];
 			if (bus_width == MMC_BUS_WIDTH_1)
 				ddr = 0; /* no DDR for 1-bit width */
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width);
 
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
@@ -1221,13 +1237,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		}
 
 		if (!err && ddr) {
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d ddr %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width, ddr);
-
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][1],
@@ -1265,6 +1274,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
+	 * Choose the power class with selected bus interface
+	 */
+	mmc_select_powerclass(card);
+
+	/*
 	 * Enable HPI feature (if supported)
 	 */
 	if (card->ext_csd.hpi) {
-- 
1.7.0.4



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

* [PATCH 4/6] mmc: rework selection of bus speed mode
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (25 preceding siblings ...)
  2014-04-23  8:08   ` [PATCH 3/6] mmc: step power class after final selection of bus mode Seungwon Jeon
@ 2014-04-23  8:08   ` Seungwon Jeon
  2014-04-23  8:14   ` [PATCH 5/6] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
  2014-04-23  8:15   ` [PATCH 6/6] mmc: core: add DT bindings for eMMC HS400 1.8/1.2V Seungwon Jeon
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-23  8:08 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar', 'Fariya Fatima',
	'John W. Linville'

Current implementation for bus speed mode selection is too
complicated. This patch is to simplify the codes and remove
some duplicate parts.

The following changes are including:
* Adds functions for each mode selection(HS, HS-DDR, HS200 and etc)
* Rearranged the mode selection sequence with supported device type
* Adds maximum speed for HS200 mode(hs200_max_dtr)
* Adds field definition for HS_TIMING of EXT_CSD

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Chris Ball <chris@printf.net>
---
 drivers/mmc/core/debugfs.c |    2 +-
 drivers/mmc/core/mmc.c     |  431 ++++++++++++++++++++++++--------------------
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/mmc.h    |    4 +
 4 files changed, 238 insertions(+), 200 deletions(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 509229b..1f730db 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -139,7 +139,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 		str = "mmc DDR52";
 		break;
 	case MMC_TIMING_MMC_HS200:
-		str = "mmc high-speed SDR200";
+		str = "mmc HS200";
 		break;
 	default:
 		str = "invalid";
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 4538541..bec6786 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -242,7 +242,7 @@ static void mmc_select_card_type(struct mmc_card *card)
 	struct mmc_host *host = card->host;
 	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
 	u32 caps = host->caps, caps2 = host->caps2;
-	unsigned int hs_max_dtr = 0;
+	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
 
 	if (caps & MMC_CAP_MMC_HIGHSPEED &&
@@ -271,17 +271,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 
 	if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
 	}
 
 	if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
 	    card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
-		hs_max_dtr = MMC_HS200_MAX_DTR;
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
+	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
 }
 
@@ -825,37 +826,46 @@ static int mmc_select_powerclass(struct mmc_card *card)
 }
 
 /*
- * Selects the desired buswidth and switch to the HS200 mode
- * if bus width set without error
+ * Set the bus speed for the selected speed mode.
  */
-static int mmc_select_hs200(struct mmc_card *card)
+static void mmc_set_bus_speed(struct mmc_card *card)
+{
+	unsigned int max_dtr = (unsigned int)-1;
+
+	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+		max_dtr = card->ext_csd.hs200_max_dtr;
+	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
+		max_dtr = card->ext_csd.hs_max_dtr;
+	else if (max_dtr > card->csd.max_dtr)
+		max_dtr = card->csd.max_dtr;
+
+	mmc_set_clock(card->host, max_dtr);
+}
+
+/*
+ * Select the bus width amoung 4-bit and 8-bit(SDR).
+ * If the bus width is changed successfully, return the selected width value.
+ * Zero is returned instead of error value if the wide width is not supported.
+ */
+static int mmc_select_bus_width(struct mmc_card *card)
 {
-	int idx, err = -EINVAL;
-	struct mmc_host *host;
 	static unsigned ext_csd_bits[] = {
-		EXT_CSD_BUS_WIDTH_4,
 		EXT_CSD_BUS_WIDTH_8,
+		EXT_CSD_BUS_WIDTH_4,
 	};
 	static unsigned bus_widths[] = {
-		MMC_BUS_WIDTH_4,
 		MMC_BUS_WIDTH_8,
+		MMC_BUS_WIDTH_4,
 	};
+	struct mmc_host *host = card->host;
+	unsigned idx, bus_width = 0;
+	int err = 0;
 
-	BUG_ON(!card);
-
-	host = card->host;
-
-	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
-
-	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
-		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
-
-	/* If fails try again during next card power cycle */
-	if (err)
-		goto err;
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
+	    !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
+		return 0;
 
-	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
 
 	/*
 	 * Unlike SD, MMC cards dont have a configuration register to notify
@@ -863,8 +873,7 @@ static int mmc_select_hs200(struct mmc_card *card)
 	 * 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 >= 0; idx--) {
-
+	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
@@ -879,27 +888,202 @@ static int mmc_select_hs200(struct mmc_card *card)
 		if (err)
 			continue;
 
-		mmc_set_bus_width(card->host, bus_widths[idx]);
+		bus_width = bus_widths[idx];
+		mmc_set_bus_width(host, bus_width);
 
+		/*
+		 * If controller can't handle bus width test,
+		 * compare ext_csd previously read in 1 bit mode
+		 * against ext_csd at new bus width
+		 */
 		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-			err = mmc_compare_ext_csds(card, bus_widths[idx]);
+			err = mmc_compare_ext_csds(card, bus_width);
 		else
-			err = mmc_bus_test(card, bus_widths[idx]);
-		if (!err)
+			err = mmc_bus_test(card, bus_width);
+
+		if (!err) {
+			err = bus_width;
 			break;
+		} else {
+			pr_warn("%s: switch to bus width %d failed\n",
+				mmc_hostname(host), ext_csd_bits[idx]);
+		}
 	}
 
-	/* switch to HS200 mode if bus width set successfully */
+	return err;
+}
+
+/*
+ * Switch to the high-speed mode
+ */
+static int mmc_select_hs(struct mmc_card *card)
+{
+	int err;
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
 	if (!err)
+		mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+
+	return err;
+}
+
+/*
+ * Activate wide bus and DDR if supported.
+ */
+static int mmc_select_hs_ddr(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	u32 bus_width, ext_csd_bits;
+	int err = 0;
+
+	if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52))
+		return 0;
+
+	bus_width = host->ios.bus_width;
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+		EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_BUS_WIDTH,
+			ext_csd_bits,
+			card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width %d ddr failed\n",
+			mmc_hostname(host), 1 << bus_width);
+		return err;
+	}
+
+	/*
+	 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+	 * signaling.
+	 *
+	 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+	 *
+	 * 1.8V vccq at 3.3V core voltage (vcc) is not required
+	 * in the JEDEC spec for DDR.
+	 *
+	 * Do not force change in vccq since we are obviously
+	 * working and no change to vccq is needed.
+	 *
+	 * WARNING: eMMC rules are NOT the same as SD DDR
+	 */
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+		err = __mmc_set_signal_voltage(host,
+				MMC_SIGNAL_VOLTAGE_120);
+		if (err)
+			return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
+
+	return err;
+}
+
+/*
+ * For device supporting HS200 mode, the following sequence
+ * should be done before executing the tuning process.
+ * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
+ * 2. switch to HS200 mode
+ * 3. set the clock to > 52Mhz and <=200MHz
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = -EINVAL;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+
+	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
+		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+
+	/* If fails try again during next card power cycle */
+	if (err)
+		goto err;
+
+	/*
+	 * Set the bus width(4 or 8) with host's support and
+	 * switch to HS200 mode if bus width is set successfully.
+	 */
+	err = mmc_select_bus_width(card);
+	if (!IS_ERR_VALUE(err)) {
 		err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				EXT_CSD_HS_TIMING, 2,
-				card->ext_csd.generic_cmd6_time,
-				true, true, true);
+				   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
+				   card->ext_csd.generic_cmd6_time,
+				   true, true, true);
+		if (!err)
+			mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+	}
 err:
 	return err;
 }
 
 /*
+ * Activate High Speed or HS200 mode if supported.
+ */
+static int mmc_select_timing(struct mmc_card *card)
+{
+	int err = 0;
+
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
+	     card->ext_csd.hs_max_dtr == 0))
+		goto bus_speed;
+
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+		err = mmc_select_hs200(card);
+	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
+		err = mmc_select_hs(card);
+
+	if (err && err != -EBADMSG)
+		return err;
+
+	if (err) {
+		pr_warn("%s: switch to %s failed\n",
+			mmc_card_hs(card) ? "high-speed" :
+			(mmc_card_hs200(card) ? "hs200" : ""),
+			mmc_hostname(card->host));
+		err = 0;
+	}
+
+bus_speed:
+	/*
+	 * Set the bus speed to the selected bus timing.
+	 * If timing is not selected, backward compatible is the default.
+	 */
+	mmc_set_bus_speed(card);
+	return err;
+}
+
+/*
+ * Execute tuning sequence to seek the proper bus operating
+ * conditions for HS200, which sends CMD21 to the device.
+ */
+static int mmc_hs200_tuning(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	if (host->ops->execute_tuning) {
+		mmc_host_clk_hold(host);
+		err = host->ops->execute_tuning(host,
+				MMC_SEND_TUNING_BLOCK_HS200);
+		mmc_host_clk_release(host);
+
+		if (err)
+			pr_warn("%s: tuning execution failed\n",
+				mmc_hostname(host));
+	}
+
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -909,9 +1093,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	struct mmc_card *oldcard)
 {
 	struct mmc_card *card;
-	int err, ddr = 0;
+	int err;
 	u32 cid[4];
-	unsigned int max_dtr;
 	u32 rocr;
 	u8 *ext_csd = NULL;
 
@@ -1103,173 +1286,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
-	 * Activate high speed (if supported)
-	 */
-	if (card->ext_csd.hs_max_dtr != 0) {
-		err = 0;
-		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-			err = mmc_select_hs200(card);
-		else if	(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
-			err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					EXT_CSD_HS_TIMING, 1,
-					card->ext_csd.generic_cmd6_time,
-					true, true, true);
-
-		if (err && err != -EBADMSG)
-			goto free_card;
-
-		if (err) {
-			pr_warning("%s: switch to highspeed failed\n",
-			       mmc_hostname(card->host));
-			err = 0;
-		} else {
-			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
-				mmc_set_timing(card->host,
-					       MMC_TIMING_MMC_HS200);
-			else
-				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-		}
-	}
-
-	/*
-	 * Compute bus speed.
-	 */
-	max_dtr = (unsigned int)-1;
-
-	if (mmc_card_hs(card) || mmc_card_hs200(card)) {
-		if (max_dtr > card->ext_csd.hs_max_dtr)
-			max_dtr = card->ext_csd.hs_max_dtr;
-		if (mmc_card_hs(card) && (max_dtr > 52000000))
-			max_dtr = 52000000;
-	} else if (max_dtr > card->csd.max_dtr) {
-		max_dtr = card->csd.max_dtr;
-	}
-
-	mmc_set_clock(host, max_dtr);
-
-	/*
-	 * Indicate DDR mode (if supported).
+	 * Select timing interface
 	 */
-	if (mmc_card_hs(card))
-		ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
+	err = mmc_select_timing(card);
+	if (err)
+		goto free_card;
 
-	/*
-	 * Indicate HS200 SDR mode (if supported).
-	 */
 	if (mmc_card_hs200(card)) {
-		u32 ext_csd_bits;
-		u32 bus_width = card->host->ios.bus_width;
-
-		/*
-		 * For devices supporting HS200 mode, the bus width has
-		 * to be set before executing the tuning function. If
-		 * set before tuning, then device will respond with CRC
-		 * errors for responses on CMD line. So for HS200 the
-		 * sequence will be
-		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
-		 * 2. switch to HS200 mode
-		 * 3. set the clock to > 52Mhz <=200MHz and
-		 * 4. execute tuning for HS200
-		 */
-		if (card->host->ops->execute_tuning) {
-			mmc_host_clk_hold(card->host);
-			err = card->host->ops->execute_tuning(card->host,
-				MMC_SEND_TUNING_BLOCK_HS200);
-			mmc_host_clk_release(card->host);
-		}
-		if (err) {
-			pr_warning("%s: tuning execution failed\n",
-				   mmc_hostname(card->host));
+		err = mmc_hs200_tuning(card);
+		if (err)
 			goto err;
-		}
-
-		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
-				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-	}
-
-	/*
-	 * Activate wide bus and DDR (if supported).
-	 */
-	if (!mmc_card_hs200(card) &&
-	    (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
-	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
-		static unsigned ext_csd_bits[][2] = {
-			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
-			{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
-			{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
-		};
-		static unsigned bus_widths[] = {
-			MMC_BUS_WIDTH_8,
-			MMC_BUS_WIDTH_4,
-			MMC_BUS_WIDTH_1
-		};
-		unsigned idx, bus_width = 0;
-
-		if (host->caps & MMC_CAP_8_BIT_DATA)
-			idx = 0;
-		else
-			idx = 1;
-		for (; idx < ARRAY_SIZE(bus_widths); idx++) {
-			bus_width = bus_widths[idx];
-			if (bus_width == MMC_BUS_WIDTH_1)
-				ddr = 0; /* no DDR for 1-bit width */
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][0],
-					 card->ext_csd.generic_cmd6_time);
-			if (!err) {
-				mmc_set_bus_width(card->host, bus_width);
-
-				/*
-				 * If controller can't handle bus width test,
-				 * compare ext_csd previously read in 1 bit mode
-				 * against ext_csd at new bus width
-				 */
-				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					err = mmc_compare_ext_csds(card,
-						bus_width);
-				else
-					err = mmc_bus_test(card, bus_width);
-				if (!err)
-					break;
-			}
-		}
-
-		if (!err && ddr) {
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][1],
-					 card->ext_csd.generic_cmd6_time);
-		}
-		if (err) {
-			pr_warning("%s: switch to bus width %d ddr %d "
-				"failed\n", mmc_hostname(card->host),
-				1 << bus_width, ddr);
-			goto free_card;
-		} else if (ddr) {
-			/*
-			 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
-			 * signaling.
-			 *
-			 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
-			 *
-			 * 1.8V vccq at 3.3V core voltage (vcc) is not required
-			 * in the JEDEC spec for DDR.
-			 *
-			 * Do not force change in vccq since we are obviously
-			 * working and no change to vccq is needed.
-			 *
-			 * WARNING: eMMC rules are NOT the same as SD DDR
-			 */
-			if (ddr & EXT_CSD_CARD_TYPE_DDR_1_2V) {
-				err = __mmc_set_signal_voltage(host,
-					MMC_SIGNAL_VOLTAGE_120);
-				if (err)
-					goto err;
-			}
-			mmc_set_timing(card->host, MMC_TIMING_MMC_DDR52);
-			mmc_set_bus_width(card->host, bus_width);
+	} else if (mmc_card_hs(card)) {
+		/* Select the desired bus width optionally */
+		err = mmc_select_bus_width(card);
+		if (!IS_ERR_VALUE(err)) {
+			err = mmc_select_hs_ddr(card);
+			if (err)
+				goto err;
 		}
 	}
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index fe31f8d..1760736 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -63,6 +63,7 @@ struct mmc_ext_csd {
 	unsigned int            power_off_longtime;     /* Units: ms */
 	u8			power_off_notification;	/* state */
 	unsigned int		hs_max_dtr;
+	unsigned int		hs200_max_dtr;
 #define MMC_HIGH_26_MAX_DTR	26000000
 #define MMC_HIGH_52_MAX_DTR	52000000
 #define MMC_HIGH_DDR_MAX_DTR	52000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f734c0c..f429f13 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -377,6 +377,10 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
 #define EXT_CSD_SEC_GB_CL_EN	BIT(4)
-- 
1.7.0.4



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

* [PATCH 5/6] mmc: add support for HS400 mode of eMMC5.0
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (26 preceding siblings ...)
  2014-04-23  8:08   ` [PATCH 4/6] mmc: rework selection of bus speed mode Seungwon Jeon
@ 2014-04-23  8:14   ` Seungwon Jeon
  2014-04-23  8:15   ` [PATCH 6/6] mmc: core: add DT bindings for eMMC HS400 1.8/1.2V Seungwon Jeon
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-23  8:14 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar', 'Fariya Fatima',
	'John W. Linville'

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: Seungwon Jeon <tgih.jun@samsung.com>
Reviewed-by: Jackey Shen <jackey.shen@amd.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Chris Ball <chris@printf.net>
---
 drivers/mmc/core/bus.c     |    1 +
 drivers/mmc/core/debugfs.c |    3 +
 drivers/mmc/core/mmc.c     |   98 +++++++++++++++++++++++++++++++++++++++++--
 include/linux/mmc/card.h   |    1 +
 include/linux/mmc/host.h   |   14 ++++++
 include/linux/mmc/mmc.h    |    7 +++-
 6 files changed, 118 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index f37e9d6..d2dbf02 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_hs(card) ? "high speed " : ""),
+			mmc_card_hs400(card) ? "HS400 " :
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 1f730db..91eb162 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_MMC_HS200:
 		str = "mmc HS200";
 		break;
+	case MMC_TIMING_MMC_HS400:
+		str = "mmc HS400";
+		break;
 	default:
 		str = "invalid";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index bec6786..793c6f7 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 static void mmc_select_card_type(struct mmc_card *card)
 {
 	struct mmc_host *host = card->host;
-	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
+	u8 card_type = card->ext_csd.raw_card_type;
 	u32 caps = host->caps, caps2 = host->caps2;
 	unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
 	unsigned int avail_type = 0;
@@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
 	}
 
+	if (caps2 & MMC_CAP2_HS400_1_8V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
+	}
+
+	if (caps2 & MMC_CAP2_HS400_1_2V &&
+	    card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
+		hs200_max_dtr = MMC_HS200_MAX_DTR;
+		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
+	}
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
@@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
 		card->ext_csd.raw_pwr_cl_ddr_52_360 =
 			ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
+		card->ext_csd.raw_pwr_cl_ddr_200_360 =
+			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
 	}
 
 	if (card->ext_csd.rev >= 5) {
@@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
 		(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
 			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
 		(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
-			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
+		(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
+			bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
+
 	if (err)
 		err = -EINVAL;
 
@@ -768,7 +785,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
 				ext_csd->raw_pwr_cl_52_360 :
 				ext_csd->raw_pwr_cl_ddr_52_360;
 		else if (host->ios.clock <= MMC_HS200_MAX_DTR)
-			pwrclass_val = ext_csd->raw_pwr_cl_200_360;
+			pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
+				ext_csd->raw_pwr_cl_ddr_200_360 :
+				ext_csd->raw_pwr_cl_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -832,7 +851,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
 {
 	unsigned int max_dtr = (unsigned int)-1;
 
-	if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
+	if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
+	     max_dtr > card->ext_csd.hs200_max_dtr)
 		max_dtr = card->ext_csd.hs200_max_dtr;
 	else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
 		max_dtr = card->ext_csd.hs_max_dtr;
@@ -985,6 +1005,61 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
 	return err;
 }
 
+static int mmc_select_hs400(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	/*
+	 * HS400 mode requires 8-bit bus width
+	 */
+	if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
+	      host->ios.bus_width == MMC_BUS_WIDTH_8))
+		return 0;
+
+	/*
+	 * Before switching to dual data rate operation for HS400,
+	 * it is required to convert from HS200 mode to HS mode.
+	 */
+	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+	mmc_set_bus_speed(card);
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
+	if (err) {
+		pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
+			mmc_hostname(host), err);
+		return err;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 EXT_CSD_DDR_BUS_WIDTH_8,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
+			mmc_hostname(host), err);
+		return err;
+	}
+
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
+			   card->ext_csd.generic_cmd6_time,
+			   true, true, true);
+	if (err) {
+		pr_warn("%s: switch to hs400 failed, err:%d\n",
+			 mmc_hostname(host), err);
+		return err;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+	mmc_set_bus_speed(card);
+
+	return 0;
+}
+
 /*
  * For device supporting HS200 mode, the following sequence
  * should be done before executing the tuning process.
@@ -1062,13 +1137,22 @@ bus_speed:
 
 /*
  * Execute tuning sequence to seek the proper bus operating
- * conditions for HS200, which sends CMD21 to the device.
+ * conditions for HS200 and HS400, which sends CMD21 to the device.
  */
 static int mmc_hs200_tuning(struct mmc_card *card)
 {
 	struct mmc_host *host = card->host;
 	int err = 0;
 
+	/*
+	 * Timing should be adjusted to the HS400 target
+	 * operation frequency for tuning process
+	 */
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
+	    host->ios.bus_width == MMC_BUS_WIDTH_8)
+		if (host->ops->prepare_hs400_tuning)
+			host->ops->prepare_hs400_tuning(host, &host->ios);
+
 	if (host->ops->execute_tuning) {
 		mmc_host_clk_hold(host);
 		err = host->ops->execute_tuning(host,
@@ -1296,6 +1380,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_hs200_tuning(card);
 		if (err)
 			goto err;
+
+		err = mmc_select_hs400(card);
+		if (err)
+			goto err;
 	} else if (mmc_card_hs(card)) {
 		/* Select the desired bus width optionally */
 		err = mmc_select_bus_width(card);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 1760736..d424b9d 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -110,6 +110,7 @@ struct mmc_ext_csd {
 	u8			raw_pwr_cl_200_360;	/* 237 */
 	u8			raw_pwr_cl_ddr_52_195;	/* 238 */
 	u8			raw_pwr_cl_ddr_52_360;	/* 239 */
+	u8			raw_pwr_cl_ddr_200_360;	/* 253 */
 	u8			raw_bkops_status;	/* 246 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 6b1e9ee..1830873 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -61,6 +61,7 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_DDR50	7
 #define MMC_TIMING_MMC_DDR52	8
 #define MMC_TIMING_MMC_HS200	9
+#define MMC_TIMING_MMC_HS400	10
 
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
@@ -132,6 +133,9 @@ struct mmc_host_ops {
 
 	/* The tuning command opcode value is different for SD and eMMC cards */
 	int	(*execute_tuning)(struct mmc_host *host, u32 opcode);
+
+	/* Prepare HS400 target operating frequency depending host driver */
+	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
 	int	(*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
 	void	(*hw_reset)(struct mmc_host *host);
 	void	(*card_event)(struct mmc_host *host);
@@ -274,6 +278,10 @@ struct mmc_host {
 #define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
 				 MMC_CAP2_PACKED_WR)
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
+#define MMC_CAP2_HS400_1_8V	(1 << 15)	/* Can support HS400 1.8V */
+#define MMC_CAP2_HS400_1_2V	(1 << 16)	/* Can support HS400 1.2V */
+#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
+				 MMC_CAP2_HS400_1_2V)
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
@@ -495,4 +503,10 @@ static inline bool mmc_card_ddr52(struct mmc_card *card)
 {
 	return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
 }
+
+static inline bool mmc_card_hs400(struct mmc_card *card)
+{
+	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
+}
+
 #endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index f429f13..64ec963 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -325,6 +325,7 @@ struct _mmc_csd {
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_PWR_CL_DDR_200_360	253	/* RO */
 #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
 #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
 #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
@@ -354,7 +355,6 @@ struct _mmc_csd {
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_HS_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_HS_52	(1<<1)	/* Card can run at 52MHz */
 #define EXT_CSD_CARD_TYPE_HS	(EXT_CSD_CARD_TYPE_HS_26 | \
@@ -370,6 +370,10 @@ struct _mmc_csd {
 						/* SDR mode @1.2V I/O */
 #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	(1<<6)	/* Card can run at 200MHz DDR, 1.8V */
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<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_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
@@ -380,6 +384,7 @@ struct _mmc_csd {
 #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_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
-- 
1.7.0.4



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

* [PATCH 6/6] mmc: core: add DT bindings for eMMC HS400 1.8/1.2V
  2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
                     ` (27 preceding siblings ...)
  2014-04-23  8:14   ` [PATCH 5/6] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
@ 2014-04-23  8:15   ` Seungwon Jeon
  28 siblings, 0 replies; 182+ messages in thread
From: Seungwon Jeon @ 2014-04-23  8:15 UTC (permalink / raw)
  To: linux-mmc
  Cc: 'Chris Ball', 'Ulf Hansson',
	'Jaehoon Chung', 'Jackey Shen',
	'Alim Akhtar', 'Fariya Fatima',
	'John W. Linville'

Provide the option to configure these speed modes per host,
for those host driver's that can't distinguish this in runtime.
Specially, if host can support HS400, it means that host can also
support HS200.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 Documentation/devicetree/bindings/mmc/mmc.txt |    2 ++
 drivers/mmc/core/host.c                       |    4 ++++
 2 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index 9dce540..3c18001 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -38,6 +38,8 @@ Optional properties:
 - mmc-highspeed-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported
 - mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported
 - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
+- mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
+- mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
 
 *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
 polarity properties, we have to fix the meaning of the "normal" and "inverted"
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index fdea825..95cceae 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -447,6 +447,10 @@ int mmc_of_parse(struct mmc_host *host)
 		host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
 	if (of_find_property(np, "mmc-hs200-1_2v", &len))
 		host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
+	if (of_find_property(np, "mmc-hs400-1_8v", &len))
+		host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
+	if (of_find_property(np, "mmc-hs400-1_2v", &len))
+		host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
 
 	return 0;
 
-- 
1.7.0.4



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

* Re: [PATCH v6 6/6] mmc: core: add DT bindings for eMMC HS400 1.8/1.2V
  2014-04-18 13:37   ` [PATCH v6 6/6] mmc: core: add DT bindings for eMMC HS400 1.8/1.2V Seungwon Jeon
@ 2014-04-23  8:30     ` Ulf Hansson
  0 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-04-23  8:30 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: linux-mmc, Chris Ball, Jaehoon Chung, Jackey Shen, Alim Akhtar

On 18 April 2014 15:37, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Provide the option to configure these speed modes per host,
> for those host driver's that can't distinguish this in runtime.
> Specially, if host can support HS400, it means that host can also
> support HS200.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>

Acked-by: Ulf Hansson <ulf.hansson@linaro.org>

> ---
>  Documentation/devicetree/bindings/mmc/mmc.txt |    2 ++
>  drivers/mmc/core/host.c                       |    4 ++++
>  2 files changed, 6 insertions(+), 0 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
> index 9dce540..3c18001 100644
> --- a/Documentation/devicetree/bindings/mmc/mmc.txt
> +++ b/Documentation/devicetree/bindings/mmc/mmc.txt
> @@ -38,6 +38,8 @@ Optional properties:
>  - mmc-highspeed-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported
>  - mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported
>  - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
> +- mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
> +- mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
>
>  *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
>  polarity properties, we have to fix the meaning of the "normal" and "inverted"
> diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
> index fdea825..95cceae 100644
> --- a/drivers/mmc/core/host.c
> +++ b/drivers/mmc/core/host.c
> @@ -447,6 +447,10 @@ int mmc_of_parse(struct mmc_host *host)
>                 host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
>         if (of_find_property(np, "mmc-hs200-1_2v", &len))
>                 host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
> +       if (of_find_property(np, "mmc-hs400-1_8v", &len))
> +               host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
> +       if (of_find_property(np, "mmc-hs400-1_2v", &len))
> +               host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
>
>         return 0;
>
> --
> 1.7.0.4
>
>

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

* Re: [PATCH 1/6] mmc: drop the speed mode of card's state
  2014-04-23  8:07     ` Seungwon Jeon
  (?)
@ 2014-05-05  8:02     ` Ulf Hansson
  -1 siblings, 0 replies; 182+ messages in thread
From: Ulf Hansson @ 2014-05-05  8:02 UTC (permalink / raw)
  To: John W. Linville
  Cc: linux-mmc, linux-wireless, Chris Ball, Jaehoon Chung,
	Jackey Shen, Alim Akhtar, Seungwon Jeon, Fariya Fatima

On 23 April 2014 10:07, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Timing mode identifier has same role and can take the place
> of speed mode. This change removes all related speed mode.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> Signed-off-by: Chris Ball <chris@printf.net>
> ---
>  drivers/mmc/core/bus.c                  |    8 ++++----
>  drivers/mmc/core/core.c                 |    3 +--
>  drivers/mmc/core/mmc.c                  |   11 +++--------
>  drivers/mmc/core/sd.c                   |   16 +++-------------
>  drivers/mmc/core/sd.h                   |    1 -
>  drivers/mmc/core/sdio.c                 |    8 ++------
>  drivers/net/wireless/rsi/rsi_91x_sdio.c |    4 +---
>  include/linux/mmc/card.h                |   23 ++++++-----------------
>  include/linux/mmc/host.h                |   23 +++++++++++++++++++++++
>  9 files changed, 43 insertions(+), 54 deletions(-)

Hi John,

We would like to queue this patch through Chris' mmc tree for 3.16.

Since it touches the rsi wireless driver, could you please have a look
and let's us know if you have any concerns.

Kind regards
Ulf Hansson

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

end of thread, other threads:[~2014-05-05  8:02 UTC | newest]

Thread overview: 182+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-05 12:10 [PATCH 0/3] mmc: tmio: Use modern PM ops Ulf Hansson
2013-11-05 12:10 ` [PATCH 1/3] mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks Ulf Hansson
2013-11-05 22:29   ` Guennadi Liakhovetski
2013-11-05 12:10 ` [PATCH 2/3] mmc: tmio_mmc: Convert from legacy to modern PM ops Ulf Hansson
2013-11-05 22:24   ` Guennadi Liakhovetski
2013-11-05 12:10 ` [PATCH 3/3] mmc: tmio: Adapt to proper PM configs for exported functions Ulf Hansson
2013-11-05 22:29   ` Guennadi Liakhovetski
2013-11-05 13:26 ` [PATCH] mmc: trivial: fix the compiling warning Seungwon Jeon
2013-11-06  3:20   ` Jaehoon Chung
2013-11-06  9:42     ` Seungwon Jeon
2013-11-05 13:27 ` [PATCH 0/3] mmc: update bus speed mode Seungwon Jeon
2013-11-05 13:27 ` [PATCH 1/3] mmc: rework selection of " Seungwon Jeon
2013-11-05 14:06   ` Ulf Hansson
2013-11-06  9:09     ` Seungwon Jeon
2013-11-06 10:46       ` Ulf Hansson
2013-11-05 13:27 ` [PATCH 2/3] mmc: correct some exclusive card state to clear Seungwon Jeon
2013-11-05 14:33   ` Ulf Hansson
2013-11-06  9:35     ` Seungwon Jeon
2013-11-06 10:38       ` Ulf Hansson
2013-11-07  3:51         ` Seungwon Jeon
2013-11-05 13:28 ` [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0 Seungwon Jeon
2013-11-07  7:38   ` Shen, Jackey
2013-11-07 11:38     ` Seungwon Jeon
2013-11-08  9:05       ` Jackey Shen
2013-11-11 12:51         ` Seungwon Jeon
2013-11-25  7:32           ` Jackey Shen
2013-11-08 12:16 ` [PATCH 0/3] mmc: tmio: Use modern PM ops Guennadi Liakhovetski
2013-11-11  9:24   ` Ulf Hansson
2014-01-15 14:10 ` [PATCH 0/7] mmc: distinguish DDR timing mode for eMMC/UHS Seungwon Jeon
2014-01-15 14:10 ` [PATCH 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC Seungwon Jeon
2014-01-16 10:50   ` Ulf Hansson
2014-01-17 21:22     ` Ulf Hansson
2014-01-20  3:55       ` Seungwon Jeon
2014-01-23  9:06         ` Ulf Hansson
2014-01-15 14:11 ` [PATCH 2/7] mmc: mmci: " Seungwon Jeon
2014-01-16 10:20   ` Ulf Hansson
2014-01-17 14:05     ` Seungwon Jeon
2014-01-17 14:50     ` [PATCH v2 " Seungwon Jeon
2014-01-15 14:11 ` [PATCH 3/7] mmc: omap: " Seungwon Jeon
2014-01-16 10:49   ` Ulf Hansson
2014-01-16 11:07     ` Balaji T K
2014-01-16 11:01   ` Balaji T K
2014-01-15 14:12 ` [PATCH 4/7] mmc: sh_mmcif: " Seungwon Jeon
2014-01-16 10:22   ` Ulf Hansson
2014-01-17 14:36     ` Seungwon Jeon
2014-01-28 13:08     ` Seungwon Jeon
2014-01-15 14:12 ` [PATCH 5/7] mmc: rtsx: " Seungwon Jeon
2014-01-16 10:51   ` Ulf Hansson
2014-01-15 14:12 ` [PATCH 6/7] mmc: dw_mmc: " Seungwon Jeon
2014-01-16 10:37   ` Ulf Hansson
2014-01-15 14:12 ` [PATCH 7/7] mmc: sdhci: " Seungwon Jeon
2014-01-16 10:25   ` Ulf Hansson
2014-01-15 14:13 ` [PATCH 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
2014-01-15 14:14 ` [PATCH 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
2014-01-15 14:14 ` [PATCH 2/5] mmc: identify available device type to select Seungwon Jeon
2014-01-15 14:14 ` [PATCH 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
2014-01-15 14:15 ` [PATCH 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
2014-01-15 14:19 ` [PATCH 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
2014-02-18 10:24   ` Jackey Shen
2014-02-18 13:31     ` Seungwon Jeon
2014-02-15 14:08 ` [PATCH v2 0/7] mmc: distinguish DDR timing mode for eMMC/UHS Seungwon Jeon
2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
2014-03-14 12:11   ` [PATCH RESEND " Seungwon Jeon
2014-04-02 11:50     ` Ulf Hansson
2014-04-03 11:56       ` Seungwon Jeon
2014-02-15 14:08 ` [PATCH v2 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC Seungwon Jeon
2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
2014-03-07 13:42     ` Jaehoon Chung
2014-03-14 12:11   ` [PATCH RESEND " Seungwon Jeon
2014-02-15 14:08 ` [PATCH v2 2/7] mmc: mmci: " Seungwon Jeon
2014-02-17 14:08   ` Ulf Hansson
2014-02-18 13:34     ` Seungwon Jeon
2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
2014-02-15 14:09 ` [PATCH v2 3/7] mmc: omap: " Seungwon Jeon
2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
2014-02-15 14:09 ` [PATCH v2 4/7] mmc: sh_mmcif: " Seungwon Jeon
2014-03-07 13:30   ` [PATCH v3 " Seungwon Jeon
2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
2014-02-15 14:09 ` [PATCH v2 5/7] mmc: rtsx: " Seungwon Jeon
2014-03-07 13:31   ` [PATCH v3 " Seungwon Jeon
2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
2014-02-15 14:09 ` [PATCH v2 6/7] mmc: dw_mmc: " Seungwon Jeon
2014-03-07 13:31   ` [PATCH v3 " Seungwon Jeon
2014-03-07 13:43     ` Jaehoon Chung
2014-03-14 12:12   ` [PATCH RESEMD " Seungwon Jeon
2014-02-15 14:09 ` [PATCH v2 7/7] mmc: sdhci: " Seungwon Jeon
2014-03-07 13:31   ` [PATCH v3 " Seungwon Jeon
2014-03-14 12:12   ` [PATCH RESEND " Seungwon Jeon
2014-02-15 14:18 ` [PATCH RESEND 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
2014-03-07 14:35   ` [PATCH v2 " Seungwon Jeon
2014-03-13 14:41     ` Ulf Hansson
2014-03-13  9:52   ` [PATCH RESEND " Jaehoon Chung
2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
2014-03-17  8:47     ` Ulf Hansson
2014-03-18  1:43       ` Seungwon Jeon
2014-03-18  4:20         ` Jaehoon Chung
2014-03-18  8:01           ` Ulf Hansson
2014-03-26 10:59   ` [PATCH v4 " Seungwon Jeon
2014-03-26 11:00   ` [PATCH v4 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
2014-03-26 11:00   ` [PATCH v4 2/5] mmc: identify available device type to select Seungwon Jeon
2014-03-26 11:00   ` [PATCH v4 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
2014-03-28  8:43     ` Ulf Hansson
2014-03-26 11:00   ` [PATCH v4 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
2014-03-26 11:00   ` [PATCH v4 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
2014-04-11 11:33   ` [PATCH v5 0/5] update selection of bus speed mode for eMMC Seungwon Jeon
2014-04-11 11:34   ` [PATCH v5 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
2014-04-11 11:34   ` [PATCH v5 2/5] mmc: identify available device type to select Seungwon Jeon
2014-04-11 11:47     ` Ulf Hansson
2014-04-11 11:34   ` [PATCH v5 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
2014-04-11 11:34   ` [PATCH v5 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
2014-04-11 11:34   ` [PATCH v5 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
2014-04-11 12:06     ` Ulf Hansson
2014-04-18 13:36   ` [PATCH v6 0/6] update selection of bus speed mode for eMMC Seungwon Jeon
2014-04-20  7:18     ` Ulf Hansson
2014-04-21  3:55       ` Seungwon Jeon
2014-04-18 13:36   ` [PATCH v6 1/6] mmc: drop the speed mode of card's state Seungwon Jeon
2014-04-18 13:36   ` [PATCH v6 2/6] mmc: identify available device type to select Seungwon Jeon
2014-04-18 13:36   ` [PATCH v6 3/6] mmc: step power class after final selection of bus mode Seungwon Jeon
2014-04-18 13:36   ` [PATCH v6 4/6] mmc: rework selection of bus speed mode Seungwon Jeon
2014-04-18 13:37   ` [PATCH v6 5/6] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
2014-04-18 13:37   ` [PATCH v6 6/6] mmc: core: add DT bindings for eMMC HS400 1.8/1.2V Seungwon Jeon
2014-04-23  8:30     ` Ulf Hansson
2014-04-23  8:07   ` [PATCH 0/6] update selection of bus speed mode for eMMC Seungwon Jeon
2014-04-23  8:07   ` [PATCH 1/6] mmc: drop the speed mode of card's state Seungwon Jeon
2014-04-23  8:07     ` Seungwon Jeon
2014-05-05  8:02     ` Ulf Hansson
2014-04-23  8:07   ` [PATCH 2/6] mmc: identify available device type to select Seungwon Jeon
2014-04-23  8:08   ` [PATCH 3/6] mmc: step power class after final selection of bus mode Seungwon Jeon
2014-04-23  8:08   ` [PATCH 4/6] mmc: rework selection of bus speed mode Seungwon Jeon
2014-04-23  8:14   ` [PATCH 5/6] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
2014-04-23  8:15   ` [PATCH 6/6] mmc: core: add DT bindings for eMMC HS400 1.8/1.2V Seungwon Jeon
2014-02-15 14:18 ` [PATCH RESEND 1/5] mmc: drop the speed mode of card's state Seungwon Jeon
2014-02-17 14:38   ` Ulf Hansson
2014-02-18 13:43     ` Seungwon Jeon
2014-02-18 16:40       ` Ulf Hansson
2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
2014-02-15 14:18 ` [PATCH RESEND 2/5] mmc: identify available device type to select Seungwon Jeon
2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
2014-03-10 10:14     ` Jaehoon Chung
2014-03-10 11:59       ` Seungwon Jeon
2014-03-13  5:37         ` Jaehoon Chung
2014-03-13  8:37           ` Seungwon Jeon
2014-03-13  9:51             ` Jaehoon Chung
2014-03-13 14:02     ` Ulf Hansson
2014-03-14  2:49       ` Seungwon Jeon
2014-03-14  7:34         ` Ulf Hansson
2014-03-14 10:24           ` Seungwon Jeon
2014-03-28  8:31         ` Ulf Hansson
2014-03-28 12:27           ` Seungwon Jeon
2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
2014-02-15 14:23 ` [PATCH RESEND 3/5] mmc: step power class after final selection of bus mode Seungwon Jeon
2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
2014-03-13 14:28     ` Ulf Hansson
2014-03-14  2:49       ` Seungwon Jeon
2014-03-14  7:31         ` Ulf Hansson
2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
2014-02-15 14:24 ` [PATCH RESEND 4/5] mmc: rework selection of bus speed mode Seungwon Jeon
2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
2014-03-21 13:01     ` Ulf Hansson
2014-03-22 12:04       ` Seungwon Jeon
2014-03-24 13:11         ` Ulf Hansson
2014-02-15 14:24 ` [PATCH RESEND 5/5] mmc: add support for HS400 mode of eMMC5.0 Seungwon Jeon
2014-03-07 14:36   ` [PATCH v2 " Seungwon Jeon
2014-03-11  0:45     ` Jackey Shen
2014-03-14 11:34       ` Seungwon Jeon
2014-03-14 12:16   ` [PATCH v3 " Seungwon Jeon
2014-03-24 15:41     ` Ulf Hansson
2014-03-25  9:23       ` Seungwon Jeon
2014-03-28  9:57         ` Ulf Hansson
2014-03-28 12:18           ` Seungwon Jeon
2014-03-28 13:33             ` Ulf Hansson
2014-04-02  1:15               ` Seungwon Jeon
2014-04-02  9:39                 ` Ulf Hansson
2014-04-03 11:53                   ` Seungwon Jeon
2014-04-03 13:14                     ` Ulf Hansson
2014-04-04 10:46                       ` Seungwon Jeon
2014-04-04 11:58                         ` Ulf Hansson
2014-04-05 14:36                           ` Seungwon Jeon

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.