[PATCH 13/17] mmc: renesas_sdhi: Add RZ/G3L HS400 support

From: Biju

Date: Sat May 30 2026 - 12:15:52 EST


From: Biju Das <biju.das.jz@xxxxxxxxxxxxxx>

Add HS400 support for RZ/G3L SoC.

Signed-off-by: Biju Das <biju.das.jz@xxxxxxxxxxxxxx>
---
drivers/mmc/host/renesas_sdhi.h | 1 +
drivers/mmc/host/renesas_sdhi_core.c | 17 +++++++++++++++--
drivers/mmc/host/renesas_sdhi_internal_dmac.c | 1 +
3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index 10f634349da9..92b66116f044 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -47,6 +47,7 @@ struct renesas_sdhi_hw_info {
/* hardware features */
unsigned tuning_delay:1; /* Has tuning delay */
unsigned internal_divider:1; /* Has internal divider */
+ unsigned scc_hs400_mode2:1; /* Has scc hs400 mode2 */
};

struct renesas_sdhi_of_data_with_info {
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 974acdf110d3..282107d06114 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -186,8 +186,12 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,

clk_set_rate(ref_clk, best_freq);

- if (priv->clkh)
+ if (priv->clkh) {
+ if (priv->info->internal_divider && host->mmc->ios.timing == MMC_TIMING_MMC_HS400)
+ clkh_shift = 1;
+
clk_set_rate(priv->clk, (best_freq >> clkh_shift) * priv->divider);
+ }

return clk_get_rate(priv->clk);
}
@@ -229,7 +233,7 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
}

clock = clk & CLK_CTL_DIV_MASK;
- if (clock != CLK_CTL_DIV_MASK)
+ if (clock != CLK_CTL_DIV_MASK && clock != 0)
host->mmc->actual_clock /= (1 << (ffs(clock) + 1));

sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clock);
@@ -275,6 +279,7 @@ static int renesas_sdhi_card_busy(struct mmc_host *mmc)
#define SH_MOBILE_SDHI_SCC_TMPPORT5 0x018 /* R-Car */
#define SH_MOBILE_SDHI_SCC_TMPPORT6 0x01A /* R-Car */
#define SH_MOBILE_SDHI_SCC_TMPPORT7 0x01C /* R-Car */
+#define RZG3L_SDHI_SCC_HS400MODE2 0x020
#define RZG3L_SDHI_SCC_HWADJ4 0x022

#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0)
@@ -308,6 +313,7 @@ static int renesas_sdhi_card_busy(struct mmc_host *mmc)
#define SH_MOBILE_SDHI_SCC_TMPPORT_DISABLE_WP_CODE 0xa5000000
#define SH_MOBILE_SDHI_SCC_TMPPORT_CALIB_CODE_MASK 0x1f
#define SH_MOBILE_SDHI_SCC_TMPPORT_MANUAL_MODE BIT(7)
+#define RZG3L_SDHI_SCC_HS400MODE2_HS400EN2 BIT(0)

static inline u32 sd_scc_read32(struct tmio_mmc_host *host,
struct renesas_sdhi *priv, int addr)
@@ -437,6 +443,10 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) |
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2));

+ if (priv->info->scc_hs400_mode2)
+ sd_scc_write32(host, priv, RZG3L_SDHI_SCC_HS400MODE2,
+ RZG3L_SDHI_SCC_HS400MODE2_HS400EN2);
+
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN |
sd_scc_read32(host, priv,
@@ -578,6 +588,9 @@ static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host,
SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) &
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2));

+ if (priv->info->scc_hs400_mode2)
+ sd_scc_write32(host, priv, RZG3L_SDHI_SCC_HS400MODE2, 0x0);
+
if (sdhi_has_quirk(priv, hs400_calib_table) || sdhi_has_quirk(priv, hs400_bad_taps))
renesas_sdhi_adjust_hs400_mode_disable(host);

diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
index fb8a70d28eed..83d348fb5eeb 100644
--- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
@@ -276,6 +276,7 @@ static const struct renesas_sdhi_hw_info sdhi_hw_info_rzg3l = {
.max_divider = 2048,
.tuning_delay = 1,
.internal_divider = 1,
+ .scc_hs400_mode2 = 1,
};

static const struct renesas_sdhi_of_data_with_quirks of_r8a7795_compatible = {
--
2.43.0