RE: [PATCH v19 05/12] mmc: renesas_sdhi: Add tuning delay support for RZ/G2L
Biju Das <[email protected]> Fri, 10 Jul 2026 08:42:02 +0000
| Newsgroups | org.kernel.vger.linux-mmc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-renesas-soc |
|---|---|
| Message-ID | <TY3PR01MB1134675EB2523D3750C08DA2A86FD2@TY3PR01MB11346.jpnprd01.prod.outlook.com> |
Hi All, > -----Original Message----- > From: Biju <[email protected]> > Sent: 09 July 2026 20:29 > Subject: [PATCH v19 05/12] mmc: renesas_sdhi: Add tuning delay support for RZ/G2L > > From: Biju Das <[email protected]> > > Some SoCs, starting with RZ/G2L, require a hardware adjustment delay to be written to SCC_TMPPORT2 when > switching signal voltage during tuning. The register value differs by voltage: 0x1 for 1.8 V and 0x0 for > 3.3 V. > > Introduce TMIO_MMC_TUNING_DELAY flag (bit 13) in tmio.h to identify controllers that need this behaviour. > Add renesas_sdhi_set_hw_adjustment_delay(), which writes the appropriate value to SCC_TMPPORT2 when the > flag is set, and call it from > renesas_sdhi_start_signal_voltage_switch() after the regulator is configured. Additionally, reset > SCC_TMPPORT2 to 0 at the start of > renesas_sdhi_execute_tuning() when the flag is set and tap_num is 8. > > Introduce a dedicated of_data_rz_g2l descriptor carrying the new flag alongside RZ/G2L-specific > capabilities, and wire of_rzg2l_compatible to it instead of the generic R-Car Gen3 descriptor. > > Signed-off-by: Biju Das <[email protected]> > --- > v18->v19: > * No change. > v18: > * New patch. > --- > drivers/mmc/host/renesas_sdhi_core.c | 86 +++++++++++-------- > drivers/mmc/host/renesas_sdhi_internal_dmac.c | 21 ++++- > include/linux/platform_data/tmio.h | 3 + > 3 files changed, 75 insertions(+), 35 deletions(-) > > diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c > index 5c478995d660..832a7a7be725 100644 > --- a/drivers/mmc/host/renesas_sdhi_core.c > +++ b/drivers/mmc/host/renesas_sdhi_core.c > @@ -256,40 +256,6 @@ static int renesas_sdhi_card_busy(struct mmc_host *mmc) > TMIO_STAT_DAT0); > } > > -static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, > - struct mmc_ios *ios) > -{ > - struct tmio_mmc_host *host = mmc_priv(mmc); > - struct renesas_sdhi *priv = host_to_priv(host); > - struct pinctrl_state *pin_state; > - int ret; > - > - switch (ios->signal_voltage) { > - case MMC_SIGNAL_VOLTAGE_330: > - pin_state = priv->pins_default; > - break; > - case MMC_SIGNAL_VOLTAGE_180: > - pin_state = priv->pins_uhs; > - break; > - default: > - return -EINVAL; > - } > - > - /* > - * If anything is missing, assume signal voltage is fixed at > - * 3.3V and succeed/fail accordingly. > - */ > - if (IS_ERR(priv->pinctrl) || IS_ERR(pin_state)) > - return ios->signal_voltage == > - MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL; > - > - ret = mmc_regulator_set_vqmmc(host->mmc, ios); > - if (ret < 0) > - return ret; > - > - return pinctrl_select_state(priv->pinctrl, pin_state); > -} > - > /* SCC registers */ > #define SH_MOBILE_SDHI_SCC_DTCNTL 0x000 > #define SH_MOBILE_SDHI_SCC_TAPSET 0x002 > @@ -350,6 +316,55 @@ static inline void sd_scc_write32(struct tmio_mmc_host *host, > writel(val, priv->scc_ctl + (addr << host->bus_shift)); } > > +static void renesas_sdhi_set_hw_adjustment_delay(struct tmio_mmc_host > +*host) { > + struct renesas_sdhi *priv = host_to_priv(host); > + > + if (!(host->pdata->flags & TMIO_MMC_TUNING_DELAY)) > + return; > + > + if (host->mmc->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) > + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, 0x0); > + else > + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, 0x1); Looks sashiko's comment is false positive as after the tuning only we set HS400 registers. So it it is safe to unconditional writes here. [1] https://sashiko.dev/#/patchset/20260709192916.630794-1-biju.das.jz%40bp.renesas.com } > + > +static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, > + struct mmc_ios *ios) > +{ > + struct tmio_mmc_host *host = mmc_priv(mmc); > + struct renesas_sdhi *priv = host_to_priv(host); > + struct pinctrl_state *pin_state; > + int ret; > + > + switch (ios->signal_voltage) { > + case MMC_SIGNAL_VOLTAGE_330: > + pin_state = priv->pins_default; > + break; > + case MMC_SIGNAL_VOLTAGE_180: > + pin_state = priv->pins_uhs; > + break; > + default: > + return -EINVAL; > + } > + > + /* > + * If anything is missing, assume signal voltage is fixed at > + * 3.3V and succeed/fail accordingly. > + */ > + if (IS_ERR(priv->pinctrl) || IS_ERR(pin_state)) > + return ios->signal_voltage == > + MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL; > + > + ret = mmc_regulator_set_vqmmc(host->mmc, ios); > + if (ret < 0) > + return ret; > + > + renesas_sdhi_set_hw_adjustment_delay(host); > + > + return pinctrl_select_state(priv->pinctrl, pin_state); } > + > static unsigned int renesas_sdhi_init_tuning(struct tmio_mmc_host *host) { > struct renesas_sdhi *priv; > @@ -709,6 +724,9 @@ 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); Same here. Cheers, Biju > + > if (priv->tap_num * 2 >= sizeof(priv->taps) * BITS_PER_BYTE) { > dev_err(&host->pdev->dev, > "Too many taps, please update 'taps' in tmio_mmc_host!\n"); diff --git > a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c > index 2bf354331b2d..8476678d47a6 100644 > --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c > +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c > @@ -142,6 +142,25 @@ static const struct renesas_sdhi_of_data of_data_rcar_gen3_no_sdh_fallback = { > .max_divider = SDHI_MAX_DIVIDER_DEFAULT, > }; > > +static const struct renesas_sdhi_of_data of_data_rz_g2l = { > + .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, > + .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, > + .bus_shift = 2, > + .scc_offset = 0x1000, > + .taps = rcar_gen3_scc_taps, > + .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), > + /* DMAC can handle 32bit blk count but only 1 segment */ > + .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, > + .max_segs = 1, > + .sdhi_flags = SDHI_FLAG_NEED_CLKH_FALLBACK, > + .clk_mask = SDHI_CLK_MASK_DEFAULT, > + .max_divider = SDHI_MAX_DIVIDER_DEFAULT, > +}; > + > static const u8 r8a7796_es13_calib_table[2][SDHI_CALIB_TABLE_MAX] = { > { 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 15, > 16, 16, 16, 16, 16, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25 }, @@ -263,7 +282,7 @@ static > const struct renesas_sdhi_of_data_with_quirks of_r8a77990_compatible = { }; > > static const struct renesas_sdhi_of_data_with_quirks of_rzg2l_compatible = { > - .of_data = &of_data_rcar_gen3, > + .of_data = &of_data_rz_g2l, > .quirks = &sdhi_quirks_rzg2l, > }; > > diff --git a/include/linux/platform_data/tmio.h b/include/linux/platform_data/tmio.h > index 27ea21c00419..868a21842fa5 100644 > --- a/include/linux/platform_data/tmio.h > +++ b/include/linux/platform_data/tmio.h > @@ -50,6 +50,9 @@ > /* Some controllers have a 64-bit wide data port register */ > #define TMIO_MMC_64BIT_DATA_PORT BIT(12) > > +/* Some controllers have tuning delay */ > +#define TMIO_MMC_TUNING_DELAY BIT(13) > + > struct tmio_mmc_data { > void *chan_priv_tx; > void *chan_priv_rx; > -- > 2.43.0