Add support for RK3588 to the rockchip sdhci driver.

Use driver data to handle differences between RK3568 and RK3588:

- Set "Receive original clock source is auto gating" for RK3588.
- Set "Receive clock source is no-inverted" only on RK3568 and "Transmit
  clock source is invertion of original clock input" for RK3588.
- Use different txclk_tapnum for HS400 modes on RK3588.
- Configure the CMDOUT reg for HS400 modes for RK3588.

This is based on the mainline linux and vendor kernel driver and have
successfully been tested with rock5b-rk3588_defconfig and

  CONFIG_MMC_HS200_SUPPORT=y
  CONFIG_MMC_HS400_SUPPORT=y
  CONFIG_MMC_HS400_ES_SUPPORT=y
  CONFIG_MMC_SPEED_MODE_SET=y

using the following command to switch mode and then read 512 MiB of data
from eMMC into memory,

  => mmc dev 0 0 <mode> && mmc info && mmc read 10000000 2000 10000

for each of the modes below.

  0 = MMC legacy
  1 = MMC High Speed (26MHz)
  3 = MMC High Speed (52MHz)
  4 = MMC DDR52 (52MHz)
  10 = HS200 (200MHz)
  11 = HS400 (200MHz)
  12 = HS400ES (200MHz)

Signed-off-by: Yifeng Zhao <yifeng.z...@rock-chips.com>
Signed-off-by: Jonas Karlman <jo...@kwiboo.se>
Reviewed-by: Shawn Lin <shawn....@rock-chips.com>
---
v2:
- Add Signed-off-by tag
- Update commit message
- Rename quirks to flags
- Save HS200/HS400 txclk_tapnum as driver data
- Remove use of rockchip,txclk-tapnum prop
- Collect r-b tag

 drivers/mmc/rockchip_sdhci.c | 57 +++++++++++++++++++++++++++++++++---
 1 file changed, 53 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index 12a616d3dfb8..2857dcc9ec4f 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -56,6 +56,7 @@
 #define DWCMSHC_EMMC_DLL_RXCLK         0x804
 #define DWCMSHC_EMMC_DLL_TXCLK         0x808
 #define DWCMSHC_EMMC_DLL_STRBIN                0x80c
+#define DWCMSHC_EMMC_DLL_CMDOUT                0x810
 #define DWCMSHC_EMMC_DLL_STATUS0       0x840
 #define DWCMSHC_EMMC_DLL_STATUS1       0x844
 #define DWCMSHC_EMMC_DLL_START         BIT(0)
@@ -70,18 +71,27 @@
 #define DLL_RXCLK_NO_INVERTER          BIT(29)
 #define DLL_RXCLK_ORI_GATE             BIT(31)
 #define DLL_TXCLK_TAPNUM_DEFAULT       0x10
+#define DLL_TXCLK_TAPNUM_90_DEGREES    0x9
 #define DLL_TXCLK_TAPNUM_FROM_SW       BIT(24)
+#define DLL_TXCLK_NO_INVERTER          BIT(29)
 #define DLL_STRBIN_TAPNUM_DEFAULT      0x4
 #define DLL_STRBIN_TAPNUM_FROM_SW      BIT(24)
 #define DLL_STRBIN_DELAY_NUM_SEL       BIT(26)
 #define DLL_STRBIN_DELAY_NUM_OFFSET    16
 #define DLL_STRBIN_DELAY_NUM_DEFAULT   0x10
+#define DLL_CMDOUT_TAPNUM_90_DEGREES   0x8
+#define DLL_CMDOUT_TAPNUM_FROM_SW      BIT(24)
+#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_LOCK_WO_TMOUT(x) \
        ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
        (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
 #define ROCKCHIP_MAX_CLKS              3
 
+#define FLAG_INVERTER_FLAG_IN_RXCLK    BIT(0)
+
 struct rockchip_sdhc_plat {
        struct mmc_config cfg;
        struct mmc mmc;
@@ -144,6 +154,10 @@ struct sdhci_data {
         * Return: 0 if successful, -ve on error
         */
        int (*set_enhanced_strobe)(struct sdhci_host *host);
+
+       u32 flags;
+       u8 hs200_txclk_tapnum;
+       u8 hs400_txclk_tapnum;
 };
 
 static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock)
@@ -294,8 +308,11 @@ static void rk3568_sdhci_set_clock(struct sdhci_host 
*host, u32 div)
 
 static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool 
enable)
 {
+       struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, 
host);
+       struct sdhci_data *data = (struct sdhci_data 
*)dev_get_driver_data(priv->dev);
+       struct mmc *mmc = host->mmc;
        int val, ret;
-       u32 extra;
+       u32 extra, txclk_tapnum;
 
        if (!enable)
                return 0;
@@ -318,12 +335,28 @@ 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_NO_INVERTER;
+               extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE;
+               if (data->flags & FLAG_INVERTER_FLAG_IN_RXCLK)
+                       extra |= DLL_RXCLK_NO_INVERTER;
                sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
 
+               txclk_tapnum = data->hs200_txclk_tapnum;
+               if (mmc->selected_mode == MMC_HS_400 ||
+                   mmc->selected_mode == MMC_HS_400_ES) {
+                       txclk_tapnum = data->hs400_txclk_tapnum;
+
+                       extra = DLL_CMDOUT_SRC_CLK_NEG |
+                               DLL_CMDOUT_BOTH_CLK_EDGE |
+                               DWCMSHC_EMMC_DLL_DLYENA |
+                               DLL_CMDOUT_TAPNUM_90_DEGREES |
+                               DLL_CMDOUT_TAPNUM_FROM_SW;
+                       sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CMDOUT);
+               }
+
                extra = DWCMSHC_EMMC_DLL_DLYENA |
-                       DLL_TXCLK_TAPNUM_DEFAULT |
-                       DLL_TXCLK_TAPNUM_FROM_SW;
+                       DLL_TXCLK_TAPNUM_FROM_SW |
+                       DLL_TXCLK_NO_INVERTER |
+                       txclk_tapnum;
                sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
 
                extra = DWCMSHC_EMMC_DLL_DLYENA |
@@ -339,6 +372,7 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, 
u32 clock, bool enab
                sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL);
                sdhci_writel(host, DLL_RXCLK_ORI_GATE, DWCMSHC_EMMC_DLL_RXCLK);
                sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
+               sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CMDOUT);
                /*
                 * Before switching to hs400es mode, the driver will enable
                 * enhanced strobe first. PHY needs to configure the parameters
@@ -594,6 +628,17 @@ static const struct sdhci_data rk3568_data = {
        .set_ios_post = rk3568_sdhci_set_ios_post,
        .set_clock = rk3568_sdhci_set_clock,
        .config_dll = rk3568_sdhci_config_dll,
+       .flags = FLAG_INVERTER_FLAG_IN_RXCLK,
+       .hs200_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT,
+       .hs400_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT,
+};
+
+static const struct sdhci_data rk3588_data = {
+       .set_ios_post = rk3568_sdhci_set_ios_post,
+       .set_clock = rk3568_sdhci_set_clock,
+       .config_dll = rk3568_sdhci_config_dll,
+       .hs200_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT,
+       .hs400_txclk_tapnum = DLL_TXCLK_TAPNUM_90_DEGREES,
 };
 
 static const struct udevice_id sdhci_ids[] = {
@@ -605,6 +650,10 @@ static const struct udevice_id sdhci_ids[] = {
                .compatible = "rockchip,rk3568-dwcmshc",
                .data = (ulong)&rk3568_data,
        },
+       {
+               .compatible = "rockchip,rk3588-dwcmshc",
+               .data = (ulong)&rk3588_data,
+       },
        { }
 };
 
-- 
2.40.0

Reply via email to