Skip to contentSkip to conversation

mmc: tmio: Use modern PM ops

PATCH In review Ulf Hansson 7 participants 181 messages Nov 5, 2013 – May 5, 2014 Page 1 of 3

Subsystems (9)
lore
Share & tools
lore
#0 lore raw

cover mmc: tmio: Use modern PM ops

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(-)
Signature · 1 line
1.7.9.5
#1 lore raw

PATCH 1/3 mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks

---
 drivers/mmc/host/sh_mobile_sdhi.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/mmc/host/sh_mobile_sdhi.c +4 -4
index 87ed3fb..2227a9f 100644
@@ -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 = {
Signature · 1 line
1.7.9.5
Acked-by on v1 1/3
#2 lore raw

Re: [PATCH 1/3] mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks

Quoted 1 line · Ulf Hansson

Thanks
Guennadi

Quoted 26 lines
---
 drivers/mmc/host/sh_mobile_sdhi.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/mmc/host/sh_mobile_sdhi.c +4 -4
index 87ed3fb..2227a9f 100644
@@ -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 = {
Signature · 1 line
1.7.9.5

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

#3 lore raw

PATCH 2/3 mmc: tmio_mmc: Convert from legacy to modern PM ops

In reply to Ulf Hansson
---
 drivers/mmc/host/tmio_mmc.c |   32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)
drivers/mmc/host/tmio_mmc.c +18 -14
index 8860d4d..a56a3fe 100644
@@ -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);
Signature · 1 line
1.7.9.5
#4 lore raw

Re: [PATCH 2/3] mmc: tmio_mmc: Convert from legacy to modern PM ops

Hi Ulf,

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

Quoted 12 lines · Ulf Hansson
---
 drivers/mmc/host/tmio_mmc.c |   32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)
drivers/mmc/host/tmio_mmc.c +0 -0
index 8860d4d..a56a3fe 100644
@@ -23,38 +23,39 @@
 
 #include "tmio_mmc.h"

drivers/mmc/host/tmio_mmc.c line 31

Quoted 10 lines
drivers/mmc/host/tmio_mmc.c +5 -3
 
-#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

drivers/mmc/host/tmio_mmc.c line 38

Quoted 9 lines
drivers/mmc/host/tmio_mmc.c +2 -2
 	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);

Quoted 7 lines
drivers/mmc/host/tmio_mmc.c +1 -1
 	return ret;
 }
 
-static int tmio_mmc_resume(struct platform_device *dev)
+static int tmio_mmc_resume(struct device *dev)
 {

drivers/mmc/host/tmio_mmc.c line 52

Quoted 10 lines
drivers/mmc/host/tmio_mmc.c +4 -2
-	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

Quoted 37 lines
drivers/mmc/host/tmio_mmc.c +6 -6
 	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);
Signature · 1 line
1.7.9.5

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

#5 lore raw

PATCH 3/3 mmc: tmio: Adapt to proper PM configs for exported functions

In reply to 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.

---
 drivers/mmc/host/tmio_mmc.h     |    7 +++----
 drivers/mmc/host/tmio_mmc_pio.c |    7 ++++---
 2 files changed, 7 insertions(+), 7 deletions(-)
drivers/mmc/host/tmio_mmc.h +3 -4
index 86fd21e..6c5b45a 100644
@@ -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)
 {
drivers/mmc/host/tmio_mmc_pio.c +4 -3
index f3b2d8c..472e803 100644
@@ -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");
Signature · 1 line
1.7.9.5
Acked-by on v1 3/3
#6 lore raw

Re: [PATCH 3/3] mmc: tmio: Adapt to proper PM configs for exported functions

Quoted 4 lines · 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.

Thanks
Guennadi

Quoted 64 lines
---
 drivers/mmc/host/tmio_mmc.h     |    7 +++----
 drivers/mmc/host/tmio_mmc_pio.c |    7 ++++---
 2 files changed, 7 insertions(+), 7 deletions(-)
drivers/mmc/host/tmio_mmc.h +3 -4
index 86fd21e..6c5b45a 100644
@@ -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)
 {
drivers/mmc/host/tmio_mmc_pio.c +4 -3
index f3b2d8c..472e803 100644
@@ -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");
Signature · 1 line
1.7.9.5

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

#7 lore raw

PATCH 1/1 mmc: trivial: fix the compiling warning

In reply to Ulf Hansson

Fixed the following warning.

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

---
 drivers/mmc/core/mmc_ops.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/mmc/core/mmc_ops.c +1 -1
index aae8d8b..e5b5eeb 100644
@@ -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);
Signature · 1 line
1.7.0.4
maintainer
#8 lore raw

Re: [PATCH] mmc: trivial: fix the compiling warning

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

mmc: core: Silence compiler warning in __mmc_switch

Best regards,
Jaehoon Chung

Quoted 24 lines · Seungwon Jeon

Fixed the following warning.

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

---
 drivers/mmc/core/mmc_ops.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/mmc/core/mmc_ops.c +1 -1
index aae8d8b..e5b5eeb 100644
@@ -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);
#9 lore raw

RE: [PATCH] mmc: trivial: fix the compiling warning

Quoted 3 lines · Jaehoon Chung

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

mmc: core: Silence compiler warning in __mmc_switch

Oh, good!

Thanks,
Seungwon Jeon

Quoted 34 lines

Best regards,
Jaehoon Chung

Quoted 16 lines · Seungwon Jeon

Fixed the following warning.

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

---
 drivers/mmc/core/mmc_ops.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/mmc/core/mmc_ops.c +0 -0
index aae8d8b..e5b5eeb 100644

drivers/mmc/core/mmc_ops.c int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, · line 420

Quoted 8 lines
drivers/mmc/core/mmc_ops.c +1 -1
@@ -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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#10 lore raw

cover mmc: update bus speed mode

In reply to Ulf Hansson

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

#11 lore raw

PATCH 1/3 mmc: rework selection of bus speed mode

In reply to Ulf Hansson

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

---
 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(-)
drivers/mmc/core/mmc.c +336 -238
index f631f5a..f4f8991 100644
@@ -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)
include/linux/mmc/card.h +5 -1
index 176fdf8..c119735 100644
@@ -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 */
include/linux/mmc/host.h +0 -6
index 99f5709..69d58b1 100644
@@ -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
include/linux/mmc/mmc.h +4 -0
index 50bcde3..87df508 100644
@@ -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)
Signature · 1 line
1.7.0.4
#12 lore raw

Re: [PATCH 1/3] mmc: rework selection of bus speed mode

Hi Seungwon,

Quoted 4 lines · Seungwon Jeon

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

Quoted 8 lines

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

Quoted 744 lines
---
 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(-)
drivers/mmc/core/mmc.c +336 -238
index f631f5a..f4f8991 100644
@@ -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)
include/linux/mmc/card.h +5 -1
index 176fdf8..c119735 100644
@@ -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 */
include/linux/mmc/host.h +0 -6
index 99f5709..69d58b1 100644
@@ -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
include/linux/mmc/mmc.h +4 -1
index 50bcde3..87df508 100644
@@ -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

#13 lore raw

RE: [PATCH 1/3] mmc: rework selection of bus speed mode

Hi Ulf,

Quoted 16 lines · Ulf Hansson

Hi Seungwon,

Quoted 4 lines · Seungwon Jeon

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

Quoted 8 lines

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

Quoted 4 lines

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

Quoted 752 lines

Kind regards
Ulf Hansson

Quoted 741 lines
---
 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(-)
drivers/mmc/core/mmc.c +336 -238
index f631f5a..f4f8991 100644
@@ -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)
include/linux/mmc/card.h +5 -1
index 176fdf8..c119735 100644
@@ -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 */
include/linux/mmc/host.h +0 -6
index 99f5709..69d58b1 100644
@@ -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
include/linux/mmc/mmc.h +4 -1
index 50bcde3..87df508 100644
@@ -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)
--
Quoted 3 lines

1.7.0.4

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

#14 lore raw

Re: [PATCH 1/3] mmc: rework selection of bus speed mode

Quoted 19 lines · Seungwon Jeon

Hi Ulf,

Quoted 16 lines · Ulf Hansson

Hi Seungwon,

Quoted 12 lines · Seungwon Jeon

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

Quoted 8 lines
Quoted 4 lines

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

Quoted 761 lines

Thanks,
Seungwon Jeon

Quoted 737 lines

Kind regards
Ulf Hansson

Quoted 733 lines
---
 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(-)
drivers/mmc/core/mmc.c +336 -238
index f631f5a..f4f8991 100644
@@ -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)
include/linux/mmc/card.h +5 -1
index 176fdf8..c119735 100644
@@ -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 */
include/linux/mmc/host.h +0 -6
index 99f5709..69d58b1 100644
@@ -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
include/linux/mmc/mmc.h +0 -0
index 50bcde3..87df508 100644
@@ -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 */
 
Quoted 15 lines
Quoted 11 lines
include/linux/mmc/mmc.h +4 -1
+#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 [email protected]
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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#15 lore raw

PATCH 2/3 mmc: correct some exclusive card state to clear

In reply to Ulf Hansson

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.

---
 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(-)
drivers/mmc/core/core.c +0 -1
index 57a2b40..b183d56 100644
@@ -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;
drivers/mmc/core/mmc.c +2 -2
index f4f8991..1668ea4 100644
@@ -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);
 
drivers/mmc/core/sd.c +3 -2
index 6f42050..b19a8f4 100644
@@ -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);
 
drivers/mmc/core/sdio.c +4 -1
index 4d721c6..7c6c43c 100644
@@ -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)
include/linux/mmc/card.h +31 -6
index c119735..f2c2620 100644
@@ -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.
Signature · 1 line
1.7.0.4
#16 lore raw

Re: [PATCH 2/3] mmc: correct some exclusive card state to clear

Hi Seungwon,

Quoted 153 lines · Seungwon Jeon

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.

---
 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(-)
drivers/mmc/core/core.c +0 -1
index 57a2b40..b183d56 100644
@@ -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;
drivers/mmc/core/mmc.c +2 -2
index f4f8991..1668ea4 100644
@@ -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);
 
drivers/mmc/core/sd.c +3 -2
index 6f42050..b19a8f4 100644
@@ -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);
 
drivers/mmc/core/sdio.c +4 -1
index 4d721c6..7c6c43c 100644
@@ -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)
include/linux/mmc/card.h +21 -6
index c119735..f2c2620 100644
@@ -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) | \

include/linux/mmc/card.h static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) · line 471

Quoted 10 lines
include/linux/mmc/card.h +10 -0
+                        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

Quoted 7 lines
include/linux/mmc/card.h +0 -1
 /*
  * Quirk add/remove for MMC products.
--

1.7.0.4

#17 lore raw

RE: [PATCH 2/3] mmc: correct some exclusive card state to clear

Quoted 179 lines · Ulf Hansson

Hi Seungwon,

Quoted 109 lines · Seungwon Jeon

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.

---
 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(-)
drivers/mmc/core/core.c +0 -1
index 57a2b40..b183d56 100644
@@ -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;
drivers/mmc/core/mmc.c +2 -2
index f4f8991..1668ea4 100644
@@ -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);
 
drivers/mmc/core/sd.c +3 -2
index 6f42050..b19a8f4 100644
@@ -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);
 
drivers/mmc/core/sdio.c +4 -1
index 4d721c6..7c6c43c 100644
@@ -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)
include/linux/mmc/card.h +0 -0
index c119735..f2c2620 100644

include/linux/mmc/card.h struct mmc_card { · line 269

Quoted 10 lines
include/linux/mmc/card.h +5 -0
@@ -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

*/

Quoted 34 lines
include/linux/mmc/card.h +16 -6
 #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) | \

include/linux/mmc/card.h static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) · line 471

Quoted 10 lines
include/linux/mmc/card.h +10 -0
+                        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.

Quoted 6 lines

-> 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

Quoted 15 lines

Kind regards
Ulf Hansson

Quoted 7 lines
include/linux/mmc/card.h +0 -1
 /*
  * 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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#18 lore raw

Re: [PATCH 2/3] mmc: correct some exclusive card state to clear

Quoted 185 lines · Seungwon Jeon
Quoted 184 lines · Ulf Hansson

Hi Seungwon,

Quoted 109 lines · Seungwon Jeon

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.

---
 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(-)
drivers/mmc/core/core.c +0 -1
index 57a2b40..b183d56 100644
@@ -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;
drivers/mmc/core/mmc.c +2 -2
index f4f8991..1668ea4 100644
@@ -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);
 
drivers/mmc/core/sd.c +3 -2
index 6f42050..b19a8f4 100644
@@ -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);
 
drivers/mmc/core/sdio.c +4 -1
index 4d721c6..7c6c43c 100644
@@ -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)
include/linux/mmc/card.h +0 -0
index c119735..f2c2620 100644

include/linux/mmc/card.h struct mmc_card { · line 269

Quoted 10 lines
include/linux/mmc/card.h +5 -0
@@ -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

*/

Quoted 34 lines
include/linux/mmc/card.h +16 -6
 #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) | \

include/linux/mmc/card.h static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) · line 471

Quoted 10 lines
include/linux/mmc/card.h +10 -0
+                        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.

Quoted 4 lines
Quoted 1 line

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

Quoted 21 lines

So I guess being kept is not bad.

Thanks,
Seungwon Jeon

Quoted 15 lines

Kind regards
Ulf Hansson

Quoted 7 lines
include/linux/mmc/card.h +0 -1
 /*
  * 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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#19 lore raw

RE: [PATCH 2/3] mmc: correct some exclusive card state to clear

Quoted 193 lines · Ulf Hansson
Quoted 116 lines · Seungwon Jeon
Quoted 115 lines · Ulf Hansson

Hi Seungwon,

Quoted 111 lines · Seungwon Jeon

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.

---
 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(-)
drivers/mmc/core/core.c +0 -1
index 57a2b40..b183d56 100644
@@ -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;
drivers/mmc/core/mmc.c +2 -2
index f4f8991..1668ea4 100644
@@ -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);
 
drivers/mmc/core/sd.c +3 -2
index 6f42050..b19a8f4 100644
@@ -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);
 
drivers/mmc/core/sdio.c +4 -1
index 4d721c6..7c6c43c 100644
@@ -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)
include/linux/mmc/card.h +0 -0
index c119735..f2c2620 100644
@@ -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 */
Quoted 8 lines
Quoted 8 lines

include/linux/mmc/card.h struct mmc_card {

Quoted 8 lines
include/linux/mmc/card.h +5 -0
 #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

Quoted 3 lines
Quoted 3 lines

*/

include/linux/mmc/card.h static inline void __maybe_unused remove_quirk(struct mmc_card *card, int

Quoted 2 lines
include/linux/mmc/card.h +0 -0
 #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)

Quoted 58 lines
Quoted 58 lines
Quoted 32 lines
include/linux/mmc/card.h +16 -6
 #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) | \

include/linux/mmc/card.h static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) · line 471

Quoted 10 lines
include/linux/mmc/card.h +10 -0
+                        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.

Quoted 4 lines
Quoted 1 line

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.

Quoted 5 lines

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

#20 lore raw

PATCH 3/3 mmc: add support for hs400 mode of eMMC5.0

In reply to Ulf Hansson

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.

---
 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(-)
drivers/mmc/core/bus.c +2 -1
index cdca8a7..fd4ba2b 100644
@@ -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);
drivers/mmc/core/mmc.c +120 -8

195 lines not on this page · raw message

include/linux/mmc/card.h +9 -1
index f2c2620..3d41869 100644
@@ -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) | \
include/linux/mmc/host.h +6 -0
index 69d58b1..8e66f4d 100644
@@ -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 */
 
include/linux/mmc/mmc.h +7 -1
index 87df508..7d5c27d 100644
@@ -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)
Signature · 1 line
1.7.0.4
#21 lore raw

RE: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0

Hi Seungwon,

Quoted 10 lines

-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Seungwon Jeon
Sent: Tuesday, November 05, 2013 9:28 PM
To: 'Chris Ball'; 'Ulf Hansson'
Cc: [email protected]
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.

Quoted 20 lines

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.

---
 drivers/mmc/core/bus.c   |    3 +-
 drivers/mmc/core/mmc.c   |  128 +++++++++++++++++++++++++++++++++++++++++++--
(quoted diff) +0 -1
-
 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(-)
drivers/mmc/core/bus.c +0 -0
index cdca8a7..fd4ba2b 100644

drivers/mmc/core/bus.c int mmc_add_card(struct mmc_card *card) · line 358

Quoted 9 lines
drivers/mmc/core/bus.c +2 -1
@@ -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 " :

drivers/mmc/core/mmc.c static void mmc_select_card_type(struct mmc_card *card) · line 284

Quoted 13 lines
drivers/mmc/core/bus.c +0 -0
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
drivers/mmc/core/mmc.c +2 -0
index 1668ea4..7c23b67 100644
@@ -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;

drivers/mmc/core/mmc.c static void mmc_select_card_type(struct mmc_card *card) · line 290

Quoted 6 lines
drivers/mmc/core/mmc.c +6 -0
+		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.

Quoted 108 lines
drivers/mmc/core/mmc.c +6 -0
+		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];
 	}
 
drivers/mmc/core/mmc.c +46 -4
 	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);
+

drivers/mmc/core/mmc.c static int mmc_select_hs_ddr(struct mmc_card *card, u8 · line 1095

Quoted 10 lines
drivers/mmc/core/mmc.c +10 -0
+	/*
+	 * 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?

Quoted 20 lines
drivers/mmc/core/mmc.c +20 -0
+	 */
+	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,

drivers/mmc/core/mmc.c static int mmc_select_hs_ddr(struct mmc_card *card, u8 · line 1125

Quoted 10 lines
drivers/mmc/core/mmc.c +10 -0
+			 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?

Quoted 167 lines
drivers/mmc/core/mmc.c +4 -0
+
+	return 0;
+}
+
 /*
  * For device supporting HS200 mode, the following sequence

* should be done before executing the tuning process.

drivers/mmc/core/mmc.c +16 -4
@@ -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);
include/linux/mmc/card.h +4 -1
index f2c2620..3d41869 100644
@@ -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 */

include/linux/mmc/card.h +1 -0
@@ -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)

include/linux/mmc/card.h +4 -0
@@ -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 = \
include/linux/mmc/card.h +0 -0
 			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
include/linux/mmc/host.h +2 -0
index 69d58b1..8e66f4d 100644
@@ -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) */

include/linux/mmc/host.h +4 -0
@@ -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 */
 
include/linux/mmc/mmc.h +3 -1
index 87df508..7d5c27d 100644
@@ -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 */

include/linux/mmc/mmc.h +3 -1
+#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)
--
Quoted 2 lines

1.7.0.4

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

drivers/mmc/core/debugfs.c +3 -0
index 54829c0..e1f075c 100644
@@ -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

Quoted 5 lines

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

#22 lore raw

RE: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0

Hi Jackey,

On Thur, November 07, 2013, Shen, Jackey wrote

Quoted 10 lines

Hi Seungwon,

Quoted 8 lines

-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Seungwon Jeon
Sent: Tuesday, November 05, 2013 9:28 PM
To: 'Chris Ball'; 'Ulf Hansson'
Cc: [email protected]
Subject: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0

Quoted 4 lines
Quoted 2 lines

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.

Quoted 32 lines
Quoted 21 lines

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.

---
 drivers/mmc/core/bus.c   |    3 +-
 drivers/mmc/core/mmc.c   |  128 +++++++++++++++++++++++++++++++++++++++++++--
(quoted diff) +0 -1
-
 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(-)
drivers/mmc/core/bus.c +0 -0
index cdca8a7..fd4ba2b 100644

drivers/mmc/core/bus.c int mmc_add_card(struct mmc_card *card) · line 358

Quoted 9 lines
drivers/mmc/core/bus.c +2 -1
@@ -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:

Quoted 1 line
			mmc_card_hs400(card) ? "HS400 " :

Ok.

Quoted 12 lines
Quoted 12 lines
drivers/mmc/core/bus.c +0 -0
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
drivers/mmc/core/mmc.c +0 -0
index 1668ea4..7c23b67 100644
@@ -280,6 +280,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_SDR_1_2V;
 	}
 
Quoted 7 lines

drivers/mmc/core/mmc.c static void mmc_select_card_type(struct mmc_card *card) · line 284

Quoted 2 lines
drivers/mmc/core/mmc.c +2 -0
+	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.

Quoted 123 lines

drivers/mmc/core/mmc.c static void mmc_select_card_type(struct mmc_card *card) · line 290

Quoted 7 lines
drivers/mmc/core/mmc.c +6 -0
+		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.

Quoted 113 lines
drivers/mmc/core/mmc.c +6 -0
+		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];
 	}
 
drivers/mmc/core/mmc.c +51 -4
 	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))
Quoted 8 lines

drivers/mmc/core/mmc.c static int mmc_select_hs_ddr(struct mmc_card *card, u8 · line 1095

Quoted 5 lines
drivers/mmc/core/mmc.c +5 -0
+		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.

Quoted 29 lines
Quoted 29 lines
drivers/mmc/core/mmc.c +28 -0
+	 */
+	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);
Quoted 8 lines

drivers/mmc/core/mmc.c static int mmc_select_hs_ddr(struct mmc_card *card, u8 · line 1125

Quoted 2 lines
drivers/mmc/core/mmc.c +2 -0
+	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.

Quoted 178 lines
Quoted 168 lines
drivers/mmc/core/mmc.c +4 -0
+
+	return 0;
+}
+
 /*
  * For device supporting HS200 mode, the following sequence

* should be done before executing the tuning process.

drivers/mmc/core/mmc.c +16 -4
@@ -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);
include/linux/mmc/card.h +4 -1
index f2c2620..3d41869 100644
@@ -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 */

include/linux/mmc/card.h +1 -0
@@ -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)

include/linux/mmc/card.h +4 -0
@@ -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 = \
include/linux/mmc/card.h +0 -0
 			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
include/linux/mmc/host.h +2 -0
index 69d58b1..8e66f4d 100644
@@ -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) */

include/linux/mmc/host.h +4 -0
@@ -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 */
 
include/linux/mmc/mmc.h +3 -1
index 87df508..7d5c27d 100644
@@ -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 */

include/linux/mmc/mmc.h +3 -1
+#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)
--
Quoted 2 lines

1.7.0.4

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

drivers/mmc/core/debugfs.c +0 -0
index 54829c0..e1f075c 100644

drivers/mmc/core/debugfs.c static int mmc_ios_show(struct seq_file *s, void *data) · line 146

Quoted 9 lines
drivers/mmc/core/debugfs.c +3 -0
@@ -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.

Quoted 2 lines

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

#23 lore raw

Re: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0

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

Quoted 445 lines · Seungwon Jeon

Hi Jackey,

On Thur, November 07, 2013, Shen, Jackey wrote

Quoted 10 lines

Hi Seungwon,

Quoted 8 lines

-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Seungwon Jeon
Sent: Tuesday, November 05, 2013 9:28 PM
To: 'Chris Ball'; 'Ulf Hansson'
Cc: [email protected]
Subject: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0

Quoted 4 lines
Quoted 2 lines

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.

Quoted 32 lines
Quoted 21 lines

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.

---
 drivers/mmc/core/bus.c   |    3 +-
 drivers/mmc/core/mmc.c   |  128 +++++++++++++++++++++++++++++++++++++++++++--
(quoted diff) +0 -1
-
 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(-)
drivers/mmc/core/bus.c +0 -0
index cdca8a7..fd4ba2b 100644

drivers/mmc/core/bus.c int mmc_add_card(struct mmc_card *card) · line 358

Quoted 9 lines
drivers/mmc/core/bus.c +2 -1
@@ -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:

Quoted 1 line
			mmc_card_hs400(card) ? "HS400 " :

Ok.

Quoted 12 lines
Quoted 12 lines
drivers/mmc/core/bus.c +0 -0
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
drivers/mmc/core/mmc.c +0 -0
index 1668ea4..7c23b67 100644
@@ -280,6 +280,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_SDR_1_2V;
 	}
 
Quoted 7 lines

drivers/mmc/core/mmc.c static void mmc_select_card_type(struct mmc_card *card) · line 284

Quoted 2 lines
drivers/mmc/core/mmc.c +2 -0
+	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.

Quoted 123 lines

drivers/mmc/core/mmc.c static void mmc_select_card_type(struct mmc_card *card) · line 290

Quoted 7 lines
drivers/mmc/core/mmc.c +6 -0
+		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.

Quoted 113 lines
drivers/mmc/core/mmc.c +6 -0
+		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];
 	}
 
drivers/mmc/core/mmc.c +51 -4
 	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))
Quoted 8 lines

drivers/mmc/core/mmc.c static int mmc_select_hs_ddr(struct mmc_card *card, u8 · line 1095

Quoted 5 lines
drivers/mmc/core/mmc.c +5 -0
+		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.

Quoted 29 lines
Quoted 29 lines
drivers/mmc/core/mmc.c +28 -0
+	 */
+	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);
Quoted 8 lines

drivers/mmc/core/mmc.c static int mmc_select_hs_ddr(struct mmc_card *card, u8 · line 1125

Quoted 2 lines
drivers/mmc/core/mmc.c +2 -0
+	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.

Quoted 178 lines
Quoted 168 lines
drivers/mmc/core/mmc.c +4 -0
+
+	return 0;
+}
+
 /*
  * For device supporting HS200 mode, the following sequence

* should be done before executing the tuning process.

drivers/mmc/core/mmc.c +16 -4
@@ -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);
include/linux/mmc/card.h +4 -1
index f2c2620..3d41869 100644
@@ -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 */

include/linux/mmc/card.h +1 -0
@@ -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)

include/linux/mmc/card.h +4 -0
@@ -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 = \
include/linux/mmc/card.h +0 -0
 			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
include/linux/mmc/host.h +2 -0
index 69d58b1..8e66f4d 100644
@@ -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) */

include/linux/mmc/host.h +4 -0
@@ -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 */
 
include/linux/mmc/mmc.h +3 -1
index 87df508..7d5c27d 100644
@@ -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 */

include/linux/mmc/mmc.h +3 -1
+#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)
--
Quoted 2 lines

1.7.0.4

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

drivers/mmc/core/debugfs.c +0 -0
index 54829c0..e1f075c 100644

drivers/mmc/core/debugfs.c static int mmc_ios_show(struct seq_file *s, void *data) · line 146

Quoted 9 lines
drivers/mmc/core/debugfs.c +3 -0
@@ -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.

Quoted 2 lines

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

#24 lore raw

RE: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0

Quoted 5 lines · Jackey Shen

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.

Quoted 3 lines

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

Quoted 455 lines

Thanks,
Jackey

Quoted 438 lines · Seungwon Jeon

Hi Jackey,

On Thur, November 07, 2013, Shen, Jackey wrote

Quoted 10 lines

Hi Seungwon,

Quoted 8 lines

-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Seungwon Jeon
Sent: Tuesday, November 05, 2013 9:28 PM
To: 'Chris Ball'; 'Ulf Hansson'
Cc: [email protected]
Subject: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0

Quoted 4 lines
Quoted 2 lines

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.

Quoted 32 lines
Quoted 21 lines

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.

---
 drivers/mmc/core/bus.c   |    3 +-
 drivers/mmc/core/mmc.c   |  128 +++++++++++++++++++++++++++++++++++++++++++--
(quoted diff) +0 -1
-
 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(-)
drivers/mmc/core/bus.c +0 -0
index cdca8a7..fd4ba2b 100644

drivers/mmc/core/bus.c int mmc_add_card(struct mmc_card *card) · line 358

Quoted 9 lines
drivers/mmc/core/bus.c +2 -1
@@ -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:

Quoted 1 line
			mmc_card_hs400(card) ? "HS400 " :

Ok.

Quoted 12 lines
Quoted 12 lines
drivers/mmc/core/bus.c +0 -0
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
drivers/mmc/core/mmc.c +0 -0
index 1668ea4..7c23b67 100644
@@ -280,6 +280,18 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_SDR_1_2V;
 	}
 
Quoted 7 lines

drivers/mmc/core/mmc.c static void mmc_select_card_type(struct mmc_card *card) · line 284

Quoted 2 lines
drivers/mmc/core/mmc.c +2 -0
+	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.

Quoted 123 lines

drivers/mmc/core/mmc.c static void mmc_select_card_type(struct mmc_card *card) · line 290

Quoted 7 lines
drivers/mmc/core/mmc.c +6 -0
+		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.

Quoted 113 lines
drivers/mmc/core/mmc.c +6 -0
+		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];
 	}
 
drivers/mmc/core/mmc.c +51 -4
 	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))
Quoted 8 lines

drivers/mmc/core/mmc.c static int mmc_select_hs_ddr(struct mmc_card *card, u8 · line 1095

Quoted 5 lines
drivers/mmc/core/mmc.c +5 -0
+		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.

Quoted 29 lines
Quoted 29 lines
drivers/mmc/core/mmc.c +28 -0
+	 */
+	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);
Quoted 8 lines

drivers/mmc/core/mmc.c static int mmc_select_hs_ddr(struct mmc_card *card, u8 · line 1125

Quoted 2 lines
drivers/mmc/core/mmc.c +2 -0
+	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.

Quoted 178 lines
Quoted 168 lines
drivers/mmc/core/mmc.c +4 -0
+
+	return 0;
+}
+
 /*
  * For device supporting HS200 mode, the following sequence

* should be done before executing the tuning process.

drivers/mmc/core/mmc.c +16 -4
@@ -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);
include/linux/mmc/card.h +4 -1
index f2c2620..3d41869 100644
@@ -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 */

include/linux/mmc/card.h +1 -0
@@ -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)

include/linux/mmc/card.h +4 -0
@@ -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 = \
include/linux/mmc/card.h +0 -0
 			 ((c)->state & ~MMC_STATE_SPEED_MASK) | \
include/linux/mmc/host.h +2 -0
index 69d58b1..8e66f4d 100644
@@ -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) */

include/linux/mmc/host.h +4 -0
@@ -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 */
 
include/linux/mmc/mmc.h +3 -1
index 87df508..7d5c27d 100644
@@ -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 */

include/linux/mmc/mmc.h +3 -1
+#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)
--
Quoted 2 lines

1.7.0.4

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

drivers/mmc/core/debugfs.c +0 -0
index 54829c0..e1f075c 100644

drivers/mmc/core/debugfs.c static int mmc_ios_show(struct seq_file *s, void *data) · line 146

Quoted 9 lines
drivers/mmc/core/debugfs.c +3 -0
@@ -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.

Quoted 1 line
Quoted 7 lines
Quoted 1 line

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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#25 lore raw

Re: [PATCH 3/3] mmc: add support for hs400 mode of eMMC5.0

Quoted 9 lines · Seungwon Jeon
Quoted 5 lines · Jackey Shen

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.

Quoted 1 line
Quoted 6 lines
Quoted 2 lines

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

#26 lore raw
In reply to Ulf Hansson

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

Quoted 7 lines · 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

Quoted 9 lines
 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(-)
Signature · 1 line
1.7.9.5

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

#27 lore raw
Quoted 8 lines · Guennadi Liakhovetski

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

Quoted 26 lines

Thanks
Guennadi

Quoted 7 lines · 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

Quoted 9 lines
 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/

#28 lore raw

cover mmc: distinguish DDR timing mode for eMMC/UHS

In reply to Ulf Hansson

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(-)
#29 lore raw

PATCH 1/7 mmc: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

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

---
 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(-)
drivers/mmc/core/debugfs.c +3 -0
index 54829c0..509229b 100644
@@ -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;
drivers/mmc/core/mmc.c +1 -1
index 98e9eb0..6d91ff7 100644
@@ -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);
 		}
 	}
include/linux/mmc/host.h +2 -1
index 99f5709..87b1f4f 100644
@@ -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
Signature · 1 line
1.7.0.4
author Acked-by on v1 1/7
#30 lore raw

Re: [PATCH 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC

Quoted 4 lines · Seungwon Jeon

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

Quoted 51 lines
---
 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(-)
drivers/mmc/core/debugfs.c +3 -0
index 54829c0..509229b 100644
@@ -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;
drivers/mmc/core/mmc.c +1 -1
index 98e9eb0..6d91ff7 100644
@@ -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);
                }
        }
include/linux/mmc/host.h +2 -2
index 99f5709..87b1f4f 100644
@@ -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

#31 lore raw

Re: [PATCH 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC

Quoted 14 lines · Ulf Hansson
Quoted 4 lines · Seungwon Jeon

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

Quoted 6 lines
---
 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(-)
Quoted 10 lines

drivers/mmc/core/debugfs.c static int mmc_ios_show(struct seq_file *s, void *data) · line 139

Quoted 10 lines
drivers/mmc/core/debugfs.c +2 -0
index 54829c0..509229b 100644
@@ -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

Quoted 35 lines
Quoted 35 lines
drivers/mmc/core/debugfs.c +1 -0
+               break;
        case MMC_TIMING_MMC_HS200:
                str = "mmc high-speed SDR200";
                break;
drivers/mmc/core/mmc.c +1 -1
index 98e9eb0..6d91ff7 100644
@@ -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);
                }
        }
include/linux/mmc/host.h +2 -2
index 99f5709..87b1f4f 100644
@@ -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

#32 lore raw

RE: [PATCH 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC

Hi Ulf,

Quoted 15 lines · Ulf Hansson
Quoted 14 lines · Ulf Hansson
Quoted 4 lines · Seungwon Jeon

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

Quoted 6 lines
---
 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(-)
Quoted 14 lines
Quoted 10 lines

drivers/mmc/core/debugfs.c static int mmc_ios_show(struct seq_file *s, void *data) · line 139

Quoted 10 lines
drivers/mmc/core/debugfs.c +2 -0
index 54829c0..509229b 100644
@@ -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

Quoted 43 lines

Kind regards
Ulf Hansson

Quoted 29 lines
Quoted 29 lines
drivers/mmc/core/debugfs.c +1 -0
+               break;
        case MMC_TIMING_MMC_HS200:
                str = "mmc high-speed SDR200";
                break;
drivers/mmc/core/mmc.c +1 -1
index 98e9eb0..6d91ff7 100644
@@ -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);
                }
        }
include/linux/mmc/host.h +2 -1
index 99f5709..87b1f4f 100644
@@ -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
 
Quoted 6 lines
Quoted 6 lines
include/linux/mmc/host.h +0 -1
 #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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#33 lore raw

Re: [PATCH 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC

Quoted 32 lines · Seungwon Jeon

Hi Ulf,

Quoted 15 lines · Ulf Hansson
Quoted 14 lines · Ulf Hansson
Quoted 4 lines · Seungwon Jeon

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

Quoted 6 lines
---
 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(-)
Quoted 14 lines
Quoted 10 lines

drivers/mmc/core/debugfs.c static int mmc_ios_show(struct seq_file *s, void *data) · line 139

Quoted 10 lines
drivers/mmc/core/debugfs.c +2 -0
index 54829c0..509229b 100644
@@ -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?

Quoted 5 lines

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

Quoted 47 lines

Thanks,
Seungwon Jeon

Quoted 43 lines

Kind regards
Ulf Hansson

Quoted 29 lines
Quoted 29 lines
drivers/mmc/core/debugfs.c +1 -0
+               break;
        case MMC_TIMING_MMC_HS200:
                str = "mmc high-speed SDR200";
                break;
drivers/mmc/core/mmc.c +1 -1
index 98e9eb0..6d91ff7 100644
@@ -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);
                }
        }
include/linux/mmc/host.h +2 -1
index 99f5709..87b1f4f 100644
@@ -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
 
Quoted 6 lines
Quoted 6 lines
include/linux/mmc/host.h +0 -1
 #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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#34 lore raw

PATCH 2/7 mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

Replaced UHS_DDR50 with MMC_DDR52.

---
 drivers/mmc/host/mmci.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/mmc/host/mmci.c +2 -2
index f320579..c348427 100644
@@ -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;
 
 	/*
Signature · 1 line
1.7.0.4
#35 lore raw

Re: [PATCH 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC

Quoted 13 lines · Seungwon Jeon

Replaced UHS_DDR50 with MMC_DDR52.

---
 drivers/mmc/host/mmci.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/mmc/host/mmci.c +0 -0
index f320579..c348427 100644

drivers/mmc/host/mmci.c static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) · line 302

Quoted 5 lines
drivers/mmc/host/mmci.c +1 -1
@@ -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.

drivers/mmc/host/mmci.c static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) · line 788

Quoted 10 lines
drivers/mmc/host/mmci.c +1 -1
                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

Quoted 10 lines
drivers/mmc/host/mmci.c +0 -1
        /*
--

1.7.0.4

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

#36 lore raw

RE: [PATCH 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC

Quoted 29 lines · Ulf Hansson
Quoted 13 lines · Seungwon Jeon

Replaced UHS_DDR50 with MMC_DDR52.

---
 drivers/mmc/host/mmci.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/mmc/host/mmci.c +0 -0
index f320579..c348427 100644

drivers/mmc/host/mmci.c static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) · line 302

Quoted 5 lines
drivers/mmc/host/mmci.c +1 -1
@@ -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.

Quoted 7 lines
drivers/mmc/host/mmci.c +0 -0
                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);
                }
 
Quoted 5 lines

drivers/mmc/host/mmci.c static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) · line 788

Quoted 3 lines
drivers/mmc/host/mmci.c +1 -1
-       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

#37 lore raw

PATCH v2 2/7 mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

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

---
 drivers/mmc/host/mmci.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
drivers/mmc/host/mmci.c +4 -2
index f320579..92d40be 100644
@@ -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;
 
 	/*
Signature · 1 line
1.7.0.4
#38 lore raw

PATCH 3/7 mmc: omap: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

Replaced UHS_DDR50 with MMC_DDR52.

---
 drivers/mmc/host/omap_hsmmc.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/mmc/host/omap_hsmmc.c +2 -2
index dbd32ad..cca397e 100644
@@ -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;
Signature · 1 line
1.7.0.4
#39 lore raw

Re: [PATCH 3/7] mmc: omap: clarify DDR timing mode between SD-UHS and eMMC

Quoted 13 lines · Seungwon Jeon

Replaced UHS_DDR50 with MMC_DDR52.

---
 drivers/mmc/host/omap_hsmmc.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/mmc/host/omap_hsmmc.c +0 -0
index dbd32ad..cca397e 100644

drivers/mmc/host/omap_hsmmc.c static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) · line 543

Quoted 5 lines
drivers/mmc/host/omap_hsmmc.c +1 -1
@@ -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

Quoted 20 lines
drivers/mmc/host/omap_hsmmc.c +1 -2
            ((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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#40 lore raw

Re: [PATCH 3/7] mmc: omap: clarify DDR timing mode between SD-UHS and eMMC

Quoted 9 lines · Ulf Hansson
Quoted 8 lines · Seungwon Jeon

Replaced UHS_DDR50 with MMC_DDR52.

---
  drivers/mmc/host/omap_hsmmc.c |    4 ++--
  1 files changed, 2 insertions(+), 2 deletions(-)
Quoted 16 lines

drivers/mmc/host/omap_hsmmc.c static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) · line 543

Quoted 10 lines
drivers/mmc/host/omap_hsmmc.c +1 -1
index dbd32ad..cca397e 100644
@@ -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.

Quoted 1 line

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

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

Quoted 3 lines

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

Quoted 26 lines

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

Kind regards
Ulf Hansson

Quoted 20 lines
drivers/mmc/host/omap_hsmmc.c +1 -2
             ((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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Acked-by on v1 3/7
#41 lore raw

Re: [PATCH 3/7] mmc: omap: clarify DDR timing mode between SD-UHS and eMMC

In reply to Seungwon Jeon
Quoted 4 lines · Seungwon Jeon

Replaced UHS_DDR50 with MMC_DDR52.

Looks good to me

Quoted 27 lines
---
  drivers/mmc/host/omap_hsmmc.c |    4 ++--
  1 files changed, 2 insertions(+), 2 deletions(-)
drivers/mmc/host/omap_hsmmc.c +2 -2
index dbd32ad..cca397e 100644
@@ -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;
#42 lore raw

PATCH 4/7 mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

Replaced UHS_DDR50 with MMC_DDR52.

CC Guennadi Liakhovetski <[email protected]>
---
 drivers/mmc/host/sh_mmcif.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)
drivers/mmc/host/sh_mmcif.c +5 -4
index 54730f4..656fbba 100644
@@ -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;
Signature · 1 line
1.7.0.4
#43 lore raw

Re: [PATCH 4/7] mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC

Quoted 13 lines · Seungwon Jeon

Replaced UHS_DDR50 with MMC_DDR52.

CC Guennadi Liakhovetski <[email protected]>
---
 drivers/mmc/host/sh_mmcif.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)
drivers/mmc/host/sh_mmcif.c +0 -0
index 54730f4..656fbba 100644

drivers/mmc/host/sh_mmcif.c static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, · line 806

Quoted 5 lines
drivers/mmc/host/sh_mmcif.c +1 -1
@@ -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

Quoted 16 lines
drivers/mmc/host/sh_mmcif.c +4 -4
                        /*
                         * 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

#44 lore raw

RE: [PATCH 4/7] mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC

Quoted 9 lines · Ulf Hansson
Quoted 8 lines · Seungwon Jeon

Replaced UHS_DDR50 with MMC_DDR52.

CC Guennadi Liakhovetski <[email protected]>
---
 drivers/mmc/host/sh_mmcif.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)
Quoted 12 lines

drivers/mmc/host/sh_mmcif.c static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, · line 806

Quoted 10 lines
drivers/mmc/host/sh_mmcif.c +1 -1
index 54730f4..656fbba 100644
@@ -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

Quoted 24 lines

Kind regards
Ulf Hansson

Quoted 13 lines
drivers/mmc/host/sh_mmcif.c +4 -4
                        /*
                         * 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;
--
Quoted 3 lines

1.7.0.4

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

#45 lore raw

RE: [PATCH 4/7] mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

Hi Guennadi,

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

Thanks,
Seungwon Jeon

Quoted 55 lines · Seungwon Jeon
Quoted 9 lines · Ulf Hansson
Quoted 8 lines · Seungwon Jeon

Replaced UHS_DDR50 with MMC_DDR52.

CC Guennadi Liakhovetski <[email protected]>
---
 drivers/mmc/host/sh_mmcif.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)
Quoted 12 lines

drivers/mmc/host/sh_mmcif.c static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, · line 806

Quoted 10 lines
drivers/mmc/host/sh_mmcif.c +1 -1
index 54730f4..656fbba 100644
@@ -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

Quoted 24 lines

Kind regards
Ulf Hansson

Quoted 13 lines
drivers/mmc/host/sh_mmcif.c +4 -4
                        /*
                         * 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;
--
Quoted 3 lines

1.7.0.4

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

#46 lore raw

PATCH 5/7 mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

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

---
 drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/mmc/host/rtsx_pci_sdmmc.c +2 -0
index c46feda..752f003 100644
@@ -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;
Signature · 1 line
1.7.0.4
author Reviewed-by on v1 5/7
#47 lore raw

Re: [PATCH 5/7] mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC

Quoted 5 lines · Seungwon Jeon

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

Quoted 32 lines
---
 drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/mmc/host/rtsx_pci_sdmmc.c +2 -1
index c46feda..752f003 100644
@@ -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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#48 lore raw

PATCH 6/7 mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

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

---
 drivers/mmc/host/dw_mmc-exynos.c |    3 +--
 drivers/mmc/host/dw_mmc.c        |    2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)
drivers/mmc/host/dw_mmc-exynos.c +1 -2
index 3423c5e..b5a36b1 100644
@@ -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,
drivers/mmc/host/dw_mmc.c +1 -1
index a776f24..99390bb 100644
@@ -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);
Signature · 1 line
1.7.0.4
author Reviewed-by on v1 6/7
#49 lore raw

Re: [PATCH 6/7] mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC

Quoted 4 lines · Seungwon Jeon

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

Quoted 40 lines
---
 drivers/mmc/host/dw_mmc-exynos.c |    3 +--
 drivers/mmc/host/dw_mmc.c        |    2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)
drivers/mmc/host/dw_mmc-exynos.c +1 -2
index 3423c5e..b5a36b1 100644
@@ -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,
drivers/mmc/host/dw_mmc.c +1 -2
index a776f24..99390bb 100644
@@ -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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#50 lore raw

PATCH 7/7 mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

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

---
 drivers/mmc/host/sdhci.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
drivers/mmc/host/sdhci.c +3 -1
index ec3eb30..6c3482a 100644
@@ -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);
 		}
Signature · 1 line
1.7.0.4
author Reviewed-by on v1 7/7
#51 lore raw

Re: [PATCH 7/7] mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC

Quoted 3 lines · Seungwon Jeon

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

Quoted 34 lines
---
 drivers/mmc/host/sdhci.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
drivers/mmc/host/sdhci.c +3 -2
index ec3eb30..6c3482a 100644
@@ -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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#52 lore raw

cover update selection of bus speed mode for eMMC

In reply to Ulf Hansson

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(-)
#53 lore raw

PATCH 1/5 mmc: drop the speed mode of card's state

In reply to Ulf Hansson

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

---
 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(-)
drivers/mmc/core/bus.c +5 -4
index 64145a3..e8a21fb 100644
@@ -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);
 	}
 
drivers/mmc/core/core.c +1 -2
index 098374b..88433bd 100644
@@ -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;
drivers/mmc/core/mmc.c +3 -8
index 6d91ff7..613e641 100644
@@ -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);
drivers/mmc/core/sd.c +3 -13
index 692fdb1..54dd3d1 100644
@@ -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);
drivers/mmc/core/sd.h +0 -1
index 4b34b24..aab824a 100644
@@ -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
drivers/mmc/core/sdio.c +2 -6
index 4d721c6..ef57d2d 100644
@@ -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;
 
include/linux/mmc/card.h +7 -17
index 176fdf8..fb13bf9 100644
@@ -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)
include/linux/mmc/host.h +23 -0
index 87b1f4f..71977f4 100644
@@ -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 */
Signature · 1 line
1.7.0.4
#54 lore raw

PATCH 2/5 mmc: identify available device type to select

In reply to Ulf Hansson

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.

---
 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(-)
drivers/mmc/core/mmc.c +44 -33
index 613e641..1ea155a 100644
@@ -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)
include/linux/mmc/card.h +4 -2
index fb13bf9..86d4572 100644
@@ -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 */
include/linux/mmc/host.h +0 -6
index 71977f4..66e632c 100644
@@ -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
include/linux/mmc/mmc.h +8 -4
index 50bcde3..f734c0c 100644
@@ -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 */
Signature · 1 line
1.7.0.4
#55 lore raw

PATCH 3/5 mmc: step power class after final selection of bus mode

In reply to Ulf Hansson

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

---
 drivers/mmc/core/mmc.c |   77 +++++++++++++++++++++++++++++++----------------
 1 files changed, 51 insertions(+), 26 deletions(-)
drivers/mmc/core/mmc.c +51 -26
index 1ea155a..92aa004 100644
@@ -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) {
Signature · 1 line
1.7.0.4
#56 lore raw

PATCH 4/5 mmc: rework selection of bus speed mode

In reply to Ulf Hansson

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

---
 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(-)
drivers/mmc/core/debugfs.c +1 -1
index 509229b..1f730db 100644
@@ -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";
drivers/mmc/core/mmc.c +251 -192

526 lines not on this page · raw message

include/linux/mmc/card.h +1 -0
index 86d4572..c278241 100644
@@ -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
include/linux/mmc/mmc.h +4 -0
index f734c0c..f429f13 100644
@@ -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)
Signature · 1 line
1.7.0.4
#57 lore raw

PATCH 5/5 mmc: add support for HS400 mode of eMMC5.0

In reply to Ulf Hansson

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.

---
 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(-)
drivers/mmc/core/bus.c +1 -0
index e8a21fb..d28ecf1 100644
@@ -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);
drivers/mmc/core/debugfs.c +3 -0
index 1f730db..91eb162 100644
@@ -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;
drivers/mmc/core/mmc.c +119 -7

198 lines not on this page · raw message

include/linux/mmc/card.h +1 -0
index c278241..eabddfb 100644
@@ -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 */
 
include/linux/mmc/host.h +14 -1
index 66e632c..7c0e277 100644
@@ -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 */
include/linux/mmc/mmc.h +6 -1
index f429f13..64ec963 100644
@@ -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)
Signature · 1 line
1.7.0.4
#58 lore raw

Re: [PATCH 5/5] mmc: add support for HS400 mode of eMMC5.0

Quoted 159 lines · Seungwon Jeon

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.

---
 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(-)
drivers/mmc/core/bus.c +1 -0
index e8a21fb..d28ecf1 100644
@@ -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);
drivers/mmc/core/debugfs.c +3 -0
index 1f730db..91eb162 100644
@@ -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;
drivers/mmc/core/mmc.c +50 -5
index 6ce5ff3..f3c899d 100644
@@ -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)

drivers/mmc/core/mmc.c static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd) · line 1068

Quoted 4 lines
drivers/mmc/core/mmc.c +1 -0
@@ -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

Quoted 198 lines
drivers/mmc/core/mmc.c +68 -2
+{
+	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);
include/linux/mmc/card.h +1 -0
index c278241..eabddfb 100644
@@ -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 */
 
include/linux/mmc/host.h +14 -1
index 66e632c..7c0e277 100644
@@ -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 */
include/linux/mmc/mmc.h +6 -1
index f429f13..64ec963 100644
@@ -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)
Signature · 7 lines
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#59 lore raw

RE: [PATCH 5/5] mmc: add support for HS400 mode of eMMC5.0

Quoted 163 lines · Jackey Shen
Quoted 162 lines · Seungwon Jeon

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.

---
 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(-)
drivers/mmc/core/bus.c +1 -0
index e8a21fb..d28ecf1 100644
@@ -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);
drivers/mmc/core/debugfs.c +3 -0
index 1f730db..91eb162 100644
@@ -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;
drivers/mmc/core/mmc.c +50 -5
index 6ce5ff3..f3c899d 100644
@@ -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;
 }
 
Quoted 5 lines

drivers/mmc/core/mmc.c static int mmc_select_hs_ddr(struct mmc_card *card, u8 *ext_csd) · line 1068

Quoted 1 line
drivers/mmc/core/mmc.c +1 -0
+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

Quoted 206 lines

Thanks,
Jackey

Quoted 193 lines
drivers/mmc/core/mmc.c +68 -2
+{
+	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);
include/linux/mmc/card.h +1 -0
index c278241..eabddfb 100644
@@ -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 */
 
include/linux/mmc/host.h +14 -1
index 66e632c..7c0e277 100644
@@ -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 */
include/linux/mmc/mmc.h +6 -2
index f429f13..64ec963 100644
@@ -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

Quoted 5 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to [email protected]
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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#60 lore raw

v2 cover mmc: distinguish DDR timing mode for eMMC/UHS

In reply to Ulf Hansson

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(-)
#61 lore raw

v3 cover mmc: distinguish DDR timing mode for eMMC/UHS

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

#62 lore raw

v3 cover mmc: distinguish DDR timing mode for eMMC/UHS

In reply to Seungwon Jeon

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

#63 lore raw

Re: [PATCH RESEND v3 0/7] mmc: distinguish DDR timing mode for eMMC/UHS

Quoted 3 lines · Seungwon Jeon

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.

Quoted 1 line

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

Quoted 32 lines

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

#64 lore raw

RE: [PATCH RESEND v3 0/7] mmc: distinguish DDR timing mode for eMMC/UHS

Quoted 7 lines · Ulf Hansson
Quoted 3 lines · Seungwon Jeon

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

Quoted 45 lines

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

Quoted 29 lines

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(-)>
Quoted 3 lines

Thanks,
sw-j

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

#65 lore raw

PATCH v2 1/7 mmc: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

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

---
 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(-)
drivers/mmc/core/debugfs.c +3 -0
index 54829c0..509229b 100644
@@ -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;
drivers/mmc/core/mmc.c +1 -1
index 98e9eb0..6d91ff7 100644
@@ -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);
 		}
 	}
include/linux/mmc/host.h +2 -1
index 99f5709..87b1f4f 100644
@@ -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
Signature · 1 line
1.7.0.4
#66 lore raw

PATCH v3 1/7 mmc: clarify DDR timing mode between SD-UHS and eMMC

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

---
 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(-)
drivers/mmc/core/debugfs.c +3 -0
index 54829c0..509229b 100644
@@ -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;
drivers/mmc/core/mmc.c +1 -1
index 1ab5f3a..e22d851 100644
@@ -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);
 		}
 	}
include/linux/mmc/host.h +2 -1
index cb61ea4..3535420 100644
@@ -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
Signature · 1 line
1.7.0.4
maintainer Acked-by on v3 1/7
#67 lore raw

Re: [PATCH v3 1/7] mmc: clarify DDR timing mode between SD-UHS and eMMC

Best Regards,
Jaehoon Chung

Quoted 53 lines · Seungwon Jeon

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

---
 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(-)
drivers/mmc/core/debugfs.c +3 -0
index 54829c0..509229b 100644
@@ -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;
drivers/mmc/core/mmc.c +1 -1
index 1ab5f3a..e22d851 100644
@@ -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);
 		}
 	}
include/linux/mmc/host.h +2 -1
index cb61ea4..3535420 100644
@@ -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
#68 lore raw

PATCH RESEND v3 1/7 mmc: clarify DDR timing mode between SD-UHS and eMMC

In reply to Seungwon Jeon

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

---
 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(-)
drivers/mmc/core/debugfs.c +3 -0
index 54829c0..509229b 100644
@@ -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;
drivers/mmc/core/mmc.c +1 -1
index 1ab5f3a..e22d851 100644
@@ -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);
 		}
 	}
include/linux/mmc/host.h +2 -1
index cb61ea4..3535420 100644
@@ -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
Signature · 1 line
1.7.0.4
#69 lore raw

PATCH v2 2/7 mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

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

---
 drivers/mmc/host/mmci.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
drivers/mmc/host/mmci.c +4 -2
index b931226..421d1fe 100644
@@ -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;
 
 	/*
Signature · 1 line
1.7.0.4
author Acked-by on v2 2/7
#70 lore raw

Re: [PATCH v2 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC

Quoted 4 lines · Seungwon Jeon

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

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

Quoted 32 lines
---
 drivers/mmc/host/mmci.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
drivers/mmc/host/mmci.c +4 -3
index b931226..421d1fe 100644
@@ -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

#71 lore raw

RE: [PATCH v2 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC

Quoted 6 lines · Ulf Hansson
Quoted 4 lines · Seungwon Jeon

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

Quoted 7 lines

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

Quoted 40 lines

Kind regards
Ulf Hansson

Quoted 29 lines
---
 drivers/mmc/host/mmci.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
drivers/mmc/host/mmci.c +4 -3
index b931226..421d1fe 100644
@@ -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;
 
        /*
--
Quoted 3 lines

1.7.0.4

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

#72 lore raw

PATCH v3 2/7 mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC

In reply to Seungwon Jeon

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

---
 drivers/mmc/host/mmci.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
drivers/mmc/host/mmci.c +4 -2
index 771c60a..7e85393 100644
@@ -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;
 
 	/*
Signature · 1 line
1.7.0.4
#73 lore raw

PATCH RESEND v3 2/7 mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC

In reply to Seungwon Jeon

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

---
 drivers/mmc/host/mmci.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
drivers/mmc/host/mmci.c +4 -2
index 771c60a..7e85393 100644
@@ -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;
 
 	/*
Signature · 1 line
1.7.0.4
#74 lore raw

PATCH v2 3/7 mmc: omap: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

Replaced UHS_DDR50 with MMC_DDR52.

---
 drivers/mmc/host/omap_hsmmc.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/mmc/host/omap_hsmmc.c +2 -2
index dbd32ad..cca397e 100644
@@ -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;
Signature · 1 line
1.7.0.4
#75 lore raw

PATCH v3 3/7 mmc: omap: clarify DDR timing mode between SD-UHS and eMMC

Replaced UHS_DDR50 with MMC_DDR52.

---
 drivers/mmc/host/omap_hsmmc.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/mmc/host/omap_hsmmc.c +2 -2
index e91ee21..b4de63b 100644
@@ -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;
Signature · 1 line
1.7.0.4
#76 lore raw

PATCH RESEND v3 3/7 mmc: omap: clarify DDR timing mode between SD-UHS and eMMC

In reply to Seungwon Jeon

Replaced UHS_DDR50 with MMC_DDR52.

---
 drivers/mmc/host/omap_hsmmc.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/mmc/host/omap_hsmmc.c +2 -2
index e91ee21..b4de63b 100644
@@ -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;
Signature · 1 line
1.7.0.4
#77 lore raw

PATCH v2 4/7 mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

Replaced UHS_DDR50 with MMC_DDR52.

CC Guennadi Liakhovetski <[email protected]>
---
 drivers/mmc/host/sh_mmcif.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)
drivers/mmc/host/sh_mmcif.c +5 -4
index 54730f4..656fbba 100644
@@ -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;
Signature · 1 line
1.7.0.4
#78 lore raw

PATCH v3 4/7 mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC

Replaced UHS_DDR50 with MMC_DDR52.

CC Guennadi Liakhovetski <[email protected]>
---
 drivers/mmc/host/sh_mmcif.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)
drivers/mmc/host/sh_mmcif.c +5 -4
index 54730f4..656fbba 100644
@@ -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;
Signature · 1 line
1.7.0.4
#79 lore raw

PATCH RESEND v3 4/7 mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC

In reply to Seungwon Jeon

Replaced UHS_DDR50 with MMC_DDR52.

CC Guennadi Liakhovetski <[email protected]>
---
 drivers/mmc/host/sh_mmcif.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)
drivers/mmc/host/sh_mmcif.c +5 -4
index 54730f4..656fbba 100644
@@ -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;
Signature · 1 line
1.7.0.4
#80 lore raw

PATCH v2 5/7 mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

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

---
 drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/mmc/host/rtsx_pci_sdmmc.c +2 -0
index c46feda..752f003 100644
@@ -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;
Signature · 1 line
1.7.0.4
#81 lore raw

PATCH v3 5/7 mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC

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

---
 drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/mmc/host/rtsx_pci_sdmmc.c +2 -0
index 5fb994f..8c2dd30 100644
@@ -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;
Signature · 1 line
1.7.0.4
#82 lore raw

PATCH RESEND v3 5/7 mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC

In reply to Seungwon Jeon

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

---
 drivers/mmc/host/rtsx_pci_sdmmc.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/mmc/host/rtsx_pci_sdmmc.c +2 -0
index 5fb994f..8c2dd30 100644
@@ -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;
Signature · 1 line
1.7.0.4
#83 lore raw

PATCH v2 6/7 mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

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

---
 drivers/mmc/host/dw_mmc-exynos.c |    3 +--
 drivers/mmc/host/dw_mmc.c        |    2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)
drivers/mmc/host/dw_mmc-exynos.c +1 -2
index 3423c5e..b5a36b1 100644
@@ -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,
drivers/mmc/host/dw_mmc.c +1 -1
index 55cd110..7866d78 100644
@@ -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);
Signature · 1 line
1.7.0.4
#84 lore raw

PATCH v3 6/7 mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC

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

---
 drivers/mmc/host/dw_mmc-exynos.c |    5 ++---
 drivers/mmc/host/dw_mmc.c        |    2 +-
 2 files changed, 3 insertions(+), 4 deletions(-)
drivers/mmc/host/dw_mmc-exynos.c +2 -3
index 3423c5e..a67e784 100644
@@ -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,
drivers/mmc/host/dw_mmc.c +1 -1
index 0c56faa..ab704d9 100644
@@ -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);
Signature · 1 line
1.7.0.4
maintainer Acked-by on v3 6/7
#85 lore raw

Re: [PATCH v3 6/7] mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC

Best Regards,
Jaehoon Chung

Quoted 47 lines · Seungwon Jeon

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

---
 drivers/mmc/host/dw_mmc-exynos.c |    5 ++---
 drivers/mmc/host/dw_mmc.c        |    2 +-
 2 files changed, 3 insertions(+), 4 deletions(-)
drivers/mmc/host/dw_mmc-exynos.c +2 -3
index 3423c5e..a67e784 100644
@@ -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,
drivers/mmc/host/dw_mmc.c +1 -1
index 0c56faa..ab704d9 100644
@@ -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);
#86 lore raw

PATCH v3 6/7 mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC

In reply to Seungwon Jeon

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

---
 drivers/mmc/host/dw_mmc-exynos.c |    5 ++---
 drivers/mmc/host/dw_mmc.c        |    2 +-
 2 files changed, 3 insertions(+), 4 deletions(-)
drivers/mmc/host/dw_mmc-exynos.c +2 -3
index 3423c5e..a67e784 100644
@@ -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,
drivers/mmc/host/dw_mmc.c +1 -1
index 0c56faa..ab704d9 100644
@@ -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);
Signature · 1 line
1.7.0.4
#87 lore raw

PATCH v2 7/7 mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC

In reply to Ulf Hansson

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

---
 drivers/mmc/host/sdhci.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
drivers/mmc/host/sdhci.c +3 -1
index 9ddef47..92e55dd 100644
@@ -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);
 		}
Signature · 1 line
1.7.0.4
#88 lore raw

PATCH v3 7/7 mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC

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

---
 drivers/mmc/host/sdhci.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
drivers/mmc/host/sdhci.c +3 -1
index 7f95211..6926b42 100644
@@ -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);
 		}
Signature · 1 line
1.7.0.4
#89 lore raw

PATCH RESEND v3 7/7 mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC

In reply to Seungwon Jeon

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

---
 drivers/mmc/host/sdhci.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
drivers/mmc/host/sdhci.c +3 -1
index 7f95211..6926b42 100644
@@ -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);
 		}
Signature · 1 line
1.7.0.4
#90 lore raw

cover update selection of bus speed mode for eMMC

In reply to Ulf Hansson

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(-)
#91 lore raw

v2 cover update selection of bus speed mode for eMMC

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(-)
#92 lore raw

Re: [PATCH v2 0/5] update selection of bus speed mode for eMMC

Quoted 8 lines · Seungwon Jeon

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.

Quoted 7 lines

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

Quoted 13 lines
 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(-)
maintainer Tested-by Acked-by on the v1 series
#93 lore raw

Re: [PATCH RESEND 0/5] update selection of bus speed mode for eMMC

In reply to Seungwon Jeon

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

Quoted 33 lines · Seungwon Jeon

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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#94 lore raw

v3 cover update selection of bus speed mode for eMMC

In reply to Seungwon Jeon

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

#95 lore raw

Re: [PATCH v3 0/5] update selection of bus speed mode for eMMC

Quoted 8 lines · Seungwon Jeon

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

Quoted 23 lines

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

#96 lore raw

RE: [PATCH v3 0/5] update selection of bus speed mode for eMMC

Quoted 6 lines · Ulf Hansson
Quoted 5 lines · Seungwon Jeon

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.

Quoted 6 lines
Quoted 3 lines

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

Quoted 31 lines

Kind regards
Ulf Hansson

Quoted 20 lines

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(-)
Quoted 3 lines

Thanks,
Sw-j

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

maintainer
#97 lore raw

Re: [PATCH v3 0/5] update selection of bus speed mode for eMMC

Quoted 11 lines · Seungwon Jeon
Quoted 10 lines · Ulf Hansson
Quoted 8 lines · Seungwon Jeon

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.

Quoted 6 lines
Quoted 2 lines

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

Quoted 37 lines

Thanks,
Seungwon Jeon

Quoted 31 lines

Kind regards
Ulf Hansson

Quoted 20 lines

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(-)
Quoted 3 lines

Thanks,
Sw-j

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

#98 lore raw

Re: [PATCH v3 0/5] update selection of bus speed mode for eMMC

Quoted 12 lines · Jaehoon Chung
Quoted 11 lines · Seungwon Jeon
Quoted 10 lines · Ulf Hansson
Quoted 8 lines · Seungwon Jeon

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.

Quoted 6 lines
Quoted 6 lines
Quoted 2 lines

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

Quoted 43 lines

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

Best Regards,
Jaehoon Chung

Quoted 37 lines

Thanks,
Seungwon Jeon

Quoted 31 lines

Kind regards
Ulf Hansson

Quoted 20 lines

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(-)
Quoted 3 lines

Thanks,
Sw-j

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

#99 lore raw

v4 cover update selection of bus speed mode for eMMC

In reply to Seungwon Jeon

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

#100 lore raw

PATCH v4 1/5 mmc: drop the speed mode of card's state

In reply to Seungwon Jeon

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

---
 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(-)
drivers/mmc/core/bus.c +4 -4
index 8246448..f37e9d6 100644
@@ -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);
 	}
 
drivers/mmc/core/core.c +1 -2
index acbc3f2..aa9f679 100644
@@ -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;
drivers/mmc/core/mmc.c +3 -8
index e22d851..db9655f 100644
@@ -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);
drivers/mmc/core/sd.c +3 -13
index 2dd359d..9fc5b31 100644
@@ -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);
drivers/mmc/core/sd.h +0 -1
index 4b34b24..aab824a 100644
@@ -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
drivers/mmc/core/sdio.c +2 -6
index 4d721c6..ef57d2d 100644
@@ -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;
 
include/linux/mmc/card.h +6 -17
index b730272..5473133 100644
@@ -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)
include/linux/mmc/host.h +23 -0
index 3535420..2f263ae 100644
@@ -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 */
Signature · 1 line
1.7.0.4
#101 lore raw

PATCH v4 2/5 mmc: identify available device type to select

In reply to Seungwon Jeon

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.

---
 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(-)
drivers/mmc/core/mmc.c +39 -33
index db9655f..97f1912 100644
@@ -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)
include/linux/mmc/card.h +4 -2
index 5473133..c232b10 100644
@@ -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 */
include/linux/mmc/host.h +0 -6
index 2f263ae..1ee3c10 100644
@@ -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
include/linux/mmc/mmc.h +8 -4
index 50bcde3..f734c0c 100644
@@ -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 */
Signature · 1 line
1.7.0.4
#102 lore raw

PATCH v4 3/5 mmc: step power class after final selection of bus mode

In reply to Seungwon Jeon

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

---
 drivers/mmc/core/mmc.c |   96 +++++++++++++++++++++++++++--------------------
 1 files changed, 55 insertions(+), 41 deletions(-)
drivers/mmc/core/mmc.c +55 -41
index 97f1912..480c100 100644
@@ -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) {
Signature · 1 line
1.7.0.4
author Acked-by on v4 3/5
#103 lore raw

Re: [PATCH v4 3/5] mmc: step power class after final selection of bus mode

Quoted 6 lines · Seungwon Jeon

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

Quoted 168 lines
---
 drivers/mmc/core/mmc.c |   96 +++++++++++++++++++++++++++--------------------
 1 files changed, 55 insertions(+), 41 deletions(-)
drivers/mmc/core/mmc.c +55 -42
index 97f1912..480c100 100644
@@ -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

#104 lore raw

PATCH v4 4/5 mmc: rework selection of bus speed mode

In reply to Seungwon Jeon

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

---
 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(-)
drivers/mmc/core/debugfs.c +1 -1
index 509229b..1f730db 100644
@@ -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";
drivers/mmc/core/mmc.c +232 -199

510 lines not on this page · raw message

include/linux/mmc/card.h +1 -0
index c232b10..def6814 100644
@@ -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
include/linux/mmc/mmc.h +4 -0
index f734c0c..f429f13 100644
@@ -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)
Signature · 1 line
1.7.0.4
#105 lore raw

PATCH v4 5/5 mmc: add support for HS400 mode of eMMC5.0

In reply to Seungwon Jeon

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.

---
 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(-)
drivers/mmc/core/bus.c +1 -0
index f37e9d6..d2dbf02 100644
@@ -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);
drivers/mmc/core/debugfs.c +3 -0
index 1f730db..91eb162 100644
@@ -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;
drivers/mmc/core/mmc.c +94 -6

160 lines not on this page · raw message

include/linux/mmc/card.h +1 -0
index def6814..2b24c36 100644
@@ -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 */
 
include/linux/mmc/host.h +14 -1
index 1ee3c10..cc716e4 100644
@@ -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 */
include/linux/mmc/mmc.h +6 -1
index f429f13..64ec963 100644
@@ -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)
Signature · 1 line
1.7.0.4
#106 lore raw

v5 cover update selection of bus speed mode for eMMC

In reply to Seungwon Jeon

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

#107 lore raw

PATCH v5 1/5 mmc: drop the speed mode of card's state

In reply to Seungwon Jeon

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

---
 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(-)
drivers/mmc/core/bus.c +4 -4
index 8246448..f37e9d6 100644
@@ -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);
 	}
 
drivers/mmc/core/core.c +1 -2
index acbc3f2..aa9f679 100644
@@ -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;
drivers/mmc/core/mmc.c +3 -8
index e22d851..db9655f 100644
@@ -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);
drivers/mmc/core/sd.c +3 -13
index 2dd359d..9fc5b31 100644
@@ -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);
drivers/mmc/core/sd.h +0 -1
index 4b34b24..aab824a 100644
@@ -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
drivers/mmc/core/sdio.c +2 -6
index 4d721c6..ef57d2d 100644
@@ -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;
 
include/linux/mmc/card.h +6 -17
index b730272..5473133 100644
@@ -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)
include/linux/mmc/host.h +23 -0
index 3535420..2f263ae 100644
@@ -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 */
Signature · 1 line
1.7.0.4
#108 lore raw

PATCH v5 2/5 mmc: identify available device type to select

In reply to Seungwon Jeon

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.

---
 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(-)
drivers/mmc/core/mmc.c +39 -33
index db9655f..97f1912 100644
@@ -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)
include/linux/mmc/card.h +1 -1
index 5473133..b9f194a 100644
@@ -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 */
include/linux/mmc/host.h +0 -6
index 2f263ae..1ee3c10 100644
@@ -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
include/linux/mmc/mmc.h +8 -4
index 50bcde3..f734c0c 100644
@@ -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 */
Signature · 1 line
1.7.0.4