From 2501c9179dff2add6aadd3898cd729e94e777d3a Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Wed, 30 Oct 2013 01:00:18 +0100 Subject: mmc: core: Use MMC_UNSAFE_RESUME as default behavior Invoking system suspend or shutdown without using the Kconfig option MMC_UNSAFE_RESUME, did trigger an ungraceful power cut of the card. To improve the situation, change the behavior to always make use of the available bus_ops callbacks that handles system suspend and shutdown properly. By changing the behavior MMC_UNSAFE_RESUME becomes redundant, so lets's remove it. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/Kconfig | 15 --------------- drivers/mmc/core/core.c | 17 ----------------- drivers/mmc/core/mmc.c | 23 +---------------------- drivers/mmc/core/sd.c | 23 +---------------------- 4 files changed, 2 insertions(+), 76 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 269d072ef55e..9ebee72d9c3f 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -2,21 +2,6 @@ # MMC core configuration # -config MMC_UNSAFE_RESUME - bool "Assume MMC/SD cards are non-removable (DANGEROUS)" - help - If you say Y here, the MMC layer will assume that all cards - stayed in their respective slots during the suspend. The - normal behaviour is to remove them at suspend and - redetecting them at resume. Breaking this assumption will - in most cases result in data corruption. - - This option is usually just for embedded systems which use - a MMC/SD card for rootfs. Most people should say N here. - - This option sets a default which can be overridden by the - module parameter "removable=0" or "removable=1". - config MMC_CLKGATE bool "MMC host clock gating" help diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 098374b1ab2b..10856ec64412 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -64,23 +64,6 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; bool use_spi_crc = 1; module_param(use_spi_crc, bool, 0); -/* - * We normally treat cards as removed during suspend if they are not - * known to be on a non-removable bus, to avoid the risk of writing - * back data to a different card after resume. Allow this to be - * overridden if necessary. - */ -#ifdef CONFIG_MMC_UNSAFE_RESUME -bool mmc_assume_removable; -#else -bool mmc_assume_removable = 1; -#endif -EXPORT_SYMBOL(mmc_assume_removable); -module_param_named(removable, mmc_assume_removable, bool, 0644); -MODULE_PARM_DESC( - removable, - "MMC/SD cards are removable and may be removed during suspend"); - /* * Internal function. Schedule delayed work in the MMC work queue. */ diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 98e9eb0f6643..20f046895228 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1634,16 +1634,6 @@ static int mmc_power_restore(struct mmc_host *host) } static const struct mmc_bus_ops mmc_ops = { - .remove = mmc_remove, - .detect = mmc_detect, - .suspend = NULL, - .resume = NULL, - .power_restore = mmc_power_restore, - .alive = mmc_alive, - .shutdown = mmc_shutdown, -}; - -static const struct mmc_bus_ops mmc_ops_unsafe = { .remove = mmc_remove, .detect = mmc_detect, .suspend = mmc_suspend, @@ -1655,17 +1645,6 @@ static const struct mmc_bus_ops mmc_ops_unsafe = { .shutdown = mmc_shutdown, }; -static void mmc_attach_bus_ops(struct mmc_host *host) -{ - const struct mmc_bus_ops *bus_ops; - - if (!mmc_card_is_removable(host)) - bus_ops = &mmc_ops_unsafe; - else - bus_ops = &mmc_ops; - mmc_attach_bus(host, bus_ops); -} - /* * Starting point for MMC card init. */ @@ -1685,7 +1664,7 @@ int mmc_attach_mmc(struct mmc_host *host) if (err) return err; - mmc_attach_bus_ops(host); + mmc_attach_bus(host, &mmc_ops); if (host->ocr_avail_mmc) host->ocr_avail = host->ocr_avail_mmc; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 692fdb177294..2dd359d2242f 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1207,16 +1207,6 @@ static int mmc_sd_power_restore(struct mmc_host *host) } static const struct mmc_bus_ops mmc_sd_ops = { - .remove = mmc_sd_remove, - .detect = mmc_sd_detect, - .suspend = NULL, - .resume = NULL, - .power_restore = mmc_sd_power_restore, - .alive = mmc_sd_alive, - .shutdown = mmc_sd_suspend, -}; - -static const struct mmc_bus_ops mmc_sd_ops_unsafe = { .remove = mmc_sd_remove, .detect = mmc_sd_detect, .runtime_suspend = mmc_sd_runtime_suspend, @@ -1228,17 +1218,6 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = { .shutdown = mmc_sd_suspend, }; -static void mmc_sd_attach_bus_ops(struct mmc_host *host) -{ - const struct mmc_bus_ops *bus_ops; - - if (!mmc_card_is_removable(host)) - bus_ops = &mmc_sd_ops_unsafe; - else - bus_ops = &mmc_sd_ops; - mmc_attach_bus(host, bus_ops); -} - /* * Starting point for SD card init. */ @@ -1254,7 +1233,7 @@ int mmc_attach_sd(struct mmc_host *host) if (err) return err; - mmc_sd_attach_bus_ops(host); + mmc_attach_bus(host, &mmc_sd_ops); if (host->ocr_avail_sd) host->ocr_avail = host->ocr_avail_sd; -- cgit v1.2.3-70-g09d2 From 5601aaf73e5c2f0aa5e3607fee7b7d3511edfea9 Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Wed, 30 Oct 2013 23:15:30 +0100 Subject: mmc: core: Remove unnecessary validations for bus_ops callbacks Due to the removal of the Kconfig option MMC_UNSAFE_RESUME, several validations of a present bus_ops callback became redundant. Let's remove these. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/bus.c | 12 ++---------- drivers/mmc/core/core.c | 13 +++++-------- 2 files changed, 7 insertions(+), 18 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 64145a32b917..824644875d41 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -185,24 +185,16 @@ static int mmc_runtime_suspend(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; - int ret = 0; - if (host->bus_ops->runtime_suspend) - ret = host->bus_ops->runtime_suspend(host); - - return ret; + return host->bus_ops->runtime_suspend(host); } static int mmc_runtime_resume(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; - int ret = 0; - if (host->bus_ops->runtime_resume) - ret = host->bus_ops->runtime_resume(host); - - return ret; + return host->bus_ops->runtime_resume(host); } static int mmc_runtime_idle(struct device *dev) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 10856ec64412..22427c684b36 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2231,9 +2231,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check) { struct mmc_card *card = host->card; - if (!host->bus_ops->power_restore) - return -EOPNOTSUPP; - if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) return -EOPNOTSUPP; @@ -2335,7 +2332,7 @@ int _mmc_detect_card_removed(struct mmc_host *host) { int ret; - if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive) + if (host->caps & MMC_CAP_NONREMOVABLE) return 0; if (!host->card || mmc_card_removed(host->card)) @@ -2418,7 +2415,7 @@ void mmc_rescan(struct work_struct *work) * if there is a _removable_ card registered, check whether it is * still present */ - if (host->bus_ops && host->bus_ops->detect && !host->bus_dead + if (host->bus_ops && !host->bus_dead && !(host->caps & MMC_CAP_NONREMOVABLE)) host->bus_ops->detect(host); @@ -2520,7 +2517,7 @@ int mmc_power_save_host(struct mmc_host *host) mmc_bus_get(host); - if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { + if (!host->bus_ops || host->bus_dead) { mmc_bus_put(host); return -EINVAL; } @@ -2546,7 +2543,7 @@ int mmc_power_restore_host(struct mmc_host *host) mmc_bus_get(host); - if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { + if (!host->bus_ops || host->bus_dead) { mmc_bus_put(host); return -EINVAL; } @@ -2651,7 +2648,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, /* Validate prerequisites for suspend */ if (host->bus_ops->pre_suspend) err = host->bus_ops->pre_suspend(host); - if (!err && host->bus_ops->suspend) + if (!err) break; /* Calling bus_ops->remove() with a claimed host can deadlock */ -- cgit v1.2.3-70-g09d2 From 469a00b017a9b2c630bff962ffd64ba626977830 Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Mon, 16 Dec 2013 14:46:00 +0100 Subject: mmc: core: Remove support for MMC_CAP2_NO_SLEEP_CMD There are no active users of this host capability. The primary reason for adding this cap was due to a bug in ux500 boot loader code, which is not a relevant issue any more. So, let's remove it. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/mmc.c | 3 --- include/linux/mmc/host.h | 1 - 2 files changed, 4 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 20f046895228..5c4ee6ab2125 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1358,9 +1358,6 @@ static int mmc_sleep(struct mmc_host *host) struct mmc_card *card = host->card; int err; - if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD) - return 0; - err = mmc_deselect_cards(host); if (err) return err; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 461c69f19425..4c0176a8e474 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -267,7 +267,6 @@ struct mmc_host { #define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */ #define MMC_CAP2_FULL_PWR_CYCLE (1 << 2) /* Can do full power cycle */ #define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock reads don't work */ -#define MMC_CAP2_NO_SLEEP_CMD (1 << 4) /* Don't allow sleep command */ #define MMC_CAP2_HS200_1_8V_SDR (1 << 5) /* can support */ #define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */ #define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \ -- cgit v1.2.3-70-g09d2 From 10e5d9652499a8bc0a99ffc2a96a3030fee576cb Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Mon, 16 Dec 2013 16:23:22 +0100 Subject: mmc: core: Use mmc_flush_cache() during mmc suspend Earlier we disabled the cache during suspend, which meant a flush was internally at the eMMC performed as well. To simplify code we can make use of the mmc_flush_cache(), during mmc suspend, which makes the mmc_cache_ctrl() redundant so then we can remove it. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Acked-by: Seungwon Jeon <tgih.jun@samsung.com> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/core.c | 38 -------------------------------------- drivers/mmc/core/mmc.c | 2 +- include/linux/mmc/host.h | 2 -- 3 files changed, 1 insertion(+), 41 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 22427c684b36..8928f9f4cfe1 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2582,44 +2582,6 @@ int mmc_flush_cache(struct mmc_card *card) } EXPORT_SYMBOL(mmc_flush_cache); -/* - * Turn the cache ON/OFF. - * Turning the cache OFF shall trigger flushing of the data - * to the non-volatile storage. - * This function should be called with host claimed - */ -int mmc_cache_ctrl(struct mmc_host *host, u8 enable) -{ - struct mmc_card *card = host->card; - unsigned int timeout; - int err = 0; - - if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) || - mmc_card_is_removable(host)) - return err; - - if (card && mmc_card_mmc(card) && - (card->ext_csd.cache_size > 0)) { - enable = !!enable; - - if (card->ext_csd.cache_ctrl ^ enable) { - timeout = enable ? card->ext_csd.generic_cmd6_time : 0; - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_CACHE_CTRL, enable, timeout); - if (err) - pr_err("%s: cache %s error %d\n", - mmc_hostname(card->host), - enable ? "on" : "off", - err); - else - card->ext_csd.cache_ctrl = enable; - } - } - - return err; -} -EXPORT_SYMBOL(mmc_cache_ctrl); - #ifdef CONFIG_PM /* Do the card removal on suspend if card is assumed removeable diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 5c4ee6ab2125..6d446e217f36 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1481,7 +1481,7 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) goto out; } - err = mmc_cache_ctrl(host, 0); + err = mmc_flush_cache(host->card); if (err) goto out; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 4c0176a8e474..f69bd70b1046 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -385,8 +385,6 @@ int mmc_power_restore_host(struct mmc_host *host); void mmc_detect_change(struct mmc_host *, unsigned long delay); void mmc_request_done(struct mmc_host *, struct mmc_request *); -int mmc_cache_ctrl(struct mmc_host *, u8); - static inline void mmc_signal_sdio_irq(struct mmc_host *host) { host->ops->enable_sdio_irq(host, 0); -- cgit v1.2.3-70-g09d2 From 7536d3f83aa42ba1a3b1c6b30c2b6d94a820cbb2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Wed, 18 Dec 2013 11:59:17 +0100 Subject: mmc: core: Enable MMC_CAP2_CACHE_CTRL as default There are no reason to why the use of a non-volatile internal eMMC cache should be controlled by a host cap. Instead let's just enable it if the eMMC card supports it. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Acked-by: Seungwon Jeon <tgih.jun@samsung.com> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/core.c | 4 ---- drivers/mmc/core/mmc.c | 3 +-- include/linux/mmc/host.h | 1 - 3 files changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 8928f9f4cfe1..f5a068d55c36 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2562,12 +2562,8 @@ EXPORT_SYMBOL(mmc_power_restore_host); */ int mmc_flush_cache(struct mmc_card *card) { - struct mmc_host *host = card->host; int err = 0; - if (!(host->caps2 & MMC_CAP2_CACHE_CTRL)) - return err; - if (mmc_card_mmc(card) && (card->ext_csd.cache_size > 0) && (card->ext_csd.cache_ctrl & 1)) { diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6d446e217f36..072171183d5b 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1287,8 +1287,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * If cache size is higher than 0, this indicates * the existence of cache and it can be turned on. */ - if ((host->caps2 & MMC_CAP2_CACHE_CTRL) && - card->ext_csd.cache_size > 0) { + if (card->ext_csd.cache_size > 0) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CACHE_CTRL, 1, card->ext_csd.generic_cmd6_time); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index f69bd70b1046..719db89ef134 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -264,7 +264,6 @@ struct mmc_host { u32 caps2; /* More host capabilities */ #define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */ -#define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */ #define MMC_CAP2_FULL_PWR_CYCLE (1 << 2) /* Can do full power cycle */ #define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock reads don't work */ #define MMC_CAP2_HS200_1_8V_SDR (1 << 5) /* can support */ -- cgit v1.2.3-70-g09d2 From b66bd0e4d00c89102851c1bc9a0f738a4ad9ca2d Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Fri, 14 Feb 2014 13:27:07 +0100 Subject: mmc: core: Add DT bindings for SD card's UHS bus speed modes Provide the option to configure these speed modes per host, for those host driver's that can't distinguish this in runtime. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Acked-by: Jaehoon Chung <jh80.chung@samsung.com> Signed-off-by: Chris Ball <chris@printf.net> --- Documentation/devicetree/bindings/mmc/mmc.txt | 5 +++++ drivers/mmc/core/host.c | 10 ++++++++++ 2 files changed, 15 insertions(+) (limited to 'drivers/mmc/core') diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt index 458b57f199af..bd2ce67dbb9e 100644 --- a/Documentation/devicetree/bindings/mmc/mmc.txt +++ b/Documentation/devicetree/bindings/mmc/mmc.txt @@ -26,6 +26,11 @@ Optional properties: this system, even if the controller claims it is. - cap-sd-highspeed: SD high-speed timing is supported - cap-mmc-highspeed: MMC high-speed timing is supported +- sd-uhs-sdr12: SD UHS SDR12 speed is supported +- sd-uhs-sdr25: SD UHS SDR25 speed is supported +- sd-uhs-sdr50: SD UHS SDR50 speed is supported +- sd-uhs-sdr104: SD UHS SDR104 speed is supported +- sd-uhs-ddr50: SD UHS DDR50 speed is supported - cap-power-off-card: powering off the card is safe - cap-sdio-irq: enable SDIO IRQ signalling on this interface - full-pwr-cycle: full power cycle of the card is supported diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 49bc403e31f0..2644d91fd336 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -419,6 +419,16 @@ int mmc_of_parse(struct mmc_host *host) host->caps |= MMC_CAP_SD_HIGHSPEED; if (of_find_property(np, "cap-mmc-highspeed", &len)) host->caps |= MMC_CAP_MMC_HIGHSPEED; + if (of_find_property(np, "sd-uhs-sdr12", &len)) + host->caps |= MMC_CAP_UHS_SDR12; + if (of_find_property(np, "sd-uhs-sdr25", &len)) + host->caps |= MMC_CAP_UHS_SDR25; + if (of_find_property(np, "sd-uhs-sdr50", &len)) + host->caps |= MMC_CAP_UHS_SDR50; + if (of_find_property(np, "sd-uhs-sdr104", &len)) + host->caps |= MMC_CAP_UHS_SDR104; + if (of_find_property(np, "sd-uhs-ddr50", &len)) + host->caps |= MMC_CAP_UHS_DDR50; if (of_find_property(np, "cap-power-off-card", &len)) host->caps |= MMC_CAP_POWER_OFF_CARD; if (of_find_property(np, "cap-sdio-irq", &len)) -- cgit v1.2.3-70-g09d2 From c0baf8485928b2db8a9530672d522d758746a2b6 Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Fri, 14 Feb 2014 13:27:08 +0100 Subject: mmc: core: Add DT bindings for eMMC high-speed DDR 1.8/1.2V Provide the option to configure these speed modes per host, for those host driver's that can't distinguish this in runtime. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Acked-by: Jaehoon Chung <jh80.chung@samsung.com> Signed-off-by: Chris Ball <chris@printf.net> --- Documentation/devicetree/bindings/mmc/mmc.txt | 2 ++ drivers/mmc/core/host.c | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'drivers/mmc/core') diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt index bd2ce67dbb9e..519d9523a413 100644 --- a/Documentation/devicetree/bindings/mmc/mmc.txt +++ b/Documentation/devicetree/bindings/mmc/mmc.txt @@ -34,6 +34,8 @@ Optional properties: - cap-power-off-card: powering off the card is safe - cap-sdio-irq: enable SDIO IRQ signalling on this interface - full-pwr-cycle: full power cycle of the card is supported +- mmc-highspeed-ddr-1_8v: eMMC high-speed DDR mode(1.8V I/O) is supported +- mmc-highspeed-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line polarity properties, we have to fix the meaning of the "normal" and "inverted" diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 2644d91fd336..d014127f1043 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -439,6 +439,10 @@ int mmc_of_parse(struct mmc_host *host) host->pm_caps |= MMC_PM_KEEP_POWER; if (of_find_property(np, "enable-sdio-wakeup", &len)) host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; + if (of_find_property(np, "mmc-ddr-1_8v", &len)) + host->caps |= MMC_CAP_1_8V_DDR; + if (of_find_property(np, "mmc-ddr-1_2v", &len)) + host->caps |= MMC_CAP_1_2V_DDR; return 0; -- cgit v1.2.3-70-g09d2 From 321bd41de1580f953c637de0fd81e06fcba8b3e8 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung <jh80.chung@samsung.com> Date: Fri, 14 Feb 2014 13:27:09 +0100 Subject: mmc: core: Add DT bindings for eMMC HS200 1.8/1.2V Provide the option to configure these speed modes per host, for those host driver's that can't distinguish this in runtime. Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com> Acked-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <chris@printf.net> --- Documentation/devicetree/bindings/mmc/mmc.txt | 2 ++ drivers/mmc/core/host.c | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'drivers/mmc/core') diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt index 519d9523a413..9dce540771fb 100644 --- a/Documentation/devicetree/bindings/mmc/mmc.txt +++ b/Documentation/devicetree/bindings/mmc/mmc.txt @@ -36,6 +36,8 @@ Optional properties: - full-pwr-cycle: full power cycle of the card is supported - mmc-highspeed-ddr-1_8v: eMMC high-speed DDR mode(1.8V I/O) is supported - mmc-highspeed-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported +- mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported +- mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line polarity properties, we have to fix the meaning of the "normal" and "inverted" diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index d014127f1043..453573d5ab08 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -443,6 +443,10 @@ int mmc_of_parse(struct mmc_host *host) host->caps |= MMC_CAP_1_8V_DDR; if (of_find_property(np, "mmc-ddr-1_2v", &len)) host->caps |= MMC_CAP_1_2V_DDR; + if (of_find_property(np, "mmc-hs200-1_8v", &len)) + host->caps2 |= MMC_CAP2_HS200_1_8V_SDR; + if (of_find_property(np, "mmc-hs200-1_2v", &len)) + host->caps2 |= MMC_CAP2_HS200_1_2V_SDR; return 0; -- cgit v1.2.3-70-g09d2 From 68eb80e06bfa06035d0304686124974780308fae Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Wed, 18 Dec 2013 09:57:38 +0100 Subject: mmc: core: Rename max_discard_to to max_busy_timeout Rename host->max_discard_to to host->max_busy_timeout, to reflect that it tells the mmc core layer about the maximum supported busy detection timeout by the host. This timeout is at the moment only applicable to erase/trim/discard commands. By the renaming we provide the option of make use of it for other commands that cares about busy detection. In other words, those commands that wants an R1B response, like for example the mmc switch command. Do note that the max_busy_timeout is supposed to be specified only by hosts supporting MMC_CAP_WAIT_WHILE_BUSY. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/core.c | 6 +++--- drivers/mmc/host/sdhci.c | 2 +- include/linux/mmc/host.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f5a068d55c36..d9c1efa2ce15 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2120,7 +2120,7 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card, y = 0; for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) { timeout = mmc_erase_timeout(card, arg, qty + x); - if (timeout > host->max_discard_to) + if (timeout > host->max_busy_timeout) break; if (timeout < last_timeout) break; @@ -2152,7 +2152,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card) struct mmc_host *host = card->host; unsigned int max_discard, max_trim; - if (!host->max_discard_to) + if (!host->max_busy_timeout) return UINT_MAX; /* @@ -2172,7 +2172,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card) max_discard = 0; } pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n", - mmc_hostname(host), max_discard, host->max_discard_to); + mmc_hostname(host), max_discard, host->max_busy_timeout); return max_discard; } EXPORT_SYMBOL(mmc_calc_max_discard); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8958edc03e04..d1e1bf52fe52 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2941,7 +2941,7 @@ int sdhci_add_host(struct sdhci_host *host) if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) host->timeout_clk = mmc->f_max / 1000; - mmc->max_discard_to = (1 << 27) / host->timeout_clk; + mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 719db89ef134..cb61ea4d6945 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -300,7 +300,7 @@ struct mmc_host { unsigned int max_req_size; /* maximum number of bytes in one req */ unsigned int max_blk_size; /* maximum size of one mmc block */ unsigned int max_blk_count; /* maximum number of blocks in one req */ - unsigned int max_discard_to; /* max. discard timeout in ms */ + unsigned int max_busy_timeout; /* max busy timeout in ms */ /* private data */ spinlock_t lock; /* lock for claim and bus ops */ -- cgit v1.2.3-70-g09d2 From 1d4d77444bf4212c44585146a2b353ca24c815f9 Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Wed, 8 Jan 2014 15:06:08 +0100 Subject: mmc: core: Rename cmd_timeout_ms to busy_timeout To better reflect that the cmd_timeout_ms is directly related to the busy detection timeout, let's rename it. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/core.c | 2 +- drivers/mmc/core/mmc_ops.c | 2 +- drivers/mmc/host/sdhci.c | 8 ++++---- include/linux/mmc/core.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index d9c1efa2ce15..1935812e4215 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1933,7 +1933,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.opcode = MMC_ERASE; cmd.arg = arg; cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; - cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty); + cmd.busy_timeout = mmc_erase_timeout(card, arg, qty); err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { pr_err("mmc_erase: erase error %d, status %#x\n", diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index e5b5eeb548d1..3377bbfc3585 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -432,7 +432,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1; - cmd.cmd_timeout_ms = timeout_ms; + cmd.busy_timeout = timeout_ms; if (index == EXT_CSD_SANITIZE_START) cmd.sanitize_busy = true; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index d1e1bf52fe52..7f95211e9449 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -675,12 +675,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) return 0xE; /* Unspecified timeout, assume max */ - if (!data && !cmd->cmd_timeout_ms) + if (!data && !cmd->busy_timeout) return 0xE; /* timeout in us */ if (!data) - target_timeout = cmd->cmd_timeout_ms * 1000; + target_timeout = cmd->busy_timeout * 1000; else { target_timeout = data->timeout_ns / 1000; if (host->clock) @@ -1019,8 +1019,8 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) } timeout = jiffies; - if (!cmd->data && cmd->cmd_timeout_ms > 9000) - timeout += DIV_ROUND_UP(cmd->cmd_timeout_ms, 1000) * HZ + HZ; + if (!cmd->data && cmd->busy_timeout > 9000) + timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ; else timeout += 10 * HZ; mod_timer(&host->timer, timeout); diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 87079fc38011..b27699612888 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -95,7 +95,7 @@ struct mmc_command { * actively failing requests */ - unsigned int cmd_timeout_ms; /* in milliseconds */ + unsigned int busy_timeout; /* busy detect timeout in ms */ /* Set this flag only for blocking sanitize request */ bool sanitize_busy; -- cgit v1.2.3-70-g09d2 From 4509f847751c9d2a724f37fe831393fbac34b80f Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Wed, 8 Jan 2014 16:09:33 +0100 Subject: mmc: core: Add ignore_crc flag to __mmc_switch Instead of handle specific adaptations, releated to certain switch operations, inside __mmc_switch, push this to be handled by the caller instead. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/core.c | 3 ++- drivers/mmc/core/mmc.c | 13 +++++++------ drivers/mmc/core/mmc_ops.c | 19 ++++++++++--------- include/linux/mmc/core.h | 2 +- 4 files changed, 20 insertions(+), 17 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 1935812e4215..dc7a5fb81a5c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -285,7 +285,8 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) } err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal, true); + EXT_CSD_BKOPS_START, 1, timeout, + use_busy_signal, true, false); if (err) { pr_warn("%s: Error %d starting bkops\n", mmc_hostname(card->host), err); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 072171183d5b..c944692f3c4e 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -856,8 +856,8 @@ static int mmc_select_hs200(struct mmc_card *card) /* switch to HS200 mode if bus width set successfully */ if (!err) - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, 2, 0); + err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HS_TIMING, 2, 0, true, true, true); err: return err; } @@ -1074,9 +1074,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, 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); + err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HS_TIMING, 1, + card->ext_csd.generic_cmd6_time, + true, true, true); if (err && err != -EBADMSG) goto free_card; @@ -1400,7 +1401,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_POWER_OFF_NOTIFICATION, - notify_type, timeout, true, false); + notify_type, timeout, true, false, false); if (err) pr_err("%s: Power Off Notification timed out, %u\n", mmc_hostname(card->host), timeout); diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 3377bbfc3585..5e1a2cbdc229 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -405,17 +405,18 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc) * timeout of zero implies maximum possible timeout * @use_busy_signal: use the busy signal as response type * @send_status: send status cmd to poll for busy + * @ignore_crc: ignore CRC errors when sending status cmd to poll for busy * * Modifies the EXT_CSD register for selected card. */ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, - unsigned int timeout_ms, bool use_busy_signal, bool send_status) + unsigned int timeout_ms, bool use_busy_signal, bool send_status, + bool ignore_crc) { int err; struct mmc_command cmd = {0}; unsigned long timeout; u32 status = 0; - bool ignore_crc = false; BUG_ON(!card); BUG_ON(!card->host); @@ -445,14 +446,13 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, return 0; /* - * Must check status to be sure of no errors - * If CMD13 is to check the busy completion of the timing change, - * disable the check of CRC error. + * CRC errors shall only be ignored in cases were CMD13 is used to poll + * to detect busy completion. */ - if (index == EXT_CSD_HS_TIMING && - !(card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)) - ignore_crc = true; + if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) + ignore_crc = false; + /* Must check status to be sure of no errors. */ timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS); do { if (send_status) { @@ -501,7 +501,8 @@ EXPORT_SYMBOL_GPL(__mmc_switch); int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned int timeout_ms) { - return __mmc_switch(card, set, index, value, timeout_ms, true, true); + return __mmc_switch(card, set, index, value, timeout_ms, true, true, + false); } EXPORT_SYMBOL_GPL(mmc_switch); diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index b27699612888..f206e29f94d7 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -152,7 +152,7 @@ extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, struct mmc_command *, int); extern void mmc_start_bkops(struct mmc_card *card, bool from_exception); extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool, - bool); + bool, bool); extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); -- cgit v1.2.3-70-g09d2 From 636bd13c12d2331ad835b89681428eccb4cf102e Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Tue, 28 Jan 2014 14:05:39 +0100 Subject: mmc: core: Minor simplifications to __mmc_switch Instead of using several references to card->host, let's use a local variable. That means we can remove the BUG_ON verifications for the same pointers. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/mmc_ops.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 5e1a2cbdc229..04ecdb913aa0 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -413,14 +413,12 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned int timeout_ms, bool use_busy_signal, bool send_status, bool ignore_crc) { + struct mmc_host *host = card->host; int err; struct mmc_command cmd = {0}; unsigned long timeout; u32 status = 0; - BUG_ON(!card); - BUG_ON(!card->host); - cmd.opcode = MMC_SWITCH; cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) | @@ -437,7 +435,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, if (index == EXT_CSD_SANITIZE_START) cmd.sanitize_busy = true; - err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); + err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); if (err) return err; @@ -449,7 +447,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, * CRC errors shall only be ignored in cases were CMD13 is used to poll * to detect busy completion. */ - if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) + if (host->caps & MMC_CAP_WAIT_WHILE_BUSY) ignore_crc = false; /* Must check status to be sure of no errors. */ @@ -460,9 +458,9 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, if (err) return err; } - if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) + if (host->caps & MMC_CAP_WAIT_WHILE_BUSY) break; - if (mmc_host_is_spi(card->host)) + if (mmc_host_is_spi(host)) break; /* @@ -478,18 +476,18 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, /* Timeout if the device never leaves the program state. */ if (time_after(jiffies, timeout)) { pr_err("%s: Card stuck in programming state! %s\n", - mmc_hostname(card->host), __func__); + mmc_hostname(host), __func__); return -ETIMEDOUT; } } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); - if (mmc_host_is_spi(card->host)) { + if (mmc_host_is_spi(host)) { if (status & R1_SPI_ILLEGAL_COMMAND) return -EBADMSG; } else { if (status & 0xFDFFA000) - pr_warning("%s: unexpected status %#x after " - "switch", mmc_hostname(card->host), status); + pr_warn("%s: unexpected status %#x after switch\n", + mmc_hostname(host), status); if (status & R1_SWITCH_ERROR) return -EBADMSG; } -- cgit v1.2.3-70-g09d2 From b9ec26160f998493509b782be999ff59e4372971 Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Tue, 28 Jan 2014 14:15:34 +0100 Subject: mmc: core: Fixup busy detection for mmc switch operations If the host controller supports busy detection in HW, we expect the MMC_CAP_WAIT_WHILE_BUSY to be set. Likewise the corresponding host->max_busy_timeout should reflect the maximum busy detection timeout supported by the host. Previously we expected a host that supported MMC_CAP_WAIT_WHILE_BUSY to cope with any timeout, which just isn't feasible due to HW limitations. For most switch operations, R1B responses are expected and thus we need to check for busy detection completion. To cope with cases where the requested busy detection timeout is greater than what the host are able to support, we fallback to use a R1 response instead. This will prevent the host from doing HW busy detection. In those cases, busy detection completion is handled by polling the for the card's status using CMD13. This is the same mechanism used when the host doesn't support MMC_CAP_WAIT_WHILE_BUSY. Do note, a host->max_busy_timeout set to zero, is interpreted by the mmc core as it don't know what the host supports. It will then provide the host with whatever timeout the mmc core finds suitable. For some cases the mmc core has unfurtunate no clue of what timeout to use. In these cases we provide the host with a timeout value of zero, which the host may interpret as use whatever timeout it finds suitable. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/mmc_ops.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 04ecdb913aa0..f51b5ba3bbea 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -418,6 +418,17 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, struct mmc_command cmd = {0}; unsigned long timeout; u32 status = 0; + bool use_r1b_resp = use_busy_signal; + + /* + * If the cmd timeout and the max_busy_timeout of the host are both + * specified, let's validate them. A failure means we need to prevent + * the host from doing hw busy detection, which is done by converting + * to a R1 response instead of a R1B. + */ + if (timeout_ms && host->max_busy_timeout && + (timeout_ms > host->max_busy_timeout)) + use_r1b_resp = false; cmd.opcode = MMC_SWITCH; cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | @@ -425,13 +436,17 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, (value << 8) | set; cmd.flags = MMC_CMD_AC; - if (use_busy_signal) + if (use_r1b_resp) { cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B; - else + /* + * A busy_timeout of zero means the host can decide to use + * whatever value it finds suitable. + */ + cmd.busy_timeout = timeout_ms; + } else { cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1; + } - - cmd.busy_timeout = timeout_ms; if (index == EXT_CSD_SANITIZE_START) cmd.sanitize_busy = true; @@ -447,18 +462,22 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, * CRC errors shall only be ignored in cases were CMD13 is used to poll * to detect busy completion. */ - if (host->caps & MMC_CAP_WAIT_WHILE_BUSY) + if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) ignore_crc = false; + /* We have an unspecified cmd timeout, use the fallback value. */ + if (!timeout_ms) + timeout_ms = MMC_OPS_TIMEOUT_MS; + /* Must check status to be sure of no errors. */ - timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS); + timeout = jiffies + msecs_to_jiffies(timeout_ms); do { if (send_status) { err = __mmc_send_status(card, &status, ignore_crc); if (err) return err; } - if (host->caps & MMC_CAP_WAIT_WHILE_BUSY) + if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) break; if (mmc_host_is_spi(host)) break; -- cgit v1.2.3-70-g09d2 From 57de31f6351ecad9212a26d2112b546e4c8b4a5b Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Tue, 14 Jan 2014 17:36:21 +0100 Subject: mmc: core: Use generic CMD6 time while switching to eMMC HS200 mode Conform to the eMMC spec and use the CMD6 generic timeout from the EXT_CSD register, when switching to HS200 mode. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/mmc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index c944692f3c4e..6b7ccef51beb 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -857,7 +857,9 @@ static int mmc_select_hs200(struct mmc_card *card) /* switch to HS200 mode if bus width set successfully */ if (!err) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, 2, 0, true, true, true); + EXT_CSD_HS_TIMING, 2, + card->ext_csd.generic_cmd6_time, + true, true, true); err: return err; } -- cgit v1.2.3-70-g09d2 From cb962e04b04fb67dbaf1455d3c60d64297ef4933 Mon Sep 17 00:00:00 2001 From: Ulf Hansson <ulf.hansson@linaro.org> Date: Tue, 14 Jan 2014 23:17:36 +0100 Subject: mmc: core: Respect host's max_busy_timeout when sending sleep cmd When sending the sleep command for host drivers supporting MMC_CAP_WAIT_WHILE_BUSY, we need to confirm that max_busy_timeout is big enough comparing to the sleep timeout specified from card's EXT_CSD. If this isn't case, we use a R1 response instead of R1B and fallback to use a delay instead. Do note that a max_busy_timeout set to zero by the host, is interpreted as it can cope with whatever timeout the mmc core provides it with. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/mmc.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6b7ccef51beb..1ab5f3a0af5b 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1358,6 +1358,7 @@ static int mmc_sleep(struct mmc_host *host) { struct mmc_command cmd = {0}; struct mmc_card *card = host->card; + unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000); int err; err = mmc_deselect_cards(host); @@ -1368,7 +1369,19 @@ static int mmc_sleep(struct mmc_host *host) cmd.arg = card->rca << 16; cmd.arg |= 1 << 15; - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + /* + * If the max_busy_timeout of the host is specified, validate it against + * the sleep cmd timeout. A failure means we need to prevent the host + * from doing hw busy detection, which is done by converting to a R1 + * response instead of a R1B. + */ + if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout)) { + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + } else { + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + cmd.busy_timeout = timeout_ms; + } + err = mmc_wait_for_cmd(host, &cmd, 0); if (err) return err; @@ -1379,8 +1392,8 @@ static int mmc_sleep(struct mmc_host *host) * SEND_STATUS command to poll the status because that command (and most * others) is invalid while the card sleeps. */ - if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY)) - mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000)); + if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY)) + mmc_delay(timeout_ms); return err; } -- cgit v1.2.3-70-g09d2 From 842f4bdd37c7a0984e22aa919ad1f043137ac5c8 Mon Sep 17 00:00:00 2001 From: Adrian Hunter <adrian.hunter@intel.com> Date: Mon, 10 Mar 2014 15:02:39 +0200 Subject: mmc: slot-gpio: Record GPIO descriptors instead of GPIO numbers In preparation for adding a descriptor-based CD GPIO API, switch from recording GPIO numbers to recording GPIO descriptors. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Tested-by: Jaehoon Chung <jh80.chung@samsung.com> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/slot-gpio.c | 45 ++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 46596b71a32f..86547a2a82c6 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -10,6 +10,7 @@ #include <linux/err.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include <linux/jiffies.h> #include <linux/mmc/host.h> @@ -18,8 +19,10 @@ #include <linux/slab.h> struct mmc_gpio { - int ro_gpio; - int cd_gpio; + struct gpio_desc *ro_gpio; + struct gpio_desc *cd_gpio; + bool override_ro_active_level; + bool override_cd_active_level; char *ro_label; char cd_label[0]; }; @@ -57,8 +60,6 @@ static int mmc_gpio_alloc(struct mmc_host *host) ctx->ro_label = ctx->cd_label + len; snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent)); snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent)); - ctx->cd_gpio = -EINVAL; - ctx->ro_gpio = -EINVAL; host->slot.handler_priv = ctx; } } @@ -72,11 +73,14 @@ int mmc_gpio_get_ro(struct mmc_host *host) { struct mmc_gpio *ctx = host->slot.handler_priv; - if (!ctx || !gpio_is_valid(ctx->ro_gpio)) + if (!ctx || !ctx->ro_gpio) return -ENOSYS; - return !gpio_get_value_cansleep(ctx->ro_gpio) ^ - !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH); + if (ctx->override_ro_active_level) + return !gpiod_get_raw_value_cansleep(ctx->ro_gpio) ^ + !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH); + + return gpiod_get_value_cansleep(ctx->ro_gpio); } EXPORT_SYMBOL(mmc_gpio_get_ro); @@ -84,11 +88,14 @@ int mmc_gpio_get_cd(struct mmc_host *host) { struct mmc_gpio *ctx = host->slot.handler_priv; - if (!ctx || !gpio_is_valid(ctx->cd_gpio)) + if (!ctx || !ctx->cd_gpio) return -ENOSYS; - return !gpio_get_value_cansleep(ctx->cd_gpio) ^ - !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); + if (ctx->override_cd_active_level) + return !gpiod_get_raw_value_cansleep(ctx->cd_gpio) ^ + !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); + + return gpiod_get_value_cansleep(ctx->cd_gpio); } EXPORT_SYMBOL(mmc_gpio_get_cd); @@ -125,7 +132,8 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio) if (ret < 0) return ret; - ctx->ro_gpio = gpio; + ctx->override_ro_active_level = true; + ctx->ro_gpio = gpio_to_desc(gpio); return 0; } @@ -201,7 +209,8 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, if (irq < 0) host->caps |= MMC_CAP_NEEDS_POLL; - ctx->cd_gpio = gpio; + ctx->override_cd_active_level = true; + ctx->cd_gpio = gpio_to_desc(gpio); return 0; } @@ -219,11 +228,11 @@ void mmc_gpio_free_ro(struct mmc_host *host) struct mmc_gpio *ctx = host->slot.handler_priv; int gpio; - if (!ctx || !gpio_is_valid(ctx->ro_gpio)) + if (!ctx || !ctx->ro_gpio) return; - gpio = ctx->ro_gpio; - ctx->ro_gpio = -EINVAL; + gpio = desc_to_gpio(ctx->ro_gpio); + ctx->ro_gpio = NULL; devm_gpio_free(&host->class_dev, gpio); } @@ -241,7 +250,7 @@ void mmc_gpio_free_cd(struct mmc_host *host) struct mmc_gpio *ctx = host->slot.handler_priv; int gpio; - if (!ctx || !gpio_is_valid(ctx->cd_gpio)) + if (!ctx || !ctx->cd_gpio) return; if (host->slot.cd_irq >= 0) { @@ -249,8 +258,8 @@ void mmc_gpio_free_cd(struct mmc_host *host) host->slot.cd_irq = -EINVAL; } - gpio = ctx->cd_gpio; - ctx->cd_gpio = -EINVAL; + gpio = desc_to_gpio(ctx->cd_gpio); + ctx->cd_gpio = NULL; devm_gpio_free(&host->class_dev, gpio); } -- cgit v1.2.3-70-g09d2 From 26652671338a443fd33cf47b50658dd8b095d54a Mon Sep 17 00:00:00 2001 From: Adrian Hunter <adrian.hunter@intel.com> Date: Mon, 10 Mar 2014 15:02:40 +0200 Subject: mmc: slot-gpio: Split out CD IRQ request into a separate function In preparation for adding a descriptor-based CD GPIO API, split out CD IRQ request into a separate function. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/slot-gpio.c | 58 ++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 23 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 86547a2a82c6..47fa07e3604d 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -139,6 +139,39 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio) } EXPORT_SYMBOL(mmc_gpio_request_ro); +static void mmc_gpiod_request_cd_irq(struct mmc_host *host) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + int ret, irq; + + if (host->slot.cd_irq >= 0 || !ctx || !ctx->cd_gpio) + return; + + irq = gpiod_to_irq(ctx->cd_gpio); + + /* + * Even if gpiod_to_irq() returns a valid IRQ number, the platform might + * still prefer to poll, e.g., because that IRQ number is already used + * by another unit and cannot be shared. + */ + if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL) + irq = -EINVAL; + + if (irq >= 0) { + ret = devm_request_threaded_irq(&host->class_dev, irq, + NULL, mmc_gpio_cd_irqt, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + ctx->cd_label, host); + if (ret < 0) + irq = ret; + } + + host->slot.cd_irq = irq; + + if (irq < 0) + host->caps |= MMC_CAP_NEEDS_POLL; +} + /** * mmc_gpio_request_cd - request a gpio for card-detection * @host: mmc host @@ -162,7 +195,6 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, unsigned int debounce) { struct mmc_gpio *ctx; - int irq = gpio_to_irq(gpio); int ret; ret = mmc_gpio_alloc(host); @@ -187,31 +219,11 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, return ret; } - /* - * Even if gpio_to_irq() returns a valid IRQ number, the platform might - * still prefer to poll, e.g., because that IRQ number is already used - * by another unit and cannot be shared. - */ - if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL) - irq = -EINVAL; - - if (irq >= 0) { - ret = devm_request_threaded_irq(&host->class_dev, irq, - NULL, mmc_gpio_cd_irqt, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - ctx->cd_label, host); - if (ret < 0) - irq = ret; - } - - host->slot.cd_irq = irq; - - if (irq < 0) - host->caps |= MMC_CAP_NEEDS_POLL; - ctx->override_cd_active_level = true; ctx->cd_gpio = gpio_to_desc(gpio); + mmc_gpiod_request_cd_irq(host); + return 0; } EXPORT_SYMBOL(mmc_gpio_request_cd); -- cgit v1.2.3-70-g09d2 From 740a221ef0e579dc7c675cf6b90f5313509788f7 Mon Sep 17 00:00:00 2001 From: Adrian Hunter <adrian.hunter@intel.com> Date: Mon, 10 Mar 2014 15:02:41 +0200 Subject: mmc: slot-gpio: Add GPIO descriptor based CD GPIO API Add functions to request a CD GPIO using the GPIO descriptor API. Note that the new request function is paired with mmc_gpiod_free_cd() not mmc_gpio_free_cd(). Note also that it must be called prior to mmc_add_host() otherwise the caller must also call mmc_gpiod_request_cd_irq(). Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Chris Ball <chris@printf.net> --- drivers/mmc/core/core.c | 4 +++ drivers/mmc/core/slot-gpio.c | 81 ++++++++++++++++++++++++++++++++++++++++++- include/linux/mmc/slot-gpio.h | 6 ++++ 3 files changed, 90 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index dc7a5fb81a5c..acbc3f2aaaf9 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -34,6 +34,7 @@ #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/sd.h> +#include <linux/mmc/slot-gpio.h> #include "core.h" #include "bus.h" @@ -2471,6 +2472,7 @@ void mmc_start_host(struct mmc_host *host) mmc_power_off(host); else mmc_power_up(host, host->ocr_avail); + mmc_gpiod_request_cd_irq(host); _mmc_detect_change(host, 0, false); } @@ -2482,6 +2484,8 @@ void mmc_stop_host(struct mmc_host *host) host->removed = 1; spin_unlock_irqrestore(&host->lock, flags); #endif + if (host->slot.cd_irq >= 0) + disable_irq(host->slot.cd_irq); host->rescan_disable = 1; cancel_delayed_work_sync(&host->detect); diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 47fa07e3604d..f7650b899e3d 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -139,7 +139,7 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio) } EXPORT_SYMBOL(mmc_gpio_request_ro); -static void mmc_gpiod_request_cd_irq(struct mmc_host *host) +void mmc_gpiod_request_cd_irq(struct mmc_host *host) { struct mmc_gpio *ctx = host->slot.handler_priv; int ret, irq; @@ -171,6 +171,7 @@ static void mmc_gpiod_request_cd_irq(struct mmc_host *host) if (irq < 0) host->caps |= MMC_CAP_NEEDS_POLL; } +EXPORT_SYMBOL(mmc_gpiod_request_cd_irq); /** * mmc_gpio_request_cd - request a gpio for card-detection @@ -276,3 +277,81 @@ void mmc_gpio_free_cd(struct mmc_host *host) devm_gpio_free(&host->class_dev, gpio); } EXPORT_SYMBOL(mmc_gpio_free_cd); + +/** + * mmc_gpiod_request_cd - request a gpio descriptor for card-detection + * @host: mmc host + * @con_id: function within the GPIO consumer + * @idx: index of the GPIO to obtain in the consumer + * @override_active_level: ignore %GPIO_ACTIVE_LOW flag + * @debounce: debounce time in microseconds + * + * Use this function in place of mmc_gpio_request_cd() to use the GPIO + * descriptor API. Note that it is paired with mmc_gpiod_free_cd() not + * mmc_gpio_free_cd(). Note also that it must be called prior to mmc_add_host() + * otherwise the caller must also call mmc_gpiod_request_cd_irq(). + * + * Returns zero on success, else an error. + */ +int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, + unsigned int idx, bool override_active_level, + unsigned int debounce) +{ + struct mmc_gpio *ctx; + struct gpio_desc *desc; + int ret; + + ret = mmc_gpio_alloc(host); + if (ret < 0) + return ret; + + ctx = host->slot.handler_priv; + + if (!con_id) + con_id = ctx->cd_label; + + desc = devm_gpiod_get_index(host->parent, con_id, idx); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + ret = gpiod_direction_input(desc); + if (ret < 0) + return ret; + + if (debounce) { + ret = gpiod_set_debounce(desc, debounce); + if (ret < 0) + return ret; + } + + ctx->override_cd_active_level = override_active_level; + ctx->cd_gpio = desc; + + return 0; +} +EXPORT_SYMBOL(mmc_gpiod_request_cd); + +/** + * mmc_gpiod_free_cd - free the card-detection gpio descriptor + * @host: mmc host + * + * It's provided only for cases that client drivers need to manually free + * up the card-detection gpio requested by mmc_gpiod_request_cd(). + */ +void mmc_gpiod_free_cd(struct mmc_host *host) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + + if (!ctx || !ctx->cd_gpio) + return; + + if (host->slot.cd_irq >= 0) { + devm_free_irq(&host->class_dev, host->slot.cd_irq, host); + host->slot.cd_irq = -EINVAL; + } + + devm_gpiod_put(&host->class_dev, ctx->cd_gpio); + + ctx->cd_gpio = NULL; +} +EXPORT_SYMBOL(mmc_gpiod_free_cd); diff --git a/include/linux/mmc/slot-gpio.h b/include/linux/mmc/slot-gpio.h index b0c73e4cacea..d2433381e828 100644 --- a/include/linux/mmc/slot-gpio.h +++ b/include/linux/mmc/slot-gpio.h @@ -22,4 +22,10 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, unsigned int debounce); void mmc_gpio_free_cd(struct mmc_host *host); +int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, + unsigned int idx, bool override_active_level, + unsigned int debounce); +void mmc_gpiod_free_cd(struct mmc_host *host); +void mmc_gpiod_request_cd_irq(struct mmc_host *host); + #endif -- cgit v1.2.3-70-g09d2