[PATCH v2] mmc: rockchip_sdhci: Set xx_TAP_VALUE for RK3528

Jonas Karlman jonas at kwiboo.se
Sat Nov 1 15:26:25 CET 2025


Hi Kever,

Please consider this patch for v2026.01.

Looking back I think most feedback from Quentin was addressed in this
v2 patch.

This v2 patch can also be found at [1] and the older v1 with the initial
feedback at [2].

[1] https://patchwork.ozlabs.org/patch/2111059/
[2] https://patchwork.ozlabs.org/patch/2109461/

Regards,
Jonas

On 7/14/2025 10:34 PM, Jonas Karlman wrote:
> eMMC erase and write support on RK3528 is somewhat unreliable, sometime
> e.g. mmc erase and write commands will fail with an error.
> 
> Use the delay line lock value for half card clock cycle, DLL_LOCK_VALUE,
> to set a manual xx_TAP_VALUE to fix the unreliable eMMC support.
> 
> This is only enabled for RK3528, remaining SoCs still use the automatic
> tap value, (DLL_LOCK_VALUE * 2) % 256, same value we configure manually
> for RK3528.
> 
> Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
> ---
> Changes in v2:
> - Rename flag and field value to function name, TAPVALUE_FROM_SW
> - Simplify and make code more understandable with use of FIELD_GET/PREP,
>   should be more clear that xx_TAP_VALUE is set to DLL_LOCK_VALUE * 2
> ---
>  drivers/mmc/rockchip_sdhci.c | 27 ++++++++++++++++++++++-----
>  1 file changed, 22 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
> index 761e3619329c..cca917da68e7 100644
> --- a/drivers/mmc/rockchip_sdhci.c
> +++ b/drivers/mmc/rockchip_sdhci.c
> @@ -9,6 +9,7 @@
>  #include <dm.h>
>  #include <dm/ofnode.h>
>  #include <dt-structs.h>
> +#include <linux/bitfield.h>
>  #include <linux/delay.h>
>  #include <linux/err.h>
>  #include <linux/libfdt.h>
> @@ -86,6 +87,9 @@
>  #define DLL_CMDOUT_SRC_CLK_NEG		BIT(28)
>  #define DLL_CMDOUT_EN_SRC_CLK_NEG	BIT(29)
>  #define DLL_CMDOUT_BOTH_CLK_EDGE	BIT(30)
> +#define DLL_TAPVALUE_FROM_SW		BIT(25)
> +#define DLL_TAP_VALUE_PREP(x)		FIELD_PREP(GENMASK(15, 8), (x))
> +#define DLL_LOCK_VALUE_GET(x)		FIELD_GET(GENMASK(7, 0), (x))
>  
>  #define DLL_LOCK_WO_TMOUT(x) \
>  	((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
> @@ -93,6 +97,7 @@
>  #define ROCKCHIP_MAX_CLKS		3
>  
>  #define FLAG_INVERTER_FLAG_IN_RXCLK	BIT(0)
> +#define FLAG_TAPVALUE_FROM_SW		BIT(1)
>  
>  struct rockchip_sdhc_plat {
>  	struct mmc_config cfg;
> @@ -317,7 +322,7 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab
>  	struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev);
>  	struct mmc *mmc = host->mmc;
>  	int val, ret;
> -	u32 extra, txclk_tapnum;
> +	u32 extra, txclk_tapnum, dll_tap_value;
>  
>  	if (!enable) {
>  		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
> @@ -347,7 +352,15 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab
>  		if (ret)
>  			return ret;
>  
> -		extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE;
> +		if (data->flags & FLAG_TAPVALUE_FROM_SW)
> +			dll_tap_value = DLL_TAPVALUE_FROM_SW |
> +					DLL_TAP_VALUE_PREP(DLL_LOCK_VALUE_GET(val) * 2);
> +		else
> +			dll_tap_value = 0;
> +
> +		extra = DWCMSHC_EMMC_DLL_DLYENA |
> +			DLL_RXCLK_ORI_GATE |
> +			dll_tap_value;
>  		if (data->flags & FLAG_INVERTER_FLAG_IN_RXCLK)
>  			extra |= DLL_RXCLK_NO_INVERTER;
>  		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
> @@ -361,19 +374,22 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab
>  				DLL_CMDOUT_BOTH_CLK_EDGE |
>  				DWCMSHC_EMMC_DLL_DLYENA |
>  				data->hs400_cmdout_tapnum |
> -				DLL_CMDOUT_TAPNUM_FROM_SW;
> +				DLL_CMDOUT_TAPNUM_FROM_SW |
> +				dll_tap_value;
>  			sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CMDOUT);
>  		}
>  
>  		extra = DWCMSHC_EMMC_DLL_DLYENA |
>  			DLL_TXCLK_TAPNUM_FROM_SW |
>  			DLL_TXCLK_NO_INVERTER |
> -			txclk_tapnum;
> +			txclk_tapnum |
> +			dll_tap_value;
>  		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
>  
>  		extra = DWCMSHC_EMMC_DLL_DLYENA |
>  			data->hs400_strbin_tapnum |
> -			DLL_STRBIN_TAPNUM_FROM_SW;
> +			DLL_STRBIN_TAPNUM_FROM_SW |
> +			dll_tap_value;
>  		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
>  	} else {
>  		/*
> @@ -663,6 +679,7 @@ static const struct sdhci_data rk3528_data = {
>  	.set_ios_post = rk3568_sdhci_set_ios_post,
>  	.set_clock = rk3568_sdhci_set_clock,
>  	.config_dll = rk3568_sdhci_config_dll,
> +	.flags = FLAG_TAPVALUE_FROM_SW,
>  	.hs200_txclk_tapnum = 0xc,
>  	.hs400_txclk_tapnum = 0x6,
>  	.hs400_cmdout_tapnum = 0x6,



More information about the U-Boot mailing list