clk: rockchip: rk356x: Set twice the SD/SDIO card clock
Subsystems (2)
PATCH 1/1 clk: rockchip: rk356x: Set twice the SD/SDIO card clock
The dw_mmc controllers divide their input clock by 2, but rk3568_sdmmc_set_clk() selects a parent equal to the requested card clock, so the card runs at half of it: 25 MHz instead of 50 MHz in high speed mode. The RK3399 and RK3328 clock drivers already set twice the rate for their dw_mmc controllers.
Select the fastest parent that does not exceed twice the requested rate, or the slowest one, and report half of the parent rate.
On ODROID-M1 with a SanDisk 128 GB card in high speed mode, reading 512 MiB with mmc read takes 22 s instead of 44 s.
---
Tested on ODROID-M1 with this change on v2026.07: CLKSEL_CON(30) selects the 100 MHz parent for a 50 MHz card clock. The CRC32 of a 512 MiB block read with mmc read is the same at 25 and 50 MHz, and the CRC32 of another block is the same as computed in Linux. With the SPL erased from SPI, SPL and U-Boot load from the SD card, also after two resets with sysrq-b.
--- drivers/clk/rockchip/clk_rk3568.c | 43 +++++++++++++++------------------------ 1 file changed, 16 insertions(+), 27 deletions(-)
drivers/clk/rockchip/clk_rk3568.c +16 -27
@@ -1426,19 +1426,20 @@ static ulong rk3568_sdmmc_get_clk(struct rk3568_clk_priv *priv, ulong clk_id)return -ENOENT ; } +/* The card clock is half of the parent: dw_mmc divides it by 2 */ switch (sel) {case CLK_SDMMC_SEL_24M : -return OSC_HZ ; +return OSC_HZ /2 ;case CLK_SDMMC_SEL_400M : -return 400 * MHz; +return 400 * MHz /2 ;case CLK_SDMMC_SEL_300M : -return 300 * MHz; +return 300 * MHz /2 ;case CLK_SDMMC_SEL_100M : -return 100 * MHz; +return 100 * MHz /2 ;case CLK_SDMMC_SEL_50M : -return 50 * MHz; +return 50 * MHz /2 ;case CLK_SDMMC_SEL_750K : -return 750 * KHz; +return 750 * KHz /2 ;default :return -ENOENT ; }
@@ -1448,34 +1449,22 @@ static ulong rk3568_sdmmc_set_clk(struct rk3568_clk_priv *priv, ulong clk_id, ulong rate) {struct rk3568_cru *cru = priv->cru; +ulong parent = rate *2 ;int src_clk; -switch (rate) { -case OSC_HZ : -case 26 * MHz: -case 25 * MHz: - src_clk =CLK_SDMMC_SEL_24M ; -break ; -case 400 * MHz: +/* Fastest parent not above twice the card clock, or the slowest one */ +if (parent >=400 * MHz) src_clk =CLK_SDMMC_SEL_400M ; -break ; -case 300 * MHz: +else if (parent >=300 * MHz) src_clk =CLK_SDMMC_SEL_300M ; -break ; -case 100 * MHz: +else if (parent >=100 * MHz) src_clk =CLK_SDMMC_SEL_100M ; -break ; -case 52 * MHz: -case 50 * MHz: +else if (parent >=50 * MHz) src_clk =CLK_SDMMC_SEL_50M ; -break ; -case 750 * KHz: -case 400 * KHz: +else if (parent >=OSC_HZ ) + src_clk =CLK_SDMMC_SEL_24M ; +else src_clk =CLK_SDMMC_SEL_750K ; -break ; -default : -return -ENOENT ; - }switch (clk_id) {case HCLK_SDMMC0 :
---
base-commit: ecdcf9e365df6249a57cd8cc946e7026804ff4ae
change-id: 20261110-rk3568-sdmmc-clk-95bccae72277
Best regards,
Signature · 1 line
Igor Velkov <[email protected]>
Hi Igor,
Quoted 7 lines · On 11/10/2026 5:30 AM, Igor Velkov via B4 Relay wrote:
From: Igor Velkov <[email protected]>
The
dw_mmccontrollers divide their input clock by 2, butrk3568_sdmmc_set_clk()selects a parent equal to the requested card clock, so the card runs at half of it: 25 MHz instead of 50 MHz in high speed mode. The RK3399 and RK3328 clock drivers already set twice the rate for theirdw_mmccontrollers.
This 2x clock rate should not be handled in the clock drivers, it should similar to Linux be handled in the rockchip dw_mmc driver. The Linux driver seem to use RK3288_CLKGEN_DIV (2) to request the 2x rate, something like:
cclkin = ios->clock * RK3288_CLKGEN_DIV; ret = clk_set_rate(host->ciu_clk, cclkin);
Please instead fix the U-Boot rockchip dw_mmc driver to do something similar and move current 2x handling from rk3399 and rk3328 clock drivers.
We should expect the clock drivers to report correct rate for a clock and not use it to workaround quirks in device drivers.
Regards,
Jonas
Quoted 100 lines
Select the fastest parent that does not exceed twice the requested rate, or the slowest one, and report half of the parent rate.
On ODROID-M1 with a SanDisk 128 GB card in high speed mode, reading 512 MiB with mmc read takes 22 s instead of 44 s.
Fixes 4a262feba3a5 ("rockchip: rk3568: add clock driver")Signed-off-by Igor Velkov <[email protected]>---
Tested on ODROID-M1 with this change on v2026.07:CLKSEL_CON(30)selects the 100 MHz parent for a 50 MHz card clock. The CRC32 of a 512 MiB block read with mmc read is the same at 25 and 50 MHz, and the CRC32 of another block is the same as computed in Linux. With the SPL erased from SPI, SPL and U-Boot load from the SD card, also after two resets with sysrq-b.--- drivers/clk/rockchip/clk_rk3568.c | 43 +++++++++++++++------------------------ 1 file changed, 16 insertions(+), 27 deletions(-)drivers/clk/rockchip/clk_rk3568.c +16
-28@@ -1426,19 +1426,20 @@ static ulong rk3568_sdmmc_get_clk(struct rk3568_clk_priv *priv, ulong clk_id)return -ENOENT ; } +/* The card clock is half of the parent: dw_mmc divides it by 2 */ switch (sel) {case CLK_SDMMC_SEL_24M : -return OSC_HZ ; +return OSC_HZ /2 ;case CLK_SDMMC_SEL_400M : -return 400 * MHz; +return 400 * MHz /2 ;case CLK_SDMMC_SEL_300M : -return 300 * MHz; +return 300 * MHz /2 ;case CLK_SDMMC_SEL_100M : -return 100 * MHz; +return 100 * MHz /2 ;case CLK_SDMMC_SEL_50M : -return 50 * MHz; +return 50 * MHz /2 ;case CLK_SDMMC_SEL_750K : -return 750 * KHz; +return 750 * KHz /2 ;default :return -ENOENT ; }@@ -1448,34 +1449,22 @@ static ulong rk3568_sdmmc_set_clk(struct rk3568_clk_priv *priv, ulong clk_id, ulong rate) {struct rk3568_cru *cru = priv->cru; +ulong parent = rate *2 ;int src_clk; -switch (rate) { -case OSC_HZ : -case 26 * MHz: -case 25 * MHz: - src_clk =CLK_SDMMC_SEL_24M ; -break ; -case 400 * MHz: +/* Fastest parent not above twice the card clock, or the slowest one */ +if (parent >=400 * MHz) src_clk =CLK_SDMMC_SEL_400M ; -break ; -case 300 * MHz: +else if (parent >=300 * MHz) src_clk =CLK_SDMMC_SEL_300M ; -break ; -case 100 * MHz: +else if (parent >=100 * MHz) src_clk =CLK_SDMMC_SEL_100M ; -break ; -case 52 * MHz: -case 50 * MHz: +else if (parent >=50 * MHz) src_clk =CLK_SDMMC_SEL_50M ; -break ; -case 750 * KHz: -case 400 * KHz: +else if (parent >=OSC_HZ ) + src_clk =CLK_SDMMC_SEL_24M ; +else src_clk =CLK_SDMMC_SEL_750K ; -break ; -default : -return -ENOENT ; - }switch (clk_id) {case HCLK_SDMMC0 : ---base-commit:
ecdcf9e365df6249a57cd8cc946e7026804ff4ae
change-id: 20261110-rk3568-sdmmc-clk-95bccae72277Best regards,
Hi Jonas,
Quoted 2 lines · Jonas Karlman
Please instead fix the U-Boot rockchip
dw_mmcdriver to do something similar and move current 2x handling from rk3399 and rk3328 clock drivers.
The 2x is in 13 clock drivers: rk3066, rk3188, rk322x, rk3288, rk3328, px30, rk3308, rk3399, rv1126, rk3036 and rv1108 (eMMC only), rk3128 and rk3368 (dead: set_rate lacks the SCLK_* ids the DT passes). rk3506, rk3528, rk3568, rk3576 and rk3588 don't double. rk3066/rk3188 are rk2928-dw-mshc, which Linux does not halve. Moving the 2x into rockchip_dw_mmc touches all 13 at once; I can test rk3328, rk3399 and rk3568 only. Is one series on that basis acceptable, rest compile-tested?
Igor