mmc: tmio: Use modern PM ops
Subsystems (9)
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
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
@@ -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
Re: [PATCH 1/3] mmc: sh_mobile_sdhi: Use modern PM macros to define pm callbacks
Quoted 1 line · Ulf Hansson
Signed-off-by Ulf Hansson <[email protected]>
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@@ -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/
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
@@ -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
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
Signed-off-by Ulf Hansson <[email protected]>--- drivers/mmc/host/tmio_mmc.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-)drivers/mmc/host/tmio_mmc.c +0
-0@@ -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
-2int 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
-1return 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
-6if (!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/
PATCH 3/3 mmc: tmio: Adapt to proper PM configs for exported functions
In reply to Ulf HanssonSince 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
@@ -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
@@ -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
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.
Signed-off-by Ulf Hansson <[email protected]>
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@@ -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@@ -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/
PATCH 1/1 mmc: trivial: fix the compiling warning
In reply to Ulf HanssonFixed 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
@@ -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
Jaehoon Chung
maintainerRe: [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]Signed-off-by Seungwon Jeon <[email protected]>--- drivers/mmc/core/mmc_ops.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)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);
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 ChungQuoted 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]Signed-off-by Seungwon Jeon <[email protected]>--- drivers/mmc/core/mmc_ops.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)drivers/mmc/core/mmc_ops.c +0
-0drivers/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
cover mmc: update bus speed mode
In reply to Ulf HanssonThis 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
PATCH 1/3 mmc: rework selection of bus speed mode
In reply to Ulf HanssonCurrent 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
@@ -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
@@ -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
@@ -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
@@ -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
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 modeselection(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 HS200mode(hs200_max_dtr)
* Adds available device type to be supported by both host and device
* Adds field definition forHS_TIMINGofEXT_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
Signed-off-by Seungwon Jeon <[email protected]>--- 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@@ -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@@ -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@@ -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 0include/linux/mmc/mmc.h +4
-1@@ -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
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 modeselection(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 HS200mode(hs200_max_dtr)
* Adds available device type to be supported by both host and device
* Adds field definition forHS_TIMINGofEXT_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 HanssonQuoted 741 lines
Signed-off-by Seungwon Jeon <[email protected]>--- 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@@ -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@@ -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@@ -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 0include/linux/mmc/mmc.h +4
-1@@ -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
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 modeselection(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 HS200mode(hs200_max_dtr)
* Adds available device type to be supported by both host and device
* Adds field definition forHS_TIMINGofEXT_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 JeonQuoted 737 lines
Kind regards
Ulf HanssonQuoted 733 lines
Signed-off-by Seungwon Jeon <[email protected]>--- 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@@ -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@@ -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@@ -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 0include/linux/mmc/mmc.h +0
-0@@ -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
PATCH 2/3 mmc: correct some exclusive card state to clear
In reply to Ulf HanssonCard 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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_PRESENTandMMC_STATE_REMOVEDare same. It's exclusive state which cannot be set at the same time.Signed-off-by Seungwon Jeon <[email protected]>--- 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@@ -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@@ -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@@ -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@@ -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@@ -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
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_PRESENTandMMC_STATE_REMOVEDare same. It's exclusive state which cannot be set at the same time.Signed-off-by Seungwon Jeon <[email protected]>--- 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@@ -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@@ -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@@ -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@@ -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
-0include/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 HanssonQuoted 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
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_PRESENTandMMC_STATE_REMOVEDare same. It's exclusive state which cannot be set at the same time.Signed-off-by Seungwon Jeon <[email protected]>--- 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@@ -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@@ -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@@ -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@@ -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
-0include/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 JeonQuoted 15 lines
Kind regards
Ulf HanssonQuoted 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
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_PRESENTandMMC_STATE_REMOVEDare same. It's exclusive state which cannot be set at the same time.Signed-off-by Seungwon Jeon <[email protected]>--- 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@@ -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@@ -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@@ -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@@ -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@@ -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, intdata)
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
PATCH 3/3 mmc: add support for hs400 mode of eMMC5.0
In reply to Ulf HanssonThis 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
@@ -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
@@ -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
@@ -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 10unsigned 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
@@ -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
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.0This 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.
Signed-off-by Seungwon Jeon <[email protected]>--- 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
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@@ -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
-4if (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@@ -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@@ -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 10unsigned 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@@ -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 */
+#defineEXT_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
@@ -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
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.
Signed-off-by Seungwon Jeon <[email protected]>--- 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
-0drivers/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@@ -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. removeEXT_CSD_CARD_TYPE_MASK
2.card_typeis 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
-4if (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@@ -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@@ -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 10unsigned 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@@ -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 */
+#defineEXT_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
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
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.0Quoted 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.
Signed-off-by Seungwon Jeon <[email protected]>--- 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
-0drivers/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@@ -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. removeEXT_CSD_CARD_TYPE_MASK
2.card_typeis 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
-4if (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@@ -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@@ -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 10unsigned 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@@ -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 */
+#defineEXT_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
-0drivers/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
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,
JackeyQuoted 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.0Quoted 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.
Signed-off-by Seungwon Jeon <[email protected]>--- 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
-0drivers/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@@ -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. removeEXT_CSD_CARD_TYPE_MASK
2.card_typeis 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
-4if (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@@ -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@@ -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 10unsigned 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@@ -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 */
+#defineEXT_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
-0drivers/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
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
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_sdhito 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/
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
GuennadiQuoted 7 lines · Ulf Hansson
This patchset converts tmio and
sh_mobile_sdhito 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 functionsQuoted 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/
cover mmc: distinguish DDR timing mode for eMMC/UHS
In reply to Ulf HanssonThese 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(-)
PATCH 1/7 mmc: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonThis 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
@@ -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
@@ -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
@@ -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
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.
Signed-off-by Seungwon Jeon <[email protected]>
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@@ -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@@ -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@@ -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
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.
Signed-off-by Seungwon Jeon <[email protected]>Acked-by Ulf Hansson <[email protected]>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@@ -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@@ -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@@ -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
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.
Signed-off-by Seungwon Jeon <[email protected]>Acked-by Ulf Hansson <[email protected]>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@@ -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 HanssonQuoted 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@@ -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@@ -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 9Quoted 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
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.
Signed-off-by Seungwon Jeon <[email protected]>Acked-by Ulf Hansson <[email protected]>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@@ -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 JeonQuoted 43 lines
Kind regards
Ulf HanssonQuoted 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@@ -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@@ -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 9Quoted 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
PATCH 2/7 mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonReplaced 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
@@ -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
Re: [PATCH 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
Quoted 13 lines · Seungwon Jeon
Replaced
UHS_DDR50withMMC_DDR52.CC Russell King <[email protected]>Signed-off-by Seungwon Jeon <[email protected]>--- drivers/mmc/host/mmci.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)drivers/mmc/host/mmci.c +0
-0
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
-1clk |=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
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_DDR50withMMC_DDR52.CC Russell King <[email protected]>Signed-off-by Seungwon Jeon <[email protected]>--- drivers/mmc/host/mmci.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)drivers/mmc/host/mmci.c +0
-0drivers/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
-0clk |=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
PATCH v2 2/7 mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonAdded 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
@@ -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
PATCH 3/7 mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonReplaced 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
@@ -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
Re: [PATCH 3/7] mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
Quoted 13 lines · Seungwon Jeon
Replaced
UHS_DDR50withMMC_DDR52.CC Balaji T K <[email protected]>Signed-off-by Seungwon Jeon <[email protected]>--- drivers/mmc/host/omap_hsmmc.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)drivers/mmc/host/omap_hsmmc.c +0
-0
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
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_DDR50withMMC_DDR52.CC Balaji T K <[email protected]>Signed-off-by Seungwon Jeon <[email protected]>--- 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@@ -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_switchandhost_ops->card_busyinstead.
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 HanssonQuoted 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
Re: [PATCH 3/7] mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
In reply to Seungwon JeonQuoted 4 lines · Seungwon Jeon
Replaced
UHS_DDR50withMMC_DDR52.CC Balaji T K <[email protected]>Signed-off-by Seungwon Jeon <[email protected]>
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@@ -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 ;
PATCH 4/7 mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonReplaced UHS_DDR50 with MMC_DDR52.
--- drivers/mmc/host/sh_mmcif.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)
drivers/mmc/host/sh_mmcif.c +5 -4
@@ -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
Re: [PATCH 4/7] mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
Quoted 13 lines · Seungwon Jeon
Replaced
UHS_DDR50withMMC_DDR52.CC Guennadi Liakhovetski <[email protected]>Signed-off-by Seungwon Jeon <[email protected]>--- drivers/mmc/host/sh_mmcif.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)drivers/mmc/host/sh_mmcif.c +0
-0
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
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_DDR50withMMC_DDR52.CC Guennadi Liakhovetski <[email protected]>Signed-off-by Seungwon Jeon <[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@@ -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 HanssonQuoted 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
RE: [PATCH 4/7] mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonHi 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_DDR50withMMC_DDR52.CC Guennadi Liakhovetski <[email protected]>Signed-off-by Seungwon Jeon <[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@@ -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_DDR50looks like pointing eMMC's DDR.Guennadi,
Can you check this more?Thanks,
Seungwon JeonQuoted 24 lines
Kind regards
Ulf HanssonQuoted 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
PATCH 5/7 mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonAdded 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
@@ -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
Re: [PATCH 5/7] mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
Quoted 5 lines · Seungwon Jeon
Added
MMC_DDR52as eMMC's DDR mode distinguished from SD-UHS.CC Wei WANG <[email protected]>CC Samuel Ortiz <[email protected]>Signed-off-by Seungwon Jeon <[email protected]>
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@@ -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
PATCH 6/7 mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonReplaced 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
@@ -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
@@ -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
Re: [PATCH 6/7] mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
Quoted 4 lines · Seungwon Jeon
Replaced
UHS_DDR50withMMC_DDR52. AndMMC_CAP_UHS_DDR50is removed because of non-implementation of UHS signaling.Signed-off-by Seungwon Jeon <[email protected]>
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@@ -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@@ -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
PATCH 7/7 mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonAdded 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
@@ -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
Re: [PATCH 7/7] mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC
Quoted 3 lines · Seungwon Jeon
Added
MMC_DDR52as eMMC's DDR mode distinguished from SD-UHS.Signed-off-by Seungwon Jeon <[email protected]>
Quoted 34 lines
--- drivers/mmc/host/sdhci.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)drivers/mmc/host/sdhci.c +3
-2@@ -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
cover update selection of bus speed mode for eMMC
In reply to Ulf HanssonThis 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(-)
PATCH 1/5 mmc: drop the speed mode of card's state
In reply to Ulf HanssonTiming 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 2/5 mmc: identify available device type to select
In reply to Ulf HanssonDevice 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
@@ -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
@@ -68,7 +68,6 @@ struct mmc_ext_csd {#define MMC_HIGH_DDR_MAX_DTR 52000000#define MMC_HS200_MAX_DTR 200000000unsigned 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
@@ -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
@@ -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
PATCH 3/5 mmc: step power class after final selection of bus mode
In reply to Ulf HanssonPower 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
@@ -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
PATCH 4/5 mmc: rework selection of bus speed mode
In reply to Ulf HanssonCurrent 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
@@ -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
@@ -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
@@ -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
PATCH 5/5 mmc: add support for HS400 mode of eMMC5.0
In reply to Ulf HanssonThis 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
@@ -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
@@ -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
@@ -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
@@ -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 11unsigned 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
@@ -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
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.
Signed-off-by Seungwon Jeon <[email protected]>--- 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@@ -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@@ -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@@ -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@@ -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@@ -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 11unsigned 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@@ -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
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.
Signed-off-by Seungwon Jeon <[email protected]>--- 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@@ -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@@ -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@@ -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_csdis never used in this function, I suggest we remove it.
Thank you for check.
I'll address.
Thanks,
Seungwon Jeon
Quoted 206 lines
Thanks,
JackeyQuoted 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@@ -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@@ -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 11unsigned 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@@ -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
v2 cover mmc: distinguish DDR timing mode for eMMC/UHS
In reply to Ulf HanssonThese 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(-)
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
v3 cover mmc: distinguish DDR timing mode for eMMC/UHS
In reply to Seungwon JeonThese 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
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_DDR50is used as eMMC DDR mode.MMC_TIMING_MMC_DDR52mode 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-exynosChanges in V2:
(2/7) Added MMC-DDR52 mode instead of replacing UHS-DDR50 in mmciSeungwon 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 eMMCdrivers/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
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_DDR50is used as eMMC DDR mode.MMC_TIMING_MMC_DDR52mode 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 HanssonQuoted 29 lines
Changes in V3:
(6/7) Added MMC-DDR52 mode instead of replacing UHS-DDR50 in dw_mmc-exynosChanges in V2:
(2/7) Added MMC-DDR52 mode instead of replacing UHS-DDR50 in mmciSeungwon 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 eMMCdrivers/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
PATCH v2 1/7 mmc: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonThis 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
@@ -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
@@ -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
@@ -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
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
@@ -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
@@ -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
@@ -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
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.
Signed-off-by Seungwon Jeon <[email protected]>Acked-by Ulf Hansson <[email protected]>--- 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@@ -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@@ -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@@ -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
PATCH RESEND v3 1/7 mmc: clarify DDR timing mode between SD-UHS and eMMC
In reply to Seungwon JeonThis 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
@@ -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
@@ -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
@@ -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
PATCH v2 2/7 mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonAdded 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
@@ -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
Re: [PATCH v2 2/7] mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
Quoted 4 lines · Seungwon Jeon
Added
MMC_DDR52as eMMC's DDR mode distinguished from SD-UHS.CC Russell King <[email protected]>Signed-off-by Seungwon Jeon <[email protected]>
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@@ -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
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_DDR52as eMMC's DDR mode distinguished from SD-UHS.CC Russell King <[email protected]>Signed-off-by Seungwon Jeon <[email protected]>
Quoted 7 lines
Acked-by Ulf Hansson <[email protected]>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 HanssonQuoted 29 lines
--- drivers/mmc/host/mmci.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-)drivers/mmc/host/mmci.c +4
-3@@ -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
PATCH v3 2/7 mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
In reply to Seungwon JeonAdded 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
@@ -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
PATCH RESEND v3 2/7 mmc: mmci: clarify DDR timing mode between SD-UHS and eMMC
In reply to Seungwon JeonAdded 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
@@ -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
PATCH v2 3/7 mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonReplaced 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
@@ -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
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
@@ -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
PATCH RESEND v3 3/7 mmc: omap: clarify DDR timing mode between SD-UHS and eMMC
In reply to Seungwon JeonReplaced 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
@@ -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
PATCH v2 4/7 mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonReplaced UHS_DDR50 with MMC_DDR52.
--- drivers/mmc/host/sh_mmcif.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)
drivers/mmc/host/sh_mmcif.c +5 -4
@@ -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
PATCH v3 4/7 mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
Replaced UHS_DDR50 with MMC_DDR52.
--- drivers/mmc/host/sh_mmcif.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)
drivers/mmc/host/sh_mmcif.c +5 -4
@@ -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
PATCH RESEND v3 4/7 mmc: sh_mmcif: clarify DDR timing mode between SD-UHS and eMMC
In reply to Seungwon JeonReplaced UHS_DDR50 with MMC_DDR52.
--- drivers/mmc/host/sh_mmcif.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)
drivers/mmc/host/sh_mmcif.c +5 -4
@@ -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
PATCH v2 5/7 mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonAdded 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
@@ -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
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
@@ -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
PATCH RESEND v3 5/7 mmc: rtsx: clarify DDR timing mode between SD-UHS and eMMC
In reply to Seungwon JeonAdded 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
@@ -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
PATCH v2 6/7 mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonReplaced 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
@@ -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
@@ -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
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
@@ -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
@@ -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
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_DDR50withMMC_DDR52. AndMMC_CAP_UHS_DDR50is removed because of non-implementation of UHS signaling.Signed-off-by Seungwon Jeon <[email protected]>Reviewed-by Ulf Hansson <[email protected]>--- 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@@ -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@@ -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 );
PATCH v3 6/7 mmc: dw_mmc: clarify DDR timing mode between SD-UHS and eMMC
In reply to Seungwon JeonReplaced 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
@@ -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
@@ -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
PATCH v2 7/7 mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC
In reply to Ulf HanssonAdded 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
@@ -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
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
@@ -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
PATCH RESEND v3 7/7 mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC
In reply to Seungwon JeonAdded 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
@@ -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
cover update selection of bus speed mode for eMMC
In reply to Ulf HanssonThis 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(-)
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(-)
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(-)
Re: [PATCH RESEND 0/5] update selection of bus speed mode for eMMC
In reply to Seungwon JeonI 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.0drivers/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
v3 cover update selection of bus speed mode for eMMC
In reply to Seungwon JeonThis 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
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 DDRtype(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.0drivers/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
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 DDRtype(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 HanssonQuoted 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.0drivers/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
Jaehoon Chung
maintainerRe: [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 DDRtype(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 JeonQuoted 31 lines
Kind regards
Ulf HanssonQuoted 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.0drivers/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
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 DDRtype(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 ChungQuoted 37 lines
Thanks,
Seungwon JeonQuoted 31 lines
Kind regards
Ulf HanssonQuoted 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.0drivers/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
v4 cover update selection of bus speed mode for eMMC
In reply to Seungwon JeonThis 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
PATCH v4 1/5 mmc: drop the speed mode of card's state
In reply to Seungwon JeonTiming 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH v4 2/5 mmc: identify available device type to select
In reply to Seungwon JeonDevice 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
@@ -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
@@ -68,7 +68,6 @@ struct mmc_ext_csd {#define MMC_HIGH_DDR_MAX_DTR 52000000#define MMC_HS200_MAX_DTR 200000000unsigned 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
@@ -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
@@ -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
PATCH v4 3/5 mmc: step power class after final selection of bus mode
In reply to Seungwon JeonPower 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
@@ -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
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.
Signed-off-by Seungwon Jeon <[email protected]>Tested-by Jaehoon Chung <[email protected]>Acked-by Jaehoon Chung <[email protected]>
Quoted 168 lines
--- drivers/mmc/core/mmc.c | 96 +++++++++++++++++++++++++++-------------------- 1 files changed, 55 insertions(+), 41 deletions(-)drivers/mmc/core/mmc.c +55
-42@@ -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
PATCH v4 4/5 mmc: rework selection of bus speed mode
In reply to Seungwon JeonCurrent 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
@@ -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
@@ -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
@@ -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
PATCH v4 5/5 mmc: add support for HS400 mode of eMMC5.0
In reply to Seungwon JeonThis 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
@@ -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
@@ -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
@@ -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
@@ -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 11unsigned 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
@@ -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
v5 cover update selection of bus speed mode for eMMC
In reply to Seungwon JeonThis 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
PATCH v5 1/5 mmc: drop the speed mode of card's state
In reply to Seungwon JeonTiming 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH v5 2/5 mmc: identify available device type to select
In reply to Seungwon JeonDevice 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
@@ -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
@@ -68,7 +68,6 @@ struct mmc_ext_csd {#define MMC_HIGH_DDR_MAX_DTR 52000000#define MMC_HS200_MAX_DTR 200000000unsigned 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
@@ -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
@@ -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