Hi Kaustabh, On Fri, Oct 17, 2025 at 08:54:09PM +0530, Kaustabh Chakraborty wrote: >During a voltage switch command (CMD11, opcode: SD_CMD_SWITCH_UHS18V), >certain hosts tend to stop responding to subsequent commands. This is >addressed by introducing an additional command flag, >DWMCI_CMD_VOLT_SWITCH.
is there any errata or spec have this information public? > >The associated interrupt bit is defined as DWMCI_INTMSK_VOLTSW. This is >set high when a voltage switch is issued, this needs to be waited for >and set to low. Implement the same in the timeout loop. Do note that >since DWMCI_INTMSK_VOLTSW shares the same bit as DWMCI_INTMSK_HTO (bit >10), the interrupt bit needs to be polled for only if the volt switch >command is issued. > >DWMCI_CMD_VOLT_SWITCH also needs to be set for subsequent clken commands >after the volt switch. To ensure this, add a boolean member in the host >private struct (herein named volt_switching), which informs if the last >command issued was for volt switching or not. > >Signed-off-by: Kaustabh Chakraborty <[email protected]> >--- > drivers/mmc/dw_mmc.c | 15 +++++++++++++-- > include/dwmmc.h | 4 ++++ > 2 files changed, 17 insertions(+), 2 deletions(-) > >diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c >index >1aa992c352c3f11ccdd1c02745fa988646952261..94b6641c44c39e67aac453c027d519c0e1580de6 > 100644 >--- a/drivers/mmc/dw_mmc.c >+++ b/drivers/mmc/dw_mmc.c >@@ -419,6 +419,10 @@ static int dwmci_send_cmd_common(struct dwmci_host *host, >struct mmc_cmd *cmd, > if (cmd->resp_type & MMC_RSP_CRC) > flags |= DWMCI_CMD_CHECK_CRC; > >+ host->volt_switching = (cmd->cmdidx == SD_CMD_SWITCH_UHS18V); >+ if (host->volt_switching) >+ flags |= DWMCI_CMD_VOLT_SWITCH; >+ > flags |= cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG; > > debug("Sending CMD%d\n", cmd->cmdidx); >@@ -427,6 +431,10 @@ static int dwmci_send_cmd_common(struct dwmci_host *host, >struct mmc_cmd *cmd, > > for (i = 0; i < retry; i++) { > mask = dwmci_readl(host, DWMCI_RINTSTS); >+ if (host->volt_switching && (mask & DWMCI_INTMSK_VOLTSW)) { >+ dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_VOLTSW); >+ break; >+ } > if (mask & DWMCI_INTMSK_CDONE) { > if (!data) > dwmci_writel(host, DWMCI_RINTSTS, mask); >@@ -508,12 +516,15 @@ static int dwmci_control_clken(struct dwmci_host *host, >bool on) > const u32 val = on ? DWMCI_CLKEN_ENABLE | DWMCI_CLKEN_LOW_PWR : 0; > const u32 cmd_only_clk = DWMCI_CMD_PRV_DAT_WAIT | DWMCI_CMD_UPD_CLK; > int i, timeout = 10000; >- u32 mask; >+ u32 flags, mask; > > dwmci_writel(host, DWMCI_CLKENA, val); > > /* Inform CIU */ >- dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_START | cmd_only_clk); >+ flags = DWMCI_CMD_START | cmd_only_clk; >+ if (host->volt_switching) >+ flags |= DWMCI_CMD_VOLT_SWITCH; >+ dwmci_writel(host, DWMCI_CMD, flags); > > for (i = 0; i < timeout; i++) { > mask = dwmci_readl(host, DWMCI_RINTSTS); >diff --git a/include/dwmmc.h b/include/dwmmc.h >index >639a2d28e7860f2ceb09955ee11550e406fd1bd2..47e3220985e900050d9db9d80e0d45efe6c2e545 > 100644 >--- a/include/dwmmc.h >+++ b/include/dwmmc.h >@@ -72,6 +72,7 @@ > #define DWMCI_INTMSK_RTO BIT(8) > #define DWMCI_INTMSK_DRTO BIT(9) > #define DWMCI_INTMSK_HTO BIT(10) >+#define DWMCI_INTMSK_VOLTSW BIT(10) /* overlap! */ > #define DWMCI_INTMSK_FRUN BIT(11) > #define DWMCI_INTMSK_HLE BIT(12) > #define DWMCI_INTMSK_SBE BIT(13) >@@ -104,6 +105,7 @@ > #define DWMCI_CMD_ABORT_STOP BIT(14) > #define DWMCI_CMD_PRV_DAT_WAIT BIT(13) > #define DWMCI_CMD_UPD_CLK BIT(21) >+#define DWMCI_CMD_VOLT_SWITCH BIT(28) > #define DWMCI_CMD_USE_HOLD_REG BIT(29) > #define DWMCI_CMD_START BIT(31) > >@@ -190,6 +192,7 @@ struct dwmci_idmac_regs { > * @cfg: Internal MMC configuration, for !CONFIG_BLK cases > * @fifo_mode: Use FIFO mode (not DMA) to read and write data > * @dma_64bit_address: Whether DMA supports 64-bit address mode or not >+ * @volt_switching: Whether SD voltage switching is in process or not Since volt_switching y means in process, I not see it is cleared when it is not needed. Is this expected? Thanks, Peng > * @regs: Registers that can vary for different DW MMC block versions > */ > struct dwmci_host { >@@ -229,6 +232,7 @@ struct dwmci_host { > > bool fifo_mode; > bool dma_64bit_address; >+ bool volt_switching; > const struct dwmci_idmac_regs *regs; > }; > > >-- >2.51.0 >

