RE: [PATCH v19 12/12] mmc: renesas_sdhi: Add HS400 enhanced strobe support for RZ/G3L
From: Biju Das
Date: Fri Jul 10 2026 - 05:36:26 EST
Hi All,
> -----Original Message-----
> From: Biju <biju.das.au@xxxxxxxxx>
> 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 <biju.das.jz@xxxxxxxxxxxxxx>
>
> 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 <biju.das.jz@xxxxxxxxxxxxxx>
> ---
> 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