RE: [PATCH v18 11/12] mmc: renesas_sdhi: Add RZ/G3L HS400 support
Biju Das <[email protected]> Tue, 7 Jul 2026 12:10:42 +0000
| Newsgroups | org.kernel.vger.linux-mmc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-renesas-soc |
|---|---|
| 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