[PATCH v23 06/14] mmc: renesas_sdhi: Add tuning delay support for RZ/G2L
Biju <[email protected]> Thu, 30 Jul 2026 12:31:44 +0100
| Newsgroups | org.kernel.vger.linux-mmc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-renesas-soc |
|---|---|
| Message-ID | <[email protected]> |
From: Biju Das <[email protected]> RZ/G2L and later SoCs need a hardware adjustment delay written to SCC_TMPPORT2 on signal-voltage switch during tuning: 0x1 for 1.8V, 0x0 for 3.3V. Add a TMIO_MMC_TUNING_DELAY flag and renesas_sdhi_set_hw_adjustment_delay(), called from renesas_sdhi_start_signal_voltage_switch() after the regulator is set, and reset SCC_TMPPORT2 to 0 at the start of renesas_sdhi_execute_tuning() when the flag is set and tap_num == 8. Add a dedicated of_data_rz_g2l descriptor with this flag and switch of_rzg2l_compatible to use it instead of the generic R-Car Gen3 descriptor. Signed-off-by: Biju Das <[email protected]> --- v22->v23: * No change. v21->v22: * Updated commit description. * Added a renesas_sdhi_set_hw_adjustment_delay() call to renesas_sdhi_init_tuning(). v20->v21: * Added clk_div_mask to RZ/G2L of_data. v19->v20: * No change. v18->v19: * No change. v18: * New patch. --- drivers/mmc/host/renesas_sdhi_core.c | 88 ++++++++++++------- drivers/mmc/host/renesas_sdhi_internal_dmac.c | 22 ++++- include/linux/platform_data/tmio.h | 3 + 3 files changed, 78 insertions(+), 35 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 5dcbb431e1e1..a0922bc9d4a5 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -256,40 +256,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 @@ -350,6 +316,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 (!(host->pdata->flags & TMIO_MMC_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; @@ -377,6 +392,8 @@ static unsigned int renesas_sdhi_init_tuning(struct tmio_mmc_host *host) sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, priv->scc_tappos); + renesas_sdhi_set_hw_adjustment_delay(host); + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); @@ -709,6 +726,9 @@ static int renesas_sdhi_execute_tuning(struct mmc_host *mmc, u32 opcode) if (!priv->tap_num) return 0; /* Tuning is not supported */ + if ((host->pdata->flags & TMIO_MMC_TUNING_DELAY) && priv->tap_num == 8) + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, 0); + if (priv->tap_num * 2 >= sizeof(priv->taps) * BITS_PER_BYTE) { dev_err(&host->pdev->dev, "Too many taps, please update 'taps' in tmio_mmc_host!\n"); diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 9bf7aa9bd867..1799c6106102 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -145,6 +145,26 @@ static const struct renesas_sdhi_of_data of_data_rcar_gen3_no_sdh_fallback = { .clk_div_mask = GENMASK(7, 0), }; +static const struct renesas_sdhi_of_data of_data_rz_g2l = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | + TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2 | + TMIO_MMC_64BIT_DATA_PORT | TMIO_MMC_TUNING_DELAY, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | + MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE, + .bus_shift = 2, + .scc_offset = 0x1000, + .taps = rcar_gen3_scc_taps, + .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), + /* DMAC can handle 32bit blk count but only 1 segment */ + .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, + .max_segs = 1, + .sdhi_flags = SDHI_FLAG_NEED_CLKH_FALLBACK, + .clk_mask = SDHI_CLK_MASK_DEFAULT, + .max_divider = SDHI_MAX_DIVIDER_DEFAULT, + .clk_div_mask = GENMASK(7, 0), +}; + static const u8 r8a7796_es13_calib_table[2][SDHI_CALIB_TABLE_MAX] = { { 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 15, 16, 16, 16, 16, 16, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25 }, @@ -266,7 +286,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, + .of_data = &of_data_rz_g2l, .quirks = &sdhi_quirks_rzg2l, }; diff --git a/include/linux/platform_data/tmio.h b/include/linux/platform_data/tmio.h index e4232934c7fe..abf4134a8bd8 100644 --- a/include/linux/platform_data/tmio.h +++ b/include/linux/platform_data/tmio.h @@ -50,6 +50,9 @@ /* Some controllers have a 64-bit wide data port register */ #define TMIO_MMC_64BIT_DATA_PORT BIT(12) +/* Some controllers have tuning delay */ +#define TMIO_MMC_TUNING_DELAY BIT(13) + struct tmio_mmc_data { void *chan_priv_tx; void *chan_priv_rx; -- 2.43.0