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