From f9a86fb118530fea5a87dd7f88e90c31c989043f Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 4 Jan 2024 04:49:42 +0100 Subject: [PATCH 01/15] mmc: Avoid buffer overrun in mmc_startup() If the CSD register contains a reserved value (4 - 7) in bits 0:2 of the TRAN_SPEED field, a buffer overrun occurs. Resize the mapping table. According to the original report https://lore.kernel.org/u-boot/20180826231332.2491-11-erosca@de.adit-jv.com/ reserved values have been observed resulting in a buffer overrun. Reported-by: Eugeniu Rosca Fixes: 272cc70b211e ("Add MMC Framework") Signed-off-by: Heinrich Schuchardt Reviewed-by: Jaehoon Chung --- drivers/mmc/mmc.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index d96db7a0f83..00f4964aae3 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1570,13 +1570,20 @@ static int sd_read_ssr(struct mmc *mmc) return 0; } #endif -/* frequency bases */ -/* divided by 10 to be nice to platforms without floating point */ +/* + * TRAN_SPEED bits 0:2 encode the frequency unit: + * 0 = 100KHz, 1 = 1MHz, 2 = 10MHz, 3 = 100MHz, values 4 - 7 are reserved. + * The values in fbase[] are divided by 10 to avoid floats in multiplier[]. + */ static const int fbase[] = { 10000, 100000, 1000000, 10000000, + 0, /* reserved */ + 0, /* reserved */ + 0, /* reserved */ + 0, /* reserved */ }; /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice @@ -2560,6 +2567,8 @@ static int mmc_startup(struct mmc *mmc) mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; mmc->legacy_speed = freq * mult; + if (!mmc->legacy_speed) + log_debug("TRAN_SPEED: reserved value"); mmc_select_mode(mmc, MMC_LEGACY); mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); From 4c9307b2552ea32179b8820751a9023f1df26b3a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 23 Jan 2024 17:18:16 +0100 Subject: [PATCH 02/15] mmc: Don't suggest to build modules in Kconfig. U-Boot does not support building kernel modules. Fixes: 3c0dbed232bd ("mmc: arm_pl180_mmci: adapt driver to DM usage") Fixes: 36645f45a048 ("drivers: mmc: Add sdhci driver for Broadcom iProc platform") Fixes: dadd43c14368 ("mmc: synquacer: Add SynQuacer F_SDH30 SDHCI driver") Fixes: b312c590bcd8 ("mmc: Add MMC support for stm32h7 Socs") Fixes: d24b69395949 ("mmc: mtk-sd: add SD/MMC host controller driver for MT7623 SoC") Signed-off-by: Heinrich Schuchardt Reviewed-by: Patrice Chotard --- drivers/mmc/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index f7fe6d1042e..872fcfe3cb5 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -83,7 +83,7 @@ config ARM_PL180_MMCI This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card Interface (PL180, PL181 and compatible) support. If you have an ARM(R) platform with a Multimedia Card slot, - say Y or M here. + say Y here. config MMC_QUIRKS bool "Enable quirks" @@ -599,7 +599,7 @@ config MMC_SDHCI_IPROC This selects the iProc SD/MMC controller. If you have a Broadcom IPROC platform with SD or MMC devices, - say Y or M here. + say Y here. If unsure, say N. @@ -610,7 +610,7 @@ config MMC_SDHCI_F_SDH30 help This selects the Secure Digital Host Controller Interface (SDHCI) 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 you have a controller with this interface, say Y here. If unsure, say N. config MMC_SDHCI_KONA @@ -804,7 +804,7 @@ config STM32_SDMMC2 help This selects support for the SD/MMC controller on STM32H7 SoCs. If you have a board based on such a SoC and with a SD/MMC slot, - say Y or M here. + say Y here. config FTSDC010 bool "Ftsdc010 SD/MMC controller Support" @@ -824,7 +824,7 @@ config MMC_MTK depends on OF_CONTROL help This selects the MediaTek(R) Secure digital and Multimedia card Interface. - If you have a machine with a integrated SD/MMC card reader, say Y or M here. + If you have a machine with a integrated SD/MMC card reader, say Y here. This is needed if support for any SD/SDIO/MMC devices is required. If unsure, say N. From d06e48990d0ee5b897a43476d03154cac3ee5a98 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sat, 27 Jan 2024 17:12:35 +0000 Subject: [PATCH 03/15] mmc: Add SPL_MMC_PWRSEQ to fix link issue when building SPL With MMC_PWRSEQ enabled the following link issue may happen when building SPL and SPL_PWRSEQ is not enabled. aarch64-linux-gnu-ld.bfd: drivers/mmc/meson_gx_mmc.o: in function `meson_mmc_probe': drivers/mmc/meson_gx_mmc.c:295: undefined reference to `pwrseq_set_power' Fix this by adding a SPL_MMC_PWRSEQ Kconfig option used to enable mmc pwrseq support in SPL. Also add depends on DM_GPIO to fix following link issue: aarch64-linux-gnu-ld.bfd: drivers/mmc/mmc-pwrseq.o: in function `mmc_pwrseq_set_power': drivers/mmc/mmc-pwrseq.c:26: undefined reference to `gpio_request_by_name' aarch64-linux-gnu-ld.bfd: drivers/mmc/mmc-pwrseq.c:29: undefined reference to `dm_gpio_set_value' aarch64-linux-gnu-ld.bfd: drivers/mmc/mmc-pwrseq.c:31: undefined reference to `dm_gpio_set_value' Signed-off-by: Jonas Karlman Reviewed-by: Kever Yang Reviewed-by: Neil Armstrong Acked-by: Ferass El Hafidi --- drivers/mmc/Kconfig | 12 ++++++++++-- drivers/mmc/Makefile | 2 +- drivers/mmc/meson_gx_mmc.c | 2 +- drivers/mmc/rockchip_dw_mmc.c | 2 +- include/mmc.h | 4 ++-- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 872fcfe3cb5..510050f3920 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -20,11 +20,19 @@ config MMC_WRITE config MMC_PWRSEQ bool "HW reset support for eMMC" - depends on PWRSEQ + depends on PWRSEQ && DM_GPIO help - Ths select Hardware reset support aka pwrseq-emmc for eMMC + This select Hardware reset support aka pwrseq-emmc for eMMC devices. +config SPL_MMC_PWRSEQ + bool "HW reset support for eMMC in SPL" + depends on SPL_PWRSEQ && SPL_DM_GPIO + default y if MMC_PWRSEQ + help + This select Hardware reset support aka pwrseq-emmc for eMMC + devices in SPL. + config MMC_BROKEN_CD bool "Poll for broken card detection case" help diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 3374321e290..72c3fb66ce0 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -11,7 +11,7 @@ obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += mmc_bootdev.o endif obj-$(CONFIG_$(SPL_TPL_)MMC_WRITE) += mmc_write.o -obj-$(CONFIG_MMC_PWRSEQ) += mmc-pwrseq.o +obj-$(CONFIG_$(SPL_)MMC_PWRSEQ) += mmc-pwrseq.o obj-$(CONFIG_MMC_SDHCI_ADMA_HELPERS) += sdhci-adma.o ifndef CONFIG_$(SPL_)BLK diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c index fcf4f03d1e2..0825c0a2a83 100644 --- a/drivers/mmc/meson_gx_mmc.c +++ b/drivers/mmc/meson_gx_mmc.c @@ -288,7 +288,7 @@ static int meson_mmc_probe(struct udevice *dev) mmc_set_clock(mmc, cfg->f_min, MMC_CLK_ENABLE); -#ifdef CONFIG_MMC_PWRSEQ +#if CONFIG_IS_ENABLED(MMC_PWRSEQ) /* Enable power if needed */ ret = mmc_pwrseq_get_power(dev, cfg); if (!ret) { diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index 72c820ee633..ad4529d6afa 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -145,7 +145,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev) host->fifo_mode = priv->fifo_mode; -#ifdef CONFIG_MMC_PWRSEQ +#if CONFIG_IS_ENABLED(MMC_PWRSEQ) /* Enable power if needed */ ret = mmc_pwrseq_get_power(dev, &plat->cfg); if (!ret) { diff --git a/include/mmc.h b/include/mmc.h index 1022db3ffa7..9aef31ea5de 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -590,7 +590,7 @@ struct mmc_config { uint f_max; uint b_max; unsigned char part_type; -#ifdef CONFIG_MMC_PWRSEQ +#if CONFIG_IS_ENABLED(MMC_PWRSEQ) struct udevice *pwr_dev; #endif }; @@ -808,7 +808,7 @@ int mmc_deinit(struct mmc *mmc); */ int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg); -#ifdef CONFIG_MMC_PWRSEQ +#if CONFIG_IS_ENABLED(MMC_PWRSEQ) /** * mmc_pwrseq_get_power() - get a power device from device tree * From ee6cee125a2bee4d1f9fa488f0a24928cf68c1d4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 8 Feb 2024 10:33:43 +0100 Subject: [PATCH 04/15] mmc: arm_pl180_mmci: Rely on DM The PL180/MMCI driver is implied to use CONFIG_DM and the ARM defconfigs such as configs/vexpress_ca9x4_defconfig will get it as well. With a simple oneline to default to not being the v2 variant, the original ARM MMCI variant works fine with the driver as well. The IP version actually needs to be read out from a register on the ARM versions, but we will simply assume we are running on the original hardware if arm,primecell-periphid is not explicitly specified in the device tree. Drop the !CONFIG_DM code and depend on DM_MMC. Tested on the Versatile Express CA9x4 board. Signed-off-by: Linus Walleij --- drivers/mmc/Kconfig | 1 + drivers/mmc/arm_pl180_mmci.c | 66 ++---------------------------------- 2 files changed, 3 insertions(+), 64 deletions(-) diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 510050f3920..06e32e75696 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -87,6 +87,7 @@ config MMC_SPI_CRC_ON config ARM_PL180_MMCI bool "ARM AMBA Multimedia Card Interface and compatible support" + depends on DM_MMC help This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card Interface (PL180, PL181 and compatible) support. diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 5cf5502ed54..2666b65362b 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -25,8 +26,6 @@ #include "arm_pl180_mmci.h" #include -#ifdef CONFIG_DM_MMC -#include #define MMC_CLOCK_MAX 48000000 #define MMC_CLOCK_MIN 400000 @@ -34,7 +33,6 @@ struct arm_pl180_mmc_plat { struct mmc_config cfg; struct mmc mmc; }; -#endif static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd) { @@ -358,65 +356,6 @@ static int host_set_ios(struct mmc *dev) return 0; } -#ifndef CONFIG_DM_MMC -/* MMC uses open drain drivers in the enumeration phase */ -static int mmc_host_reset(struct mmc *dev) -{ - struct pl180_mmc_host *host = dev->priv; - - writel(host->pwr_init, &host->base->power); - - return 0; -} - -static const struct mmc_ops arm_pl180_mmci_ops = { - .send_cmd = host_request, - .set_ios = host_set_ios, - .init = mmc_host_reset, -}; - -/* - * mmc_host_init - initialize the mmc controller. - * Set initial clock and power for mmc slot. - * Initialize mmc struct and register with mmc framework. - */ - -int arm_pl180_mmci_init(struct pl180_mmc_host *host, struct mmc **mmc) -{ - u32 sdi_u32; - - writel(host->pwr_init, &host->base->power); - writel(host->clkdiv_init, &host->base->clock); - udelay(CLK_CHANGE_DELAY); - - /* Disable mmc interrupts */ - sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK; - writel(sdi_u32, &host->base->mask0); - - host->cfg.name = host->name; - host->cfg.ops = &arm_pl180_mmci_ops; - - /* TODO remove the duplicates */ - host->cfg.host_caps = host->caps; - host->cfg.voltages = host->voltages; - host->cfg.f_min = host->clock_min; - host->cfg.f_max = host->clock_max; - if (host->b_max != 0) - host->cfg.b_max = host->b_max; - else - host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; - - *mmc = mmc_create(&host->cfg, host); - if (!*mmc) - return -1; - debug("registered mmc interface number is:%d\n", - (*mmc)->block_dev.devnum); - - return 0; -} -#endif - -#ifdef CONFIG_DM_MMC static void arm_pl180_mmc_init(struct pl180_mmc_host *host) { u32 sdi_u32; @@ -477,7 +416,7 @@ static int arm_pl180_mmc_probe(struct udevice *dev) host->version2 = true; break; default: - host->version2 = true; + host->version2 = false; /* ARM variant */ } gpio_request_by_name(dev, "cd-gpios", 0, &host->cd_gpio, GPIOD_IS_IN); @@ -561,4 +500,3 @@ U_BOOT_DRIVER(arm_pl180_mmc) = { .priv_auto = sizeof(struct pl180_mmc_host), .plat_auto = sizeof(struct arm_pl180_mmc_plat), }; -#endif From a3b2786651c7966ea9038f16c97f401406bdf7d3 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 20 Feb 2024 09:36:23 +0100 Subject: [PATCH 05/15] mmc: Drop unused mmc_send_tuning() cmd_error parameter The cmd_error parameter is not used, remove it. Signed-off-by: Marek Vasut --- drivers/mmc/am654_sdhci.c | 2 +- drivers/mmc/fsl_esdhc.c | 2 +- drivers/mmc/fsl_esdhc_imx.c | 2 +- drivers/mmc/mmc.c | 2 +- drivers/mmc/mtk-sd.c | 21 ++++++++++----------- drivers/mmc/octeontx_hsmmc.c | 8 +++++++- drivers/mmc/omap_hsmmc.c | 6 +++--- drivers/mmc/renesas-sdhi.c | 2 +- drivers/mmc/sdhci-cadence.c | 2 +- include/mmc.h | 2 +- 10 files changed, 27 insertions(+), 22 deletions(-) diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index 05595bdac39..2139fea04d5 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -390,7 +390,7 @@ static int am654_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) for (itap = 0; itap < ITAP_MAX; itap++) { am654_sdhci_write_itapdly(plat, itap); - cur_val = !mmc_send_tuning(mmc, opcode, NULL); + cur_val = !mmc_send_tuning(mmc, opcode); if (cur_val && !prev_val) pass_window = itap; diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index d5066666698..d44dfa5d06f 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -1123,7 +1123,7 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) esdhc_write32(®s->irqstaten, IRQSTATEN_BRR); for (i = 0; i < MAX_TUNING_LOOP; i++) { - mmc_send_tuning(mmc, opcode, NULL); + mmc_send_tuning(mmc, opcode); mdelay(1); val = esdhc_read32(®s->autoc12err); diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 7c39c86c5e9..b74c0140020 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -882,7 +882,7 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) esdhc_write32(®s->mixctrl, val); /* We are using STD tuning, no need to check return value */ - mmc_send_tuning(mmc, opcode, NULL); + mmc_send_tuning(mmc, opcode); ctrl = esdhc_read32(®s->autoc12err); if ((!(ctrl & MIX_CTRL_EXE_TUNE)) && diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 00f4964aae3..156e2a0242c 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -360,7 +360,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error) +int mmc_send_tuning(struct mmc *mmc, u32 opcode) { struct mmc_cmd cmd; struct mmc_data data; diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c index 5a0c61daed5..296aaee7331 100644 --- a/drivers/mmc/mtk-sd.c +++ b/drivers/mmc/mtk-sd.c @@ -1131,7 +1131,7 @@ static int hs400_tune_response(struct udevice *dev, u32 opcode) i << PAD_CMD_TUNE_RX_DLY3_S); for (j = 0; j < 3; j++) { - mmc_send_tuning(mmc, opcode, &cmd_err); + cmd_err = mmc_send_tuning(mmc, opcode); if (!cmd_err) { cmd_delay |= (1 << i); } else { @@ -1181,7 +1181,7 @@ static int msdc_tune_response(struct udevice *dev, u32 opcode) i << MSDC_PAD_TUNE_CMDRDLY_S); for (j = 0; j < 3; j++) { - mmc_send_tuning(mmc, opcode, &cmd_err); + cmd_err = mmc_send_tuning(mmc, opcode); if (!cmd_err) { rise_delay |= (1 << i); } else { @@ -1203,7 +1203,7 @@ static int msdc_tune_response(struct udevice *dev, u32 opcode) i << MSDC_PAD_TUNE_CMDRDLY_S); for (j = 0; j < 3; j++) { - mmc_send_tuning(mmc, opcode, &cmd_err); + cmd_err = mmc_send_tuning(mmc, opcode); if (!cmd_err) { fall_delay |= (1 << i); } else { @@ -1238,7 +1238,7 @@ skip_fall: clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRRDLY_M, i << MSDC_PAD_TUNE_CMDRRDLY_S); - mmc_send_tuning(mmc, opcode, &cmd_err); + cmd_err = mmc_send_tuning(mmc, opcode); if (!cmd_err) internal_delay |= (1 << i); } @@ -1264,7 +1264,6 @@ static int msdc_tune_data(struct udevice *dev, u32 opcode) struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0, }; u8 final_delay, final_maxlen; void __iomem *tune_reg = &host->base->pad_tune; - int cmd_err; int i, ret; if (host->dev_comp->pad_tune0) @@ -1277,10 +1276,10 @@ static int msdc_tune_data(struct udevice *dev, u32 opcode) clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M, i << MSDC_PAD_TUNE_DATRRDLY_S); - ret = mmc_send_tuning(mmc, opcode, &cmd_err); + ret = mmc_send_tuning(mmc, opcode); if (!ret) { rise_delay |= (1 << i); - } else if (cmd_err) { + } else { /* in this case, retune response is needed */ ret = msdc_tune_response(dev, opcode); if (ret) @@ -1300,10 +1299,10 @@ static int msdc_tune_data(struct udevice *dev, u32 opcode) clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M, i << MSDC_PAD_TUNE_DATRRDLY_S); - ret = mmc_send_tuning(mmc, opcode, &cmd_err); + ret = mmc_send_tuning(mmc, opcode); if (!ret) { fall_delay |= (1 << i); - } else if (cmd_err) { + } else { /* in this case, retune response is needed */ ret = msdc_tune_response(dev, opcode); if (ret) @@ -1362,7 +1361,7 @@ static int msdc_tune_together(struct udevice *dev, u32 opcode) for (i = 0; i < PAD_DELAY_MAX; i++) { msdc_set_cmd_delay(host, i); msdc_set_data_delay(host, i); - ret = mmc_send_tuning(mmc, opcode, NULL); + ret = mmc_send_tuning(mmc, opcode); if (!ret) rise_delay |= (1 << i); } @@ -1378,7 +1377,7 @@ static int msdc_tune_together(struct udevice *dev, u32 opcode) for (i = 0; i < PAD_DELAY_MAX; i++) { msdc_set_cmd_delay(host, i); msdc_set_data_delay(host, i); - ret = mmc_send_tuning(mmc, opcode, NULL); + ret = mmc_send_tuning(mmc, opcode); if (!ret) fall_delay |= (1 << i); } diff --git a/drivers/mmc/octeontx_hsmmc.c b/drivers/mmc/octeontx_hsmmc.c index 4ee62df9d40..7f9c4f4d36d 100644 --- a/drivers/mmc/octeontx_hsmmc.c +++ b/drivers/mmc/octeontx_hsmmc.c @@ -1653,6 +1653,12 @@ static int octeontx_mmc_test_cmd(struct mmc *mmc, u32 opcode, int *statp) return err; } +static int octeontx_mmc_send_tuning(struct mmc *mmc, u32 opcode, int *error) +{ + *error = 0; + return mmc_send_tuning(mmc, opcode); +} + static int octeontx_mmc_test_get_ext_csd(struct mmc *mmc, u32 opcode, int *statp) { @@ -2006,7 +2012,7 @@ struct adj adj[] = { { "CMD_IN", 48, octeontx_mmc_test_cmd, MMC_CMD_SEND_STATUS, false, false, false, 2, }, /* { "CMD_OUT", 32, octeontx_mmc_test_cmd, MMC_CMD_SEND_STATUS, },*/ - { "DATA_IN(HS200)", 16, mmc_send_tuning, + { "DATA_IN(HS200)", 16, octeontx_mmc_send_tuning, MMC_CMD_SEND_TUNING_BLOCK_HS200, false, true, false, 2, }, { "DATA_IN", 16, octeontx_mmc_test_get_ext_csd, 0, false, false, true, 2, }, diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index a2595d19e7f..99f21b2c546 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -666,7 +666,7 @@ static int omap_hsmmc_execute_tuning(struct udevice *dev, uint opcode) while (phase_delay <= MAX_PHASE_DELAY) { omap_hsmmc_set_dll(mmc, phase_delay); - cur_match = !mmc_send_tuning(mmc, opcode, NULL); + cur_match = !mmc_send_tuning(mmc, opcode); if (cur_match) { if (prev_match) { @@ -731,7 +731,7 @@ static int omap_hsmmc_execute_tuning(struct udevice *dev, uint opcode) */ for (i = 3; i <= 10; i++) { omap_hsmmc_set_dll(mmc, phase_delay + i); - if (mmc_send_tuning(mmc, opcode, NULL)) { + if (mmc_send_tuning(mmc, opcode)) { if (temperature < 10000) phase_delay += i + 6; else if (temperature < 20000) @@ -749,7 +749,7 @@ static int omap_hsmmc_execute_tuning(struct udevice *dev, uint opcode) for (i = 2; i >= -10; i--) { omap_hsmmc_set_dll(mmc, phase_delay + i); - if (mmc_send_tuning(mmc, opcode, NULL)) { + if (mmc_send_tuning(mmc, opcode)) { if (temperature < 10000) phase_delay += i + 12; else if (temperature < 20000) diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 20b1e9277eb..4ee8657f795 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -605,7 +605,7 @@ int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode) caps = priv->caps; priv->caps &= ~TMIO_SD_CAP_DMA_INTERNAL; - ret = mmc_send_tuning(mmc, opcode, NULL); + ret = mmc_send_tuning(mmc, opcode); priv->caps = caps; diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index 327a05ad11d..c0a9f60b149 100644 --- a/drivers/mmc/sdhci-cadence.c +++ b/drivers/mmc/sdhci-cadence.c @@ -224,7 +224,7 @@ static int __maybe_unused sdhci_cdns_execute_tuning(struct udevice *dev, for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) { if (sdhci_cdns_set_tune_val(plat, i) || - mmc_send_tuning(mmc, opcode, NULL)) { /* bad */ + mmc_send_tuning(mmc, opcode)) { /* bad */ cur_streak = 0; } else { /* good */ cur_streak++; diff --git a/include/mmc.h b/include/mmc.h index 9aef31ea5de..8df14130edd 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -795,7 +795,7 @@ int mmc_unbind(struct udevice *dev); int mmc_initialize(struct bd_info *bis); int mmc_init_device(int num); int mmc_init(struct mmc *mmc); -int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error); +int mmc_send_tuning(struct mmc *mmc, u32 opcode); int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data); int mmc_deinit(struct mmc *mmc); From 60649a8d6cc975a36d06aad14ed55079e75bc4fa Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 20 Feb 2024 09:38:14 +0100 Subject: [PATCH 06/15] mmc: tmio: Check INFO1 for completion during DMA transfer In case a CRC error occurs during DMA transfer, the transfer completion flag is not set in TMIO_SD_DMA_INFO1 and the transfer would eventually time out. The timeout could be very long in case the transfer consists of a large amount of blocks, the base timeout is 10 seconds and every block adds 100 us more. In case a CRC error does occur, a completion flag is set in a different register, TMIO_SD_INFO1. Use this other completion flag to detect DMA transfer ended and stop waiting for TMIO_SD_DMA_INFO1 completion flag. This reduces the lengthy timeout in case of an error. The unconditional check of TMIO_SD_DMA_INFO2 register for DMA related errors must not be skipped in any case to actually recognize the DMA error and report it. Signed-off-by: Marek Vasut Reviewed-by: Paul Barker Tested-by: Paul Barker Reviewed-by: Jaehoon Chung --- drivers/mmc/tmio-common.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 890c496b535..719c4830bc3 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -299,7 +299,13 @@ static int tmio_sd_dma_wait_for_irq(struct udevice *dev, u32 flag, struct tmio_sd_priv *priv = dev_get_priv(dev); long wait = 1000000 + 10 * blocks; - while (!(tmio_sd_readl(priv, TMIO_SD_DMA_INFO1) & flag)) { + for (;;) { + if (tmio_sd_readl(priv, TMIO_SD_DMA_INFO1) & flag) + break; + + if (tmio_sd_readl(priv, TMIO_SD_INFO1) & TMIO_SD_INFO1_CMP) + break; + if (wait-- < 0) { dev_err(dev, "timeout during DMA\n"); return -ETIMEDOUT; From 12859c2219a61bf4ce8b33de267d2b0e3e11ef37 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 20 Feb 2024 09:38:45 +0100 Subject: [PATCH 07/15] mmc: renesas-sdhi: Stop transmission in case tuning block transfer fails The current code uses the state of tuning block received by SCC to determine whether or not to send transmission stop command. This is not correct. Use the state of tuning block transfer to determine whether or not to send transmission stop command instead, because the transmission stop command has to be sent in case the tuning block transfer failed. This requires two changes, separate variable to store and check the state of tuning block received by SCC, and another separate variable to store and check return value from transmission stop command. Signed-off-by: Marek Vasut Reviewed-by: Paul Barker Tested-by: Paul Barker Reviewed-by: Jaehoon Chung --- drivers/mmc/renesas-sdhi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 4ee8657f795..7f37d7af186 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -568,8 +568,8 @@ int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode) struct mmc *mmc = upriv->mmc; unsigned int tap_num; unsigned int taps = 0; - int i, ret = 0; - u32 caps; + int i, ret = 0, sret; + u32 caps, reg; /* Only supported on Renesas RCar */ if (!(priv->caps & TMIO_SD_CAP_RCAR_UHS)) @@ -612,8 +612,8 @@ int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode) if (ret == 0) taps |= BIT(i); - ret = renesas_sdhi_compare_scc_data(priv); - if (ret == 0) + reg = renesas_sdhi_compare_scc_data(priv); + if (reg == 0) priv->smpcmp |= BIT(i); mdelay(1); @@ -624,9 +624,9 @@ int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode) * eMMC. */ if (ret && (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200)) { - ret = mmc_send_stop_transmission(mmc, false); - if (ret < 0) - dev_dbg(dev, "Tuning abort fail (%d)\n", ret); + sret = mmc_send_stop_transmission(mmc, false); + if (sret < 0) + dev_dbg(dev, "Tuning abort fail (%d)\n", sret); } } From d1343522e509ea78dd53615846bd7b0a0049e97a Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 24 Feb 2024 23:32:09 +0100 Subject: [PATCH 08/15] mmc: Convert hs400_tuning flag from u8 to bool This hs400_tuning is a flag, make it bool. No functional change. This will be useful in the following patch, which adds another more generic flag, where the compiler can better use the space now reserved for the u8 to store more flags in it. Signed-off-by: Marek Vasut Reviewed-by: Jaehoon Chung --- drivers/mmc/mmc.c | 4 ++-- include/mmc.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 156e2a0242c..55987f329ef 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -2034,9 +2034,9 @@ static int mmc_select_hs400(struct mmc *mmc) mmc_set_clock(mmc, mmc->tran_speed, false); /* execute tuning if needed */ - mmc->hs400_tuning = 1; + mmc->hs400_tuning = true; err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200); - mmc->hs400_tuning = 0; + mmc->hs400_tuning = false; if (err) { debug("tuning failed\n"); return err; diff --git a/include/mmc.h b/include/mmc.h index 8df14130edd..a4584f84729 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -736,7 +736,7 @@ struct mmc { * accessing the boot partitions */ u32 quirks; - u8 hs400_tuning; + bool hs400_tuning:1; enum bus_mode user_speed_mode; /* input speed mode from user */ }; From 8c2208978877bf6533d97bde97ee763322d6308f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 24 Feb 2024 23:32:10 +0100 Subject: [PATCH 09/15] mmc: Add generic tuning flag Set generic mmc->tuning flag when performing tuning to indicate this condition to drivers. Drivers may use this to bypass various checks during tuning. Signed-off-by: Marek Vasut Reviewed-by: Jaehoon Chung --- drivers/mmc/mmc-uclass.c | 8 +++++++- include/mmc.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 328456831dd..304bd5eaee2 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -124,7 +124,13 @@ static int dm_mmc_execute_tuning(struct udevice *dev, uint opcode) int mmc_execute_tuning(struct mmc *mmc, uint opcode) { - return dm_mmc_execute_tuning(mmc->dev, opcode); + int ret; + + mmc->tuning = true; + ret = dm_mmc_execute_tuning(mmc->dev, opcode); + mmc->tuning = false; + + return ret; } #endif diff --git a/include/mmc.h b/include/mmc.h index a4584f84729..4b8327f1f93 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -736,6 +736,7 @@ struct mmc { * accessing the boot partitions */ u32 quirks; + bool tuning:1; bool hs400_tuning:1; enum bus_mode user_speed_mode; /* input speed mode from user */ From b78630630a9e419a50de986a3d268b428f5d0c28 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 24 Feb 2024 23:32:11 +0100 Subject: [PATCH 10/15] mmc: renesas-sdhi: Do not access SCC during tuning in send_cmd callback Do not access SCC when sending commands during tuning operation as that will disrupt the tuning operation. The tuning operation is adjusting the SCC settings itself in execute_tuning callback. When renesas_sdhi_execute_tuning() is called by the MMC core code, a loop which consists of renesas_sdhi_prepare_tuning(), mmc_send_tuning() and renesas_sdhi_compare_scc_data() iterates over each SCC tuning tap. The renesas_sdhi_prepare_tuning() configures the SCC tuning tap number into hardware, mmc_send_tuning() triggers transfer of tuning block which depends on the bus mode for which the bus is currently being tuned, this information is supplied by the MMC core code, and finally renesas_sdhi_compare_scc_data() tests the received tuning block for validity. Because renesas_sdhi_prepare_tuning() configures the SCC tuning tap into the hardware to fit the tuning operation, mmc_send_tuning() which triggers command transfer using renesas_sdhi_send_cmd() must not manipulate with the SCC in any way. Currently renesas_sdhi_send_cmd() does unconditionally call renesas_sdhi_check_scc_error(), which may adjust the SCC tuning tap position by writing RENESAS_SDHI_SCC_TAPSET, which would overwrite the required tuning configuration set by renesas_sdhi_prepare_tuning() and disrupt the tuning operation. Fix this by skipping the renesas_sdhi_check_scc_error() call in case the MMC subsystem is in tuning state. This way, the SCC settings are left unmodified by command transfer during tuning operation. Reviewed-by: Paul Barker Tested-by: Paul Barker Signed-off-by: Marek Vasut Reviewed-by: Jaehoon Chung --- drivers/mmc/renesas-sdhi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 7f37d7af186..23db2a75c44 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -798,9 +798,12 @@ static int renesas_sdhi_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct tmio_sd_priv *priv = dev_get_priv(dev); + struct mmc *mmc = upriv->mmc; - renesas_sdhi_check_scc_error(dev); + if (!mmc->tuning) + renesas_sdhi_check_scc_error(dev); if (cmd->cmdidx == MMC_CMD_SEND_STATUS) renesas_sdhi_adjust_hs400_mode_enable(priv); From 27ba82cb6c2be7e4bb4694d52f107a75fc66ce68 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 17 Mar 2024 04:01:22 +0100 Subject: [PATCH 11/15] mmc: Unconditionally call mmc_deinit() Place the SDR104/HS200/HS400 checks into the mmc_deinit() and always call it. This simplifies the code and removes ifdeffery. No functional change is expected. Reviewed-by: Jaehoon Chung Signed-off-by: Marek Vasut Reviewed-by: Dragan Simic --- drivers/mmc/mmc-uclass.c | 13 +------------ drivers/mmc/mmc.c | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 304bd5eaee2..1e03901e9dc 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -500,10 +500,7 @@ static int mmc_blk_probe(struct udevice *dev) if (ret) { debug("Probing %s failed (err=%d)\n", dev->name, ret); - if (CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || - CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || - CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)) - mmc_deinit(mmc); + mmc_deinit(mmc); return ret; } @@ -511,9 +508,6 @@ static int mmc_blk_probe(struct udevice *dev) return 0; } -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ - CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ - CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) static int mmc_blk_remove(struct udevice *dev) { struct udevice *mmc_dev = dev_get_parent(dev); @@ -522,7 +516,6 @@ static int mmc_blk_remove(struct udevice *dev) return mmc_deinit(mmc); } -#endif static const struct blk_ops mmc_blk_ops = { .read = mmc_bread, @@ -538,12 +531,8 @@ U_BOOT_DRIVER(mmc_blk) = { .id = UCLASS_BLK, .ops = &mmc_blk_ops, .probe = mmc_blk_probe, -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ - CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ - CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) .remove = mmc_blk_remove, .flags = DM_FLAG_OS_PREPARE, -#endif }; #endif /* CONFIG_BLK */ diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 55987f329ef..7b068c71ff3 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -2257,6 +2257,16 @@ error: return -ENOTSUPP; } +#else +static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) +{ + return 0; +}; + +static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) +{ + return 0; +}; #endif #if CONFIG_IS_ENABLED(MMC_TINY) @@ -3019,13 +3029,15 @@ int mmc_init(struct mmc *mmc) return err; } -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ - CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ - CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) int mmc_deinit(struct mmc *mmc) { u32 caps_filtered; + if (!CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) && + !CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) && + !CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)) + return 0; + if (!mmc->has_init) return 0; @@ -3043,7 +3055,6 @@ int mmc_deinit(struct mmc *mmc) return mmc_select_mode_and_width(mmc, caps_filtered); } } -#endif int mmc_set_dsr(struct mmc *mmc, u16 val) { From 4685d6fbe47f9aab196558334ec89c3ca7bdb642 Mon Sep 17 00:00:00 2001 From: Yang Xiwen Date: Thu, 1 Feb 2024 22:05:42 +0800 Subject: [PATCH 12/15] mmc: hi6220-dwmmc: handle clocks and resets if CONFIG_CLK and CONFIG_DM_RESET enabled This can avoid hardcoding a clock rate in driver. Also can enable the clocks and deassert the resets if the pre-bootloader does not do this for us. Currently only enabled for Hi3798MV200. Signed-off-by: Yang Xiwen Reviewed-by: Jaehoon Chung --- drivers/mmc/hi6220_dw_mmc.c | 61 ++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/hi6220_dw_mmc.c b/drivers/mmc/hi6220_dw_mmc.c index 71962cd47e0..a4b80729764 100644 --- a/drivers/mmc/hi6220_dw_mmc.c +++ b/drivers/mmc/hi6220_dw_mmc.c @@ -5,15 +5,24 @@ */ #include +#include #include #include #include #include #include +#include #include +#include DECLARE_GLOBAL_DATA_PTR; +enum hi6220_dwmmc_clk_type { + HI6220_DWMMC_CLK_BIU, + HI6220_DWMMC_CLK_CIU, + HI6220_DWMMC_CLK_CNT, +}; + struct hi6220_dwmmc_plat { struct mmc_config cfg; struct mmc mmc; @@ -21,6 +30,8 @@ struct hi6220_dwmmc_plat { struct hi6220_dwmmc_priv_data { struct dwmci_host host; + struct clk *clks[HI6220_DWMMC_CLK_CNT]; + struct reset_ctl_bulk rsts; }; struct hisi_mmc_data { @@ -32,7 +43,29 @@ static int hi6220_dwmmc_of_to_plat(struct udevice *dev) { struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; + int ret; + if (CONFIG_IS_ENABLED(CLK) && CONFIG_IS_ENABLED(DM_RESET)) { + priv->clks[HI6220_DWMMC_CLK_BIU] = devm_clk_get(dev, "biu"); + if (IS_ERR(priv->clks[HI6220_DWMMC_CLK_BIU])) { + ret = PTR_ERR(priv->clks[HI6220_DWMMC_CLK_BIU]); + dev_err(dev, "Failed to get BIU clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + priv->clks[HI6220_DWMMC_CLK_CIU] = devm_clk_get(dev, "ciu"); + if (IS_ERR(priv->clks[HI6220_DWMMC_CLK_CIU])) { + ret = PTR_ERR(priv->clks[HI6220_DWMMC_CLK_CIU]); + dev_err(dev, "Failed to get CIU clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + ret = reset_get_bulk(dev, &priv->rsts); + if (ret) { + dev_err(dev, "Failed to get resets(ret = %d)", ret); + return log_msg_ret("rst", ret); + } + } host->name = dev->name; host->ioaddr = dev_read_addr_ptr(dev); host->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), @@ -56,11 +89,37 @@ static int hi6220_dwmmc_probe(struct udevice *dev) struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; struct hisi_mmc_data *mmc_data; + int ret; mmc_data = (struct hisi_mmc_data *)dev_get_driver_data(dev); - /* Use default bus speed due to absence of clk driver */ host->bus_hz = mmc_data->clock; + if (CONFIG_IS_ENABLED(CLK) && CONFIG_IS_ENABLED(DM_RESET)) { + ret = clk_prepare_enable(priv->clks[HI6220_DWMMC_CLK_BIU]); + if (ret) { + dev_err(dev, "Failed to enable biu clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + ret = clk_prepare_enable(priv->clks[HI6220_DWMMC_CLK_CIU]); + if (ret) { + dev_err(dev, "Failed to enable ciu clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + ret = reset_deassert_bulk(&priv->rsts); + if (ret) { + dev_err(dev, "Failed to deassert resets(ret = %d).\n", ret); + return log_msg_ret("rst", ret); + } + + host->bus_hz = clk_get_rate(priv->clks[HI6220_DWMMC_CLK_CIU]); + if (host->bus_hz <= 0) { + dev_err(dev, "Failed to get ciu clock rate(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + } + dev_dbg(dev, "bus clock rate: %d.\n", host->bus_hz); dwmci_setup_cfg(&plat->cfg, host, host->bus_hz, 400000); host->mmc = &plat->mmc; From 1fa6dc2879899a42ba85d4ece617c2356d048308 Mon Sep 17 00:00:00 2001 From: Yang Xiwen Date: Thu, 1 Feb 2024 22:05:43 +0800 Subject: [PATCH 13/15] mmc: dw_mmc: Don't return error if data busy timeout As described in [1], some poor hardware or cards would fail to release the bus and keep driving data lines low. Ignore it and send the next cmd directly seems okay for most cases. [1]: https://patchwork.kernel.org/project/linux-mmc/patch/1424458179-5456-1-git-send-email-dianders@chromium.org/ Signed-off-by: Yang Xiwen Tested-by: Jaehoon Chung --- drivers/mmc/dw_mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 400066fa99a..e1036641452 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -262,8 +262,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { if (get_timer(start) > timeout) { - debug("%s: Timeout on data busy\n", __func__); - return -ETIMEDOUT; + debug("%s: Timeout on data busy, continue anyway\n", __func__); + break; } } From 2ea7b7a42a59ffa88817cc297655fcacb1e407cc Mon Sep 17 00:00:00 2001 From: Yang Xiwen Date: Thu, 1 Feb 2024 22:05:44 +0800 Subject: [PATCH 14/15] mmc: hi6220_dw_mmc: add fifoth_val to private data and set it in .probe The value defaults to 0 and is ignored by dw_mmc code, so the other users are not affected. Setting this explicitly fixes some weird reading error found on Hi3798MV200. Fixes: 8a5dc8140e62 ("mmc: hi6220_dw_mmc: add compatible for HC2910 support") Signed-off-by: Yang Xiwen Reviewed-by: Jaehoon Chung --- drivers/mmc/hi6220_dw_mmc.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/hi6220_dw_mmc.c b/drivers/mmc/hi6220_dw_mmc.c index a4b80729764..dc0210402bd 100644 --- a/drivers/mmc/hi6220_dw_mmc.c +++ b/drivers/mmc/hi6220_dw_mmc.c @@ -37,6 +37,7 @@ struct hi6220_dwmmc_priv_data { struct hisi_mmc_data { unsigned int clock; bool use_fifo; + u32 fifoth_val; }; static int hi6220_dwmmc_of_to_plat(struct udevice *dev) @@ -125,6 +126,7 @@ static int hi6220_dwmmc_probe(struct udevice *dev) host->mmc = &plat->mmc; host->fifo_mode = mmc_data->use_fifo; + host->fifoth_val = mmc_data->fifoth_val; host->mmc->priv = &priv->host; upriv->mmc = host->mmc; host->mmc->dev = dev; @@ -154,13 +156,20 @@ static const struct hisi_mmc_data hi6220_mmc_data = { .use_fifo = false, }; +static const struct hisi_mmc_data hi3798mv2x_mmc_data = { + .clock = 50000000, + .use_fifo = false, + // FIFO depth is 256 + .fifoth_val = MSIZE(4) | RX_WMARK(0x7f) | TX_WMARK(0x80), +}; + static const struct udevice_id hi6220_dwmmc_ids[] = { { .compatible = "hisilicon,hi6220-dw-mshc", .data = (ulong)&hi6220_mmc_data }, { .compatible = "hisilicon,hi3798cv200-dw-mshc", .data = (ulong)&hi6220_mmc_data }, { .compatible = "hisilicon,hi3798mv200-dw-mshc", - .data = (ulong)&hi6220_mmc_data }, + .data = (ulong)&hi3798mv2x_mmc_data }, { .compatible = "hisilicon,hi3660-dw-mshc", .data = (ulong)&hi3660_mmc_data }, { } From 3657ef738ad6aa2c32c569e7ae67a5557343f7d0 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 15 Apr 2024 16:56:50 +0900 Subject: [PATCH 15/15] mmc: cv1800b_sdhci: Remove the unused argument Remove the unused argument about cmd_error. Fixes: a3b2786651c7 ("mmc: Drop unused mmc_send_tuning() cmd_error parameter") Signed-off-by: Jaehoon Chung --- drivers/mmc/cv1800b_sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/cv1800b_sdhci.c b/drivers/mmc/cv1800b_sdhci.c index 2275c537772..9af6b971984 100644 --- a/drivers/mmc/cv1800b_sdhci.c +++ b/drivers/mmc/cv1800b_sdhci.c @@ -42,7 +42,7 @@ static int cv1800b_execute_tuning(struct mmc *mmc, u8 opcode) for (tap = 0; tap < TUNE_MAX_PHCODE; tap++) { cv1800b_set_tap_delay(host, tap); - if (mmc_send_tuning(host->mmc, opcode, NULL)) { + if (mmc_send_tuning(host->mmc, opcode)) { current_size = 0; } else { current_size++;