RE: [PATCH v18 11/12] mmc: renesas_sdhi: Add RZ/G3L HS400 support

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

> -----Original Message-----
> From: Biju <[email protected]>
> Sent: 22 June 2026 16:56
> Subject: [PATCH v18 11/12] mmc: renesas_sdhi: Add RZ/G3L HS400 support
> 
> From: Biju Das <[email protected]>
> 
> Add HS400 support for RZ/G3L SoC.
> 
> RZ/G3L requires a dedicated HS400 enable register (SDm_SCC_HS400MODE2 at offset 0x020) in addition to the
> existing TMPPORT2 path used by R-Car. Introduce a TMIO_MMC_HS400MODE2 flag (bit 16) to identify
> controllers that need this second register.
> When the flag is set, renesas_sdhi_hs400_complete() additionally sets
> HS400EN2 in HS400MODE2, and renesas_sdhi_reset_hs400_mode() clears it on exit. During tuning, when both
> TMIO_MMC_TUNING_DELAY and
> TMIO_MMC_HS400MODE2 are set, the lower 16 bits of TMPPORT2 (TMPOUT) are masked off while preserving the
> upper bits, replacing the previous unconditional write of zero.
> 
> In renesas_sdhi_clk_update(), force clkh_shift to 1 when TMIO_MMC_INTERNAL_DIVIDER is active and the
> timing mode is HS400, allowing the SoC's internal divider to be bypassed for that mode. Adjust
> renesas_sdhi_set_clock() to halve actual_clock when TMIO_MMC_INTERNAL_DIVIDER is set, and guard the clock
> divider calculation against a zero clock value.
> 
> Enable TMIO_MMC_HS400MODE2 in of_data_rzg3l, completing HS400 support for RZ/G3L.
> 
> Signed-off-by: Biju Das <[email protected]>
> ---
> v18:
>  * New patch.
> ---
>  drivers/mmc/host/renesas_sdhi_core.c          | 33 ++++++++++++++++---
>  drivers/mmc/host/renesas_sdhi_internal_dmac.c |  3 +-
>  include/linux/platform_data/tmio.h            |  3 ++
>  3 files changed, 33 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
> index 42645480b62f..efc8bd1d2422 100644
> --- a/drivers/mmc/host/renesas_sdhi_core.c
> +++ b/drivers/mmc/host/renesas_sdhi_core.c
> @@ -186,8 +186,13 @@ 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 ((host->pdata->flags & TMIO_MMC_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);
>  }
> @@ -206,7 +211,8 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
>  		goto out;
>  	}
> 
> -	host->mmc->actual_clock = renesas_sdhi_clk_update(host, new_clock);
> +	host->mmc->actual_clock = renesas_sdhi_clk_update(host, new_clock) /
> +		(host->pdata->flags & TMIO_MMC_INTERNAL_DIVIDER ? 2 : 1);
>  	clock = host->mmc->actual_clock / host->pdata->max_divider;
> 
>  	/*
> @@ -227,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));

Ref: https://sashiko.dev/#/patchset/20260622155610.184271-1-biju.das.jz%40bp.renesas.com

I will drop checking the clock. Also, I have reported an issue with divider control values in
Hardware manual for HS400 mode. I am planning to defer HS400 support, till I get response from
them. I guess it is OK for you.

Cheers,
Biju



> 
>  	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clock); @@ -274,6 +280,7 @@ static int
> renesas_sdhi_card_busy(struct mmc_host *mmc)
>  #define SH_MOBILE_SDHI_SCC_TMPPORT5	0x018
>  #define SH_MOBILE_SDHI_SCC_TMPPORT6	0x01A
>  #define SH_MOBILE_SDHI_SCC_TMPPORT7	0x01C
> +#define RZG3L_SDHI_SCC_HS400MODE2	0x020
>  #define RZG3L_SDHI_SCC_HWADJ4		0x022
> 
>  #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN		BIT(0)
> @@ -306,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) @@ -441,6 +449,10 @@ static void
> renesas_sdhi_hs400_complete(struct mmc_host *mmc)
>  			host->pdata->osel_tmpout) |
>  			sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2));
> 
> +	if (host->pdata->flags & TMIO_MMC_HS400MODE2)
> +		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,
> @@ -582,6 +594,9 @@ static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host,
>  			 host->pdata->osel_tmpout) &
>  			sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2));
> 
> +	if (host->pdata->flags & TMIO_MMC_HS400MODE2)
> +		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);
> 
> @@ -739,8 +754,16 @@ 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 ((host->pdata->flags & TMIO_MMC_TUNING_DELAY) && priv->tap_num == 8) {
> +		u32 val = 0;
> +
> +		if (host->pdata->flags & TMIO_MMC_HS400MODE2) {
> +			val = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2);
> +			val &= ~GENMASK(15, 0); /* TMPOUT MASK */
> +		}
> +
> +		sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, val);
> +	}
> 
>  	if (priv->tap_num * 2 >= sizeof(priv->taps) * BITS_PER_BYTE) {
>  		dev_err(&host->pdev->dev,
> diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
> b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
> index 709351693efa..bce8f4bb6cf2 100644
> --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
> +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
> @@ -175,7 +175,8 @@ static const struct renesas_sdhi_of_data of_data_rzg3l = {
>  	.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 |
> -			  TMIO_MMC_INTERNAL_DIVIDER | TMIO_MMC_HWADJ2,
> +			  TMIO_MMC_INTERNAL_DIVIDER | TMIO_MMC_HWADJ2 |
> +			  TMIO_MMC_HS400MODE2,
>  	.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,
> diff --git a/include/linux/platform_data/tmio.h b/include/linux/platform_data/tmio.h
> index 8b4032b24d36..fe8cdc057e5a 100644
> --- a/include/linux/platform_data/tmio.h
> +++ b/include/linux/platform_data/tmio.h
> @@ -59,6 +59,9 @@
>  /* Some controllers have hw adjustment delay */
>  #define TMIO_MMC_HWADJ2			BIT(15)
> 
> +/* Some controllers have HS400mode2  */
> +#define TMIO_MMC_HS400MODE2		BIT(16)
> +
>  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.