xref: /openbmc/u-boot/drivers/mmc/zynq_sdhci.c (revision d01806a8)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2293eb33fSMichal Simek /*
3d9ae52c8SMichal Simek  * (C) Copyright 2013 - 2015 Xilinx, Inc.
4293eb33fSMichal Simek  *
5293eb33fSMichal Simek  * Xilinx Zynq SD Host Controller Interface
6293eb33fSMichal Simek  */
7293eb33fSMichal Simek 
8e0f4de1aSStefan Herbrechtsmeier #include <clk.h>
9293eb33fSMichal Simek #include <common.h>
10d9ae52c8SMichal Simek #include <dm.h>
11345d3c0fSMichal Simek #include <fdtdec.h>
12d1f4e39dSSiva Durga Prasad Paladugu #include "mmc_private.h"
13b08c8c48SMasahiro Yamada #include <linux/libfdt.h>
14293eb33fSMichal Simek #include <malloc.h>
15293eb33fSMichal Simek #include <sdhci.h>
16d1f4e39dSSiva Durga Prasad Paladugu #include <zynqmp_tap_delay.h>
17293eb33fSMichal Simek 
1861e745d1SStefan Herbrechtsmeier DECLARE_GLOBAL_DATA_PTR;
1961e745d1SStefan Herbrechtsmeier 
20329a449fSSimon Glass struct arasan_sdhci_plat {
21329a449fSSimon Glass 	struct mmc_config cfg;
22329a449fSSimon Glass 	struct mmc mmc;
2361e745d1SStefan Herbrechtsmeier 	unsigned int f_max;
24329a449fSSimon Glass };
25329a449fSSimon Glass 
26d1f4e39dSSiva Durga Prasad Paladugu struct arasan_sdhci_priv {
27d1f4e39dSSiva Durga Prasad Paladugu 	struct sdhci_host *host;
28d1f4e39dSSiva Durga Prasad Paladugu 	u8 deviceid;
29d1f4e39dSSiva Durga Prasad Paladugu 	u8 bank;
30d1f4e39dSSiva Durga Prasad Paladugu 	u8 no_1p8;
31d1f4e39dSSiva Durga Prasad Paladugu };
32d1f4e39dSSiva Durga Prasad Paladugu 
33d1f4e39dSSiva Durga Prasad Paladugu #if defined(CONFIG_ARCH_ZYNQMP)
3484333708SSiva Durga Prasad Paladugu #define MMC_HS200_BUS_SPEED	5
3584333708SSiva Durga Prasad Paladugu 
36d1f4e39dSSiva Durga Prasad Paladugu static const u8 mode2timing[] = {
3784333708SSiva Durga Prasad Paladugu 	[MMC_LEGACY] = UHS_SDR12_BUS_SPEED,
3884333708SSiva Durga Prasad Paladugu 	[SD_LEGACY] = UHS_SDR12_BUS_SPEED,
3984333708SSiva Durga Prasad Paladugu 	[MMC_HS] = HIGH_SPEED_BUS_SPEED,
4084333708SSiva Durga Prasad Paladugu 	[SD_HS] = HIGH_SPEED_BUS_SPEED,
4184333708SSiva Durga Prasad Paladugu 	[MMC_HS_52] = HIGH_SPEED_BUS_SPEED,
4284333708SSiva Durga Prasad Paladugu 	[MMC_DDR_52] = HIGH_SPEED_BUS_SPEED,
43d1f4e39dSSiva Durga Prasad Paladugu 	[UHS_SDR12] = UHS_SDR12_BUS_SPEED,
44d1f4e39dSSiva Durga Prasad Paladugu 	[UHS_SDR25] = UHS_SDR25_BUS_SPEED,
45d1f4e39dSSiva Durga Prasad Paladugu 	[UHS_SDR50] = UHS_SDR50_BUS_SPEED,
46d1f4e39dSSiva Durga Prasad Paladugu 	[UHS_DDR50] = UHS_DDR50_BUS_SPEED,
4784333708SSiva Durga Prasad Paladugu 	[UHS_SDR104] = UHS_SDR104_BUS_SPEED,
4884333708SSiva Durga Prasad Paladugu 	[MMC_HS_200] = MMC_HS200_BUS_SPEED,
49d1f4e39dSSiva Durga Prasad Paladugu };
50d1f4e39dSSiva Durga Prasad Paladugu 
51d1f4e39dSSiva Durga Prasad Paladugu #define SDHCI_HOST_CTRL2	0x3E
52d1f4e39dSSiva Durga Prasad Paladugu #define SDHCI_CTRL2_MODE_MASK	0x7
53d1f4e39dSSiva Durga Prasad Paladugu #define SDHCI_18V_SIGNAL	0x8
54d1f4e39dSSiva Durga Prasad Paladugu #define SDHCI_CTRL_EXEC_TUNING	0x0040
55d1f4e39dSSiva Durga Prasad Paladugu #define SDHCI_CTRL_TUNED_CLK	0x80
56d1f4e39dSSiva Durga Prasad Paladugu #define SDHCI_TUNING_LOOP_COUNT	40
57d1f4e39dSSiva Durga Prasad Paladugu 
arasan_zynqmp_dll_reset(struct sdhci_host * host,u8 deviceid)58d1f4e39dSSiva Durga Prasad Paladugu static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid)
59d1f4e39dSSiva Durga Prasad Paladugu {
60d1f4e39dSSiva Durga Prasad Paladugu 	u16 clk;
61d1f4e39dSSiva Durga Prasad Paladugu 	unsigned long timeout;
62d1f4e39dSSiva Durga Prasad Paladugu 
63d1f4e39dSSiva Durga Prasad Paladugu 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
64d1f4e39dSSiva Durga Prasad Paladugu 	clk &= ~(SDHCI_CLOCK_CARD_EN);
65d1f4e39dSSiva Durga Prasad Paladugu 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
66d1f4e39dSSiva Durga Prasad Paladugu 
67d1f4e39dSSiva Durga Prasad Paladugu 	/* Issue DLL Reset */
68d1f4e39dSSiva Durga Prasad Paladugu 	zynqmp_dll_reset(deviceid);
69d1f4e39dSSiva Durga Prasad Paladugu 
70d1f4e39dSSiva Durga Prasad Paladugu 	/* Wait max 20 ms */
71d1f4e39dSSiva Durga Prasad Paladugu 	timeout = 100;
72d1f4e39dSSiva Durga Prasad Paladugu 	while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
73d1f4e39dSSiva Durga Prasad Paladugu 				& SDHCI_CLOCK_INT_STABLE)) {
74d1f4e39dSSiva Durga Prasad Paladugu 		if (timeout == 0) {
75d1f4e39dSSiva Durga Prasad Paladugu 			dev_err(mmc_dev(host->mmc),
76d1f4e39dSSiva Durga Prasad Paladugu 				": Internal clock never stabilised.\n");
77d1f4e39dSSiva Durga Prasad Paladugu 			return;
78d1f4e39dSSiva Durga Prasad Paladugu 		}
79d1f4e39dSSiva Durga Prasad Paladugu 		timeout--;
80d1f4e39dSSiva Durga Prasad Paladugu 		udelay(1000);
81d1f4e39dSSiva Durga Prasad Paladugu 	}
82d1f4e39dSSiva Durga Prasad Paladugu 
83d1f4e39dSSiva Durga Prasad Paladugu 	clk |= SDHCI_CLOCK_CARD_EN;
84d1f4e39dSSiva Durga Prasad Paladugu 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
85d1f4e39dSSiva Durga Prasad Paladugu }
86d1f4e39dSSiva Durga Prasad Paladugu 
arasan_sdhci_execute_tuning(struct mmc * mmc,u8 opcode)87d1f4e39dSSiva Durga Prasad Paladugu static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
88d1f4e39dSSiva Durga Prasad Paladugu {
89d1f4e39dSSiva Durga Prasad Paladugu 	struct mmc_cmd cmd;
90d1f4e39dSSiva Durga Prasad Paladugu 	struct mmc_data data;
91d1f4e39dSSiva Durga Prasad Paladugu 	u32 ctrl;
92d1f4e39dSSiva Durga Prasad Paladugu 	struct sdhci_host *host;
93d1f4e39dSSiva Durga Prasad Paladugu 	struct arasan_sdhci_priv *priv = dev_get_priv(mmc->dev);
94*b6911780SMichal Simek 	char tuning_loop_counter = SDHCI_TUNING_LOOP_COUNT;
95d1f4e39dSSiva Durga Prasad Paladugu 	u8 deviceid;
96d1f4e39dSSiva Durga Prasad Paladugu 
97d1f4e39dSSiva Durga Prasad Paladugu 	debug("%s\n", __func__);
98d1f4e39dSSiva Durga Prasad Paladugu 
99d1f4e39dSSiva Durga Prasad Paladugu 	host = priv->host;
100d1f4e39dSSiva Durga Prasad Paladugu 	deviceid = priv->deviceid;
101d1f4e39dSSiva Durga Prasad Paladugu 
102d1f4e39dSSiva Durga Prasad Paladugu 	ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2);
103d1f4e39dSSiva Durga Prasad Paladugu 	ctrl |= SDHCI_CTRL_EXEC_TUNING;
104d1f4e39dSSiva Durga Prasad Paladugu 	sdhci_writew(host, ctrl, SDHCI_HOST_CTRL2);
105d1f4e39dSSiva Durga Prasad Paladugu 
106d1f4e39dSSiva Durga Prasad Paladugu 	mdelay(1);
107d1f4e39dSSiva Durga Prasad Paladugu 
108d1f4e39dSSiva Durga Prasad Paladugu 	arasan_zynqmp_dll_reset(host, deviceid);
109d1f4e39dSSiva Durga Prasad Paladugu 
110d1f4e39dSSiva Durga Prasad Paladugu 	sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
111d1f4e39dSSiva Durga Prasad Paladugu 	sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
112d1f4e39dSSiva Durga Prasad Paladugu 
113d1f4e39dSSiva Durga Prasad Paladugu 	do {
114d1f4e39dSSiva Durga Prasad Paladugu 		cmd.cmdidx = opcode;
115d1f4e39dSSiva Durga Prasad Paladugu 		cmd.resp_type = MMC_RSP_R1;
116d1f4e39dSSiva Durga Prasad Paladugu 		cmd.cmdarg = 0;
117d1f4e39dSSiva Durga Prasad Paladugu 
118d1f4e39dSSiva Durga Prasad Paladugu 		data.blocksize = 64;
119d1f4e39dSSiva Durga Prasad Paladugu 		data.blocks = 1;
120d1f4e39dSSiva Durga Prasad Paladugu 		data.flags = MMC_DATA_READ;
121d1f4e39dSSiva Durga Prasad Paladugu 
122d1f4e39dSSiva Durga Prasad Paladugu 		if (tuning_loop_counter-- == 0)
123d1f4e39dSSiva Durga Prasad Paladugu 			break;
124d1f4e39dSSiva Durga Prasad Paladugu 
125d1f4e39dSSiva Durga Prasad Paladugu 		if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200 &&
126d1f4e39dSSiva Durga Prasad Paladugu 		    mmc->bus_width == 8)
127d1f4e39dSSiva Durga Prasad Paladugu 			data.blocksize = 128;
128d1f4e39dSSiva Durga Prasad Paladugu 
129d1f4e39dSSiva Durga Prasad Paladugu 		sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
130d1f4e39dSSiva Durga Prasad Paladugu 						    data.blocksize),
131d1f4e39dSSiva Durga Prasad Paladugu 			     SDHCI_BLOCK_SIZE);
132d1f4e39dSSiva Durga Prasad Paladugu 		sdhci_writew(host, data.blocks, SDHCI_BLOCK_COUNT);
133d1f4e39dSSiva Durga Prasad Paladugu 		sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
134d1f4e39dSSiva Durga Prasad Paladugu 
135d1f4e39dSSiva Durga Prasad Paladugu 		mmc_send_cmd(mmc, &cmd, NULL);
136d1f4e39dSSiva Durga Prasad Paladugu 		ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2);
137d1f4e39dSSiva Durga Prasad Paladugu 
138d1f4e39dSSiva Durga Prasad Paladugu 		if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK)
139d1f4e39dSSiva Durga Prasad Paladugu 			udelay(1);
140d1f4e39dSSiva Durga Prasad Paladugu 
141d1f4e39dSSiva Durga Prasad Paladugu 	} while (ctrl & SDHCI_CTRL_EXEC_TUNING);
142d1f4e39dSSiva Durga Prasad Paladugu 
143d1f4e39dSSiva Durga Prasad Paladugu 	if (tuning_loop_counter < 0) {
144d1f4e39dSSiva Durga Prasad Paladugu 		ctrl &= ~SDHCI_CTRL_TUNED_CLK;
145d1f4e39dSSiva Durga Prasad Paladugu 		sdhci_writel(host, ctrl, SDHCI_HOST_CTRL2);
146d1f4e39dSSiva Durga Prasad Paladugu 	}
147d1f4e39dSSiva Durga Prasad Paladugu 
148d1f4e39dSSiva Durga Prasad Paladugu 	if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
149d1f4e39dSSiva Durga Prasad Paladugu 		printf("%s:Tuning failed\n", __func__);
150d1f4e39dSSiva Durga Prasad Paladugu 		return -1;
151d1f4e39dSSiva Durga Prasad Paladugu 	}
152d1f4e39dSSiva Durga Prasad Paladugu 
153d1f4e39dSSiva Durga Prasad Paladugu 	udelay(1);
154d1f4e39dSSiva Durga Prasad Paladugu 	arasan_zynqmp_dll_reset(host, deviceid);
155d1f4e39dSSiva Durga Prasad Paladugu 
156d1f4e39dSSiva Durga Prasad Paladugu 	/* Enable only interrupts served by the SD controller */
157d1f4e39dSSiva Durga Prasad Paladugu 	sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK,
158d1f4e39dSSiva Durga Prasad Paladugu 		     SDHCI_INT_ENABLE);
159d1f4e39dSSiva Durga Prasad Paladugu 	/* Mask all sdhci interrupt sources */
160d1f4e39dSSiva Durga Prasad Paladugu 	sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
161d1f4e39dSSiva Durga Prasad Paladugu 
162d1f4e39dSSiva Durga Prasad Paladugu 	return 0;
163d1f4e39dSSiva Durga Prasad Paladugu }
164d1f4e39dSSiva Durga Prasad Paladugu 
arasan_sdhci_set_tapdelay(struct sdhci_host * host)165d1f4e39dSSiva Durga Prasad Paladugu static void arasan_sdhci_set_tapdelay(struct sdhci_host *host)
166d1f4e39dSSiva Durga Prasad Paladugu {
167d1f4e39dSSiva Durga Prasad Paladugu 	struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev);
168d1f4e39dSSiva Durga Prasad Paladugu 	struct mmc *mmc = (struct mmc *)host->mmc;
169d1f4e39dSSiva Durga Prasad Paladugu 	u8 uhsmode;
170d1f4e39dSSiva Durga Prasad Paladugu 
171d1f4e39dSSiva Durga Prasad Paladugu 	uhsmode = mode2timing[mmc->selected_mode];
172d1f4e39dSSiva Durga Prasad Paladugu 
173d1f4e39dSSiva Durga Prasad Paladugu 	if (uhsmode >= UHS_SDR25_BUS_SPEED)
174d1f4e39dSSiva Durga Prasad Paladugu 		arasan_zynqmp_set_tapdelay(priv->deviceid, uhsmode,
175d1f4e39dSSiva Durga Prasad Paladugu 					   priv->bank);
176d1f4e39dSSiva Durga Prasad Paladugu }
177d1f4e39dSSiva Durga Prasad Paladugu 
arasan_sdhci_set_control_reg(struct sdhci_host * host)178d1f4e39dSSiva Durga Prasad Paladugu static void arasan_sdhci_set_control_reg(struct sdhci_host *host)
179d1f4e39dSSiva Durga Prasad Paladugu {
180d1f4e39dSSiva Durga Prasad Paladugu 	struct mmc *mmc = (struct mmc *)host->mmc;
181d1f4e39dSSiva Durga Prasad Paladugu 	u32 reg;
182d1f4e39dSSiva Durga Prasad Paladugu 
18384333708SSiva Durga Prasad Paladugu 	if (!IS_SD(mmc))
18484333708SSiva Durga Prasad Paladugu 		return;
18584333708SSiva Durga Prasad Paladugu 
186d1f4e39dSSiva Durga Prasad Paladugu 	if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
187d1f4e39dSSiva Durga Prasad Paladugu 		reg = sdhci_readw(host, SDHCI_HOST_CTRL2);
188d1f4e39dSSiva Durga Prasad Paladugu 		reg |= SDHCI_18V_SIGNAL;
189d1f4e39dSSiva Durga Prasad Paladugu 		sdhci_writew(host, reg, SDHCI_HOST_CTRL2);
190d1f4e39dSSiva Durga Prasad Paladugu 	}
191d1f4e39dSSiva Durga Prasad Paladugu 
192d1f4e39dSSiva Durga Prasad Paladugu 	if (mmc->selected_mode > SD_HS &&
193d1f4e39dSSiva Durga Prasad Paladugu 	    mmc->selected_mode <= UHS_DDR50) {
194d1f4e39dSSiva Durga Prasad Paladugu 		reg = sdhci_readw(host, SDHCI_HOST_CTRL2);
195d1f4e39dSSiva Durga Prasad Paladugu 		reg &= ~SDHCI_CTRL2_MODE_MASK;
196d1f4e39dSSiva Durga Prasad Paladugu 		switch (mmc->selected_mode) {
197d1f4e39dSSiva Durga Prasad Paladugu 		case UHS_SDR12:
198d1f4e39dSSiva Durga Prasad Paladugu 			reg |= UHS_SDR12_BUS_SPEED;
199d1f4e39dSSiva Durga Prasad Paladugu 			break;
200d1f4e39dSSiva Durga Prasad Paladugu 		case UHS_SDR25:
201d1f4e39dSSiva Durga Prasad Paladugu 			reg |= UHS_SDR25_BUS_SPEED;
202d1f4e39dSSiva Durga Prasad Paladugu 			break;
203d1f4e39dSSiva Durga Prasad Paladugu 		case UHS_SDR50:
204d1f4e39dSSiva Durga Prasad Paladugu 			reg |= UHS_SDR50_BUS_SPEED;
205d1f4e39dSSiva Durga Prasad Paladugu 			break;
206d1f4e39dSSiva Durga Prasad Paladugu 		case UHS_SDR104:
207d1f4e39dSSiva Durga Prasad Paladugu 			reg |= UHS_SDR104_BUS_SPEED;
208d1f4e39dSSiva Durga Prasad Paladugu 			break;
209d1f4e39dSSiva Durga Prasad Paladugu 		case UHS_DDR50:
210d1f4e39dSSiva Durga Prasad Paladugu 			reg |= UHS_DDR50_BUS_SPEED;
211d1f4e39dSSiva Durga Prasad Paladugu 			break;
212d1f4e39dSSiva Durga Prasad Paladugu 		default:
213d1f4e39dSSiva Durga Prasad Paladugu 			break;
214d1f4e39dSSiva Durga Prasad Paladugu 		}
215d1f4e39dSSiva Durga Prasad Paladugu 		sdhci_writew(host, reg, SDHCI_HOST_CTRL2);
216d1f4e39dSSiva Durga Prasad Paladugu 	}
217d1f4e39dSSiva Durga Prasad Paladugu }
218d1f4e39dSSiva Durga Prasad Paladugu #endif
219d1f4e39dSSiva Durga Prasad Paladugu 
220d1f4e39dSSiva Durga Prasad Paladugu #if defined(CONFIG_DM_MMC) && defined(CONFIG_ARCH_ZYNQMP)
221d1f4e39dSSiva Durga Prasad Paladugu const struct sdhci_ops arasan_ops = {
222d1f4e39dSSiva Durga Prasad Paladugu 	.platform_execute_tuning	= &arasan_sdhci_execute_tuning,
223d1f4e39dSSiva Durga Prasad Paladugu 	.set_delay = &arasan_sdhci_set_tapdelay,
224d1f4e39dSSiva Durga Prasad Paladugu 	.set_control_reg = &arasan_sdhci_set_control_reg,
225d1f4e39dSSiva Durga Prasad Paladugu };
226d1f4e39dSSiva Durga Prasad Paladugu #endif
227d1f4e39dSSiva Durga Prasad Paladugu 
arasan_sdhci_probe(struct udevice * dev)228d9ae52c8SMichal Simek static int arasan_sdhci_probe(struct udevice *dev)
229293eb33fSMichal Simek {
230329a449fSSimon Glass 	struct arasan_sdhci_plat *plat = dev_get_platdata(dev);
231d9ae52c8SMichal Simek 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
232d1f4e39dSSiva Durga Prasad Paladugu 	struct arasan_sdhci_priv *priv = dev_get_priv(dev);
233d1f4e39dSSiva Durga Prasad Paladugu 	struct sdhci_host *host;
234e0f4de1aSStefan Herbrechtsmeier 	struct clk clk;
235e0f4de1aSStefan Herbrechtsmeier 	unsigned long clock;
236329a449fSSimon Glass 	int ret;
237293eb33fSMichal Simek 
238d1f4e39dSSiva Durga Prasad Paladugu 	host = priv->host;
239d1f4e39dSSiva Durga Prasad Paladugu 
240e0f4de1aSStefan Herbrechtsmeier 	ret = clk_get_by_index(dev, 0, &clk);
241e0f4de1aSStefan Herbrechtsmeier 	if (ret < 0) {
242e0f4de1aSStefan Herbrechtsmeier 		dev_err(dev, "failed to get clock\n");
243e0f4de1aSStefan Herbrechtsmeier 		return ret;
244e0f4de1aSStefan Herbrechtsmeier 	}
245e0f4de1aSStefan Herbrechtsmeier 
246e0f4de1aSStefan Herbrechtsmeier 	clock = clk_get_rate(&clk);
247e0f4de1aSStefan Herbrechtsmeier 	if (IS_ERR_VALUE(clock)) {
248e0f4de1aSStefan Herbrechtsmeier 		dev_err(dev, "failed to get rate\n");
249e0f4de1aSStefan Herbrechtsmeier 		return clock;
250e0f4de1aSStefan Herbrechtsmeier 	}
251d1f4e39dSSiva Durga Prasad Paladugu 
252e0f4de1aSStefan Herbrechtsmeier 	debug("%s: CLK %ld\n", __func__, clock);
253e0f4de1aSStefan Herbrechtsmeier 
254e0f4de1aSStefan Herbrechtsmeier 	ret = clk_enable(&clk);
255e0f4de1aSStefan Herbrechtsmeier 	if (ret && ret != -ENOSYS) {
256e0f4de1aSStefan Herbrechtsmeier 		dev_err(dev, "failed to enable clock\n");
257e0f4de1aSStefan Herbrechtsmeier 		return ret;
258e0f4de1aSStefan Herbrechtsmeier 	}
259e0f4de1aSStefan Herbrechtsmeier 
260eddabd16SSiva Durga Prasad Paladugu 	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD |
261f9ec45d1SSiva Durga Prasad Paladugu 		       SDHCI_QUIRK_BROKEN_R1B;
262b2156146SSiva Durga Prasad Paladugu 
263b2156146SSiva Durga Prasad Paladugu #ifdef CONFIG_ZYNQ_HISPD_BROKEN
26447819216SHannes Schmelzer 	host->quirks |= SDHCI_QUIRK_BROKEN_HISPD_MODE;
265b2156146SSiva Durga Prasad Paladugu #endif
266b2156146SSiva Durga Prasad Paladugu 
267d1f4e39dSSiva Durga Prasad Paladugu 	if (priv->no_1p8)
268d1f4e39dSSiva Durga Prasad Paladugu 		host->quirks |= SDHCI_QUIRK_NO_1_8_V;
269d1f4e39dSSiva Durga Prasad Paladugu 
270e0f4de1aSStefan Herbrechtsmeier 	host->max_clk = clock;
2716d0e34bfSStefan Herbrechtsmeier 
27261e745d1SStefan Herbrechtsmeier 	ret = sdhci_setup_cfg(&plat->cfg, host, plat->f_max,
27314bed52dSJaehoon Chung 			      CONFIG_ZYNQ_SDHCI_MIN_FREQ);
274329a449fSSimon Glass 	host->mmc = &plat->mmc;
275329a449fSSimon Glass 	if (ret)
276329a449fSSimon Glass 		return ret;
277329a449fSSimon Glass 	host->mmc->priv = host;
278cffe5d86SSimon Glass 	host->mmc->dev = dev;
279329a449fSSimon Glass 	upriv->mmc = host->mmc;
280d9ae52c8SMichal Simek 
281329a449fSSimon Glass 	return sdhci_probe(dev);
282293eb33fSMichal Simek }
283d9ae52c8SMichal Simek 
arasan_sdhci_ofdata_to_platdata(struct udevice * dev)284d9ae52c8SMichal Simek static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev)
285d9ae52c8SMichal Simek {
28661e745d1SStefan Herbrechtsmeier 	struct arasan_sdhci_plat *plat = dev_get_platdata(dev);
287d1f4e39dSSiva Durga Prasad Paladugu 	struct arasan_sdhci_priv *priv = dev_get_priv(dev);
288d9ae52c8SMichal Simek 
289d1f4e39dSSiva Durga Prasad Paladugu 	priv->host = calloc(1, sizeof(struct sdhci_host));
290d1f4e39dSSiva Durga Prasad Paladugu 	if (!priv->host)
291d1f4e39dSSiva Durga Prasad Paladugu 		return -1;
292d1f4e39dSSiva Durga Prasad Paladugu 
293d1f4e39dSSiva Durga Prasad Paladugu 	priv->host->name = dev->name;
294d1f4e39dSSiva Durga Prasad Paladugu 
295d1f4e39dSSiva Durga Prasad Paladugu #if defined(CONFIG_DM_MMC) && defined(CONFIG_ARCH_ZYNQMP)
296d1f4e39dSSiva Durga Prasad Paladugu 	priv->host->ops = &arasan_ops;
297d1f4e39dSSiva Durga Prasad Paladugu #endif
298d9ae52c8SMichal Simek 
299458e8d80SMichal Simek 	priv->host->ioaddr = (void *)dev_read_addr(dev);
300458e8d80SMichal Simek 	if (IS_ERR(priv->host->ioaddr))
301458e8d80SMichal Simek 		return PTR_ERR(priv->host->ioaddr);
30261e745d1SStefan Herbrechtsmeier 
303458e8d80SMichal Simek 	priv->deviceid = dev_read_u32_default(dev, "xlnx,device_id", -1);
304458e8d80SMichal Simek 	priv->bank = dev_read_u32_default(dev, "xlnx,mio_bank", -1);
305458e8d80SMichal Simek 	priv->no_1p8 = dev_read_bool(dev, "no-1-8-v");
306458e8d80SMichal Simek 
307458e8d80SMichal Simek 	plat->f_max = dev_read_u32_default(dev, "max-frequency",
308458e8d80SMichal Simek 					   CONFIG_ZYNQ_SDHCI_MAX_FREQ);
309d9ae52c8SMichal Simek 	return 0;
310d9ae52c8SMichal Simek }
311d9ae52c8SMichal Simek 
arasan_sdhci_bind(struct udevice * dev)312329a449fSSimon Glass static int arasan_sdhci_bind(struct udevice *dev)
313329a449fSSimon Glass {
314329a449fSSimon Glass 	struct arasan_sdhci_plat *plat = dev_get_platdata(dev);
315329a449fSSimon Glass 
31624f5aec3SMasahiro Yamada 	return sdhci_bind(dev, &plat->mmc, &plat->cfg);
317329a449fSSimon Glass }
318329a449fSSimon Glass 
319d9ae52c8SMichal Simek static const struct udevice_id arasan_sdhci_ids[] = {
320d9ae52c8SMichal Simek 	{ .compatible = "arasan,sdhci-8.9a" },
321d9ae52c8SMichal Simek 	{ }
322d9ae52c8SMichal Simek };
323d9ae52c8SMichal Simek 
324d9ae52c8SMichal Simek U_BOOT_DRIVER(arasan_sdhci_drv) = {
325d9ae52c8SMichal Simek 	.name		= "arasan_sdhci",
326d9ae52c8SMichal Simek 	.id		= UCLASS_MMC,
327d9ae52c8SMichal Simek 	.of_match	= arasan_sdhci_ids,
328d9ae52c8SMichal Simek 	.ofdata_to_platdata = arasan_sdhci_ofdata_to_platdata,
329329a449fSSimon Glass 	.ops		= &sdhci_ops,
330329a449fSSimon Glass 	.bind		= arasan_sdhci_bind,
331d9ae52c8SMichal Simek 	.probe		= arasan_sdhci_probe,
332d1f4e39dSSiva Durga Prasad Paladugu 	.priv_auto_alloc_size = sizeof(struct arasan_sdhci_priv),
333329a449fSSimon Glass 	.platdata_auto_alloc_size = sizeof(struct arasan_sdhci_plat),
334d9ae52c8SMichal Simek };
335