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