]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
e7ecf7cb SG |
2 | /* |
3 | * Copyright (C) 2015 Google, Inc | |
39913ace | 4 | * Copyright 2020 NXP |
e7ecf7cb | 5 | * Written by Simon Glass <[email protected]> |
e7ecf7cb SG |
6 | */ |
7 | ||
b953ec2b PD |
8 | #define LOG_CATEGORY UCLASS_MMC |
9 | ||
e7ecf7cb | 10 | #include <common.h> |
b8aa463e | 11 | #include <bootdev.h> |
f7ae49fc | 12 | #include <log.h> |
e7ecf7cb SG |
13 | #include <mmc.h> |
14 | #include <dm.h> | |
eede897e | 15 | #include <dm/device-internal.h> |
336d4615 | 16 | #include <dm/device_compat.h> |
e7ecf7cb | 17 | #include <dm/lists.h> |
336d4615 | 18 | #include <linux/compat.h> |
eede897e | 19 | #include "mmc_private.h" |
e7ecf7cb | 20 | |
d77d61ea | 21 | static int dm_mmc_get_b_max(struct udevice *dev, void *dst, lbaint_t blkcnt) |
145429aa MV |
22 | { |
23 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
24 | struct mmc *mmc = mmc_get_mmc_dev(dev); | |
25 | ||
26 | if (ops->get_b_max) | |
27 | return ops->get_b_max(dev, dst, blkcnt); | |
28 | else | |
29 | return mmc->cfg->b_max; | |
30 | } | |
31 | ||
32 | int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt) | |
33 | { | |
34 | return dm_mmc_get_b_max(mmc->dev, dst, blkcnt); | |
35 | } | |
36 | ||
d77d61ea | 37 | static int dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, |
8ca51e51 SG |
38 | struct mmc_data *data) |
39 | { | |
40 | struct mmc *mmc = mmc_get_mmc_dev(dev); | |
41 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
42 | int ret; | |
43 | ||
44 | mmmc_trace_before_send(mmc, cmd); | |
45 | if (ops->send_cmd) | |
46 | ret = ops->send_cmd(dev, cmd, data); | |
47 | else | |
48 | ret = -ENOSYS; | |
49 | mmmc_trace_after_send(mmc, cmd, ret); | |
50 | ||
51 | return ret; | |
52 | } | |
53 | ||
54 | int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) | |
55 | { | |
56 | return dm_mmc_send_cmd(mmc->dev, cmd, data); | |
57 | } | |
58 | ||
d77d61ea | 59 | static int dm_mmc_set_ios(struct udevice *dev) |
8ca51e51 SG |
60 | { |
61 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
62 | ||
63 | if (!ops->set_ios) | |
64 | return -ENOSYS; | |
65 | return ops->set_ios(dev); | |
66 | } | |
67 | ||
68 | int mmc_set_ios(struct mmc *mmc) | |
69 | { | |
70 | return dm_mmc_set_ios(mmc->dev); | |
71 | } | |
72 | ||
d77d61ea | 73 | static int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout_us) |
c10b85d6 JJH |
74 | { |
75 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
76 | ||
77 | if (!ops->wait_dat0) | |
78 | return -ENOSYS; | |
6cf8a903 | 79 | return ops->wait_dat0(dev, state, timeout_us); |
c10b85d6 JJH |
80 | } |
81 | ||
6cf8a903 | 82 | int mmc_wait_dat0(struct mmc *mmc, int state, int timeout_us) |
c10b85d6 | 83 | { |
6cf8a903 | 84 | return dm_mmc_wait_dat0(mmc->dev, state, timeout_us); |
c10b85d6 JJH |
85 | } |
86 | ||
d77d61ea | 87 | static int dm_mmc_get_wp(struct udevice *dev) |
8ca51e51 SG |
88 | { |
89 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
90 | ||
91 | if (!ops->get_wp) | |
92 | return -ENOSYS; | |
93 | return ops->get_wp(dev); | |
94 | } | |
95 | ||
96 | int mmc_getwp(struct mmc *mmc) | |
97 | { | |
98 | return dm_mmc_get_wp(mmc->dev); | |
99 | } | |
100 | ||
d77d61ea | 101 | static int dm_mmc_get_cd(struct udevice *dev) |
8ca51e51 SG |
102 | { |
103 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
104 | ||
105 | if (!ops->get_cd) | |
106 | return -ENOSYS; | |
107 | return ops->get_cd(dev); | |
108 | } | |
109 | ||
110 | int mmc_getcd(struct mmc *mmc) | |
111 | { | |
112 | return dm_mmc_get_cd(mmc->dev); | |
113 | } | |
8ca51e51 | 114 | |
f99c2efe | 115 | #ifdef MMC_SUPPORTS_TUNING |
d77d61ea | 116 | static int dm_mmc_execute_tuning(struct udevice *dev, uint opcode) |
ec841209 KVA |
117 | { |
118 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
119 | ||
120 | if (!ops->execute_tuning) | |
121 | return -ENOSYS; | |
122 | return ops->execute_tuning(dev, opcode); | |
123 | } | |
124 | ||
125 | int mmc_execute_tuning(struct mmc *mmc, uint opcode) | |
126 | { | |
127 | return dm_mmc_execute_tuning(mmc->dev, opcode); | |
128 | } | |
f99c2efe | 129 | #endif |
ec841209 | 130 | |
44acd492 | 131 | #if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) |
d77d61ea | 132 | static int dm_mmc_set_enhanced_strobe(struct udevice *dev) |
44acd492 PF |
133 | { |
134 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
135 | ||
136 | if (ops->set_enhanced_strobe) | |
137 | return ops->set_enhanced_strobe(dev); | |
138 | ||
139 | return -ENOTSUPP; | |
140 | } | |
141 | ||
142 | int mmc_set_enhanced_strobe(struct mmc *mmc) | |
143 | { | |
144 | return dm_mmc_set_enhanced_strobe(mmc->dev); | |
145 | } | |
146 | #endif | |
147 | ||
d77d61ea | 148 | static int dm_mmc_hs400_prepare_ddr(struct udevice *dev) |
d271e105 YL |
149 | { |
150 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
151 | ||
152 | if (ops->hs400_prepare_ddr) | |
153 | return ops->hs400_prepare_ddr(dev); | |
154 | ||
155 | return 0; | |
156 | } | |
157 | ||
158 | int mmc_hs400_prepare_ddr(struct mmc *mmc) | |
159 | { | |
160 | return dm_mmc_hs400_prepare_ddr(mmc->dev); | |
161 | } | |
162 | ||
d77d61ea | 163 | static int dm_mmc_host_power_cycle(struct udevice *dev) |
3602a56a YG |
164 | { |
165 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
166 | ||
167 | if (ops->host_power_cycle) | |
168 | return ops->host_power_cycle(dev); | |
169 | return 0; | |
170 | } | |
171 | ||
172 | int mmc_host_power_cycle(struct mmc *mmc) | |
173 | { | |
174 | return dm_mmc_host_power_cycle(mmc->dev); | |
175 | } | |
176 | ||
d77d61ea | 177 | static int dm_mmc_deferred_probe(struct udevice *dev) |
32860bdb FA |
178 | { |
179 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
180 | ||
181 | if (ops->deferred_probe) | |
182 | return ops->deferred_probe(dev); | |
183 | ||
184 | return 0; | |
185 | } | |
186 | ||
187 | int mmc_deferred_probe(struct mmc *mmc) | |
188 | { | |
189 | return dm_mmc_deferred_probe(mmc->dev); | |
190 | } | |
191 | ||
d77d61ea | 192 | static int dm_mmc_reinit(struct udevice *dev) |
390f9bdd YL |
193 | { |
194 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
195 | ||
196 | if (ops->reinit) | |
197 | return ops->reinit(dev); | |
198 | ||
199 | return 0; | |
200 | } | |
201 | ||
202 | int mmc_reinit(struct mmc *mmc) | |
203 | { | |
204 | return dm_mmc_reinit(mmc->dev); | |
205 | } | |
206 | ||
7abff2c3 | 207 | int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) |
9215ef5e KVA |
208 | { |
209 | int val; | |
210 | ||
7abff2c3 | 211 | val = dev_read_u32_default(dev, "bus-width", 1); |
9215ef5e KVA |
212 | |
213 | switch (val) { | |
214 | case 0x8: | |
215 | cfg->host_caps |= MMC_MODE_8BIT; | |
216 | /* fall through */ | |
217 | case 0x4: | |
218 | cfg->host_caps |= MMC_MODE_4BIT; | |
219 | /* fall through */ | |
220 | case 0x1: | |
221 | cfg->host_caps |= MMC_MODE_1BIT; | |
222 | break; | |
223 | default: | |
4b28f7bc MY |
224 | dev_err(dev, "Invalid \"bus-width\" value %u!\n", val); |
225 | return -EINVAL; | |
9215ef5e KVA |
226 | } |
227 | ||
c42ee367 MY |
228 | /* f_max is obtained from the optional "max-frequency" property */ |
229 | dev_read_u32(dev, "max-frequency", &cfg->f_max); | |
9215ef5e | 230 | |
7abff2c3 | 231 | if (dev_read_bool(dev, "cap-sd-highspeed")) |
9215ef5e | 232 | cfg->host_caps |= MMC_CAP(SD_HS); |
7abff2c3 | 233 | if (dev_read_bool(dev, "cap-mmc-highspeed")) |
f80b8ac6 | 234 | cfg->host_caps |= MMC_CAP(MMC_HS) | MMC_CAP(MMC_HS_52); |
7abff2c3 | 235 | if (dev_read_bool(dev, "sd-uhs-sdr12")) |
9215ef5e | 236 | cfg->host_caps |= MMC_CAP(UHS_SDR12); |
7abff2c3 | 237 | if (dev_read_bool(dev, "sd-uhs-sdr25")) |
9215ef5e | 238 | cfg->host_caps |= MMC_CAP(UHS_SDR25); |
7abff2c3 | 239 | if (dev_read_bool(dev, "sd-uhs-sdr50")) |
9215ef5e | 240 | cfg->host_caps |= MMC_CAP(UHS_SDR50); |
7abff2c3 | 241 | if (dev_read_bool(dev, "sd-uhs-sdr104")) |
9215ef5e | 242 | cfg->host_caps |= MMC_CAP(UHS_SDR104); |
7abff2c3 | 243 | if (dev_read_bool(dev, "sd-uhs-ddr50")) |
9215ef5e | 244 | cfg->host_caps |= MMC_CAP(UHS_DDR50); |
7abff2c3 | 245 | if (dev_read_bool(dev, "mmc-ddr-1_8v")) |
9215ef5e | 246 | cfg->host_caps |= MMC_CAP(MMC_DDR_52); |
7abff2c3 JJH |
247 | if (dev_read_bool(dev, "mmc-ddr-1_2v")) |
248 | cfg->host_caps |= MMC_CAP(MMC_DDR_52); | |
249 | if (dev_read_bool(dev, "mmc-hs200-1_8v")) | |
250 | cfg->host_caps |= MMC_CAP(MMC_HS_200); | |
251 | if (dev_read_bool(dev, "mmc-hs200-1_2v")) | |
9215ef5e | 252 | cfg->host_caps |= MMC_CAP(MMC_HS_200); |
eb2acbaf MV |
253 | if (dev_read_bool(dev, "mmc-hs400-1_8v")) |
254 | cfg->host_caps |= MMC_CAP(MMC_HS_400); | |
255 | if (dev_read_bool(dev, "mmc-hs400-1_2v")) | |
256 | cfg->host_caps |= MMC_CAP(MMC_HS_400); | |
b0fc3127 PF |
257 | if (dev_read_bool(dev, "mmc-hs400-enhanced-strobe")) |
258 | cfg->host_caps |= MMC_CAP(MMC_HS_400_ES); | |
9215ef5e | 259 | |
86a94e7b KR |
260 | if (dev_read_bool(dev, "non-removable")) { |
261 | cfg->host_caps |= MMC_CAP_NONREMOVABLE; | |
262 | } else { | |
263 | if (dev_read_bool(dev, "cd-inverted")) | |
264 | cfg->host_caps |= MMC_CAP_CD_ACTIVE_HIGH; | |
265 | if (dev_read_bool(dev, "broken-cd")) | |
266 | cfg->host_caps |= MMC_CAP_NEEDS_POLL; | |
267 | } | |
268 | ||
479a8dd6 PF |
269 | if (dev_read_bool(dev, "no-1-8-v")) { |
270 | cfg->host_caps &= ~(UHS_CAPS | MMC_MODE_HS200 | | |
271 | MMC_MODE_HS400 | MMC_MODE_HS400_ES); | |
272 | } | |
273 | ||
9215ef5e KVA |
274 | return 0; |
275 | } | |
276 | ||
3a905cd2 | 277 | struct mmc *mmc_get_mmc_dev(const struct udevice *dev) |
e7ecf7cb SG |
278 | { |
279 | struct mmc_uclass_priv *upriv; | |
280 | ||
281 | if (!device_active(dev)) | |
282 | return NULL; | |
283 | upriv = dev_get_uclass_priv(dev); | |
284 | return upriv->mmc; | |
285 | } | |
286 | ||
c4d660d4 | 287 | #if CONFIG_IS_ENABLED(BLK) |
8ef761ed SG |
288 | struct mmc *find_mmc_device(int dev_num) |
289 | { | |
290 | struct udevice *dev, *mmc_dev; | |
291 | int ret; | |
292 | ||
e33a5c6b | 293 | ret = blk_find_device(UCLASS_MMC, dev_num, &dev); |
8ef761ed SG |
294 | |
295 | if (ret) { | |
296 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | |
297 | printf("MMC Device %d not found\n", dev_num); | |
298 | #endif | |
299 | return NULL; | |
300 | } | |
301 | ||
302 | mmc_dev = dev_get_parent(dev); | |
303 | ||
97525647 SG |
304 | struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); |
305 | ||
306 | return mmc; | |
8ef761ed SG |
307 | } |
308 | ||
309 | int get_mmc_num(void) | |
310 | { | |
e33a5c6b | 311 | return max((blk_find_max_devnum(UCLASS_MMC) + 1), 0); |
8ef761ed SG |
312 | } |
313 | ||
314 | int mmc_get_next_devnum(void) | |
315 | { | |
e33a5c6b | 316 | return blk_find_max_devnum(UCLASS_MMC); |
8ef761ed SG |
317 | } |
318 | ||
b8aa463e SG |
319 | int mmc_get_blk(struct udevice *dev, struct udevice **blkp) |
320 | { | |
321 | struct udevice *blk; | |
322 | int ret; | |
323 | ||
324 | device_find_first_child_by_uclass(dev, UCLASS_BLK, &blk); | |
325 | ret = device_probe(blk); | |
326 | if (ret) | |
327 | return ret; | |
328 | *blkp = blk; | |
329 | ||
330 | return 0; | |
331 | } | |
332 | ||
8ef761ed SG |
333 | struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) |
334 | { | |
335 | struct blk_desc *desc; | |
336 | struct udevice *dev; | |
337 | ||
ce34a665 | 338 | device_find_first_child_by_uclass(mmc->dev, UCLASS_BLK, &dev); |
8ef761ed SG |
339 | if (!dev) |
340 | return NULL; | |
caa4daa2 | 341 | desc = dev_get_uclass_plat(dev); |
8ef761ed SG |
342 | |
343 | return desc; | |
344 | } | |
345 | ||
346 | void mmc_do_preinit(void) | |
347 | { | |
348 | struct udevice *dev; | |
349 | struct uclass *uc; | |
350 | int ret; | |
351 | ||
352 | ret = uclass_get(UCLASS_MMC, &uc); | |
353 | if (ret) | |
354 | return; | |
355 | uclass_foreach_dev(dev, uc) { | |
356 | struct mmc *m = mmc_get_mmc_dev(dev); | |
357 | ||
358 | if (!m) | |
359 | continue; | |
19f7a34a AG |
360 | |
361 | m->user_speed_mode = MMC_MODES_END; /* Initialising user set speed mode */ | |
362 | ||
8ef761ed SG |
363 | if (m->preinit) |
364 | mmc_start_init(m); | |
365 | } | |
366 | } | |
367 | ||
368 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | |
369 | void print_mmc_devices(char separator) | |
370 | { | |
371 | struct udevice *dev; | |
372 | char *mmc_type; | |
373 | bool first = true; | |
374 | ||
375 | for (uclass_first_device(UCLASS_MMC, &dev); | |
376 | dev; | |
1bd4f92c | 377 | uclass_next_device(&dev), first = false) { |
8ef761ed SG |
378 | struct mmc *m = mmc_get_mmc_dev(dev); |
379 | ||
380 | if (!first) { | |
381 | printf("%c", separator); | |
382 | if (separator != '\n') | |
383 | puts(" "); | |
384 | } | |
385 | if (m->has_init) | |
386 | mmc_type = IS_SD(m) ? "SD" : "eMMC"; | |
387 | else | |
388 | mmc_type = NULL; | |
389 | ||
390 | printf("%s: %d", m->cfg->name, mmc_get_blk_desc(m)->devnum); | |
391 | if (mmc_type) | |
392 | printf(" (%s)", mmc_type); | |
393 | } | |
394 | ||
395 | printf("\n"); | |
396 | } | |
397 | ||
398 | #else | |
399 | void print_mmc_devices(char separator) { } | |
400 | #endif | |
eede897e SG |
401 | |
402 | int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) | |
403 | { | |
404 | struct blk_desc *bdesc; | |
405 | struct udevice *bdev; | |
2243d19e | 406 | int ret; |
02ad33aa | 407 | |
66656020 SG |
408 | if (!mmc_get_ops(dev)) |
409 | return -ENOSYS; | |
2243d19e AG |
410 | |
411 | /* Use the fixed index with aliases node's index */ | |
412 | debug("%s: alias devnum=%d\n", __func__, dev_seq(dev)); | |
eede897e | 413 | |
e33a5c6b SG |
414 | ret = blk_create_devicef(dev, "mmc_blk", "blk", UCLASS_MMC, |
415 | dev_seq(dev), 512, 0, &bdev); | |
eede897e SG |
416 | if (ret) { |
417 | debug("Cannot create block device\n"); | |
418 | return ret; | |
419 | } | |
caa4daa2 | 420 | bdesc = dev_get_uclass_plat(bdev); |
eede897e SG |
421 | mmc->cfg = cfg; |
422 | mmc->priv = dev; | |
423 | ||
3a2cb96e | 424 | ret = bootdev_setup_sibling_blk(bdev, "mmc_bootdev"); |
b8aa463e SG |
425 | if (ret) |
426 | return log_msg_ret("bootdev", ret); | |
427 | ||
eede897e SG |
428 | /* the following chunk was from mmc_register() */ |
429 | ||
430 | /* Setup dsr related values */ | |
431 | mmc->dsr_imp = 0; | |
432 | mmc->dsr = 0xffffffff; | |
433 | /* Setup the universal parts of the block interface just once */ | |
434 | bdesc->removable = 1; | |
435 | ||
436 | /* setup initial part type */ | |
437 | bdesc->part_type = cfg->part_type; | |
438 | mmc->dev = dev; | |
19f7a34a | 439 | mmc->user_speed_mode = MMC_MODES_END; |
eede897e SG |
440 | return 0; |
441 | } | |
442 | ||
443 | int mmc_unbind(struct udevice *dev) | |
444 | { | |
445 | struct udevice *bdev; | |
b8aa463e | 446 | int ret; |
eede897e | 447 | |
ce34a665 | 448 | device_find_first_child_by_uclass(dev, UCLASS_BLK, &bdev); |
eede897e | 449 | if (bdev) { |
706865af | 450 | device_remove(bdev, DM_REMOVE_NORMAL); |
eede897e SG |
451 | device_unbind(bdev); |
452 | } | |
b8aa463e SG |
453 | ret = bootdev_unbind_dev(dev); |
454 | if (ret) | |
455 | return log_msg_ret("bootdev", ret); | |
eede897e SG |
456 | |
457 | return 0; | |
458 | } | |
459 | ||
460 | static int mmc_select_hwpart(struct udevice *bdev, int hwpart) | |
461 | { | |
462 | struct udevice *mmc_dev = dev_get_parent(bdev); | |
463 | struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); | |
caa4daa2 | 464 | struct blk_desc *desc = dev_get_uclass_plat(bdev); |
47b7fa30 | 465 | int ret; |
eede897e SG |
466 | |
467 | if (desc->hwpart == hwpart) | |
468 | return 0; | |
469 | ||
470 | if (mmc->part_config == MMCPART_NOAVAILABLE) | |
471 | return -EMEDIUMTYPE; | |
472 | ||
47b7fa30 WG |
473 | ret = mmc_switch_part(mmc, hwpart); |
474 | if (!ret) | |
8149b150 | 475 | blkcache_invalidate(desc->uclass_id, desc->devnum); |
47b7fa30 WG |
476 | |
477 | return ret; | |
eede897e SG |
478 | } |
479 | ||
a0269bb6 FA |
480 | static int mmc_blk_probe(struct udevice *dev) |
481 | { | |
854f9a71 SG |
482 | struct udevice *mmc_dev = dev_get_parent(dev); |
483 | struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc_dev); | |
484 | struct mmc *mmc = upriv->mmc; | |
485 | int ret; | |
486 | ||
487 | ret = mmc_init(mmc); | |
488 | if (ret) { | |
489 | debug("%s: mmc_init() failed (err=%d)\n", __func__, ret); | |
490 | return ret; | |
491 | } | |
a0269bb6 | 492 | |
c822c1a5 AT |
493 | ret = device_probe(dev); |
494 | if (ret) { | |
495 | debug("Probing %s failed (err=%d)\n", dev->name, ret); | |
496 | ||
497 | if (CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || | |
498 | CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || | |
499 | CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)) | |
500 | mmc_deinit(mmc); | |
501 | ||
502 | return ret; | |
503 | } | |
504 | ||
854f9a71 | 505 | return 0; |
a0269bb6 FA |
506 | } |
507 | ||
fceea992 MV |
508 | #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ |
509 | CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ | |
510 | CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) | |
511 | static int mmc_blk_remove(struct udevice *dev) | |
512 | { | |
513 | struct udevice *mmc_dev = dev_get_parent(dev); | |
514 | struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc_dev); | |
515 | struct mmc *mmc = upriv->mmc; | |
516 | ||
517 | return mmc_deinit(mmc); | |
518 | } | |
519 | #endif | |
520 | ||
eede897e SG |
521 | static const struct blk_ops mmc_blk_ops = { |
522 | .read = mmc_bread, | |
d6400c3f | 523 | #if CONFIG_IS_ENABLED(MMC_WRITE) |
eede897e | 524 | .write = mmc_bwrite, |
561e624c | 525 | .erase = mmc_berase, |
eede897e SG |
526 | #endif |
527 | .select_hwpart = mmc_select_hwpart, | |
528 | }; | |
529 | ||
530 | U_BOOT_DRIVER(mmc_blk) = { | |
531 | .name = "mmc_blk", | |
532 | .id = UCLASS_BLK, | |
533 | .ops = &mmc_blk_ops, | |
a0269bb6 | 534 | .probe = mmc_blk_probe, |
fceea992 MV |
535 | #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ |
536 | CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ | |
537 | CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) | |
538 | .remove = mmc_blk_remove, | |
539 | .flags = DM_FLAG_OS_PREPARE, | |
540 | #endif | |
eede897e | 541 | }; |
8ef761ed SG |
542 | #endif /* CONFIG_BLK */ |
543 | ||
e7ecf7cb SG |
544 | |
545 | UCLASS_DRIVER(mmc) = { | |
546 | .id = UCLASS_MMC, | |
547 | .name = "mmc", | |
548 | .flags = DM_UC_FLAG_SEQ_ALIAS, | |
41575d8e | 549 | .per_device_auto = sizeof(struct mmc_uclass_priv), |
e7ecf7cb | 550 | }; |