|
|
@@ -0,0 +1,109 @@
|
|
|
+From 498a9756adf57e94af64e31b144a6698c656c50a Mon Sep 17 00:00:00 2001
|
|
|
+From: Jonas Karlman <[email protected]>
|
|
|
+Date: Mon, 14 Jul 2025 20:34:07 +0000
|
|
|
+Subject: [PATCH] mmc: rockchip_sdhci: Set xx_TAP_VALUE for RK3528
|
|
|
+
|
|
|
+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 <[email protected]>
|
|
|
+Reviewed-by: Kever Yang <[email protected]>
|
|
|
+---
|
|
|
+ drivers/mmc/rockchip_sdhci.c | 27 ++++++++++++++++++++++-----
|
|
|
+ 1 file changed, 22 insertions(+), 5 deletions(-)
|
|
|
+
|
|
|
+--- 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(struc
|
|
|
+ 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(struc
|
|
|
+ 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(struc
|
|
|
+ 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_da
|
|
|
+ .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,
|