After sdhci_set_clock() runs sdhci_set_uhs_signaling() (which writes the standard SDHCI_CTRL_HS400 = 0x5 to HOST_CONTROL2's UHS field) and the SDCLK is gated for the high-speed DLL config, fix up two things that the dwcmshc controller needs in HS400:
- HOST_CONTROL2's UHS field needs DWCMSHC_CTRL_HS400 (0x7) instead of the standard SDHCI_CTRL_HS400 (0x5). - EMMC_CONTROL.CARD_IS_EMMC (BIT 0 at offset 0x52c) must be set to enable the data-strobe sampling path that HS400 uses. The high-speed DLL branch (>52 MHz) already programs DLL_TXCLK, DLL_STRBIN and locks the DLL the same way HS200 does, which is what HS400 needs as well. Together with the core HS200 -> HS -> HS400 transition, this lets HS400 run on rk3568 / rk3588. Tested on a K3588 Radxa Rock5T board. Assisted-by: Claude Opus 4.7 <[email protected]> Signed-off-by: Sascha Hauer <[email protected]> --- drivers/mci/rockchip-dwcmshc-sdhci.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/mci/rockchip-dwcmshc-sdhci.c b/drivers/mci/rockchip-dwcmshc-sdhci.c index 4b2ee03e9a..3aa3f12930 100644 --- a/drivers/mci/rockchip-dwcmshc-sdhci.c +++ b/drivers/mci/rockchip-dwcmshc-sdhci.c @@ -18,6 +18,7 @@ #define DWCMSHC_VER_TYPE 0x504 #define DWCMSHC_HOST_CTRL3 0x508 #define DWCMSHC_EMMC_CONTROL 0x52c +#define DWCMSHC_CARD_IS_EMMC BIT(0) #define DWCMSHC_EMMC_ATCTRL 0x540 /* Rockchip specific Registers */ @@ -183,6 +184,25 @@ static void rk_sdhci_set_clock(struct rk_sdhci_host *host, unsigned int clock) /* Disable clock while config DLL */ sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0); + /* + * HS400 needs the dwcmshc-specific value (0x7) in HOST_CONTROL2's UHS + * field rather than the standard SDHCI_CTRL_HS400 (0x5) the generic + * sdhci_set_uhs_signaling() wrote. It also requires CARD_IS_EMMC in + * EMMC_CONTROL to enable the data strobe sampling path. + */ + if (host->mci.ios.timing == MMC_TIMING_MMC_HS400) { + u16 ctrl_2; + + ctrl_2 = sdhci_read16(&host->sdhci, SDHCI_HOST_CONTROL2); + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; + ctrl_2 |= DWCMSHC_CTRL_HS400; + sdhci_write16(&host->sdhci, SDHCI_HOST_CONTROL2, ctrl_2); + + extra = sdhci_read32(&host->sdhci, DWCMSHC_EMMC_CONTROL); + extra |= DWCMSHC_CARD_IS_EMMC; + sdhci_write32(&host->sdhci, DWCMSHC_EMMC_CONTROL, extra); + } + if (clock <= 52000000) { /* * Disable DLL and reset both of sample and drive clock. -- 2.47.3
