From fc6b5d82607f2c351455a8048a3dbc6169987c13 Mon Sep 17 00:00:00 2001 From: Sergei Antonov Date: Fri, 2 Sep 2022 10:40:10 +0300 Subject: mmc: ftsdc010: make command timeout 250 ms as in the comment Get rid of discrepancy beween comment /* 250 ms */ and code which shifts by 4 thus dividing by 16. So change code to shift by 2 and make the timeout value 250 ms. Signed-off-by: Sergei Antonov Reviewed-by: Rick Chen Reviewed-by: Jaehoon Chung --- drivers/mmc/ftsdc010_mci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c index 570d54cf9d..cabb747fbb 100644 --- a/drivers/mmc/ftsdc010_mci.c +++ b/drivers/mmc/ftsdc010_mci.c @@ -30,7 +30,7 @@ #include #include -#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */ +#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */ #define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */ #if CONFIG_IS_ENABLED(OF_PLATDATA) -- cgit v1.2.3 From 2b0dd4174f36e1f57f32116e44cb6e0e84fb2c67 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 9 Sep 2022 16:23:32 +0900 Subject: mmc: sdhci: Add new quirks for SUPPORT_SINGLE This patch defines a quirk to disable the block count for single block transactions. This is similar to Linux kernel commit d3fc5d71ac4d ("mmc: sdhci: add a quirk for single block transactions"). Signed-off-by: Kunihiko Hayashi Reviewed-by: Jaehoon Chung --- drivers/mmc/sdhci.c | 8 +++++--- include/sdhci.h | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index bf989a594f..a80ad8329a 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -211,7 +211,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, unsigned int stat = 0; int ret = 0; int trans_bytes = 0, is_aligned = 1; - u32 mask, flags, mode; + u32 mask, flags, mode = 0; unsigned int time = 0; int mmc_dev = mmc_get_blk_desc(mmc)->devnum; ulong start = get_timer(0); @@ -273,10 +273,12 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, /* Set Transfer mode regarding to data flag */ if (data) { sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL); - mode = SDHCI_TRNS_BLK_CNT_EN; + + if (!(host->quirks & SDHCI_QUIRK_SUPPORT_SINGLE)) + mode = SDHCI_TRNS_BLK_CNT_EN; trans_bytes = data->blocks * data->blocksize; if (data->blocks > 1) - mode |= SDHCI_TRNS_MULTI; + mode |= SDHCI_TRNS_MULTI | SDHCI_TRNS_BLK_CNT_EN; if (data->flags == MMC_DATA_READ) mode |= SDHCI_TRNS_READ; diff --git a/include/sdhci.h b/include/sdhci.h index 88f1917480..24b4599b85 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -247,6 +247,7 @@ #define SDHCI_QUIRK_WAIT_SEND_CMD (1 << 6) #define SDHCI_QUIRK_USE_WIDE8 (1 << 8) #define SDHCI_QUIRK_NO_1_8_V (1 << 9) +#define SDHCI_QUIRK_SUPPORT_SINGLE (1 << 10) /* to make gcc happy */ struct sdhci_host; -- cgit v1.2.3 From 12fc8efe5ad3d57ee82e0a4c548f5c47f473a9b4 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 9 Sep 2022 16:23:33 +0900 Subject: mmc: f_sdh30: Add support for F_SDH30_E51 Add Socionext F_SDH30_E51 IP support. The features of this IP includes CMD/DAT line delay and force card insertion mode for non-removable cards. And the IP needs to add some quirks. Signed-off-by: Kunihiko Hayashi --- drivers/mmc/Kconfig | 4 ++-- drivers/mmc/f_sdh30.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 4 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index f799f70e43..56f42820c7 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -576,12 +576,12 @@ config MMC_SDHCI_IPROC If unsure, say N. config MMC_SDHCI_F_SDH30 - bool "SDHCI support for Fujitsu Semiconductor F_SDH30" + bool "SDHCI support for Fujitsu Semiconductor/Socionext F_SDH30" depends on BLK && DM_MMC depends on MMC_SDHCI help This selects the Secure Digital Host Controller Interface (SDHCI) - Needed by some Fujitsu SoC for MMC / SD / SDIO support. + Needed by some Fujitsu/Socionext SoC for MMC / SD / SDIO support. If you have a controller with this interface, say Y or M here. If unsure, say N. diff --git a/drivers/mmc/f_sdh30.c b/drivers/mmc/f_sdh30.c index 3a85d9e348..3d587a464d 100644 --- a/drivers/mmc/f_sdh30.c +++ b/drivers/mmc/f_sdh30.c @@ -11,13 +11,48 @@ #include #include +#define F_SDH30_ESD_CONTROL 0x124 +#define F_SDH30_CMD_DAT_DELAY BIT(9) + +#define F_SDH30_TEST 0x158 +#define F_SDH30_FORCE_CARD_INSERT BIT(6) + +struct f_sdh30_data { + void (*init)(struct udevice *dev); + u32 quirks; +}; + struct f_sdh30_plat { struct mmc_config cfg; struct mmc mmc; + + bool enable_cmd_dat_delay; + const struct f_sdh30_data *data; }; DECLARE_GLOBAL_DATA_PTR; +static void f_sdh30_e51_init(struct udevice *dev) +{ + struct f_sdh30_plat *plat = dev_get_plat(dev); + struct sdhci_host *host = dev_get_priv(dev); + u32 val; + + val = sdhci_readl(host, F_SDH30_ESD_CONTROL); + if (plat->enable_cmd_dat_delay) + val |= F_SDH30_CMD_DAT_DELAY; + else + val &= ~F_SDH30_CMD_DAT_DELAY; + sdhci_writel(host, val, F_SDH30_ESD_CONTROL); + + val = sdhci_readl(host, F_SDH30_TEST); + if (plat->cfg.host_caps & MMC_CAP_NONREMOVABLE) + val |= F_SDH30_FORCE_CARD_INSERT; + else + val &= ~F_SDH30_FORCE_CARD_INSERT; + sdhci_writel(host, val, F_SDH30_TEST); +} + static int f_sdh30_sdhci_probe(struct udevice *dev) { struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); @@ -25,6 +60,8 @@ static int f_sdh30_sdhci_probe(struct udevice *dev) struct sdhci_host *host = dev_get_priv(dev); int ret; + plat->data = (const struct f_sdh30_data *)dev_get_driver_data(dev); + ret = mmc_of_parse(dev, &plat->cfg); if (ret) return ret; @@ -33,6 +70,9 @@ static int f_sdh30_sdhci_probe(struct udevice *dev) host->mmc->dev = dev; host->mmc->priv = host; + if (plat->data && plat->data->quirks) + host->quirks = plat->data->quirks; + ret = sdhci_setup_cfg(&plat->cfg, host, 200000000, 400000); if (ret) return ret; @@ -41,18 +81,29 @@ static int f_sdh30_sdhci_probe(struct udevice *dev) mmc_set_clock(host->mmc, host->mmc->cfg->f_min, MMC_CLK_ENABLE); - return sdhci_probe(dev); + ret = sdhci_probe(dev); + if (ret) + return ret; + + if (plat->data && plat->data->init) + plat->data->init(dev); + + return 0; } static int f_sdh30_of_to_plat(struct udevice *dev) { struct sdhci_host *host = dev_get_priv(dev); + struct f_sdh30_plat *plat = dev_get_plat(dev); host->name = strdup(dev->name); host->ioaddr = dev_read_addr_ptr(dev); host->bus_width = dev_read_u32_default(dev, "bus-width", 4); host->index = dev_read_u32_default(dev, "index", 0); + plat->enable_cmd_dat_delay = + dev_read_bool(dev, "socionext,enable-cmd-dat-delay"); + return 0; } @@ -63,8 +114,19 @@ static int f_sdh30_bind(struct udevice *dev) return sdhci_bind(dev, &plat->mmc, &plat->cfg); } +static const struct f_sdh30_data f_sdh30_e51_data = { + .init = f_sdh30_e51_init, + .quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_SUPPORT_SINGLE, +}; + static const struct udevice_id f_sdh30_mmc_ids[] = { - { .compatible = "fujitsu,mb86s70-sdhci-3.0" }, + { + .compatible = "fujitsu,mb86s70-sdhci-3.0", + }, + { + .compatible = "socionext,f-sdh30-e51-mmc", + .data = (ulong)&f_sdh30_e51_data, + }, { } }; -- cgit v1.2.3 From be1872982e425375a7da6ac75da946f9d15df405 Mon Sep 17 00:00:00 2001 From: Yann Gautier Date: Tue, 13 Sep 2022 13:23:44 +0200 Subject: mmc: stm32_sdmmc2: add dual data rate support To support dual data rate with STM32 sdmmc2 driver, the dedicated bit (DDR - BIT(18)) needs to be set in the CLKRC register. Clock bypass (no divider) is not allowed in this case. This is required for the eMMC DDR modes. Signed-off-by: Yann Gautier Reviewed-by: Jaehoon Chung --- drivers/mmc/stm32_sdmmc2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index 7ab4d949e7..952d02f9b8 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -598,13 +598,16 @@ static int stm32_sdmmc2_set_ios(struct udevice *dev) * clk_div > 0 and NEGEDGE = 1 => command and data generated on * SDMMCCLK falling edge */ - if (desired && ((sys_clock > desired) || + if (desired && (sys_clock > desired || mmc->ddr_mode || IS_RISING_EDGE(plat->clk_reg_msk))) { clk = DIV_ROUND_UP(sys_clock, 2 * desired); if (clk > SDMMC_CLKCR_CLKDIV_MAX) clk = SDMMC_CLKCR_CLKDIV_MAX; } + if (mmc->ddr_mode) + clk |= SDMMC_CLKCR_DDR; + if (mmc->bus_width == 4) clk |= SDMMC_CLKCR_WIDBUS_4; if (mmc->bus_width == 8) -- cgit v1.2.3 From 27fbce4326a4d2134791784e054c7acb62ee6761 Mon Sep 17 00:00:00 2001 From: Yann Gautier Date: Tue, 13 Sep 2022 13:23:45 +0200 Subject: mmc: stm32_sdmmc2: protect against unsupported modes The UHS modes for SD, HS200 and HS400 modes for eMMC are not supported by the stm32_sdmmc2 driver. Make it clear by removing the corresponding caps after parsing the DT. Signed-off-by: Yann Gautier Reviewed-by: Jaehoon Chung --- drivers/mmc/stm32_sdmmc2.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index 952d02f9b8..d42262c14f 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -675,6 +675,8 @@ static int stm32_sdmmc2_of_to_plat(struct udevice *dev) if (ret) return ret; + cfg->host_caps &= ~(UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_HS400 | MMC_MODE_HS400_ES); + ret = clk_get_by_index(dev, 0, &plat->clk); if (ret) return ret; -- cgit v1.2.3 From 359c176de550be54805e762d296a9fec3dc24d63 Mon Sep 17 00:00:00 2001 From: Yann Gautier Date: Tue, 13 Sep 2022 13:23:46 +0200 Subject: mmc: stm32_sdmmc2: manage vqmmc The SDMMC IOs can be in an IO domain, that has to be enabled. This is done by enabling vqmmc in the driver. This has no impact on configurations not using an IO domain, the check can then be executed on all platforms managing regulator, and the vqmmc regulator enabled on all platforms having it in their DT. Signed-off-by: Yann Gautier Reviewed-by: Jaehoon Chung --- drivers/mmc/stm32_sdmmc2.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index d42262c14f..b68594de37 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -25,6 +25,7 @@ #include #include #include +#include #include struct stm32_sdmmc2_plat { @@ -36,6 +37,9 @@ struct stm32_sdmmc2_plat { struct gpio_desc cd_gpio; u32 clk_reg_msk; u32 pwr_reg_msk; +#if CONFIG_IS_ENABLED(DM_REGULATOR) + bool vqmmc_enabled; +#endif }; struct stm32_sdmmc2_ctx { @@ -572,6 +576,15 @@ static void stm32_sdmmc2_pwron(struct stm32_sdmmc2_plat *plat) plat->base + SDMMC_POWER); /* during the first 74 SDMMC_CK cycles the SDMMC is still disabled. */ + +#if CONFIG_IS_ENABLED(DM_REGULATOR) + if (plat->mmc.vqmmc_supply && !plat->vqmmc_enabled) { + if (regulator_set_enable_if_allowed(plat->mmc.vqmmc_supply, true)) + dev_dbg(plat->mmc.dev, "failed to enable vqmmc-supply\n"); + else + plat->vqmmc_enabled = true; + } +#endif } #define IS_RISING_EDGE(reg) (reg & SDMMC_CLKCR_NEGEDGE ? 0 : 1) -- cgit v1.2.3 From 7ff2f30b63947ffe4e707bbe4b94143e947fce35 Mon Sep 17 00:00:00 2001 From: John Keeping Date: Thu, 15 Sep 2022 18:56:56 +0100 Subject: mmc: dwmmc: only clear handled interrupts Unconditionally clearing DTO when RXDR is set leads to spurious timeouts in FIFO mode transfers if events occur in the following order: mask = dwmci_readl(host, DWMCI_RINTSTS); // Hardware asserts DWMCI_INTMSK_DTO here dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_DTO); if (mask & DWMCI_INTMSK_DTO) { // Unreachable as DTO is cleared without being handled! return 0; } Only clear interrupts that we have seen and are handling so that DTO is not missed. Signed-off-by: John Keeping Tested-by: Jerome Forissier (Rock PI 4B) Tested-by: Quentin Schulz Reviewed-by: Jaehoon Chung --- drivers/mmc/dw_mmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 4232c5eb8c..5085a3b491 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -168,7 +168,8 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) if (data->flags == MMC_DATA_READ && (mask & (DWMCI_INTMSK_RXDR | DWMCI_INTMSK_DTO))) { dwmci_writel(host, DWMCI_RINTSTS, - DWMCI_INTMSK_RXDR | DWMCI_INTMSK_DTO); + mask & (DWMCI_INTMSK_RXDR | + DWMCI_INTMSK_DTO)); while (size) { ret = dwmci_fifo_ready(host, DWMCI_FIFO_EMPTY, -- cgit v1.2.3 From 337af54a36c6409b7eeb49619c796178b3c22372 Mon Sep 17 00:00:00 2001 From: Venkatesh Yadav Abbarapu Date: Thu, 29 Sep 2022 10:22:49 +0530 Subject: mmc: Fix static checker warnings Correct pointer dereferencing check to be more consistent. Eliminate the below smatch warning: drivers/mmc/mmc.c:3118 mmc_init_device() warn: variable dereferenced before check 'm' (see line 3116) Signed-off-by: Venkatesh Yadav Abbarapu Reviewed-by: Michal Simek Reviewed-by: Jaehoon Chung --- drivers/mmc/mmc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 0b7c0be8cb..210703ea46 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -3113,10 +3113,12 @@ int mmc_init_device(int num) } m = mmc_get_mmc_dev(dev); - m->user_speed_mode = MMC_MODES_END; /* Initialising user set speed mode */ - if (!m) return 0; + + /* Initialising user set speed mode */ + m->user_speed_mode = MMC_MODES_END; + if (m->preinit) mmc_start_init(m); -- cgit v1.2.3