]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
mmc: dw_mmc: Remove vqmmc_enabled from struct dw_mci and update the reset
authorShawn Lin <shawn.lin@rock-chips.com>
Tue, 16 Dec 2025 11:49:56 +0000 (19:49 +0800)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 23 Feb 2026 11:06:52 +0000 (12:06 +0100)
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 <shawn.lin@rock-chips.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h

index 9c491cd5c36860261279d840845e2b331d8d4625..6cb891aaa5c2a68d8c69ab128d9e25c07b15057e 100644 (file)
@@ -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;
index b4ceca0167c42aef8d85f0b7b0426cf9bd6d770d..6faa63b3ce30aba7f5ea91ee9819b1160787bf66 100644 (file)
@@ -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;