]>
Commit | Line | Data |
---|---|---|
b6acb5f1 SR |
1 | /* |
2 | * Driver for Marvell SOC Platform Group Xenon SDHC as a platform device | |
3 | * | |
4 | * Copyright (C) 2016 Marvell, All Rights Reserved. | |
5 | * | |
6 | * Author: Victor Gu <xigu@marvell.com> | |
7 | * Date: 2016-8-24 | |
8 | * | |
9 | * Included parts of the Linux driver version which was written by: | |
10 | * Hu Ziji <huziji@marvell.com> | |
11 | * | |
12 | * Ported to from Marvell 2015.01 to mainline U-Boot 2017.01: | |
13 | * Stefan Roese <sr@denx.de> | |
14 | * | |
15 | * SPDX-License-Identifier: GPL-2.0 | |
16 | */ | |
17 | ||
18 | #include <common.h> | |
19 | #include <dm.h> | |
20 | #include <fdtdec.h> | |
21 | #include <libfdt.h> | |
22 | #include <malloc.h> | |
23 | #include <sdhci.h> | |
24 | ||
25 | DECLARE_GLOBAL_DATA_PTR; | |
26 | ||
27 | /* Register Offset of SD Host Controller SOCP self-defined register */ | |
28 | #define SDHC_SYS_CFG_INFO 0x0104 | |
29 | #define SLOT_TYPE_SDIO_SHIFT 24 | |
30 | #define SLOT_TYPE_EMMC_MASK 0xFF | |
31 | #define SLOT_TYPE_EMMC_SHIFT 16 | |
32 | #define SLOT_TYPE_SD_SDIO_MMC_MASK 0xFF | |
33 | #define SLOT_TYPE_SD_SDIO_MMC_SHIFT 8 | |
34 | #define NR_SUPPORTED_SLOT_MASK 0x7 | |
35 | ||
36 | #define SDHC_SYS_OP_CTRL 0x0108 | |
37 | #define AUTO_CLKGATE_DISABLE_MASK BIT(20) | |
38 | #define SDCLK_IDLEOFF_ENABLE_SHIFT 8 | |
39 | #define SLOT_ENABLE_SHIFT 0 | |
40 | ||
41 | #define SDHC_SYS_EXT_OP_CTRL 0x010C | |
42 | #define MASK_CMD_CONFLICT_ERROR BIT(8) | |
43 | ||
44 | #define SDHC_SLOT_RETUNING_REQ_CTRL 0x0144 | |
45 | /* retuning compatible */ | |
46 | #define RETUNING_COMPATIBLE 0x1 | |
47 | ||
48 | /* Xenon specific Mode Select value */ | |
49 | #define XENON_SDHCI_CTRL_HS200 0x5 | |
50 | #define XENON_SDHCI_CTRL_HS400 0x6 | |
51 | ||
52 | #define EMMC_PHY_REG_BASE 0x170 | |
53 | #define EMMC_PHY_TIMING_ADJUST EMMC_PHY_REG_BASE | |
54 | #define OUTPUT_QSN_PHASE_SELECT BIT(17) | |
55 | #define SAMPL_INV_QSP_PHASE_SELECT BIT(18) | |
56 | #define SAMPL_INV_QSP_PHASE_SELECT_SHIFT 18 | |
57 | #define EMMC_PHY_SLOW_MODE BIT(29) | |
58 | #define PHY_INITIALIZAION BIT(31) | |
59 | #define WAIT_CYCLE_BEFORE_USING_MASK 0xf | |
60 | #define WAIT_CYCLE_BEFORE_USING_SHIFT 12 | |
61 | #define FC_SYNC_EN_DURATION_MASK 0xf | |
62 | #define FC_SYNC_EN_DURATION_SHIFT 8 | |
63 | #define FC_SYNC_RST_EN_DURATION_MASK 0xf | |
64 | #define FC_SYNC_RST_EN_DURATION_SHIFT 4 | |
65 | #define FC_SYNC_RST_DURATION_MASK 0xf | |
66 | #define FC_SYNC_RST_DURATION_SHIFT 0 | |
67 | ||
68 | #define EMMC_PHY_FUNC_CONTROL (EMMC_PHY_REG_BASE + 0x4) | |
69 | #define DQ_ASYNC_MODE BIT(4) | |
70 | #define DQ_DDR_MODE_SHIFT 8 | |
71 | #define DQ_DDR_MODE_MASK 0xff | |
72 | #define CMD_DDR_MODE BIT(16) | |
73 | ||
74 | #define EMMC_PHY_PAD_CONTROL (EMMC_PHY_REG_BASE + 0x8) | |
75 | #define REC_EN_SHIFT 24 | |
76 | #define REC_EN_MASK 0xf | |
77 | #define FC_DQ_RECEN BIT(24) | |
78 | #define FC_CMD_RECEN BIT(25) | |
79 | #define FC_QSP_RECEN BIT(26) | |
80 | #define FC_QSN_RECEN BIT(27) | |
81 | #define OEN_QSN BIT(28) | |
82 | #define AUTO_RECEN_CTRL BIT(30) | |
83 | ||
84 | #define EMMC_PHY_PAD_CONTROL1 (EMMC_PHY_REG_BASE + 0xc) | |
85 | #define EMMC5_1_FC_QSP_PD BIT(9) | |
86 | #define EMMC5_1_FC_QSP_PU BIT(25) | |
87 | #define EMMC5_1_FC_CMD_PD BIT(8) | |
88 | #define EMMC5_1_FC_CMD_PU BIT(24) | |
89 | #define EMMC5_1_FC_DQ_PD 0xff | |
90 | #define EMMC5_1_FC_DQ_PU (0xff << 16) | |
91 | ||
92 | #define SDHCI_RETUNE_EVT_INTSIG 0x00001000 | |
93 | ||
94 | /* Hyperion only have one slot 0 */ | |
95 | #define XENON_MMC_SLOT_ID_HYPERION 0 | |
96 | ||
97 | #define MMC_TIMING_LEGACY 0 | |
98 | #define MMC_TIMING_MMC_HS 1 | |
99 | #define MMC_TIMING_SD_HS 2 | |
100 | #define MMC_TIMING_UHS_SDR12 3 | |
101 | #define MMC_TIMING_UHS_SDR25 4 | |
102 | #define MMC_TIMING_UHS_SDR50 5 | |
103 | #define MMC_TIMING_UHS_SDR104 6 | |
104 | #define MMC_TIMING_UHS_DDR50 7 | |
105 | #define MMC_TIMING_MMC_DDR52 8 | |
106 | #define MMC_TIMING_MMC_HS200 9 | |
107 | #define MMC_TIMING_MMC_HS400 10 | |
108 | ||
109 | #define XENON_MMC_MAX_CLK 400000000 | |
110 | ||
111 | enum soc_pad_ctrl_type { | |
112 | SOC_PAD_SD, | |
113 | SOC_PAD_FIXED_1_8V, | |
114 | }; | |
115 | ||
116 | struct xenon_sdhci_plat { | |
117 | struct mmc_config cfg; | |
118 | struct mmc mmc; | |
119 | }; | |
120 | ||
121 | struct xenon_sdhci_priv { | |
122 | struct sdhci_host host; | |
123 | ||
124 | u8 timing; | |
125 | ||
126 | unsigned int clock; | |
127 | ||
128 | void *pad_ctrl_reg; | |
129 | int pad_type; | |
130 | }; | |
131 | ||
132 | static int xenon_mmc_phy_init(struct sdhci_host *host) | |
133 | { | |
134 | struct xenon_sdhci_priv *priv = host->mmc->priv; | |
135 | u32 clock = priv->clock; | |
136 | u32 time; | |
137 | u32 var; | |
138 | ||
139 | /* Enable QSP PHASE SELECT */ | |
140 | var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST); | |
141 | var |= SAMPL_INV_QSP_PHASE_SELECT; | |
142 | if ((priv->timing == MMC_TIMING_UHS_SDR50) || | |
143 | (priv->timing == MMC_TIMING_UHS_SDR25) || | |
144 | (priv->timing == MMC_TIMING_UHS_SDR12) || | |
145 | (priv->timing == MMC_TIMING_SD_HS) || | |
146 | (priv->timing == MMC_TIMING_LEGACY)) | |
147 | var |= EMMC_PHY_SLOW_MODE; | |
148 | sdhci_writel(host, var, EMMC_PHY_TIMING_ADJUST); | |
149 | ||
150 | /* Poll for host MMC PHY clock init to be stable */ | |
151 | /* Wait up to 10ms */ | |
152 | time = 100; | |
153 | while (time--) { | |
154 | var = sdhci_readl(host, SDHCI_CLOCK_CONTROL); | |
155 | if (var & SDHCI_CLOCK_INT_STABLE) | |
156 | break; | |
157 | ||
158 | udelay(100); | |
159 | } | |
160 | ||
161 | if (time <= 0) { | |
9b643e31 | 162 | pr_err("Failed to enable MMC internal clock in time\n"); |
b6acb5f1 SR |
163 | return -ETIMEDOUT; |
164 | } | |
165 | ||
166 | /* Init PHY */ | |
167 | var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST); | |
168 | var |= PHY_INITIALIZAION; | |
169 | sdhci_writel(host, var, EMMC_PHY_TIMING_ADJUST); | |
170 | ||
171 | if (clock == 0) { | |
172 | /* Use the possibly slowest bus frequency value */ | |
173 | clock = 100000; | |
174 | } | |
175 | ||
176 | /* Poll for host eMMC PHY init to complete */ | |
177 | /* Wait up to 10ms */ | |
178 | time = 100; | |
179 | while (time--) { | |
180 | var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST); | |
181 | var &= PHY_INITIALIZAION; | |
182 | if (!var) | |
183 | break; | |
184 | ||
185 | /* wait for host eMMC PHY init to complete */ | |
186 | udelay(100); | |
187 | } | |
188 | ||
189 | if (time <= 0) { | |
9b643e31 | 190 | pr_err("Failed to init MMC PHY in time\n"); |
b6acb5f1 SR |
191 | return -ETIMEDOUT; |
192 | } | |
193 | ||
194 | return 0; | |
195 | } | |
196 | ||
197 | #define ARMADA_3700_SOC_PAD_1_8V 0x1 | |
198 | #define ARMADA_3700_SOC_PAD_3_3V 0x0 | |
199 | ||
200 | static void armada_3700_soc_pad_voltage_set(struct sdhci_host *host) | |
201 | { | |
202 | struct xenon_sdhci_priv *priv = host->mmc->priv; | |
203 | ||
204 | if (priv->pad_type == SOC_PAD_FIXED_1_8V) | |
205 | writel(ARMADA_3700_SOC_PAD_1_8V, priv->pad_ctrl_reg); | |
206 | else if (priv->pad_type == SOC_PAD_SD) | |
207 | writel(ARMADA_3700_SOC_PAD_3_3V, priv->pad_ctrl_reg); | |
208 | } | |
209 | ||
210 | static void xenon_mmc_phy_set(struct sdhci_host *host) | |
211 | { | |
212 | struct xenon_sdhci_priv *priv = host->mmc->priv; | |
213 | u32 var; | |
214 | ||
215 | /* Setup pad, set bit[30], bit[28] and bits[26:24] */ | |
216 | var = sdhci_readl(host, EMMC_PHY_PAD_CONTROL); | |
217 | var |= AUTO_RECEN_CTRL | OEN_QSN | FC_QSP_RECEN | | |
218 | FC_CMD_RECEN | FC_DQ_RECEN; | |
219 | sdhci_writel(host, var, EMMC_PHY_PAD_CONTROL); | |
220 | ||
221 | /* Set CMD and DQ Pull Up */ | |
222 | var = sdhci_readl(host, EMMC_PHY_PAD_CONTROL1); | |
223 | var |= (EMMC5_1_FC_CMD_PU | EMMC5_1_FC_DQ_PU); | |
224 | var &= ~(EMMC5_1_FC_CMD_PD | EMMC5_1_FC_DQ_PD); | |
225 | sdhci_writel(host, var, EMMC_PHY_PAD_CONTROL1); | |
226 | ||
227 | /* | |
228 | * If timing belongs to high speed, set bit[17] of | |
229 | * EMMC_PHY_TIMING_ADJUST register | |
230 | */ | |
231 | if ((priv->timing == MMC_TIMING_MMC_HS400) || | |
232 | (priv->timing == MMC_TIMING_MMC_HS200) || | |
233 | (priv->timing == MMC_TIMING_UHS_SDR50) || | |
234 | (priv->timing == MMC_TIMING_UHS_SDR104) || | |
235 | (priv->timing == MMC_TIMING_UHS_DDR50) || | |
236 | (priv->timing == MMC_TIMING_UHS_SDR25) || | |
237 | (priv->timing == MMC_TIMING_MMC_DDR52)) { | |
238 | var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST); | |
239 | var |= OUTPUT_QSN_PHASE_SELECT; | |
240 | sdhci_writel(host, var, EMMC_PHY_TIMING_ADJUST); | |
241 | } | |
242 | ||
243 | /* | |
244 | * When setting EMMC_PHY_FUNC_CONTROL register, | |
245 | * SD clock should be disabled | |
246 | */ | |
247 | var = sdhci_readl(host, SDHCI_CLOCK_CONTROL); | |
248 | var &= ~SDHCI_CLOCK_CARD_EN; | |
249 | sdhci_writew(host, var, SDHCI_CLOCK_CONTROL); | |
250 | ||
251 | var = sdhci_readl(host, EMMC_PHY_FUNC_CONTROL); | |
252 | if (host->mmc->ddr_mode) { | |
253 | var |= (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE; | |
254 | } else { | |
255 | var &= ~((DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | | |
256 | CMD_DDR_MODE); | |
257 | } | |
258 | sdhci_writel(host, var, EMMC_PHY_FUNC_CONTROL); | |
259 | ||
260 | /* Enable bus clock */ | |
261 | var = sdhci_readl(host, SDHCI_CLOCK_CONTROL); | |
262 | var |= SDHCI_CLOCK_CARD_EN; | |
263 | sdhci_writew(host, var, SDHCI_CLOCK_CONTROL); | |
264 | ||
265 | xenon_mmc_phy_init(host); | |
266 | } | |
267 | ||
268 | /* Enable/Disable the Auto Clock Gating function of this slot */ | |
269 | static void xenon_mmc_set_acg(struct sdhci_host *host, bool enable) | |
270 | { | |
271 | u32 var; | |
272 | ||
273 | var = sdhci_readl(host, SDHC_SYS_OP_CTRL); | |
274 | if (enable) | |
275 | var &= ~AUTO_CLKGATE_DISABLE_MASK; | |
276 | else | |
277 | var |= AUTO_CLKGATE_DISABLE_MASK; | |
278 | ||
279 | sdhci_writel(host, var, SDHC_SYS_OP_CTRL); | |
280 | } | |
281 | ||
282 | #define SLOT_MASK(slot) BIT(slot) | |
283 | ||
284 | /* Enable specific slot */ | |
285 | static void xenon_mmc_enable_slot(struct sdhci_host *host, u8 slot) | |
286 | { | |
287 | u32 var; | |
288 | ||
289 | var = sdhci_readl(host, SDHC_SYS_OP_CTRL); | |
290 | var |= SLOT_MASK(slot) << SLOT_ENABLE_SHIFT; | |
291 | sdhci_writel(host, var, SDHC_SYS_OP_CTRL); | |
292 | } | |
293 | ||
294 | /* Enable Parallel Transfer Mode */ | |
295 | static void xenon_mmc_enable_parallel_tran(struct sdhci_host *host, u8 slot) | |
296 | { | |
297 | u32 var; | |
298 | ||
299 | var = sdhci_readl(host, SDHC_SYS_EXT_OP_CTRL); | |
300 | var |= SLOT_MASK(slot); | |
301 | sdhci_writel(host, var, SDHC_SYS_EXT_OP_CTRL); | |
302 | } | |
303 | ||
304 | static void xenon_mmc_disable_tuning(struct sdhci_host *host, u8 slot) | |
305 | { | |
306 | u32 var; | |
307 | ||
308 | /* Clear the Re-Tuning Request functionality */ | |
309 | var = sdhci_readl(host, SDHC_SLOT_RETUNING_REQ_CTRL); | |
310 | var &= ~RETUNING_COMPATIBLE; | |
311 | sdhci_writel(host, var, SDHC_SLOT_RETUNING_REQ_CTRL); | |
312 | ||
313 | /* Clear the Re-tuning Event Signal Enable */ | |
314 | var = sdhci_readl(host, SDHCI_SIGNAL_ENABLE); | |
315 | var &= ~SDHCI_RETUNE_EVT_INTSIG; | |
316 | sdhci_writel(host, var, SDHCI_SIGNAL_ENABLE); | |
317 | } | |
318 | ||
319 | /* Mask command conflict error */ | |
320 | static void xenon_mask_cmd_conflict_err(struct sdhci_host *host) | |
321 | { | |
322 | u32 reg; | |
323 | ||
324 | reg = sdhci_readl(host, SDHC_SYS_EXT_OP_CTRL); | |
325 | reg |= MASK_CMD_CONFLICT_ERROR; | |
326 | sdhci_writel(host, reg, SDHC_SYS_EXT_OP_CTRL); | |
327 | } | |
328 | ||
329 | /* Platform specific function for post set_ios configuration */ | |
330 | static void xenon_sdhci_set_ios_post(struct sdhci_host *host) | |
331 | { | |
332 | struct xenon_sdhci_priv *priv = host->mmc->priv; | |
333 | uint speed = host->mmc->tran_speed; | |
334 | int pwr_18v = 0; | |
335 | ||
336 | if ((sdhci_readb(host, SDHCI_POWER_CONTROL) & ~SDHCI_POWER_ON) == | |
337 | SDHCI_POWER_180) | |
338 | pwr_18v = 1; | |
339 | ||
340 | /* Set timing variable according to the configured speed */ | |
341 | if (IS_SD(host->mmc)) { | |
342 | /* SD/SDIO */ | |
343 | if (pwr_18v) { | |
344 | if (host->mmc->ddr_mode) | |
345 | priv->timing = MMC_TIMING_UHS_DDR50; | |
346 | else if (speed <= 25000000) | |
347 | priv->timing = MMC_TIMING_UHS_SDR25; | |
348 | else | |
349 | priv->timing = MMC_TIMING_UHS_SDR50; | |
350 | } else { | |
351 | if (speed <= 25000000) | |
352 | priv->timing = MMC_TIMING_LEGACY; | |
353 | else | |
354 | priv->timing = MMC_TIMING_SD_HS; | |
355 | } | |
356 | } else { | |
357 | /* eMMC */ | |
358 | if (host->mmc->ddr_mode) | |
359 | priv->timing = MMC_TIMING_MMC_DDR52; | |
360 | else if (speed <= 26000000) | |
361 | priv->timing = MMC_TIMING_LEGACY; | |
362 | else | |
363 | priv->timing = MMC_TIMING_MMC_HS; | |
364 | } | |
365 | ||
366 | /* Re-init the PHY */ | |
367 | xenon_mmc_phy_set(host); | |
368 | } | |
369 | ||
370 | /* Install a driver specific handler for post set_ios configuration */ | |
371 | static const struct sdhci_ops xenon_sdhci_ops = { | |
372 | .set_ios_post = xenon_sdhci_set_ios_post | |
373 | }; | |
374 | ||
375 | static int xenon_sdhci_probe(struct udevice *dev) | |
376 | { | |
377 | struct xenon_sdhci_plat *plat = dev_get_platdata(dev); | |
378 | struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); | |
379 | struct xenon_sdhci_priv *priv = dev_get_priv(dev); | |
380 | struct sdhci_host *host = dev_get_priv(dev); | |
381 | int ret; | |
382 | ||
383 | host->mmc = &plat->mmc; | |
384 | host->mmc->priv = host; | |
385 | host->mmc->dev = dev; | |
386 | upriv->mmc = host->mmc; | |
387 | ||
388 | /* Set quirks */ | |
389 | host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_32BIT_DMA_ADDR; | |
390 | ||
391 | /* Set default timing */ | |
392 | priv->timing = MMC_TIMING_LEGACY; | |
393 | ||
394 | /* Disable auto clock gating during init */ | |
395 | xenon_mmc_set_acg(host, false); | |
396 | ||
397 | /* Enable slot */ | |
398 | xenon_mmc_enable_slot(host, XENON_MMC_SLOT_ID_HYPERION); | |
399 | ||
400 | /* | |
401 | * Set default power on SoC PHY PAD register (currently only | |
402 | * available on the Armada 3700) | |
403 | */ | |
404 | if (priv->pad_ctrl_reg) | |
405 | armada_3700_soc_pad_voltage_set(host); | |
406 | ||
407 | host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_DDR_52MHz; | |
e160f7d4 SG |
408 | switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width", |
409 | 1)) { | |
b6acb5f1 SR |
410 | case 8: |
411 | host->host_caps |= MMC_MODE_8BIT; | |
412 | break; | |
413 | case 4: | |
414 | host->host_caps |= MMC_MODE_4BIT; | |
415 | break; | |
416 | case 1: | |
417 | break; | |
418 | default: | |
419 | printf("Invalid \"bus-width\" value\n"); | |
420 | return -EINVAL; | |
421 | } | |
422 | ||
423 | host->ops = &xenon_sdhci_ops; | |
424 | ||
de0359c2 SR |
425 | host->max_clk = XENON_MMC_MAX_CLK; |
426 | ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0); | |
b6acb5f1 SR |
427 | if (ret) |
428 | return ret; | |
429 | ||
430 | ret = sdhci_probe(dev); | |
431 | if (ret) | |
432 | return ret; | |
433 | ||
434 | /* Enable parallel transfer */ | |
435 | xenon_mmc_enable_parallel_tran(host, XENON_MMC_SLOT_ID_HYPERION); | |
436 | ||
437 | /* Disable tuning functionality of this slot */ | |
438 | xenon_mmc_disable_tuning(host, XENON_MMC_SLOT_ID_HYPERION); | |
439 | ||
440 | /* Enable auto clock gating after init */ | |
441 | xenon_mmc_set_acg(host, true); | |
442 | ||
443 | xenon_mask_cmd_conflict_err(host); | |
444 | ||
445 | return ret; | |
446 | } | |
447 | ||
448 | static int xenon_sdhci_ofdata_to_platdata(struct udevice *dev) | |
449 | { | |
450 | struct sdhci_host *host = dev_get_priv(dev); | |
451 | struct xenon_sdhci_priv *priv = dev_get_priv(dev); | |
452 | const char *name; | |
453 | ||
454 | host->name = dev->name; | |
a821c4af | 455 | host->ioaddr = (void *)devfdt_get_addr(dev); |
b6acb5f1 | 456 | |
911f3aef | 457 | if (device_is_compatible(dev, "marvell,armada-3700-sdhci")) |
a821c4af | 458 | priv->pad_ctrl_reg = (void *)devfdt_get_addr_index(dev, 1); |
b6acb5f1 | 459 | |
e160f7d4 | 460 | name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "marvell,pad-type", |
b6acb5f1 SR |
461 | NULL); |
462 | if (name) { | |
463 | if (0 == strncmp(name, "sd", 2)) { | |
464 | priv->pad_type = SOC_PAD_SD; | |
465 | } else if (0 == strncmp(name, "fixed-1-8v", 10)) { | |
466 | priv->pad_type = SOC_PAD_FIXED_1_8V; | |
467 | } else { | |
468 | printf("Unsupported SOC PHY PAD ctrl type %s\n", name); | |
469 | return -EINVAL; | |
470 | } | |
471 | } | |
472 | ||
473 | return 0; | |
474 | } | |
475 | ||
476 | static int xenon_sdhci_bind(struct udevice *dev) | |
477 | { | |
478 | struct xenon_sdhci_plat *plat = dev_get_platdata(dev); | |
479 | ||
480 | return sdhci_bind(dev, &plat->mmc, &plat->cfg); | |
481 | } | |
482 | ||
483 | static const struct udevice_id xenon_sdhci_ids[] = { | |
484 | { .compatible = "marvell,armada-8k-sdhci",}, | |
485 | { .compatible = "marvell,armada-3700-sdhci",}, | |
486 | { } | |
487 | }; | |
488 | ||
489 | U_BOOT_DRIVER(xenon_sdhci_drv) = { | |
490 | .name = "xenon_sdhci", | |
491 | .id = UCLASS_MMC, | |
492 | .of_match = xenon_sdhci_ids, | |
493 | .ofdata_to_platdata = xenon_sdhci_ofdata_to_platdata, | |
494 | .ops = &sdhci_ops, | |
495 | .bind = xenon_sdhci_bind, | |
496 | .probe = xenon_sdhci_probe, | |
497 | .priv_auto_alloc_size = sizeof(struct xenon_sdhci_priv), | |
498 | .platdata_auto_alloc_size = sizeof(struct xenon_sdhci_plat), | |
499 | }; |