[PATCH v2 2/3] mmc: rockchip_sdhci: Add support for RK3568

Yifeng Zhao yifeng.zhao at rock-chips.com
Mon Jun 28 11:19:51 CEST 2021


This patch adds support for the RK3568 platform to this driver.

Signed-off-by: Yifeng Zhao <yifeng.zhao at rock-chips.com>
---

Changes in v2:
- Used sdhci_set_clock api to set clock.
- Used read_poll_timeout api to check dll status.

 drivers/mmc/rockchip_sdhci.c | 117 +++++++++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)

diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index 2973911446..5ac524c9c9 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -42,6 +42,34 @@
 	((((x) >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK) ==\
 	PHYCTRL_DLLRDY_DONE)
 
+/* Rockchip specific Registers */
+#define DWCMSHC_EMMC_DLL_CTRL		0x800
+#define DWCMSHC_EMMC_DLL_CTRL_RESET	BIT(1)
+#define DWCMSHC_EMMC_DLL_RXCLK		0x804
+#define DWCMSHC_EMMC_DLL_TXCLK		0x808
+#define DWCMSHC_EMMC_DLL_STRBIN		0x80c
+#define DWCMSHC_EMMC_DLL_STATUS0	0x840
+#define DWCMSHC_EMMC_DLL_STATUS1	0x844
+#define DWCMSHC_EMMC_DLL_START		BIT(0)
+#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL	29
+#define DWCMSHC_EMMC_DLL_START_POINT	16
+#define DWCMSHC_EMMC_DLL_START_DEFAULT	5
+#define DWCMSHC_EMMC_DLL_INC_VALUE	2
+#define DWCMSHC_EMMC_DLL_INC		8
+#define DWCMSHC_EMMC_DLL_DLYENA		BIT(27)
+#define DLL_TXCLK_TAPNUM_DEFAULT	0x10
+#define DLL_STRBIN_TAPNUM_DEFAULT	0x3
+#define DLL_TXCLK_TAPNUM_FROM_SW	BIT(24)
+#define DWCMSHC_EMMC_DLL_LOCKED		BIT(8)
+#define DWCMSHC_EMMC_DLL_TIMEOUT	BIT(9)
+#define DLL_RXCLK_NO_INVERTER		1
+#define DLL_RXCLK_INVERTER		0
+#define DWCMSHC_ENHANCED_STROBE		BIT(8)
+#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
+
 struct rockchip_sdhc_plat {
 	struct mmc_config cfg;
 	struct mmc mmc;
@@ -178,6 +206,85 @@ static int rk3399_sdhci_emmc_set_clock(struct sdhci_host *host, unsigned int clo
 	return 0;
 }
 
+static int rk3568_emmc_phy_init(struct udevice *dev)
+{
+	struct rockchip_sdhc *prv = dev_get_priv(dev);
+	struct sdhci_host *host = &prv->host;
+	u32 extra;
+
+	extra = DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL;
+	sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
+
+	return 0;
+}
+
+static int rk3568_sdhci_emmc_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host);
+	int max_clk = host->max_clk;
+	unsigned long mmc_clock;
+	int val, ret;
+	u32 extra;
+
+	if (clock) {
+		mmc_clock = clk_set_rate(&priv->emmc_clk, clock);
+		if (IS_ERR_VALUE(mmc_clock))
+			host->max_clk = max_clk;
+		else
+			host->max_clk = mmc_clock;
+	}
+
+	sdhci_set_clock(host->mmc, clock);
+	if (!clock)
+		return 0;
+	host->max_clk = max_clk;
+
+	if (clock >= 100 * MHz) {
+		/* reset DLL */
+		sdhci_writel(host, DWCMSHC_EMMC_DLL_CTRL_RESET, DWCMSHC_EMMC_DLL_CTRL);
+		udelay(1);
+		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
+
+		/* Init DLL settings */
+		extra = DWCMSHC_EMMC_DLL_START_DEFAULT << DWCMSHC_EMMC_DLL_START_POINT |
+			DWCMSHC_EMMC_DLL_INC_VALUE << DWCMSHC_EMMC_DLL_INC |
+			DWCMSHC_EMMC_DLL_START;
+		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL);
+
+		ret = read_poll_timeout(readl, host->ioaddr + DWCMSHC_EMMC_DLL_STATUS0,
+					val, DLL_LOCK_WO_TMOUT(val), 1, 500);
+		if (ret)
+			return ret;
+
+		extra = DWCMSHC_EMMC_DLL_DLYENA |
+			DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL;
+		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
+
+		extra = DWCMSHC_EMMC_DLL_DLYENA |
+			DLL_TXCLK_TAPNUM_DEFAULT |
+			DLL_TXCLK_TAPNUM_FROM_SW;
+		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
+
+		extra = DWCMSHC_EMMC_DLL_DLYENA |
+			DLL_STRBIN_TAPNUM_DEFAULT;
+		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
+	} else {
+		/* reset the clock phase when the frequency is lower than 100MHz */
+		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
+		extra = DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL;
+		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
+		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
+		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN);
+	}
+
+	return 0;
+}
+
+static int rk3568_emmc_get_phy(struct udevice *dev)
+{
+	return 0;
+}
+
 static int rockchip_sdhci_set_ios_post(struct sdhci_host *host)
 {
 	struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host);
@@ -336,11 +443,21 @@ static const struct sdhci_data rk3399_data = {
 	.emmc_phy_init = rk3399_emmc_phy_init,
 };
 
+static const struct sdhci_data rk3568_data = {
+	.emmc_set_clock = rk3568_sdhci_emmc_set_clock,
+	.get_phy = rk3568_emmc_get_phy,
+	.emmc_phy_init = rk3568_emmc_phy_init,
+};
+
 static const struct udevice_id sdhci_ids[] = {
 	{
 		.compatible = "arasan,sdhci-5.1",
 		.data = (ulong)&rk3399_data,
 	},
+	{
+		.compatible = "rockchip,rk3568-dwcmshc",
+		.data = (ulong)&rk3568_data,
+	},
 	{ }
 };
 
-- 
2.17.1





More information about the U-Boot mailing list