RE: [PATCH v19 12/12] mmc: renesas_sdhi: Add HS400 enhanced strobe support for RZ/G3L

Biju Das <[email protected]> Fri, 10 Jul 2026 09:27:26 +0000
Newsgroups org.kernel.vger.linux-mmc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-renesas-soc
Message-ID <TY3PR01MB11346F6F629176C46DEC3498D86FD2@TY3PR01MB11346.jpnprd01.prod.outlook.com>
Hi All,

> -----Original Message-----
> From: Biju <[email protected]>
> Sent: 09 July 2026 20:29
> Subject: [PATCH v19 12/12] mmc: renesas_sdhi: Add HS400 enhanced strobe support for RZ/G3L
> 
> From: Biju Das <[email protected]>
> 
> The RZ/G3L SoC supports HS400 enhanced strobe mode, which requires additional SCC register programming
> beyond the standard HS400 path.
> 
> Introduce a TMIO_MMC_HS400ES flag (bit 17) to identify controllers that support enhanced strobe. Add
> renesas_sdhi_hs400_enhanced_strobe(),
> which, when ios->enhanced_strobe is set, disables DTSEL in SCC_CKSEL, clears TAPEN in SCC_DTCNTL,
> programs SCC_TMPPORT3, sets HWADJ2 to 0xFF, enables the HS400 interface mode bit in CTL_SDIF_MODE, sets
> HS400EN2 in HS400MODE2, and sets both HS400EN and the new HS400MODE1_ENHANCED_STROBE bit (BIT(30)) in
> TMPPORT2. On exit from enhanced strobe, only the enhanced strobe bit is cleared. Register this callback
> as host->ops.hs400_enhanced_strobe for controllers carrying the TMIO_MMC_HS400ES flag.
> 
> Update renesas_sdhi_reset_hs400_mode() to also mask off HS400MODE1_ENHANCED_STROBE from TMPPORT2 when
> TMIO_MMC_HS400ES is set, ensuring a clean reset on mode exit.
> 
> Enable the TMIO_MMC_HS400ES flag in of_data_rzg3l to finalize support.
> 
> Signed-off-by: Biju Das <[email protected]>
> ---
> v18->v19:
>  * Updated commit description.
>  * HS400ES support is enabled based on of_data.
>  * Fixed the space in HS400ES comment block.
> v18:
>  * New patch.
> ---
>  drivers/mmc/host/renesas_sdhi_core.c          | 49 +++++++++++++++++--
>  drivers/mmc/host/renesas_sdhi_internal_dmac.c |  2 +-
>  include/linux/platform_data/tmio.h            |  3 ++
>  3 files changed, 49 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
> index ae6b7d8c5b98..894da06b0d2b 100644
> --- a/drivers/mmc/host/renesas_sdhi_core.c
> +++ b/drivers/mmc/host/renesas_sdhi_core.c
> @@ -308,7 +308,8 @@ static int renesas_sdhi_card_busy(struct mmc_host *mmc)
>  #define SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQUP	BIT(24)
>  #define SH_MOBILE_SDHI_SCC_SMPCMP_CMD_ERR	(BIT(8) | BIT(24))
> 
> -#define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN	BIT(31)
> +#define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN		BIT(31)
> +#define SH_MOBILE_SDHI_SCC_HS400MODE1_ENHANCED_STROBE	BIT(30)
> 
>  /* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT4 register */
>  #define SH_MOBILE_SDHI_SCC_TMPPORT4_DLL_ACC_START	BIT(0)
> @@ -589,6 +590,8 @@ static void renesas_sdhi_adjust_hs400_mode_disable(struct tmio_mmc_host *host)
> static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host,
>  					  struct renesas_sdhi *priv)
>  {
> +	u32 val = ~(SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN |
> +host->pdata->osel_tmpout);
> +
>  	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
>  			sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
> 
> @@ -598,10 +601,11 @@ static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host,
> 
>  	sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, priv->scc_tappos);
> 
> +	if (host->pdata->flags & TMIO_MMC_HS400ES)
> +		val &= ~SH_MOBILE_SDHI_SCC_HS400MODE1_ENHANCED_STROBE;
> +
>  	sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2,
> -		       ~(SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN |
> -			 host->pdata->osel_tmpout) &
> -			sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2));
> +		       val & 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); @@ -806,6 +810,41 @@ static int
> renesas_sdhi_execute_tuning(struct mmc_host *mmc, u32 opcode)
>  	return ret;
>  }
> 
> +static void renesas_sdhi_hs400_enhanced_strobe(struct mmc_host *mmc,
> +					       struct mmc_ios *ios)
> +{

Looks it is false positive as mentioned by sashiko[1], I can enter
and exit suspend to RAM without any issues. On this platform during
STR all power supplies down except PMIC which puts the DDR into retention mode.

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


root@smarc-rzg3l:~# cat /sys/kernel/debug/mmc0/ios
clock:          150000000 Hz
actual clock:   150000000 Hz
vdd:            21 (3.3 ~ 3.4 V)
bus mode:       2 (push-pull)
chip select:    0 (don't care)
power mode:     2 (on)
bus width:      3 (8 bits)
timing spec:    10 (mmc HS400 enhanced strobe)
signal voltage: 1 (1.80 V)
driver type:    1 (driver type A)

root@smarc-rzg3l:~# mount -t auto /dev/mmcblk0p2 /media/
[   75.719668] EXT4-fs (mmcblk0p2): recovery complete
[   75.725806] EXT4-fs (mmcblk0p2): mounted filesystem 3a87d114-78ab-4be0-8fac-d055b25f4bd0 r/w with ordered data mode. Quota mode: none.
root@smarc-rzg3l:~#

echo TEST > /media/1.txt

root@smarc-rzg3l:~# echo mem > /sys/power/state
[  105.965920] PM: suspend entry (deep)
[  105.980163] Filesystems sync: 0.009 seconds
[  105.992243] Freezing user space processes
[  106.001271] Freezing user space processes completed (elapsed 0.003 seconds)
[  106.008260] OOM killer disabled.
[  106.011496] Freezing remaining freezable tasks
[  106.017309] Freezing remaining freezable tasks completed (elapsed 0.001 seconds)
[  106.024713] printk: Suspending console(s) (use no_console_suspend to debug)
NOTICE:  BL2: v2.10.5(release):2.10.5/rzg3l_1.0.1_rc2
NOTICE:  BL2: Built : 09:19:29, Jun 16 2026
INFO:    BL2: Doing platform setup
INFO:    Configuring TrustZone Controller
INFO:    Total 3 regions set.
INFO:    Configuring TrustZone Controller
INFO:    Total 1 regions set.
INFO:    Configuring TrustZone Controller
INFO:    Total 1 regions set.
INFO:    Loading image id=39 at address 0x44428
INFO:    Image id=39 loaded: 0x44428 - 0x45428
INFO:    DDR: Retention Exit (Rev. 02.05)
NOTICE:  BL2: SYS_LSI_MODE: 0x12061
NOTICE:  BL2: SYS_LSI_DEVID: 0x87d9447
INFO:    BL2: Skip loading image id 3
INFO:    BL2: Skip loading image id 5
NOTICE:  BL2: Booting BL31
INFO:    Entry point address = 0x44000000
INFO:    SPSR = 0x3cd
[  106.061768] renesas-gbeth 11c30000.ethernet end0: Link is Down
[  106.065811] Disabling non-boot CPUs ...
[  106.068100] psci: CPU3 killed (polled 4 ms)
[  106.071161] psci: CPU2 killed (polled 4 ms)
[  106.075159] psci: CPU1 killed (polled 4 ms)
[  106.076800] Enabling non-boot CPUs ...
[  106.077070] Detected VIPT I-cache on CPU1
[  106.077135] GICv3: CPU1: found redistributor 100 region 0:0x0000000012460000
[  106.077182] CPU1: Booted secondary processor 0x0000000100 [0x412fd050]
[  106.078267] CPU1 is up
[  106.078429] Detected VIPT I-cache on CPU2
[  106.078469] GICv3: CPU2: found redistributor 200 region 0:0x0000000012480000
[  106.078502] CPU2: Booted secondary processor 0x0000000200 [0x412fd050]
[  106.079474] CPU2 is up
[  106.079661] Detected VIPT I-cache on CPU3
[  106.079708] GICv3: CPU3: found redistributor 300 region 0:0x00000000124a0000
[  106.079751] CPU3: Booted secondary processor 0x0000000300 [0x412fd050]
[  106.080888] CPU3 is up
[  106.095014] dwmac4: Master AXI performs fixed burst length
[  106.095061] renesas-gbeth 11c30000.ethernet end0: No Safety Features support found
[  106.095104] renesas-gbeth 11c30000.ethernet end0: IEEE 1588-2008 Advanced Timestamp supported
[  106.096191] renesas-gbeth 11c30000.ethernet end0: configuring for phy/rgmii-id link mode
[  106.111005] dwmac4: Master AXI performs fixed burst length
[  106.111035] renesas-gbeth 11c40000.ethernet end1: No Safety Features support found
[  106.111066] renesas-gbeth 11c40000.ethernet end1: IEEE 1588-2008 Advanced Timestamp supported
[  106.112144] renesas-gbeth 11c40000.ethernet end1: configuring for phy/rgmii-id link mode
[  106.283664] OOM killer enabled.
[  106.286800] Restarting tasks: Starting
[  106.292440] Restarting tasks: Done
[  106.296062] random: crng reseeded on system resumption
[  106.301515] PM: suspend exit
[  109.062679] renesas-gbeth 11c30000.ethernet end0: Link is Up - 1Gbps/Full - flow control rx/tx

root@smarc-rzg3l:~# cat /media/1.txt
TEST
root@smarc-rzg3l:~# cat /sys/kernel/debug/mmc0/ios
clock:          150000000 Hz
actual clock:   150000000 Hz
vdd:            21 (3.3 ~ 3.4 V)
bus mode:       2 (push-pull)
chip select:    0 (don't care)
power mode:     2 (on)
bus width:      3 (8 bits)
timing spec:    10 (mmc HS400 enhanced strobe)
signal voltage: 1 (1.80 V)
driver type:    1 (driver type A)
root@smarc-rzg3l:~#


> +	struct tmio_mmc_host *host = mmc_priv(mmc);
> +	struct renesas_sdhi *priv = host_to_priv(host);
> +	u32 val = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2);
> +
> +	if (!(host->pdata->flags & TMIO_MMC_HS400ES))
> +		return;
> +
> +	if (ios->enhanced_strobe) {
> +		sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL,
> +			       ~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL &
> +			       sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL));

OK,  hardware manual mention this "When this bit is switched, stop the SD clock output from the SD/MMC host interface (set
SCLKEN in SD_CLK_CTRL to 0)."

So, I will disable CLK_CTL_SCLKEN before changing these registers.

Cheers,
Biju

> +
> +		sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
> +			       ~SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN &
> +			       sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL));
> +
> +		sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT3, BIT(8) | BIT(9));
> +		sd_scc_write32(host, priv, RZG3L_SDHI_SCC_HWADJ2, 0xFF);
> +		sd_ctrl_write16(host, CTL_SDIF_MODE, SDIF_MODE_HS400 |
> +				sd_ctrl_read16(host, CTL_SDIF_MODE));
> +		sd_scc_write32(host, priv, RZG3L_SDHI_SCC_HS400MODE2,
> +			       RZG3L_SDHI_SCC_HS400MODE2_HS400EN2);
> +
> +		val |= SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN |
> +		       SH_MOBILE_SDHI_SCC_HS400MODE1_ENHANCED_STROBE;
> +	} else {
> +		val &= ~SH_MOBILE_SDHI_SCC_HS400MODE1_ENHANCED_STROBE;
> +	}
> +
> +	sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, val); }
> +
>  static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_4tap)  {
>  	struct renesas_sdhi *priv = host_to_priv(host); @@ -1358,6 +1397,8 @@ int
> renesas_sdhi_probe(struct platform_device *pdev,
>  		host->ops.prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning;
>  		host->ops.hs400_downgrade = renesas_sdhi_disable_scc;
>  		host->ops.hs400_complete = renesas_sdhi_hs400_complete;
> +		if (host->pdata->flags & TMIO_MMC_HS400ES)
> +			host->ops.hs400_enhanced_strobe =
> +renesas_sdhi_hs400_enhanced_strobe;
>  	}
> 
>  	sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask_all); diff --git
> a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
> index 4000673ed7f8..ea993197aff2 100644
> --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
> +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
> @@ -175,7 +175,7 @@ static const struct renesas_sdhi_of_data of_data_rzg3l = {
>  			  TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2 |
>  			  TMIO_MMC_64BIT_DATA_PORT | TMIO_MMC_TUNING_DELAY |
>  			  TMIO_MMC_INTERNAL_DIVIDER | TMIO_MMC_HWADJ |
> -			  TMIO_MMC_HS400MODE2,
> +			  TMIO_MMC_HS400MODE2 | TMIO_MMC_HS400ES,
>  	.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 8a5dc18d43da..75d32c8ee57a 100644
> --- a/include/linux/platform_data/tmio.h
> +++ b/include/linux/platform_data/tmio.h
> @@ -62,6 +62,9 @@
>  /* Some controllers have HS400MODE2 */
>  #define TMIO_MMC_HS400MODE2		BIT(16)
> 
> +/* Some controllers have HS400ES */
> +#define TMIO_MMC_HS400ES		BIT(17)
> +
>  struct tmio_mmc_data {
>  	void				*chan_priv_tx;
>  	void				*chan_priv_rx;
> --
> 2.43.0