* [PATCH v25 01/11] dt-bindings: mmc: renesas,sdhi: Document RZ/G3L (r9a08g046) SoC
2026-10-28 12:51 [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Biju Das
@ 2026-10-28 12:51 ` Biju Das
2026-10-28 12:51 ` [PATCH v25 02/11] mmc: renesas_sdhi: Clean up whitespace and add OF table sentinels Biju Das
` (11 subsequent siblings)
12 siblings, 0 replies; 22+ messages in thread
From: Biju Das @ 2026-10-28 12:51 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Wolfram Sang, Philipp Zabel
Cc: linux-mmc, devicetree, linux-kernel, linux-renesas-soc, Biju Das,
Conor Dooley
From: Biju Das <biju.das.jz@bp.renesas.com>
Document the RZ/G3L (r9a08g046) SDHI controller. The RZ/G3L SDHI
controller is similar to RZ/G2L but has five clocks (core, clkh,
cd, aclkm, aclks) and three resets (rst, axim, axis), so update the
clocks/clock-names maximum to 5 and resets/reset-names maximum to 3.
It also has an internal divider for all modes except HS400, with a
maximum division ratio of 2048 compared to 512 on other SoCs. Because
of this divider, make max-frequency required so that it is always
defined in DT.
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v24->v25:
* Updated commit description.
* Added max-frequency is a required property for SoCs with internal
divider.
* Retained the tags as the change is trivial.
v23->v24:
* No change.
v22->v23:
* No change.
v21->v22:
* No change.
v20->v21:
* No change.
v19->v20:
* No change.
v18->v19:
* Updated commit description
* Updated clock and reset description with AXI master and AXI slave
* Added else condition for reset and reset-names.
* Renamed aclk->aclkm and reordered the axi clocks similar to resets.
* Retained the tag as the changes are trivial.
v17->v18:
* No change.
v1->v17:
* Collected tag.
---
.../devicetree/bindings/mmc/renesas,sdhi.yaml | 109 ++++++++++++++++-----
1 file changed, 82 insertions(+), 27 deletions(-)
diff --git a/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml b/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml
index 4d66966ce290..2bc74288d933 100644
--- a/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml
+++ b/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml
@@ -18,6 +18,7 @@ properties:
- renesas,sdhi-r7s9210 # SH-Mobile AG5
- renesas,sdhi-r8a73a4 # R-Mobile APE6
- renesas,sdhi-r8a7740 # R-Mobile A1
+ - renesas,sdhi-r9a08g046 # RZ/G3L
- renesas,sdhi-r9a09g057 # RZ/V2H(P)
- renesas,sdhi-sh73a0 # R-Mobile APE6
- items:
@@ -86,11 +87,11 @@ properties:
clocks:
minItems: 1
- maxItems: 4
+ maxItems: 5
clock-names:
minItems: 1
- maxItems: 4
+ maxItems: 5
dmas:
minItems: 4
@@ -116,7 +117,12 @@ properties:
maxItems: 1
resets:
- maxItems: 1
+ minItems: 1
+ maxItems: 3
+
+ reset-names:
+ minItems: 1
+ maxItems: 3
pinctrl-0:
minItems: 1
@@ -155,60 +161,107 @@ allOf:
properties:
compatible:
contains:
- enum:
- - renesas,sdhi-r9a09g057
- - renesas,rzg2l-sdhi
+ const: renesas,sdhi-r9a08g046
then:
properties:
clocks:
items:
- description: IMCLK, SDHI channel main clock1.
- description: CLK_HS, SDHI channel High speed clock which operates
- 4 times that of SDHI channel main clock1.
+ 2 times that of SDHI channel main clock1.
- description: IMCLK2, SDHI channel main clock2. When this clock is
turned off, external SD card detection cannot be
detected.
- - description: ACLK, SDHI channel bus clock.
+ - description: IACLKM, SDHI channel AXI master bus clock.
+ - description: IACLKS, SDHI channel AXI slave bus clock.
clock-names:
items:
- const: core
- const: clkh
- const: cd
- - const: aclk
+ - const: aclkm
+ - const: aclks
+ resets:
+ items:
+ - description: rst, Core reset.
+ - description: axim, SDHI channel AXI master bus reset.
+ - description: axis, SDHI channel AXI slave bus reset.
+ reset-names:
+ items:
+ - const: rst
+ - const: axim
+ - const: axis
required:
- clock-names
- resets
+ - reset-names
+ - max-frequency
else:
+ properties:
+ resets:
+ maxItems: 1
+ reset-names:
+ maxItems: 1
if:
properties:
compatible:
contains:
enum:
- - renesas,rcar-gen2-sdhi
- - renesas,rcar-gen3-sdhi
- - renesas,rcar-gen4-sdhi
+ - renesas,sdhi-r9a09g057
+ - renesas,rzg2l-sdhi
then:
properties:
clocks:
- minItems: 1
- maxItems: 3
- clock-names:
- minItems: 1
- uniqueItems: true
items:
- - const: core
- - enum: [ clkh, cd ]
- - const: cd
- else:
- properties:
- clocks:
- minItems: 1
- maxItems: 2
+ - description: IMCLK, SDHI channel main clock1.
+ - description: CLK_HS, SDHI channel High speed clock which operates
+ 4 times that of SDHI channel main clock1.
+ - description: IMCLK2, SDHI channel main clock2. When this clock is
+ turned off, external SD card detection cannot be
+ detected.
+ - description: ACLK, SDHI channel bus clock.
clock-names:
- minItems: 1
items:
- const: core
+ - const: clkh
- const: cd
+ - const: aclk
+ resets:
+ maxItems: 1
+ required:
+ - clock-names
+ - resets
+ else:
+ if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - renesas,rcar-gen2-sdhi
+ - renesas,rcar-gen3-sdhi
+ - renesas,rcar-gen4-sdhi
+ then:
+ properties:
+ clocks:
+ minItems: 1
+ maxItems: 3
+ clock-names:
+ minItems: 1
+ uniqueItems: true
+ items:
+ - const: core
+ - enum: [ clkh, cd ]
+ - const: cd
+ else:
+ properties:
+ clocks:
+ minItems: 1
+ maxItems: 2
+ clock-names:
+ minItems: 1
+ items:
+ - const: core
+ - const: cd
- if:
properties:
@@ -247,7 +300,9 @@ allOf:
properties:
compatible:
contains:
- const: renesas,sdhi-r9a09g057
+ enum:
+ - renesas,sdhi-r9a08g046
+ - renesas,sdhi-r9a09g057
then:
properties:
vqmmc-regulator:
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH v25 02/11] mmc: renesas_sdhi: Clean up whitespace and add OF table sentinels
2026-10-28 12:51 [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Biju Das
2026-10-28 12:51 ` [PATCH v25 01/11] dt-bindings: mmc: renesas,sdhi: Document RZ/G3L (r9a08g046) SoC Biju Das
@ 2026-10-28 12:51 ` Biju Das
2026-10-28 12:51 ` [PATCH v25 03/11] mmc: renesas_sdhi: Add clk_mask to support wider clock dividers Biju Das
` (10 subsequent siblings)
12 siblings, 0 replies; 22+ messages in thread
From: Biju Das @ 2026-10-28 12:51 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Wolfram Sang, Philipp Zabel
Cc: linux-mmc, devicetree, linux-kernel, linux-renesas-soc, Biju Das
From: Biju Das <biju.das.jz@bp.renesas.com>
Clean up coding style inconsistencies across the Renesas SDHI host driver
files. Remove redundant internal spacing in the struct definitions and
static initializers to enforce a single space separator or uniform tabs,
aligning the code with standard kernel formatting guidelines.
While at it, add a "Sentinel." comment block to the empty terminating
entries of the Open Firmware (OF) device matching tables to improve
code readability and explicitly mark the table boundaries.
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v24->v25:
* Restored struct of_default_cfg.
v23->v24:
* No change.
v22->v23:
* No change.
v21->v22:
* No change.
v20->v21:
* No change.
v19->v20:
* No change.
v18->v19:
* Updated commit description.
v17->v18:
* Merged patch#4 and #5
* Updated commit description
* Annotate the empty sentinel entries in the OF match tables with a
"Sentinel." comment for clarity.
* Retained the tag as it is trivial cleanups.
v1->v17:
* No change.
---
drivers/mmc/host/renesas_sdhi.h | 2 +-
drivers/mmc/host/renesas_sdhi_internal_dmac.c | 6 +++---
drivers/mmc/host/renesas_sdhi_sys_dmac.c | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index afc36a407c2c..09bf9b24a8c3 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -25,7 +25,7 @@ struct renesas_sdhi_scc {
struct renesas_sdhi_of_data {
unsigned long tmio_flags;
- u32 tmio_ocr_mask;
+ u32 tmio_ocr_mask;
unsigned long capabilities;
unsigned long capabilities2;
enum dma_slave_buswidth dma_buswidth;
diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
index 033d8cd92726..45e0d8f5c64d 100644
--- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
@@ -270,8 +270,8 @@ static const struct renesas_sdhi_of_data_with_quirks of_rcar_gen3_nohs400_compat
};
static const struct renesas_sdhi_of_data_with_quirks of_rza2_compatible = {
- .of_data = &of_data_rza2,
- .quirks = &sdhi_quirks_fixed_addr,
+ .of_data = &of_data_rza2,
+ .quirks = &sdhi_quirks_fixed_addr,
};
static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
@@ -292,7 +292,7 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
{ .compatible = "renesas,rzg2l-sdhi", .data = &of_rzg2l_compatible, },
{ .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,rcar-gen4-sdhi", .data = &of_rcar_gen3_compatible, },
- {},
+ { /* Sentinel. */ }
};
MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match);
diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
index c7df4da9e865..615bbc86930d 100644
--- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
@@ -88,7 +88,7 @@ static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = {
{ .compatible = "renesas,rcar-gen1-sdhi", .data = &of_rcar_gen1_compatible, },
{ .compatible = "renesas,rcar-gen2-sdhi", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-shmobile" },
- {},
+ { /* Sentinel. */ }
};
MODULE_DEVICE_TABLE(of, renesas_sdhi_sys_dmac_of_match);
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH v25 03/11] mmc: renesas_sdhi: Add clk_mask to support wider clock dividers
2026-10-28 12:51 [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Biju Das
2026-10-28 12:51 ` [PATCH v25 01/11] dt-bindings: mmc: renesas,sdhi: Document RZ/G3L (r9a08g046) SoC Biju Das
2026-10-28 12:51 ` [PATCH v25 02/11] mmc: renesas_sdhi: Clean up whitespace and add OF table sentinels Biju Das
@ 2026-10-28 12:51 ` Biju Das
2026-11-11 10:07 ` Wolfram Sang
2026-10-28 12:51 ` [PATCH v25 04/11] mmc: renesas_sdhi: Add max_divider field to support SoC-specific clock ranges Biju Das
` (9 subsequent siblings)
12 siblings, 1 reply; 22+ messages in thread
From: Biju Das @ 2026-10-28 12:51 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Wolfram Sang, Philipp Zabel
Cc: linux-mmc, devicetree, linux-kernel, linux-renesas-soc, Biju Das
From: Biju Das <biju.das.jz@bp.renesas.com>
The clock divider on the RZ/G3L SoC is 11 bits wide, which needs a
clock mask of 0x200000200 in renesas_sdhi_set_clock() instead of the
hardcoded 0x80000080 used so far.
Add a u64 clk_mask field to struct renesas_sdhi_of_data and struct
tmio_mmc_data so SoC-specific match data can supply its own mask, and
widen the clk and clock variables in renesas_sdhi_set_clock() from
u32 to u64 to hold it.
While at it, clamp the initial clock value to a minimum of 1. If
actual_clock / 512 evaluates to 0, the loop condition
"new_clock + clk_margin >= (clock << 1)" is always true, and the
loop never terminates.
In probe, copy clk_mask from the OF data and fall back to
SDHI_CLK_MASK_DEFAULT when none is provided, so existing
SoCs keep their current behaviour.
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v24->v25:
* Updated commit header and description.
* Dropped initializing clk_mask as it uses the default value.
* Added suffix ULL to macro SDHI_CLK_MASK_DEFAULT.
* Fixed a very low or zero clock rate from the clock provider that causes
an infinite loop in `renesas_sdhi_set_clock` by max operator.
v23->v24:
* No change.
v22->v23:
* No change.
v21->v22:
* No change.
v20->v21:
* No change.
v19->v20:
* Replaced the check mmd->clk_mask with mmc_data->clk_mask and moved
the code after assignment of variable mmd, this ensures assigning
the default values for non-DT platforms and DT platforms with no
device data.
v18->v19:
* Fixed the clk_mask for non-DT platforms.
v18:
* New patch dropping struct renesas_sdhi_hw_info instead using
renesas_sdhi_of_data and tmio_mmc_data.
---
drivers/mmc/host/renesas_sdhi.h | 2 ++
drivers/mmc/host/renesas_sdhi_core.c | 10 +++++++---
include/linux/platform_data/tmio.h | 1 +
3 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index 09bf9b24a8c3..bfa626ea6bee 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -22,6 +22,7 @@ struct renesas_sdhi_scc {
};
#define SDHI_FLAG_NEED_CLKH_FALLBACK BIT(0)
+#define SDHI_CLK_MASK_DEFAULT 0x80000080ULL
struct renesas_sdhi_of_data {
unsigned long tmio_flags;
@@ -37,6 +38,7 @@ struct renesas_sdhi_of_data {
unsigned int max_blk_count;
unsigned short max_segs;
unsigned long sdhi_flags;
+ u64 clk_mask;
};
#define SDHI_CALIB_TABLE_MAX 32
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index f9ec78d699f4..495e58fa7728 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -194,7 +194,7 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
unsigned int new_clock)
{
unsigned int clk_margin;
- u32 clk = 0, clock;
+ u64 clk = 0, clock;
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
@@ -205,7 +205,7 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
}
host->mmc->actual_clock = renesas_sdhi_clk_update(host, new_clock);
- clock = host->mmc->actual_clock / 512;
+ clock = max(host->mmc->actual_clock / 512, 1);
/*
* Add a margin of 1/1024 rate higher to the clock rate in order
@@ -213,7 +213,7 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
* provided for actual_clock in renesas_sdhi_clk_update().
*/
clk_margin = new_clock >> 10;
- for (clk = 0x80000080; new_clock + clk_margin >= (clock << 1); clk >>= 1)
+ for (clk = host->pdata->clk_mask; new_clock + clk_margin >= (clock << 1); clk >>= 1)
clock <<= 1;
/* 1/1 clock is option */
@@ -1136,6 +1136,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
mmc_data->dma_rx_offset = of_data->dma_rx_offset;
mmc_data->max_blk_count = of_data->max_blk_count;
mmc_data->max_segs = of_data->max_segs;
+ mmc_data->clk_mask = of_data->clk_mask;
dma_priv->dma_buswidth = of_data->dma_buswidth;
host->bus_shift = of_data->bus_shift;
/* Fallback for old DTs */
@@ -1178,6 +1179,9 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (mmd)
*mmc_data = *mmd;
+ if (!mmc_data->clk_mask)
+ mmc_data->clk_mask = SDHI_CLK_MASK_DEFAULT;
+
dma_priv->filter = shdma_chan_filter;
dma_priv->enable = renesas_sdhi_enable_dma;
diff --git a/include/linux/platform_data/tmio.h b/include/linux/platform_data/tmio.h
index 426291713b83..76056d49f5e0 100644
--- a/include/linux/platform_data/tmio.h
+++ b/include/linux/platform_data/tmio.h
@@ -61,5 +61,6 @@ struct tmio_mmc_data {
dma_addr_t dma_rx_offset;
unsigned int max_blk_count;
unsigned short max_segs;
+ u64 clk_mask;
};
#endif
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v25 03/11] mmc: renesas_sdhi: Add clk_mask to support wider clock dividers
2026-10-28 12:51 ` [PATCH v25 03/11] mmc: renesas_sdhi: Add clk_mask to support wider clock dividers Biju Das
@ 2026-11-11 10:07 ` Wolfram Sang
0 siblings, 0 replies; 22+ messages in thread
From: Wolfram Sang @ 2026-11-11 10:07 UTC (permalink / raw)
To: Biju Das
Cc: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Philipp Zabel, linux-mmc,
devicetree, linux-kernel, linux-renesas-soc, Biju Das
[-- Attachment #1: Type: text/plain, Size: 1044 bytes --]
On Wed, Oct 28, 2026 at 12:51:20PM +0000, Biju Das wrote:
> From: Biju Das <biju.das.jz@bp.renesas.com>
>
> The clock divider on the RZ/G3L SoC is 11 bits wide, which needs a
> clock mask of 0x200000200 in renesas_sdhi_set_clock() instead of the
> hardcoded 0x80000080 used so far.
>
> Add a u64 clk_mask field to struct renesas_sdhi_of_data and struct
> tmio_mmc_data so SoC-specific match data can supply its own mask, and
> widen the clk and clock variables in renesas_sdhi_set_clock() from
> u32 to u64 to hold it.
>
> While at it, clamp the initial clock value to a minimum of 1. If
> actual_clock / 512 evaluates to 0, the loop condition
> "new_clock + clk_margin >= (clock << 1)" is always true, and the
> loop never terminates.
>
> In probe, copy clk_mask from the OF data and fall back to
> SDHI_CLK_MASK_DEFAULT when none is provided, so existing
> SoCs keep their current behaviour.
>
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v25 04/11] mmc: renesas_sdhi: Add max_divider field to support SoC-specific clock ranges
2026-10-28 12:51 [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Biju Das
` (2 preceding siblings ...)
2026-10-28 12:51 ` [PATCH v25 03/11] mmc: renesas_sdhi: Add clk_mask to support wider clock dividers Biju Das
@ 2026-10-28 12:51 ` Biju Das
2026-11-11 10:13 ` Wolfram Sang
2026-10-28 12:51 ` [PATCH v25 05/11] mmc: renesas_sdhi: Add SDHI_SD_CLK_CTL_DIV1 macro for 1/1 option Biju Das
` (8 subsequent siblings)
12 siblings, 1 reply; 22+ messages in thread
From: Biju Das @ 2026-10-28 12:51 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Wolfram Sang, Philipp Zabel
Cc: linux-mmc, devicetree, linux-kernel, linux-renesas-soc, Biju Das
From: Biju Das <biju.das.jz@bp.renesas.com>
RZ/G3L supports a wider clock divider range than the hardcoded 512
used by existing SoCs. Add a max_divider field to
renesas_sdhi_of_data and tmio_mmc_data, and use it in
renesas_sdhi_clk_enable(), renesas_sdhi_clk_update(), and
renesas_sdhi_set_clock() instead of the fixed value.
While at it, check the return value of clk_round_rate() in
renesas_sdhi_clk_enable(). A negative error code was previously
divided and clamped into f_min; now the error is propagated and the
clk_cd clock is disabled again.
Default to SDHI_MAX_DIVIDER_DEFAULT (512) at probe time when
platform data doesn't set it. This paves the way for RZ/G3L's extended
divider support.
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v24->v25:
* Updated commit description.
* Restored the data type of max_divider from signed int to unsigned int.
* Dropped initializing max_divider as it use default value.
* Updated mmc->f_min calculation with clk_round_rate().
* Updated the comment using "ilog2(max_divider)" instead of "{9,11}".
v23->v24:
* No change.
v22->v23:
* Changed the data type of max_divider from unsigned int to signed int.
v21->v22:
* Updated comit description.
v20->v21:
* No change.
v19->v20:
* Replaced the check mmd->max_divider with mmc_data->max_divider and
moved the code after assignment of variable mmd, this ensures
assigning the default values for non-DT platforms and DT platforms with
no device data.
v18->v19:
* Fixed max-divider setting for non-DT platforms.
* Replaced the magic number '9' with ilog2 function in
renesas_sdhi_clk_enable().
v18:
* New patch.
---
drivers/mmc/host/renesas_sdhi.h | 2 ++
drivers/mmc/host/renesas_sdhi_core.c | 22 +++++++++++++++++-----
include/linux/platform_data/tmio.h | 1 +
3 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index bfa626ea6bee..b54802c0807c 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -23,6 +23,7 @@ struct renesas_sdhi_scc {
#define SDHI_FLAG_NEED_CLKH_FALLBACK BIT(0)
#define SDHI_CLK_MASK_DEFAULT 0x80000080ULL
+#define SDHI_MAX_DIVIDER_DEFAULT 512
struct renesas_sdhi_of_data {
unsigned long tmio_flags;
@@ -39,6 +40,7 @@ struct renesas_sdhi_of_data {
unsigned short max_segs;
unsigned long sdhi_flags;
u64 clk_mask;
+ unsigned int max_divider;
};
#define SDHI_CALIB_TABLE_MAX 32
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 495e58fa7728..74834e72f038 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -22,6 +22,7 @@
#include <linux/delay.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
+#include <linux/minmax.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
@@ -98,6 +99,7 @@ static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
{
struct mmc_host *mmc = host->mmc;
struct renesas_sdhi *priv = host_to_priv(host);
+ long rate;
int ret;
ret = clk_prepare_enable(priv->clk_cd);
@@ -117,7 +119,13 @@ static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
* Minimum frequency is the minimum input clock frequency
* divided by our maximum divider.
*/
- mmc->f_min = max(clk_round_rate(priv->clk, 1) / 512, 1L);
+ rate = clk_round_rate(priv->clk, 1);
+ if (rate < 0) {
+ clk_disable_unprepare(priv->clk_cd);
+ return rate;
+ }
+
+ mmc->f_min = max_t(long, rate / host->pdata->max_divider, 1);
/* enable 16bit data access on SDBUF as default */
renesas_sdhi_sdbuf_width(host, 16);
@@ -156,8 +164,8 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
/*
* We want the bus clock to be as close as possible to, but no
* greater than, new_clock. As we can divide by 1 << i for
- * any i in [0, 9] we want the input clock to be as close as
- * possible, but no greater than, new_clock << i.
+ * any i in [0, ilog2(max_divider)] we want the input clock to be as
+ * close as possible, but no greater than, new_clock << i.
*
* Add an upper limit of 1/1024 rate higher to the clock rate to fix
* clk rate jumping to lower rate due to rounding error (eg: RZ/G2L has
@@ -165,7 +173,7 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
* for 533.333333 MHz will selects a slower 400 MHz due to rounding
* error (533333333 Hz / 4 * 4 = 533333332 Hz < 533333333 Hz)).
*/
- for (i = min(9, ilog2(UINT_MAX / new_clock)); i >= 0; i--) {
+ for (i = min(ilog2(host->pdata->max_divider), ilog2(UINT_MAX / new_clock)); i >= 0; i--) {
freq = clk_round_rate(ref_clk, new_clock << i);
new_upper_limit = (new_clock << i) + ((new_clock << i) >> 10);
if (freq > new_upper_limit) {
@@ -205,7 +213,7 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
}
host->mmc->actual_clock = renesas_sdhi_clk_update(host, new_clock);
- clock = max(host->mmc->actual_clock / 512, 1);
+ clock = max(host->mmc->actual_clock / host->pdata->max_divider, 1);
/*
* Add a margin of 1/1024 rate higher to the clock rate in order
@@ -1137,6 +1145,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
mmc_data->max_blk_count = of_data->max_blk_count;
mmc_data->max_segs = of_data->max_segs;
mmc_data->clk_mask = of_data->clk_mask;
+ mmc_data->max_divider = of_data->max_divider;
dma_priv->dma_buswidth = of_data->dma_buswidth;
host->bus_shift = of_data->bus_shift;
/* Fallback for old DTs */
@@ -1182,6 +1191,9 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (!mmc_data->clk_mask)
mmc_data->clk_mask = SDHI_CLK_MASK_DEFAULT;
+ if (!mmc_data->max_divider)
+ mmc_data->max_divider = SDHI_MAX_DIVIDER_DEFAULT;
+
dma_priv->filter = shdma_chan_filter;
dma_priv->enable = renesas_sdhi_enable_dma;
diff --git a/include/linux/platform_data/tmio.h b/include/linux/platform_data/tmio.h
index 76056d49f5e0..27ea21c00419 100644
--- a/include/linux/platform_data/tmio.h
+++ b/include/linux/platform_data/tmio.h
@@ -62,5 +62,6 @@ struct tmio_mmc_data {
unsigned int max_blk_count;
unsigned short max_segs;
u64 clk_mask;
+ unsigned int max_divider;
};
#endif
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v25 04/11] mmc: renesas_sdhi: Add max_divider field to support SoC-specific clock ranges
2026-10-28 12:51 ` [PATCH v25 04/11] mmc: renesas_sdhi: Add max_divider field to support SoC-specific clock ranges Biju Das
@ 2026-11-11 10:13 ` Wolfram Sang
0 siblings, 0 replies; 22+ messages in thread
From: Wolfram Sang @ 2026-11-11 10:13 UTC (permalink / raw)
To: Biju Das
Cc: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Philipp Zabel, linux-mmc,
devicetree, linux-kernel, linux-renesas-soc, Biju Das
[-- Attachment #1: Type: text/plain, Size: 934 bytes --]
On Wed, Oct 28, 2026 at 12:51:21PM +0000, Biju Das wrote:
> From: Biju Das <biju.das.jz@bp.renesas.com>
>
> RZ/G3L supports a wider clock divider range than the hardcoded 512
> used by existing SoCs. Add a max_divider field to
> renesas_sdhi_of_data and tmio_mmc_data, and use it in
> renesas_sdhi_clk_enable(), renesas_sdhi_clk_update(), and
> renesas_sdhi_set_clock() instead of the fixed value.
>
> While at it, check the return value of clk_round_rate() in
> renesas_sdhi_clk_enable(). A negative error code was previously
> divided and clamped into f_min; now the error is propagated and the
> clk_cd clock is disabled again.
>
> Default to SDHI_MAX_DIVIDER_DEFAULT (512) at probe time when
> platform data doesn't set it. This paves the way for RZ/G3L's extended
> divider support.
>
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v25 05/11] mmc: renesas_sdhi: Add SDHI_SD_CLK_CTL_DIV1 macro for 1/1 option
2026-10-28 12:51 [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Biju Das
` (3 preceding siblings ...)
2026-10-28 12:51 ` [PATCH v25 04/11] mmc: renesas_sdhi: Add max_divider field to support SoC-specific clock ranges Biju Das
@ 2026-10-28 12:51 ` Biju Das
2026-10-28 12:51 ` [PATCH v25 06/11] mmc: renesas_sdhi: Make clock divider mask configurable Biju Das
` (7 subsequent siblings)
12 siblings, 0 replies; 22+ messages in thread
From: Biju Das @ 2026-10-28 12:51 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Wolfram Sang, Philipp Zabel
Cc: linux-mmc, devicetree, linux-kernel, linux-renesas-soc, Biju Das
From: Biju Das <biju.das.jz@bp.renesas.com>
Replace the magic number 0xff, used for selecting the SD clock 1/1
divider option, with a new SDHI_SD_CLK_CTL_DIV1 macro. This improves
readability and self-documents the purpose of the value at each use
site (setting/clearing the divider bits and comparing against
CLK_CTL_DIV_MASK).
No functional change.
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v24->v25:
* No change
v24:
* New patch
---
drivers/mmc/host/renesas_sdhi.h | 1 +
drivers/mmc/host/renesas_sdhi_core.c | 6 +++---
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index b54802c0807c..b759376103d7 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -24,6 +24,7 @@ struct renesas_sdhi_scc {
#define SDHI_FLAG_NEED_CLKH_FALLBACK BIT(0)
#define SDHI_CLK_MASK_DEFAULT 0x80000080ULL
#define SDHI_MAX_DIVIDER_DEFAULT 512
+#define SDHI_SD_CLK_CTL_DIV1 0xff
struct renesas_sdhi_of_data {
unsigned long tmio_flags;
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 74834e72f038..500ecc357095 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -227,13 +227,13 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
/* 1/1 clock is option */
if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && ((clk >> 22) & 0x1)) {
if (!(host->mmc->ios.timing == MMC_TIMING_MMC_HS400))
- clk |= 0xff;
+ clk |= SDHI_SD_CLK_CTL_DIV1;
else
- clk &= ~0xff;
+ clk &= ~SDHI_SD_CLK_CTL_DIV1;
}
clock = clk & CLK_CTL_DIV_MASK;
- if (clock != CLK_CTL_DIV_MASK)
+ if (clock != SDHI_SD_CLK_CTL_DIV1)
host->mmc->actual_clock /= (1 << (ffs(clock) + 1));
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clock);
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH v25 06/11] mmc: renesas_sdhi: Make clock divider mask configurable
2026-10-28 12:51 [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Biju Das
` (4 preceding siblings ...)
2026-10-28 12:51 ` [PATCH v25 05/11] mmc: renesas_sdhi: Add SDHI_SD_CLK_CTL_DIV1 macro for 1/1 option Biju Das
@ 2026-10-28 12:51 ` Biju Das
2026-11-11 10:14 ` Wolfram Sang
2026-10-28 12:51 ` [PATCH v25 07/11] mmc: renesas_sdhi: Add tuning delay support for RZ/G2L Biju Das
` (6 subsequent siblings)
12 siblings, 1 reply; 22+ messages in thread
From: Biju Das @ 2026-10-28 12:51 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Wolfram Sang, Philipp Zabel
Cc: linux-mmc, devicetree, linux-kernel, linux-renesas-soc, Biju Das
From: Biju Das <biju.das.jz@bp.renesas.com>
Add a clk_div_mask field to renesas_sdhi_of_data and tmio_mmc_data
so each SoC can specify its own divider mask instead of the
hardcoded CLK_CTL_DIV_MASK used in renesas_sdhi_set_clock().
Default to CLK_CTL_DIV_MASK at probe time when unset.
This lets RZ/G3L, which has a wider divider field, reuse the same
clock-setting code.
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v24->v25:
* Updated commit description
* Dropped initializing clk_div_mask as it use default value.
v23->v24:
* Updated commit description.
* Replaced GENMASK(7, 0) with CLK_CTL_DIV_MASK.
v22->v23:
* Assigned of_data->clk_div_mask in renesas_sdhi_probe().
v21->v22:
* Updated commit description.
* Added clk_div_mask to of_default_cfg and of_rcar_gen2_compatible.
v21:
* New patch.
---
drivers/mmc/host/renesas_sdhi.h | 1 +
drivers/mmc/host/renesas_sdhi_core.c | 6 +++++-
include/linux/platform_data/tmio.h | 1 +
3 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index b759376103d7..3c991f6b988b 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -42,6 +42,7 @@ struct renesas_sdhi_of_data {
unsigned long sdhi_flags;
u64 clk_mask;
unsigned int max_divider;
+ u16 clk_div_mask;
};
#define SDHI_CALIB_TABLE_MAX 32
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 500ecc357095..86778d83eb7d 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -232,7 +232,7 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
clk &= ~SDHI_SD_CLK_CTL_DIV1;
}
- clock = clk & CLK_CTL_DIV_MASK;
+ clock = clk & host->pdata->clk_div_mask;
if (clock != SDHI_SD_CLK_CTL_DIV1)
host->mmc->actual_clock /= (1 << (ffs(clock) + 1));
@@ -1146,6 +1146,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
mmc_data->max_segs = of_data->max_segs;
mmc_data->clk_mask = of_data->clk_mask;
mmc_data->max_divider = of_data->max_divider;
+ mmc_data->clk_div_mask = of_data->clk_div_mask;
dma_priv->dma_buswidth = of_data->dma_buswidth;
host->bus_shift = of_data->bus_shift;
/* Fallback for old DTs */
@@ -1194,6 +1195,9 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (!mmc_data->max_divider)
mmc_data->max_divider = SDHI_MAX_DIVIDER_DEFAULT;
+ if (!mmc_data->clk_div_mask)
+ mmc_data->clk_div_mask = CLK_CTL_DIV_MASK;
+
dma_priv->filter = shdma_chan_filter;
dma_priv->enable = renesas_sdhi_enable_dma;
diff --git a/include/linux/platform_data/tmio.h b/include/linux/platform_data/tmio.h
index 27ea21c00419..f684f4087a8f 100644
--- a/include/linux/platform_data/tmio.h
+++ b/include/linux/platform_data/tmio.h
@@ -63,5 +63,6 @@ struct tmio_mmc_data {
unsigned short max_segs;
u64 clk_mask;
unsigned int max_divider;
+ u16 clk_div_mask;
};
#endif
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v25 06/11] mmc: renesas_sdhi: Make clock divider mask configurable
2026-10-28 12:51 ` [PATCH v25 06/11] mmc: renesas_sdhi: Make clock divider mask configurable Biju Das
@ 2026-11-11 10:14 ` Wolfram Sang
0 siblings, 0 replies; 22+ messages in thread
From: Wolfram Sang @ 2026-11-11 10:14 UTC (permalink / raw)
To: Biju Das
Cc: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Philipp Zabel, linux-mmc,
devicetree, linux-kernel, linux-renesas-soc, Biju Das
[-- Attachment #1: Type: text/plain, Size: 586 bytes --]
On Wed, Oct 28, 2026 at 12:51:23PM +0000, Biju Das wrote:
> From: Biju Das <biju.das.jz@bp.renesas.com>
>
> Add a clk_div_mask field to renesas_sdhi_of_data and tmio_mmc_data
> so each SoC can specify its own divider mask instead of the
> hardcoded CLK_CTL_DIV_MASK used in renesas_sdhi_set_clock().
>
> Default to CLK_CTL_DIV_MASK at probe time when unset.
> This lets RZ/G3L, which has a wider divider field, reuse the same
> clock-setting code.
>
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v25 07/11] mmc: renesas_sdhi: Add tuning delay support for RZ/G2L
2026-10-28 12:51 [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Biju Das
` (5 preceding siblings ...)
2026-10-28 12:51 ` [PATCH v25 06/11] mmc: renesas_sdhi: Make clock divider mask configurable Biju Das
@ 2026-10-28 12:51 ` Biju Das
2026-11-11 10:28 ` Wolfram Sang
2026-10-28 12:51 ` [PATCH v25 08/11] mmc: renesas_sdhi: Add TMIO_MMC_INTERNAL_DIVIDER flag Biju Das
` (5 subsequent siblings)
12 siblings, 1 reply; 22+ messages in thread
From: Biju Das @ 2026-10-28 12:51 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Wolfram Sang, Philipp Zabel
Cc: linux-mmc, devicetree, linux-kernel, linux-renesas-soc, Biju Das
From: Biju Das <biju.das.jz@bp.renesas.com>
RZ/G2L and later SoCs (RZ/V2M and RZ/G3E) need a hardware adjustment
delay written to SCC_TMPPORT2 on signal-voltage switch during
tuning: 0x1 for 1.8V, 0x0 for 3.3V.
Add a TMIO_MMC_TUNING_DELAY flag and
renesas_sdhi_set_hw_adjustment_delay(), called from
renesas_sdhi_start_signal_voltage_switch() after the regulator is
set, and reset SCC_TMPPORT2 to 0 at the start of
renesas_sdhi_execute_tuning() when the flag is set and tap_num == 8.
Add a dedicated of_data_rz_g2l descriptor with this flag and switch
of_rzg2l_compatible to use it instead of the generic R-Car Gen3
descriptor.
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v24->v25:
* Updated commit description.
* Updated renesas_sdhi_set_hw_adjustment_delay() with force_clear
parameter
* Added a comment in renesas_sdhi_execute_tuning() for tuning delay.
* In probe, if the SCC registers are not available, it clear the tuning
delay flag.
* Dropped default masks from struct of_data_rz_g2l.
v23->v24:
* Replaced GENMASK(7, 0) with CLK_CTL_DIV_MASK.
v22->v23:
* No change.
v21->v22:
* Updated commit description.
* Added a renesas_sdhi_set_hw_adjustment_delay() call to
renesas_sdhi_init_tuning().
v20->v21:
* Added clk_div_mask to RZ/G2L of_data.
v19->v20:
* No change.
v18->v19:
* No change.
v18:
* New patch.
---
drivers/mmc/host/renesas_sdhi_core.c | 101 +++++++++++++++++---------
drivers/mmc/host/renesas_sdhi_internal_dmac.c | 19 ++++-
include/linux/platform_data/tmio.h | 3 +
3 files changed, 88 insertions(+), 35 deletions(-)
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 86778d83eb7d..5c317ab29d92 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -264,40 +264,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
@@ -358,6 +324,56 @@ 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,
+ bool force_clear)
+{
+ 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 || force_clear)
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, 0x0);
+ else
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, 0x1);
+}
+
+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, false);
+
+ return pinctrl_select_state(priv->pinctrl, pin_state);
+}
+
static unsigned int renesas_sdhi_init_tuning(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv;
@@ -385,6 +401,8 @@ static unsigned int renesas_sdhi_init_tuning(struct tmio_mmc_host *host)
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, priv->scc_tappos);
+ renesas_sdhi_set_hw_adjustment_delay(host, false);
+
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
@@ -717,6 +735,14 @@ static int renesas_sdhi_execute_tuning(struct mmc_host *mmc, u32 opcode)
if (!priv->tap_num)
return 0; /* Tuning is not supported */
+ /*
+ * As per section 40.7.8 (Hardware adjustment register 2, SCC_TMPPORT)
+ * of the RZ/G2L hardware manual, if the tap number is 8, the tmpout
+ * bits must be set to 0.
+ */
+ if ((host->pdata->flags & TMIO_MMC_TUNING_DELAY) && priv->tap_num == 8)
+ renesas_sdhi_set_hw_adjustment_delay(host, true);
+
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");
@@ -1267,6 +1293,13 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (of_data && of_data->scc_offset && ver >= SDHI_VER_GEN2_SDR104)
priv->scc_ctl = host->ctl + of_data->scc_offset;
+ /*
+ * The tuning delay is applied through SCC registers, so it must not
+ * be used when the SCC isn't mapped.
+ */
+ if (!priv->scc_ctl)
+ mmc_data->flags &= ~TMIO_MMC_TUNING_DELAY;
+
/* Enable tuning iff we have an SCC and a supported mode */
if (priv->scc_ctl && (host->mmc->caps & MMC_CAP_UHS_SDR104 ||
host->mmc->caps2 & MMC_CAP2_HSX00_1_8V)) {
diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
index 45e0d8f5c64d..e934b35fc205 100644
--- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
@@ -135,6 +135,23 @@ static const struct renesas_sdhi_of_data of_data_rcar_gen3_no_sdh_fallback = {
.max_segs = 1,
};
+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,
+};
+
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 },
@@ -256,7 +273,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 f684f4087a8f..77d3dc91c828 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
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v25 07/11] mmc: renesas_sdhi: Add tuning delay support for RZ/G2L
2026-10-28 12:51 ` [PATCH v25 07/11] mmc: renesas_sdhi: Add tuning delay support for RZ/G2L Biju Das
@ 2026-11-11 10:28 ` Wolfram Sang
0 siblings, 0 replies; 22+ messages in thread
From: Wolfram Sang @ 2026-11-11 10:28 UTC (permalink / raw)
To: Biju Das
Cc: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Philipp Zabel, linux-mmc,
devicetree, linux-kernel, linux-renesas-soc, Biju Das
[-- Attachment #1: Type: text/plain, Size: 861 bytes --]
On Wed, Oct 28, 2026 at 12:51:24PM +0000, Biju Das wrote:
> From: Biju Das <biju.das.jz@bp.renesas.com>
>
> RZ/G2L and later SoCs (RZ/V2M and RZ/G3E) need a hardware adjustment
> delay written to SCC_TMPPORT2 on signal-voltage switch during
> tuning: 0x1 for 1.8V, 0x0 for 3.3V.
>
> Add a TMIO_MMC_TUNING_DELAY flag and
> renesas_sdhi_set_hw_adjustment_delay(), called from
> renesas_sdhi_start_signal_voltage_switch() after the regulator is
> set, and reset SCC_TMPPORT2 to 0 at the start of
> renesas_sdhi_execute_tuning() when the flag is set and tap_num == 8.
>
> Add a dedicated of_data_rz_g2l descriptor with this flag and switch
> of_rzg2l_compatible to use it instead of the generic R-Car Gen3
> descriptor.
>
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v25 08/11] mmc: renesas_sdhi: Add TMIO_MMC_INTERNAL_DIVIDER flag
2026-10-28 12:51 [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Biju Das
` (6 preceding siblings ...)
2026-10-28 12:51 ` [PATCH v25 07/11] mmc: renesas_sdhi: Add tuning delay support for RZ/G2L Biju Das
@ 2026-10-28 12:51 ` Biju Das
2026-11-11 10:32 ` Wolfram Sang
2026-10-28 12:51 ` [PATCH v25 09/11] mmc: renesas_sdhi: Add optional axis/axim reset controls Biju Das
` (4 subsequent siblings)
12 siblings, 1 reply; 22+ messages in thread
From: Biju Das @ 2026-10-28 12:51 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Wolfram Sang, Philipp Zabel
Cc: linux-mmc, devicetree, linux-kernel, linux-renesas-soc, Biju Das
From: Biju Das <biju.das.jz@bp.renesas.com>
RZ/G3L has a fixed internal /2 clock divider active in all bus
timing modes except HS400, where the divider is bypassed. Add a
TMIO_MMC_INTERNAL_DIVIDER flag to mark controllers with this
divider.
Add renesas_sdhi_clk_get_rate() to fold the /2 division into the
reported clock rate when the flag is set, and use it in
renesas_sdhi_clk_update() in place of clk_get_rate(). HS400 is not
yet supported in software for this SoC. Adjust clkh_shift for the
internal divider case.
No existing platform sets this flag, so this is infrastructure only,
with no functional change for current SoCs.
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v24->v25:
* Dropped renesas_sdhi_is_internal_divider_enabled().
* Added a comment about the internal divider in
renesas_sdhi_clk_update() and replaced 'clkh_shift = 1' with
'clkh_shift--'
* Moved mmc->f_max to probe() and made it fail if max-frequency is
not defined in DT for SoCs with an internal divider.
v23->v24:
* No change.
v22->v23:
* Updated commit description.
v21->v22:
* Updated commit description.
* Added renesas_sdhi_is_internal_divider_enabled() and
renesas_sdhi_clk_get_rate() to simplify the clock rate logic.
v20->v21:
* No change.
v19->v20:
* No change.
v18->v19:
* Updated commit description.
* Dropped divider variable from struct renesas_sdhi.
* Updated renesas_sdhi_clk_update() to return rate for HS400mode
and nonHS400mode(uses 1/2 internal divider).
v18:
* New patch using flag.
---
drivers/mmc/host/renesas_sdhi_core.c | 47 +++++++++++++++++++++++++++---------
include/linux/platform_data/tmio.h | 3 +++
2 files changed, 38 insertions(+), 12 deletions(-)
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 5c317ab29d92..3a1a558bc98c 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -106,15 +106,6 @@ static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
if (ret < 0)
return ret;
- /*
- * The clock driver may not know what maximum frequency
- * actually works, so it should be set with the max-frequency
- * property which will already have been read to f_max. If it
- * was missing, assume the current frequency is the maximum.
- */
- if (!mmc->f_max)
- mmc->f_max = clk_get_rate(priv->clk);
-
/*
* Minimum frequency is the minimum input clock frequency
* divided by our maximum divider.
@@ -133,6 +124,17 @@ static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
return 0;
}
+static unsigned int renesas_sdhi_clk_get_rate(struct tmio_mmc_host *host,
+ struct clk *clk)
+{
+ unsigned int freq = clk_get_rate(clk);
+
+ if (host->pdata->flags & TMIO_MMC_INTERNAL_DIVIDER)
+ freq /= 2;
+
+ return freq;
+}
+
static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
unsigned int wanted_clock)
{
@@ -149,7 +151,7 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
* clock during tuning, so we don't change the external clock setup.
*/
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2) || mmc_doing_tune(host->mmc))
- return clk_get_rate(priv->clk);
+ return renesas_sdhi_clk_get_rate(host, priv->clk);
if (priv->clkh) {
/* HS400 with 4TAP needs different clock settings */
@@ -192,10 +194,15 @@ 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) {
+ /* internal /2 divider is always active here */
+ if (host->pdata->flags & TMIO_MMC_INTERNAL_DIVIDER)
+ clkh_shift--;
+
clk_set_rate(priv->clk, best_freq >> clkh_shift);
+ }
- return clk_get_rate(priv->clk);
+ return renesas_sdhi_clk_get_rate(host, priv->clk);
}
static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
@@ -1255,6 +1262,22 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (ret)
return ret;
+ /*
+ * The clock driver may not know the maximum working frequency, so it
+ * should come from the 'max-frequency' property. If it is missing,
+ * assume the current rate is the maximum. SoCs with an internal
+ * divider can't do that, because the current rate is not
+ * meaningful for them, so the property is mandatory there.
+ */
+ if (!host->mmc->f_max) {
+ if (mmc_data->flags & TMIO_MMC_INTERNAL_DIVIDER) {
+ ret = dev_err_probe(dev, -EINVAL, "max-frequency is required\n");
+ goto edisclk;
+ }
+
+ host->mmc->f_max = clk_get_rate(priv->clk);
+ }
+
rcfg.of_node = of_get_available_child_by_name(dev->of_node, "vqmmc-regulator");
if (rcfg.of_node) {
rcfg.driver_data = priv->host;
diff --git a/include/linux/platform_data/tmio.h b/include/linux/platform_data/tmio.h
index 77d3dc91c828..09b3411a59c9 100644
--- a/include/linux/platform_data/tmio.h
+++ b/include/linux/platform_data/tmio.h
@@ -53,6 +53,9 @@
/* Some controllers have tuning delay */
#define TMIO_MMC_TUNING_DELAY BIT(13)
+/* Some controllers have internal divider */
+#define TMIO_MMC_INTERNAL_DIVIDER BIT(14)
+
struct tmio_mmc_data {
void *chan_priv_tx;
void *chan_priv_rx;
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v25 08/11] mmc: renesas_sdhi: Add TMIO_MMC_INTERNAL_DIVIDER flag
2026-10-28 12:51 ` [PATCH v25 08/11] mmc: renesas_sdhi: Add TMIO_MMC_INTERNAL_DIVIDER flag Biju Das
@ 2026-11-11 10:32 ` Wolfram Sang
0 siblings, 0 replies; 22+ messages in thread
From: Wolfram Sang @ 2026-11-11 10:32 UTC (permalink / raw)
To: Biju Das
Cc: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Philipp Zabel, linux-mmc,
devicetree, linux-kernel, linux-renesas-soc, Biju Das
[-- Attachment #1: Type: text/plain, Size: 1250 bytes --]
On Wed, Oct 28, 2026 at 12:51:25PM +0000, Biju Das wrote:
> From: Biju Das <biju.das.jz@bp.renesas.com>
>
> RZ/G3L has a fixed internal /2 clock divider active in all bus
> timing modes except HS400, where the divider is bypassed. Add a
> TMIO_MMC_INTERNAL_DIVIDER flag to mark controllers with this
> divider.
>
> Add renesas_sdhi_clk_get_rate() to fold the /2 division into the
> reported clock rate when the flag is set, and use it in
> renesas_sdhi_clk_update() in place of clk_get_rate(). HS400 is not
> yet supported in software for this SoC. Adjust clkh_shift for the
> internal divider case.
>
> No existing platform sets this flag, so this is infrastructure only,
> with no functional change for current SoCs.
>
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> + /*
> + * The clock driver may not know the maximum working frequency, so it
> + * should come from the 'max-frequency' property. If it is missing,
> + * assume the current rate is the maximum. SoCs with an internal
> + * divider can't do that, because the current rate is not
> + * meaningful for them, so the property is mandatory there.
> + */
Good description!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v25 09/11] mmc: renesas_sdhi: Add optional axis/axim reset controls
2026-10-28 12:51 [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Biju Das
` (7 preceding siblings ...)
2026-10-28 12:51 ` [PATCH v25 08/11] mmc: renesas_sdhi: Add TMIO_MMC_INTERNAL_DIVIDER flag Biju Das
@ 2026-10-28 12:51 ` Biju Das
2026-10-28 12:51 ` [PATCH v25 10/11] mmc: renesas_sdhi: Add write32_hook for CTL_SD_CARD_CLK_CTL register writes Biju Das
` (3 subsequent siblings)
12 siblings, 0 replies; 22+ messages in thread
From: Biju Das @ 2026-10-28 12:51 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Wolfram Sang, Philipp Zabel
Cc: linux-mmc, devicetree, linux-kernel, linux-renesas-soc, Biju Das
From: Biju Das <biju.das.jz@bp.renesas.com>
The RZ/G3L SoC has axis/axim resets compared to other SoCs.
Add two optional reset controls, rstc_axis and rstc_axim, to the
renesas_sdhi struct. Both are acquired at probe time using
devm_reset_control_get_optional_exclusive_deasserted() with the
"axis" and "axim" reset names respectively.
Include them alongside the existing rstc in bulk reset/assert/deassert
operations: triggered together in renesas_sdhi_reset(), and managed
via reset_control_bulk_assert/deassert() in the suspend and resume
paths, replacing the previous single-control calls.
Being optional, these resets are a no-op on platforms that do not
provide them, so existing behaviour is preserved.
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v24->v25:
* No change.
v23->v24:
* No change.
v22->v23:
* No change.
v21->v22:
* No change.
v20->v21:
* No change.
v19->v20:
* Fixed the ordering of resets in suspend/resume paths.
V18->v19:
* No change.
v17->v18:
* Fixed ordering of reset in renesas_sdhi_reset().
v1->v17:
* No change.
---
drivers/mmc/host/renesas_sdhi.h | 2 ++
drivers/mmc/host/renesas_sdhi_core.c | 26 +++++++++++++++++++++++---
2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index 3c991f6b988b..4f8ed1d8efee 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -102,6 +102,8 @@ struct renesas_sdhi {
unsigned int tap_set;
struct reset_control *rstc;
+ struct reset_control *rstc_axis;
+ struct reset_control *rstc_axim;
struct tmio_mmc_host *host;
struct regulator_dev *rdev;
};
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 3a1a558bc98c..e897328d5b70 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -632,6 +632,8 @@ static void renesas_sdhi_reset(struct tmio_mmc_host *host, bool preserve)
sd_status = sd_ctrl_read32(host, CTL_SD_STATUS);
reset_control_reset(priv->rstc);
+ reset_control_reset(priv->rstc_axim);
+ reset_control_reset(priv->rstc_axis);
/* Unknown why but without polling reset status, it will hang */
read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100,
false, priv->rstc);
@@ -1151,6 +1153,14 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (IS_ERR(priv->rstc))
return PTR_ERR(priv->rstc);
+ priv->rstc_axim = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, "axim");
+ if (IS_ERR(priv->rstc_axim))
+ return PTR_ERR(priv->rstc_axim);
+
+ priv->rstc_axis = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, "axis");
+ if (IS_ERR(priv->rstc_axis))
+ return PTR_ERR(priv->rstc_axis);
+
priv->pinctrl = devm_pinctrl_get(&pdev->dev);
if (!IS_ERR(priv->pinctrl)) {
priv->pins_default = pinctrl_lookup_state(priv->pinctrl,
@@ -1404,13 +1414,18 @@ int renesas_sdhi_suspend(struct device *dev)
{
struct tmio_mmc_host *host = dev_get_drvdata(dev);
struct renesas_sdhi *priv = host_to_priv(host);
+ struct reset_control_bulk_data resets[] = {
+ { .rstc = priv->rstc_axis },
+ { .rstc = priv->rstc_axim },
+ { .rstc = priv->rstc },
+ };
int ret;
ret = pm_runtime_force_suspend(dev);
if (ret)
return ret;
- ret = reset_control_assert(priv->rstc);
+ ret = reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
if (ret)
pm_runtime_force_resume(dev);
@@ -1422,15 +1437,20 @@ int renesas_sdhi_resume(struct device *dev)
{
struct tmio_mmc_host *host = dev_get_drvdata(dev);
struct renesas_sdhi *priv = host_to_priv(host);
+ struct reset_control_bulk_data resets[] = {
+ { .rstc = priv->rstc_axis },
+ { .rstc = priv->rstc_axim },
+ { .rstc = priv->rstc },
+ };
int ret;
- ret = reset_control_deassert(priv->rstc);
+ ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets);
if (ret)
return ret;
ret = pm_runtime_force_resume(dev);
if (ret)
- reset_control_assert(priv->rstc);
+ reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
return ret;
}
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH v25 10/11] mmc: renesas_sdhi: Add write32_hook for CTL_SD_CARD_CLK_CTL register writes
2026-10-28 12:51 [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Biju Das
` (8 preceding siblings ...)
2026-10-28 12:51 ` [PATCH v25 09/11] mmc: renesas_sdhi: Add optional axis/axim reset controls Biju Das
@ 2026-10-28 12:51 ` Biju Das
2026-11-11 10:36 ` Wolfram Sang
2026-10-28 12:51 ` [PATCH v25 11/11] mmc: renesas_sdhi: Add RZ/G3L SDHI support Biju Das
` (2 subsequent siblings)
12 siblings, 1 reply; 22+ messages in thread
From: Biju Das @ 2026-10-28 12:51 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Wolfram Sang, Philipp Zabel
Cc: linux-mmc, devicetree, linux-kernel, linux-renesas-soc, Biju Das
From: Biju Das <biju.das.jz@bp.renesas.com>
Add a write32_hook, analogous to the existing write16_hook, so that
sd_ctrl_write32() can wait for the SD bus to become idle before
certain 32-bit register writes.
renesas_sdhi_write32_hook() checks whether the target register is
CTL_SD_CARD_CLK_CTL and, if so, waits for TMIO_STAT_SCLKDIVEN via
renesas_sdhi_wait_idle() before the write proceeds. Other registers
are unaffected. As with write16_hook, the write is skipped if the
hook returns a non-zero error.
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v24->v25:
* Updated comit description.
* Updated tmio_mmc_host_probe() to set write32_hook() to NULL if
TMIO_MMC_HAS_IDLE_WAIT is not defined.
v23->v24:
* No change.
v23:
* New patch.
---
drivers/mmc/host/renesas_sdhi_core.c | 9 +++++++++
drivers/mmc/host/tmio_mmc.h | 7 +++++++
drivers/mmc/host/tmio_mmc_core.c | 4 +++-
3 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index e897328d5b70..cb41f38ec80e 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -965,6 +965,14 @@ static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
return 0;
}
+static int renesas_sdhi_write32_hook(struct tmio_mmc_host *host, int addr)
+{
+ if (addr == CTL_SD_CARD_CLK_CTL)
+ return renesas_sdhi_wait_idle(host, TMIO_STAT_SCLKDIVEN);
+
+ return 0;
+}
+
static int renesas_sdhi_multi_io_quirk(struct mmc_card *card,
unsigned int direction, int blk_size)
{
@@ -1199,6 +1207,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
}
host->write16_hook = renesas_sdhi_write16_hook;
+ host->write32_hook = renesas_sdhi_write32_hook;
host->clk_enable = renesas_sdhi_clk_enable;
host->clk_disable = renesas_sdhi_clk_disable;
host->set_clock = renesas_sdhi_set_clock;
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 3ab8c0d8a2bd..e29a2fe06ef6 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -189,6 +189,7 @@ struct tmio_mmc_host {
int (*multi_io_quirk)(struct mmc_card *card,
unsigned int direction, int blk_size);
int (*write16_hook)(struct tmio_mmc_host *host, int addr);
+ int (*write32_hook)(struct tmio_mmc_host *host, int addr);
void (*reset)(struct tmio_mmc_host *host, bool preserve);
bool (*check_retune)(struct tmio_mmc_host *host, struct mmc_request *mrq);
void (*fixup_request)(struct tmio_mmc_host *host, struct mmc_request *mrq);
@@ -283,6 +284,12 @@ static inline void sd_ctrl_write32_as_16_and_16(struct tmio_mmc_host *host,
static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val)
{
+ /* If there is a hook and it returns non-zero then there
+ * is an error and the write should be skipped
+ */
+ if (host->write32_hook && host->write32_hook(host, addr))
+ return;
+
iowrite32(val, host->ctl + (addr << host->bus_shift));
}
diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index 4116c4d29c63..4fe98b437121 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -1169,8 +1169,10 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
if (mmc->f_min == 0)
return -EINVAL;
- if (!(pdata->flags & TMIO_MMC_HAS_IDLE_WAIT))
+ if (!(pdata->flags & TMIO_MMC_HAS_IDLE_WAIT)) {
_host->write16_hook = NULL;
+ _host->write32_hook = NULL;
+ }
if (pdata->flags & TMIO_MMC_USE_BUSY_TIMEOUT && !_host->get_timeout_cycles)
_host->get_timeout_cycles = tmio_mmc_get_timeout_cycles;
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v25 10/11] mmc: renesas_sdhi: Add write32_hook for CTL_SD_CARD_CLK_CTL register writes
2026-10-28 12:51 ` [PATCH v25 10/11] mmc: renesas_sdhi: Add write32_hook for CTL_SD_CARD_CLK_CTL register writes Biju Das
@ 2026-11-11 10:36 ` Wolfram Sang
0 siblings, 0 replies; 22+ messages in thread
From: Wolfram Sang @ 2026-11-11 10:36 UTC (permalink / raw)
To: Biju Das
Cc: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Philipp Zabel, linux-mmc,
devicetree, linux-kernel, linux-renesas-soc, Biju Das
[-- Attachment #1: Type: text/plain, Size: 725 bytes --]
On Wed, Oct 28, 2026 at 12:51:27PM +0000, Biju Das wrote:
> From: Biju Das <biju.das.jz@bp.renesas.com>
>
> Add a write32_hook, analogous to the existing write16_hook, so that
> sd_ctrl_write32() can wait for the SD bus to become idle before
> certain 32-bit register writes.
>
> renesas_sdhi_write32_hook() checks whether the target register is
> CTL_SD_CARD_CLK_CTL and, if so, waits for TMIO_STAT_SCLKDIVEN via
> renesas_sdhi_wait_idle() before the write proceeds. Other registers
> are unaffected. As with write16_hook, the write is skipped if the
> hook returns a non-zero error.
>
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v25 11/11] mmc: renesas_sdhi: Add RZ/G3L SDHI support
2026-10-28 12:51 [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Biju Das
` (9 preceding siblings ...)
2026-10-28 12:51 ` [PATCH v25 10/11] mmc: renesas_sdhi: Add write32_hook for CTL_SD_CARD_CLK_CTL register writes Biju Das
@ 2026-10-28 12:51 ` Biju Das
2026-11-11 11:24 ` Wolfram Sang
2026-11-11 11:48 ` [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Wolfram Sang
2026-11-11 12:37 ` Ulf Hansson
12 siblings, 1 reply; 22+ messages in thread
From: Biju Das @ 2026-10-28 12:51 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Wolfram Sang, Philipp Zabel
Cc: linux-mmc, devicetree, linux-kernel, linux-renesas-soc, Biju Das
From: Biju Das <biju.das.jz@bp.renesas.com>
The RZ/G3L SDHI is close to existing variants but differs in three
ways the driver can't handle today:
- It has an 11-bit clock divider. The upper bits live in CLK_CTL
bits [17:16], so the register must be written with a 32-bit access
on this SoC.
- Tuning needs a second HW adjustment register (HWADJ2), programmed
together with TMPPORT2.
- HWADJ4 must be cleared when tuning starts.
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v24->v25:
* Updated commit description.
* Added macros RZG3L_SDHI_SCC_HWADJ2_{1_8V,3_3V}
* Replaced the quirks sdhi_quirks_rzg3l with sdhi_quirks_fixed_addr.
* Added helper renesas_sdhi_sclken() to handle 16-bit and 32-bit access.
* Updated renesas_sdhi_set_clock() with max_divider check for
TMIO_MMC_INTERNAL_DIVIDER instead of SDHI_MAX_DIVIDER_DEFAULT for
consistency with tmio_mmc_reset().
v23->v24:
* Replaced magic bits GENMASK(9, 8) and GENMASK(17, 16) with
RZG3L_CLK_CTL_DIV9_DIV8 and RZG3L_CLK_CTL_DIV9_DIV8_SRC.
v22->v23:
* Updated tmio_mmc_reset() to handle 32 bit divider register in RZ/G3L.
v21->v22:
* Updated commit description.
* Added `clock &= ~GENMASK(9, 8)` to clear the divider mask bits in
the register value.
v20->v21:
* Added clk_div_mask to RZ/G3L of_data.
* Restored actual_clk calculation in renesas_sdhi_set_clock().
v19->v20:
* Added bitfield.h header file.
* Reworked on renesas_sdhi_set_clock() to handle the 11-bit divider
case and the 32-bit register write.
v18->v19:
* Update commit description.
* Updated handling for clk divider.
* Renamed TMIO_MMC_HWADJ2->TMIO_MMC_HWADJ to make it generic for
hardware tuning delays
* Dropped duplicate SH_MOBILE_SDHI_SCC_TMPPORT2 macro
v18:
* New patch.
---
drivers/mmc/host/renesas_sdhi_core.c | 84 +++++++++++++++++++--------
drivers/mmc/host/renesas_sdhi_internal_dmac.c | 34 +++++++++++
drivers/mmc/host/tmio_mmc_core.c | 16 ++++-
include/linux/platform_data/tmio.h | 3 +
4 files changed, 110 insertions(+), 27 deletions(-)
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index cb41f38ec80e..4b6c0dbd15e7 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -18,6 +18,7 @@
*
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
@@ -60,9 +61,13 @@
#define SDHI_VER_GEN2_SDR104 0xcb0d
#define SDHI_VER_GEN3_SD 0xcc10
#define SDHI_VER_GEN3_SDMMC 0xcd10
+#define SDHI_VER_RZ_G3L_SDMMC 0xce10
#define SDHI_GEN3_MMC0_ADDR 0xee140000
+#define RZG3L_CLK_CTL_DIV9_DIV8 GENMASK(17, 16)
+#define RZG3L_CLK_CTL_DIV9_DIV8_SRC GENMASK(9, 8)
+
static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
{
u32 val;
@@ -80,6 +85,7 @@ static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
break;
case SDHI_VER_GEN3_SD:
case SDHI_VER_GEN3_SDMMC:
+ case SDHI_VER_RZ_G3L_SDMMC:
if (width == 64)
val = HOST_MODE_GEN3_64BIT;
else if (width == 32)
@@ -205,14 +211,28 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
return renesas_sdhi_clk_get_rate(host, priv->clk);
}
+static void renesas_sdhi_sclken(struct tmio_mmc_host *host, bool enable)
+{
+ if (host->pdata->flags & TMIO_MMC_INTERNAL_DIVIDER) {
+ u32 val = sd_ctrl_read32(host, CTL_SD_CARD_CLK_CTL);
+
+ val = enable ? val | CLK_CTL_SCLKEN : val & ~CLK_CTL_SCLKEN;
+ sd_ctrl_write32(host, CTL_SD_CARD_CLK_CTL, val);
+ } else {
+ u16 val = sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL);
+
+ val = enable ? val | CLK_CTL_SCLKEN : val & ~CLK_CTL_SCLKEN;
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, val);
+ }
+}
+
static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
unsigned int new_clock)
{
unsigned int clk_margin;
u64 clk = 0, clock;
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ renesas_sdhi_sclken(host, false);
if (new_clock == 0) {
host->mmc->actual_clock = 0;
@@ -243,12 +263,21 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
if (clock != SDHI_SD_CLK_CTL_DIV1)
host->mmc->actual_clock /= (1 << (ffs(clock) + 1));
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clock);
+ if (host->pdata->flags & TMIO_MMC_INTERNAL_DIVIDER) {
+ u64 tmp;
+
+ tmp = FIELD_GET(RZG3L_CLK_CTL_DIV9_DIV8_SRC, clk);
+ clock |= FIELD_PREP(RZG3L_CLK_CTL_DIV9_DIV8, tmp);
+ clock &= ~RZG3L_CLK_CTL_DIV9_DIV8_SRC;
+ sd_ctrl_write32(host, CTL_SD_CARD_CLK_CTL, clock);
+ } else {
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clock);
+ }
+
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
usleep_range(10000, 11000);
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ renesas_sdhi_sclken(host, true);
out:
/* HW engineers overrode docs: no sleep needed on R-Car2+ */
@@ -279,12 +308,14 @@ static int renesas_sdhi_card_busy(struct mmc_host *mmc)
#define SH_MOBILE_SDHI_SCC_RVSCNTL 0x008
#define SH_MOBILE_SDHI_SCC_RVSREQ 0x00A
#define SH_MOBILE_SDHI_SCC_SMPCMP 0x00C
-#define SH_MOBILE_SDHI_SCC_TMPPORT2 0x00E
+#define SH_MOBILE_SDHI_SCC_TMPPORT2 0x00E /* G3L: SDm_SCC_HS400MODE1 */
+#define RZG3L_SDHI_SCC_HWADJ2 0x010
#define SH_MOBILE_SDHI_SCC_TMPPORT3 0x014
#define SH_MOBILE_SDHI_SCC_TMPPORT4 0x016
#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_HWADJ4 0x022
#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0)
#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16
@@ -305,6 +336,9 @@ static int renesas_sdhi_card_busy(struct mmc_host *mmc)
#define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4)
#define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN BIT(31)
+#define RZG3L_SDHI_SCC_HWADJ2_1_8V 0xff
+#define RZG3L_SDHI_SCC_HWADJ2_3_3V 0x3fff
+
/* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT4 register */
#define SH_MOBILE_SDHI_SCC_TMPPORT4_DLL_ACC_START BIT(0)
@@ -335,14 +369,22 @@ static void renesas_sdhi_set_hw_adjustment_delay(struct tmio_mmc_host *host,
bool force_clear)
{
struct renesas_sdhi *priv = host_to_priv(host);
+ bool hwadj2 = host->pdata->flags & TMIO_MMC_HWADJ;
if (!(host->pdata->flags & TMIO_MMC_TUNING_DELAY))
return;
- if (host->mmc->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330 || force_clear)
+ if (host->mmc->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330 || force_clear) {
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, 0x0);
- else
+ if (hwadj2)
+ sd_scc_write32(host, priv, RZG3L_SDHI_SCC_HWADJ2,
+ RZG3L_SDHI_SCC_HWADJ2_3_3V);
+ } else {
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, 0x1);
+ if (hwadj2)
+ sd_scc_write32(host, priv, RZG3L_SDHI_SCC_HWADJ2,
+ RZG3L_SDHI_SCC_HWADJ2_1_8V);
+ }
}
static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
@@ -390,8 +432,7 @@ static unsigned int renesas_sdhi_init_tuning(struct tmio_mmc_host *host)
/* Initialize SCC */
sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, 0x0);
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ renesas_sdhi_sclken(host, false);
/* set sampling clock selection range */
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
@@ -409,9 +450,10 @@ static unsigned int renesas_sdhi_init_tuning(struct tmio_mmc_host *host)
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, priv->scc_tappos);
renesas_sdhi_set_hw_adjustment_delay(host, false);
+ if (host->pdata->flags & TMIO_MMC_HWADJ)
+ sd_scc_write32(host, priv, RZG3L_SDHI_SCC_HWADJ4, 0x0);
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ renesas_sdhi_sclken(host, true);
/* Read TAPNUM */
return (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL) >>
@@ -426,8 +468,7 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0;
bool use_4tap = sdhi_has_quirk(priv, hs400_4taps);
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ renesas_sdhi_sclken(host, false);
/* Set HS400 mode */
sd_ctrl_write16(host, CTL_SDIF_MODE, SDIF_MODE_HS400 |
@@ -473,8 +514,7 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
SH_MOBILE_SDHI_SCC_CKSEL_DTSEL |
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL));
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ renesas_sdhi_sclken(host, true);
if (priv->adjust_hs400_calib_table)
priv->needs_adjust_hs400 = true;
@@ -485,8 +525,7 @@ static void renesas_sdhi_disable_scc(struct mmc_host *mmc)
struct tmio_mmc_host *host = mmc_priv(mmc);
struct renesas_sdhi *priv = host_to_priv(host);
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ renesas_sdhi_sclken(host, false);
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL,
~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL &
@@ -498,8 +537,7 @@ static void renesas_sdhi_disable_scc(struct mmc_host *mmc)
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));
+ renesas_sdhi_sclken(host, true);
}
static u32 sd_scc_tmpport_read32(struct tmio_mmc_host *host,
@@ -573,8 +611,7 @@ 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)
{
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ renesas_sdhi_sclken(host, false);
/* Reset HS400 mode */
sd_ctrl_write16(host, CTL_SDIF_MODE, ~SDIF_MODE_HS400 &
@@ -590,8 +627,7 @@ static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host,
if (sdhi_has_quirk(priv, hs400_calib_table) || sdhi_has_quirk(priv, hs400_bad_taps))
renesas_sdhi_adjust_hs400_mode_disable(host);
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ renesas_sdhi_sclken(host, true);
}
static int renesas_sdhi_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
index e934b35fc205..eaf21f93f5d3 100644
--- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
@@ -87,6 +87,13 @@ static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
},
};
+static struct renesas_sdhi_scc rzg3l_scc_taps[] = {
+ {
+ .clk_rate = 0,
+ .tap = 0x00000300,
+ },
+};
+
static const struct renesas_sdhi_of_data of_data_rza2 = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
TMIO_MMC_HAVE_CBSY,
@@ -152,6 +159,27 @@ static const struct renesas_sdhi_of_data of_data_rz_g2l = {
.sdhi_flags = SDHI_FLAG_NEED_CLKH_FALLBACK,
};
+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_HWADJ,
+ .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 = rzg3l_scc_taps,
+ .taps_num = ARRAY_SIZE(rzg3l_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 = 0x200000200,
+ .max_divider = 2048,
+ .clk_div_mask = GENMASK(9, 0),
+};
+
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 },
@@ -291,6 +319,11 @@ static const struct renesas_sdhi_of_data_with_quirks of_rza2_compatible = {
.quirks = &sdhi_quirks_fixed_addr,
};
+static const struct renesas_sdhi_of_data_with_quirks of_rzg3l_compatible = {
+ .of_data = &of_data_rzg3l,
+ .quirks = &sdhi_quirks_fixed_addr,
+};
+
static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, },
{ .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, },
@@ -304,6 +337,7 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, },
{ .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, },
{ .compatible = "renesas,sdhi-r8a779md", .data = &of_rcar_gen3_nohs400_compatible, },
+ { .compatible = "renesas,sdhi-r9a08g046", .data = &of_rzg3l_compatible, },
{ .compatible = "renesas,sdhi-r9a09g011", .data = &of_rzg2l_compatible, },
{ .compatible = "renesas,sdhi-r9a09g057", .data = &of_rzg2l_compatible, },
{ .compatible = "renesas,rzg2l-sdhi", .data = &of_rzg2l_compatible, },
diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index 4fe98b437121..d016306956f9 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -180,11 +180,17 @@ static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
static void tmio_mmc_reset(struct tmio_mmc_host *host, bool preserve)
{
- u16 card_opt, clk_ctrl, sdif_mode;
+ u16 card_opt, sdif_mode;
+ u32 clk_ctrl;
+ bool wide_clk = host->pdata->flags & TMIO_MMC_INTERNAL_DIVIDER;
if (preserve) {
card_opt = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
- clk_ctrl = sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL);
+ if (wide_clk)
+ clk_ctrl = sd_ctrl_read32(host, CTL_SD_CARD_CLK_CTL);
+ else
+ clk_ctrl = sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL);
+
if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
sdif_mode = sd_ctrl_read16(host, CTL_SDIF_MODE);
}
@@ -216,7 +222,11 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host, bool preserve)
if (preserve) {
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, card_opt);
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk_ctrl);
+ if (wide_clk)
+ sd_ctrl_write32(host, CTL_SD_CARD_CLK_CTL, clk_ctrl);
+ else
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk_ctrl);
+
if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
sd_ctrl_write16(host, CTL_SDIF_MODE, sdif_mode);
}
diff --git a/include/linux/platform_data/tmio.h b/include/linux/platform_data/tmio.h
index 09b3411a59c9..99b05c8c840a 100644
--- a/include/linux/platform_data/tmio.h
+++ b/include/linux/platform_data/tmio.h
@@ -56,6 +56,9 @@
/* Some controllers have internal divider */
#define TMIO_MMC_INTERNAL_DIVIDER BIT(14)
+/* Some controllers have hw adjustment delay */
+#define TMIO_MMC_HWADJ BIT(15)
+
struct tmio_mmc_data {
void *chan_priv_tx;
void *chan_priv_rx;
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v25 11/11] mmc: renesas_sdhi: Add RZ/G3L SDHI support
2026-10-28 12:51 ` [PATCH v25 11/11] mmc: renesas_sdhi: Add RZ/G3L SDHI support Biju Das
@ 2026-11-11 11:24 ` Wolfram Sang
0 siblings, 0 replies; 22+ messages in thread
From: Wolfram Sang @ 2026-11-11 11:24 UTC (permalink / raw)
To: Biju Das
Cc: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Philipp Zabel, linux-mmc,
devicetree, linux-kernel, linux-renesas-soc, Biju Das
[-- Attachment #1: Type: text/plain, Size: 788 bytes --]
On Wed, Oct 28, 2026 at 12:51:28PM +0000, Biju Das wrote:
> From: Biju Das <biju.das.jz@bp.renesas.com>
>
> The RZ/G3L SDHI is close to existing variants but differs in three
> ways the driver can't handle today:
>
> - It has an 11-bit clock divider. The upper bits live in CLK_CTL
> bits [17:16], so the register must be written with a 32-bit access
> on this SoC.
> - Tuning needs a second HW adjustment register (HWADJ2), programmed
> together with TMPPORT2.
> - HWADJ4 must be cleared when tuning starts.
>
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
I like the renesas_sdhi_sclken() helper.
All review done, congrats! I will run some tests on R-Car hardware in
a few minutes.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support
2026-10-28 12:51 [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Biju Das
` (10 preceding siblings ...)
2026-10-28 12:51 ` [PATCH v25 11/11] mmc: renesas_sdhi: Add RZ/G3L SDHI support Biju Das
@ 2026-11-11 11:48 ` Wolfram Sang
2026-11-11 14:42 ` Biju Das
2026-11-11 12:37 ` Ulf Hansson
12 siblings, 1 reply; 22+ messages in thread
From: Wolfram Sang @ 2026-11-11 11:48 UTC (permalink / raw)
To: Biju Das
Cc: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Philipp Zabel, linux-mmc,
devicetree, linux-kernel, linux-renesas-soc, Biju Das,
Conor Dooley
[-- Attachment #1: Type: text/plain, Size: 1037 bytes --]
On Wed, Oct 28, 2026 at 12:51:17PM +0000, Biju Das wrote:
> Hi All,
>
> The Renesas RZ/G3L SoC has:
>
> Channel 0 supports SD and eMMC (including HS400/HS400ES).
> Channel 1 supports SD and eMMC (except for HS400).
> Channel 2 supports SD.
>
> The SoC supports a maximum frequency of 150 MHz. The SD0 interface does
> not support IOVS and PWEN in the SDHI register (no internal regulator),
> unlike SD1 and SD2. It has an internal divider for all modes except HS400.
> It also has a 2048-bit divider compared to 512 on others. Moreover
> RZ/G3L supports HS400 enhanced strobe mode.
>
> This patch series support all modes except HS400. HS400 support will be
> added later.
>
> This patch series tested on smarc-rz{v2l,g2l,g2lc,g2ul,g3s,g3l,g3e},
> rz{v2h,t2h}-evk and hihope-rz{g2h,g2m,g2n} boards
Tested with a Renesas Salvator-XS board (R-Car M3N). I don't see bugs or
performance regressions. I think the series is good to go!
Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Thank you!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 22+ messages in thread* RE: [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support
2026-11-11 11:48 ` [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Wolfram Sang
@ 2026-11-11 14:42 ` Biju Das
0 siblings, 0 replies; 22+ messages in thread
From: Biju Das @ 2026-11-11 14:42 UTC (permalink / raw)
To: wsa+renesas, biju.das.au
Cc: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, magnus.damm, Philipp Zabel, linux-mmc,
devicetree, linux-kernel, linux-renesas-soc, Conor Dooley
Hi Wolfram,
> -----Original Message-----
> From: Wolfram Sang <wsa+renesas@sang-engineering.com>
> Sent: 11 November 2026 11:49
> Subject: Re: [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support
>
> On Wed, Oct 28, 2026 at 12:51:17PM +0000, Biju Das wrote:
> > Hi All,
> >
> > The Renesas RZ/G3L SoC has:
> >
> > Channel 0 supports SD and eMMC (including HS400/HS400ES).
> > Channel 1 supports SD and eMMC (except for HS400).
> > Channel 2 supports SD.
> >
> > The SoC supports a maximum frequency of 150 MHz. The SD0 interface
> > does not support IOVS and PWEN in the SDHI register (no internal
> > regulator), unlike SD1 and SD2. It has an internal divider for all modes except HS400.
> > It also has a 2048-bit divider compared to 512 on others. Moreover
> > RZ/G3L supports HS400 enhanced strobe mode.
> >
> > This patch series support all modes except HS400. HS400 support will
> > be added later.
> >
> > This patch series tested on smarc-rz{v2l,g2l,g2lc,g2ul,g3s,g3l,g3e},
> > rz{v2h,t2h}-evk and hihope-rz{g2h,g2m,g2n} boards
>
> Tested with a Renesas Salvator-XS board (R-Car M3N). I don't see bugs or performance regressions. I
> think the series is good to go!
Thanks for review and testing. The code is much better now
based on your review feedback.
Cheers,
Biju
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support
2026-10-28 12:51 [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Biju Das
` (11 preceding siblings ...)
2026-11-11 11:48 ` [PATCH v25 00/11] Add Renesas RZ/G3L SD/eMMC support Wolfram Sang
@ 2026-11-11 12:37 ` Ulf Hansson
12 siblings, 0 replies; 22+ messages in thread
From: Ulf Hansson @ 2026-11-11 12:37 UTC (permalink / raw)
To: Biju Das
Cc: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Wolfram Sang, Philipp Zabel,
linux-mmc, devicetree, linux-kernel, linux-renesas-soc, Biju Das,
Conor Dooley
On Wed, Oct 28, 2026 at 1:51 PM Biju Das <biju.das.au@gmail.com> wrote:
>
> Hi All,
>
> The Renesas RZ/G3L SoC has:
>
> Channel 0 supports SD and eMMC (including HS400/HS400ES).
> Channel 1 supports SD and eMMC (except for HS400).
> Channel 2 supports SD.
>
> The SoC supports a maximum frequency of 150 MHz. The SD0 interface does
> not support IOVS and PWEN in the SDHI register (no internal regulator),
> unlike SD1 and SD2. It has an internal divider for all modes except HS400.
> It also has a 2048-bit divider compared to 512 on others. Moreover
> RZ/G3L supports HS400 enhanced strobe mode.
>
> This patch series support all modes except HS400. HS400 support will be
> added later.
>
> This patch series tested on smarc-rz{v2l,g2l,g2lc,g2ul,g3s,g3l,g3e},
> rz{v2h,t2h}-evk and hihope-rz{g2h,g2m,g2n} boards
>
> v24->v25:
> * Added max-frequency is a required property for SoCs with internal
> divider.
> * Retained the tags as the change is trivial.
> * Restored struct of_default_cfg.
> * Updated commit description for patch#3,#4,#6,#10 and #11
> * Dropped initializing clk_mask as it uses the default value.
> * Added suffix ULL to macro SDHI_CLK_MASK_DEFAULT.
> * Fixed a very low or zero clock rate from the clock provider that causes
> an infinite loop in `renesas_sdhi_set_clock` by max operator.
> * Restored the data type of max_divider from signed int to unsigned int.
> * Dropped initializing max_divider as it use default value.
> * Updated mmc->f_min calculation with clk_round_rate().
> * Updated the comment using "ilog2(max_divider)" instead of "{9,11}".
> * Dropped initializing clk_div_mask as it use default value.
> * Updated renesas_sdhi_set_hw_adjustment_delay() with force_clear
> parameter
> * Added a comment in renesas_sdhi_execute_tuning() for tuning delay.
> * In probe, if the SCC registers are not available, it clear the tuning
> delay flag.
> * Dropped default masks from struct of_data_rz_g2l.
> * Dropped renesas_sdhi_is_internal_divider_enabled().
> * Added a comment about the internal divider in
> renesas_sdhi_clk_update() and replaced 'clkh_shift = 1' with
> 'clkh_shift--'
> * Moved mmc->f_max to probe() and made it fail if max-frequency is
> not defined in DT for SoCs with an internal divider.
> * Updated tmio_mmc_host_probe() to set write32_hook() to NULL if
> TMIO_MMC_HAS_IDLE_WAIT is not defined.
> * Added macros RZG3L_SDHI_SCC_HWADJ2_{1_8V,3_3V}
> * Replaced the quirks sdhi_quirks_rzg3l with sdhi_quirks_fixed_addr.
> * Added helper renesas_sdhi_sclken() to handle 16-bit and 32-bit access.
> * Updated renesas_sdhi_set_clock() with max_divider check for
> TMIO_MMC_INTERNAL_DIVIDER instead of SDHI_MAX_DIVIDER_DEFAULT for
> consistency with tmio_mmc_reset().
The v25 series applied for next, thanks!
[...]
Kind regards
Uffe
^ permalink raw reply [flat|nested] 22+ messages in thread