From 38929d4f0d811df399c99398ce0599f546369bd4 Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Wed, 25 Aug 2021 18:33:45 +0900 Subject: mmc: sdhci: Change the code to check auto_cmd23 It is replaced with a function that is already declared. //[1/5] mmc: sdhci: Add helpers for the auto-CMD23 flag //20200412090349.1607-2-adrian.hunter@intel.com Signed-off-by: ChanWoo Lee Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20210825093345.14706-1-cw9316.lee@samsung.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8eefa7d5fe85..7ae398f8d4d3 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3232,7 +3232,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p) -ETIMEDOUT : -EILSEQ; - if (mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { + if (sdhci_auto_cmd23(host, mrq)) { mrq->sbc->error = err; __sdhci_finish_mrq(host, mrq); return; -- cgit From 43e5fee317f4b0a48992b8b07935b1a3ac20ce84 Mon Sep 17 00:00:00 2001 From: Derong Liu Date: Fri, 27 Aug 2021 15:15:37 +0800 Subject: mmc: mtk-sd: Add wait dma stop done flow We found this issue on a 5G platform, during CMDQ error handling, if DMA status is active when it call msdc_reset_hw(), it means mmc host hw reset and DMA transfer will be parallel, mmc host may access sram region unexpectedly. According to the programming guide of mtk-sd host, it needs to wait for dma stop done after set dma stop. This change should be applied to all SoCs. Signed-off-by: Derong Liu Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20210827071537.1034-1-derong.liu@mediatek.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 4dfc246c5f95..b99330bad6a5 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -2330,6 +2331,7 @@ static void msdc_cqe_enable(struct mmc_host *mmc) static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery) { struct msdc_host *host = mmc_priv(mmc); + unsigned int val = 0; /* disable cmdq irq */ sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INT_CMDQ); @@ -2339,6 +2341,9 @@ static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery) if (recovery) { sdr_set_field(host->base + MSDC_DMA_CTRL, MSDC_DMA_CTRL_STOP, 1); + if (WARN_ON(readl_poll_timeout(host->base + MSDC_DMA_CFG, val, + !(val & MSDC_DMA_CFG_STS), 1, 3000))) + return; msdc_reset_hw(host); } } -- cgit From 961e40f714f6ef958e008b7ee4e66df1ea0fac89 Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Fri, 27 Aug 2021 18:31:19 +0900 Subject: mmc: mtk-sd: Remove unused parameters(mrq) The mmc_request structure(*mrq) is not used. //msdc_cmd_find_resp I remove the unnecessary code related to the mmc_request structure. Signed-off-by: ChanWoo Lee Link: https://lore.kernel.org/r/20210827093119.32481-1-cw9316.lee@samsung.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index b99330bad6a5..8d9bed92677c 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -962,7 +962,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) } static inline u32 msdc_cmd_find_resp(struct msdc_host *host, - struct mmc_request *mrq, struct mmc_command *cmd) + struct mmc_command *cmd) { u32 resp; @@ -998,7 +998,7 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host, * stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode */ u32 opcode = cmd->opcode; - u32 resp = msdc_cmd_find_resp(host, mrq, cmd); + u32 resp = msdc_cmd_find_resp(host, cmd); u32 rawcmd = (opcode & 0x3f) | ((resp & 0x7) << 7); host->cmd_rsp = resp; -- cgit From d74179b86925165562aec81e0ba269ebc453dad2 Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Mon, 30 Aug 2021 11:17:49 +0900 Subject: mmc: mtk-sd: Remove unused parameters Remove unused parameters 1. msdc_start_data() - struct mmc_request *mrq 2. msdc_track_cmd_data() - struct mmc_data *data Signed-off-by: ChanWoo Lee Link: https://lore.kernel.org/r/20210830021749.5947-1-cw9316.lee@samsung.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 8d9bed92677c..f611db05d1d9 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1044,8 +1044,8 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host, return rawcmd; } -static void msdc_start_data(struct msdc_host *host, struct mmc_request *mrq, - struct mmc_command *cmd, struct mmc_data *data) +static void msdc_start_data(struct msdc_host *host, struct mmc_command *cmd, + struct mmc_data *data) { bool read; @@ -1113,8 +1113,7 @@ static void msdc_recheck_sdio_irq(struct msdc_host *host) } } -static void msdc_track_cmd_data(struct msdc_host *host, - struct mmc_command *cmd, struct mmc_data *data) +static void msdc_track_cmd_data(struct msdc_host *host, struct mmc_command *cmd) { if (host->error) dev_dbg(host->dev, "%s: cmd=%d arg=%08X; host->error=0x%08X\n", @@ -1135,7 +1134,7 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) host->mrq = NULL; spin_unlock_irqrestore(&host->lock, flags); - msdc_track_cmd_data(host, mrq->cmd, mrq->data); + msdc_track_cmd_data(host, mrq->cmd); if (mrq->data) msdc_unprepare_data(host, mrq->data); if (host->error) @@ -1296,7 +1295,7 @@ static void msdc_cmd_next(struct msdc_host *host, else if (!cmd->data) msdc_request_done(host, mrq); else - msdc_start_data(host, mrq, cmd, cmd->data); + msdc_start_data(host, cmd, cmd->data); } static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq) -- cgit From 9c1aaec47527816877befb7f18ea1cf25e55b8c8 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Mon, 30 Aug 2021 14:25:34 -0700 Subject: mmc: block: Add error handling support for add_disk() We never checked for errors on add_disk() as this function returned void. Now that this is fixed, use the shiny new error handling. The caller only cleanups the disk if we pass on an allocated md but on error we return return ERR_PTR(ret), and so we must do all the unwinding ourselves. Signed-off-by: Luis Chamberlain Link: https://lore.kernel.org/r/20210830212538.148729-5-mcgrof@kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 431af5e8be2f..61590cf7a7b1 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -2442,9 +2442,14 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, /* used in ->open, must be set before add_disk: */ if (area_type == MMC_BLK_DATA_AREA_MAIN) dev_set_drvdata(&card->dev, md); - device_add_disk(md->parent, md->disk, mmc_disk_attr_groups); + ret = device_add_disk(md->parent, md->disk, mmc_disk_attr_groups); + if (ret) + goto err_cleanup_queue; return md; + err_cleanup_queue: + blk_cleanup_queue(md->disk->queue); + blk_mq_free_tag_set(&md->queue.tag_set); err_kfree: kfree(md); out: -- cgit From c88cb98e61395bae3350a4b721dfc2f9bcb74f5a Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 10:59:39 +0800 Subject: mmc: omap_hsmmc: Make use of the helper macro SET_RUNTIME_PM_OPS() Use the helper macro SET_RUNTIME_PM_OPS() instead of the verbose operators ".runtime_suspend/.runtime_resume", because the SET_RUNTIME_PM_OPS() is a nice helper macro that could be brought in to make code a little more concise. Signed-off-by: Cai Huoqing Link: https://lore.kernel.org/r/20210907025940.1535-1-caihuoqing@baidu.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 2f8038d69f67..7a29ad542e4a 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -702,11 +702,6 @@ static void omap_hsmmc_context_save(struct omap_hsmmc_host *host) #else -static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) -{ - return 0; -} - static void omap_hsmmc_context_save(struct omap_hsmmc_host *host) { } @@ -2086,6 +2081,7 @@ static int omap_hsmmc_resume(struct device *dev) } #endif +#ifdef CONFIG_PM static int omap_hsmmc_runtime_suspend(struct device *dev) { struct omap_hsmmc_host *host; @@ -2153,11 +2149,11 @@ static int omap_hsmmc_runtime_resume(struct device *dev) spin_unlock_irqrestore(&host->irq_lock, flags); return 0; } +#endif static const struct dev_pm_ops omap_hsmmc_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(omap_hsmmc_suspend, omap_hsmmc_resume) - .runtime_suspend = omap_hsmmc_runtime_suspend, - .runtime_resume = omap_hsmmc_runtime_resume, + SET_RUNTIME_PM_OPS(omap_hsmmc_runtime_suspend, omap_hsmmc_runtime_resume, NULL) }; static struct platform_driver omap_hsmmc_driver = { -- cgit From 39013f09681341e8264dff633e70d43da84d579a Mon Sep 17 00:00:00 2001 From: Rashmi A Date: Sun, 29 Aug 2021 23:54:40 +0530 Subject: mmc: sdhci-of-arasan: Add intel Thunder Bay SOC support to the arasan eMMC driver Intel Thunder Bay SoC eMMC controller is based on Arasan eMMC 5.1 host controller IP Signed-off-by: Rashmi A Reviewed-by: Adrian Hunter Link: https://lore.kernel.org/r/20210829182443.30802-2-rashmi.a@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 737e2bfdedc2..6a2e5a468424 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -191,6 +191,13 @@ static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = { .hiword_update = false, }; +static const struct sdhci_arasan_soc_ctl_map thunderbay_soc_ctl_map = { + .baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 }, + .clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 }, + .support64b = { .reg = 0x4, .width = 1, .shift = 24 }, + .hiword_update = false, +}; + static const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = { .baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 }, .clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 }, @@ -456,6 +463,15 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = { SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, }; +static const struct sdhci_pltfm_data sdhci_arasan_thunderbay_pdata = { + .ops = &sdhci_arasan_cqe_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | + SDHCI_QUIRK2_STOP_WITH_TC | + SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400, +}; + #ifdef CONFIG_PM_SLEEP /** * sdhci_arasan_suspend - Suspend method for the driver @@ -1132,6 +1148,12 @@ static struct sdhci_arasan_of_data sdhci_arasan_generic_data = { .clk_ops = &arasan_clk_ops, }; +static const struct sdhci_arasan_of_data sdhci_arasan_thunderbay_data = { + .soc_ctl_map = &thunderbay_soc_ctl_map, + .pdata = &sdhci_arasan_thunderbay_pdata, + .clk_ops = &arasan_clk_ops, +}; + static const struct sdhci_pltfm_data sdhci_keembay_emmc_pdata = { .ops = &sdhci_arasan_cqe_ops, .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | @@ -1265,6 +1287,10 @@ static const struct of_device_id sdhci_arasan_of_match[] = { .compatible = "intel,keembay-sdhci-5.1-sdio", .data = &intel_keembay_sdio_data, }, + { + .compatible = "intel,thunderbay-sdhci-5.1", + .data = &sdhci_arasan_thunderbay_data, + }, /* Generic compatible below here */ { .compatible = "arasan,sdhci-8.9a", @@ -1626,7 +1652,8 @@ static int sdhci_arasan_probe(struct platform_device *pdev) if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") || of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd") || - of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio")) { + of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio") || + of_device_is_compatible(np, "intel,thunderbay-sdhci-5.1")) { sdhci_arasan_update_clockmultiplier(host, 0x0); sdhci_arasan_update_support64b(host, 0x0); -- cgit From d47f163c7794ce93e762897dcb6a956b3421b368 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Tue, 7 Sep 2021 17:12:03 +0200 Subject: mmc: cqhci: Print out qcnt in case of timeout Print task count that has not been completed, this is for the purpose of debugging. Signed-off-by: Bean Huo Link: https://lore.kernel.org/r/20210907151204.118861-2-huobean@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/cqhci-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c index 38559a956330..ca8329d55f43 100644 --- a/drivers/mmc/host/cqhci-core.c +++ b/drivers/mmc/host/cqhci-core.c @@ -899,8 +899,8 @@ static bool cqhci_timeout(struct mmc_host *mmc, struct mmc_request *mrq, spin_unlock_irqrestore(&cq_host->lock, flags); if (timed_out) { - pr_err("%s: cqhci: timeout for tag %d\n", - mmc_hostname(mmc), tag); + pr_err("%s: cqhci: timeout for tag %d, qcnt %d\n", + mmc_hostname(mmc), tag, cq_host->qcnt); cqhci_dumpregs(cq_host); } -- cgit From 43592c8736e84025d7a45e61a46c3fa40536a364 Mon Sep 17 00:00:00 2001 From: Christian Löhle Date: Thu, 16 Sep 2021 05:59:19 +0000 Subject: mmc: dw_mmc: Dont wait for DRTO on Write RSP error Only wait for DRTO on reads, otherwise the driver hangs. The driver prevents sending CMD12 on response errors like CRCs. According to the comment this is because some cards have problems with this during the UHS tuning sequence. Unfortunately this workaround currently also applies for any command with data. On reads this will set the drto timer, which then triggers after a while. On writes this will not set any timer and the tasklet will not be scheduled again. I cannot test for the UHS workarounds need, but even if so, it should at most apply to reads. I have observed many hangs when CMD25 response contained a CRC error. This patch fixes this without touching the actual UHS tuning workaround. Signed-off-by: Christian Loehle Reviewed-by: Jaehoon Chung Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/af8f8b8674ba4fcc9a781019e4aeb72c@hyperstone.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 380f9aa56eb2..1e8f1bb3cad7 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2086,7 +2086,8 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t) * delayed. Allowing the transfer to take place * avoids races and keeps things simple. */ - if (err != -ETIMEDOUT) { + if (err != -ETIMEDOUT && + host->dir_status == DW_MCI_RECV_STATUS) { state = STATE_SENDING_DATA; continue; } -- cgit From 8c2db344e5a213607764bf3d13ea1666d86dc44b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 16 Sep 2021 11:55:04 +0200 Subject: dt-bindings: mmc: update mmc-card.yaml reference The recent change ("dt-bindings: mmc: Convert MMC Card binding to a schema") renamed: Documentation/devicetree/bindings/mmc/mmc-card.txt to: Documentation/devicetree/bindings/mmc/mmc-card.yaml. Let's update its cross-reference accordingly. Signed-off-by: Mauro Carvalho Chehab Acked-by: Rob Herring Link: https://lore.kernel.org/r/820bb7a1d7e0e51cbea72c9bee6bce806427d1f3.1631785820.git.mchehab+huawei@kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 7a29ad542e4a..9dafcbf969d9 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1510,7 +1510,7 @@ static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) * REVISIT: should be moved to sdio core and made more * general e.g. by expanding the DT bindings of child nodes * to provide a mechanism to provide this information: - * Documentation/devicetree/bindings/mmc/mmc-card.txt + * Documentation/devicetree/bindings/mmc/mmc-card.yaml */ np = of_get_compatible_child(np, "ti,wl1251"); -- cgit From bc9fd32c294f4728663fac2dd82ecd0cfcba7ba9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Sep 2021 19:05:11 +0200 Subject: mmc: sdhci-s3c: drop unneeded MODULE_ALIAS The MODULE_DEVICE_TABLE already creates proper alias for platform driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Jaehoon Chung Link: https://lore.kernel.org/r/20210916170511.137915-1-krzysztof.kozlowski@canonical.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-s3c.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 862f033d235d..9085f3932443 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -791,4 +791,3 @@ module_platform_driver(sdhci_s3c_driver); MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue"); MODULE_AUTHOR("Ben Dooks, "); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:s3c-sdhci"); -- cgit From f614fb60a1983819e83796198de2b607fba75e99 Mon Sep 17 00:00:00 2001 From: Wenbin Mei Date: Fri, 17 Sep 2021 20:48:02 +0800 Subject: mmc: core: Add host specific tuning support for eMMC HS400 mode This adds a ->execute_hs400_tuning() host callback to enable optional support for host specific tuning for eMMC HS400 mode. Additionally, share mmc_get_ext_csd() through the public host headerfile, to allow it to be used by the host drivers, which is needed to support the HS400 tuning. Signed-off-by: Wenbin Mei Link: https://lore.kernel.org/r/20210917124803.22871-3-wenbin.mei@mediatek.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 8 ++++++++ drivers/mmc/core/mmc_ops.h | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 29e58ffae379..b1c1716dacf0 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1224,6 +1224,14 @@ static int mmc_select_hs400(struct mmc_card *card) mmc_set_timing(host, MMC_TIMING_MMC_HS400); mmc_set_bus_speed(card); + if (host->ops->execute_hs400_tuning) { + mmc_retune_disable(host); + err = host->ops->execute_hs400_tuning(host, card); + mmc_retune_enable(host); + if (err) + goto out_err; + } + if (host->ops->hs400_complete) host->ops->hs400_complete(host); diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index ae25ffc2e870..e5e94567a9a9 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -38,7 +38,6 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); int mmc_spi_set_crc(struct mmc_host *host, int use_crc); int mmc_bus_test(struct mmc_card *card, u8 bus_width); int mmc_can_ext_csd(struct mmc_card *card); -int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal); bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd, unsigned int timeout_ms); -- cgit From c4ac38c6539b6cccfda7e8cf8da50edf7877c865 Mon Sep 17 00:00:00 2001 From: Wenbin Mei Date: Fri, 17 Sep 2021 20:48:03 +0800 Subject: mmc: mtk-sd: Add HS400 online tuning support According to JEDEC Spec, there is no need to do tuning under HS400 mode since the Rx signal is aligned with the DS signal. However, MediaTek's IC need set its "DS delay" internally to ensure it can latch Rx signal correctly. In previous version, We provide an "hs400-ds-delay" in device tree to cover different chipset/PCB design, and it works fine in most cases. But, with the development of process technology and the big VCore voltage scale range(may have 0.7V/0.6V/0.55V), it is difficult to find a suitable "hs400-ds-delay" to cover all of IC corner cases(SSSS/TTTT/FFFF). So that We must have the ability to do hs400 online tuning. Signed-off-by: Wenbin Mei Reviewed-by: Chaotian Jing Link: https://lore.kernel.org/r/20210917124803.22871-4-wenbin.mei@mediatek.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 79 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index f611db05d1d9..b124cfee05a1 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -259,6 +259,7 @@ #define MSDC_PAD_TUNE_RD_SEL (0x1 << 13) /* RW */ #define MSDC_PAD_TUNE_CMD_SEL (0x1 << 21) /* RW */ +#define PAD_DS_TUNE_DLY_SEL (0x1 << 0) /* RW */ #define PAD_DS_TUNE_DLY1 (0x1f << 2) /* RW */ #define PAD_DS_TUNE_DLY2 (0x1f << 7) /* RW */ #define PAD_DS_TUNE_DLY3 (0x1f << 12) /* RW */ @@ -302,6 +303,11 @@ #define PAD_CMD_RD_RXDLY_SEL (0x1 << 11) /* RW */ #define PAD_CMD_TX_DLY (0x1f << 12) /* RW */ +/* EMMC50_PAD_DS_TUNE mask */ +#define PAD_DS_DLY_SEL (0x1 << 16) /* RW */ +#define PAD_DS_DLY1 (0x1f << 10) /* RW */ +#define PAD_DS_DLY3 (0x1f << 0) /* RW */ + #define REQ_CMD_EIO (0x1 << 0) #define REQ_CMD_TMO (0x1 << 1) #define REQ_DAT_ERR (0x1 << 2) @@ -449,11 +455,13 @@ struct msdc_host { bool vqmmc_enabled; u32 latch_ck; u32 hs400_ds_delay; + u32 hs400_ds_dly3; u32 hs200_cmd_int_delay; /* cmd internal delay for HS200/SDR104 */ u32 hs400_cmd_int_delay; /* cmd internal delay for HS400 */ bool hs400_cmd_resp_sel_rising; /* cmd response sample selection for HS400 */ bool hs400_mode; /* current eMMC will run at hs400 mode */ + bool hs400_tuning; /* hs400 mode online tuning */ bool internal_cd; /* Use internal card-detect logic */ bool cqhci; /* support eMMC hw cmdq */ struct msdc_save_para save_para; /* used when gate HCLK */ @@ -1190,7 +1198,8 @@ static bool msdc_cmd_done(struct msdc_host *host, int events, if (!sbc_error && !(events & MSDC_INT_CMDRDY)) { if (events & MSDC_INT_CMDTMO || (cmd->opcode != MMC_SEND_TUNING_BLOCK && - cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200)) + cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 && + !host->hs400_tuning)) /* * should not clear fifo/interrupt as the tune data * may have alreay come when cmd19/cmd21 gets response @@ -1287,7 +1296,8 @@ static void msdc_cmd_next(struct msdc_host *host, if ((cmd->error && !(cmd->error == -EILSEQ && (cmd->opcode == MMC_SEND_TUNING_BLOCK || - cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200))) || + cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200 || + host->hs400_tuning))) || (mrq->sbc && mrq->sbc->error)) msdc_request_done(host, mrq); else if (cmd == mrq->sbc) @@ -2251,6 +2261,67 @@ static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) return 0; } +static int msdc_execute_hs400_tuning(struct mmc_host *mmc, struct mmc_card *card) +{ + struct msdc_host *host = mmc_priv(mmc); + struct msdc_delay_phase dly1_delay; + u32 val, result_dly1 = 0; + u8 *ext_csd; + int i, ret; + + if (host->top_base) { + sdr_set_bits(host->top_base + EMMC50_PAD_DS_TUNE, + PAD_DS_DLY_SEL); + if (host->hs400_ds_dly3) + sdr_set_field(host->top_base + EMMC50_PAD_DS_TUNE, + PAD_DS_DLY3, host->hs400_ds_dly3); + } else { + sdr_set_bits(host->base + PAD_DS_TUNE, PAD_DS_TUNE_DLY_SEL); + if (host->hs400_ds_dly3) + sdr_set_field(host->base + PAD_DS_TUNE, + PAD_DS_TUNE_DLY3, host->hs400_ds_dly3); + } + + host->hs400_tuning = true; + for (i = 0; i < PAD_DELAY_MAX; i++) { + if (host->top_base) + sdr_set_field(host->top_base + EMMC50_PAD_DS_TUNE, + PAD_DS_DLY1, i); + else + sdr_set_field(host->base + PAD_DS_TUNE, + PAD_DS_TUNE_DLY1, i); + ret = mmc_get_ext_csd(card, &ext_csd); + if (!ret) + result_dly1 |= (1 << i); + } + host->hs400_tuning = false; + + dly1_delay = get_best_delay(host, result_dly1); + if (dly1_delay.maxlen == 0) { + dev_err(host->dev, "Failed to get DLY1 delay!\n"); + goto fail; + } + if (host->top_base) + sdr_set_field(host->top_base + EMMC50_PAD_DS_TUNE, + PAD_DS_DLY1, dly1_delay.final_phase); + else + sdr_set_field(host->base + PAD_DS_TUNE, + PAD_DS_TUNE_DLY1, dly1_delay.final_phase); + + if (host->top_base) + val = readl(host->top_base + EMMC50_PAD_DS_TUNE); + else + val = readl(host->base + PAD_DS_TUNE); + + dev_info(host->dev, "Fianl PAD_DS_TUNE: 0x%x\n", val); + + return 0; + +fail: + dev_err(host->dev, "Failed to tuning DS pin delay!\n"); + return -EIO; +} + static void msdc_hw_reset(struct mmc_host *mmc) { struct msdc_host *host = mmc_priv(mmc); @@ -2381,6 +2452,7 @@ static const struct mmc_host_ops mt_msdc_ops = { .card_busy = msdc_card_busy, .execute_tuning = msdc_execute_tuning, .prepare_hs400_tuning = msdc_prepare_hs400_tuning, + .execute_hs400_tuning = msdc_execute_hs400_tuning, .hw_reset = msdc_hw_reset, }; @@ -2400,6 +2472,9 @@ static void msdc_of_property_parse(struct platform_device *pdev, of_property_read_u32(pdev->dev.of_node, "hs400-ds-delay", &host->hs400_ds_delay); + of_property_read_u32(pdev->dev.of_node, "mediatek,hs400-ds-dly3", + &host->hs400_ds_dly3); + of_property_read_u32(pdev->dev.of_node, "mediatek,hs200-cmd-int-delay", &host->hs200_cmd_int_delay); -- cgit From 8e0e7bd38b1ec7f9e5d18725ad41828be4e09859 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 21 Sep 2021 14:00:25 +0300 Subject: mmc: sdhci-omap: Fix NULL pointer exception if regulator is not configured If sdhci-omap is configured for an unused device instance and the device is not set as disabled, we can get a NULL pointer dereference: Unable to handle kernel NULL pointer dereference at virtual address 00000045 ... (regulator_set_voltage) from [] (mmc_regulator_set_ocr+0x44/0xd0) (mmc_regulator_set_ocr) from [] (sdhci_set_ios+0xa4/0x490) (sdhci_set_ios) from [] (sdhci_omap_set_ios+0x124/0x160) (sdhci_omap_set_ios) from [] (mmc_power_up.part.0+0x3c/0x154) (mmc_power_up.part.0) from [] (mmc_start_host+0x88/0x9c) (mmc_start_host) from [] (mmc_add_host+0x58/0x7c) (mmc_add_host) from [] (__sdhci_add_host+0xf0/0x22c) (__sdhci_add_host) from [] (sdhci_omap_probe+0x318/0x72c) (sdhci_omap_probe) from [] (platform_probe+0x58/0xb8) AFAIK we are not seeing this with the devices configured in the mainline kernel but this can cause issues for folks bringing up their boards. Fixes: 7d326930d352 ("mmc: sdhci-omap: Add OMAP SDHCI driver") Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20210921110029.21944-2-tony@atomide.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 8f4d1f003f65..3ddced779e96 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -682,7 +682,8 @@ static void sdhci_omap_set_power(struct sdhci_host *host, unsigned char mode, { struct mmc_host *mmc = host->mmc; - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); + if (!IS_ERR(mmc->supply.vmmc)) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); } static int sdhci_omap_enable_dma(struct sdhci_host *host) -- cgit From d806e334d0390502cd2a820ad33d65d7f9bba618 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 21 Sep 2021 14:00:26 +0300 Subject: mmc: sdhci-omap: Fix context restore We need to restore context in a specified order with HCTL set in two phases. This is similar to what omap_hsmmc_context_restore() is doing. Otherwise SDIO can stop working on resume. And for PM runtime and SDIO cards, we need to also save SYSCTL, IE and ISE. This should not be a problem currently, and these patches can be applied whenever suitable. Fixes: ee0f309263a6 ("mmc: sdhci-omap: Add Support for Suspend/Resume") Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20210921110029.21944-3-tony@atomide.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 3ddced779e96..fd188b6d88f4 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -62,6 +62,8 @@ #define SDHCI_OMAP_IE 0x234 #define INT_CC_EN BIT(0) +#define SDHCI_OMAP_ISE 0x238 + #define SDHCI_OMAP_AC12 0x23c #define AC12_V1V8_SIGEN BIT(19) #define AC12_SCLK_SEL BIT(23) @@ -113,6 +115,8 @@ struct sdhci_omap_host { u32 hctl; u32 sysctl; u32 capa; + u32 ie; + u32 ise; }; static void sdhci_omap_start_clock(struct sdhci_omap_host *omap_host); @@ -1245,14 +1249,23 @@ static void sdhci_omap_context_save(struct sdhci_omap_host *omap_host) { omap_host->con = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); omap_host->hctl = sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL); + omap_host->sysctl = sdhci_omap_readl(omap_host, SDHCI_OMAP_SYSCTL); omap_host->capa = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA); + omap_host->ie = sdhci_omap_readl(omap_host, SDHCI_OMAP_IE); + omap_host->ise = sdhci_omap_readl(omap_host, SDHCI_OMAP_ISE); } +/* Order matters here, HCTL must be restored in two phases */ static void sdhci_omap_context_restore(struct sdhci_omap_host *omap_host) { - sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, omap_host->con); sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, omap_host->hctl); sdhci_omap_writel(omap_host, SDHCI_OMAP_CAPA, omap_host->capa); + sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, omap_host->hctl); + + sdhci_omap_writel(omap_host, SDHCI_OMAP_SYSCTL, omap_host->sysctl); + sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, omap_host->con); + sdhci_omap_writel(omap_host, SDHCI_OMAP_IE, omap_host->ie); + sdhci_omap_writel(omap_host, SDHCI_OMAP_ISE, omap_host->ise); } static int __maybe_unused sdhci_omap_suspend(struct device *dev) -- cgit From 53f9460e0883b029b7e93716d2f44f512c1efe94 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 21 Sep 2021 14:00:27 +0300 Subject: mmc: sdhci-omap: Restore sysconfig after reset The sysconfig register is managed in a generic way by PM runtime for us by the interconnect target module layer code. SDHCI_RESET_ALL also resets the target module configuration, so we need to restore sysconfig after reset. Note that there is no need to save and restore sysconfig during PM runtime, the PM runtime layer will do that for us. Not sure if this issue is a problem with the current configurations, I noticed the issue while adding support for older TI SoCs and testing with wlcore SDIO wlan device. Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20210921110029.21944-4-tony@atomide.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index fd188b6d88f4..3e745d5debef 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -21,6 +21,8 @@ #include "sdhci-pltfm.h" +#define SDHCI_OMAP_SYSCONFIG 0x110 + #define SDHCI_OMAP_CON 0x12c #define CON_DW8 BIT(5) #define CON_DMA_MASTER BIT(20) @@ -797,6 +799,11 @@ static void sdhci_omap_reset(struct sdhci_host *host, u8 mask) struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); unsigned long limit = MMC_TIMEOUT_US; unsigned long i = 0; + u32 sysc; + + /* Save target module sysconfig configured by SoC PM layer */ + if (mask & SDHCI_RESET_ALL) + sysc = sdhci_omap_readl(omap_host, SDHCI_OMAP_SYSCONFIG); /* Don't reset data lines during tuning operation */ if (omap_host->is_tuning) @@ -816,10 +823,15 @@ static void sdhci_omap_reset(struct sdhci_host *host, u8 mask) dev_err(mmc_dev(host->mmc), "Timeout waiting on controller reset in %s\n", __func__); - return; + + goto restore_sysc; } sdhci_reset(host, mask); + +restore_sysc: + if (mask & SDHCI_RESET_ALL) + sdhci_omap_writel(omap_host, SDHCI_OMAP_SYSCONFIG, sysc); } #define CMD_ERR_MASK (SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX |\ -- cgit From 3781d28805eca89796fd50af8e05569c210fc87d Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 21 Sep 2021 14:00:28 +0300 Subject: mmc: sdhci-omap: Parse legacy ti,non-removable property We need to support the legacy ti,non-removable property too. Let's warn about the legacy property and mark the device as non-removable. Naturally all the mainline kernel devicetree files will get updated to use the standard non-removable property with the sdhci-omap conversion. But we also have folks updating their kernels with custom devicetree files that we need to consider. Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20210921110029.21944-5-tony@atomide.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 3e745d5debef..f28862e03783 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -1213,6 +1213,11 @@ static int sdhci_omap_probe(struct platform_device *pdev) if (of_find_property(dev->of_node, "dmas", NULL)) sdhci_switch_external_dma(host, true); + if (device_property_read_bool(dev, "ti,non-removable")) { + dev_warn_once(dev, "using old ti,non-removable property\n"); + mmc->caps |= MMC_CAP_NONREMOVABLE; + } + /* R1B responses is required to properly manage HW busy detection. */ mmc->caps |= MMC_CAP_NEED_RSP_BUSY; -- cgit From c66e21fdc42dcc1c5c559fc4682f3a7f8b4c93f1 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 21 Sep 2021 14:00:29 +0300 Subject: mmc: sdhci-omap: Check MMCHS_HL_HWINFO register for ADMA ADMA is only available on controller instances that are connected to the L3 interconnect and are bus mastering capable. As the MMCHS_HL_HWINFO is in the module registers before omap registers and sdhci registers, and the omap registers and sdhci registers can be at different offsets depending on the SoC, let's read MMCHS_HL_HWINFO directly. Let's also switch to using device_property_present() while at it. Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20210921110029.21944-6-tony@atomide.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index f28862e03783..9422c9819b77 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -692,6 +692,22 @@ static void sdhci_omap_set_power(struct sdhci_host *host, unsigned char mode, mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); } +/* + * MMCHS_HL_HWINFO has the MADMA_EN bit set if the controller instance + * is connected to L3 interconnect and is bus master capable. Note that + * the MMCHS_HL_HWINFO register is in the module registers before the + * omap registers and sdhci registers. The offset can vary for omap + * registers depending on the SoC. Do not use sdhci_omap_readl() here. + */ +static bool sdhci_omap_has_adma(struct sdhci_omap_host *omap_host, int offset) +{ + /* MMCHS_HL_HWINFO register is only available on omap4 and later */ + if (offset < 0x200) + return false; + + return readl(omap_host->base + 4) & 1; +} + static int sdhci_omap_enable_dma(struct sdhci_host *host) { u32 reg; @@ -1209,8 +1225,12 @@ static int sdhci_omap_probe(struct platform_device *pdev) host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning; host->mmc_host_ops.enable_sdio_irq = sdhci_omap_enable_sdio_irq; - /* Switch to external DMA only if there is the "dmas" property */ - if (of_find_property(dev->of_node, "dmas", NULL)) + /* + * Switch to external DMA only if there is the "dmas" property and + * ADMA is not available on the controller instance. + */ + if (device_property_present(dev, "dmas") && + !sdhci_omap_has_adma(omap_host, offset)) sdhci_switch_external_dma(host, true); if (device_property_read_bool(dev, "ti,non-removable")) { -- cgit From 546b73ab019b10e8487cc8784220d32cfa08944b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 21 Sep 2021 16:33:59 +0200 Subject: mmc: mmci: Add small comment about reset thread Put a small comment before assigning IRQ_WAKE_THREAD telling us what is going on. Cc: Russell King Cc: Yann Gautier Cc: Ludovic Barre Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20210921143359.1738149-1-linus.walleij@linaro.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 3765e2f4ad98..c9cacd4d5b22 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1394,6 +1394,10 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, } else if (host->variant->busy_timeout && busy_resp && status & MCI_DATATIMEOUT) { cmd->error = -ETIMEDOUT; + /* + * This will wake up mmci_irq_thread() which will issue + * a hardware reset of the MMCI block. + */ host->irq_action = IRQ_WAKE_THREAD; } else { cmd->resp[0] = readl(base + MMCIRESPONSE0); -- cgit From 9c6bb8c6a1a48608692f3c8c21be13b759ec9056 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Fri, 17 Sep 2021 19:27:26 +0200 Subject: mmc: sdhci: Return true only when timeout exceeds capacity of the HW timer Clean up sdhci_calc_timeout() a bit, and let it set too_big to be true only when the timeout value required by the eMMC device exceeds the capability of the host hardware timer. Signed-off-by: Bean Huo Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20210917172727.26834-2-huobean@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 7ae398f8d4d3..357b365bf0ec 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -930,7 +930,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd, struct mmc_data *data; unsigned target_timeout, current_timeout; - *too_big = true; + *too_big = false; /* * If the host controller provides us with an incorrect timeout @@ -941,7 +941,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd, if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) return host->max_timeout_count; - /* Unspecified command, asume max */ + /* Unspecified command, assume max */ if (cmd == NULL) return host->max_timeout_count; @@ -968,17 +968,14 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd, while (current_timeout < target_timeout) { count++; current_timeout <<= 1; - if (count > host->max_timeout_count) + if (count > host->max_timeout_count) { + if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT)) + DBG("Too large timeout 0x%x requested for CMD%d!\n", + count, cmd->opcode); + count = host->max_timeout_count; + *too_big = true; break; - } - - if (count > host->max_timeout_count) { - if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT)) - DBG("Too large timeout 0x%x requested for CMD%d!\n", - count, cmd->opcode); - count = host->max_timeout_count; - } else { - *too_big = false; + } } return count; -- cgit From 46cdda974757f069d2c830f5a14c83960a782537 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Sep 2021 15:32:57 +0200 Subject: mmc: sdhci-s3c: Describe driver in KConfig Describe better which driver applies to which SoC, to make configuring kernel for Samsung SoC easier. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210924133257.112017-1-krzysztof.kozlowski@canonical.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 95b3511b0560..ed1bab8f3a8f 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -315,15 +315,17 @@ config MMC_SDHCI_TEGRA If unsure, say N. config MMC_SDHCI_S3C - tristate "SDHCI support on Samsung S3C SoC" + tristate "SDHCI support on Samsung S3C/S5P/Exynos SoC" depends on MMC_SDHCI depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST help This selects the Secure Digital Host Controller Interface (SDHCI) often referrered to as the HSMMC block in some of the Samsung S3C - range of SoC. + (S3C2416, S3C2443, S3C6410), S5Pv210 and Exynos (Exynso4210, + Exynos4412) SoCs. - If you have a controller with this interface, say Y or M here. + If you have a controller with this interface (thereforeyou build for + such Samsung SoC), say Y or M here. If unsure, say N. -- cgit From 0818d197d2ab0e4d47ce0a72cfa3bc32ac66ae0d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 24 Sep 2021 23:51:11 +0100 Subject: mmc: sdhci-pci-o2micro: Fix spelling mistake "unsupport" -> "unsupported" There is a spelling mistake in a pr_info message. Fix it. Also put msi in capital letters. Signed-off-by: Colin Ian King Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20210924225111.143112-1-colin.king@canonical.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-o2micro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c index 51d55a87aebe..f045c1ee4667 100644 --- a/drivers/mmc/host/sdhci-pci-o2micro.c +++ b/drivers/mmc/host/sdhci-pci-o2micro.c @@ -489,7 +489,7 @@ static void sdhci_pci_o2_enable_msi(struct sdhci_pci_chip *chip, ret = pci_find_capability(chip->pdev, PCI_CAP_ID_MSI); if (!ret) { - pr_info("%s: unsupport msi, use INTx irq\n", + pr_info("%s: unsupported MSI, use INTx irq\n", mmc_hostname(host->mmc)); return; } -- cgit From 7f00917a82331d4a3a22acce5076cb40fa7be668 Mon Sep 17 00:00:00 2001 From: Zhenxiong Lai Date: Sun, 26 Sep 2021 17:28:35 +0800 Subject: mmc: sdhci-sprd: Wait until DLL locked after being configured According to the specification, DLL status has to be locked before using it. Signed-off-by: Zhenxiong Lai Signed-off-by: Chunyan Zhang Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20210926092835.146449-1-zhang.lyra@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-sprd.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index 11e375579cfb..f33e9349e4e6 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,9 @@ #define SDHCI_SPRD_BIT_POSRD_DLY_INV BIT(21) #define SDHCI_SPRD_BIT_NEGRD_DLY_INV BIT(29) +#define SDHCI_SPRD_REG_32_DLL_STS0 0x210 +#define SDHCI_SPRD_DLL_LOCKED BIT(18) + #define SDHCI_SPRD_REG_32_BUSY_POSI 0x250 #define SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN BIT(25) #define SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN BIT(24) @@ -256,6 +260,15 @@ static void sdhci_sprd_enable_phy_dll(struct sdhci_host *host) sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG); /* wait 1ms */ usleep_range(1000, 1250); + + if (read_poll_timeout(sdhci_readl, tmp, (tmp & SDHCI_SPRD_DLL_LOCKED), + 2000, USEC_PER_SEC, false, host, SDHCI_SPRD_REG_32_DLL_STS0)) { + pr_err("%s: DLL locked fail!\n", mmc_hostname(host->mmc)); + pr_info("%s: DLL_STS0 : 0x%x, DLL_CFG : 0x%x\n", + mmc_hostname(host->mmc), + sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_STS0), + sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG)); + } } static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock) -- cgit From 4877b81f0fa2a3b1eb80541e49790683926104c9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 29 Sep 2021 14:17:56 +0300 Subject: mmc: slot-gpio: Refactor mmc_gpio_alloc() Refactor mmc_gpio_alloc() to drop unneeded indentation level and double condition. This increases readability of the code. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210929111757.52625-1-andriy.shevchenko@linux.intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/slot-gpio.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 05e907451df9..e365d328f43c 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -39,24 +39,24 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) int mmc_gpio_alloc(struct mmc_host *host) { - struct mmc_gpio *ctx = devm_kzalloc(host->parent, - sizeof(*ctx), GFP_KERNEL); - - if (ctx) { - ctx->cd_debounce_delay_ms = 200; - ctx->cd_label = devm_kasprintf(host->parent, GFP_KERNEL, - "%s cd", dev_name(host->parent)); - if (!ctx->cd_label) - return -ENOMEM; - ctx->ro_label = devm_kasprintf(host->parent, GFP_KERNEL, - "%s ro", dev_name(host->parent)); - if (!ctx->ro_label) - return -ENOMEM; - host->slot.handler_priv = ctx; - host->slot.cd_irq = -EINVAL; - } + const char *devname = dev_name(host->parent); + struct mmc_gpio *ctx; + + ctx = devm_kzalloc(host->parent, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->cd_debounce_delay_ms = 200; + ctx->cd_label = devm_kasprintf(host->parent, GFP_KERNEL, "%s cd", devname); + if (!ctx->cd_label) + return -ENOMEM; + ctx->ro_label = devm_kasprintf(host->parent, GFP_KERNEL, "%s ro", devname); + if (!ctx->ro_label) + return -ENOMEM; + host->slot.handler_priv = ctx; + host->slot.cd_irq = -EINVAL; - return ctx ? 0 : -ENOMEM; + return 0; } int mmc_gpio_get_ro(struct mmc_host *host) -- cgit From 8792b0a09fa470cc476b2124f6c1061258c9ef7a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 29 Sep 2021 14:17:57 +0300 Subject: mmc: slot-gpio: Update default label when no con_id provided Currently default label of GPIO is assigned to the device name, when no con_id provided. Instead, let's update it to reflect what it's about (use already prepared template). Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210929111757.52625-2-andriy.shevchenko@linux.intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/slot-gpio.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index e365d328f43c..dd2a4b6ab6ad 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -178,6 +178,10 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, if (IS_ERR(desc)) return PTR_ERR(desc); + /* Update default label if no con_id provided */ + if (!con_id) + gpiod_set_consumer_name(desc, ctx->cd_label); + if (debounce) { ret = gpiod_set_debounce(desc, debounce); if (ret < 0) @@ -226,6 +230,10 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, if (IS_ERR(desc)) return PTR_ERR(desc); + /* Update default label if no con_id provided */ + if (!con_id) + gpiod_set_consumer_name(desc, ctx->ro_label); + if (debounce) { ret = gpiod_set_debounce(desc, debounce); if (ret < 0) -- cgit From 8105c2abbf36296bf38ca44f55ee45d160db476a Mon Sep 17 00:00:00 2001 From: Xin Xiong Date: Sat, 9 Oct 2021 12:19:18 +0800 Subject: mmc: moxart: Fix reference count leaks in moxart_probe The issue happens in several error handling paths on two refcounted object related to the object "host" (dma_chan_rx, dma_chan_tx). In these paths, the function forgets to decrement one or both objects' reference count increased earlier by dma_request_chan(), causing reference count leaks. Fix it by balancing the refcounts of both objects in some error handling paths. In correspondence with the changes in moxart_probe(), IS_ERR() is replaced with IS_ERR_OR_NULL() in moxart_remove() as well. Signed-off-by: Xin Xiong Signed-off-by: Xiyu Yang Signed-off-by: Xin Tan Link: https://lore.kernel.org/r/20211009041918.28419-1-xiongx18@fudan.edu.cn Signed-off-by: Ulf Hansson --- drivers/mmc/host/moxart-mmc.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index 6c9d38132f74..7b9fcef490de 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -621,6 +621,14 @@ static int moxart_probe(struct platform_device *pdev) ret = -EPROBE_DEFER; goto out; } + if (!IS_ERR(host->dma_chan_tx)) { + dma_release_channel(host->dma_chan_tx); + host->dma_chan_tx = NULL; + } + if (!IS_ERR(host->dma_chan_rx)) { + dma_release_channel(host->dma_chan_rx); + host->dma_chan_rx = NULL; + } dev_dbg(dev, "PIO mode transfer enabled\n"); host->have_dma = false; } else { @@ -675,6 +683,10 @@ static int moxart_probe(struct platform_device *pdev) return 0; out: + if (!IS_ERR_OR_NULL(host->dma_chan_tx)) + dma_release_channel(host->dma_chan_tx); + if (!IS_ERR_OR_NULL(host->dma_chan_rx)) + dma_release_channel(host->dma_chan_rx); if (mmc) mmc_free_host(mmc); return ret; @@ -687,9 +699,9 @@ static int moxart_remove(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, NULL); - if (!IS_ERR(host->dma_chan_tx)) + if (!IS_ERR_OR_NULL(host->dma_chan_tx)) dma_release_channel(host->dma_chan_tx); - if (!IS_ERR(host->dma_chan_rx)) + if (!IS_ERR_OR_NULL(host->dma_chan_rx)) dma_release_channel(host->dma_chan_rx); mmc_remove_host(mmc); mmc_free_host(mmc); -- cgit From 0eab756f8821d255016c63bb55804c429ff4bdb1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 13 Oct 2021 11:00:52 +0100 Subject: mmc: moxart: Fix null pointer dereference on pointer host There are several error return paths that dereference the null pointer host because the pointer has not yet been set to a valid value. Fix this by adding a new out_mmc label and exiting via this label to avoid the host clean up and hence the null pointer dereference. Addresses-Coverity: ("Explicit null dereference") Fixes: 8105c2abbf36 ("mmc: moxart: Fix reference count leaks in moxart_probe") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20211013100052.125461-1-colin.king@canonical.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/moxart-mmc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index 7b9fcef490de..16d1c7a43d33 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -566,37 +566,37 @@ static int moxart_probe(struct platform_device *pdev) if (!mmc) { dev_err(dev, "mmc_alloc_host failed\n"); ret = -ENOMEM; - goto out; + goto out_mmc; } ret = of_address_to_resource(node, 0, &res_mmc); if (ret) { dev_err(dev, "of_address_to_resource failed\n"); - goto out; + goto out_mmc; } irq = irq_of_parse_and_map(node, 0); if (irq <= 0) { dev_err(dev, "irq_of_parse_and_map failed\n"); ret = -EINVAL; - goto out; + goto out_mmc; } clk = devm_clk_get(dev, NULL); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - goto out; + goto out_mmc; } reg_mmc = devm_ioremap_resource(dev, &res_mmc); if (IS_ERR(reg_mmc)) { ret = PTR_ERR(reg_mmc); - goto out; + goto out_mmc; } ret = mmc_of_parse(mmc); if (ret) - goto out; + goto out_mmc; host = mmc_priv(mmc); host->mmc = mmc; @@ -687,6 +687,7 @@ out: dma_release_channel(host->dma_chan_tx); if (!IS_ERR_OR_NULL(host->dma_chan_rx)) dma_release_channel(host->dma_chan_rx); +out_mmc: if (mmc) mmc_free_host(mmc); return ret; -- cgit From 2caa11bc2d29043714cddab1bd5d5841834b008c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 14 Oct 2021 16:26:09 +0300 Subject: mmc: sdhci: Deduplicate sdhci_get_cd_nogpio() The analogue of the sdhci_get_cd_nogpio() is used in the sdhci-pci-core and sdhci-acpi modules. Deduplicate it by moving to sdhci and exporting. Signed-off-by: Andy Shevchenko Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20211014132613.27861-2-andriy.shevchenko@linux.intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-acpi.c | 14 +------------- drivers/mmc/host/sdhci-pci-core.c | 18 ------------------ drivers/mmc/host/sdhci.c | 19 +++++++++++++++++++ drivers/mmc/host/sdhci.h | 1 + 4 files changed, 21 insertions(+), 31 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 8fe65f172a61..f1ef0d28b0dd 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -362,23 +362,11 @@ static inline bool sdhci_acpi_no_fixup_child_power(struct acpi_device *adev) static int bxt_get_cd(struct mmc_host *mmc) { int gpio_cd = mmc_gpio_get_cd(mmc); - struct sdhci_host *host = mmc_priv(mmc); - unsigned long flags; - int ret = 0; if (!gpio_cd) return 0; - spin_lock_irqsave(&host->lock, flags); - - if (host->flags & SDHCI_DEVICE_DEAD) - goto out; - - ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); -out: - spin_unlock_irqrestore(&host->lock, flags); - - return ret; + return sdhci_get_cd_nogpio(mmc); } static int intel_probe_slot(struct platform_device *pdev, struct acpi_device *adev) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index d0f2edfe296c..19e13dfae593 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -616,24 +616,6 @@ static int intel_select_drive_strength(struct mmc_card *card, return intel_host->drv_strength; } -static int sdhci_get_cd_nogpio(struct mmc_host *mmc) -{ - struct sdhci_host *host = mmc_priv(mmc); - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&host->lock, flags); - - if (host->flags & SDHCI_DEVICE_DEAD) - goto out; - - ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); -out: - spin_unlock_irqrestore(&host->lock, flags); - - return ret; -} - static int bxt_get_cd(struct mmc_host *mmc) { int gpio_cd = mmc_gpio_get_cd(mmc); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index dbe87995596c..269c86569402 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2425,6 +2425,25 @@ static int sdhci_get_cd(struct mmc_host *mmc) return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); } +int sdhci_get_cd_nogpio(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&host->lock, flags); + + if (host->flags & SDHCI_DEVICE_DEAD) + goto out; + + ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); +out: + spin_unlock_irqrestore(&host->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(sdhci_get_cd_nogpio); + static int sdhci_check_ro(struct sdhci_host *host) { unsigned long flags; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index e8d04e42a5af..c593af479832 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -775,6 +775,7 @@ void sdhci_set_power_and_bus_voltage(struct sdhci_host *host, unsigned short vdd); void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, unsigned short vdd); +int sdhci_get_cd_nogpio(struct mmc_host *mmc); void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq); int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq); void sdhci_set_bus_width(struct sdhci_host *host, int width); -- cgit From e087e11c4cff869bc54bda3c2cb52f394ecdbb79 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 14 Oct 2021 16:26:10 +0300 Subject: mmc: sdhci: Remove unused prototype declaration in the header sdhci_card_detect() is not defined anywhere. Remove it. Signed-off-by: Andy Shevchenko Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20211014132613.27861-3-andriy.shevchenko@linux.intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index c593af479832..bb883553d3b4 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -750,7 +750,6 @@ static inline void *sdhci_priv(struct sdhci_host *host) return host->private; } -void sdhci_card_detect(struct sdhci_host *host); void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver, const u32 *caps, const u32 *caps1); int sdhci_setup_host(struct sdhci_host *host); -- cgit From 5c67aa59bd8f99d70c81b5e71bd02083056a8486 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 14 Oct 2021 16:26:11 +0300 Subject: mmc: sdhci-pci: Remove dead code (struct sdhci_pci_data et al) The last user of this struct gone a couple of releases ago. Besides that there were not so many users of this API for more than 10 years: 1/ The one is Intel Merrifield, that had been added 2016-08-31 by the commit 3976b0380b31 ("x86/platform/intel-mid: Enable SD card detection on Merrifield") and removed 2021-02-11 by the commit 4590d98f5a4f ("sfi: Remove framework for deprecated firmware"). 2/ The other is Intel Sunrisepoint related, that had been added 2015-02-06 by the commit e1bfad6d936d ("mmc: sdhci-pci: Add support for drive strength selection for SPT") and removed 2017-03-20 by the commit 51ced59cc02e ("mmc: sdhci-pci: Use ACPI DSM to get driver strength for some Intel devices"). Effectively this is a revert of the commit 52c506f0bc72 ("mmc: sdhci-pci: add platform data"). Signed-off-by: Andy Shevchenko Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20211014132613.27861-4-andriy.shevchenko@linux.intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/Makefile | 1 - drivers/mmc/host/sdhci-pci-core.c | 31 ++++--------------------------- drivers/mmc/host/sdhci-pci-data.c | 6 ------ drivers/mmc/host/sdhci-pci.h | 1 - 4 files changed, 4 insertions(+), 35 deletions(-) delete mode 100644 drivers/mmc/host/sdhci-pci-data.c (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 14004cc09aaa..ea36d379bd3c 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -14,7 +14,6 @@ obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \ sdhci-pci-dwc-mshc.o sdhci-pci-gli.o -obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 19e13dfae593..8938c63b1e77 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -17,8 +17,6 @@ #include #include #include -#include -#include #include #include #include @@ -26,11 +24,13 @@ #include #include #include -#include -#include #include #include +#include +#include +#include + #ifdef CONFIG_X86 #include #endif @@ -2131,22 +2131,6 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( slot->cd_gpio = -EINVAL; slot->cd_idx = -1; - /* Retrieve platform data if there is any */ - if (*sdhci_pci_get_data) - slot->data = sdhci_pci_get_data(pdev, slotno); - - if (slot->data) { - if (slot->data->setup) { - ret = slot->data->setup(slot->data); - if (ret) { - dev_err(&pdev->dev, "platform setup failed\n"); - goto free; - } - } - slot->rst_n_gpio = slot->data->rst_n_gpio; - slot->cd_gpio = slot->data->cd_gpio; - } - host->hw_name = "PCI"; host->ops = chip->fixes && chip->fixes->ops ? chip->fixes->ops : @@ -2233,10 +2217,6 @@ remove: chip->fixes->remove_slot(slot, 0); cleanup: - if (slot->data && slot->data->cleanup) - slot->data->cleanup(slot->data); - -free: sdhci_free_host(host); return ERR_PTR(ret); @@ -2259,9 +2239,6 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) if (slot->chip->fixes && slot->chip->fixes->remove_slot) slot->chip->fixes->remove_slot(slot, dead); - if (slot->data && slot->data->cleanup) - slot->data->cleanup(slot->data); - sdhci_free_host(slot->host); } diff --git a/drivers/mmc/host/sdhci-pci-data.c b/drivers/mmc/host/sdhci-pci-data.c deleted file mode 100644 index 18638fb363d8..000000000000 --- a/drivers/mmc/host/sdhci-pci-data.c +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#include -#include - -struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, int slotno); -EXPORT_SYMBOL_GPL(sdhci_pci_get_data); diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 8f90c4163bb5..15b36cd47860 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -156,7 +156,6 @@ struct sdhci_pci_fixes { struct sdhci_pci_slot { struct sdhci_pci_chip *chip; struct sdhci_host *host; - struct sdhci_pci_data *data; int rst_n_gpio; int cd_gpio; -- cgit From 67f7296e13b58e2555b358f9f4fecaf3b2091f73 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 14 Oct 2021 16:26:12 +0300 Subject: mmc: sdhci-pci: Remove dead code (cd_gpio, cd_irq et al) The last user of this struct gone couple of releases ago. Remove the dead code for good and encourage people to use MMC core functionality for that. The removal is dependent on the previous removal of the struct sdhci_pci_data. Signed-off-by: Andy Shevchenko Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20211014132613.27861-5-andriy.shevchenko@linux.intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 76 +-------------------------------------- drivers/mmc/host/sdhci-pci.h | 2 -- 2 files changed, 1 insertion(+), 77 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 8938c63b1e77..e2b6f60e9f01 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -345,73 +345,6 @@ static int pch_hc_probe_slot(struct sdhci_pci_slot *slot) return 0; } -#ifdef CONFIG_PM - -static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id) -{ - struct sdhci_pci_slot *slot = dev_id; - struct sdhci_host *host = slot->host; - - mmc_detect_change(host->mmc, msecs_to_jiffies(200)); - return IRQ_HANDLED; -} - -static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) -{ - int err, irq, gpio = slot->cd_gpio; - - slot->cd_gpio = -EINVAL; - slot->cd_irq = -EINVAL; - - if (!gpio_is_valid(gpio)) - return; - - err = devm_gpio_request(&slot->chip->pdev->dev, gpio, "sd_cd"); - if (err < 0) - goto out; - - err = gpio_direction_input(gpio); - if (err < 0) - goto out_free; - - irq = gpio_to_irq(gpio); - if (irq < 0) - goto out_free; - - err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING | - IRQF_TRIGGER_FALLING, "sd_cd", slot); - if (err) - goto out_free; - - slot->cd_gpio = gpio; - slot->cd_irq = irq; - - return; - -out_free: - devm_gpio_free(&slot->chip->pdev->dev, gpio); -out: - dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n"); -} - -static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) -{ - if (slot->cd_irq >= 0) - free_irq(slot->cd_irq, slot); -} - -#else - -static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) -{ -} - -static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) -{ -} - -#endif - static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) { slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; @@ -2128,7 +2061,6 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( slot->chip = chip; slot->host = host; slot->rst_n_gpio = -EINVAL; - slot->cd_gpio = -EINVAL; slot->cd_idx = -1; host->hw_name = "PCI"; @@ -2199,15 +2131,11 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( if (ret) goto remove; - sdhci_pci_add_own_cd(slot); - /* * Check if the chip needs a separate GPIO for card detect to wake up * from runtime suspend. If it is not there, don't allow runtime PM. - * Note sdhci_pci_add_own_cd() sets slot->cd_gpio to -EINVAL on failure. */ - if (chip->fixes && chip->fixes->own_cd_for_runtime_pm && - !gpio_is_valid(slot->cd_gpio) && slot->cd_idx < 0) + if (chip->fixes && chip->fixes->own_cd_for_runtime_pm && slot->cd_idx < 0) chip->allow_runtime_pm = false; return slot; @@ -2227,8 +2155,6 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) int dead; u32 scratch; - sdhci_pci_remove_own_cd(slot); - dead = 0; scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS); if (scratch == (u32)-1) diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 15b36cd47860..8bb3b9c78589 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -158,8 +158,6 @@ struct sdhci_pci_slot { struct sdhci_host *host; int rst_n_gpio; - int cd_gpio; - int cd_irq; int cd_idx; bool cd_override_level; -- cgit From 976171c360c73c059924928d55176a78c2241456 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 14 Oct 2021 16:26:13 +0300 Subject: mmc: sdhci-pci: Remove dead code (rst_n_gpio et al) There is no user of this member. Remove the dead code for good. The removal is dependent on the previous removal of the struct sdhci_pci_data. Signed-off-by: Andy Shevchenko Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20211014132613.27861-6-andriy.shevchenko@linux.intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 27 --------------------------- drivers/mmc/host/sdhci-pci.h | 2 -- 2 files changed, 29 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index e2b6f60e9f01..6f9877546830 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -1915,21 +1915,6 @@ int sdhci_pci_enable_dma(struct sdhci_host *host) return 0; } -static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host) -{ - struct sdhci_pci_slot *slot = sdhci_priv(host); - int rst_n_gpio = slot->rst_n_gpio; - - if (!gpio_is_valid(rst_n_gpio)) - return; - gpio_set_value_cansleep(rst_n_gpio, 0); - /* For eMMC, minimum is 1us but give it 10us for good measure */ - udelay(10); - gpio_set_value_cansleep(rst_n_gpio, 1); - /* For eMMC, minimum is 200us but give it 300us for good measure */ - usleep_range(300, 1000); -} - static void sdhci_pci_hw_reset(struct sdhci_host *host) { struct sdhci_pci_slot *slot = sdhci_priv(host); @@ -2060,7 +2045,6 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( slot->chip = chip; slot->host = host; - slot->rst_n_gpio = -EINVAL; slot->cd_idx = -1; host->hw_name = "PCI"; @@ -2086,17 +2070,6 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( goto cleanup; } - if (gpio_is_valid(slot->rst_n_gpio)) { - if (!devm_gpio_request(&pdev->dev, slot->rst_n_gpio, "eMMC_reset")) { - gpio_direction_output(slot->rst_n_gpio, 1); - slot->host->mmc->caps |= MMC_CAP_HW_RESET; - slot->hw_reset = sdhci_pci_gpio_hw_reset; - } else { - dev_warn(&pdev->dev, "failed to request rst_n_gpio\n"); - slot->rst_n_gpio = -EINVAL; - } - } - host->mmc->pm_caps = MMC_PM_KEEP_POWER; host->mmc->slotno = slotno; host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP; diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 8bb3b9c78589..5e3193278ff9 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -157,8 +157,6 @@ struct sdhci_pci_slot { struct sdhci_pci_chip *chip; struct sdhci_host *host; - int rst_n_gpio; - int cd_idx; bool cd_override_level; -- cgit From de5ccd2af71fc616d7112420054478b84622eb5d Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 15 Oct 2021 13:47:16 +0300 Subject: mmc: sdhci-omap: Handle voltages to add support omap4 In order to start deprecating the custom omap_hsmmc.c in favor of the generic sdhci-omap driver, we need to add support for voltages for earlier SoCs. The PBIAS regulator on omap4 and earlier only supports nominal values of 1.8V and 3.0V, while omap5 and later support nominal values of 1.8V and 3.3V IO voltage. This gets omap4/5 working with sdhci-omap driver. Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20211015104720.52240-3-tony@atomide.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 124 ++++++++++++++++++++++++++++++++---------- 1 file changed, 96 insertions(+), 28 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 9422c9819b77..a33b74238294 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -178,7 +178,7 @@ static int sdhci_omap_set_pbias(struct sdhci_omap_host *omap_host, } static int sdhci_omap_enable_iov(struct sdhci_omap_host *omap_host, - unsigned int iov) + unsigned int iov_pbias) { int ret; struct sdhci_host *host = omap_host->host; @@ -189,14 +189,15 @@ static int sdhci_omap_enable_iov(struct sdhci_omap_host *omap_host, return ret; if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_set_voltage(mmc->supply.vqmmc, iov, iov); - if (ret) { + /* Pick the right voltage to allow 3.0V for 3.3V nominal PBIAS */ + ret = mmc_regulator_set_vqmmc(mmc, &mmc->ios); + if (ret < 0) { dev_err(mmc_dev(mmc), "vqmmc set voltage failed\n"); return ret; } } - ret = sdhci_omap_set_pbias(omap_host, true, iov); + ret = sdhci_omap_set_pbias(omap_host, true, iov_pbias); if (ret) return ret; @@ -206,16 +207,28 @@ static int sdhci_omap_enable_iov(struct sdhci_omap_host *omap_host, static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host, unsigned char signal_voltage) { - u32 reg; + u32 reg, capa; ktime_t timeout; reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL); reg &= ~HCTL_SDVS_MASK; - if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) - reg |= HCTL_SDVS_33; - else + switch (signal_voltage) { + case MMC_SIGNAL_VOLTAGE_330: + capa = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA); + if (capa & CAPA_VS33) + reg |= HCTL_SDVS_33; + else if (capa & CAPA_VS30) + reg |= HCTL_SDVS_30; + else + dev_warn(omap_host->dev, "misconfigured CAPA: %08x\n", + capa); + break; + case MMC_SIGNAL_VOLTAGE_180: + default: reg |= HCTL_SDVS_18; + break; + } sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, reg); @@ -533,28 +546,32 @@ static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc, if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA); - if (!(reg & CAPA_VS33)) + if (!(reg & (CAPA_VS30 | CAPA_VS33))) return -EOPNOTSUPP; + if (reg & CAPA_VS30) + iov = IOV_3V0; + else + iov = IOV_3V3; + sdhci_omap_conf_bus_power(omap_host, ios->signal_voltage); reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12); reg &= ~AC12_V1V8_SIGEN; sdhci_omap_writel(omap_host, SDHCI_OMAP_AC12, reg); - iov = IOV_3V3; } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA); if (!(reg & CAPA_VS18)) return -EOPNOTSUPP; + iov = IOV_1V8; + sdhci_omap_conf_bus_power(omap_host, ios->signal_voltage); reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12); reg |= AC12_V1V8_SIGEN; sdhci_omap_writel(omap_host, SDHCI_OMAP_AC12, reg); - - iov = IOV_1V8; } else { return -EOPNOTSUPP; } @@ -910,34 +927,73 @@ static struct sdhci_ops sdhci_omap_ops = { .set_timeout = sdhci_omap_set_timeout, }; -static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host) +static unsigned int sdhci_omap_regulator_get_caps(struct device *dev, + const char *name) { - u32 reg; - int ret = 0; + struct regulator *reg; + unsigned int caps = 0; + + reg = regulator_get(dev, name); + if (IS_ERR(reg)) + return ~0U; + + if (regulator_is_supported_voltage(reg, 1700000, 1950000)) + caps |= SDHCI_CAN_VDD_180; + if (regulator_is_supported_voltage(reg, 2700000, 3150000)) + caps |= SDHCI_CAN_VDD_300; + if (regulator_is_supported_voltage(reg, 3150000, 3600000)) + caps |= SDHCI_CAN_VDD_330; + + regulator_put(reg); + + return caps; +} + +static int sdhci_omap_set_capabilities(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); struct device *dev = omap_host->dev; - struct regulator *vqmmc; + const u32 mask = SDHCI_CAN_VDD_180 | SDHCI_CAN_VDD_300 | SDHCI_CAN_VDD_330; + unsigned int pbias, vqmmc, caps = 0; + u32 reg; - vqmmc = regulator_get(dev, "vqmmc"); - if (IS_ERR(vqmmc)) { - ret = PTR_ERR(vqmmc); - goto reg_put; - } + pbias = sdhci_omap_regulator_get_caps(dev, "pbias"); + vqmmc = sdhci_omap_regulator_get_caps(dev, "vqmmc"); + caps = pbias & vqmmc; + + if (pbias != ~0U && vqmmc == ~0U) + dev_warn(dev, "vqmmc regulator missing for pbias\n"); + else if (caps == ~0U) + return 0; + + /* + * Quirk handling to allow 3.0V vqmmc with a valid 3.3V PBIAS. This is + * needed for 3.0V ldo9_reg on omap5 at least. + */ + if (pbias != ~0U && (pbias & SDHCI_CAN_VDD_330) && + (vqmmc & SDHCI_CAN_VDD_300)) + caps |= SDHCI_CAN_VDD_330; /* voltage capabilities might be set by boot loader, clear it */ reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA); reg &= ~(CAPA_VS18 | CAPA_VS30 | CAPA_VS33); - if (regulator_is_supported_voltage(vqmmc, IOV_3V3, IOV_3V3)) - reg |= CAPA_VS33; - if (regulator_is_supported_voltage(vqmmc, IOV_1V8, IOV_1V8)) + if (caps & SDHCI_CAN_VDD_180) reg |= CAPA_VS18; + if (caps & SDHCI_CAN_VDD_300) + reg |= CAPA_VS30; + + if (caps & SDHCI_CAN_VDD_330) + reg |= CAPA_VS33; + sdhci_omap_writel(omap_host, SDHCI_OMAP_CAPA, reg); -reg_put: - regulator_put(vqmmc); + host->caps &= ~mask; + host->caps |= caps; - return ret; + return 0; } static const struct sdhci_pltfm_data sdhci_omap_pdata = { @@ -953,6 +1009,16 @@ static const struct sdhci_pltfm_data sdhci_omap_pdata = { .ops = &sdhci_omap_ops, }; +static const struct sdhci_omap_data omap4_data = { + .offset = 0x200, + .flags = SDHCI_OMAP_SPECIAL_RESET, +}; + +static const struct sdhci_omap_data omap5_data = { + .offset = 0x200, + .flags = SDHCI_OMAP_SPECIAL_RESET, +}; + static const struct sdhci_omap_data k2g_data = { .offset = 0x200, }; @@ -973,6 +1039,8 @@ static const struct sdhci_omap_data dra7_data = { }; static const struct of_device_id omap_sdhci_match[] = { + { .compatible = "ti,omap4-sdhci", .data = &omap4_data }, + { .compatible = "ti,omap5-sdhci", .data = &omap5_data }, { .compatible = "ti,dra7-sdhci", .data = &dra7_data }, { .compatible = "ti,k2g-sdhci", .data = &k2g_data }, { .compatible = "ti,am335-sdhci", .data = &am335_data }, @@ -1212,7 +1280,7 @@ static int sdhci_omap_probe(struct platform_device *pdev) goto err_rpm_disable; } - ret = sdhci_omap_set_capabilities(omap_host); + ret = sdhci_omap_set_capabilities(host); if (ret) { dev_err(dev, "failed to set system capabilities\n"); goto err_put_sync; -- cgit From 42b380b69b2ea0e218d3534ea8073fd67bbbf67b Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 15 Oct 2021 13:47:17 +0300 Subject: mmc: sdhci-omap: Add omap_offset to support omap3 and earlier The omap specific registers are at offset 0x100 from base for omap4 and later, and for omap3 and earlier they are at offset 0. Let's handle also the earlier SoCs by adding omap_offset. Note that eventually we should just move to using standard sdhci register access for the sdhci range with new offsets starting at 0x100. Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20211015104720.52240-4-tony@atomide.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 61 +++++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 16 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index a33b74238294..00a30681c857 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -21,9 +21,14 @@ #include "sdhci-pltfm.h" -#define SDHCI_OMAP_SYSCONFIG 0x110 +/* + * Note that the register offsets used here are from omap_regs + * base which is 0x100 for omap4 and later, and 0 for omap3 and + * earlier. + */ +#define SDHCI_OMAP_SYSCONFIG 0x10 -#define SDHCI_OMAP_CON 0x12c +#define SDHCI_OMAP_CON 0x2c #define CON_DW8 BIT(5) #define CON_DMA_MASTER BIT(20) #define CON_DDR BIT(19) @@ -33,20 +38,20 @@ #define CON_INIT BIT(1) #define CON_OD BIT(0) -#define SDHCI_OMAP_DLL 0x0134 +#define SDHCI_OMAP_DLL 0x34 #define DLL_SWT BIT(20) #define DLL_FORCE_SR_C_SHIFT 13 #define DLL_FORCE_SR_C_MASK (0x7f << DLL_FORCE_SR_C_SHIFT) #define DLL_FORCE_VALUE BIT(12) #define DLL_CALIB BIT(1) -#define SDHCI_OMAP_CMD 0x20c +#define SDHCI_OMAP_CMD 0x10c -#define SDHCI_OMAP_PSTATE 0x0224 +#define SDHCI_OMAP_PSTATE 0x124 #define PSTATE_DLEV_DAT0 BIT(20) #define PSTATE_DATI BIT(1) -#define SDHCI_OMAP_HCTL 0x228 +#define SDHCI_OMAP_HCTL 0x128 #define HCTL_SDBP BIT(8) #define HCTL_SDVS_SHIFT 9 #define HCTL_SDVS_MASK (0x7 << HCTL_SDVS_SHIFT) @@ -54,28 +59,28 @@ #define HCTL_SDVS_30 (0x6 << HCTL_SDVS_SHIFT) #define HCTL_SDVS_18 (0x5 << HCTL_SDVS_SHIFT) -#define SDHCI_OMAP_SYSCTL 0x22c +#define SDHCI_OMAP_SYSCTL 0x12c #define SYSCTL_CEN BIT(2) #define SYSCTL_CLKD_SHIFT 6 #define SYSCTL_CLKD_MASK 0x3ff -#define SDHCI_OMAP_STAT 0x230 +#define SDHCI_OMAP_STAT 0x130 -#define SDHCI_OMAP_IE 0x234 +#define SDHCI_OMAP_IE 0x134 #define INT_CC_EN BIT(0) -#define SDHCI_OMAP_ISE 0x238 +#define SDHCI_OMAP_ISE 0x138 -#define SDHCI_OMAP_AC12 0x23c +#define SDHCI_OMAP_AC12 0x13c #define AC12_V1V8_SIGEN BIT(19) #define AC12_SCLK_SEL BIT(23) -#define SDHCI_OMAP_CAPA 0x240 +#define SDHCI_OMAP_CAPA 0x140 #define CAPA_VS33 BIT(24) #define CAPA_VS30 BIT(25) #define CAPA_VS18 BIT(26) -#define SDHCI_OMAP_CAPA2 0x0244 +#define SDHCI_OMAP_CAPA2 0x144 #define CAPA2_TSDR50 BIT(13) #define SDHCI_OMAP_TIMEOUT 1 /* 1 msec */ @@ -93,7 +98,8 @@ #define SDHCI_OMAP_SPECIAL_RESET BIT(1) struct sdhci_omap_data { - u32 offset; + int omap_offset; /* Offset for omap regs from base */ + u32 offset; /* Offset for SDHCI regs from base */ u8 flags; }; @@ -112,6 +118,10 @@ struct sdhci_omap_host { struct pinctrl *pinctrl; struct pinctrl_state **pinctrl_state; bool is_tuning; + + /* Offset for omap specific registers from base */ + int omap_offset; + /* Omap specific context save */ u32 con; u32 hctl; @@ -127,13 +137,13 @@ static void sdhci_omap_stop_clock(struct sdhci_omap_host *omap_host); static inline u32 sdhci_omap_readl(struct sdhci_omap_host *host, unsigned int offset) { - return readl(host->base + offset); + return readl(host->base + host->omap_offset + offset); } static inline void sdhci_omap_writel(struct sdhci_omap_host *host, unsigned int offset, u32 data) { - writel(data, host->base + offset); + writel(data, host->base + host->omap_offset + offset); } static int sdhci_omap_set_pbias(struct sdhci_omap_host *omap_host, @@ -1009,36 +1019,54 @@ static const struct sdhci_pltfm_data sdhci_omap_pdata = { .ops = &sdhci_omap_ops, }; +static const struct sdhci_omap_data omap2430_data = { + .omap_offset = 0, + .offset = 0x100, +}; + +static const struct sdhci_omap_data omap3_data = { + .omap_offset = 0, + .offset = 0x100, +}; + static const struct sdhci_omap_data omap4_data = { + .omap_offset = 0x100, .offset = 0x200, .flags = SDHCI_OMAP_SPECIAL_RESET, }; static const struct sdhci_omap_data omap5_data = { + .omap_offset = 0x100, .offset = 0x200, .flags = SDHCI_OMAP_SPECIAL_RESET, }; static const struct sdhci_omap_data k2g_data = { + .omap_offset = 0x100, .offset = 0x200, }; static const struct sdhci_omap_data am335_data = { + .omap_offset = 0x100, .offset = 0x200, .flags = SDHCI_OMAP_SPECIAL_RESET, }; static const struct sdhci_omap_data am437_data = { + .omap_offset = 0x100, .offset = 0x200, .flags = SDHCI_OMAP_SPECIAL_RESET, }; static const struct sdhci_omap_data dra7_data = { + .omap_offset = 0x100, .offset = 0x200, .flags = SDHCI_OMAP_REQUIRE_IODELAY, }; static const struct of_device_id omap_sdhci_match[] = { + { .compatible = "ti,omap2430-sdhci", .data = &omap2430_data }, + { .compatible = "ti,omap3-sdhci", .data = &omap3_data }, { .compatible = "ti,omap4-sdhci", .data = &omap4_data }, { .compatible = "ti,omap5-sdhci", .data = &omap5_data }, { .compatible = "ti,dra7-sdhci", .data = &dra7_data }, @@ -1223,6 +1251,7 @@ static int sdhci_omap_probe(struct platform_device *pdev) omap_host->power_mode = MMC_POWER_UNDEFINED; omap_host->timing = MMC_TIMING_LEGACY; omap_host->flags = data->flags; + omap_host->omap_offset = data->omap_offset; host->ioaddr += offset; host->mapbase = regs->start + offset; -- cgit From f433e8aac6b94218394c6e7b80bb89e4e79c9549 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 15 Oct 2021 13:47:18 +0300 Subject: mmc: sdhci-omap: Implement PM runtime functions Implement PM runtime functions and enable autosuspend. Note that we save context in probe to avoid restoring invalid context on the first resume. For system suspend, we have the new PM runtime functions do most of the work. Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20211015104720.52240-5-tony@atomide.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 48 ++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 17 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 00a30681c857..cdfe85824195 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -1207,6 +1207,8 @@ static const struct soc_device_attribute sdhci_omap_soc_devices[] = { } }; +static void sdhci_omap_context_save(struct sdhci_omap_host *omap_host); + static int sdhci_omap_probe(struct platform_device *pdev) { int ret; @@ -1252,6 +1254,7 @@ static int sdhci_omap_probe(struct platform_device *pdev) omap_host->timing = MMC_TIMING_LEGACY; omap_host->flags = data->flags; omap_host->omap_offset = data->omap_offset; + omap_host->con = -EINVAL; /* Prevent invalid restore on first resume */ host->ioaddr += offset; host->mapbase = regs->start + offset; @@ -1302,6 +1305,8 @@ static int sdhci_omap_probe(struct platform_device *pdev) * SYSCONFIG register of omap devices. The callback will be invoked * as part of pm_runtime_get_sync. */ + pm_runtime_use_autosuspend(dev); + pm_runtime_set_autosuspend_delay(dev, 50); pm_runtime_enable(dev); ret = pm_runtime_resume_and_get(dev); if (ret) { @@ -1312,7 +1317,7 @@ static int sdhci_omap_probe(struct platform_device *pdev) ret = sdhci_omap_set_capabilities(host); if (ret) { dev_err(dev, "failed to set system capabilities\n"); - goto err_put_sync; + goto err_rpm_put; } host->mmc_host_ops.start_signal_voltage_switch = @@ -1340,7 +1345,7 @@ static int sdhci_omap_probe(struct platform_device *pdev) ret = sdhci_setup_host(host); if (ret) - goto err_put_sync; + goto err_rpm_put; ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host); if (ret) @@ -1350,15 +1355,19 @@ static int sdhci_omap_probe(struct platform_device *pdev) if (ret) goto err_cleanup_host; + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return 0; err_cleanup_host: sdhci_cleanup_host(host); -err_put_sync: - pm_runtime_put_sync(dev); - +err_rpm_put: + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); err_rpm_disable: + pm_runtime_dont_use_autosuspend(dev); pm_runtime_disable(dev); err_pltfm_free: @@ -1371,9 +1380,12 @@ static int sdhci_omap_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; struct sdhci_host *host = platform_get_drvdata(pdev); + pm_runtime_get_sync(dev); sdhci_remove_host(host, true); + pm_runtime_dont_use_autosuspend(dev); pm_runtime_put_sync(dev); - pm_runtime_disable(dev); + /* Ensure device gets disabled despite userspace sysfs config */ + pm_runtime_force_suspend(dev); sdhci_pltfm_free(pdev); return 0; @@ -1402,42 +1414,44 @@ static void sdhci_omap_context_restore(struct sdhci_omap_host *omap_host) sdhci_omap_writel(omap_host, SDHCI_OMAP_ISE, omap_host->ise); } -static int __maybe_unused sdhci_omap_suspend(struct device *dev) +static int __maybe_unused sdhci_omap_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); - sdhci_suspend_host(host); + sdhci_runtime_suspend_host(host); sdhci_omap_context_save(omap_host); pinctrl_pm_select_idle_state(dev); - pm_runtime_force_suspend(dev); - return 0; } -static int __maybe_unused sdhci_omap_resume(struct device *dev) +static int __maybe_unused sdhci_omap_runtime_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); - pm_runtime_force_resume(dev); - pinctrl_pm_select_default_state(dev); - sdhci_omap_context_restore(omap_host); + if (omap_host->con != -EINVAL) + sdhci_omap_context_restore(omap_host); - sdhci_resume_host(host); + sdhci_runtime_resume_host(host, 0); return 0; } #endif -static SIMPLE_DEV_PM_OPS(sdhci_omap_dev_pm_ops, sdhci_omap_suspend, - sdhci_omap_resume); + +static const struct dev_pm_ops sdhci_omap_dev_pm_ops = { + SET_RUNTIME_PM_OPS(sdhci_omap_runtime_suspend, + sdhci_omap_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; static struct platform_driver sdhci_omap_driver = { .probe = sdhci_omap_probe, -- cgit From 3edf588e7fe00e90d1dc7fb9e599861b2c2cf442 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 15 Oct 2021 13:47:19 +0300 Subject: mmc: sdhci-omap: Allow SDIO card power off and enable aggressive PM Allow powering off SDIO cards and enable runtime PM for eMMC/SD card devices. Without this, SDIO WLAN devices will not idle. Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20211015104720.52240-6-tony@atomide.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index cdfe85824195..660f4d4c27a4 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -1343,6 +1343,9 @@ static int sdhci_omap_probe(struct platform_device *pdev) /* R1B responses is required to properly manage HW busy detection. */ mmc->caps |= MMC_CAP_NEED_RSP_BUSY; + /* Allow card power off and runtime PM for eMMC/SD card devices */ + mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_AGGRESSIVE_PM; + ret = sdhci_setup_host(host); if (ret) goto err_rpm_put; -- cgit From a1e97bd2e0773fd8459f9f78ab923f69d5647571 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 15 Oct 2021 13:47:20 +0300 Subject: mmc: sdhci-omap: Configure optional wakeirq Configure optional wakeirq. This may be optionally configured for SDIO dat1 pin for wake-up events for SoCs that support deeper idle states. Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20211015104720.52240-7-tony@atomide.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 660f4d4c27a4..0dec2f849b81 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -12,8 +12,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -117,6 +119,7 @@ struct sdhci_omap_host { struct pinctrl *pinctrl; struct pinctrl_state **pinctrl_state; + int wakeirq; bool is_tuning; /* Offset for omap specific registers from base */ @@ -1358,6 +1361,25 @@ static int sdhci_omap_probe(struct platform_device *pdev) if (ret) goto err_cleanup_host; + /* + * SDIO devices can use the dat1 pin as a wake-up interrupt. Some + * devices like wl1xxx, use an out-of-band GPIO interrupt instead. + */ + omap_host->wakeirq = of_irq_get_byname(dev->of_node, "wakeup"); + if (omap_host->wakeirq == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_cleanup_host; + } + if (omap_host->wakeirq > 0) { + device_init_wakeup(dev, true); + ret = dev_pm_set_dedicated_wake_irq(dev, omap_host->wakeirq); + if (ret) { + device_init_wakeup(dev, false); + goto err_cleanup_host; + } + host->mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; + } + pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); @@ -1385,6 +1407,8 @@ static int sdhci_omap_remove(struct platform_device *pdev) pm_runtime_get_sync(dev); sdhci_remove_host(host, true); + device_init_wakeup(dev, false); + dev_pm_clear_wake_irq(dev); pm_runtime_dont_use_autosuspend(dev); pm_runtime_put_sync(dev); /* Ensure device gets disabled despite userspace sysfs config */ -- cgit From ce5f6c2c9b0fcb4094f8e162cfd37fb4294204f7 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 16 Oct 2021 08:21:44 +0200 Subject: mmc: mxs-mmc: disable regulator on error and in the remove function The 'reg_vmmc' regulator is enabled in the probe. It is never disabled. Neither in the error handling path of the probe nor in the remove function. Register a devm_action to disable it when needed. Fixes: 4dc5a79f1350 ("mmc: mxs-mmc: enable regulator for mmc slot") Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/4aadb3c97835f7b80f00819c3d549e6130384e67.1634365151.git.christophe.jaillet@wanadoo.fr Signed-off-by: Ulf Hansson --- drivers/mmc/host/mxs-mmc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 947581de7860..8c3655d3be96 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -552,6 +552,11 @@ static const struct of_device_id mxs_mmc_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, mxs_mmc_dt_ids); +static void mxs_mmc_regulator_disable(void *regulator) +{ + regulator_disable(regulator); +} + static int mxs_mmc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -591,6 +596,11 @@ static int mxs_mmc_probe(struct platform_device *pdev) "Failed to enable vmmc regulator: %d\n", ret); goto out_mmc_free; } + + ret = devm_add_action_or_reset(&pdev->dev, mxs_mmc_regulator_disable, + reg_vmmc); + if (ret) + goto out_mmc_free; } ssp->clk = devm_clk_get(&pdev->dev, NULL); -- cgit From b3e202fa0f9a20995eb8e1efbc0bf4a67616965e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 20 Oct 2021 10:39:02 +0200 Subject: mmc: sdhci-omap: Remove forward declaration of sdhci_omap_context_save() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If CONFIG_PM_SLEEP=n: drivers/mmc/host/sdhci-omap.c:1213:13: error: ‘sdhci_omap_context_save’ declared ‘static’ but never defined [-Werror=unused-function] 1213 | static void sdhci_omap_context_save(struct sdhci_omap_host *omap_host); | ^~~~~~~~~~~~~~~~~~~~~~~ The referenced commit added an unrelated forward declaration of sdhci_omap_context_save(), which is unneeded in general, and unused when CONFIG_PM_SLEEP=n. Fixes: f433e8aac6b94218 ("mmc: sdhci-omap: Implement PM runtime functions") Reported-by: noreply@ellerman.id.au Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20211020083902.3669769-1-geert@linux-m68k.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 0dec2f849b81..a4a1734dcb84 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -1210,8 +1210,6 @@ static const struct soc_device_attribute sdhci_omap_soc_devices[] = { } }; -static void sdhci_omap_context_save(struct sdhci_omap_host *omap_host); - static int sdhci_omap_probe(struct platform_device *pdev) { int ret; -- cgit From f85a15c5efe1d7d2c4e3ed069a3b8b7653cb6a0d Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 21 Oct 2021 16:43:52 +0300 Subject: mmc: sdhci-omap: Fix build if CONFIG_PM_SLEEP is not set Commit f433e8aac6b9 ("mmc: sdhci-omap: Implement PM runtime functions") combined the use of runtime PM and system suspend functions but left the ifdef CONFIG_PM_SLEEP in place causing undeclared identifier error for sdhci_omap_runtime_suspend if CONFIG_PM_SLEEP is not enabled. Let's fix the error by removing ifdef CONFIG_PM_SLEEP and tagging the reset of the PM related functions with __maybe_unused. Let's also remove the forward declaration for sdhci_omap_context_save(), that was accidentally left from an earlier version and is no longer used. Reported-by: kernel test robot Signed-off-by: Tony Lindgren [Ulf: Rebased and fixed build error] Link: https://lore.kernel.org/r/20211021134352.10135-1-tony@atomide.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index a4a1734dcb84..64e27c2821f9 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -1415,8 +1415,9 @@ static int sdhci_omap_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static void sdhci_omap_context_save(struct sdhci_omap_host *omap_host) + +#ifdef CONFIG_PM +static void __maybe_unused sdhci_omap_context_save(struct sdhci_omap_host *omap_host) { omap_host->con = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); omap_host->hctl = sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL); @@ -1427,7 +1428,7 @@ static void sdhci_omap_context_save(struct sdhci_omap_host *omap_host) } /* Order matters here, HCTL must be restored in two phases */ -static void sdhci_omap_context_restore(struct sdhci_omap_host *omap_host) +static void __maybe_unused sdhci_omap_context_restore(struct sdhci_omap_host *omap_host) { sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, omap_host->hctl); sdhci_omap_writel(omap_host, SDHCI_OMAP_CAPA, omap_host->capa); -- cgit From 61840edc88138cb7e274ac530aeec6de36fbf386 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 20 Oct 2021 12:29:07 +0200 Subject: mmc: dw_mmc: Drop use of ->init_card() callback For dw_mmc, the ->init_card() callback is being used to turn on/off automatic internal clock gating for powersave, which is needed to properly support SDIO irqs on DAT1. However, using the ->init_card() comes with a drawback in this case, as it means that the powersave feature becomes disabled, no matter whether the SDIO irqs becomes turned on or not. To improve the behaviour, let's change into using the ->enable_sdio_irq() callback instead. This works fine, because dw_mmc uses sdio_signal_irq() to signal the irqs, thus the ->enable_sdio_irq() is never executed from within atomic context. Signed-off-by: Ulf Hansson Reviewed-by: Douglas Anderson Link: https://lore.kernel.org/r/20211020102907.70195-1-ulf.hansson@linaro.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 1e8f1bb3cad7..d977f34f6b55 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1611,37 +1611,32 @@ static void dw_mci_hw_reset(struct mmc_host *mmc) usleep_range(200, 300); } -static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) +static void dw_mci_prepare_sdio_irq(struct dw_mci_slot *slot, bool prepare) { - struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci *host = slot->host; + const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; + u32 clk_en_a_old; + u32 clk_en_a; /* * Low power mode will stop the card clock when idle. According to the * description of the CLKENA register we should disable low power mode * for SDIO cards if we need SDIO interrupts to work. */ - if (mmc->caps & MMC_CAP_SDIO_IRQ) { - const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; - u32 clk_en_a_old; - u32 clk_en_a; - clk_en_a_old = mci_readl(host, CLKENA); - - if (card->type == MMC_TYPE_SDIO || - card->type == MMC_TYPE_SD_COMBO) { - set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); - clk_en_a = clk_en_a_old & ~clken_low_pwr; - } else { - clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); - clk_en_a = clk_en_a_old | clken_low_pwr; - } + clk_en_a_old = mci_readl(host, CLKENA); + if (prepare) { + set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); + clk_en_a = clk_en_a_old & ~clken_low_pwr; + } else { + clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); + clk_en_a = clk_en_a_old | clken_low_pwr; + } - if (clk_en_a != clk_en_a_old) { - mci_writel(host, CLKENA, clk_en_a); - mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | - SDMMC_CMD_PRV_DAT_WAIT, 0); - } + if (clk_en_a != clk_en_a_old) { + mci_writel(host, CLKENA, clk_en_a); + mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, + 0); } } @@ -1669,6 +1664,7 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci *host = slot->host; + dw_mci_prepare_sdio_irq(slot, enb); __dw_mci_enable_sdio_irq(slot, enb); /* Avoid runtime suspending the device when SDIO IRQ is enabled */ @@ -1790,7 +1786,6 @@ static const struct mmc_host_ops dw_mci_ops = { .execute_tuning = dw_mci_execute_tuning, .card_busy = dw_mci_card_busy, .start_signal_voltage_switch = dw_mci_switch_voltage, - .init_card = dw_mci_init_card, .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning, }; -- cgit From 5c4f00627c9a881bacfd55ae9f2cd01ff33d4a9a Mon Sep 17 00:00:00 2001 From: Chester Lin Date: Thu, 21 Oct 2021 15:13:32 +0800 Subject: mmc: sdhci-esdhc-imx: add NXP S32G2 support Support the SDHCI controller found on NXP S32G2 platform. The new flag ESDHC_FLAG_SKIP_ERR004536 is used because the hardware erratum bit is not applicable for S32G2. Signed-off-by: Chester Lin Link: https://lore.kernel.org/r/20211021071333.32485-3-clin@suse.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index e658f0174242..afaf33707d46 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -196,6 +196,9 @@ */ #define ESDHC_FLAG_BROKEN_AUTO_CMD23 BIT(16) +/* ERR004536 is not applicable for the IP */ +#define ESDHC_FLAG_SKIP_ERR004536 BIT(17) + enum wp_types { ESDHC_WP_NONE, /* no WP, neither controller nor gpio */ ESDHC_WP_CONTROLLER, /* mmc controller internal WP */ @@ -289,6 +292,13 @@ static const struct esdhc_soc_data usdhc_imx7d_data = { | ESDHC_FLAG_BROKEN_AUTO_CMD23, }; +static struct esdhc_soc_data usdhc_s32g2_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 + | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES + | ESDHC_FLAG_SKIP_ERR004536, +}; + static struct esdhc_soc_data usdhc_imx7ulp_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 @@ -347,6 +357,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { { .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, }, { .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, }, { .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx8mm_data, }, + { .compatible = "nxp,s32g2-usdhc", .data = &usdhc_s32g2_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); @@ -1375,8 +1386,10 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) * erratum ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL * TO1.1, it's harmless for MX6SL */ - writel(readl(host->ioaddr + 0x6c) & ~BIT(7), - host->ioaddr + 0x6c); + if (!(imx_data->socdata->flags & ESDHC_FLAG_SKIP_ERR004536)) { + writel(readl(host->ioaddr + 0x6c) & ~BIT(7), + host->ioaddr + 0x6c); + } /* disable DLL_CTRL delay line settings */ writel(0x0, host->ioaddr + ESDHC_DLL_CTRL); -- cgit From c3ed02845e9f99229bb65446100e7c875d018f69 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 27 Oct 2021 14:08:12 +0100 Subject: mmc: dw_mmc: exynos: Fix spelling mistake "candiates" -> candidates There are several spelling mistakes in variable names and in a dev_warn message. Fix these. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20211027130812.426373-1-colin.i.king@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-exynos.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 1f8a3c0ddfe1..c2dd29ef45c6 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -442,14 +442,14 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) return sample; } -static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates) +static s8 dw_mci_exynos_get_best_clksmpl(u8 candidates) { const u8 iter = 8; u8 __c; s8 i, loc = -1; for (i = 0; i < iter; i++) { - __c = ror8(candiates, i); + __c = ror8(candidates, i); if ((__c & 0xc7) == 0xc7) { loc = i; goto out; @@ -457,7 +457,7 @@ static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates) } for (i = 0; i < iter; i++) { - __c = ror8(candiates, i); + __c = ror8(candidates, i); if ((__c & 0x83) == 0x83) { loc = i; goto out; @@ -466,11 +466,11 @@ static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates) /* * If there is no cadiates value, then it needs to return -EIO. - * If there are candiates values and don't find bset clk sample value, - * then use a first candiates clock sample value. + * If there are candidates values and don't find bset clk sample value, + * then use a first candidates clock sample value. */ for (i = 0; i < iter; i++) { - __c = ror8(candiates, i); + __c = ror8(candidates, i); if ((__c & 0x1) == 0x1) { loc = i; goto out; @@ -485,7 +485,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode) struct dw_mci *host = slot->host; struct dw_mci_exynos_priv_data *priv = host->priv; struct mmc_host *mmc = slot->mmc; - u8 start_smpl, smpl, candiates = 0; + u8 start_smpl, smpl, candidates = 0; s8 found; int ret = 0; @@ -496,18 +496,18 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode) smpl = dw_mci_exynos_move_next_clksmpl(host); if (!mmc_send_tuning(mmc, opcode, NULL)) - candiates |= (1 << smpl); + candidates |= (1 << smpl); } while (start_smpl != smpl); - found = dw_mci_exynos_get_best_clksmpl(candiates); + found = dw_mci_exynos_get_best_clksmpl(candidates); if (found >= 0) { dw_mci_exynos_set_clksmpl(host, found); priv->tuned_sample = found; } else { ret = -EIO; dev_warn(&mmc->class_dev, - "There is no candiates value about clksmpl!\n"); + "There is no candidates value about clksmpl!\n"); } return ret; -- cgit