RE: [PATCH v19 05/12] mmc: renesas_sdhi: Add tuning delay support for RZ/G2L

Biju Das <[email protected]>
Newsgroups org.kernel.vger.linux-renesas-soc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-mmc
Message-ID <TY3PR01MB1134675EB2523D3750C08DA2A86FD2@TY3PR01MB11346.jpnprd01.prod.outlook.com>
Hi All,

> -----Original Message-----
> From: Biju <[email protected]>
> Sent: 09 July 2026 20:29
> Subject: [PATCH v19 05/12] mmc: renesas_sdhi: Add tuning delay support for RZ/G2L
> 
> From: Biju Das <[email protected]>
> 
> Some SoCs, starting with RZ/G2L, require a hardware adjustment delay to be written to SCC_TMPPORT2 when
> switching signal voltage during tuning. The register value differs by voltage: 0x1 for 1.8 V and 0x0 for
> 3.3 V.
> 
> Introduce TMIO_MMC_TUNING_DELAY flag (bit 13) in tmio.h to identify controllers that need this behaviour.
> Add renesas_sdhi_set_hw_adjustment_delay(), which writes the appropriate value to SCC_TMPPORT2 when the
> flag is set, and call it from
> renesas_sdhi_start_signal_voltage_switch() after the regulator is configured. Additionally, reset
> SCC_TMPPORT2 to 0 at the start of
> renesas_sdhi_execute_tuning() when the flag is set and tap_num is 8.
> 
> Introduce a dedicated of_data_rz_g2l descriptor carrying the new flag alongside RZ/G2L-specific
> capabilities, and wire of_rzg2l_compatible to it instead of the generic R-Car Gen3 descriptor.
> 
> Signed-off-by: Biju Das <[email protected]>
> ---
> v18->v19:
>  * No change.
> v18:
>  * New patch.
> ---
>  drivers/mmc/host/renesas_sdhi_core.c          | 86 +++++++++++--------
>  drivers/mmc/host/renesas_sdhi_internal_dmac.c | 21 ++++-
>  include/linux/platform_data/tmio.h            |  3 +
>  3 files changed, 75 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
> index 5c478995d660..832a7a7be725 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);

Looks sashiko's comment is false positive as after the tuning only we set HS400
registers. So it it is safe to unconditional writes here.

[1] https://sashiko.dev/#/patchset/20260709192916.630794-1-biju.das.jz%40bp.renesas.com

 }
> +
> +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;
> @@ -709,6 +724,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);

Same here.

Cheers,
Biju

> +
>  	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 2bf354331b2d..8476678d47a6 100644
> --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
> +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
> @@ -142,6 +142,25 @@ static const struct renesas_sdhi_of_data of_data_rcar_gen3_no_sdh_fallback = {
>  	.max_divider	= SDHI_MAX_DIVIDER_DEFAULT,
>  };
> 
> +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,
> +};
> +
>  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 }, @@ -263,7 +282,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 27ea21c00419..868a21842fa5 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.