From 0dbcdc0622ea77fae87732c485ca13a1f9375571 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 21 Oct 2015 11:10:02 +0100 Subject: mmc: core: enable support for the standard "wakeup-source" property Though the mmc core driver should/will continue to support the legacy "enable-sdio-wakeup" property to enable SDIO as the wakeup source, we need to add support for the new standard property "wakeup-source". This patch adds support for "wakeup-source" property in addition to the existing "enable-sdio-wakeup" property. Cc: Adrian Hunter Signed-off-by: Sudeep Holla Signed-off-by: Ulf Hansson --- drivers/mmc/core/host.c | 3 ++- drivers/mmc/host/sdhci-pltfm.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index da950c44204d..e2cad924a26f 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -275,7 +275,8 @@ int mmc_of_parse(struct mmc_host *host) host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE; if (of_property_read_bool(np, "keep-power-in-suspend")) host->pm_caps |= MMC_PM_KEEP_POWER; - if (of_property_read_bool(np, "enable-sdio-wakeup")) + if (of_property_read_bool(np, "wakeup-source") || + of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */ host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; if (of_property_read_bool(np, "mmc-ddr-1_8v")) host->caps |= MMC_CAP_1_8V_DDR; diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 87fb5ea8ebe7..072bb27a65cf 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -104,7 +104,8 @@ void sdhci_get_of_property(struct platform_device *pdev) if (of_find_property(np, "keep-power-in-suspend", NULL)) host->mmc->pm_caps |= MMC_PM_KEEP_POWER; - if (of_find_property(np, "enable-sdio-wakeup", NULL)) + if (of_property_read_bool(np, "wakeup-source") || + of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */ host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; } #else -- cgit v1.2.3 From 3373cbf009e41a42c2ba6d3067fe6d2025003958 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Tue, 27 Oct 2015 17:56:31 +0100 Subject: mmc: sh_mmcif: Document r8a7793 DT bindings Signed-off-by: Ulrich Hecht Acked-by: Simon Horman [geert: Rebased] Signed-off-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/renesas,mmcif.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt index cae29eb5733d..ff611fa66871 100644 --- a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt +++ b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt @@ -11,6 +11,7 @@ Required properties: - "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs - "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs - "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs + - "renesas,mmcif-r8a7793" for the MMCIF found in r8a7793 SoCs - "renesas,mmcif-r8a7794" for the MMCIF found in r8a7794 SoCs - clocks: reference to the functional clock -- cgit v1.2.3 From dc28562bf2d67c1ccbcd7ebdfc261f4316c02113 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 3 Nov 2015 13:37:31 +0200 Subject: mmc: omap_hsmmc: No need to check DMA channel validity at module remove The driver will not probe without valid DMA channels so no need to check if they are valid when the module is removed. Signed-off-by: Peter Ujfalusi CC: Ulf Hansson Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 7fb0753abe30..b6639ea0bf18 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2250,10 +2250,8 @@ static int omap_hsmmc_remove(struct platform_device *pdev) pm_runtime_get_sync(host->dev); mmc_remove_host(host->mmc); - if (host->tx_chan) - dma_release_channel(host->tx_chan); - if (host->rx_chan) - dma_release_channel(host->rx_chan); + dma_release_channel(host->tx_chan); + dma_release_channel(host->rx_chan); pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); -- cgit v1.2.3 From 86236813ff23e0e8afc6844d307fb84df98f6723 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 5 Nov 2015 16:08:07 +0100 Subject: mmc: core: Invoke ->card_event() callback only when needed The ->card_event() callback may be called when re-scan is disabled and for non-removable cards, which both cases are unnecessary. Instead let's move the call later in mmc_rescan() where these constraints have been validated. Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 5ae89e48fd85..c1027a432785 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2567,11 +2567,6 @@ void mmc_rescan(struct work_struct *work) container_of(work, struct mmc_host, detect.work); int i; - if (host->trigger_card_event && host->ops->card_event) { - host->ops->card_event(host); - host->trigger_card_event = false; - } - if (host->rescan_disable) return; @@ -2580,6 +2575,11 @@ void mmc_rescan(struct work_struct *work) return; host->rescan_entered = 1; + if (host->trigger_card_event && host->ops->card_event) { + host->ops->card_event(host); + host->trigger_card_event = false; + } + mmc_bus_get(host); /* -- cgit v1.2.3 From d234d2123fa734c8018f7d01ed5d663cf5e6f665 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 5 Nov 2015 16:08:08 +0100 Subject: mmc: core: Keep host claimed in mmc_rescan() while calling host ops As mmc_claim_host() invokes pm_runtime_get_sync() for the mmc host device, it's important that the host is kept claimed for *all* accesses to it via the host_ops callbacks. In mmc_rescan(), the ->card_event() and the ->get_cd() callback are being invoked without claiming the host, let's fix this. Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index c1027a432785..394963d3fb18 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2576,7 +2576,9 @@ void mmc_rescan(struct work_struct *work) host->rescan_entered = 1; if (host->trigger_card_event && host->ops->card_event) { + mmc_claim_host(host); host->ops->card_event(host); + mmc_release_host(host); host->trigger_card_event = false; } @@ -2611,15 +2613,14 @@ void mmc_rescan(struct work_struct *work) */ mmc_bus_put(host); + mmc_claim_host(host); if (!(host->caps & MMC_CAP_NONREMOVABLE) && host->ops->get_cd && host->ops->get_cd(host) == 0) { - mmc_claim_host(host); mmc_power_off(host); mmc_release_host(host); goto out; } - mmc_claim_host(host); for (i = 0; i < ARRAY_SIZE(freqs); i++) { if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) break; -- cgit v1.2.3 From c29536e85b5f7cf42b2e761f7ff35bc97de7cf95 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 5 Nov 2015 16:01:32 +0100 Subject: mmc: core: Make runtime resume default behavior for MMC/SD MMC_CAP_RUNTIME_RESUME was invented to decrease system PM resume time for systems that particularly needs this. As the feature has matured let's make it the default behavior for MMC/SD. Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 15 ++------------- drivers/mmc/core/sd.c | 15 ++------------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 3a9a79ec4343..66957addf9e4 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1907,16 +1907,8 @@ static int mmc_shutdown(struct mmc_host *host) */ static int mmc_resume(struct mmc_host *host) { - int err = 0; - - if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) { - err = _mmc_resume(host); - pm_runtime_set_active(&host->card->dev); - pm_runtime_mark_last_busy(&host->card->dev); - } pm_runtime_enable(&host->card->dev); - - return err; + return 0; } /* @@ -1944,12 +1936,9 @@ static int mmc_runtime_resume(struct mmc_host *host) { int err; - if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME))) - return 0; - err = _mmc_resume(host); if (err) - pr_err("%s: error %d doing aggressive resume\n", + pr_err("%s: error %d doing runtime resume\n", mmc_hostname(host), err); return 0; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 141eaa923e18..8f3b46a56b3d 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1128,16 +1128,8 @@ out: */ static int mmc_sd_resume(struct mmc_host *host) { - int err = 0; - - if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) { - err = _mmc_sd_resume(host); - pm_runtime_set_active(&host->card->dev); - pm_runtime_mark_last_busy(&host->card->dev); - } pm_runtime_enable(&host->card->dev); - - return err; + return 0; } /* @@ -1165,12 +1157,9 @@ static int mmc_sd_runtime_resume(struct mmc_host *host) { int err; - if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME))) - return 0; - err = _mmc_sd_resume(host); if (err) - pr_err("%s: error %d doing aggressive resume\n", + pr_err("%s: error %d doing runtime resume\n", mmc_hostname(host), err); return 0; -- cgit v1.2.3 From 7b6471a968bf95e8d526393de125df3bc0c6a73a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 5 Nov 2015 16:01:33 +0100 Subject: mmc: core: Remove MMC_CAP_RUNTIME_RESUME as it's redundant Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-rockchip.c | 8 -------- drivers/mmc/host/mtk-sd.c | 1 - include/linux/mmc/host.h | 1 - 3 files changed, 10 deletions(-) diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 9becebeeccd1..d9c92f31da64 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -239,20 +239,12 @@ static int dw_mci_rockchip_init(struct dw_mci *host) return 0; } -/* Common capabilities of RK3288 SoC */ -static unsigned long dw_mci_rk3288_dwmmc_caps[4] = { - MMC_CAP_RUNTIME_RESUME, /* emmc */ - MMC_CAP_RUNTIME_RESUME, /* sdmmc */ - MMC_CAP_RUNTIME_RESUME, /* sdio0 */ - MMC_CAP_RUNTIME_RESUME, /* sdio1 */ -}; static const struct dw_mci_drv_data rk2928_drv_data = { .prepare_command = dw_mci_rockchip_prepare_command, .init = dw_mci_rockchip_init, }; static const struct dw_mci_drv_data rk3288_drv_data = { - .caps = dw_mci_rk3288_dwmmc_caps, .prepare_command = dw_mci_rockchip_prepare_command, .set_ios = dw_mci_rk3288_set_ios, .execute_tuning = dw_mci_rk3288_execute_tuning, diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 33dfd7e72516..a5beb3618240 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1543,7 +1543,6 @@ static int msdc_drv_probe(struct platform_device *pdev) mmc->f_min = host->src_clk_freq / (4 * 255); mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23; - mmc->caps |= MMC_CAP_RUNTIME_RESUME; /* MMC core transfer sizes tunable parameters */ mmc->max_segs = MAX_BD_NUM; mmc->max_seg_size = BDMA_DESC_BUFLEN; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 8673ffe3d86e..9b04e717bb86 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -259,7 +259,6 @@ struct mmc_host { #define MMC_CAP_UHS_SDR50 (1 << 17) /* Host supports UHS SDR50 mode */ #define MMC_CAP_UHS_SDR104 (1 << 18) /* Host supports UHS SDR104 mode */ #define MMC_CAP_UHS_DDR50 (1 << 19) /* Host supports UHS DDR50 mode */ -#define MMC_CAP_RUNTIME_RESUME (1 << 20) /* Resume at runtime_resume. */ #define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */ #define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */ #define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */ -- cgit v1.2.3 From 8dede18e2e86c8e272cd74e66b0e86872cbe7e02 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 5 Nov 2015 16:11:12 +0100 Subject: mmc: core: Refactor code to register the MMC PM notifier Instead of checking for "#ifdef" directly in the code, let's invent a pair of mmc core functions to deal with register/unregister the MMC PM notifier block. Implement stubs for these functions when CONFIG_PM_SLEEP is unset, as in that case the PM notifiers isn't used. Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 18 ++++++++++++++---- drivers/mmc/core/core.h | 8 ++++++++ drivers/mmc/core/host.c | 8 ++------ include/linux/mmc/host.h | 4 ++-- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 394963d3fb18..18a3f2c41136 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2760,14 +2760,13 @@ int mmc_flush_cache(struct mmc_card *card) } EXPORT_SYMBOL(mmc_flush_cache); -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP /* Do the card removal on suspend if card is assumed removeable * Do that in pm notifier while userspace isn't yet frozen, so we will be able to sync the card. */ -int mmc_pm_notify(struct notifier_block *notify_block, - unsigned long mode, void *unused) +static int mmc_pm_notify(struct notifier_block *notify_block, + unsigned long mode, void *unused) { struct mmc_host *host = container_of( notify_block, struct mmc_host, pm_notify); @@ -2814,6 +2813,17 @@ int mmc_pm_notify(struct notifier_block *notify_block, return 0; } + +void mmc_register_pm_notifier(struct mmc_host *host) +{ + host->pm_notify.notifier_call = mmc_pm_notify; + register_pm_notifier(&host->pm_notify); +} + +void mmc_unregister_pm_notifier(struct mmc_host *host) +{ + unregister_pm_notifier(&host->pm_notify); +} #endif /** diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 09241e56d628..bd00ac2cdc1b 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -90,5 +90,13 @@ int mmc_execute_tuning(struct mmc_card *card); int mmc_hs200_to_hs400(struct mmc_card *card); int mmc_hs400_to_hs200(struct mmc_card *card); +#ifdef CONFIG_PM_SLEEP +void mmc_register_pm_notifier(struct mmc_host *host); +void mmc_unregister_pm_notifier(struct mmc_host *host); +#else +static void mmc_register_pm_notifier(struct mmc_host *host) { } +static void mmc_unregister_pm_notifier(struct mmc_host *host) { } +#endif + #endif diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index e2cad924a26f..0aecd5c00b86 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -349,9 +348,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_DELAYED_WORK(&host->detect, mmc_rescan); -#ifdef CONFIG_PM - host->pm_notify.notifier_call = mmc_pm_notify; -#endif setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host); /* @@ -396,7 +392,7 @@ int mmc_add_host(struct mmc_host *host) #endif mmc_start_host(host); - register_pm_notifier(&host->pm_notify); + mmc_register_pm_notifier(host); return 0; } @@ -413,7 +409,7 @@ EXPORT_SYMBOL(mmc_add_host); */ void mmc_remove_host(struct mmc_host *host) { - unregister_pm_notifier(&host->pm_notify); + mmc_unregister_pm_notifier(host); mmc_stop_host(host); #ifdef CONFIG_DEBUG_FS diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 9b04e717bb86..f39888cf5017 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -212,7 +212,9 @@ struct mmc_host { u32 ocr_avail_sdio; /* SDIO-specific OCR */ u32 ocr_avail_sd; /* SD-specific OCR */ u32 ocr_avail_mmc; /* MMC-specific OCR */ +#ifdef CONFIG_PM_SLEEP struct notifier_block pm_notify; +#endif u32 max_current_330; u32 max_current_300; u32 max_current_180; @@ -433,8 +435,6 @@ static inline int mmc_regulator_set_vqmmc(struct mmc_host *mmc, int mmc_regulator_get_supply(struct mmc_host *mmc); -int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *); - static inline int mmc_card_is_removable(struct mmc_host *host) { return !(host->caps & MMC_CAP_NONREMOVABLE); -- cgit v1.2.3 From 1ff2575bcf42caefaaab8e2fb00e238852fac8e2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 5 Nov 2015 16:21:39 +0100 Subject: mmc: core: Check for non-removable cards earlier in the error path _mmc_detect_card_removed() validates that the card is removable, but when being called via the bus_ops ->detect() callbacks, the validation is redundant as it's already done in mmc_rescan(). Move the validation of a removable card to the mmc_detect_card_removed() API, which is where it's applicable, to allow the blk error recovery path to get the response a bit earlier. Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 18a3f2c41136..a450e91504f3 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2498,9 +2498,6 @@ int _mmc_detect_card_removed(struct mmc_host *host) { int ret; - if (host->caps & MMC_CAP_NONREMOVABLE) - return 0; - if (!host->card || mmc_card_removed(host->card)) return 1; @@ -2536,6 +2533,9 @@ int mmc_detect_card_removed(struct mmc_host *host) if (!card) return 1; + if (host->caps & MMC_CAP_NONREMOVABLE) + return 0; + ret = mmc_card_removed(card); /* * The card will be considered unchanged unless we have been asked to -- cgit v1.2.3 From 6e1bbc51439705b834688c592e13dfa82e32ff04 Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Mon, 9 Nov 2015 15:03:59 +0100 Subject: mmc: core: set regulator not found message as debug Turn the informative message about no vmmc/vqmmc regulator found in debug one. There is no need to indicate that something optional is missing. Moreover, it can bring confusion, people who doesn't know it is optional may consider these messages as warnings or errors. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index a450e91504f3..07b2f086213f 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1485,7 +1485,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) if (IS_ERR(mmc->supply.vmmc)) { if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER) return -EPROBE_DEFER; - dev_info(dev, "No vmmc regulator found\n"); + dev_dbg(dev, "No vmmc regulator found\n"); } else { ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc); if (ret > 0) @@ -1497,7 +1497,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) if (IS_ERR(mmc->supply.vqmmc)) { if (PTR_ERR(mmc->supply.vqmmc) == -EPROBE_DEFER) return -EPROBE_DEFER; - dev_info(dev, "No vqmmc regulator found\n"); + dev_dbg(dev, "No vqmmc regulator found\n"); } return 0; -- cgit v1.2.3 From 1ff8950c04331883b11c5e0d6db96e2da8b6f8c9 Mon Sep 17 00:00:00 2001 From: yalin wang Date: Thu, 12 Nov 2015 19:27:11 +0800 Subject: mmc: block: change to use kmalloc when copy data from userspace Use kmalloc instead of kzalloc, as zeroing the memory isn't needed. Signed-off-by: yalin wang Signed-off-by: Ulf Hansson --- drivers/mmc/card/block.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index d8486168415a..ce38960cca12 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -344,7 +344,7 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( struct mmc_blk_ioc_data *idata; int err; - idata = kzalloc(sizeof(*idata), GFP_KERNEL); + idata = kmalloc(sizeof(*idata), GFP_KERNEL); if (!idata) { err = -ENOMEM; goto out; @@ -364,7 +364,7 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( if (!idata->buf_bytes) return idata; - idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL); + idata->buf = kmalloc(idata->buf_bytes, GFP_KERNEL); if (!idata->buf) { err = -ENOMEM; goto idata_err; -- cgit v1.2.3 From 28ff4fda9e5b4917375a49a3c6f76aed0cdd55ae Mon Sep 17 00:00:00 2001 From: Adrien Schildknecht Date: Tue, 10 Nov 2015 20:12:19 +0100 Subject: mmc: kconfig: replace FAULT_INJECTION with FAULT_INJECTION_DEBUG_FS Fault-injection capability for MMC IO uses debugfs entries to configure the attributes. FAULT_INJECTION_DEBUG_FS must be enabled to use FAIL_MMC_REQUEST. Replace FAULT_INJECTION with FAULT_INJECTION_DEBUG_FS. Also remove 'select DEBUG_FS' since FAULT_INJECTION_DEBUG_FS depends on it. Signed-off-by: Adrien Schildknecht Signed-off-by: Ulf Hansson --- lib/Kconfig.debug | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 8c15b29d5adc..cdbf7fd69eb9 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1523,8 +1523,7 @@ config FAIL_IO_TIMEOUT config FAIL_MMC_REQUEST bool "Fault-injection capability for MMC IO" - select DEBUG_FS - depends on FAULT_INJECTION && MMC + depends on FAULT_INJECTION_DEBUG_FS && MMC help Provide fault-injection capability for MMC IO. This will make the mmc core return data errors. This is -- cgit v1.2.3 From f5f17813ae9b80fc8458281014c308e5121e0a4e Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Wed, 11 Nov 2015 19:11:48 +0100 Subject: mmc: sdhci-of-at91: add PM support Add runtime PM support and use runtime_force_suspend|resume() for system PM. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-at91.c | 75 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 06d0b50dfe71..7e7d8f0c9438 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "sdhci-pltfm.h" @@ -51,6 +53,60 @@ static const struct of_device_id sdhci_at91_dt_match[] = { {} }; +#ifdef CONFIG_PM +static int sdhci_at91_runtime_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_at91_priv *priv = pltfm_host->priv; + int ret; + + ret = sdhci_runtime_suspend_host(host); + + clk_disable_unprepare(priv->gck); + clk_disable_unprepare(priv->hclock); + clk_disable_unprepare(priv->mainck); + + return ret; +} + +static int sdhci_at91_runtime_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_at91_priv *priv = pltfm_host->priv; + int ret; + + ret = clk_prepare_enable(priv->mainck); + if (ret) { + dev_err(dev, "can't enable mainck\n"); + return ret; + } + + ret = clk_prepare_enable(priv->hclock); + if (ret) { + dev_err(dev, "can't enable hclock\n"); + return ret; + } + + ret = clk_prepare_enable(priv->gck); + if (ret) { + dev_err(dev, "can't enable gck\n"); + return ret; + } + + return sdhci_runtime_resume_host(host); +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops sdhci_at91_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(sdhci_at91_runtime_suspend, + sdhci_at91_runtime_resume, + NULL) +}; + static int sdhci_at91_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -144,12 +200,23 @@ static int sdhci_at91_probe(struct platform_device *pdev) sdhci_get_of_property(pdev); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 50); + pm_runtime_use_autosuspend(&pdev->dev); + ret = sdhci_add_host(host); if (ret) - goto clocks_disable_unprepare; + goto pm_runtime_disable; + + pm_runtime_put_autosuspend(&pdev->dev); return 0; +pm_runtime_disable: + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); clocks_disable_unprepare: clk_disable_unprepare(priv->gck); clk_disable_unprepare(priv->mainck); @@ -165,6 +232,10 @@ static int sdhci_at91_remove(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_at91_priv *priv = pltfm_host->priv; + pm_runtime_get_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + sdhci_pltfm_unregister(pdev); clk_disable_unprepare(priv->gck); @@ -178,7 +249,7 @@ static struct platform_driver sdhci_at91_driver = { .driver = { .name = "sdhci-at91", .of_match_table = sdhci_at91_dt_match, - .pm = SDHCI_PLTFM_PMOPS, + .pm = &sdhci_at91_dev_pm_ops, }, .probe = sdhci_at91_probe, .remove = sdhci_at91_remove, -- cgit v1.2.3 From d49d19c2a8f90be7f9cccb527e80175d9454e851 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 16 Nov 2015 10:27:14 +0100 Subject: mmc: tegra: Constify SoC data The data in the SoC description structures is static and can therefore reside in read-only memory. Signed-off-by: Thierry Reding Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index ad28b49f0203..8d49d9af6f54 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -184,7 +184,7 @@ static const struct sdhci_pltfm_data sdhci_tegra20_pdata = { .ops = &tegra_sdhci_ops, }; -static struct sdhci_tegra_soc_data soc_data_tegra20 = { +static const struct sdhci_tegra_soc_data soc_data_tegra20 = { .pdata = &sdhci_tegra20_pdata, .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 | NVQUIRK_ENABLE_BLOCK_GAP_DET, @@ -200,7 +200,7 @@ static const struct sdhci_pltfm_data sdhci_tegra30_pdata = { .ops = &tegra_sdhci_ops, }; -static struct sdhci_tegra_soc_data soc_data_tegra30 = { +static const struct sdhci_tegra_soc_data soc_data_tegra30 = { .pdata = &sdhci_tegra30_pdata, .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 | NVQUIRK_DISABLE_SDR50 | @@ -229,7 +229,7 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { .ops = &tegra114_sdhci_ops, }; -static struct sdhci_tegra_soc_data soc_data_tegra114 = { +static const struct sdhci_tegra_soc_data soc_data_tegra114 = { .pdata = &sdhci_tegra114_pdata, .nvquirks = NVQUIRK_DISABLE_SDR50 | NVQUIRK_DISABLE_DDR50 | -- cgit v1.2.3 From b5a84ecf025add96b11f778a5a9d455ab5fddff2 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 16 Nov 2015 10:27:15 +0100 Subject: mmc: tegra: Add Tegra210 support Signed-off-by: Thierry Reding Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 8d49d9af6f54..368f1b74a525 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -236,7 +236,24 @@ static const struct sdhci_tegra_soc_data soc_data_tegra114 = { NVQUIRK_DISABLE_SDR104, }; +static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { + .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | + SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_NO_HISPD_BIT | + SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, + .ops = &tegra114_sdhci_ops, +}; + +static const struct sdhci_tegra_soc_data soc_data_tegra210 = { + .pdata = &sdhci_tegra210_pdata, + .nvquirks = NVQUIRK_DISABLE_SDR50 | + NVQUIRK_DISABLE_DDR50 | + NVQUIRK_DISABLE_SDR104, +}; + static const struct of_device_id sdhci_tegra_dt_match[] = { + { .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 }, { .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra114 }, { .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 }, { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, -- cgit v1.2.3 From ffedbd2210f2f4cba490a9205adc11fd1b89a852 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 14 Nov 2015 18:05:20 +0100 Subject: mmc: pwrseq: constify mmc_pwrseq_ops structures The mmc_pwrseq_ops structures are never modified, so declare them as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Ulf Hansson --- drivers/mmc/core/pwrseq.h | 2 +- drivers/mmc/core/pwrseq_emmc.c | 2 +- drivers/mmc/core/pwrseq_simple.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h index 096da48c6a7e..133de0426687 100644 --- a/drivers/mmc/core/pwrseq.h +++ b/drivers/mmc/core/pwrseq.h @@ -16,7 +16,7 @@ struct mmc_pwrseq_ops { }; struct mmc_pwrseq { - struct mmc_pwrseq_ops *ops; + const struct mmc_pwrseq_ops *ops; }; #ifdef CONFIG_OF diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c index ad4f94ec7e8d..4a82bc77fe49 100644 --- a/drivers/mmc/core/pwrseq_emmc.c +++ b/drivers/mmc/core/pwrseq_emmc.c @@ -51,7 +51,7 @@ static void mmc_pwrseq_emmc_free(struct mmc_host *host) kfree(pwrseq); } -static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { +static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { .post_power_on = mmc_pwrseq_emmc_reset, .free = mmc_pwrseq_emmc_free, }; diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index d10538bb5e07..2b16263458af 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -87,7 +87,7 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host) kfree(pwrseq); } -static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = { +static const struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = { .pre_power_on = mmc_pwrseq_simple_pre_power_on, .post_power_on = mmc_pwrseq_simple_post_power_on, .power_off = mmc_pwrseq_simple_power_off, -- cgit v1.2.3 From 2e4456f08fa81b9a4804379c56c7ef02c0b0d8f0 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 18 Nov 2015 10:47:02 +0100 Subject: mmc: sdhci: Fix strings broken across multiple lines This is a trivial patch which fixes printed strings split across two or more lines in the source. I tried to grep for some error output*, but I couldn't find it easily because it was broken across multiple lines. This patch makes my life easier. * in particular "Timeout waiting for hardware interrupt." Signed-off-by: Marek Vasut Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 57 +++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index b48565ed5616..2b17cc1246ca 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -768,8 +768,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) if (unlikely(broken)) { for_each_sg(data->sg, sg, data->sg_len, i) { if (sg->length & 0x3) { - DBG("Reverting to PIO because of " - "transfer size (%d)\n", + DBG("Reverting to PIO because of transfer size (%d)\n", sg->length); host->flags &= ~SDHCI_REQ_USE_DMA; break; @@ -803,8 +802,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) if (unlikely(broken)) { for_each_sg(data->sg, sg, data->sg_len, i) { if (sg->offset & 0x3) { - DBG("Reverting to PIO because of " - "bad alignment\n"); + DBG("Reverting to PIO because of bad alignment\n"); host->flags &= ~SDHCI_REQ_USE_DMA; break; } @@ -1016,8 +1014,8 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { if (timeout == 0) { - pr_err("%s: Controller never released " - "inhibit bit(s).\n", mmc_hostname(host->mmc)); + pr_err("%s: Controller never released inhibit bit(s).\n", + mmc_hostname(host->mmc)); sdhci_dumpregs(host); cmd->error = -EIO; tasklet_schedule(&host->finish_tasklet); @@ -1254,8 +1252,8 @@ clock_set: while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { - pr_err("%s: Internal clock never " - "stabilised.\n", mmc_hostname(host->mmc)); + pr_err("%s: Internal clock never stabilised.\n", + mmc_hostname(host->mmc)); sdhci_dumpregs(host); return; } @@ -1540,8 +1538,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) else if (ios->drv_type == MMC_SET_DRIVER_TYPE_D) ctrl_2 |= SDHCI_CTRL_DRV_TYPE_D; else { - pr_warn("%s: invalid driver type, default to " - "driver type B\n", mmc_hostname(mmc)); + pr_warn("%s: invalid driver type, default to driver type B\n", + mmc_hostname(mmc)); ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B; } @@ -2015,10 +2013,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) spin_lock_irqsave(&host->lock, flags); if (!host->tuning_done) { - pr_info(DRIVER_NAME ": Timeout waiting for " - "Buffer Read Ready interrupt during tuning " - "procedure, falling back to fixed sampling " - "clock\n"); + pr_info(DRIVER_NAME ": Timeout waiting for Buffer Read Ready interrupt during tuning procedure, falling back to fixed sampling clock\n"); ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); ctrl &= ~SDHCI_CTRL_TUNED_CLK; ctrl &= ~SDHCI_CTRL_EXEC_TUNING; @@ -2046,9 +2041,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); } if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { - pr_info(DRIVER_NAME ": Tuning procedure" - " failed, falling back to fixed sampling" - " clock\n"); + pr_info(DRIVER_NAME ": Tuning procedure failed, falling back to fixed sampling clock\n"); err = -EIO; } @@ -2293,8 +2286,8 @@ static void sdhci_timeout_timer(unsigned long data) spin_lock_irqsave(&host->lock, flags); if (host->mrq) { - pr_err("%s: Timeout waiting for hardware " - "interrupt.\n", mmc_hostname(host->mmc)); + pr_err("%s: Timeout waiting for hardware interrupt.\n", + mmc_hostname(host->mmc)); sdhci_dumpregs(host); if (host->data) { @@ -2325,9 +2318,8 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) BUG_ON(intmask == 0); if (!host->cmd) { - pr_err("%s: Got command interrupt 0x%08x even " - "though no command operation was in progress.\n", - mmc_hostname(host->mmc), (unsigned)intmask); + pr_err("%s: Got command interrupt 0x%08x even though no command operation was in progress.\n", + mmc_hostname(host->mmc), (unsigned)intmask); sdhci_dumpregs(host); return; } @@ -2356,8 +2348,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) */ if (host->cmd->flags & MMC_RSP_BUSY) { if (host->cmd->data) - DBG("Cannot wait for busy signal when also " - "doing a data transfer"); + DBG("Cannot wait for busy signal when also doing a data transfer"); else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) && !host->busy_handle) { /* Mark that command complete before busy is ended */ @@ -2451,9 +2442,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } } - pr_err("%s: Got data interrupt 0x%08x even " - "though no data operation was in progress.\n", - mmc_hostname(host->mmc), (unsigned)intmask); + pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n", + mmc_hostname(host->mmc), (unsigned)intmask); sdhci_dumpregs(host); return; @@ -2896,9 +2886,8 @@ int sdhci_add_host(struct sdhci_host *host) host->version = (host->version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; if (host->version > SDHCI_SPEC_300) { - pr_err("%s: Unknown controller version (%d). " - "You may experience problems.\n", mmc_hostname(mmc), - host->version); + pr_err("%s: Unknown controller version (%d). You may experience problems.\n", + mmc_hostname(mmc), host->version); } caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps : @@ -3031,8 +3020,8 @@ int sdhci_add_host(struct sdhci_host *host) if (host->max_clk == 0 || host->quirks & SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) { if (!host->ops->get_max_clock) { - pr_err("%s: Hardware doesn't specify base clock " - "frequency.\n", mmc_hostname(mmc)); + pr_err("%s: Hardware doesn't specify base clock frequency.\n", + mmc_hostname(mmc)); return -ENODEV; } host->max_clk = host->ops->get_max_clock(host); @@ -3294,8 +3283,8 @@ int sdhci_add_host(struct sdhci_host *host) mmc->ocr_avail_mmc &= host->ocr_avail_mmc; if (mmc->ocr_avail == 0) { - pr_err("%s: Hardware doesn't report any " - "support voltages.\n", mmc_hostname(mmc)); + pr_err("%s: Hardware doesn't report any support voltages.\n", + mmc_hostname(mmc)); return -ENODEV; } -- cgit v1.2.3 From 27cbd7e815a8e223ff7c4fe56daca724101288ac Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 16 Nov 2015 17:08:41 +0100 Subject: mmc: sh_mmcif: rework dma channel handling When compiling the sh_mmcif driver for ARM64, we currently get a harmless build warning: ../drivers/mmc/host/sh_mmcif.c: In function 'sh_mmcif_request_dma_one': ../drivers/mmc/host/sh_mmcif.c:417:4: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] (void *)pdata->slave_id_tx : ^ ../drivers/mmc/host/sh_mmcif.c:418:4: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] (void *)pdata->slave_id_rx; This could be worked around by adding another cast to uintptr_t, but I decided to simplify the code a little more to avoid that. This splits out the platform data using code into a separate function and builds that only for CONFIG_SUPERH. This part still has a typecast but does not need a second one. The SH platform code could be further modified to pass a pointer directly as we do on other architectures when we have a filter function. The normal case is simplified further and now just calls dma_request_slave_channel() directly without going through the compat handling. Signed-off-by: Arnd Bergmann Signed-off-by: Ulf Hansson --- drivers/mmc/host/sh_mmcif.c | 84 ++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 46 deletions(-) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index ad9ffea7d659..1ca8a1359cbc 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -397,38 +397,26 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) } static struct dma_chan * -sh_mmcif_request_dma_one(struct sh_mmcif_host *host, - struct sh_mmcif_plat_data *pdata, - enum dma_transfer_direction direction) +sh_mmcif_request_dma_pdata(struct sh_mmcif_host *host, uintptr_t slave_id) { - struct dma_slave_config cfg = { 0, }; - struct dma_chan *chan; - void *slave_data = NULL; - struct resource *res; - struct device *dev = sh_mmcif_host_to_dev(host); dma_cap_mask_t mask; - int ret; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); + if (slave_id <= 0) + return NULL; - if (pdata) - slave_data = direction == DMA_MEM_TO_DEV ? - (void *)pdata->slave_id_tx : - (void *)pdata->slave_id_rx; - - chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, - slave_data, dev, - direction == DMA_MEM_TO_DEV ? "tx" : "rx"); - - dev_dbg(dev, "%s: %s: got channel %p\n", __func__, - direction == DMA_MEM_TO_DEV ? "TX" : "RX", chan); + return dma_request_channel(mask, shdma_chan_filter, (void *)slave_id); +} - if (!chan) - return NULL; +static int sh_mmcif_dma_slave_config(struct sh_mmcif_host *host, + struct dma_chan *chan, + enum dma_transfer_direction direction) +{ + struct resource *res; + struct dma_slave_config cfg = { 0, }; res = platform_get_resource(host->pd, IORESOURCE_MEM, 0); - cfg.direction = direction; if (direction == DMA_DEV_TO_MEM) { @@ -439,38 +427,42 @@ sh_mmcif_request_dma_one(struct sh_mmcif_host *host, cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; } - ret = dmaengine_slave_config(chan, &cfg); - if (ret < 0) { - dma_release_channel(chan); - return NULL; - } - - return chan; + return dmaengine_slave_config(chan, &cfg); } -static void sh_mmcif_request_dma(struct sh_mmcif_host *host, - struct sh_mmcif_plat_data *pdata) +static void sh_mmcif_request_dma(struct sh_mmcif_host *host) { struct device *dev = sh_mmcif_host_to_dev(host); host->dma_active = false; - if (pdata) { - if (pdata->slave_id_tx <= 0 || pdata->slave_id_rx <= 0) - return; - } else if (!dev->of_node) { - return; + /* We can only either use DMA for both Tx and Rx or not use it at all */ + if (IS_ENABLED(CONFIG_SUPERH) && dev->platform_data) { + struct sh_mmcif_plat_data *pdata = dev->platform_data; + + host->chan_tx = sh_mmcif_request_dma_pdata(host, + pdata->slave_id_tx); + host->chan_rx = sh_mmcif_request_dma_pdata(host, + pdata->slave_id_rx); + } else { + host->chan_tx = dma_request_slave_channel(dev, "tx"); + host->chan_tx = dma_request_slave_channel(dev, "rx"); } + dev_dbg(dev, "%s: got channel TX %p RX %p\n", __func__, host->chan_tx, + host->chan_rx); - /* We can only either use DMA for both Tx and Rx or not use it at all */ - host->chan_tx = sh_mmcif_request_dma_one(host, pdata, DMA_MEM_TO_DEV); - if (!host->chan_tx) - return; + if (!host->chan_tx || !host->chan_rx || + sh_mmcif_dma_slave_config(host, host->chan_tx, DMA_MEM_TO_DEV) || + sh_mmcif_dma_slave_config(host, host->chan_rx, DMA_DEV_TO_MEM)) + goto error; - host->chan_rx = sh_mmcif_request_dma_one(host, pdata, DMA_DEV_TO_MEM); - if (!host->chan_rx) { + return; + +error: + if (host->chan_tx) dma_release_channel(host->chan_tx); - host->chan_tx = NULL; - } + if (host->chan_rx) + dma_release_channel(host->chan_rx); + host->chan_tx = host->chan_rx = NULL; } static void sh_mmcif_release_dma(struct sh_mmcif_host *host) @@ -1102,7 +1094,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->power_mode == MMC_POWER_UP) { if (!host->card_present) { /* See if we also get DMA */ - sh_mmcif_request_dma(host, dev->platform_data); + sh_mmcif_request_dma(host); host->card_present = true; } sh_mmcif_set_power(host, ios); -- cgit v1.2.3 From 260ecb3c915fae3d67bf0378016ae68929be3b0e Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 10 Nov 2015 17:43:30 +0800 Subject: mmc: sdhci-esdhc-imx: correct the tuning-step setting Here we use '|=' to set the tuning-step, but before that, we should clear the tuning-step, otherwise we could got the wrong setting. Signed-off-by: Haibo Chen Acked-by: Dong Aisheng Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 1f1582f6cccb..f25f29253595 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -76,6 +76,7 @@ #define ESDHC_STD_TUNING_EN (1 << 24) /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ #define ESDHC_TUNING_START_TAP 0x1 +#define ESDHC_TUNING_STEP_MASK 0x00070000 #define ESDHC_TUNING_STEP_SHIFT 16 /* pinctrl state */ @@ -489,9 +490,11 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) m |= ESDHC_MIX_CTRL_FBCLK_SEL; tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL); tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP; - if (imx_data->boarddata.tuning_step) + if (imx_data->boarddata.tuning_step) { + tuning_ctrl &= ~ESDHC_TUNING_STEP_MASK; tuning_ctrl |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT; - writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL); + } + writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL); } else { v &= ~ESDHC_MIX_CTRL_EXE_TUNE; } -- cgit v1.2.3 From fb0229dfec3df9247190f001f1b51d767f2ee035 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 20 Nov 2015 11:28:42 +0100 Subject: mmc: fix mmc_{un,}register_pm_notifier prototypes The mmc pm notifiers were recently reworked, but the new code produces a lot of warnings when CONFIG_PM_SLEEP is disabled: In file included from ../drivers/mmc/core/sdio_bus.c:27:0: drivers/mmc/core/core.h:97:13: warning: 'mmc_register_pm_notifier' defined but not used [-Wunused-function] The obvious solution is to add the 'inline' keyword at the function definition, as it should be for any function defined in a header file. Signed-off-by: Arnd Bergmann Fixes: 0e40be7c20e0 ("mmc: core: Refactor code to register the MMC PM notifier") Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index bd00ac2cdc1b..0fa86a2afc26 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -94,8 +94,8 @@ int mmc_hs400_to_hs200(struct mmc_card *card); void mmc_register_pm_notifier(struct mmc_host *host); void mmc_unregister_pm_notifier(struct mmc_host *host); #else -static void mmc_register_pm_notifier(struct mmc_host *host) { } -static void mmc_unregister_pm_notifier(struct mmc_host *host) { } +static inline void mmc_register_pm_notifier(struct mmc_host *host) { } +static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { } #endif #endif -- cgit v1.2.3 From ec8fc9cfa060fa41b84fdcf931b90ab2841a64bd Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Mon, 23 Nov 2015 16:27:30 +0100 Subject: mmc: atmel-mci: move atmel-mci-regs.h content in atmel-mci.c atmel-mci-regs.h is only included in atmel-mci.c so move its content in the driver and do some cleanup in these definitions to remove checkpatch errors. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci-regs.h | 171 -------------------------------------- drivers/mmc/host/atmel-mci.c | 150 ++++++++++++++++++++++++++++++++- 2 files changed, 149 insertions(+), 172 deletions(-) delete mode 100644 drivers/mmc/host/atmel-mci-regs.h diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h deleted file mode 100644 index 0aa44e679df4..000000000000 --- a/drivers/mmc/host/atmel-mci-regs.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Atmel MultiMedia Card Interface driver - * - * Copyright (C) 2004-2006 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors - * Registers and bitfields marked with [2] are only available in MCI2 - */ - -#ifndef __DRIVERS_MMC_ATMEL_MCI_H__ -#define __DRIVERS_MMC_ATMEL_MCI_H__ - -/* MCI Register Definitions */ -#define ATMCI_CR 0x0000 /* Control */ -# define ATMCI_CR_MCIEN ( 1 << 0) /* MCI Enable */ -# define ATMCI_CR_MCIDIS ( 1 << 1) /* MCI Disable */ -# define ATMCI_CR_PWSEN ( 1 << 2) /* Power Save Enable */ -# define ATMCI_CR_PWSDIS ( 1 << 3) /* Power Save Disable */ -# define ATMCI_CR_SWRST ( 1 << 7) /* Software Reset */ -#define ATMCI_MR 0x0004 /* Mode */ -# define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */ -# define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */ -# define ATMCI_MR_RDPROOF ( 1 << 11) /* Read Proof */ -# define ATMCI_MR_WRPROOF ( 1 << 12) /* Write Proof */ -# define ATMCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */ -# define ATMCI_MR_PDCPADV ( 1 << 14) /* Padding Value */ -# define ATMCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */ -# define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */ -#define ATMCI_DTOR 0x0008 /* Data Timeout */ -# define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ -# define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ -#define ATMCI_SDCR 0x000c /* SD Card / SDIO */ -# define ATMCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */ -# define ATMCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */ -# define ATMCI_SDCSEL_MASK ( 3 << 0) -# define ATMCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */ -# define ATMCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */ -# define ATMCI_SDCBUS_8BIT ( 3 << 6) /* 8-bit data bus[2] */ -# define ATMCI_SDCBUS_MASK ( 3 << 6) -#define ATMCI_ARGR 0x0010 /* Command Argument */ -#define ATMCI_CMDR 0x0014 /* Command */ -# define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */ -# define ATMCI_CMDR_RSPTYP_NONE ( 0 << 6) /* No response */ -# define ATMCI_CMDR_RSPTYP_48BIT ( 1 << 6) /* 48-bit response */ -# define ATMCI_CMDR_RSPTYP_136BIT ( 2 << 6) /* 136-bit response */ -# define ATMCI_CMDR_SPCMD_INIT ( 1 << 8) /* Initialization command */ -# define ATMCI_CMDR_SPCMD_SYNC ( 2 << 8) /* Synchronized command */ -# define ATMCI_CMDR_SPCMD_INT ( 4 << 8) /* Interrupt command */ -# define ATMCI_CMDR_SPCMD_INTRESP ( 5 << 8) /* Interrupt response */ -# define ATMCI_CMDR_OPDCMD ( 1 << 11) /* Open Drain */ -# define ATMCI_CMDR_MAXLAT_5CYC ( 0 << 12) /* Max latency 5 cycles */ -# define ATMCI_CMDR_MAXLAT_64CYC ( 1 << 12) /* Max latency 64 cycles */ -# define ATMCI_CMDR_START_XFER ( 1 << 16) /* Start data transfer */ -# define ATMCI_CMDR_STOP_XFER ( 2 << 16) /* Stop data transfer */ -# define ATMCI_CMDR_TRDIR_WRITE ( 0 << 18) /* Write data */ -# define ATMCI_CMDR_TRDIR_READ ( 1 << 18) /* Read data */ -# define ATMCI_CMDR_BLOCK ( 0 << 19) /* Single-block transfer */ -# define ATMCI_CMDR_MULTI_BLOCK ( 1 << 19) /* Multi-block transfer */ -# define ATMCI_CMDR_STREAM ( 2 << 19) /* MMC Stream transfer */ -# define ATMCI_CMDR_SDIO_BYTE ( 4 << 19) /* SDIO Byte transfer */ -# define ATMCI_CMDR_SDIO_BLOCK ( 5 << 19) /* SDIO Block transfer */ -# define ATMCI_CMDR_SDIO_SUSPEND ( 1 << 24) /* SDIO Suspend Command */ -# define ATMCI_CMDR_SDIO_RESUME ( 2 << 24) /* SDIO Resume Command */ -#define ATMCI_BLKR 0x0018 /* Block */ -# define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */ -# define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */ -#define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */ -# define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */ -# define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */ -#define ATMCI_RSPR 0x0020 /* Response 0 */ -#define ATMCI_RSPR1 0x0024 /* Response 1 */ -#define ATMCI_RSPR2 0x0028 /* Response 2 */ -#define ATMCI_RSPR3 0x002c /* Response 3 */ -#define ATMCI_RDR 0x0030 /* Receive Data */ -#define ATMCI_TDR 0x0034 /* Transmit Data */ -#define ATMCI_SR 0x0040 /* Status */ -#define ATMCI_IER 0x0044 /* Interrupt Enable */ -#define ATMCI_IDR 0x0048 /* Interrupt Disable */ -#define ATMCI_IMR 0x004c /* Interrupt Mask */ -# define ATMCI_CMDRDY ( 1 << 0) /* Command Ready */ -# define ATMCI_RXRDY ( 1 << 1) /* Receiver Ready */ -# define ATMCI_TXRDY ( 1 << 2) /* Transmitter Ready */ -# define ATMCI_BLKE ( 1 << 3) /* Data Block Ended */ -# define ATMCI_DTIP ( 1 << 4) /* Data Transfer In Progress */ -# define ATMCI_NOTBUSY ( 1 << 5) /* Data Not Busy */ -# define ATMCI_ENDRX ( 1 << 6) /* End of RX Buffer */ -# define ATMCI_ENDTX ( 1 << 7) /* End of TX Buffer */ -# define ATMCI_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */ -# define ATMCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */ -# define ATMCI_SDIOWAIT ( 1 << 12) /* SDIO Read Wait Operation Status */ -# define ATMCI_CSRCV ( 1 << 13) /* CE-ATA Completion Signal Received */ -# define ATMCI_RXBUFF ( 1 << 14) /* RX Buffer Full */ -# define ATMCI_TXBUFE ( 1 << 15) /* TX Buffer Empty */ -# define ATMCI_RINDE ( 1 << 16) /* Response Index Error */ -# define ATMCI_RDIRE ( 1 << 17) /* Response Direction Error */ -# define ATMCI_RCRCE ( 1 << 18) /* Response CRC Error */ -# define ATMCI_RENDE ( 1 << 19) /* Response End Bit Error */ -# define ATMCI_RTOE ( 1 << 20) /* Response Time-Out Error */ -# define ATMCI_DCRCE ( 1 << 21) /* Data CRC Error */ -# define ATMCI_DTOE ( 1 << 22) /* Data Time-Out Error */ -# define ATMCI_CSTOE ( 1 << 23) /* Completion Signal Time-out Error */ -# define ATMCI_BLKOVRE ( 1 << 24) /* DMA Block Overrun Error */ -# define ATMCI_DMADONE ( 1 << 25) /* DMA Transfer Done */ -# define ATMCI_FIFOEMPTY ( 1 << 26) /* FIFO Empty Flag */ -# define ATMCI_XFRDONE ( 1 << 27) /* Transfer Done Flag */ -# define ATMCI_ACKRCV ( 1 << 28) /* Boot Operation Acknowledge Received */ -# define ATMCI_ACKRCVE ( 1 << 29) /* Boot Operation Acknowledge Error */ -# define ATMCI_OVRE ( 1 << 30) /* RX Overrun Error */ -# define ATMCI_UNRE ( 1 << 31) /* TX Underrun Error */ -#define ATMCI_DMA 0x0050 /* DMA Configuration[2] */ -# define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */ -# define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */ -# define ATMCI_DMAEN ( 1 << 8) /* DMA Hardware Handshaking Enable */ -#define ATMCI_CFG 0x0054 /* Configuration[2] */ -# define ATMCI_CFG_FIFOMODE_1DATA ( 1 << 0) /* MCI Internal FIFO control mode */ -# define ATMCI_CFG_FERRCTRL_COR ( 1 << 4) /* Flow Error flag reset control mode */ -# define ATMCI_CFG_HSMODE ( 1 << 8) /* High Speed Mode */ -# define ATMCI_CFG_LSYNC ( 1 << 12) /* Synchronize on the last block */ -#define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */ -# define ATMCI_WP_EN ( 1 << 0) /* WP Enable */ -# define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */ -#define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */ -# define ATMCI_GET_WP_VS(x) ((x) & 0x0f) -# define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff) -#define ATMCI_VERSION 0x00FC /* Version */ -#define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ - -/* This is not including the FIFO Aperture on MCI2 */ -#define ATMCI_REGS_SIZE 0x100 - -/* Register access macros */ -#ifdef CONFIG_AVR32 -#define atmci_readl(port, reg) \ - __raw_readl((port)->regs + reg) -#define atmci_writel(port, reg, value) \ - __raw_writel((value), (port)->regs + reg) -#else -#define atmci_readl(port, reg) \ - readl_relaxed((port)->regs + reg) -#define atmci_writel(port, reg, value) \ - writel_relaxed((value), (port)->regs + reg) -#endif - -/* On AVR chips the Peripheral DMA Controller is not connected to MCI. */ -#ifdef CONFIG_AVR32 -# define ATMCI_PDC_CONNECTED 0 -#else -# define ATMCI_PDC_CONNECTED 1 -#endif - -/* - * Fix sconfig's burst size according to atmel MCI. We need to convert them as: - * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. - * - * This can be done by finding most significant bit set. - */ -static inline unsigned int atmci_convert_chksize(unsigned int maxburst) -{ - if (maxburst > 1) - return fls(maxburst) - 2; - else - return 0; -} - -#endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */ diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index bf62e429f7fc..9f3bb611000f 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -44,7 +44,155 @@ #include #include -#include "atmel-mci-regs.h" +/* + * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors + * Registers and bitfields marked with [2] are only available in MCI2 + */ + +/* MCI Register Definitions */ +#define ATMCI_CR 0x0000 /* Control */ +#define ATMCI_CR_MCIEN BIT(0) /* MCI Enable */ +#define ATMCI_CR_MCIDIS BIT(1) /* MCI Disable */ +#define ATMCI_CR_PWSEN BIT(2) /* Power Save Enable */ +#define ATMCI_CR_PWSDIS BIT(3) /* Power Save Disable */ +#define ATMCI_CR_SWRST BIT(7) /* Software Reset */ +#define ATMCI_MR 0x0004 /* Mode */ +#define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */ +#define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */ +#define ATMCI_MR_RDPROOF BIT(11) /* Read Proof */ +#define ATMCI_MR_WRPROOF BIT(12) /* Write Proof */ +#define ATMCI_MR_PDCFBYTE BIT(13) /* Force Byte Transfer */ +#define ATMCI_MR_PDCPADV BIT(14) /* Padding Value */ +#define ATMCI_MR_PDCMODE BIT(15) /* PDC-oriented Mode */ +#define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */ +#define ATMCI_DTOR 0x0008 /* Data Timeout */ +#define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ +#define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ +#define ATMCI_SDCR 0x000c /* SD Card / SDIO */ +#define ATMCI_SDCSEL_SLOT_A (0 << 0) /* Select SD slot A */ +#define ATMCI_SDCSEL_SLOT_B (1 << 0) /* Select SD slot A */ +#define ATMCI_SDCSEL_MASK (3 << 0) +#define ATMCI_SDCBUS_1BIT (0 << 6) /* 1-bit data bus */ +#define ATMCI_SDCBUS_4BIT (2 << 6) /* 4-bit data bus */ +#define ATMCI_SDCBUS_8BIT (3 << 6) /* 8-bit data bus[2] */ +#define ATMCI_SDCBUS_MASK (3 << 6) +#define ATMCI_ARGR 0x0010 /* Command Argument */ +#define ATMCI_CMDR 0x0014 /* Command */ +#define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */ +#define ATMCI_CMDR_RSPTYP_NONE (0 << 6) /* No response */ +#define ATMCI_CMDR_RSPTYP_48BIT (1 << 6) /* 48-bit response */ +#define ATMCI_CMDR_RSPTYP_136BIT (2 << 6) /* 136-bit response */ +#define ATMCI_CMDR_SPCMD_INIT (1 << 8) /* Initialization command */ +#define ATMCI_CMDR_SPCMD_SYNC (2 << 8) /* Synchronized command */ +#define ATMCI_CMDR_SPCMD_INT (4 << 8) /* Interrupt command */ +#define ATMCI_CMDR_SPCMD_INTRESP (5 << 8) /* Interrupt response */ +#define ATMCI_CMDR_OPDCMD (1 << 11) /* Open Drain */ +#define ATMCI_CMDR_MAXLAT_5CYC (0 << 12) /* Max latency 5 cycles */ +#define ATMCI_CMDR_MAXLAT_64CYC (1 << 12) /* Max latency 64 cycles */ +#define ATMCI_CMDR_START_XFER (1 << 16) /* Start data transfer */ +#define ATMCI_CMDR_STOP_XFER (2 << 16) /* Stop data transfer */ +#define ATMCI_CMDR_TRDIR_WRITE (0 << 18) /* Write data */ +#define ATMCI_CMDR_TRDIR_READ (1 << 18) /* Read data */ +#define ATMCI_CMDR_BLOCK (0 << 19) /* Single-block transfer */ +#define ATMCI_CMDR_MULTI_BLOCK (1 << 19) /* Multi-block transfer */ +#define ATMCI_CMDR_STREAM (2 << 19) /* MMC Stream transfer */ +#define ATMCI_CMDR_SDIO_BYTE (4 << 19) /* SDIO Byte transfer */ +#define ATMCI_CMDR_SDIO_BLOCK (5 << 19) /* SDIO Block transfer */ +#define ATMCI_CMDR_SDIO_SUSPEND (1 << 24) /* SDIO Suspend Command */ +#define ATMCI_CMDR_SDIO_RESUME (2 << 24) /* SDIO Resume Command */ +#define ATMCI_BLKR 0x0018 /* Block */ +#define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */ +#define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */ +#define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */ +#define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */ +#define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */ +#define ATMCI_RSPR 0x0020 /* Response 0 */ +#define ATMCI_RSPR1 0x0024 /* Response 1 */ +#define ATMCI_RSPR2 0x0028 /* Response 2 */ +#define ATMCI_RSPR3 0x002c /* Response 3 */ +#define ATMCI_RDR 0x0030 /* Receive Data */ +#define ATMCI_TDR 0x0034 /* Transmit Data */ +#define ATMCI_SR 0x0040 /* Status */ +#define ATMCI_IER 0x0044 /* Interrupt Enable */ +#define ATMCI_IDR 0x0048 /* Interrupt Disable */ +#define ATMCI_IMR 0x004c /* Interrupt Mask */ +#define ATMCI_CMDRDY BIT(0) /* Command Ready */ +#define ATMCI_RXRDY BIT(1) /* Receiver Ready */ +#define ATMCI_TXRDY BIT(2) /* Transmitter Ready */ +#define ATMCI_BLKE BIT(3) /* Data Block Ended */ +#define ATMCI_DTIP BIT(4) /* Data Transfer In Progress */ +#define ATMCI_NOTBUSY BIT(5) /* Data Not Busy */ +#define ATMCI_ENDRX BIT(6) /* End of RX Buffer */ +#define ATMCI_ENDTX BIT(7) /* End of TX Buffer */ +#define ATMCI_SDIOIRQA BIT(8) /* SDIO IRQ in slot A */ +#define ATMCI_SDIOIRQB BIT(9) /* SDIO IRQ in slot B */ +#define ATMCI_SDIOWAIT BIT(12) /* SDIO Read Wait Operation Status */ +#define ATMCI_CSRCV BIT(13) /* CE-ATA Completion Signal Received */ +#define ATMCI_RXBUFF BIT(14) /* RX Buffer Full */ +#define ATMCI_TXBUFE BIT(15) /* TX Buffer Empty */ +#define ATMCI_RINDE BIT(16) /* Response Index Error */ +#define ATMCI_RDIRE BIT(17) /* Response Direction Error */ +#define ATMCI_RCRCE BIT(18) /* Response CRC Error */ +#define ATMCI_RENDE BIT(19) /* Response End Bit Error */ +#define ATMCI_RTOE BIT(20) /* Response Time-Out Error */ +#define ATMCI_DCRCE BIT(21) /* Data CRC Error */ +#define ATMCI_DTOE BIT(22) /* Data Time-Out Error */ +#define ATMCI_CSTOE BIT(23) /* Completion Signal Time-out Error */ +#define ATMCI_BLKOVRE BIT(24) /* DMA Block Overrun Error */ +#define ATMCI_DMADONE BIT(25) /* DMA Transfer Done */ +#define ATMCI_FIFOEMPTY BIT(26) /* FIFO Empty Flag */ +#define ATMCI_XFRDONE BIT(27) /* Transfer Done Flag */ +#define ATMCI_ACKRCV BIT(28) /* Boot Operation Acknowledge Received */ +#define ATMCI_ACKRCVE BIT(29) /* Boot Operation Acknowledge Error */ +#define ATMCI_OVRE BIT(30) /* RX Overrun Error */ +#define ATMCI_UNRE BIT(31) /* TX Underrun Error */ +#define ATMCI_DMA 0x0050 /* DMA Configuration[2] */ +#define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */ +#define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */ +#define ATMCI_DMAEN BIT(8) /* DMA Hardware Handshaking Enable */ +#define ATMCI_CFG 0x0054 /* Configuration[2] */ +#define ATMCI_CFG_FIFOMODE_1DATA BIT(0) /* MCI Internal FIFO control mode */ +#define ATMCI_CFG_FERRCTRL_COR BIT(4) /* Flow Error flag reset control mode */ +#define ATMCI_CFG_HSMODE BIT(8) /* High Speed Mode */ +#define ATMCI_CFG_LSYNC BIT(12) /* Synchronize on the last block */ +#define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */ +#define ATMCI_WP_EN BIT(0) /* WP Enable */ +#define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */ +#define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */ +#define ATMCI_GET_WP_VS(x) ((x) & 0x0f) +#define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff) +#define ATMCI_VERSION 0x00FC /* Version */ +#define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ + +/* This is not including the FIFO Aperture on MCI2 */ +#define ATMCI_REGS_SIZE 0x100 + +/* Register access macros */ +#define atmci_readl(port, reg) \ + __raw_readl((port)->regs + reg) +#define atmci_writel(port, reg, value) \ + __raw_writel((value), (port)->regs + reg) + +/* On AVR chips the Peripheral DMA Controller is not connected to MCI. */ +#ifdef CONFIG_AVR32 +# define ATMCI_PDC_CONNECTED 0 +#else +# define ATMCI_PDC_CONNECTED 1 +#endif + +/* + * Fix sconfig's burst size according to atmel MCI. We need to convert them as: + * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. + * + * This can be done by finding most significant bit set. + */ +static inline unsigned int atmci_convert_chksize(unsigned int maxburst) +{ + if (maxburst > 1) + return fls(maxburst) - 2; + else + return 0; +} #define AUTOSUSPEND_DELAY 50 -- cgit v1.2.3 From a1904f3cb6a881c6d3b6fa9427e0058e9ac23af6 Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Mon, 23 Nov 2015 16:27:31 +0100 Subject: MAINTAINERS: remove atmel-mci-regs.h file Remove atmel-mci-regs.h file since it has been merged in atmel-mci.c. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 233f83464814..9a4c4e54d681 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1896,7 +1896,6 @@ ATMEL AT91 / AT32 MCI DRIVER M: Ludovic Desroches S: Maintained F: drivers/mmc/host/atmel-mci.c -F: drivers/mmc/host/atmel-mci-regs.h ATMEL AT91 / AT32 SERIAL DRIVER M: Nicolas Ferre -- cgit v1.2.3 From 447dc0d20a69ebd59f335a096528634a40ea55c0 Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Mon, 23 Nov 2015 16:27:32 +0100 Subject: mmc: atmel-mci: atmci_convert_chksize depends on controller version The atmci_convert_chksize() function is no more valid for controller version 0x600 due to the introduction of '2 data' chunk size. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 9f3bb611000f..a36ebdae2388 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -180,20 +180,6 @@ # define ATMCI_PDC_CONNECTED 1 #endif -/* - * Fix sconfig's burst size according to atmel MCI. We need to convert them as: - * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. - * - * This can be done by finding most significant bit set. - */ -static inline unsigned int atmci_convert_chksize(unsigned int maxburst) -{ - if (maxburst > 1) - return fls(maxburst) - 2; - else - return 0; -} - #define AUTOSUSPEND_DELAY 50 #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE) @@ -732,6 +718,29 @@ static inline unsigned int atmci_get_version(struct atmel_mci *host) return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; } +/* + * Fix sconfig's burst size according to atmel MCI. We need to convert them as: + * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. + * With version 0x600, we need to convert them as: 1 -> 0, 2 -> 1, 4 -> 2, + * 8 -> 3, 16 -> 4. + * + * This can be done by finding most significant bit set. + */ +static inline unsigned int atmci_convert_chksize(struct atmel_mci *host, + unsigned int maxburst) +{ + unsigned int version = atmci_get_version(host); + unsigned int offset = 2; + + if (version >= 0x600) + offset = 1; + + if (maxburst > 1) + return fls(maxburst) - offset; + else + return 0; +} + static void atmci_timeout_timer(unsigned long data) { struct atmel_mci *host; @@ -1182,11 +1191,13 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) if (data->flags & MMC_DATA_READ) { direction = DMA_FROM_DEVICE; host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM; - maxburst = atmci_convert_chksize(host->dma_conf.src_maxburst); + maxburst = atmci_convert_chksize(host, + host->dma_conf.src_maxburst); } else { direction = DMA_TO_DEVICE; host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV; - maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst); + maxburst = atmci_convert_chksize(host, + host->dma_conf.dst_maxburst); } if (host->caps.has_dma_conf_reg) -- cgit v1.2.3 From 1ef5e49e46b919052474d9b54a15debc79ff0133 Mon Sep 17 00:00:00 2001 From: yangbo lu Date: Wed, 25 Nov 2015 10:05:37 +0800 Subject: mmc: sdhci-of-esdhc: add/remove some quirks according to vendor version A previous patch had removed esdhc_of_platform_init() by mistake. static void esdhc_of_platform_init(struct sdhci_host *host) { u32 vvn; vvn = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS); vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT; if (vvn == VENDOR_V_22) host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; if (vvn > VENDOR_V_22) host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; } This patch is used to fix it by add/remove some quirks according to verdor version in probe. Signed-off-by: Yangbo Lu Fixes: f4932cfd22f1 ("mmc: sdhci-of-esdhc: support both BE and LE host controller") Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-esdhc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 90e94a028a49..83b1226471c1 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -584,6 +584,8 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) { struct sdhci_host *host; struct device_node *np; + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_esdhc *esdhc; int ret; np = pdev->dev.of_node; @@ -600,6 +602,14 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) sdhci_get_of_property(pdev); + pltfm_host = sdhci_priv(host); + esdhc = pltfm_host->priv; + if (esdhc->vendor_ver == VENDOR_V_22) + host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; + + if (esdhc->vendor_ver > VENDOR_V_22) + host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; + if (of_device_is_compatible(np, "fsl,p5040-esdhc") || of_device_is_compatible(np, "fsl,p5020-esdhc") || of_device_is_compatible(np, "fsl,p4080-esdhc") || -- cgit v1.2.3 From 6d91439ae2d31c45706802e0a0716e25f9f97563 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 25 Nov 2015 14:57:31 +0100 Subject: mmc: mvsdio: delete platform data header This platform data struct is only used inside the MVSDIO driver, nowhere else in the entire kernel. Move the struct into the driver and delete the external header. Cc: Nicolas Pitre Cc: Andrew Lunn Cc: Sebastian Hesselbarth Signed-off-by: Linus Walleij Acked-by: Nicolas Pitre Acked-by: Andrew Lunn Signed-off-by: Ulf Hansson --- drivers/mmc/host/mvsdio.c | 7 ++++++- include/linux/platform_data/mmc-mvsdio.h | 18 ------------------ 2 files changed, 6 insertions(+), 19 deletions(-) delete mode 100644 include/linux/platform_data/mmc-mvsdio.h diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index a448498e3af2..18c70380ea93 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -28,7 +28,6 @@ #include #include -#include #include "mvsdio.h" @@ -37,6 +36,12 @@ static int maxfreq; static int nodma; +struct mvsdio_platform_data { + unsigned int clock; + int gpio_card_detect; + int gpio_write_protect; +}; + struct mvsd_host { void __iomem *base; struct mmc_request *mrq; diff --git a/include/linux/platform_data/mmc-mvsdio.h b/include/linux/platform_data/mmc-mvsdio.h deleted file mode 100644 index d02704cd3695..000000000000 --- a/include/linux/platform_data/mmc-mvsdio.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __MMC_MVSDIO_H -#define __MMC_MVSDIO_H - -#include - -struct mvsdio_platform_data { - unsigned int clock; - int gpio_card_detect; - int gpio_write_protect; -}; - -#endif -- cgit v1.2.3 From 17da678368fac22375f0854c811034e311be23b5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 25 Nov 2015 14:57:57 +0100 Subject: mmc: mvsdio: delete platform data code path There are no in-kernel users of the MVSDIO platform data method (instantiating from a board file) so just delete this code and make this a DT-only driver. We depend on OF and check that we have an OF node in probe(). Cc: Nicolas Pitre Cc: Andrew Lunn Cc: Sebastian Hesselbarth Signed-off-by: Linus Walleij Acked-by: Nicolas Pitre Acked-by: Andrew Lunn Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 1 + drivers/mmc/host/mvsdio.c | 63 +++++++++++------------------------------------ 2 files changed, 15 insertions(+), 49 deletions(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 1dee533634c9..1526b8a10b09 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -455,6 +455,7 @@ config MMC_TIFM_SD config MMC_MVSDIO tristate "Marvell MMC/SD/SDIO host driver" depends on PLAT_ORION + depends on OF ---help--- This selects the Marvell SDIO host driver. SDIO may currently be found on the Kirkwood 88F6281 and 88F6192 diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 18c70380ea93..42296e55b9de 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -20,8 +20,6 @@ #include #include #include -#include -#include #include #include #include @@ -36,12 +34,6 @@ static int maxfreq; static int nodma; -struct mvsdio_platform_data { - unsigned int clock; - int gpio_card_detect; - int gpio_write_protect; -}; - struct mvsd_host { void __iomem *base; struct mmc_request *mrq; @@ -709,6 +701,10 @@ static int mvsd_probe(struct platform_device *pdev) struct resource *r; int ret, irq; + if (!np) { + dev_err(&pdev->dev, "no DT node\n"); + return -ENODEV; + } r = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!r || irq < 0) @@ -732,8 +728,12 @@ static int mvsd_probe(struct platform_device *pdev) * fixed rate clock). */ host->clk = devm_clk_get(&pdev->dev, NULL); - if (!IS_ERR(host->clk)) - clk_prepare_enable(host->clk); + if (IS_ERR(host->clk)) { + dev_err(&pdev->dev, "no clock associated\n"); + ret = -EINVAL; + goto out; + } + clk_prepare_enable(host->clk); mmc->ops = &mvsd_ops; @@ -749,45 +749,10 @@ static int mvsd_probe(struct platform_device *pdev) mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; - if (np) { - if (IS_ERR(host->clk)) { - dev_err(&pdev->dev, "DT platforms must have a clock associated\n"); - ret = -EINVAL; - goto out; - } - - host->base_clock = clk_get_rate(host->clk) / 2; - ret = mmc_of_parse(mmc); - if (ret < 0) - goto out; - } else { - const struct mvsdio_platform_data *mvsd_data; - - mvsd_data = pdev->dev.platform_data; - if (!mvsd_data) { - ret = -ENXIO; - goto out; - } - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ | - MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; - host->base_clock = mvsd_data->clock / 2; - /* GPIO 0 regarded as invalid for backward compatibility */ - if (mvsd_data->gpio_card_detect && - gpio_is_valid(mvsd_data->gpio_card_detect)) { - ret = mmc_gpio_request_cd(mmc, - mvsd_data->gpio_card_detect, - 0); - if (ret) - goto out; - } else { - mmc->caps |= MMC_CAP_NEEDS_POLL; - } - - if (mvsd_data->gpio_write_protect && - gpio_is_valid(mvsd_data->gpio_write_protect)) - mmc_gpio_request_ro(mmc, mvsd_data->gpio_write_protect); - } - + host->base_clock = clk_get_rate(host->clk) / 2; + ret = mmc_of_parse(mmc); + if (ret < 0) + goto out; if (maxfreq) mmc->f_max = maxfreq; -- cgit v1.2.3 From 100a606d54a087cfec54efbedba72f36e5a9cdf0 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Wed, 25 Nov 2015 15:39:51 +0100 Subject: mmc: core: Introduce MMC_CAP2_NO_SDIO cap This patch introduce a new MMC_CAP2_NO_SDIO cap used to tell the mmc core to not send SDIO specific commands. Signed-off-by: Carlo Caione Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 11 ++++++++--- include/linux/mmc/host.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 07b2f086213f..910aa254f23a 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2476,15 +2476,20 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) * sdio_reset sends CMD52 to reset card. Since we do not know * if the card is being re-initialized, just send it. CMD52 * should be ignored by SD/eMMC cards. + * Skip it if we already know that we do not support SDIO commands */ - sdio_reset(host); + if (!(host->caps2 & MMC_CAP2_NO_SDIO)) + sdio_reset(host); + mmc_go_idle(host); mmc_send_if_cond(host, host->ocr_avail); /* Order's important: probe SDIO, then SD, then MMC */ - if (!mmc_attach_sdio(host)) - return 0; + if (!(host->caps2 & MMC_CAP2_NO_SDIO)) + if (!mmc_attach_sdio(host)) + return 0; + if (!mmc_attach_sd(host)) return 0; if (!mmc_attach_mmc(host)) diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index f39888cf5017..8dd4d290ab0d 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -290,6 +290,7 @@ struct mmc_host { #define MMC_CAP2_HSX00_1_2V (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V) #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17) #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18) /* No physical write protect pin, assume that card is always read-write */ +#define MMC_CAP2_NO_SDIO (1 << 19) /* Do not send SDIO commands during initialization */ mmc_pm_flag_t pm_caps; /* supported pm features */ -- cgit v1.2.3 From adb24d42a516bca8b9741ed21206509daaab5b13 Mon Sep 17 00:00:00 2001 From: Wenkai Du Date: Thu, 26 Nov 2015 14:00:44 +0200 Subject: mmc: mmc: Fix incorrect use of driver strength switching HS200 and HS400 Commit cc4f414c885c ("mmc: mmc: Add driver strength selection") added driver strength selection for eMMC HS200 and HS400 modes. That patch also set the driver stength when transitioning through High Speed mode to HS200/HS400, but driver strength is not defined for High Speed mode. While the JEDEC specification is not clear on this point it has been observed to cause problems for some eMMC, and removing the driver strength setting in this case makes it consistent with the normal use of High Speed mode. Signed-off-by: Wenkai Du Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org # v4.2+ Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 66957addf9e4..549c56e8cf6b 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1076,8 +1076,7 @@ static int mmc_select_hs400(struct mmc_card *card) mmc_set_clock(host, max_dtr); /* Switch card to HS mode */ - val = EXT_CSD_TIMING_HS | - card->drive_strength << EXT_CSD_DRV_STR_SHIFT; + val = EXT_CSD_TIMING_HS; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, @@ -1160,8 +1159,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) mmc_set_clock(host, max_dtr); /* Switch HS400 to HS DDR */ - val = EXT_CSD_TIMING_HS | - card->drive_strength << EXT_CSD_DRV_STR_SHIFT; + val = EXT_CSD_TIMING_HS; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, true, send_status, true); -- cgit v1.2.3 From 1ca896856281d3f1ad4f6f7d4e32e2943452de23 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 26 Nov 2015 14:00:45 +0200 Subject: mmc: sdhci-pci: Do not default to 33 Ohm driver strength for Intel SPT In some cases, the stronger 33 Ohm driver strength must not be used so it is not a suitable default. Change it to the standard default 50 Ohm value. The patch applies to v4.2+ except the file name changed. It is drivers/mmc/host/sdhci-pci.c prior to v.4.4. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org # v4.2+ Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index cf7ad458b4f4..08f4a9fe8550 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -277,7 +277,7 @@ static int spt_select_drive_strength(struct sdhci_host *host, if (sdhci_pci_spt_drive_strength > 0) drive_strength = sdhci_pci_spt_drive_strength & 0xf; else - drive_strength = 1; /* 33-ohm */ + drive_strength = 0; /* Default 50-ohm */ if ((mmc_driver_type_mask(drive_strength) & card_drv) == 0) drive_strength = 0; /* Default 50-ohm */ -- cgit v1.2.3 From 9d5de93f6d543b356e39e225988ef443a7bce34c Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 26 Nov 2015 14:00:46 +0200 Subject: mmc: sdhci: Do not BUG on invalid vdd The driver may not be able to set the power correctly but that is not a reason to BUG(). Signed-off-by: Adrian Hunter Reviewed-by: Venu Byravarasu Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2b17cc1246ca..4cfb26152a58 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1299,7 +1299,9 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode, pwr = SDHCI_POWER_330; break; default: - BUG(); + WARN(1, "%s: Invalid vdd %#x\n", + mmc_hostname(host->mmc), vdd); + break; } } -- cgit v1.2.3 From d9bfbb95ed598a09cf336adb0f190ee0ff802f0d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 26 Nov 2015 14:00:47 +0200 Subject: mmc: sdio: Fix invalid vdd in voltage switch power cycle The 'ocr' parameter passed to mmc_set_signal_voltage() defines the power-on voltage used when power cycling after a failure to set the voltage. However, in the case of mmc_sdio_init_card(), the value passed has the R4_18V_PRESENT flag set which is not valid for power-on and results in an invalid vdd. Fix by passing the card's ocr value which does not have the flag. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org # v3.13+ Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 16d838e6d623..d61ba1a0495e 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -630,7 +630,7 @@ try_again: */ if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) { err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, - ocr); + ocr_card); if (err == -EAGAIN) { sdio_reset(host); mmc_go_idle(host); -- cgit v1.2.3 From 347ea32dc118326c4f2636928239a29d192cc9b8 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 26 Nov 2015 14:00:48 +0200 Subject: mmc: sdhci: Fix DMA descriptor with zero data length SDHCI has built-in DMA called ADMA2. ADMA2 uses a descriptor table to define DMA scatter-gather. Each desciptor can specify a data length up to 65536 bytes, however the length field is only 16-bits so zero means 65536. Consequently, putting zero when the size is zero must not be allowed. This patch fixes one case where zero data length could be set inadvertently. The problem happens because unaligned data gets split and the code did not consider that the remaining aligned portion might be zero length. That case really only happens for SDIO because SD and eMMC cards transfer blocks that are invariably sector- aligned. For SDIO, access to function registers is done by data transfer (CMD53) when the register is bigger than 1 byte. Generally registers are 4 bytes but 2-byte registers are possible. So DMA of 4 bytes or less can happen. When 32-bit DMA is used, the data alignment must be 4, so 4-byte transfers won't casue a problem, but a 2-byte transfer could. However with the introduction of 64-bit DMA, the data alignment for 64-bit DMA was made 8 bytes, so all 4-byte transfers not on 8-byte boundaries get "split" into a 4-byte chunk and a 0-byte chunk, thereby hitting the bug. In fact, a closer look at the SDHCI specs indicates that only the descriptor table requires 8-byte alignment for 64-bit DMA. That will be dealt with in a separate patch, but the potential for a 2-byte access remains, so this fix is needed anyway. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org # v3.19+ Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 4cfb26152a58..8df0ba0f63f4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -540,9 +540,12 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, BUG_ON(len > 65536); - /* tran, valid */ - sdhci_adma_write_desc(host, desc, addr, len, ADMA2_TRAN_VALID); - desc += host->desc_sz; + if (len) { + /* tran, valid */ + sdhci_adma_write_desc(host, desc, addr, len, + ADMA2_TRAN_VALID); + desc += host->desc_sz; + } /* * If this triggers then we have a calculation bug -- cgit v1.2.3 From 04a5ae6fdd018af29675eb8b6c2550c87f471570 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 26 Nov 2015 14:00:49 +0200 Subject: mmc: sdhci: 64-bit DMA actually has 4-byte alignment The version 3.00 SDHCI spec. was a bit unclear about the required data alignment for 64-bit DMA, whereas the version 4.10 spec. uses different language and indicates that only 4-byte alignment is required rather than the 8-byte alignment currently implemented. That make no difference to SD and EMMC which invariably transfer data in sector-aligned blocks. However with SDIO, it results in using more DMA descriptors than necessary. Theoretically that slows DMA slightly although DMA is not the limiting factor for throughput, so there is no discernable impact on performance. Nevertheless, the driver should follw the spec unless there is good reason not to, so this patch corrects the alignment criterion. There is a more complicated criterion for the DMA descriptor table itself. However the table is allocated by dma_alloc_coherent() which allocates pages (i.e. aligned to a page boundary). For simplicity just check it is 8-byte aligned, but add a comment that some Intel controllers actually require 8-byte alignment even when using 32-bit DMA. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 31 ++++++++++++------------------- drivers/mmc/host/sdhci.h | 21 ++++++++++++--------- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8df0ba0f63f4..1a8f42eb8c50 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -492,7 +492,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, host->align_buffer, host->align_buffer_sz, direction); if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) goto fail; - BUG_ON(host->align_addr & host->align_mask); + BUG_ON(host->align_addr & SDHCI_ADMA2_MASK); host->sg_count = sdhci_pre_dma_transfer(host, data); if (host->sg_count < 0) @@ -514,8 +514,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, * the (up to three) bytes that screw up the * alignment. */ - offset = (host->align_sz - (addr & host->align_mask)) & - host->align_mask; + offset = (SDHCI_ADMA2_ALIGN - (addr & SDHCI_ADMA2_MASK)) & + SDHCI_ADMA2_MASK; if (offset) { if (data->flags & MMC_DATA_WRITE) { buffer = sdhci_kmap_atomic(sg, &flags); @@ -529,8 +529,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, BUG_ON(offset > 65536); - align += host->align_sz; - align_addr += host->align_sz; + align += SDHCI_ADMA2_ALIGN; + align_addr += SDHCI_ADMA2_ALIGN; desc += host->desc_sz; @@ -611,7 +611,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host, /* Do a quick scan of the SG list for any unaligned mappings */ has_unaligned = false; for_each_sg(data->sg, sg, host->sg_count, i) - if (sg_dma_address(sg) & host->align_mask) { + if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) { has_unaligned = true; break; } @@ -623,15 +623,15 @@ static void sdhci_adma_table_post(struct sdhci_host *host, align = host->align_buffer; for_each_sg(data->sg, sg, host->sg_count, i) { - if (sg_dma_address(sg) & host->align_mask) { - size = host->align_sz - - (sg_dma_address(sg) & host->align_mask); + if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) { + size = SDHCI_ADMA2_ALIGN - + (sg_dma_address(sg) & SDHCI_ADMA2_MASK); buffer = sdhci_kmap_atomic(sg, &flags); memcpy(buffer, align, size); sdhci_kunmap_atomic(buffer, &flags); - align += host->align_sz; + align += SDHCI_ADMA2_ALIGN; } } } @@ -2961,24 +2961,17 @@ int sdhci_add_host(struct sdhci_host *host) if (host->flags & SDHCI_USE_64_BIT_DMA) { host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) * SDHCI_ADMA2_64_DESC_SZ; - host->align_buffer_sz = SDHCI_MAX_SEGS * - SDHCI_ADMA2_64_ALIGN; host->desc_sz = SDHCI_ADMA2_64_DESC_SZ; - host->align_sz = SDHCI_ADMA2_64_ALIGN; - host->align_mask = SDHCI_ADMA2_64_ALIGN - 1; } else { host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) * SDHCI_ADMA2_32_DESC_SZ; - host->align_buffer_sz = SDHCI_MAX_SEGS * - SDHCI_ADMA2_32_ALIGN; host->desc_sz = SDHCI_ADMA2_32_DESC_SZ; - host->align_sz = SDHCI_ADMA2_32_ALIGN; - host->align_mask = SDHCI_ADMA2_32_ALIGN - 1; } host->adma_table = dma_alloc_coherent(mmc_dev(mmc), host->adma_table_sz, &host->adma_addr, GFP_KERNEL); + host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN; host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL); if (!host->adma_table || !host->align_buffer) { if (host->adma_table) @@ -2992,7 +2985,7 @@ int sdhci_add_host(struct sdhci_host *host) host->flags &= ~SDHCI_USE_ADMA; host->adma_table = NULL; host->align_buffer = NULL; - } else if (host->adma_addr & host->align_mask) { + } else if (host->adma_addr & (SDHCI_ADMA2_DESC_ALIGN - 1)) { pr_warn("%s: unable to allocate aligned ADMA descriptor\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 9d4aa31b683a..7654ae5d2b4e 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -272,22 +272,27 @@ /* ADMA2 32-bit DMA descriptor size */ #define SDHCI_ADMA2_32_DESC_SZ 8 -/* ADMA2 32-bit DMA alignment */ -#define SDHCI_ADMA2_32_ALIGN 4 - /* ADMA2 32-bit descriptor */ struct sdhci_adma2_32_desc { __le16 cmd; __le16 len; __le32 addr; -} __packed __aligned(SDHCI_ADMA2_32_ALIGN); +} __packed __aligned(4); + +/* ADMA2 data alignment */ +#define SDHCI_ADMA2_ALIGN 4 +#define SDHCI_ADMA2_MASK (SDHCI_ADMA2_ALIGN - 1) + +/* + * ADMA2 descriptor alignment. Some controllers (e.g. Intel) require 8 byte + * alignment for the descriptor table even in 32-bit DMA mode. Memory + * allocation is at least 8 byte aligned anyway, so just stipulate 8 always. + */ +#define SDHCI_ADMA2_DESC_ALIGN 8 /* ADMA2 64-bit DMA descriptor size */ #define SDHCI_ADMA2_64_DESC_SZ 12 -/* ADMA2 64-bit DMA alignment */ -#define SDHCI_ADMA2_64_ALIGN 8 - /* * ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte * aligned. @@ -482,8 +487,6 @@ struct sdhci_host { dma_addr_t align_addr; /* Mapped bounce buffer */ unsigned int desc_sz; /* ADMA descriptor size */ - unsigned int align_sz; /* ADMA alignment */ - unsigned int align_mask; /* ADMA alignment mask */ struct tasklet_struct finish_tasklet; /* Tasklet structures */ -- cgit v1.2.3 From 5c671c410c8704800f4f1673b6f572137e7e6ddd Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 26 Nov 2015 14:00:50 +0200 Subject: mmc: sdhci: Fix sdhci_runtime_pm_bus_on/off() sdhci has a legacy facility to prevent runtime suspend if the bus power is on. This is needed in cases where the power to the card is dependent on the bus power. It is controlled by a pair of functions: sdhci_runtime_pm_bus_on() and sdhci_runtime_pm_bus_off(). These functions use a boolean variable 'bus_on' to ensure changes are always paired. There is an additional check for 'runtime_suspended' which is the problem. In fact, its use is ill-conceived as the only requirement for the logic is that 'on' and 'off' are paired, which is actually broken by the check, for example if the bus power is turned on during runtime resume. So remove the check. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org # v3.11+ Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1a8f42eb8c50..2753b722d1c9 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2755,7 +2755,7 @@ static int sdhci_runtime_pm_put(struct sdhci_host *host) static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) { - if (host->runtime_suspended || host->bus_on) + if (host->bus_on) return; host->bus_on = true; pm_runtime_get_noresume(host->mmc->parent); @@ -2763,7 +2763,7 @@ static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) static void sdhci_runtime_pm_bus_off(struct sdhci_host *host) { - if (host->runtime_suspended || !host->bus_on) + if (!host->bus_on) return; host->bus_on = false; pm_runtime_put_noidle(host->mmc->parent); -- cgit v1.2.3 From ec076cd226c3d93565ede082a240e23b5090e36c Mon Sep 17 00:00:00 2001 From: "Fu, Zhonghui" Date: Fri, 4 Dec 2015 21:05:56 +0800 Subject: mmc: enable MMC/SD/SDIO device to suspend/resume asynchronously Now, PM core supports asynchronous suspend/resume mode for devices during system suspend/resume, and the power state transition of one device may be completed in separate kernel thread. PM core ensures all power state transition dependency between devices. This patch enables MMC/SD/SDIO card and SDIO function devices to suspend/resume asynchronously. This will take advantage of multicore and improve system suspend/resume speed. After applying this patch and enabling all SDIO function's child devices to suspend/resume asynchronously on ASUS T100TA, the system suspend-to-idle time is reduced from 1645ms to 1108ms, and the system resume time is reduced from 940ms to 918ms. Signed-off-by: Zhonghui Fu Signed-off-by: Ulf Hansson --- drivers/mmc/core/bus.c | 2 ++ drivers/mmc/core/sdio_bus.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 972ff844cf5a..4bc48f10452f 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -349,6 +349,8 @@ int mmc_add_card(struct mmc_card *card) card->dev.of_node = mmc_of_find_child_device(card->host, 0); + device_enable_async_suspend(&card->dev); + ret = device_add(&card->dev); if (ret) return ret; diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 7e327a6dd53d..86f5b3223aae 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -322,6 +322,7 @@ int sdio_add_func(struct sdio_func *func) sdio_set_of_node(func); sdio_acpi_set_handle(func); + device_enable_async_suspend(&func->dev); ret = device_add(&func->dev); if (ret == 0) sdio_func_set_present(func); -- cgit v1.2.3 From 2066fd285efdd201316e0236aec177354b39ee71 Mon Sep 17 00:00:00 2001 From: Chaotian Jing Date: Tue, 1 Dec 2015 20:12:34 +0800 Subject: mmc: mediatek: change some dev_err to dev_dbg there are too many error logs shown when use CMD21/CMD19 to do tune, and it will appear at each resume time, print out so many logs to the uart console cost too mush time. so change it to dev_dbg. Signed-off-by: Chaotian Jing Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index a5beb3618240..82a97ac4e956 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -972,7 +972,7 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events, if ((events & MSDC_INT_XFER_COMPL) && (!stop || !stop->error)) { data->bytes_xfered = data->blocks * data->blksz; } else { - dev_err(host->dev, "interrupt events: %x\n", events); + dev_dbg(host->dev, "interrupt events: %x\n", events); msdc_reset_hw(host); host->error |= REQ_DAT_ERR; data->bytes_xfered = 0; @@ -982,10 +982,10 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events, else if (events & MSDC_INT_DATCRCERR) data->error = -EILSEQ; - dev_err(host->dev, "%s: cmd=%d; blocks=%d", + dev_dbg(host->dev, "%s: cmd=%d; blocks=%d", __func__, mrq->cmd->opcode, data->blocks); - dev_err(host->dev, "data_error=%d xfer_size=%d\n", - (int)data->error, data->bytes_xfered); + dev_dbg(host->dev, "data_error=%d xfer_size=%d\n", + (int)data->error, data->bytes_xfered); } msdc_data_xfer_next(host, mrq, data); -- cgit v1.2.3 From 60b71f607796f10ec8814312724759574398512b Mon Sep 17 00:00:00 2001 From: saurabh Date: Wed, 25 Nov 2015 23:56:24 +0530 Subject: mmc: of_mmc_spi: Add IRQF_ONESHOT to interrupt flags If no primary handler is specified for threaded_irq then a default one is assigned which always returns IRQ_WAKE_THREAD. This handler requires the IRQF_ONESHOT, because the source of interrupt is not disabled Signed-off-by: Saurabh Sengar Signed-off-by: Ulf Hansson --- drivers/mmc/host/of_mmc_spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/of_mmc_spi.c b/drivers/mmc/host/of_mmc_spi.c index 6e218fb1a669..660170cd04d9 100644 --- a/drivers/mmc/host/of_mmc_spi.c +++ b/drivers/mmc/host/of_mmc_spi.c @@ -55,8 +55,8 @@ static int of_mmc_spi_init(struct device *dev, { struct of_mmc_spi *oms = to_of_mmc_spi(dev); - return request_threaded_irq(oms->detect_irq, NULL, irqhandler, 0, - dev_name(dev), mmc); + return request_threaded_irq(oms->detect_irq, NULL, irqhandler, + IRQF_ONESHOT, dev_name(dev), mmc); } static void of_mmc_spi_exit(struct device *dev, void *mmc) -- cgit v1.2.3 From 05caee939f8d58d81e962071da85761e1e3a4c73 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 27 Nov 2015 12:59:11 +0100 Subject: mmc: usdhi6rol0: handle NULL data in timeout Commit bb08a7d489bd ("mmc: usdhi6rol0: fix NULL pointer deref in debug print") fixed one NULL pointer dereference but unfortunately introduced another. "data" may be NULL if this is a command timeout for a command without any data, so we should only use it if we're actually waiting for data. Fixes: bb08a7d489bd ("mmc: usdhi6rol0: fix NULL pointer deref in debug print") Cc: stable@vger.kernel.org # v4.3 Signed-off-by: Rabin Vincent Signed-off-by: Ulf Hansson --- drivers/mmc/host/usdhi6rol0.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index 4498e92116b8..b47122d3e8d8 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1634,7 +1634,7 @@ static void usdhi6_timeout_work(struct work_struct *work) struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work); struct mmc_request *mrq = host->mrq; struct mmc_data *data = mrq ? mrq->data : NULL; - struct scatterlist *sg = host->sg ?: data->sg; + struct scatterlist *sg; dev_warn(mmc_dev(host->mmc), "%s timeout wait %u CMD%d: IRQ 0x%08x:0x%08x, last IRQ 0x%08x\n", @@ -1666,6 +1666,7 @@ static void usdhi6_timeout_work(struct work_struct *work) case USDHI6_WAIT_FOR_MWRITE: case USDHI6_WAIT_FOR_READ: case USDHI6_WAIT_FOR_WRITE: + sg = host->sg ?: data->sg; dev_dbg(mmc_dev(host->mmc), "%c: page #%u @ +0x%zx %ux%u in SG%u. Current SG %u bytes @ %u\n", data->flags & MMC_DATA_READ ? 'R' : 'W', host->page_idx, -- cgit v1.2.3 From 3bbb0deea6d5c6d5ed38ae927a5bf9b0cd7c8639 Mon Sep 17 00:00:00 2001 From: Chaotian Jing Date: Mon, 30 Nov 2015 09:27:30 +0800 Subject: mmc: core: fix __mmc_switch timeout caused by preempt there is a time window between __mmc_send_status() and time_afer(), on some eMMC chip, the timeout_ms is only 10ms, if this thread was scheduled out during this period, then, even card has already changes to transfer state by the result of CMD13, this part of code also treat it to timeout error. So, need calculate timeout first, then call __mmc_send_status(), if already timeout and card still in programing state, then treat it to the real timeout error. Signed-off-by: Chaotian Jing Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_ops.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 1f444269ebbe..2c90635c89af 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -489,6 +489,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned long timeout; u32 status = 0; bool use_r1b_resp = use_busy_signal; + bool expired = false; mmc_retune_hold(host); @@ -545,6 +546,12 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, timeout = jiffies + msecs_to_jiffies(timeout_ms); do { if (send_status) { + /* + * Due to the possibility of being preempted after + * sending the status command, check the expiration + * time first. + */ + expired = time_after(jiffies, timeout); err = __mmc_send_status(card, &status, ignore_crc); if (err) goto out; @@ -565,7 +572,7 @@ 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)) { + if (expired && R1_CURRENT_STATE(status) == R1_STATE_PRG) { pr_err("%s: Card stuck in programming state! %s\n", mmc_hostname(host), __func__); err = -ETIMEDOUT; -- cgit v1.2.3 From 260b31643691e8a58683a4ccc3bdf7abfd86f54a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 12 Nov 2015 15:14:23 +0100 Subject: mmc: dw_mmc: use resource_size_t to store physical address The dw_mmc driver stores the physical address of the MMIO registers in a pointer, which requires the use of type casts, and is actually broken if anyone ever has this device on a 32-bit SoC in registers above 4GB. Gcc warns about this possibility when the driver is built with ARM LPAE enabled: mmc/host/dw_mmc.c: In function 'dw_mci_edmac_start_dma': mmc/host/dw_mmc.c:702:17: warning: cast from pointer to integer of different size cfg.dst_addr = (dma_addr_t)(host->phy_regs + fifo_offset); ^ mmc/host/dw_mmc-pltfm.c: In function 'dw_mci_pltfm_register': mmc/host/dw_mmc-pltfm.c:63:19: warning: cast to pointer from integer of different size host->phy_regs = (void *)(regs->start); This changes the code to use resource_size_t, which gets rid of the warning, the bug and the useless casts. Signed-off-by: Arnd Bergmann Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-pltfm.c | 2 +- drivers/mmc/host/dw_mmc.c | 2 +- include/linux/mmc/dw_mmc.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index 7e1d13b68b06..81bdeeb05a4d 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -60,7 +60,7 @@ int dw_mci_pltfm_register(struct platform_device *pdev, regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); /* Get registers' physical base address */ - host->phy_regs = (void *)(regs->start); + host->phy_regs = regs->start; host->regs = devm_ioremap_resource(&pdev->dev, regs); if (IS_ERR(host->regs)) return PTR_ERR(host->regs); diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 7a6cedbe48a8..fb204ee6ff89 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -699,7 +699,7 @@ static int dw_mci_edmac_start_dma(struct dw_mci *host, int ret = 0; /* Set external dma config: burst size, burst width */ - cfg.dst_addr = (dma_addr_t)(host->phy_regs + fifo_offset); + cfg.dst_addr = host->phy_regs + fifo_offset; cfg.src_addr = cfg.dst_addr; cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index f67b2ec18e6d..7776afb0ffa5 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -172,7 +172,7 @@ struct dw_mci { /* For edmac */ struct dw_mci_dma_slave *dms; /* Registers's physical base address */ - void *phy_regs; + resource_size_t phy_regs; u32 cmd_status; u32 data_status; -- cgit v1.2.3 From 520bd7a8b4152aacfbd34eb7f7a447354b631039 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 1 Dec 2015 10:35:29 +0100 Subject: mmc: core: Optimize boot time by detecting cards simultaneously The mmc workqueue is an ordered workqueue, allowing only one work to execute per given time. As this workqueue is used for card detection, the conseqeunce is that cards will be detected one by one waiting for each other. Moreover, most of the time spent during card initialization is waiting for the card's internal firmware to be ready. From a CPU perspective this typically means waiting for a completion variable to be kicked via an IRQ-handler or waiting for a sleep timer to finish. This behaviour of detecting/initializing cards is sub-optimal, especially for SOCs having several controllers/cards. Let's convert to use the system_freezable_wq for the mmc detect works. This enables several works to be executed simultaneously and thus also cards to be detected like so. Tests on UX500, which holds two eMMC cards and an SD-card (actually also an SDIO card, currently not detected), shows a significant improved behaviour due to this change. Before this change, both the eMMC cards waited for the SD card to be initialized as its detect work entered the workqueue first. In some cases, depending on the characteristic of the SD-card, they got delayed 1-1.5 s. Additionally for the second eMMC, it needed to wait for the first eMMC to be initialized which added another 120-190 ms. Converting to the system_freezable_wq, removed these delays and made both the eMMC cards available far earlier in the boot sequence. Selecting the system_freezable_wq, in favour of for example the system_wq, is because we need card detection mechanism to be disabled once userspace are frozen during system PM. Currently the mmc core deal with this via PM notifiers, but following patches may utilize the behaviour of the system_freezable_wq, to simplify the use of the PM notifiers. Signed-off-by: Ulf Hansson Tested-by: Alan Cooper Tested-by: Shawn Lin --- drivers/mmc/core/core.c | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 910aa254f23a..f95d41ffc766 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -55,7 +55,6 @@ */ #define MMC_BKOPS_MAX_TIMEOUT (4 * 60 * 1000) /* max time to wait in ms */ -static struct workqueue_struct *workqueue; static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; /* @@ -66,21 +65,16 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; bool use_spi_crc = 1; module_param(use_spi_crc, bool, 0); -/* - * Internal function. Schedule delayed work in the MMC work queue. - */ static int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay) { - return queue_delayed_work(workqueue, work, delay); -} - -/* - * Internal function. Flush all scheduled work from the MMC work queue. - */ -static void mmc_flush_scheduled_work(void) -{ - flush_workqueue(workqueue); + /* + * We use the system_freezable_wq, because of two reasons. + * First, it allows several works (not the same work item) to be + * executed simultaneously. Second, the queue becomes frozen when + * userspace becomes frozen during system PM. + */ + return queue_delayed_work(system_freezable_wq, work, delay); } #ifdef CONFIG_FAIL_MMC_REQUEST @@ -2669,7 +2663,6 @@ void mmc_stop_host(struct mmc_host *host) host->rescan_disable = 1; cancel_delayed_work_sync(&host->detect); - mmc_flush_scheduled_work(); /* clear pm flags now and let card drivers set them as needed */ host->pm_flags = 0; @@ -2852,13 +2845,9 @@ static int __init mmc_init(void) { int ret; - workqueue = alloc_ordered_workqueue("kmmcd", 0); - if (!workqueue) - return -ENOMEM; - ret = mmc_register_bus(); if (ret) - goto destroy_workqueue; + return ret; ret = mmc_register_host_class(); if (ret) @@ -2874,9 +2863,6 @@ unregister_host_class: mmc_unregister_host_class(); unregister_bus: mmc_unregister_bus(); -destroy_workqueue: - destroy_workqueue(workqueue); - return ret; } @@ -2885,7 +2871,6 @@ static void __exit mmc_exit(void) sdio_unregister_bus(); mmc_unregister_host_class(); mmc_unregister_bus(); - destroy_workqueue(workqueue); } subsys_initcall(mmc_init); -- cgit v1.2.3 From 382c55f88ffeb218c446bf0c46d0fc25d2795fe2 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 22 Oct 2015 10:00:41 -0700 Subject: mmc: block: Allow more than 8 partitions per card It is quite common for Android devices to utilize more then 8 partitions on internal eMMC storage. The vanilla kernel can support this via CONFIG_MMC_BLOCK_MINORS, however that solution caps the system to 256 minors total, which limits the number of mmc cards the system can support. This patch, which has been carried for quite awhile in the AOSP common tree, provides an alternative solution that doesn't seem to limit the total card count. So I wanted to submit it for consideration upstream. This patch sets the GENHD_FL_EXT_DEVT flag, which will allocate minor number in major 259 for partitions past disk->minors. It also removes the use of disk_devt to determine devidx from md->disk. md->disk->first_minor is always initialized from devidx and can always be used to recover it. Cc: Ulf Hansson Cc: Adrian Hunter Cc: Ben Hutchings Cc: Chuanxiao Dong Cc: Shawn Lin Cc: Austin S Hemmelgarn Cc: Arnd Bergmann Cc: Android Kernel Team Cc: linux-mmc@vger.kernel.org Signed-off-by: Colin Cross [jstultz: Added context to commit message] Signed-off-by: John Stultz Signed-off-by: Ulf Hansson --- drivers/mmc/card/block.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index ce38960cca12..5914263090fc 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -171,11 +171,7 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) static inline int mmc_get_devidx(struct gendisk *disk) { - int devmaj = MAJOR(disk_devt(disk)); - int devidx = MINOR(disk_devt(disk)) / perdev_minors; - - if (!devmaj) - devidx = disk->first_minor / perdev_minors; + int devidx = disk->first_minor / perdev_minors; return devidx; } @@ -2244,6 +2240,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, md->disk->queue = md->queue.queue; md->disk->driverfs_dev = parent; set_disk_ro(md->disk, md->read_only || default_ro); + md->disk->flags = GENHD_FL_EXT_DEVT; if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT)) md->disk->flags |= GENHD_FL_NO_PART_SCAN; -- cgit v1.2.3 From 520322d92eab66b6fee562557fdd201b01cd6240 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Dec 2015 15:51:27 +0200 Subject: mmc: It is not an error for the card to be removed while suspended A card can be removed while it is runtime suspended. Do not print an error message. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 2 +- drivers/mmc/core/sd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 549c56e8cf6b..bf49e44571f2 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1935,7 +1935,7 @@ static int mmc_runtime_resume(struct mmc_host *host) int err; err = _mmc_resume(host); - if (err) + if (err && err != -ENOMEDIUM) pr_err("%s: error %d doing runtime resume\n", mmc_hostname(host), err); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 8f3b46a56b3d..f2b164b214ae 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1158,7 +1158,7 @@ static int mmc_sd_runtime_resume(struct mmc_host *host) int err; err = _mmc_sd_resume(host); - if (err) + if (err && err != -ENOMEDIUM) pr_err("%s: error %d doing runtime resume\n", mmc_hostname(host), err); -- cgit v1.2.3 From 918f4cbd4340ddd1eb389cd8efa3b07ac74ec4c0 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 11 Dec 2015 21:36:29 +0800 Subject: mmc: sdhci: restore behavior when setting VDD via external regulator After commit 52221610dd84 ("mmc: sdhci: Improve external VDD regulator support"), for the VDD is supplied via external regulators, we ignore the code to convert a VDD voltage request into one of the standard SDHCI voltage levels, then program it in the SDHCI_POWER_CONTROL. This brings two issues: 1. SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON quirk isn't handled properly any more. 2. What's more, once SDHCI_POWER_ON bit is set, some controllers such as the sdhci-pxav3 used in marvell berlin SoCs require the voltage levels programming in the SDHCI_POWER_CONTROL register, even the VDD is supplied by external regulator. So the host in marvell berlin SoCs still works fine after the commit. However, commit 3cbc6123a93d ("mmc: sdhci: Set SDHCI_POWER_ON with external vmmc") sets the SDHCI_POWER_ON bit, this would make the host in marvell berlin SoCs won't work any more with external vmmc. This patch restores the behavior when setting VDD through external regulator by moving the call of mmc_regulator_set_ocr() to the end of sdhci_set_power() function. After this patch, the sdcard on Marvell Berlin SoC boards work again. Signed-off-by: Jisheng Zhang Fixes: 52221610dd84 ("mmc: sdhci: Improve external VDD ...") Reviewed-by: Ludovic Desroches Tested-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2753b722d1c9..d622435d1bcc 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1275,19 +1275,6 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode, struct mmc_host *mmc = host->mmc; u8 pwr = 0; - if (!IS_ERR(mmc->supply.vmmc)) { - spin_unlock_irq(&host->lock); - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); - spin_lock_irq(&host->lock); - - if (mode != MMC_POWER_OFF) - sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL); - else - sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - - return; - } - if (mode != MMC_POWER_OFF) { switch (1 << vdd) { case MMC_VDD_165_195: @@ -1348,6 +1335,12 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode, if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER) mdelay(10); } + + if (!IS_ERR(mmc->supply.vmmc)) { + spin_unlock_irq(&host->lock); + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); + spin_lock_irq(&host->lock); + } } /*****************************************************************************\ -- cgit v1.2.3 From a8e326a911d3ca1b7480aca936956a4e89c4add5 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Tue, 22 Dec 2015 19:41:00 +0100 Subject: mmc: tegra: implement module external clock change Allow the the driver to change the clock supplied from the CAR directly, minimizing the need to divide the clock inside the SDMMC module itself. This allows for higher clock speeds than the default 48MHz supplied to the module and is a prerequisite to support DDR signaling modes, where the Tegra host needs to be run with a fixed internal divider of 2 for data to be sampled correctly. (Tegra K1 TRM v03p chapter 29.7.1.1) Also enable the broken preset value quirk as the preset values need to be adapted to the changed clocking. While Tegra114+ allows this through vendor registers, there is no such way for Tegra30. Takes the easy way out and keep things consistent between the different SoC generations by flagging the preset registers as unusable. Signed-off-by: Lucas Stach Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 61 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 368f1b74a525..f11db8337cce 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -49,6 +49,7 @@ struct sdhci_tegra_soc_data { struct sdhci_tegra { const struct sdhci_tegra_soc_data *soc_data; struct gpio_desc *power_gpio; + bool ddr_signaling; }; static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) @@ -143,6 +144,8 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) if (soc_data->nvquirks & NVQUIRK_DISABLE_SDR104) misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR104; sdhci_writew(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); + + tegra_host->ddr_signaling = false; } static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width) @@ -164,15 +167,54 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width) sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } +static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = pltfm_host->priv; + unsigned long host_clk; + + if (!clock) + return; + + host_clk = tegra_host->ddr_signaling ? clock * 2 : clock; + clk_set_rate(pltfm_host->clk, host_clk); + host->max_clk = clk_get_rate(pltfm_host->clk); + + return sdhci_set_clock(host, clock); +} + +static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, + unsigned timing) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = pltfm_host->priv; + + if (timing == MMC_TIMING_UHS_DDR50) + tegra_host->ddr_signaling = true; + + return sdhci_set_uhs_signaling(host, timing); +} + +static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + /* + * DDR modes require the host to run at double the card frequency, so + * the maximum rate we can support is half of the module input clock. + */ + return clk_round_rate(pltfm_host->clk, UINT_MAX) / 2; +} + static const struct sdhci_ops tegra_sdhci_ops = { .get_ro = tegra_sdhci_get_ro, .read_w = tegra_sdhci_readw, .write_l = tegra_sdhci_writel, - .set_clock = sdhci_set_clock, + .set_clock = tegra_sdhci_set_clock, .set_bus_width = tegra_sdhci_set_bus_width, .reset = tegra_sdhci_reset, - .set_uhs_signaling = sdhci_set_uhs_signaling, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, + .get_max_clock = tegra_sdhci_get_max_clock, }; static const struct sdhci_pltfm_data sdhci_tegra20_pdata = { @@ -197,6 +239,7 @@ static const struct sdhci_pltfm_data sdhci_tegra30_pdata = { SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .ops = &tegra_sdhci_ops, }; @@ -212,11 +255,11 @@ static const struct sdhci_ops tegra114_sdhci_ops = { .read_w = tegra_sdhci_readw, .write_w = tegra_sdhci_writew, .write_l = tegra_sdhci_writel, - .set_clock = sdhci_set_clock, + .set_clock = tegra_sdhci_set_clock, .set_bus_width = tegra_sdhci_set_bus_width, .reset = tegra_sdhci_reset, - .set_uhs_signaling = sdhci_set_uhs_signaling, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, + .get_max_clock = tegra_sdhci_get_max_clock, }; static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { @@ -226,6 +269,7 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .ops = &tegra114_sdhci_ops, }; @@ -241,7 +285,9 @@ static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_NO_HISPD_BIT | - SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, + SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | + SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .ops = &tegra114_sdhci_ops, }; @@ -288,6 +334,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) rc = -ENOMEM; goto err_alloc_tegra_host; } + tegra_host->ddr_signaling = false; tegra_host->soc_data = soc_data; pltfm_host->priv = tegra_host; -- cgit v1.2.3 From 74cd42bcad7486664d13b1b42bc81a399d7ed763 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Tue, 22 Dec 2015 19:41:01 +0100 Subject: mmc: tegra: disable SPI_MODE_CLKEN The Tegra30 and up TRM states that this bit should always be programmed to 0 by driver software. Signed-off-by: Lucas Stach Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index f11db8337cce..20ce81b57d32 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -28,6 +28,10 @@ #include "sdhci-pltfm.h" /* Tegra SDHOST controller vendor register definitions */ +#define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100 +#define SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE BIT(3) +#define SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE BIT(2) + #define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120 #define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8 #define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10 @@ -125,7 +129,7 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = pltfm_host->priv; const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; - u32 misc_ctrl; + u32 misc_ctrl, clk_ctrl; sdhci_reset(host, mask); @@ -145,6 +149,10 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR104; sdhci_writew(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); + clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); + clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE; + sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); + tegra_host->ddr_signaling = false; } -- cgit v1.2.3 From c3c2384c3ac073cdc2d8e3bbc89b55cdcf507b8f Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Tue, 22 Dec 2015 19:41:02 +0100 Subject: mmc: tegra: implement UHS tuning This implements the UHS tuning sequence in a similar way to the one contained in the TRM. It deviates in the way how to check if the tap value is passing, by using the common Linux MMC function, which does not only check for data CRC errors, but also if the received block pattern is correct. Signed-off-by: Lucas Stach Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 20ce81b57d32..020154943732 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,9 @@ /* Tegra SDHOST controller vendor register definitions */ #define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100 +#define SDHCI_CLOCK_CTRL_TAP_MASK 0x00ff0000 +#define SDHCI_CLOCK_CTRL_TAP_SHIFT 16 +#define SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE BIT(5) #define SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE BIT(3) #define SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE BIT(2) @@ -151,6 +155,8 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE; + if (!(soc_data->nvquirks & NVQUIRK_DISABLE_SDR50)) + clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); tegra_host->ddr_signaling = false; @@ -214,6 +220,50 @@ static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host) return clk_round_rate(pltfm_host->clk, UINT_MAX) / 2; } +static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) +{ + u32 reg; + + reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); + reg &= ~SDHCI_CLOCK_CTRL_TAP_MASK; + reg |= tap << SDHCI_CLOCK_CTRL_TAP_SHIFT; + sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); +} + +static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + unsigned int min, max; + + /* + * Start search for minimum tap value at 10, as smaller values are + * may wrongly be reported as working but fail at higher speeds, + * according to the TRM. + */ + min = 10; + while (min < 255) { + tegra_sdhci_set_tap(host, min); + if (!mmc_send_tuning(host->mmc, opcode, NULL)) + break; + min++; + } + + /* Find the maximum tap value that still passes. */ + max = min + 1; + while (max < 255) { + tegra_sdhci_set_tap(host, max); + if (mmc_send_tuning(host->mmc, opcode, NULL)) { + max--; + break; + } + max++; + } + + /* The TRM states the ideal tap value is at 75% in the passing range. */ + tegra_sdhci_set_tap(host, min + ((max - min) * 3 / 4)); + + return mmc_send_tuning(host->mmc, opcode, NULL); +} + static const struct sdhci_ops tegra_sdhci_ops = { .get_ro = tegra_sdhci_get_ro, .read_w = tegra_sdhci_readw, @@ -221,6 +271,7 @@ static const struct sdhci_ops tegra_sdhci_ops = { .set_clock = tegra_sdhci_set_clock, .set_bus_width = tegra_sdhci_set_bus_width, .reset = tegra_sdhci_reset, + .platform_execute_tuning = tegra_sdhci_execute_tuning, .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, .get_max_clock = tegra_sdhci_get_max_clock, }; @@ -266,6 +317,7 @@ static const struct sdhci_ops tegra114_sdhci_ops = { .set_clock = tegra_sdhci_set_clock, .set_bus_width = tegra_sdhci_set_bus_width, .reset = tegra_sdhci_reset, + .platform_execute_tuning = tegra_sdhci_execute_tuning, .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, .get_max_clock = tegra_sdhci_get_max_clock, }; @@ -350,6 +402,9 @@ static int sdhci_tegra_probe(struct platform_device *pdev) if (rc) goto err_parse_dt; + if (!(tegra_host->soc_data->nvquirks & NVQUIRK_DISABLE_DDR50)) + host->mmc->caps |= MMC_CAP_1_8V_DDR; + tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", GPIOD_OUT_HIGH); if (IS_ERR(tegra_host->power_gpio)) { -- cgit v1.2.3 From 7ad2ed1dfcbed6f50923fc0afc24aac475bdc0b5 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Tue, 22 Dec 2015 19:41:03 +0100 Subject: mmc: tegra: enable UHS-I modes Keep the quirk bits, as Tegra30 and Tegra114 host have different levels of support for UHS-I modes and so need different spare bits to be set, but change the logic to be positive. Tegra210 needs a different tuning sequence than Tegra30+. Disable UHS modes until support for this is properly added. Signed-off-by: Lucas Stach Acked-by: Thierry Reding Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 020154943732..ff2eefe9f237 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -45,9 +45,9 @@ #define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) #define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) #define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) -#define NVQUIRK_DISABLE_SDR50 BIT(3) -#define NVQUIRK_DISABLE_SDR104 BIT(4) -#define NVQUIRK_DISABLE_DDR50 BIT(5) +#define NVQUIRK_ENABLE_SDR50 BIT(3) +#define NVQUIRK_ENABLE_SDR104 BIT(4) +#define NVQUIRK_ENABLE_DDR50 BIT(5) struct sdhci_tegra_soc_data { const struct sdhci_pltfm_data *pdata; @@ -144,18 +144,18 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) /* Erratum: Enable SDHCI spec v3.00 support */ if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; - /* Don't advertise UHS modes which aren't supported yet */ - if (soc_data->nvquirks & NVQUIRK_DISABLE_SDR50) - misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR50; - if (soc_data->nvquirks & NVQUIRK_DISABLE_DDR50) - misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_DDR50; - if (soc_data->nvquirks & NVQUIRK_DISABLE_SDR104) - misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR104; + /* Advertise UHS modes as supported by host */ + if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) + misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50; + if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) + misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; + if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) + misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; sdhci_writew(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE; - if (!(soc_data->nvquirks & NVQUIRK_DISABLE_SDR50)) + if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50) clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); @@ -305,8 +305,8 @@ static const struct sdhci_pltfm_data sdhci_tegra30_pdata = { static const struct sdhci_tegra_soc_data soc_data_tegra30 = { .pdata = &sdhci_tegra30_pdata, .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 | - NVQUIRK_DISABLE_SDR50 | - NVQUIRK_DISABLE_SDR104, + NVQUIRK_ENABLE_SDR50 | + NVQUIRK_ENABLE_SDR104, }; static const struct sdhci_ops tegra114_sdhci_ops = { @@ -335,9 +335,9 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { static const struct sdhci_tegra_soc_data soc_data_tegra114 = { .pdata = &sdhci_tegra114_pdata, - .nvquirks = NVQUIRK_DISABLE_SDR50 | - NVQUIRK_DISABLE_DDR50 | - NVQUIRK_DISABLE_SDR104, + .nvquirks = NVQUIRK_ENABLE_SDR50 | + NVQUIRK_ENABLE_DDR50 | + NVQUIRK_ENABLE_SDR104, }; static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { @@ -353,9 +353,6 @@ static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { static const struct sdhci_tegra_soc_data soc_data_tegra210 = { .pdata = &sdhci_tegra210_pdata, - .nvquirks = NVQUIRK_DISABLE_SDR50 | - NVQUIRK_DISABLE_DDR50 | - NVQUIRK_DISABLE_SDR104, }; static const struct of_device_id sdhci_tegra_dt_match[] = { @@ -402,7 +399,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) if (rc) goto err_parse_dt; - if (!(tegra_host->soc_data->nvquirks & NVQUIRK_DISABLE_DDR50)) + if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) host->mmc->caps |= MMC_CAP_1_8V_DDR; tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", -- cgit v1.2.3 From 1b84def8bf86ae9a39940c12a20ce9a2dfd66d56 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Tue, 22 Dec 2015 19:41:04 +0100 Subject: mmc: tegra: use correct accessor for misc ctrl register The misc control register is 32bit wide, the used readw/writew accessors only mainipulate the low 16bit of this register. It currently doesn't matter as all the bit changed are located in the lower half, but together with the u32 variable used to hold the contents of the register it is seriously confusing. Switch to 32bit accessors to avoid any future breakage. Signed-off-by: Lucas Stach Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index ff2eefe9f237..83c4bf7bc16c 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -140,7 +140,7 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) if (!(mask & SDHCI_RESET_ALL)) return; - misc_ctrl = sdhci_readw(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); + misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); /* Erratum: Enable SDHCI spec v3.00 support */ if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; @@ -151,7 +151,7 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; - sdhci_writew(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); + sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE; -- cgit v1.2.3 From 12dd7fe2967a7e60e689e7e9a016b8288c8ea756 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Sun, 27 Dec 2015 21:15:43 +0800 Subject: mmc: cb710: use to_platform_device() Use to_platform_device() instead of open-coding it. Signed-off-by: Geliang Tang Signed-off-by: Ulf Hansson --- drivers/mmc/host/cb710-mmc.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mmc/host/cb710-mmc.h b/drivers/mmc/host/cb710-mmc.h index 8984ec878fc9..8ecd9e56636a 100644 --- a/drivers/mmc/host/cb710-mmc.h +++ b/drivers/mmc/host/cb710-mmc.h @@ -29,8 +29,7 @@ static inline struct mmc_host *cb710_slot_to_mmc(struct cb710_slot *slot) static inline struct cb710_slot *cb710_mmc_to_slot(struct mmc_host *mmc) { - struct platform_device *pdev = container_of(mmc_dev(mmc), - struct platform_device, dev); + struct platform_device *pdev = to_platform_device(mmc_dev(mmc)); return cb710_pdev_to_slot(pdev); } -- cgit v1.2.3 From 923a231c871120c08a74a1fda397fed184334924 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Sun, 27 Dec 2015 18:46:00 +0800 Subject: mmc: sdhci-pci: use to_pci_dev() Use to_pci_dev() instead of open-coding it. Signed-off-by: Geliang Tang Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 08f4a9fe8550..cc851b065d0a 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -1464,7 +1464,7 @@ static int sdhci_pci_resume(struct device *dev) static int sdhci_pci_runtime_suspend(struct device *dev) { - struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + struct pci_dev *pdev = to_pci_dev(dev); struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; int i, ret; @@ -1500,7 +1500,7 @@ err_pci_runtime_suspend: static int sdhci_pci_runtime_resume(struct device *dev) { - struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + struct pci_dev *pdev = to_pci_dev(dev); struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; int i, ret; -- cgit v1.2.3 From 01a999e48995a35faaa513f811c335bce72917d6 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 24 Dec 2015 18:41:03 +0900 Subject: mmc: dw_mmc: remove the unused quirks Removed the unused quirks. These quirks don't used anywhere. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 19 ------------------- include/linux/mmc/dw_mmc.h | 10 ++-------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index fb204ee6ff89..712835177e8b 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1634,12 +1634,6 @@ static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd) else cmd->error = 0; - if (cmd->error) { - /* newer ip versions need a delay between retries */ - if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY) - mdelay(20); - } - return cmd->error; } @@ -2355,16 +2349,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) pending = mci_readl(host, MINTSTS); /* read-only mask reg */ - /* - * DTO fix - version 2.10a and below, and only if internal DMA - * is configured. - */ - if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) { - if (!pending && - ((mci_readl(host, STATUS) >> 17) & 0x1fff)) - pending |= SDMMC_INT_DATA_OVER; - } - if (pending) { /* Check volt switch first, since it can look like an error */ if ((host->state == STATE_SENDING_CMD11) && @@ -3165,9 +3149,6 @@ int dw_mci_probe(struct dw_mci *host) /* Now that slots are all setup, we can enable card detect */ dw_mci_enable_cd(host); - if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) - dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n"); - return 0; err_dmaunmap: diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index 7776afb0ffa5..89df7abedd67 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -235,16 +235,10 @@ struct dw_mci_dma_ops { }; /* IP Quirks/flags. */ -/* DTO fix for command transmission with IDMAC configured */ -#define DW_MCI_QUIRK_IDMAC_DTO BIT(0) -/* delay needed between retries on some 2.11a implementations */ -#define DW_MCI_QUIRK_RETRY_DELAY BIT(1) -/* High Speed Capable - Supports HS cards (up to 50MHz) */ -#define DW_MCI_QUIRK_HIGHSPEED BIT(2) /* Unreliable card detection */ -#define DW_MCI_QUIRK_BROKEN_CARD_DETECTION BIT(3) +#define DW_MCI_QUIRK_BROKEN_CARD_DETECTION BIT(0) /* Timer for broken data transfer over scheme */ -#define DW_MCI_QUIRK_BROKEN_DTO BIT(4) +#define DW_MCI_QUIRK_BROKEN_DTO BIT(1) struct dma_pdata; -- cgit v1.2.3