From: Kaustabh Chakraborty Date: Fri, 17 Oct 2025 15:24:09 +0000 (+0530) Subject: mmc: dw_mmc: add voltage switch command flag X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e6b66e9f338fe9c8a6bc498399e736f7ec9deb10;p=thirdparty%2Fu-boot.git mmc: dw_mmc: add voltage switch command flag 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. 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 Signed-off-by: Peng Fan --- diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 1aa992c352c..94b6641c44c 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 639a2d28e78..47e3220985e 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 * @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; };