[PATCH 08/17] mmc: renesas_sdhi: Add tuning_delay hw_info flag

From: Biju

Date: Sat May 30 2026 - 12:14:43 EST


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

As per the RZ/G2L hardware manual, the TMPOUT bit field in the SCC_TMPPORT
register needs to be set to 0 when transferring at 3.3V, and to 1 when
transferring at 1.8V.

Add a tuning_delay bitfield to renesas_sdhi_hw_info to indicate hardware
that requires an adjustment when the signal voltage changes.

Add sdhi_hw_info_rzg2l with tuning_delay = 1 and assign it to
of_rzg2l_compatible, enabling the adjustment for RZ/G2L. All other
platforms retain sdhi_hw_info_generic with tuning_delay = 0 and
are unaffected.

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

diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index a42934e6d49d..a3c5fa368242 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -44,6 +44,8 @@ struct renesas_sdhi_of_data {
struct renesas_sdhi_hw_info {
u64 clk_mask;
unsigned int max_divider;
+ /* hardware features */
+ unsigned tuning_delay:1; /* Has tuning delay */
};

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 16ed6fd8470d..868ba6a6919e 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -257,40 +257,6 @@ static int renesas_sdhi_card_busy(struct mmc_host *mmc)
TMIO_STAT_DAT0);
}

-static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
- struct mmc_ios *ios)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
- struct renesas_sdhi *priv = host_to_priv(host);
- struct pinctrl_state *pin_state;
- int ret;
-
- switch (ios->signal_voltage) {
- case MMC_SIGNAL_VOLTAGE_330:
- pin_state = priv->pins_default;
- break;
- case MMC_SIGNAL_VOLTAGE_180:
- pin_state = priv->pins_uhs;
- break;
- default:
- return -EINVAL;
- }
-
- /*
- * If anything is missing, assume signal voltage is fixed at
- * 3.3V and succeed/fail accordingly.
- */
- if (IS_ERR(priv->pinctrl) || IS_ERR(pin_state))
- return ios->signal_voltage ==
- MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL;
-
- ret = mmc_regulator_set_vqmmc(host->mmc, ios);
- if (ret < 0)
- return ret;
-
- return pinctrl_select_state(priv->pinctrl, pin_state);
-}
-
/* SCC registers */
#define SH_MOBILE_SDHI_SCC_DTCNTL 0x000
#define SH_MOBILE_SDHI_SCC_TAPSET 0x002
@@ -351,6 +317,55 @@ static inline void sd_scc_write32(struct tmio_mmc_host *host,
writel(val, priv->scc_ctl + (addr << host->bus_shift));
}

+static void renesas_sdhi_set_hw_adjustment_delay(struct tmio_mmc_host *host)
+{
+ struct renesas_sdhi *priv = host_to_priv(host);
+
+ if (!priv->info->tuning_delay)
+ return;
+
+ if (host->mmc->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330)
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, 0x0);
+ else
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, 0x1);
+}
+
+static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ struct renesas_sdhi *priv = host_to_priv(host);
+ struct pinctrl_state *pin_state;
+ int ret;
+
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_330:
+ pin_state = priv->pins_default;
+ break;
+ case MMC_SIGNAL_VOLTAGE_180:
+ pin_state = priv->pins_uhs;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * If anything is missing, assume signal voltage is fixed at
+ * 3.3V and succeed/fail accordingly.
+ */
+ if (IS_ERR(priv->pinctrl) || IS_ERR(pin_state))
+ return ios->signal_voltage ==
+ MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL;
+
+ ret = mmc_regulator_set_vqmmc(host->mmc, ios);
+ if (ret < 0)
+ return ret;
+
+ renesas_sdhi_set_hw_adjustment_delay(host);
+
+ return pinctrl_select_state(priv->pinctrl, pin_state);
+}
+
static unsigned int renesas_sdhi_init_tuning(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv;
diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
index 84b1b38ca465..d056c3586e6f 100644
--- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
@@ -237,6 +237,12 @@ static const struct renesas_sdhi_hw_info sdhi_hw_info_generic = {
.max_divider = 512,
};

+static const struct renesas_sdhi_hw_info sdhi_hw_info_rzg2l = {
+ .clk_mask = 0x80000080,
+ .max_divider = 512,
+ .tuning_delay = 1,
+};
+
static const struct renesas_sdhi_of_data_with_quirks of_r8a7795_compatible = {
.of_data = &of_data_rcar_gen3,
.quirks = &sdhi_quirks_bad_taps2367,
@@ -270,7 +276,7 @@ static const struct renesas_sdhi_of_data_with_quirks of_r8a77990_compatible = {
static const struct renesas_sdhi_of_data_with_quirks of_rzg2l_compatible = {
.of_data = &of_data_rcar_gen3,
.quirks = &sdhi_quirks_rzg2l,
- .info = &sdhi_hw_info_generic,
+ .info = &sdhi_hw_info_rzg2l,
};

static const struct renesas_sdhi_of_data_with_quirks of_rcar_gen3_compatible = {
--
2.43.0