xref: /rk3399_rockchip-uboot/drivers/mmc/rockchip_sdhci.c (revision 1bf19a93d4306fc9da3df7bbb0e7db9b2bfa1a1a)
179c83065SKever Yang /*
279c83065SKever Yang  * (C) Copyright 2016 Fuzhou Rockchip Electronics Co., Ltd
379c83065SKever Yang  *
479c83065SKever Yang  * Rockchip SD Host Controller Interface
579c83065SKever Yang  *
679c83065SKever Yang  * SPDX-License-Identifier:	GPL-2.0+
779c83065SKever Yang  */
879c83065SKever Yang 
9dce4cf74SZiyuan Xu #include <asm/arch/hardware.h>
1079c83065SKever Yang #include <common.h>
1179c83065SKever Yang #include <dm.h>
12c2868212SKever Yang #include <dt-structs.h>
130e00a84cSMasahiro Yamada #include <linux/libfdt.h>
1479c83065SKever Yang #include <malloc.h>
15c2868212SKever Yang #include <mapmem.h>
1679c83065SKever Yang #include <sdhci.h>
1739fbb56fSKever Yang #include <clk.h>
182f972333SKever Yang #include <syscon.h>
192f972333SKever Yang #include <dm/ofnode.h>
202f972333SKever Yang #include <asm/arch/clock.h>
2179c83065SKever Yang 
2239fbb56fSKever Yang DECLARE_GLOBAL_DATA_PTR;
2379c83065SKever Yang /* 400KHz is max freq for card ID etc. Use that as min */
2479c83065SKever Yang #define EMMC_MIN_FREQ	400000
2505f3b0abSJason Zhu #define KHz	(1000)
2605f3b0abSJason Zhu #define MHz	(1000 * KHz)
2705f3b0abSJason Zhu 
2805f3b0abSJason Zhu #define PHYCTRL_CALDONE_MASK		0x1
2905f3b0abSJason Zhu #define PHYCTRL_CALDONE_SHIFT		0x6
3005f3b0abSJason Zhu #define PHYCTRL_CALDONE_DONE		0x1
3105f3b0abSJason Zhu #define PHYCTRL_DLLRDY_MASK		0x1
3205f3b0abSJason Zhu #define PHYCTRL_DLLRDY_SHIFT		0x5
3305f3b0abSJason Zhu #define PHYCTRL_DLLRDY_DONE		0x1
3405f3b0abSJason Zhu #define PHYCTRL_FREQSEL_200M		0x0
3505f3b0abSJason Zhu #define PHYCTRL_FREQSEL_50M		0x1
3605f3b0abSJason Zhu #define PHYCTRL_FREQSEL_100M		0x2
3705f3b0abSJason Zhu #define PHYCTRL_FREQSEL_150M		0x3
380bcee30cSYifeng Zhao #define PHYCTRL_DLL_LOCK_WO_TMOUT(x)	\
390bcee30cSYifeng Zhao 	((((x) >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK) ==\
400bcee30cSYifeng Zhao 	PHYCTRL_DLLRDY_DONE)
4179c83065SKever Yang 
4213669fc5SYifeng Zhao #define ARASAN_VENDOR_REGISTER		0x78
4313669fc5SYifeng Zhao #define ARASAN_VENDOR_ENHANCED_STROBE	BIT(0)
4413669fc5SYifeng Zhao 
4513669fc5SYifeng Zhao /* DWC IP vendor area 1 pointer */
4613669fc5SYifeng Zhao #define DWCMSHC_P_VENDOR_AREA1		0xe8
4713669fc5SYifeng Zhao #define DWCMSHC_AREA1_MASK		GENMASK(11, 0)
48b7b23550SJason Zhu /* Rockchip specific Registers */
49a4de9ecaSYifeng Zhao #define DWCMSHC_CTRL_HS400		0x7
50a4de9ecaSYifeng Zhao #define DWCMSHC_CARD_IS_EMMC		BIT(0)
51a4de9ecaSYifeng Zhao #define DWCMSHC_ENHANCED_STROBE		BIT(8)
52a4de9ecaSYifeng Zhao 
53a4de9ecaSYifeng Zhao #define DWCMSHC_HOST_CTRL3		0x508
54a4de9ecaSYifeng Zhao #define DWCMSHC_EMMC_CONTROL		0x52c
5513669fc5SYifeng Zhao #define DWCMSHC_EMMC_ATCTRL		0x540
56b7b23550SJason Zhu #define DWCMSHC_EMMC_DLL_CTRL		0x800
570bcee30cSYifeng Zhao #define DWCMSHC_EMMC_DLL_CTRL_RESET	BIT(1)
5828b3b131SYifeng Zhao #define DWCMSHC_EMMC_DLL_RXCLK		0x804
5928b3b131SYifeng Zhao #define DWCMSHC_EMMC_DLL_TXCLK		0x808
60b7b23550SJason Zhu #define DWCMSHC_EMMC_DLL_STRBIN		0x80c
610bcee30cSYifeng Zhao #define DECMSHC_EMMC_DLL_CMDOUT		0x810
6228b3b131SYifeng Zhao #define DWCMSHC_EMMC_DLL_STATUS0	0x840
6328b3b131SYifeng Zhao #define DWCMSHC_EMMC_DLL_STATUS1	0x844
64b7b23550SJason Zhu #define DWCMSHC_EMMC_DLL_START		BIT(0)
65b7b23550SJason Zhu #define DWCMSHC_EMMC_DLL_START_POINT	16
660bcee30cSYifeng Zhao #define DWCMSHC_EMMC_DLL_START_DEFAULT	5
670bcee30cSYifeng Zhao #define DWCMSHC_EMMC_DLL_INC_VALUE	2
68b7b23550SJason Zhu #define DWCMSHC_EMMC_DLL_INC		8
6913669fc5SYifeng Zhao #define DWCMSHC_EMMC_DLL_BYPASS		BIT(24)
70b7b23550SJason Zhu #define DWCMSHC_EMMC_DLL_DLYENA		BIT(27)
7190747fa1SYifeng Zhao #define DLL_TXCLK_TAPNUM_DEFAULT	0x10
725e555c00SYifeng Zhao #define DLL_TXCLK_TAPNUM_90_DEGREES	0x9
735e555c00SYifeng Zhao #define DLL_STRBIN_TAPNUM_DEFAULT	0x4
7413669fc5SYifeng Zhao #define DLL_STRBIN_DELAY_NUM_OFFSET	16
755e555c00SYifeng Zhao #define DLL_STRBIN_TAPNUM_FROM_SW	BIT(24)
765e555c00SYifeng Zhao #define DLL_STRBIN_DELAY_NUM_SEL	BIT(26)
7760238d95SJason Zhu #define DLL_TXCLK_TAPNUM_FROM_SW	BIT(24)
78a4de9ecaSYifeng Zhao #define DLL_TXCLK_NO_INVERTER		BIT(29)
79b7b23550SJason Zhu #define DWCMSHC_EMMC_DLL_LOCKED		BIT(8)
80b7b23550SJason Zhu #define DWCMSHC_EMMC_DLL_TIMEOUT	BIT(9)
81ed382477SYifeng Zhao #define DLL_TAP_VALUE_SEL		BIT(25)
82ed382477SYifeng Zhao #define DLL_TAP_VALUE_OFFSET		8
835e555c00SYifeng Zhao #define DLL_RXCLK_NO_INVERTER		BIT(29)
845e555c00SYifeng Zhao #define DLL_RXCLK_ORI_GATE		BIT(31)
850bcee30cSYifeng Zhao #define DLL_CMDOUT_TAPNUM_90_DEGREES	0x8
860bcee30cSYifeng Zhao #define DLL_CMDOUT_TAPNUM_FROM_SW	BIT(24)
870bcee30cSYifeng Zhao #define DLL_CMDOUT_SRC_CLK_NEG		BIT(28)
88a4de9ecaSYifeng Zhao #define DLL_CMDOUT_EN_SRC_CLK_NEG	BIT(29)
8913669fc5SYifeng Zhao #define DLL_CMDOUT_BOTH_CLK_EDGE	BIT(30)
900bcee30cSYifeng Zhao 
91b7b23550SJason Zhu #define DWCMSHC_ENHANCED_STROBE		BIT(8)
92b7b23550SJason Zhu #define DLL_LOCK_WO_TMOUT(x) \
93b7b23550SJason Zhu 	((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
94b7b23550SJason Zhu 	(((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
95b7b23550SJason Zhu #define ROCKCHIP_MAX_CLKS		3
96b7b23550SJason Zhu 
9779c83065SKever Yang struct rockchip_sdhc_plat {
98c2868212SKever Yang #if CONFIG_IS_ENABLED(OF_PLATDATA)
99c2868212SKever Yang 	struct dtd_rockchip_rk3399_sdhci_5_1 dtplat;
100c2868212SKever Yang #endif
10179c83065SKever Yang 	struct mmc_config cfg;
10279c83065SKever Yang 	struct mmc mmc;
10379c83065SKever Yang };
10479c83065SKever Yang 
105dce4cf74SZiyuan Xu struct rockchip_emmc_phy {
106dce4cf74SZiyuan Xu 	u32 emmcphy_con[7];
107dce4cf74SZiyuan Xu 	u32 reserved;
108dce4cf74SZiyuan Xu 	u32 emmcphy_status;
109dce4cf74SZiyuan Xu };
110dce4cf74SZiyuan Xu 
11179c83065SKever Yang struct rockchip_sdhc {
11279c83065SKever Yang 	struct sdhci_host host;
11305f3b0abSJason Zhu 	struct udevice *dev;
11479c83065SKever Yang 	void *base;
115dce4cf74SZiyuan Xu 	struct rockchip_emmc_phy *phy;
116cc0bf5edSchenfen 	struct clk emmc_clk;
11779c83065SKever Yang };
11879c83065SKever Yang 
11905f3b0abSJason Zhu struct sdhci_data {
12005f3b0abSJason Zhu 	int (*emmc_set_clock)(struct sdhci_host *host, unsigned int clock);
121a4de9ecaSYifeng Zhao 	void (*set_ios_post)(struct sdhci_host *host);
12213669fc5SYifeng Zhao 	int (*set_enhanced_strobe)(struct sdhci_host *host);
12305f3b0abSJason Zhu 	int (*get_phy)(struct udevice *dev);
124f9527902SYifeng Zhao 	u32 flags;
125f9527902SYifeng Zhao #define RK_DLL_CMD_OUT		BIT(1)
126f9527902SYifeng Zhao #define RK_RXCLK_NO_INVERTER	BIT(2)
127ed382477SYifeng Zhao #define RK_TAP_VALUE_SEL	BIT(3)
1285e555c00SYifeng Zhao 
1295e555c00SYifeng Zhao 	u8 hs200_tx_tap;
1305e555c00SYifeng Zhao 	u8 hs400_tx_tap;
1315e555c00SYifeng Zhao 	u8 hs400_cmd_tap;
1325e555c00SYifeng Zhao 	u8 hs400_strbin_tap;
13313669fc5SYifeng Zhao 	u8 ddr50_strbin_delay_num;
13405f3b0abSJason Zhu };
135dce4cf74SZiyuan Xu 
rk3399_emmc_phy_power_on(struct rockchip_emmc_phy * phy,u32 clock)136dce4cf74SZiyuan Xu static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock)
137dce4cf74SZiyuan Xu {
138dce4cf74SZiyuan Xu 	u32 caldone, dllrdy, freqsel;
139dce4cf74SZiyuan Xu 	uint start;
140dce4cf74SZiyuan Xu 
141dce4cf74SZiyuan Xu 	writel(RK_CLRSETBITS(7 << 4, 0), &phy->emmcphy_con[6]);
142dce4cf74SZiyuan Xu 	writel(RK_CLRSETBITS(1 << 11, 1 << 11), &phy->emmcphy_con[0]);
143cc0bf5edSchenfen 	writel(RK_CLRSETBITS(0xf << 7, 6 << 7), &phy->emmcphy_con[0]);
144dce4cf74SZiyuan Xu 
145dce4cf74SZiyuan Xu 	/*
146dce4cf74SZiyuan Xu 	 * According to the user manual, calpad calibration
147dce4cf74SZiyuan Xu 	 * cycle takes more than 2us without the minimal recommended
148dce4cf74SZiyuan Xu 	 * value, so we may need a little margin here
149dce4cf74SZiyuan Xu 	 */
150dce4cf74SZiyuan Xu 	udelay(3);
151dce4cf74SZiyuan Xu 	writel(RK_CLRSETBITS(1, 1), &phy->emmcphy_con[6]);
152dce4cf74SZiyuan Xu 
153dce4cf74SZiyuan Xu 	/*
154dce4cf74SZiyuan Xu 	 * According to the user manual, it asks driver to
15510f01e73SZiyuan Xu 	 * wait 5us for calpad busy trimming. But it seems that
15610f01e73SZiyuan Xu 	 * 5us of caldone isn't enough for all cases.
157dce4cf74SZiyuan Xu 	 */
15810f01e73SZiyuan Xu 	udelay(500);
159dce4cf74SZiyuan Xu 	caldone = readl(&phy->emmcphy_status);
160dce4cf74SZiyuan Xu 	caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK;
161dce4cf74SZiyuan Xu 	if (caldone != PHYCTRL_CALDONE_DONE) {
162fafc4637SZiyuan Xu 		printf("%s: caldone timeout.\n", __func__);
163dce4cf74SZiyuan Xu 		return;
164dce4cf74SZiyuan Xu 	}
165dce4cf74SZiyuan Xu 
166dce4cf74SZiyuan Xu 	/* Set the frequency of the DLL operation */
167dce4cf74SZiyuan Xu 	if (clock < 75 * MHz)
168dce4cf74SZiyuan Xu 		freqsel = PHYCTRL_FREQSEL_50M;
169dce4cf74SZiyuan Xu 	else if (clock < 125 * MHz)
170dce4cf74SZiyuan Xu 		freqsel = PHYCTRL_FREQSEL_100M;
171dce4cf74SZiyuan Xu 	else if (clock < 175 * MHz)
172dce4cf74SZiyuan Xu 		freqsel = PHYCTRL_FREQSEL_150M;
173dce4cf74SZiyuan Xu 	else
174dce4cf74SZiyuan Xu 		freqsel = PHYCTRL_FREQSEL_200M;
175dce4cf74SZiyuan Xu 
176dce4cf74SZiyuan Xu 	/* Set the frequency of the DLL operation */
177dce4cf74SZiyuan Xu 	writel(RK_CLRSETBITS(3 << 12, freqsel << 12), &phy->emmcphy_con[0]);
178dce4cf74SZiyuan Xu 	writel(RK_CLRSETBITS(1 << 1, 1 << 1), &phy->emmcphy_con[6]);
179dce4cf74SZiyuan Xu 
180a4ec4b18SNico Cheng 	/* REN Enable on STRB Line for HS400 */
181a4ec4b18SNico Cheng 	writel(RK_CLRSETBITS(0, 1 << 9), &phy->emmcphy_con[2]);
182a4ec4b18SNico Cheng 
183dce4cf74SZiyuan Xu 	start = get_timer(0);
184dce4cf74SZiyuan Xu 
185dce4cf74SZiyuan Xu 	do {
186dce4cf74SZiyuan Xu 		udelay(1);
187dce4cf74SZiyuan Xu 		dllrdy = readl(&phy->emmcphy_status);
188dce4cf74SZiyuan Xu 		dllrdy = (dllrdy >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK;
189dce4cf74SZiyuan Xu 		if (dllrdy == PHYCTRL_DLLRDY_DONE)
190dce4cf74SZiyuan Xu 			break;
191dce4cf74SZiyuan Xu 	} while (get_timer(start) < 50000);
192dce4cf74SZiyuan Xu 
193dce4cf74SZiyuan Xu 	if (dllrdy != PHYCTRL_DLLRDY_DONE)
194fafc4637SZiyuan Xu 		printf("%s: dllrdy timeout.\n", __func__);
195dce4cf74SZiyuan Xu }
196dce4cf74SZiyuan Xu 
rk3399_emmc_phy_power_off(struct rockchip_emmc_phy * phy)197dce4cf74SZiyuan Xu static void rk3399_emmc_phy_power_off(struct rockchip_emmc_phy *phy)
198dce4cf74SZiyuan Xu {
199dce4cf74SZiyuan Xu 	writel(RK_CLRSETBITS(1, 0), &phy->emmcphy_con[6]);
200dce4cf74SZiyuan Xu 	writel(RK_CLRSETBITS(1 << 1, 0), &phy->emmcphy_con[6]);
201dce4cf74SZiyuan Xu }
202dce4cf74SZiyuan Xu 
rockchip_emmc_set_clock(struct sdhci_host * host,unsigned int clock)203ca831a23SYifeng Zhao static int rockchip_emmc_set_clock(struct sdhci_host *host, unsigned int clock)
204cc0bf5edSchenfen {
205cc0bf5edSchenfen 	unsigned int div, clk = 0, timeout;
206cc0bf5edSchenfen 	unsigned int input_clk;
207cc0bf5edSchenfen 	struct rockchip_sdhc *priv =
208cc0bf5edSchenfen 			container_of(host, struct rockchip_sdhc, host);
209cc0bf5edSchenfen 
210cc0bf5edSchenfen 	/* Wait max 20 ms */
211cc0bf5edSchenfen 	timeout = 200;
212cc0bf5edSchenfen 	while (sdhci_readl(host, SDHCI_PRESENT_STATE) &
213cc0bf5edSchenfen 			   (SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT)) {
214cc0bf5edSchenfen 		if (timeout == 0) {
215cc0bf5edSchenfen 			printf("%s: Timeout to wait cmd & data inhibit\n",
216cc0bf5edSchenfen 			       __func__);
217cc0bf5edSchenfen 			return -EBUSY;
218cc0bf5edSchenfen 		}
219cc0bf5edSchenfen 
220cc0bf5edSchenfen 		timeout--;
221cc0bf5edSchenfen 		udelay(100);
222cc0bf5edSchenfen 	}
223cc0bf5edSchenfen 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
224cc0bf5edSchenfen 
225cc0bf5edSchenfen 	if (clock == 0)
226cc0bf5edSchenfen 		return 0;
227cc0bf5edSchenfen 
228cc0bf5edSchenfen 	input_clk = clk_set_rate(&priv->emmc_clk, clock);
229cc0bf5edSchenfen 	if (IS_ERR_VALUE(input_clk))
230cc0bf5edSchenfen 		input_clk = host->max_clk;
231cc0bf5edSchenfen 
232cc0bf5edSchenfen 	if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
233cc0bf5edSchenfen 		/*
234cc0bf5edSchenfen 		 * Check if the Host Controller supports Programmable Clock
235cc0bf5edSchenfen 		 * Mode.
236cc0bf5edSchenfen 		 */
237cc0bf5edSchenfen 		if (host->clk_mul) {
238cc0bf5edSchenfen 			for (div = 1; div <= 1024; div++) {
239cc0bf5edSchenfen 				if ((input_clk / div) <= clock)
240cc0bf5edSchenfen 					break;
241cc0bf5edSchenfen 			}
242cc0bf5edSchenfen 
243cc0bf5edSchenfen 			/*
244cc0bf5edSchenfen 			 * Set Programmable Clock Mode in the Clock
245cc0bf5edSchenfen 			 * Control register.
246cc0bf5edSchenfen 			 */
247cc0bf5edSchenfen 			clk = SDHCI_PROG_CLOCK_MODE;
248cc0bf5edSchenfen 			div--;
249cc0bf5edSchenfen 		} else {
250cc0bf5edSchenfen 			/* Version 3.00 divisors must be a multiple of 2. */
251cc0bf5edSchenfen 			if (input_clk <= clock) {
252cc0bf5edSchenfen 				div = 1;
253cc0bf5edSchenfen 			} else {
254cc0bf5edSchenfen 				for (div = 2;
255cc0bf5edSchenfen 				     div < SDHCI_MAX_DIV_SPEC_300;
256cc0bf5edSchenfen 				     div += 2) {
257cc0bf5edSchenfen 					if ((input_clk / div) <= clock)
258cc0bf5edSchenfen 						break;
259cc0bf5edSchenfen 				}
260cc0bf5edSchenfen 			}
261cc0bf5edSchenfen 			div >>= 1;
262cc0bf5edSchenfen 		}
263cc0bf5edSchenfen 	} else {
264cc0bf5edSchenfen 		/* Version 2.00 divisors must be a power of 2. */
265cc0bf5edSchenfen 		for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
266cc0bf5edSchenfen 			if ((input_clk / div) <= clock)
267cc0bf5edSchenfen 				break;
268cc0bf5edSchenfen 		}
269cc0bf5edSchenfen 		div >>= 1;
270cc0bf5edSchenfen 	}
271cc0bf5edSchenfen 
272cc0bf5edSchenfen 	clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
273cc0bf5edSchenfen 	clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
274cc0bf5edSchenfen 		<< SDHCI_DIVIDER_HI_SHIFT;
275cc0bf5edSchenfen 	clk |= SDHCI_CLOCK_INT_EN;
276cc0bf5edSchenfen 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
277cc0bf5edSchenfen 
2781976213dSYifeng Zhao 	sdhci_enable_clk(host, clk);
279cc0bf5edSchenfen 
280cc0bf5edSchenfen 	return 0;
281cc0bf5edSchenfen }
282cc0bf5edSchenfen 
rk3399_emmc_get_phy(struct udevice * dev)28305f3b0abSJason Zhu static int rk3399_emmc_get_phy(struct udevice *dev)
284dce4cf74SZiyuan Xu {
285dce4cf74SZiyuan Xu 	struct rockchip_sdhc *priv = dev_get_priv(dev);
286dce4cf74SZiyuan Xu 
287dce4cf74SZiyuan Xu #if CONFIG_IS_ENABLED(OF_PLATDATA)
288dce4cf74SZiyuan Xu 	priv->phy = (struct rockchip_emmc_phy *)0xff77f780;
289dce4cf74SZiyuan Xu #else
2902f972333SKever Yang 	ofnode phy_node;
2912f972333SKever Yang 	void *grf_base;
2922f972333SKever Yang 	u32 grf_phy_offset, phandle;
293dce4cf74SZiyuan Xu 
2942f972333SKever Yang 	phandle = dev_read_u32_default(dev, "phys", 0);
2952f972333SKever Yang 	phy_node = ofnode_get_by_phandle(phandle);
2962f972333SKever Yang 	if (!ofnode_valid(phy_node)) {
297dce4cf74SZiyuan Xu 		debug("Not found emmc phy device\n");
298dce4cf74SZiyuan Xu 		return -ENODEV;
299dce4cf74SZiyuan Xu 	}
300dce4cf74SZiyuan Xu 
3012f972333SKever Yang 	grf_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
3022cdd2239SJianqun Xu 	if (IS_ERR(grf_base))
3032f972333SKever Yang 		printf("%s Get syscon grf failed", __func__);
3042f972333SKever Yang 	grf_phy_offset = ofnode_read_u32_default(phy_node, "reg", 0);
305dce4cf74SZiyuan Xu 
306dce4cf74SZiyuan Xu 	priv->phy = (struct rockchip_emmc_phy *)(grf_base + grf_phy_offset);
307dce4cf74SZiyuan Xu #endif
308dce4cf74SZiyuan Xu 	return 0;
309dce4cf74SZiyuan Xu }
310dce4cf74SZiyuan Xu 
rk3399_sdhci_emmc_set_clock(struct sdhci_host * host,unsigned int clock)31105f3b0abSJason Zhu static int rk3399_sdhci_emmc_set_clock(struct sdhci_host *host, unsigned int clock)
31205f3b0abSJason Zhu {
31305f3b0abSJason Zhu 	struct rockchip_sdhc *priv =
31405f3b0abSJason Zhu 			container_of(host, struct rockchip_sdhc, host);
31505f3b0abSJason Zhu 	int cycle_phy = host->clock != clock &&
31605f3b0abSJason Zhu 			clock > EMMC_MIN_FREQ;
31705f3b0abSJason Zhu 
31805f3b0abSJason Zhu 	if (cycle_phy)
31905f3b0abSJason Zhu 		rk3399_emmc_phy_power_off(priv->phy);
32005f3b0abSJason Zhu 
321ca831a23SYifeng Zhao 	rockchip_emmc_set_clock(host, clock);
32205f3b0abSJason Zhu 
32305f3b0abSJason Zhu 	if (cycle_phy)
32405f3b0abSJason Zhu 		rk3399_emmc_phy_power_on(priv->phy, clock);
32505f3b0abSJason Zhu 
32605f3b0abSJason Zhu 	return 0;
32705f3b0abSJason Zhu }
32805f3b0abSJason Zhu 
dwcmshc_sdhci_emmc_set_clock(struct sdhci_host * host,unsigned int clock)3290bcee30cSYifeng Zhao static int dwcmshc_sdhci_emmc_set_clock(struct sdhci_host *host, unsigned int clock)
330b7b23550SJason Zhu {
3310bcee30cSYifeng Zhao 	struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host);
3320bcee30cSYifeng Zhao 	struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev);
333ed382477SYifeng Zhao 	u32 txclk_tapnum, extra, dll_lock_value;
33428b3b131SYifeng Zhao 	int timeout = 500, ret;
33528b3b131SYifeng Zhao 
336ca831a23SYifeng Zhao 	ret = rockchip_emmc_set_clock(host, clock);
33728b3b131SYifeng Zhao 
33868834fe2SYifeng Zhao 	/* Disable output clock while config DLL */
339ed382477SYifeng Zhao 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
34068834fe2SYifeng Zhao 
3410bcee30cSYifeng Zhao 	if (clock >= 100 * MHz) {
3420bcee30cSYifeng Zhao 		/* reset DLL */
3430bcee30cSYifeng Zhao 		sdhci_writel(host, DWCMSHC_EMMC_DLL_CTRL_RESET, DWCMSHC_EMMC_DLL_CTRL);
344b7b23550SJason Zhu 		udelay(1);
345b7b23550SJason Zhu 		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
3460bcee30cSYifeng Zhao 
34713669fc5SYifeng Zhao 		extra = 0x1 << 16 | /* tune clock stop en */
34813669fc5SYifeng Zhao 			0x2 << 17 | /* pre-change delay */
34913669fc5SYifeng Zhao 			0x3 << 19;  /* post-change delay */
35013669fc5SYifeng Zhao 		sdhci_writel(host, extra, DWCMSHC_EMMC_ATCTRL);
35113669fc5SYifeng Zhao 
352b7b23550SJason Zhu 		/* Init DLL settings */
3530bcee30cSYifeng Zhao 		extra = DWCMSHC_EMMC_DLL_START_DEFAULT << DWCMSHC_EMMC_DLL_START_POINT |
3540bcee30cSYifeng Zhao 			DWCMSHC_EMMC_DLL_INC_VALUE << DWCMSHC_EMMC_DLL_INC |
355b7b23550SJason Zhu 			DWCMSHC_EMMC_DLL_START;
356b7b23550SJason Zhu 		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL);
35728b3b131SYifeng Zhao 
358b7b23550SJason Zhu 		while (1) {
35968834fe2SYifeng Zhao 			if (timeout < 0) {
36068834fe2SYifeng Zhao 				ret = -ETIMEDOUT;
36168834fe2SYifeng Zhao 				goto exit;
36268834fe2SYifeng Zhao 			}
36328b3b131SYifeng Zhao 			if (DLL_LOCK_WO_TMOUT((sdhci_readl(host, DWCMSHC_EMMC_DLL_STATUS0))))
364b7b23550SJason Zhu 				break;
365b7b23550SJason Zhu 			udelay(1);
366b7b23550SJason Zhu 			timeout--;
367b7b23550SJason Zhu 		}
368ed382477SYifeng Zhao 		dll_lock_value = ((sdhci_readl(host, DWCMSHC_EMMC_DLL_STATUS0) & 0xFF) * 2 ) & 0xFF;
3695e555c00SYifeng Zhao 		extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE;
370f9527902SYifeng Zhao 		if (data->flags & RK_RXCLK_NO_INVERTER)
3715e555c00SYifeng Zhao 			extra |= DLL_RXCLK_NO_INVERTER;
372ed382477SYifeng Zhao 		if (data->flags & RK_TAP_VALUE_SEL)
373ed382477SYifeng Zhao 			extra |= DLL_TAP_VALUE_SEL | (dll_lock_value << DLL_TAP_VALUE_OFFSET);
3740bcee30cSYifeng Zhao 		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
3750bcee30cSYifeng Zhao 
3765e555c00SYifeng Zhao 		txclk_tapnum = data->hs200_tx_tap;
3775e555c00SYifeng Zhao 		if ((data->flags & RK_DLL_CMD_OUT) &&
3785e555c00SYifeng Zhao 		    (host->mmc->timing == MMC_TIMING_MMC_HS400 ||
3795e555c00SYifeng Zhao 		    host->mmc->timing == MMC_TIMING_MMC_HS400ES)) {
3805e555c00SYifeng Zhao 			txclk_tapnum = data->hs400_tx_tap;
3815e555c00SYifeng Zhao 
3825e555c00SYifeng Zhao 			extra = DLL_CMDOUT_SRC_CLK_NEG |
38313669fc5SYifeng Zhao 				DLL_CMDOUT_BOTH_CLK_EDGE |
3845e555c00SYifeng Zhao 				DWCMSHC_EMMC_DLL_DLYENA |
3855e555c00SYifeng Zhao 				data->hs400_cmd_tap |
3865e555c00SYifeng Zhao 				DLL_CMDOUT_TAPNUM_FROM_SW;
387ed382477SYifeng Zhao 			if (data->flags & RK_TAP_VALUE_SEL)
388ed382477SYifeng Zhao 				extra |= DLL_TAP_VALUE_SEL | (dll_lock_value << DLL_TAP_VALUE_OFFSET);
3895e555c00SYifeng Zhao 			sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT);
3905e555c00SYifeng Zhao 		}
3915e555c00SYifeng Zhao 
392b7b23550SJason Zhu 		extra = DWCMSHC_EMMC_DLL_DLYENA |
393f9527902SYifeng Zhao 			DLL_TXCLK_TAPNUM_FROM_SW |
394a4de9ecaSYifeng Zhao 			DLL_TXCLK_NO_INVERTER|
3955e555c00SYifeng Zhao 			txclk_tapnum;
396ed382477SYifeng Zhao 		if (data->flags & RK_TAP_VALUE_SEL)
397ed382477SYifeng Zhao 			extra |= DLL_TAP_VALUE_SEL | (dll_lock_value << DLL_TAP_VALUE_OFFSET);
398b7b23550SJason Zhu 		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
39928b3b131SYifeng Zhao 
400b7b23550SJason Zhu 		extra = DWCMSHC_EMMC_DLL_DLYENA |
4015e555c00SYifeng Zhao 			data->hs400_strbin_tap |
4025e555c00SYifeng Zhao 			DLL_STRBIN_TAPNUM_FROM_SW;
403ed382477SYifeng Zhao 		if (data->flags & RK_TAP_VALUE_SEL)
404ed382477SYifeng Zhao 			extra |= DLL_TAP_VALUE_SEL | (dll_lock_value << DLL_TAP_VALUE_OFFSET);
405b7b23550SJason Zhu 		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
406d62fa582SJason Zhu 	} else {
407ed382477SYifeng Zhao 		/* disable dll */
408ed382477SYifeng Zhao 		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
409ed382477SYifeng Zhao 
410a4de9ecaSYifeng Zhao 		/* Disable cmd conflict check */
411a4de9ecaSYifeng Zhao 		extra = sdhci_readl(host, DWCMSHC_HOST_CTRL3);
412a4de9ecaSYifeng Zhao 		extra &= ~BIT(0);
413a4de9ecaSYifeng Zhao 		sdhci_writel(host, extra, DWCMSHC_HOST_CTRL3);
414a4de9ecaSYifeng Zhao 
4150bcee30cSYifeng Zhao 		/* reset the clock phase when the frequency is lower than 100MHz */
41613669fc5SYifeng Zhao 		sdhci_writel(host, DWCMSHC_EMMC_DLL_BYPASS | DWCMSHC_EMMC_DLL_START, DWCMSHC_EMMC_DLL_CTRL);
417ed382477SYifeng Zhao 		sdhci_writel(host, DLL_RXCLK_ORI_GATE, DWCMSHC_EMMC_DLL_RXCLK);
418d62fa582SJason Zhu 		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
4190bcee30cSYifeng Zhao 		sdhci_writel(host, 0, DECMSHC_EMMC_DLL_CMDOUT);
42013669fc5SYifeng Zhao 		/*
42113669fc5SYifeng Zhao 		 * Before switching to hs400es mode, the driver will enable
42213669fc5SYifeng Zhao 		 * enhanced strobe first. PHY needs to configure the parameters
42313669fc5SYifeng Zhao 		 * of enhanced strobe first.
42413669fc5SYifeng Zhao 		 */
42513669fc5SYifeng Zhao 		extra = DWCMSHC_EMMC_DLL_DLYENA |
42613669fc5SYifeng Zhao 			DLL_STRBIN_DELAY_NUM_SEL |
42713669fc5SYifeng Zhao 			data->ddr50_strbin_delay_num << DLL_STRBIN_DELAY_NUM_OFFSET;
42813669fc5SYifeng Zhao 		sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
429b7b23550SJason Zhu 	}
43013669fc5SYifeng Zhao 
43168834fe2SYifeng Zhao exit:
43268834fe2SYifeng Zhao 	/* enable output clock */
433ed382477SYifeng Zhao 	sdhci_enable_clk(host, 0);
43468834fe2SYifeng Zhao 
43528b3b131SYifeng Zhao 	return ret;
436b7b23550SJason Zhu }
437b7b23550SJason Zhu 
dwcmshc_sdhci_set_enhanced_strobe(struct sdhci_host * host)43813669fc5SYifeng Zhao static int dwcmshc_sdhci_set_enhanced_strobe(struct sdhci_host *host)
43913669fc5SYifeng Zhao {
44013669fc5SYifeng Zhao 	struct mmc *mmc = host->mmc;
44113669fc5SYifeng Zhao 	u32 vendor;
44213669fc5SYifeng Zhao 
44313669fc5SYifeng Zhao 	vendor = sdhci_readl(host, DWCMSHC_EMMC_CONTROL);
44413669fc5SYifeng Zhao 	if (mmc->timing == MMC_TIMING_MMC_HS400ES)
44513669fc5SYifeng Zhao 		vendor |= DWCMSHC_ENHANCED_STROBE;
44613669fc5SYifeng Zhao 	else
44713669fc5SYifeng Zhao 		vendor &= ~DWCMSHC_ENHANCED_STROBE;
44813669fc5SYifeng Zhao 	sdhci_writel(host, vendor, DWCMSHC_EMMC_CONTROL);
44913669fc5SYifeng Zhao 
4503ee58449SYifeng Zhao 	/* some emmc device need a delay before send command */
4513ee58449SYifeng Zhao 	udelay(100);
4523ee58449SYifeng Zhao 
45313669fc5SYifeng Zhao 	return 0;
45413669fc5SYifeng Zhao }
45513669fc5SYifeng Zhao 
dwcmshc_sdhci_set_ios_post(struct sdhci_host * host)456a4de9ecaSYifeng Zhao static void dwcmshc_sdhci_set_ios_post(struct sdhci_host *host)
457a4de9ecaSYifeng Zhao {
458a4de9ecaSYifeng Zhao 	u16 ctrl;
459a4de9ecaSYifeng Zhao 	u32 timing = host->mmc->timing;
460a4de9ecaSYifeng Zhao 
461a4de9ecaSYifeng Zhao 	if (timing == MMC_TIMING_MMC_HS400 || timing == MMC_TIMING_MMC_HS400ES) {
462a4de9ecaSYifeng Zhao 		ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
463a4de9ecaSYifeng Zhao 		ctrl &= ~SDHCI_CTRL_UHS_MASK;
464a4de9ecaSYifeng Zhao 		ctrl |= DWCMSHC_CTRL_HS400;
465a4de9ecaSYifeng Zhao 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
466a4de9ecaSYifeng Zhao 
467a4de9ecaSYifeng Zhao 		/* set CARD_IS_EMMC bit to enable Data Strobe for HS400 */
468a4de9ecaSYifeng Zhao 		ctrl = sdhci_readw(host, DWCMSHC_EMMC_CONTROL);
469a4de9ecaSYifeng Zhao 		ctrl |= DWCMSHC_CARD_IS_EMMC;
470a4de9ecaSYifeng Zhao 		sdhci_writew(host, ctrl, DWCMSHC_EMMC_CONTROL);
471a4de9ecaSYifeng Zhao 	}
472a4de9ecaSYifeng Zhao }
473a4de9ecaSYifeng Zhao 
dwcmshc_emmc_get_phy(struct udevice * dev)4740bcee30cSYifeng Zhao static int dwcmshc_emmc_get_phy(struct udevice *dev)
475b7b23550SJason Zhu {
476b7b23550SJason Zhu 	return 0;
477b7b23550SJason Zhu }
478b7b23550SJason Zhu 
rockchip_sdhci_set_clock(struct sdhci_host * host,unsigned int clock)479ca831a23SYifeng Zhao static int rockchip_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
48005f3b0abSJason Zhu {
48105f3b0abSJason Zhu 	struct rockchip_sdhc *priv =
48205f3b0abSJason Zhu 			container_of(host, struct rockchip_sdhc, host);
48305f3b0abSJason Zhu 	struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev);
48405f3b0abSJason Zhu 	if (!data)
48505f3b0abSJason Zhu 		return -EINVAL;
48605f3b0abSJason Zhu 
48705f3b0abSJason Zhu 	return data->emmc_set_clock(host, clock);
48805f3b0abSJason Zhu }
48905f3b0abSJason Zhu 
rockchip_sdhci_set_ios_post(struct sdhci_host * host)490a4de9ecaSYifeng Zhao static void rockchip_sdhci_set_ios_post(struct sdhci_host *host)
491a4de9ecaSYifeng Zhao {
492a4de9ecaSYifeng Zhao 	struct rockchip_sdhc *priv =
493a4de9ecaSYifeng Zhao 			container_of(host, struct rockchip_sdhc, host);
494a4de9ecaSYifeng Zhao 	struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev);
495a4de9ecaSYifeng Zhao 
496a4de9ecaSYifeng Zhao 	if (data && data->set_ios_post)
497a4de9ecaSYifeng Zhao 		data->set_ios_post(host);
498a4de9ecaSYifeng Zhao }
499a4de9ecaSYifeng Zhao 
rockchip_sdhci_set_enhanced_strobe(struct sdhci_host * host)50013669fc5SYifeng Zhao static int rockchip_sdhci_set_enhanced_strobe(struct sdhci_host *host)
50113669fc5SYifeng Zhao {
50213669fc5SYifeng Zhao 	struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host);
50313669fc5SYifeng Zhao 	struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev);
50413669fc5SYifeng Zhao 
50513669fc5SYifeng Zhao 	if (data->set_enhanced_strobe)
50613669fc5SYifeng Zhao 		return data->set_enhanced_strobe(host);
50713669fc5SYifeng Zhao 
50813669fc5SYifeng Zhao 	return -ENOTSUPP;
50913669fc5SYifeng Zhao }
51013669fc5SYifeng Zhao 
511ca831a23SYifeng Zhao static struct sdhci_ops rockchip_sdhci_ops = {
512ca831a23SYifeng Zhao 	.set_clock	= rockchip_sdhci_set_clock,
513a4de9ecaSYifeng Zhao 	.set_ios_post	= rockchip_sdhci_set_ios_post,
51413669fc5SYifeng Zhao 	.set_enhanced_strobe = rockchip_sdhci_set_enhanced_strobe,
51505f3b0abSJason Zhu };
51605f3b0abSJason Zhu 
rockchip_sdhci_probe(struct udevice * dev)517ca831a23SYifeng Zhao static int rockchip_sdhci_probe(struct udevice *dev)
51879c83065SKever Yang {
51905f3b0abSJason Zhu 	struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(dev);
52079c83065SKever Yang 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
52179c83065SKever Yang 	struct rockchip_sdhc_plat *plat = dev_get_platdata(dev);
52279c83065SKever Yang 	struct rockchip_sdhc *prv = dev_get_priv(dev);
52379c83065SKever Yang 	struct sdhci_host *host = &prv->host;
52439fbb56fSKever Yang 	int max_frequency, ret;
52539fbb56fSKever Yang 	struct clk clk;
52639fbb56fSKever Yang 
527c2868212SKever Yang #if CONFIG_IS_ENABLED(OF_PLATDATA)
528c2868212SKever Yang 	struct dtd_rockchip_rk3399_sdhci_5_1 *dtplat = &plat->dtplat;
52939fbb56fSKever Yang 
530c2868212SKever Yang 	host->name = dev->name;
531adcf6d06SKever Yang 	host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
5322a62bae8SZiyuan Xu 	host->host_caps |= MMC_MODE_8BIT;
533c2868212SKever Yang 	max_frequency = dtplat->max_frequency;
534c2868212SKever Yang 	ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &clk);
535c2868212SKever Yang #else
536fd1bf8dfSPhilipp Tomsich 	max_frequency = dev_read_u32_default(dev, "max-frequency", 0);
5372a62bae8SZiyuan Xu 	switch (dev_read_u32_default(dev, "bus-width", 4)) {
5382a62bae8SZiyuan Xu 	case 8:
5392a62bae8SZiyuan Xu 		host->host_caps |= MMC_MODE_8BIT;
5402a62bae8SZiyuan Xu 		break;
5412a62bae8SZiyuan Xu 	case 4:
5422a62bae8SZiyuan Xu 		host->host_caps |= MMC_MODE_4BIT;
5432a62bae8SZiyuan Xu 		break;
5442a62bae8SZiyuan Xu 	case 1:
5452a62bae8SZiyuan Xu 		break;
5462a62bae8SZiyuan Xu 	default:
5472a62bae8SZiyuan Xu 		printf("Invalid \"bus-width\" value\n");
5482a62bae8SZiyuan Xu 		return -EINVAL;
5492a62bae8SZiyuan Xu 	}
55039fbb56fSKever Yang 	ret = clk_get_by_index(dev, 0, &clk);
551c2868212SKever Yang #endif
55239fbb56fSKever Yang 	if (!ret) {
55339fbb56fSKever Yang 		ret = clk_set_rate(&clk, max_frequency);
55439fbb56fSKever Yang 		if (IS_ERR_VALUE(ret))
55539fbb56fSKever Yang 			printf("%s clk set rate fail!\n", __func__);
55639fbb56fSKever Yang 	} else {
55739fbb56fSKever Yang 		printf("%s fail to get clk\n", __func__);
55839fbb56fSKever Yang 	}
55979c83065SKever Yang 
560cc0bf5edSchenfen 	prv->emmc_clk = clk;
56105f3b0abSJason Zhu 	prv->dev = dev;
56205f3b0abSJason Zhu 	ret = data->get_phy(dev);
56305f3b0abSJason Zhu 	if (ret)
56405f3b0abSJason Zhu 		return ret;
56505f3b0abSJason Zhu 
566ca831a23SYifeng Zhao 	host->ops = &rockchip_sdhci_ops;
567dce4cf74SZiyuan Xu 
5686d0e34bfSStefan Herbrechtsmeier 	host->max_clk = max_frequency;
56979c83065SKever Yang 
570a59bd218SJason Zhu 	if (dev_read_bool(dev, "mmc-hs200-1_8v"))
571a59bd218SJason Zhu 		host->host_caps |= MMC_MODE_HS200;
572a59bd218SJason Zhu 	else if (dev_read_bool(dev, "mmc-hs400-1_8v"))
573a59bd218SJason Zhu 		host->host_caps |= MMC_MODE_HS400;
57413669fc5SYifeng Zhao 
57513669fc5SYifeng Zhao 	if (data->set_enhanced_strobe && dev_read_bool(dev, "mmc-hs400-enhanced-strobe"))
57613669fc5SYifeng Zhao 		host->host_caps |= MMC_MODE_HS400ES;
57713669fc5SYifeng Zhao 
5786d0e34bfSStefan Herbrechtsmeier 	ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
57979c83065SKever Yang 
5807a9b5d70SYifeng Zhao 	plat->cfg.fixed_drv_type = dev_read_u32_default(dev, "fixed-emmc-driver-type", 0);
5817a9b5d70SYifeng Zhao 
58279c83065SKever Yang 	host->mmc = &plat->mmc;
58379c83065SKever Yang 	if (ret)
58479c83065SKever Yang 		return ret;
58579c83065SKever Yang 	host->mmc->priv = &prv->host;
58679c83065SKever Yang 	host->mmc->dev = dev;
58779c83065SKever Yang 	upriv->mmc = host->mmc;
58879c83065SKever Yang 
58979c83065SKever Yang 	return sdhci_probe(dev);
59079c83065SKever Yang }
59179c83065SKever Yang 
rockchip_sdhci_of_to_plat(struct udevice * dev)592ca831a23SYifeng Zhao static int rockchip_sdhci_of_to_plat(struct udevice *dev)
59379c83065SKever Yang {
594c2868212SKever Yang #if !CONFIG_IS_ENABLED(OF_PLATDATA)
59579c83065SKever Yang 	struct sdhci_host *host = dev_get_priv(dev);
59679c83065SKever Yang 
59779c83065SKever Yang 	host->name = dev->name;
5984ae650e5SPhilipp Tomsich 	host->ioaddr = dev_read_addr_ptr(dev);
599c2868212SKever Yang #endif
60079c83065SKever Yang 
60179c83065SKever Yang 	return 0;
60279c83065SKever Yang }
60379c83065SKever Yang 
rockchip_sdhci_bind(struct udevice * dev)60479c83065SKever Yang static int rockchip_sdhci_bind(struct udevice *dev)
60579c83065SKever Yang {
60679c83065SKever Yang 	struct rockchip_sdhc_plat *plat = dev_get_platdata(dev);
60779c83065SKever Yang 
60824f5aec3SMasahiro Yamada 	return sdhci_bind(dev, &plat->mmc, &plat->cfg);
60979c83065SKever Yang }
61079c83065SKever Yang 
61105f3b0abSJason Zhu static const struct sdhci_data arasan_data = {
61205f3b0abSJason Zhu 	.emmc_set_clock = rk3399_sdhci_emmc_set_clock,
61305f3b0abSJason Zhu 	.get_phy = rk3399_emmc_get_phy,
61405f3b0abSJason Zhu };
61505f3b0abSJason Zhu 
6160bcee30cSYifeng Zhao static const struct sdhci_data rk3568_data = {
6170bcee30cSYifeng Zhao 	.emmc_set_clock = dwcmshc_sdhci_emmc_set_clock,
6180bcee30cSYifeng Zhao 	.get_phy = dwcmshc_emmc_get_phy,
61980715258SYifeng Zhao 	.flags = RK_RXCLK_NO_INVERTER | RK_TAP_VALUE_SEL,
6205e555c00SYifeng Zhao 	.hs200_tx_tap = 16,
6215e555c00SYifeng Zhao 	.hs400_tx_tap = 8,
6225e555c00SYifeng Zhao 	.hs400_cmd_tap = 8,
6235e555c00SYifeng Zhao 	.hs400_strbin_tap = 3,
62413669fc5SYifeng Zhao 	.ddr50_strbin_delay_num = 16,
6250bcee30cSYifeng Zhao };
6260bcee30cSYifeng Zhao 
6270bcee30cSYifeng Zhao static const struct sdhci_data rk3588_data = {
6280bcee30cSYifeng Zhao 	.emmc_set_clock = dwcmshc_sdhci_emmc_set_clock,
6290bcee30cSYifeng Zhao 	.get_phy = dwcmshc_emmc_get_phy,
630a4de9ecaSYifeng Zhao 	.set_ios_post = dwcmshc_sdhci_set_ios_post,
63113669fc5SYifeng Zhao 	.set_enhanced_strobe = dwcmshc_sdhci_set_enhanced_strobe,
63280715258SYifeng Zhao 	.flags = RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL,
6335e555c00SYifeng Zhao 	.hs200_tx_tap = 16,
6345e555c00SYifeng Zhao 	.hs400_tx_tap = 9,
6355e555c00SYifeng Zhao 	.hs400_cmd_tap = 8,
6365e555c00SYifeng Zhao 	.hs400_strbin_tap = 3,
63713669fc5SYifeng Zhao 	.ddr50_strbin_delay_num = 16,
6385e555c00SYifeng Zhao };
6395e555c00SYifeng Zhao 
6405e555c00SYifeng Zhao static const struct sdhci_data rk3528_data = {
6415e555c00SYifeng Zhao 	.emmc_set_clock = dwcmshc_sdhci_emmc_set_clock,
6425e555c00SYifeng Zhao 	.get_phy = dwcmshc_emmc_get_phy,
6435e555c00SYifeng Zhao 	.set_ios_post = dwcmshc_sdhci_set_ios_post,
64413669fc5SYifeng Zhao 	.set_enhanced_strobe = dwcmshc_sdhci_set_enhanced_strobe,
645ed382477SYifeng Zhao 	.flags = RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL,
6465e555c00SYifeng Zhao 	.hs200_tx_tap = 12,
647ed382477SYifeng Zhao 	.hs400_tx_tap = 6,
648ed382477SYifeng Zhao 	.hs400_cmd_tap = 6,
6495e555c00SYifeng Zhao 	.hs400_strbin_tap = 3,
65013669fc5SYifeng Zhao 	.ddr50_strbin_delay_num = 10,
651b7b23550SJason Zhu };
652b7b23550SJason Zhu 
6530fa64586SYifeng Zhao static const struct sdhci_data rk3562_data = {
6540fa64586SYifeng Zhao 	.emmc_set_clock = dwcmshc_sdhci_emmc_set_clock,
6550fa64586SYifeng Zhao 	.get_phy = dwcmshc_emmc_get_phy,
6560fa64586SYifeng Zhao 	.set_ios_post = dwcmshc_sdhci_set_ios_post,
6570fa64586SYifeng Zhao 	.set_enhanced_strobe = dwcmshc_sdhci_set_enhanced_strobe,
658ed382477SYifeng Zhao 	.flags = RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL,
6590fa64586SYifeng Zhao 	.hs200_tx_tap = 12,
6600fa64586SYifeng Zhao 	.hs400_tx_tap = 6,
6610fa64586SYifeng Zhao 	.hs400_cmd_tap = 6,
662ed382477SYifeng Zhao 	.hs400_strbin_tap = 3,
6630fa64586SYifeng Zhao 	.ddr50_strbin_delay_num = 10,
6640fa64586SYifeng Zhao };
6650fa64586SYifeng Zhao 
666b9c90533SYifeng Zhao static const struct sdhci_data rk3576_data = {
667b9c90533SYifeng Zhao 	.emmc_set_clock = dwcmshc_sdhci_emmc_set_clock,
668b9c90533SYifeng Zhao 	.get_phy = dwcmshc_emmc_get_phy,
669b9c90533SYifeng Zhao 	.set_ios_post = dwcmshc_sdhci_set_ios_post,
670b9c90533SYifeng Zhao 	.set_enhanced_strobe = dwcmshc_sdhci_set_enhanced_strobe,
671b9c90533SYifeng Zhao 	.flags = RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL,
672b9c90533SYifeng Zhao 	.hs200_tx_tap = 16,
673b9c90533SYifeng Zhao 	.hs400_tx_tap = 7,
674b9c90533SYifeng Zhao 	.hs400_cmd_tap = 7,
675*1bf19a93SYifeng Zhao 	.hs400_strbin_tap = 7,
676b9c90533SYifeng Zhao 	.ddr50_strbin_delay_num = 16,
677b9c90533SYifeng Zhao };
678b9c90533SYifeng Zhao 
679ca831a23SYifeng Zhao static const struct udevice_id sdhci_ids[] = {
68005f3b0abSJason Zhu 	{
68105f3b0abSJason Zhu 		.compatible = "arasan,sdhci-5.1",
68205f3b0abSJason Zhu 		.data = (ulong)&arasan_data,
68305f3b0abSJason Zhu 	},
684b7b23550SJason Zhu 	{
685b7b23550SJason Zhu 		.compatible = "snps,dwcmshc-sdhci",
6860bcee30cSYifeng Zhao 		.data = (ulong)&rk3568_data,
6870bcee30cSYifeng Zhao 	},
6880bcee30cSYifeng Zhao 	{
6895e555c00SYifeng Zhao 		.compatible = "rockchip,rk3528-dwcmshc",
6905e555c00SYifeng Zhao 		.data = (ulong)&rk3528_data,
6915e555c00SYifeng Zhao 	},
6925e555c00SYifeng Zhao 	{
6930fa64586SYifeng Zhao 		.compatible = "rockchip,rk3562-dwcmshc",
6940fa64586SYifeng Zhao 		.data = (ulong)&rk3562_data,
6950fa64586SYifeng Zhao 	},
6960fa64586SYifeng Zhao 	{
697b9c90533SYifeng Zhao 		.compatible = "rockchip,rk3576-dwcmshc",
698b9c90533SYifeng Zhao 		.data = (ulong)&rk3576_data,
699b9c90533SYifeng Zhao 	},
700b9c90533SYifeng Zhao 	{
701f9527902SYifeng Zhao 		.compatible = "rockchip,rk3588-dwcmshc",
7020bcee30cSYifeng Zhao 		.data = (ulong)&rk3588_data,
703b7b23550SJason Zhu 	},
70479c83065SKever Yang 	{ }
70579c83065SKever Yang };
70679c83065SKever Yang 
70779c83065SKever Yang U_BOOT_DRIVER(arasan_sdhci_drv) = {
708ca831a23SYifeng Zhao 	.name		= "rockchip_sdhci_5_1",
70979c83065SKever Yang 	.id		= UCLASS_MMC,
710ca831a23SYifeng Zhao 	.of_match	= sdhci_ids,
711ca831a23SYifeng Zhao 	.ofdata_to_platdata = rockchip_sdhci_of_to_plat,
71279c83065SKever Yang 	.ops		= &sdhci_ops,
71379c83065SKever Yang 	.bind		= rockchip_sdhci_bind,
714ca831a23SYifeng Zhao 	.probe		= rockchip_sdhci_probe,
71579c83065SKever Yang 	.priv_auto_alloc_size = sizeof(struct rockchip_sdhc),
71679c83065SKever Yang 	.platdata_auto_alloc_size = sizeof(struct rockchip_sdhc_plat),
71779c83065SKever Yang };
718