[PATCH v20 12/12] mmc: renesas_sdhi: Add HS400 enhanced strobe support for RZ/G3L
Biju <[email protected]> Mon, 13 Jul 2026 18:51:53 +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]> 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]> --- v19->v20: * SD_CLK_CTRL clk enable turned off before updating SCC_CKSEL_DTSEL register. 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 | 55 +++++++++++++++++-- drivers/mmc/host/renesas_sdhi_internal_dmac.c | 2 +- include/linux/platform_data/tmio.h | 3 + 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 4cab7a85d517..5d9a3dc814c7 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -311,7 +311,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) @@ -592,6 +593,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)); @@ -601,10 +604,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); @@ -809,6 +813,47 @@ 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) +{ + 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_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); + + 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)); + + 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_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); + + 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); @@ -1361,6 +1406,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