From: Shawn Lin Date: Tue, 16 Dec 2025 11:49:56 +0000 (+0800) Subject: mmc: dw_mmc: Remove vqmmc_enabled from struct dw_mci and update the reset X-Git-Tag: v7.1-rc1~157^2~114 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9313c6c3dbd7aab645f1a37943f8187ea48edc6f;p=thirdparty%2Fkernel%2Fstable.git mmc: dw_mmc: Remove vqmmc_enabled from struct dw_mci and update the reset commit 51da2240906c ("mmc: dw_mmc: use mmc_regulator_get_supply to handle regulators") introduced tracking of vqmmc_enabled. Currently, mmc_regulator_enable_vqmmc() and mmc_regulator_disable_vqmmc() well record the status of vqmmc, so use these two helpers to remove vqmmc_enabled locally. With vqmmc_enabled gone, resetting controller on MMC_POWER_ON phase won't work as dw_mci_set_ios() will be called several times during enumerating which leads to reset the controller several times too. This messes up the status machine of controller. By looking into the commit d1f1dd86006c ("mmc: dw_mmc: Give a good reset after we give power"), it tried to solve failures on rk3288. The problem is probably because the vqmmc is used for IO block associated with dw controller. When SD is removed during I/O, cutting off vqmmc in MMC_POWER_OFF phase will confuse the controller as its status machine refers to several IO status, such as data_state_mc_busy and data_busy on SDMMC_STATUS reg. So the controller could run into an unexpected state and could not enumerate cards correctly the next time. Reset it on MMC_POWER_ON phase or MMC_POWER_OFF phase should work, let's do the latter. This patch is tested on RK3588s/RK3399/RK3576 EVB with TF cards with both vqmmc present or not. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 9c491cd5c3686..6cb891aaa5c2a 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1443,25 +1443,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) mci_writel(slot->host, PWREN, regs); break; case MMC_POWER_ON: - if (!slot->host->vqmmc_enabled) { - if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_enable(mmc->supply.vqmmc); - if (ret < 0) - dev_err(slot->host->dev, - "failed to enable vqmmc\n"); - else - slot->host->vqmmc_enabled = true; - - } else { - /* Keep track so we don't reset again */ - slot->host->vqmmc_enabled = true; - } - - /* Reset our state machine after powering on */ - dw_mci_ctrl_reset(slot->host, - SDMMC_CTRL_ALL_RESET_FLAGS); - } - + mmc_regulator_enable_vqmmc(mmc); /* Adjust clock / bus width after power is up */ dw_mci_setup_bus(slot, false); @@ -1473,13 +1455,13 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (!IS_ERR(mmc->supply.vmmc)) mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); - if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) - regulator_disable(mmc->supply.vqmmc); - slot->host->vqmmc_enabled = false; + mmc_regulator_disable_vqmmc(mmc); regs = mci_readl(slot->host, PWREN); regs &= ~(1 << slot->id); mci_writel(slot->host, PWREN, regs); + /* Reset our state machine after powering off */ + dw_mci_ctrl_reset(slot->host, SDMMC_CTRL_ALL_RESET_FLAGS); break; default: break; diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index b4ceca0167c42..6faa63b3ce30a 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -121,7 +121,6 @@ struct dw_mci_dma_slave { * @push_data: Pointer to FIFO push function. * @pull_data: Pointer to FIFO pull function. * @quirks: Set of quirks that apply to specific versions of the IP. - * @vqmmc_enabled: Status of vqmmc, should be true or false. * @irq_flags: The flags to be passed to request_irq. * @irq: The irq value to be passed to request_irq. * @sdio_id0: Number of slot0 in the SDIO interrupt registers. @@ -228,7 +227,6 @@ struct dw_mci { void (*pull_data)(struct dw_mci *host, void *buf, int cnt); u32 quirks; - bool vqmmc_enabled; unsigned long irq_flags; /* IRQ flags */ int irq;