From 541a95e64d7606ead18a4e8aa78c753a2494cae0 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Thu, 31 Aug 2023 11:26:47 +0800 Subject: mmc: sdhci-esdhc-imx: optimize the manual tuing logic to get the best timing Current manual tuning logic only get the first pass window, but this pass window maybe not the best pass window. Now find all the pass window, and chose the largest pass window, and use the average value of this largest pass window to get the best timing. Signed-off-by: Haibo Chen Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20230831032647.3128702-1-haibo.chen@nxp.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 52 ++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 3b8030f3552a..40a6e2f8145a 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -1154,32 +1154,52 @@ static void esdhc_post_tuning(struct sdhci_host *host) writel(reg, host->ioaddr + ESDHC_MIX_CTRL); } +/* + * find the largest pass window, and use the average delay of this + * largest window to get the best timing. + */ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) { int min, max, avg, ret; + int win_length, target_min, target_max, target_win_length; - /* find the mininum delay first which can pass tuning */ min = ESDHC_TUNE_CTRL_MIN; - while (min < ESDHC_TUNE_CTRL_MAX) { - esdhc_prepare_tuning(host, min); - if (!mmc_send_tuning(host->mmc, opcode, NULL)) - break; - min += ESDHC_TUNE_CTRL_STEP; - } - - /* find the maxinum delay which can not pass tuning */ - max = min + ESDHC_TUNE_CTRL_STEP; + max = ESDHC_TUNE_CTRL_MIN; + target_win_length = 0; while (max < ESDHC_TUNE_CTRL_MAX) { - esdhc_prepare_tuning(host, max); - if (mmc_send_tuning(host->mmc, opcode, NULL)) { - max -= ESDHC_TUNE_CTRL_STEP; - break; + /* find the mininum delay first which can pass tuning */ + while (min < ESDHC_TUNE_CTRL_MAX) { + esdhc_prepare_tuning(host, min); + if (!mmc_send_tuning(host->mmc, opcode, NULL)) + break; + min += ESDHC_TUNE_CTRL_STEP; } - max += ESDHC_TUNE_CTRL_STEP; + + /* find the maxinum delay which can not pass tuning */ + max = min + ESDHC_TUNE_CTRL_STEP; + while (max < ESDHC_TUNE_CTRL_MAX) { + esdhc_prepare_tuning(host, max); + if (mmc_send_tuning(host->mmc, opcode, NULL)) { + max -= ESDHC_TUNE_CTRL_STEP; + break; + } + max += ESDHC_TUNE_CTRL_STEP; + } + + win_length = max - min + 1; + /* get the largest pass window */ + if (win_length > target_win_length) { + target_win_length = win_length; + target_min = min; + target_max = max; + } + + /* continue to find the next pass window */ + min = max + ESDHC_TUNE_CTRL_STEP; } /* use average delay to get the best timing */ - avg = (min + max) / 2; + avg = (target_min + target_max) / 2; esdhc_prepare_tuning(host, avg); ret = mmc_send_tuning(host->mmc, opcode, NULL); esdhc_post_tuning(host); -- cgit v1.2.3-70-g09d2 From bbe6dc429bf52b0062c2a9b39f850cfd317289a7 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 1 Sep 2023 13:27:01 +0100 Subject: mmc: host: Kconfig: Make MMC_SDHI_INTERNAL_DMAC config option dependant on ARCH_RENESAS MMC_SDHI_INTERNAL_DMAC config option has dependency on ARM64 and R7S9210/R8A77470 this dependency will keep growing for future SoCs for varying architectures. So to simplify this configuration make MMC_SDHI_INTERNAL_DMAC solely depend on ARCH_RENESAS, as all Renesas SoCs inherently depend on the ARCH_RENESAS config option. This allows selecting MMC_SDHI_INTERNAL_DMAC config option for RZ/Five SoC which is based on RISC-V architecture. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Acked-by: Wolfram Sang Link: https://lore.kernel.org/r/20230901122701.318082-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 554e67103c1a..2e8476db2381 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -677,9 +677,9 @@ config MMC_SDHI_SYS_DMAC config MMC_SDHI_INTERNAL_DMAC tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering" - depends on ARM64 || ARCH_R7S9210 || ARCH_R8A77470 || COMPILE_TEST + depends on ARCH_RENESAS || COMPILE_TEST depends on MMC_SDHI - default MMC_SDHI if (ARM64 || ARCH_R7S9210 || ARCH_R8A77470) + default MMC_SDHI if ARCH_RENESAS help This provides DMA support for SDHI SD/SDIO controllers using on-chip bus mastering. This supports the controllers -- cgit v1.2.3-70-g09d2 From 134d3cfbb8658eb9600a6db689d0b47d24d96fbe Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 7 Sep 2023 11:55:15 +0200 Subject: mmc: atmel-mci: add missing of_node_put for_each_child_of_node performs an of_node_get on each iteration, so a break out of the loop requires an of_node_put. This was done using the Coccinelle semantic patch iterators/for_each_child.cocci Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20230907095521.14053-6-Julia.Lawall@inria.fr Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 535783c43105..14401a599fe6 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -674,8 +674,10 @@ atmci_of_init(struct platform_device *pdev) "cd", GPIOD_IN, "cd-gpios"); err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].detect_pin); if (err) { - if (err != -ENOENT) + if (err != -ENOENT) { + of_node_put(cnp); return ERR_PTR(err); + } pdata->slot[slot_id].detect_pin = NULL; } @@ -687,8 +689,10 @@ atmci_of_init(struct platform_device *pdev) "wp", GPIOD_IN, "wp-gpios"); err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].wp_pin); if (err) { - if (err != -ENOENT) + if (err != -ENOENT) { + of_node_put(cnp); return ERR_PTR(err); + } pdata->slot[slot_id].wp_pin = NULL; } } -- cgit v1.2.3-70-g09d2 From 6f39adf955d8767c78fba94cf9abe989e0d1e111 Mon Sep 17 00:00:00 2001 From: Balamanikandan Gunasundar Date: Mon, 11 Sep 2023 14:55:40 +0530 Subject: mmc: atmel-mci: Add description for struct member Add description for dma filtering function in struct mci_platform_data. Fixes the warning: Function parameter or member 'dma_filter' not described in 'mci_platform_data'. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202309020937.C5S2sRnr-lkp@intel.com/ Signed-off-by: Balamanikandan Gunasundar Link: https://lore.kernel.org/r/20230911092540.76334-1-balamanikandan.gunasundar@microchip.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 14401a599fe6..dba826db739a 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -227,6 +227,7 @@ struct mci_slot_pdata { /** * struct mci_platform_data - board-specific MMC/SDcard configuration * @dma_slave: DMA slave interface to use in data transfers. + * @dma_filter: Filtering function to filter the DMA channel * @slot: Per-slot configuration data. */ struct mci_platform_data { -- cgit v1.2.3-70-g09d2 From d7133797e9e1b72fd89237f68cb36d745599ed86 Mon Sep 17 00:00:00 2001 From: Victor Shih Date: Tue, 12 Sep 2023 17:17:10 +0800 Subject: mmc: sdhci-pci-gli: A workaround to allow GL9750 to enter ASPM L1.2 When GL9750 enters ASPM L1 sub-states, it will stay at L1.1 and will not enter L1.2. The workaround is to toggle PM state to allow GL9750 to enter ASPM L1.2. Signed-off-by: Victor Shih Link: https://lore.kernel.org/r/20230912091710.7797-1-victorshihgli@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-gli.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index ae8c307b7aa7..dd6f09024f08 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -25,6 +25,9 @@ #define GLI_9750_WT_EN_ON 0x1 #define GLI_9750_WT_EN_OFF 0x0 +#define PCI_GLI_9750_PM_CTRL 0xFC +#define PCI_GLI_9750_PM_STATE GENMASK(1, 0) + #define SDHCI_GLI_9750_CFG2 0x848 #define SDHCI_GLI_9750_CFG2_L1DLY GENMASK(28, 24) #define GLI_9750_CFG2_L1DLY_VALUE 0x1F @@ -536,8 +539,12 @@ static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock) static void gl9750_hw_setting(struct sdhci_host *host) { + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct pci_dev *pdev; u32 value; + pdev = slot->chip->pdev; + gl9750_wt_on(host); value = sdhci_readl(host, SDHCI_GLI_9750_CFG2); @@ -547,6 +554,13 @@ static void gl9750_hw_setting(struct sdhci_host *host) GLI_9750_CFG2_L1DLY_VALUE); sdhci_writel(host, value, SDHCI_GLI_9750_CFG2); + /* toggle PM state to allow GL9750 to enter ASPM L1.2 */ + pci_read_config_dword(pdev, PCI_GLI_9750_PM_CTRL, &value); + value |= PCI_GLI_9750_PM_STATE; + pci_write_config_dword(pdev, PCI_GLI_9750_PM_CTRL, value); + value &= ~PCI_GLI_9750_PM_STATE; + pci_write_config_dword(pdev, PCI_GLI_9750_PM_CTRL, value); + gl9750_wt_off(host); } -- cgit v1.2.3-70-g09d2 From 2e2b547950bc09e75afe912f9683be39c2195d9d Mon Sep 17 00:00:00 2001 From: Wenchao Chen Date: Tue, 19 Sep 2023 15:47:06 +0800 Subject: mmc: core: Allow dynamical updates of the number of requests for hsq To allow dynamical updates of the current number of used in-flight requests, let's move away from using a hard-coded value to a use a corresponding variable in the struct mmc_host. This can be valuable when optimizing for certain I/O request sequences, as shown by subsequent changes. Signed-off-by: Wenchao Chen Link: https://lore.kernel.org/r/20230919074707.25517-2-wenchao.chen@unisoc.com [Ulf: Re-wrote the commitmsg to clarify the change] Signed-off-by: Ulf Hansson --- drivers/mmc/core/queue.c | 6 +----- drivers/mmc/host/mmc_hsq.c | 1 + drivers/mmc/host/mmc_hsq.h | 6 ++++++ include/linux/mmc/host.h | 1 + 4 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index b396e3900717..a0a2412f62a7 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -260,11 +260,7 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, } break; case MMC_ISSUE_ASYNC: - /* - * For MMC host software queue, we only allow 2 requests in - * flight to avoid a long latency. - */ - if (host->hsq_enabled && mq->in_flight[issue_type] > 2) { + if (host->hsq_enabled && mq->in_flight[issue_type] > host->hsq_depth) { spin_unlock_irq(&mq->lock); return BLK_STS_RESOURCE; } diff --git a/drivers/mmc/host/mmc_hsq.c b/drivers/mmc/host/mmc_hsq.c index 424dc7b07858..8556cacb21a1 100644 --- a/drivers/mmc/host/mmc_hsq.c +++ b/drivers/mmc/host/mmc_hsq.c @@ -337,6 +337,7 @@ int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc) hsq->mmc = mmc; hsq->mmc->cqe_private = hsq; mmc->cqe_ops = &mmc_hsq_ops; + mmc->hsq_depth = HSQ_NORMAL_DEPTH; for (i = 0; i < HSQ_NUM_SLOTS; i++) hsq->tag_slot[i] = HSQ_INVALID_TAG; diff --git a/drivers/mmc/host/mmc_hsq.h b/drivers/mmc/host/mmc_hsq.h index 1808024fc6c5..aa5c4543b55f 100644 --- a/drivers/mmc/host/mmc_hsq.h +++ b/drivers/mmc/host/mmc_hsq.h @@ -5,6 +5,12 @@ #define HSQ_NUM_SLOTS 64 #define HSQ_INVALID_TAG HSQ_NUM_SLOTS +/* + * For MMC host software queue, we only allow 2 requests in + * flight to avoid a long latency. + */ +#define HSQ_NORMAL_DEPTH 2 + struct hsq_slot { struct mmc_request *mrq; }; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 62a6847a3b6f..2f445c651742 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -526,6 +526,7 @@ struct mmc_host { /* Host Software Queue support */ bool hsq_enabled; + int hsq_depth; u32 err_stats[MMC_ERR_MAX]; unsigned long private[] ____cacheline_aligned; -- cgit v1.2.3-70-g09d2 From 68df98c48398e68e7f187b5ee92fb2576d6fd7d1 Mon Sep 17 00:00:00 2001 From: Wenchao Chen Date: Tue, 19 Sep 2023 15:47:07 +0800 Subject: mmc: hsq: Improve random I/O write performance for 4k buffers By dynamically adjusting the host->hsq_depth, based upon the buffer size being 4k and that we get at least two I/O write requests in flight, we can improve the throughput a bit. This is typical for a random I/O write pattern. More precisely, by dynamically changing the number of requests in flight from 2 to 5, we can on some platforms observe ~4-5% increase in throughput. Signed-off-by: Wenchao Chen Link: https://lore.kernel.org/r/20230919074707.25517-3-wenchao.chen@unisoc.com [Ulf: Re-wrote the commitmsg, minor adjustment to the code - all to clarify.] Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmc_hsq.c | 21 +++++++++++++++++++++ drivers/mmc/host/mmc_hsq.h | 5 +++++ 2 files changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/mmc_hsq.c b/drivers/mmc/host/mmc_hsq.c index 8556cacb21a1..79836705c176 100644 --- a/drivers/mmc/host/mmc_hsq.c +++ b/drivers/mmc/host/mmc_hsq.c @@ -21,6 +21,25 @@ static void mmc_hsq_retry_handler(struct work_struct *work) mmc->ops->request(mmc, hsq->mrq); } +static void mmc_hsq_modify_threshold(struct mmc_hsq *hsq) +{ + struct mmc_host *mmc = hsq->mmc; + struct mmc_request *mrq; + unsigned int tag, need_change = 0; + + mmc->hsq_depth = HSQ_NORMAL_DEPTH; + for (tag = 0; tag < HSQ_NUM_SLOTS; tag++) { + mrq = hsq->slot[tag].mrq; + if (mrq && mrq->data && + (mrq->data->blksz * mrq->data->blocks == 4096) && + (mrq->data->flags & MMC_DATA_WRITE) && + (++need_change == 2)) { + mmc->hsq_depth = HSQ_PERFORMANCE_DEPTH; + break; + } + } +} + static void mmc_hsq_pump_requests(struct mmc_hsq *hsq) { struct mmc_host *mmc = hsq->mmc; @@ -42,6 +61,8 @@ static void mmc_hsq_pump_requests(struct mmc_hsq *hsq) return; } + mmc_hsq_modify_threshold(hsq); + slot = &hsq->slot[hsq->next_tag]; hsq->mrq = slot->mrq; hsq->qcnt--; diff --git a/drivers/mmc/host/mmc_hsq.h b/drivers/mmc/host/mmc_hsq.h index aa5c4543b55f..dd352a6ac32a 100644 --- a/drivers/mmc/host/mmc_hsq.h +++ b/drivers/mmc/host/mmc_hsq.h @@ -10,6 +10,11 @@ * flight to avoid a long latency. */ #define HSQ_NORMAL_DEPTH 2 +/* + * For 4k random writes, we allow hsq_depth to increase to 5 + * for better performance. + */ +#define HSQ_PERFORMANCE_DEPTH 5 struct hsq_slot { struct mmc_request *mrq; -- cgit v1.2.3-70-g09d2 From c8b850f0f021c15594a1543b7f5d629e45f9150a Mon Sep 17 00:00:00 2001 From: William Qiu Date: Fri, 22 Sep 2023 14:28:33 +0800 Subject: mmc: starfive: Change tuning implementation Before, we used syscon to achieve tuning, but the actual measurement showed little effect, so the tuning implementation was modified here, and it was realized by reading and writing the UHS_REG_EXT register. Signed-off-by: William Qiu Reviewed-by: Emil Renner Berthing Link: https://lore.kernel.org/r/20230922062834.39212-3-william.qiu@starfivetech.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-starfive.c | 137 +++++++++++-------------------------- 1 file changed, 40 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc-starfive.c b/drivers/mmc/host/dw_mmc-starfive.c index fd05a648a8bb..b4d81ef0f3af 100644 --- a/drivers/mmc/host/dw_mmc-starfive.c +++ b/drivers/mmc/host/dw_mmc-starfive.c @@ -5,6 +5,7 @@ * Copyright (c) 2022 StarFive Technology Co., Ltd. */ +#include #include #include #include @@ -20,13 +21,7 @@ #define ALL_INT_CLR 0x1ffff #define MAX_DELAY_CHAIN 32 -struct starfive_priv { - struct device *dev; - struct regmap *reg_syscon; - u32 syscon_offset; - u32 syscon_shift; - u32 syscon_mask; -}; +#define STARFIVE_SMPL_PHASE GENMASK(20, 16) static void dw_mci_starfive_set_ios(struct dw_mci *host, struct mmc_ios *ios) { @@ -44,117 +39,65 @@ static void dw_mci_starfive_set_ios(struct dw_mci *host, struct mmc_ios *ios) } } +static void dw_mci_starfive_set_sample_phase(struct dw_mci *host, u32 smpl_phase) +{ + /* change driver phase and sample phase */ + u32 reg_value = mci_readl(host, UHS_REG_EXT); + + /* In UHS_REG_EXT, only 5 bits valid in DRV_PHASE and SMPL_PHASE */ + reg_value &= ~STARFIVE_SMPL_PHASE; + reg_value |= FIELD_PREP(STARFIVE_SMPL_PHASE, smpl_phase); + mci_writel(host, UHS_REG_EXT, reg_value); + + /* We should delay 1ms wait for timing setting finished. */ + mdelay(1); +} + static int dw_mci_starfive_execute_tuning(struct dw_mci_slot *slot, u32 opcode) { static const int grade = MAX_DELAY_CHAIN; struct dw_mci *host = slot->host; - struct starfive_priv *priv = host->priv; - int rise_point = -1, fall_point = -1; - int err, prev_err = 0; - int i; - bool found = 0; - u32 regval; - - /* - * Use grade as the max delay chain, and use the rise_point and - * fall_point to ensure the best sampling point of a data input - * signals. - */ - for (i = 0; i < grade; i++) { - regval = i << priv->syscon_shift; - err = regmap_update_bits(priv->reg_syscon, priv->syscon_offset, - priv->syscon_mask, regval); - if (err) - return err; + int smpl_phase, smpl_raise = -1, smpl_fall = -1; + int ret; + + for (smpl_phase = 0; smpl_phase < grade; smpl_phase++) { + dw_mci_starfive_set_sample_phase(host, smpl_phase); mci_writel(host, RINTSTS, ALL_INT_CLR); - err = mmc_send_tuning(slot->mmc, opcode, NULL); - if (!err) - found = 1; + ret = mmc_send_tuning(slot->mmc, opcode, NULL); - if (i > 0) { - if (err && !prev_err) - fall_point = i - 1; - if (!err && prev_err) - rise_point = i; + if (!ret && smpl_raise < 0) { + smpl_raise = smpl_phase; + } else if (ret && smpl_raise >= 0) { + smpl_fall = smpl_phase - 1; + break; } - - if (rise_point != -1 && fall_point != -1) - goto tuning_out; - - prev_err = err; - err = 0; } -tuning_out: - if (found) { - if (rise_point == -1) - rise_point = 0; - if (fall_point == -1) - fall_point = grade - 1; - if (fall_point < rise_point) { - if ((rise_point + fall_point) > - (grade - 1)) - i = fall_point / 2; - else - i = (rise_point + grade - 1) / 2; - } else { - i = (rise_point + fall_point) / 2; - } - - regval = i << priv->syscon_shift; - err = regmap_update_bits(priv->reg_syscon, priv->syscon_offset, - priv->syscon_mask, regval); - if (err) - return err; - mci_writel(host, RINTSTS, ALL_INT_CLR); + if (smpl_phase >= grade) + smpl_fall = grade - 1; - dev_info(host->dev, "Found valid delay chain! use it [delay=%d]\n", i); - } else { + if (smpl_raise < 0) { + smpl_phase = 0; dev_err(host->dev, "No valid delay chain! use default\n"); - err = -EINVAL; + ret = -EINVAL; + goto out; } - mci_writel(host, RINTSTS, ALL_INT_CLR); - return err; -} - -static int dw_mci_starfive_parse_dt(struct dw_mci *host) -{ - struct of_phandle_args args; - struct starfive_priv *priv; - int ret; - - priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + smpl_phase = (smpl_raise + smpl_fall) / 2; + dev_dbg(host->dev, "Found valid delay chain! use it [delay=%d]\n", smpl_phase); + ret = 0; - ret = of_parse_phandle_with_fixed_args(host->dev->of_node, - "starfive,sysreg", 3, 0, &args); - if (ret) { - dev_err(host->dev, "Failed to parse starfive,sysreg\n"); - return -EINVAL; - } - - priv->reg_syscon = syscon_node_to_regmap(args.np); - of_node_put(args.np); - if (IS_ERR(priv->reg_syscon)) - return PTR_ERR(priv->reg_syscon); - - priv->syscon_offset = args.args[0]; - priv->syscon_shift = args.args[1]; - priv->syscon_mask = args.args[2]; - - host->priv = priv; - - return 0; +out: + dw_mci_starfive_set_sample_phase(host, smpl_phase); + mci_writel(host, RINTSTS, ALL_INT_CLR); + return ret; } static const struct dw_mci_drv_data starfive_data = { .common_caps = MMC_CAP_CMD23, .set_ios = dw_mci_starfive_set_ios, - .parse_dt = dw_mci_starfive_parse_dt, .execute_tuning = dw_mci_starfive_execute_tuning, }; -- cgit v1.2.3-70-g09d2 From 45492b13453f9862abff6f9d7af5e8116849a9c9 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:52:50 -0700 Subject: memstick: jmb38x_ms: Annotate struct jmb38x_ms with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct jmb38x_ms. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Maxim Levitsky Cc: Alex Dubov Cc: Ulf Hansson Cc: Tom Rix Cc: Len Baker Cc: Dan Carpenter Cc: "Gustavo A. R. Silva" Cc: linux-mmc@vger.kernel.org Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20230922175249.work.593-kees@kernel.org Signed-off-by: Ulf Hansson --- drivers/memstick/host/jmb38x_ms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index 21cb2a786058..e77eb8b0eb12 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -66,7 +66,7 @@ struct jmb38x_ms_host { struct jmb38x_ms { struct pci_dev *pdev; int host_cnt; - struct memstick_host *hosts[]; + struct memstick_host *hosts[] __counted_by(host_cnt); }; #define BLOCK_COUNT_MASK 0xffff0000 -- cgit v1.2.3-70-g09d2 From 4b9b94766534ea23bffc8606b73fb18501b49a67 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Wed, 27 Sep 2023 06:41:37 +0000 Subject: mmc: vub300: replace deprecated strncpy with strscpy `strncpy` is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect `vub300->vub_name` to be NUL-terminated based on its uses with format strings: | dev_info(&vub300->udev->dev, "using %s for SDIO offload processing\n", | vub300->vub_name); NUL-padding is not needed. We can see cleaning out vub_name simply consists of: | vub300->vub_name[0] = 0; Considering the above, for all 11 cases a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. To be clear, there is no existing bug in the current implementation as the string literals are all small enough as to not cause a buffer overread. Nonetheless, this gets us 11 steps closer to removing strncpy uses. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20230927-strncpy-drivers-mmc-host-vub300-c-v1-1-77426f62eef4@google.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/vub300.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index 9ec593d52f0f..de3f443f5fdc 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -512,7 +512,7 @@ static void new_system_port_status(struct vub300_mmc_host *vub300) vub300->card_present = 1; vub300->bus_width = 0; if (disable_offload_processing) - strncpy(vub300->vub_name, "EMPTY Processing Disabled", + strscpy(vub300->vub_name, "EMPTY Processing Disabled", sizeof(vub300->vub_name)); else vub300->vub_name[0] = 0; @@ -1216,7 +1216,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, dev_err(&vub300->udev->dev, "corrupt offload pseudocode in firmware %s\n", vub300->vub_name); - strncpy(vub300->vub_name, "corrupt offload pseudocode", + strscpy(vub300->vub_name, "corrupt offload pseudocode", sizeof(vub300->vub_name)); return; } @@ -1250,7 +1250,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, "not enough memory for xfer buffer to send" " INTERRUPT_PSEUDOCODE for %s %s\n", fw->data, vub300->vub_name); - strncpy(vub300->vub_name, + strscpy(vub300->vub_name, "SDIO interrupt pseudocode download failed", sizeof(vub300->vub_name)); return; @@ -1259,7 +1259,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, dev_err(&vub300->udev->dev, "corrupt interrupt pseudocode in firmware %s %s\n", fw->data, vub300->vub_name); - strncpy(vub300->vub_name, "corrupt interrupt pseudocode", + strscpy(vub300->vub_name, "corrupt interrupt pseudocode", sizeof(vub300->vub_name)); return; } @@ -1293,7 +1293,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, "not enough memory for xfer buffer to send" " TRANSFER_PSEUDOCODE for %s %s\n", fw->data, vub300->vub_name); - strncpy(vub300->vub_name, + strscpy(vub300->vub_name, "SDIO transfer pseudocode download failed", sizeof(vub300->vub_name)); return; @@ -1302,7 +1302,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, dev_err(&vub300->udev->dev, "corrupt transfer pseudocode in firmware %s %s\n", fw->data, vub300->vub_name); - strncpy(vub300->vub_name, "corrupt transfer pseudocode", + strscpy(vub300->vub_name, "corrupt transfer pseudocode", sizeof(vub300->vub_name)); return; } @@ -1336,13 +1336,13 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, dev_err(&vub300->udev->dev, "corrupt dynamic registers in firmware %s\n", vub300->vub_name); - strncpy(vub300->vub_name, "corrupt dynamic registers", + strscpy(vub300->vub_name, "corrupt dynamic registers", sizeof(vub300->vub_name)); return; } copy_error_message: - strncpy(vub300->vub_name, "SDIO pseudocode download failed", + strscpy(vub300->vub_name, "SDIO pseudocode download failed", sizeof(vub300->vub_name)); } @@ -1370,11 +1370,11 @@ static void download_offload_pseudocode(struct vub300_mmc_host *vub300) vub300->vub_name); retval = request_firmware(&fw, vub300->vub_name, &card->dev); if (retval < 0) { - strncpy(vub300->vub_name, "vub_default.bin", + strscpy(vub300->vub_name, "vub_default.bin", sizeof(vub300->vub_name)); retval = request_firmware(&fw, vub300->vub_name, &card->dev); if (retval < 0) { - strncpy(vub300->vub_name, + strscpy(vub300->vub_name, "no SDIO offload firmware found", sizeof(vub300->vub_name)); } else { @@ -1758,7 +1758,7 @@ static void vub300_cmndwork_thread(struct work_struct *work) * has been already downloaded to the VUB300 chip */ } else if (0 == vub300->mmc->card->sdio_funcs) { - strncpy(vub300->vub_name, "SD memory device", + strscpy(vub300->vub_name, "SD memory device", sizeof(vub300->vub_name)); } else { download_offload_pseudocode(vub300); -- cgit v1.2.3-70-g09d2 From 44ac5e91580b9c88212bd0336214ac204e6e9fe7 Mon Sep 17 00:00:00 2001 From: Ben Wolsieffer Date: Thu, 28 Sep 2023 09:56:44 -0400 Subject: mmc: mmci: use peripheral flow control for STM32 The STM32 SDMMC peripheral (at least for the STM32F429, STM32F469 and STM32F746, which are all the currently supported devices using periphid 0x00880180) requires DMA to be performed in peripheral flow controller mode. From the STM32F74/5 reference manual, section 35.3.2: "SDMMC host allows only to use the DMA in peripheral flow controller mode. DMA stream used to serve SDMMC must be configured in peripheral flow controller mode" This patch adds a variant option to control peripheral flow control and enables it for the STM32 variant. Signed-off-by: Ben Wolsieffer Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20230928135644.1489691-1-ben.wolsieffer@hefring.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 3 ++- drivers/mmc/host/mmci.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index dda756a56379..e967cca7a16f 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -249,6 +249,7 @@ static struct variant_data variant_stm32 = { .f_max = 48000000, .pwrreg_clkgate = true, .pwrreg_nopower = true, + .dma_flow_controller = true, .init = mmci_variant_init, }; @@ -1015,7 +1016,7 @@ static int _mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data, .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, .src_maxburst = variant->fifohalfsize >> 2, /* # of words */ .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */ - .device_fc = false, + .device_fc = variant->dma_flow_controller, }; struct dma_chan *chan; struct dma_device *device; diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 253197f132fc..34d9897c289b 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -332,6 +332,7 @@ enum mmci_busy_state { * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register * @dma_lli: true if variant has dma link list feature. * @stm32_idmabsize_mask: stm32 sdmmc idma buffer size. + * @dma_flow_controller: use peripheral as flow controller for DMA. */ struct variant_data { unsigned int clkreg; @@ -378,6 +379,7 @@ struct variant_data { u8 dma_lli:1; u32 stm32_idmabsize_mask; u32 stm32_idmabsize_align; + bool dma_flow_controller; void (*init)(struct mmci_host *host); }; -- cgit v1.2.3-70-g09d2 From 6fff35f0335300af81c96326061f3cf3866ba6b8 Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Fri, 29 Sep 2023 09:45:08 +0200 Subject: mmc: core: Always reselect card type We want to allow host caps to be changed dynamically via debugfs, so for these to have an effect, ensure that the card type reselection is always applied even if the card is old. Signed-off-by: Vincent Whitchurch Link: https://lore.kernel.org/r/20230929-mmc-caps-v2-1-11a4c2d94f15@axis.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 4a4bab9aa726..8180983bd402 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -419,7 +419,6 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT]; card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; - mmc_select_card_type(card); card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.raw_erase_timeout_mult = @@ -1732,6 +1731,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, mmc_set_erase_size(card); } + /* + * Reselect the card type since host caps could have been changed when + * debugging even if the card is not new. + */ + mmc_select_card_type(card); + /* Enable ERASE_GRP_DEF. This bit is lost after a reset or power off. */ if (card->ext_csd.rev >= 3) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, -- cgit v1.2.3-70-g09d2 From ff369d7b98426abf7bccb0722253f5d4490f3c17 Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Fri, 29 Sep 2023 09:45:09 +0200 Subject: mmc: debugfs: Allow host caps to be modified During board verification, there is a need to test the various supported eMMC/SD speed modes. However, since the framework chooses the best mode supported by the card and the host controller's caps, this currently necessitates changing the devicetree for every iteration. Allow the various speed mode host capabilities to be modified via debugfs in order to allow easier hardware verification. The values to be written are the raw MMC_CAP* values from include/linux/mmc/host.h. This is rather low-level, and these defines are not guaranteed to be stable, but it is perhaps good enough for the intended use case. MMC_CAP_AGGRESSIVE_PM can also be set, in order to be able to re-initialize the card without having to physically remove and re-insert it. /sys/kernel/debug/mmc0# grep timing ios timing spec: 9 (mmc HS200) // Turn on MMC_CAP_AGGRESSIVE_PM and re-trigger runtime suspend /sys/kernel/debug/mmc0# echo $(($(cat caps) | (1 << 7))) > caps /sys/kernel/debug/mmc0# echo on > /sys/bus/mmc/devices/mmc0\:0001/power/control /sys/kernel/debug/mmc0# echo auto > /sys/bus/mmc/devices/mmc0\:0001/power/control // MMC_CAP2_HS200_1_8V_SDR /sys/kernel/debug/mmc0# echo $(($(cat caps2) & ~(1 << 5))) > caps2 /sys/kernel/debug/mmc0# echo on > /sys/bus/mmc/devices/mmc0\:0001/power/control /sys/kernel/debug/mmc0# grep timing ios timing spec: 8 (mmc DDR52) Signed-off-by: Vincent Whitchurch Link: https://lore.kernel.org/r/20230929-mmc-caps-v2-2-11a4c2d94f15@axis.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/debugfs.c | 51 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 2c97b94aab23..1642ea72d22c 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -12,9 +12,12 @@ #include #include #include +#include #include #include +#include +#include #include "core.h" #include "card.h" @@ -298,6 +301,49 @@ static const struct file_operations mmc_err_stats_fops = { .release = single_release, }; +static int mmc_caps_get(void *data, u64 *val) +{ + *val = *(u32 *)data; + return 0; +} + +static int mmc_caps_set(void *data, u64 val) +{ + u32 *caps = data; + u32 diff = *caps ^ val; + u32 allowed = MMC_CAP_AGGRESSIVE_PM | + MMC_CAP_SD_HIGHSPEED | + MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_UHS | + MMC_CAP_DDR; + + if (diff & ~allowed) + return -EINVAL; + + *caps = val; + + return 0; +} + +static int mmc_caps2_set(void *data, u64 val) +{ + u32 allowed = MMC_CAP2_HSX00_1_8V | MMC_CAP2_HSX00_1_2V; + u32 *caps = data; + u32 diff = *caps ^ val; + + if (diff & ~allowed) + return -EINVAL; + + *caps = val; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(mmc_caps_fops, mmc_caps_get, mmc_caps_set, + "0x%08llx\n"); +DEFINE_DEBUGFS_ATTRIBUTE(mmc_caps2_fops, mmc_caps_get, mmc_caps2_set, + "0x%08llx\n"); + void mmc_add_host_debugfs(struct mmc_host *host) { struct dentry *root; @@ -306,8 +352,9 @@ void mmc_add_host_debugfs(struct mmc_host *host) host->debugfs_root = root; debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops); - debugfs_create_x32("caps", S_IRUSR, root, &host->caps); - debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2); + debugfs_create_file("caps", 0600, root, &host->caps, &mmc_caps_fops); + debugfs_create_file("caps2", 0600, root, &host->caps2, + &mmc_caps2_fops); debugfs_create_file_unsafe("clock", S_IRUSR | S_IWUSR, root, host, &mmc_clock_fops); -- cgit v1.2.3-70-g09d2 From a30c6251859cf93700c2294b65706046bac29e55 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Oct 2023 16:51:03 +0300 Subject: mmc: sdhci-pci: Switch to use acpi_evaluate_dsm_typed() The acpi_evaluate_dsm_typed() provides a way to check the type of the object evaluated by _DSM call. Use it instead of open coded variant. Signed-off-by: Andy Shevchenko Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20231002135103.2602847-1-andriy.shevchenko@linux.intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 7c14feb5db77..025b31aa712c 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -483,11 +483,12 @@ static int __intel_dsm(struct intel_host *intel_host, struct device *dev, int err = 0; size_t len; - obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &intel_dsm_guid, 0, fn, NULL); + obj = acpi_evaluate_dsm_typed(ACPI_HANDLE(dev), &intel_dsm_guid, 0, fn, NULL, + ACPI_TYPE_BUFFER); if (!obj) return -EOPNOTSUPP; - if (obj->type != ACPI_TYPE_BUFFER || obj->buffer.length < 1) { + if (obj->buffer.length < 1) { err = -EINVAL; goto out; } -- cgit v1.2.3-70-g09d2 From 34457e4e0c15ad5bcd8eb4e8a728e750bb020288 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 6 Oct 2023 13:58:02 +0300 Subject: mmc: sdhci-pltfm: Drop unnecessary error messages in sdhci_pltfm_init() The devm_platform_ioremap_resource() and platform_get_irq() print the error messages themselves and our "failed" one brings no value and just noise. Refactor code to avoid those noisy error messages. Signed-off-by: Andy Shevchenko Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20231006105803.3374241-1-andriy.shevchenko@linux.intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pltfm.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index a72e123a585d..4d1a703a5bdb 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -115,26 +115,21 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, { struct sdhci_host *host; void __iomem *ioaddr; - int irq, ret; + int irq; ioaddr = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(ioaddr)) { - ret = PTR_ERR(ioaddr); - goto err; - } + if (IS_ERR(ioaddr)) + return ERR_CAST(ioaddr); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto err; - } + if (irq < 0) + return ERR_PTR(irq); host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pltfm_host) + priv_size); - if (IS_ERR(host)) { - ret = PTR_ERR(host); - goto err; + dev_err(&pdev->dev, "%s failed %pe\n", __func__, host); + return ERR_CAST(host); } host->ioaddr = ioaddr; @@ -152,9 +147,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, platform_set_drvdata(pdev, host); return host; -err: - dev_err(&pdev->dev, "%s failed %d\n", __func__, ret); - return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(sdhci_pltfm_init); -- cgit v1.2.3-70-g09d2 From 4261ff59f4be26fb4a553c6e916852221fae4477 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 6 Oct 2023 13:58:03 +0300 Subject: mmc: sdhci-pltfm: Make driver OF independent Since we have device_is_compatible() API, drop OF dependency in the driver. Signed-off-by: Andy Shevchenko Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20231006105803.3374241-2-andriy.shevchenko@linux.intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pltfm.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 4d1a703a5bdb..62753d72198a 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -19,7 +19,6 @@ #include #include #include -#include #ifdef CONFIG_PPC #include #endif @@ -56,19 +55,16 @@ static bool sdhci_wp_inverted(struct device *dev) static void sdhci_get_compatibility(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct sdhci_host *host = platform_get_drvdata(pdev); - struct device_node *np = pdev->dev.of_node; - - if (!np) - return; - if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc")) + if (device_is_compatible(dev, "fsl,p2020-rev1-esdhc")) host->quirks |= SDHCI_QUIRK_BROKEN_DMA; - if (of_device_is_compatible(np, "fsl,p2020-esdhc") || - of_device_is_compatible(np, "fsl,p1010-esdhc") || - of_device_is_compatible(np, "fsl,t4240-esdhc") || - of_device_is_compatible(np, "fsl,mpc8536-esdhc")) + if (device_is_compatible(dev, "fsl,p2020-esdhc") || + device_is_compatible(dev, "fsl,p1010-esdhc") || + device_is_compatible(dev, "fsl,t4240-esdhc") || + device_is_compatible(dev, "fsl,mpc8536-esdhc")) host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; } -- cgit v1.2.3-70-g09d2 From 0ebebb21c48408bfa96a6fb18aa1a5bb543e2312 Mon Sep 17 00:00:00 2001 From: Tomer Maimon Date: Mon, 2 Oct 2023 23:06:10 +0300 Subject: mmc: sdhci-npcm: Add NPCM SDHCI driver Add Nuvoton NPCM BMC sdhci-pltfm controller driver. Signed-off-by: Tomer Maimon Acked-by: Adrian Hunter Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231002200610.129799-3-tmaimon77@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 8 ++++ drivers/mmc/host/Makefile | 1 + drivers/mmc/host/sdhci-npcm.c | 94 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 drivers/mmc/host/sdhci-npcm.c (limited to 'drivers') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 2e8476db2381..58bd5fe4cd25 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -429,6 +429,14 @@ config MMC_SDHCI_IPROC If unsure, say N. +config MMC_SDHCI_NPCM + tristate "Secure Digital Host Controller Interface support for NPCM" + depends on ARCH_NPCM || COMPILE_TEST + depends on MMC_SDHCI_PLTFM + help + This provides support for the SD/eMMC controller found in + NPCM BMC family SoCs. + config MMC_MESON_GX tristate "Amlogic S905/GX*/AXG SD/MMC Host Controller support" depends on ARCH_MESON|| COMPILE_TEST diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index a693fa3d3f1c..d0be4465f3ec 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o obj-$(CONFIG_MMC_SDHCI_OF_SPARX5) += sdhci-of-sparx5.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o +obj-$(CONFIG_MMC_SDHCI_NPCM) += sdhci-npcm.o obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o diff --git a/drivers/mmc/host/sdhci-npcm.c b/drivers/mmc/host/sdhci-npcm.c new file mode 100644 index 000000000000..5bf9d18f364e --- /dev/null +++ b/drivers/mmc/host/sdhci-npcm.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NPCM SDHC MMC host controller driver. + * + * Copyright (c) 2023 Nuvoton Technology corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sdhci-pltfm.h" + +static const struct sdhci_pltfm_data npcm7xx_sdhci_pdata = { + .quirks = SDHCI_QUIRK_DELAY_AFTER_POWER, + .quirks2 = SDHCI_QUIRK2_STOP_WITH_TC | + SDHCI_QUIRK2_NO_1_8_V, +}; + +static const struct sdhci_pltfm_data npcm8xx_sdhci_pdata = { + .quirks = SDHCI_QUIRK_DELAY_AFTER_POWER, + .quirks2 = SDHCI_QUIRK2_STOP_WITH_TC, +}; + +static int npcm_sdhci_probe(struct platform_device *pdev) +{ + const struct sdhci_pltfm_data *data; + struct sdhci_pltfm_host *pltfm_host; + struct device *dev = &pdev->dev; + struct sdhci_host *host; + u32 caps; + int ret; + + data = of_device_get_match_data(dev); + if (!data) + return -EINVAL; + + host = sdhci_pltfm_init(pdev, data, 0); + if (IS_ERR(host)) + return PTR_ERR(host); + + pltfm_host = sdhci_priv(host); + + pltfm_host->clk = devm_clk_get_optional_enabled(dev, NULL); + if (IS_ERR(pltfm_host->clk)) { + ret = PTR_ERR(pltfm_host->clk); + goto err_sdhci; + } + + caps = sdhci_readl(host, SDHCI_CAPABILITIES); + if (caps & SDHCI_CAN_DO_8BIT) + host->mmc->caps |= MMC_CAP_8_BIT_DATA; + + ret = mmc_of_parse(host->mmc); + if (ret) + goto err_sdhci; + + ret = sdhci_add_host(host); + if (ret) + goto err_sdhci; + + return 0; + +err_sdhci: + sdhci_pltfm_free(pdev); + return ret; +} + +static const struct of_device_id npcm_sdhci_of_match[] = { + { .compatible = "nuvoton,npcm750-sdhci", .data = &npcm7xx_sdhci_pdata }, + { .compatible = "nuvoton,npcm845-sdhci", .data = &npcm8xx_sdhci_pdata }, + { } +}; +MODULE_DEVICE_TABLE(of, npcm_sdhci_of_match); + +static struct platform_driver npcm_sdhci_driver = { + .driver = { + .name = "npcm-sdhci", + .of_match_table = npcm_sdhci_of_match, + .pm = &sdhci_pltfm_pmops, + }, + .probe = npcm_sdhci_probe, + .remove_new = sdhci_pltfm_remove, +}; +module_platform_driver(npcm_sdhci_driver); + +MODULE_DESCRIPTION("NPCM Secure Digital Host Controller Interface driver"); +MODULE_AUTHOR("Tomer Maimon "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From a2b8fa785358f699e9736718f430cddf596cd79e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 6 Oct 2023 17:43:43 -0500 Subject: mmc: jz4740: Use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Signed-off-by: Rob Herring Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20231006224343.441720-1-robh@kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/jz4740_mmc.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index f379ce5b582d..6a45991ca056 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -18,9 +18,10 @@ #include #include #include -#include +#include #include #include +#include #include #include @@ -1040,7 +1041,6 @@ static int jz4740_mmc_probe(struct platform_device* pdev) int ret; struct mmc_host *mmc; struct jz4740_mmc_host *host; - const struct of_device_id *match; mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev); if (!mmc) { @@ -1050,13 +1050,8 @@ static int jz4740_mmc_probe(struct platform_device* pdev) host = mmc_priv(mmc); - match = of_match_device(jz4740_mmc_of_match, &pdev->dev); - if (match) { - host->version = (enum jz4740_mmc_version)match->data; - } else { - /* JZ4740 should be the only one using legacy probe */ - host->version = JZ_MMC_JZ4740; - } + /* Default if no match is JZ4740 */ + host->version = (enum jz4740_mmc_version)device_get_match_data(&pdev->dev); ret = mmc_of_parse(mmc); if (ret) { @@ -1200,7 +1195,7 @@ static struct platform_driver jz4740_mmc_driver = { .driver = { .name = "jz4740-mmc", .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .of_match_table = of_match_ptr(jz4740_mmc_of_match), + .of_match_table = jz4740_mmc_of_match, .pm = pm_sleep_ptr(&jz4740_mmc_pm_ops), }, }; -- cgit v1.2.3-70-g09d2 From 57925e16c9f7d18012bcf45bfa658f92c087981a Mon Sep 17 00:00:00 2001 From: Rong Chen Date: Thu, 26 Oct 2023 15:31:56 +0800 Subject: mmc: meson-gx: Remove setting of CMD_CFG_ERROR For the t7 and older SoC families, the CMD_CFG_ERROR has no effect. Starting from SoC family C3, setting this bit without SG LINK data address will cause the controller to generate an IRQ and stop working. To fix it, don't set the bit CMD_CFG_ERROR anymore. Fixes: 18f92bc02f17 ("mmc: meson-gx: make sure the descriptor is stopped on errors") Signed-off-by: Rong Chen Reviewed-by: Jerome Brunet Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20231026073156.2868310-1-rong.chen@amlogic.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 9837dab096e6..c7c067b9415a 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -801,7 +801,6 @@ static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd) cmd_cfg |= FIELD_PREP(CMD_CFG_CMD_INDEX_MASK, cmd->opcode); cmd_cfg |= CMD_CFG_OWNER; /* owned by CPU */ - cmd_cfg |= CMD_CFG_ERROR; /* stop in case of error */ meson_mmc_set_response_bits(cmd, &cmd_cfg); -- cgit v1.2.3-70-g09d2