xref: /rk3399_ARM-atf/drivers/mmc/mmc.c (revision 7d6394297dca05165f52232e74c31da85c1c816c)
1 /*
2  * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /* Define a simple and generic interface to access eMMC and SD-card devices. */
8 
9 #include <arch_helpers.h>
10 #include <assert.h>
11 #include <debug.h>
12 #include <delay_timer.h>
13 #include <errno.h>
14 #include <mmc.h>
15 #include <stdbool.h>
16 #include <string.h>
17 #include <utils.h>
18 
19 #define MMC_DEFAULT_MAX_RETRIES		5
20 #define SEND_OP_COND_MAX_RETRIES	100
21 
22 #define MULT_BY_512K_SHIFT		19
23 
24 static const struct mmc_ops *ops;
25 static unsigned int mmc_ocr_value;
26 static struct mmc_csd_emmc mmc_csd;
27 static unsigned char mmc_ext_csd[512] __aligned(16);
28 static unsigned int mmc_flags;
29 static struct mmc_device_info *mmc_dev_info;
30 static unsigned int rca;
31 
32 static const unsigned char tran_speed_base[16] = {
33 	0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80
34 };
35 
36 static const unsigned char sd_tran_speed_base[16] = {
37 	0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80
38 };
39 
40 static bool is_cmd23_enabled(void)
41 {
42 	return ((mmc_flags & MMC_FLAG_CMD23) != 0U);
43 }
44 
45 static int mmc_send_cmd(unsigned int idx, unsigned int arg,
46 			unsigned int r_type, unsigned int *r_data)
47 {
48 	struct mmc_cmd cmd;
49 	int ret;
50 
51 	zeromem(&cmd, sizeof(struct mmc_cmd));
52 
53 	cmd.cmd_idx = idx;
54 	cmd.cmd_arg = arg;
55 	cmd.resp_type = r_type;
56 
57 	ret = ops->send_cmd(&cmd);
58 
59 	if ((ret == 0) && (r_data != NULL)) {
60 		int i;
61 
62 		for (i = 0; i < 4; i++) {
63 			*r_data = cmd.resp_data[i];
64 			r_data++;
65 		}
66 	}
67 
68 	if (ret != 0) {
69 		VERBOSE("Send command %u error: %d\n", idx, ret);
70 	}
71 
72 	return ret;
73 }
74 
75 static int mmc_device_state(void)
76 {
77 	int retries = MMC_DEFAULT_MAX_RETRIES;
78 	unsigned int resp_data[4];
79 
80 	do {
81 		int ret;
82 
83 		if (retries == 0) {
84 			ERROR("CMD13 failed after %d retries\n",
85 			      MMC_DEFAULT_MAX_RETRIES);
86 			return -EIO;
87 		}
88 
89 		ret = mmc_send_cmd(MMC_CMD(13), rca << RCA_SHIFT_OFFSET,
90 				   MMC_RESPONSE_R1, &resp_data[0]);
91 		if (ret != 0) {
92 			return ret;
93 		}
94 
95 		if ((resp_data[0] & STATUS_SWITCH_ERROR) != 0U) {
96 			return -EIO;
97 		}
98 
99 		retries--;
100 	} while ((resp_data[0] & STATUS_READY_FOR_DATA) == 0U);
101 
102 	return MMC_GET_STATE(resp_data[0]);
103 }
104 
105 static int mmc_set_ext_csd(unsigned int ext_cmd, unsigned int value)
106 {
107 	int ret;
108 
109 	ret = mmc_send_cmd(MMC_CMD(6),
110 			   EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) |
111 			   EXTCSD_VALUE(value) | EXTCSD_CMD_SET_NORMAL,
112 			   MMC_RESPONSE_R1B, NULL);
113 	if (ret != 0) {
114 		return ret;
115 	}
116 
117 	do {
118 		ret = mmc_device_state();
119 		if (ret < 0) {
120 			return ret;
121 		}
122 	} while (ret == MMC_STATE_PRG);
123 
124 	return 0;
125 }
126 
127 static int mmc_sd_switch(unsigned int bus_width)
128 {
129 	int ret;
130 	int retries = MMC_DEFAULT_MAX_RETRIES;
131 	unsigned int scr[2] = { 0 };
132 	unsigned int bus_width_arg = 0;
133 
134 	ret = ops->prepare(0, (uintptr_t)&scr, sizeof(scr));
135 	if (ret != 0) {
136 		return ret;
137 	}
138 
139 	/* CMD55: Application Specific Command */
140 	ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET,
141 			   MMC_RESPONSE_R5, NULL);
142 	if (ret != 0) {
143 		return ret;
144 	}
145 
146 	/* ACMD51: SEND_SCR */
147 	do {
148 		ret = mmc_send_cmd(MMC_ACMD(51), 0, MMC_RESPONSE_R1, NULL);
149 		if ((ret != 0) && (retries == 0)) {
150 			ERROR("ACMD51 failed after %d retries (ret=%d)\n",
151 			      MMC_DEFAULT_MAX_RETRIES, ret);
152 			return ret;
153 		}
154 
155 		retries--;
156 	} while (ret != 0);
157 
158 	ret = ops->read(0, (uintptr_t)&scr, sizeof(scr));
159 	if (ret != 0) {
160 		return ret;
161 	}
162 
163 	if (((scr[0] & SD_SCR_BUS_WIDTH_4) != 0U) &&
164 	    (bus_width == MMC_BUS_WIDTH_4)) {
165 		bus_width_arg = 2;
166 	}
167 
168 	/* CMD55: Application Specific Command */
169 	ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET,
170 			   MMC_RESPONSE_R5, NULL);
171 	if (ret != 0) {
172 		return ret;
173 	}
174 
175 	/* ACMD6: SET_BUS_WIDTH */
176 	ret = mmc_send_cmd(MMC_ACMD(6), bus_width_arg, MMC_RESPONSE_R1, NULL);
177 	if (ret != 0) {
178 		return ret;
179 	}
180 
181 	do {
182 		ret = mmc_device_state();
183 		if (ret < 0) {
184 			return ret;
185 		}
186 	} while (ret == MMC_STATE_PRG);
187 
188 	return 0;
189 }
190 
191 static int mmc_set_ios(unsigned int clk, unsigned int bus_width)
192 {
193 	int ret;
194 	unsigned int width = bus_width;
195 
196 	if (mmc_dev_info->mmc_dev_type != MMC_IS_EMMC) {
197 		if (width == MMC_BUS_WIDTH_8) {
198 			WARN("Wrong bus config for SD-card, force to 4\n");
199 			width = MMC_BUS_WIDTH_4;
200 		}
201 		ret = mmc_sd_switch(width);
202 		if (ret != 0) {
203 			return ret;
204 		}
205 	} else if (mmc_csd.spec_vers == 4U) {
206 		ret = mmc_set_ext_csd(CMD_EXTCSD_BUS_WIDTH,
207 				      (unsigned int)width);
208 		if (ret != 0) {
209 			return ret;
210 		}
211 	} else {
212 		VERBOSE("Wrong MMC type or spec version\n");
213 	}
214 
215 	return ops->set_ios(clk, width);
216 }
217 
218 static int mmc_fill_device_info(void)
219 {
220 	unsigned long long c_size;
221 	unsigned int speed_idx;
222 	unsigned int nb_blocks;
223 	unsigned int freq_unit;
224 	int ret = 0;
225 	struct mmc_csd_sd_v2 *csd_sd_v2;
226 
227 	switch (mmc_dev_info->mmc_dev_type) {
228 	case MMC_IS_EMMC:
229 		mmc_dev_info->block_size = MMC_BLOCK_SIZE;
230 
231 		ret = ops->prepare(0, (uintptr_t)&mmc_ext_csd,
232 				   sizeof(mmc_ext_csd));
233 		if (ret != 0) {
234 			return ret;
235 		}
236 
237 		/* MMC CMD8: SEND_EXT_CSD */
238 		ret = mmc_send_cmd(MMC_CMD(8), 0, MMC_RESPONSE_R1, NULL);
239 		if (ret != 0) {
240 			return ret;
241 		}
242 
243 		ret = ops->read(0, (uintptr_t)&mmc_ext_csd,
244 				sizeof(mmc_ext_csd));
245 		if (ret != 0) {
246 			return ret;
247 		}
248 
249 		do {
250 			ret = mmc_device_state();
251 			if (ret < 0) {
252 				return ret;
253 			}
254 		} while (ret != MMC_STATE_TRAN);
255 
256 		nb_blocks = (mmc_ext_csd[CMD_EXTCSD_SEC_CNT] << 0) |
257 			    (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 1] << 8) |
258 			    (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 2] << 16) |
259 			    (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 3] << 24);
260 
261 		mmc_dev_info->device_size = (unsigned long long)nb_blocks *
262 			mmc_dev_info->block_size;
263 
264 		break;
265 
266 	case MMC_IS_SD:
267 		/*
268 		 * Use the same mmc_csd struct, as required fields here
269 		 * (READ_BL_LEN, C_SIZE, CSIZE_MULT) are common with eMMC.
270 		 */
271 		mmc_dev_info->block_size = BIT_32(mmc_csd.read_bl_len);
272 
273 		c_size = ((unsigned long long)mmc_csd.c_size_high << 2U) |
274 			 (unsigned long long)mmc_csd.c_size_low;
275 		assert(c_size != 0xFFFU);
276 
277 		mmc_dev_info->device_size = (c_size + 1U) *
278 					    BIT_64(mmc_csd.c_size_mult + 2U) *
279 					    mmc_dev_info->block_size;
280 
281 		break;
282 
283 	case MMC_IS_SD_HC:
284 		assert(mmc_csd.csd_structure == 1U);
285 
286 		mmc_dev_info->block_size = MMC_BLOCK_SIZE;
287 
288 		/* Need to use mmc_csd_sd_v2 struct */
289 		csd_sd_v2 = (struct mmc_csd_sd_v2 *)&mmc_csd;
290 		c_size = ((unsigned long long)csd_sd_v2->c_size_high << 16) |
291 			 (unsigned long long)csd_sd_v2->c_size_low;
292 
293 		mmc_dev_info->device_size = (c_size + 1U) << MULT_BY_512K_SHIFT;
294 
295 		break;
296 
297 	default:
298 		ret = -EINVAL;
299 		break;
300 	}
301 
302 	if (ret != 0) {
303 		return ret;
304 	}
305 
306 	speed_idx = (mmc_csd.tran_speed & CSD_TRAN_SPEED_MULT_MASK) >>
307 			 CSD_TRAN_SPEED_MULT_SHIFT;
308 
309 	assert(speed_idx > 0U);
310 
311 	if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
312 		mmc_dev_info->max_bus_freq = tran_speed_base[speed_idx];
313 	} else {
314 		mmc_dev_info->max_bus_freq = sd_tran_speed_base[speed_idx];
315 	}
316 
317 	freq_unit = mmc_csd.tran_speed & CSD_TRAN_SPEED_UNIT_MASK;
318 	while (freq_unit != 0U) {
319 		mmc_dev_info->max_bus_freq *= 10U;
320 		--freq_unit;
321 	}
322 
323 	mmc_dev_info->max_bus_freq *= 10000U;
324 
325 	return 0;
326 }
327 
328 static int sd_send_op_cond(void)
329 {
330 	int n;
331 	unsigned int resp_data[4];
332 
333 	for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
334 		int ret;
335 
336 		/* CMD55: Application Specific Command */
337 		ret = mmc_send_cmd(MMC_CMD(55), 0, MMC_RESPONSE_R1, NULL);
338 		if (ret != 0) {
339 			return ret;
340 		}
341 
342 		/* ACMD41: SD_SEND_OP_COND */
343 		ret = mmc_send_cmd(MMC_ACMD(41), OCR_HCS, MMC_RESPONSE_R3,
344 				   &resp_data[0]);
345 		if (ret != 0) {
346 			return ret;
347 		}
348 
349 		if ((resp_data[0] & OCR_POWERUP) != 0U) {
350 			mmc_ocr_value = resp_data[0];
351 
352 			if ((mmc_ocr_value & OCR_HCS) != 0U) {
353 				mmc_dev_info->mmc_dev_type = MMC_IS_SD_HC;
354 			} else {
355 				mmc_dev_info->mmc_dev_type = MMC_IS_SD;
356 			}
357 
358 			return 0;
359 		}
360 
361 		mdelay(1);
362 	}
363 
364 	ERROR("ACMD41 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
365 
366 	return -EIO;
367 }
368 
369 static int mmc_reset_to_idle(void)
370 {
371 	int ret;
372 
373 	/* CMD0: reset to IDLE */
374 	ret = mmc_send_cmd(MMC_CMD(0), 0, 0, NULL);
375 	if (ret != 0) {
376 		return ret;
377 	}
378 
379 	mdelay(2);
380 
381 	return 0;
382 }
383 
384 static int mmc_send_op_cond(void)
385 {
386 	int ret, n;
387 	unsigned int resp_data[4];
388 
389 	ret = mmc_reset_to_idle();
390 	if (ret != 0) {
391 		return ret;
392 	};
393 
394 	for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
395 		ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE |
396 				   OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7,
397 				   MMC_RESPONSE_R3, &resp_data[0]);
398 		if (ret != 0) {
399 			return ret;
400 		}
401 
402 		if ((resp_data[0] & OCR_POWERUP) != 0U) {
403 			mmc_ocr_value = resp_data[0];
404 			return 0;
405 		}
406 
407 		mdelay(10);
408 	}
409 
410 	ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
411 
412 	return -EIO;
413 }
414 
415 static int mmc_enumerate(unsigned int clk, unsigned int bus_width)
416 {
417 	int ret;
418 	unsigned int resp_data[4];
419 
420 	ops->init();
421 
422 	ret = mmc_reset_to_idle();
423 	if (ret != 0) {
424 		return ret;
425 	};
426 
427 	if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
428 		ret = mmc_send_op_cond();
429 	} else {
430 		/* CMD8: Send Interface Condition Command */
431 		ret = mmc_send_cmd(MMC_CMD(8), VHS_2_7_3_6_V | CMD8_CHECK_PATTERN,
432 				   MMC_RESPONSE_R5, &resp_data[0]);
433 
434 		if ((ret == 0) && ((resp_data[0] & 0xffU) == CMD8_CHECK_PATTERN)) {
435 			ret = sd_send_op_cond();
436 		}
437 	}
438 	if (ret != 0) {
439 		return ret;
440 	}
441 
442 	/* CMD2: Card Identification */
443 	ret = mmc_send_cmd(MMC_CMD(2), 0, MMC_RESPONSE_R2, NULL);
444 	if (ret != 0) {
445 		return ret;
446 	}
447 
448 	/* CMD3: Set Relative Address */
449 	if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
450 		rca = MMC_FIX_RCA;
451 		ret = mmc_send_cmd(MMC_CMD(3), rca << RCA_SHIFT_OFFSET,
452 				   MMC_RESPONSE_R1, NULL);
453 		if (ret != 0) {
454 			return ret;
455 		}
456 	} else {
457 		ret = mmc_send_cmd(MMC_CMD(3), 0,
458 				   MMC_RESPONSE_R6, &resp_data[0]);
459 		if (ret != 0) {
460 			return ret;
461 		}
462 
463 		rca = (resp_data[0] & 0xFFFF0000U) >> 16;
464 	}
465 
466 	/* CMD9: CSD Register */
467 	ret = mmc_send_cmd(MMC_CMD(9), rca << RCA_SHIFT_OFFSET,
468 			   MMC_RESPONSE_R2, &resp_data[0]);
469 	if (ret != 0) {
470 		return ret;
471 	}
472 
473 	memcpy(&mmc_csd, &resp_data, sizeof(resp_data));
474 
475 	/* CMD7: Select Card */
476 	ret = mmc_send_cmd(MMC_CMD(7), rca << RCA_SHIFT_OFFSET,
477 			   MMC_RESPONSE_R1, NULL);
478 	if (ret != 0) {
479 		return ret;
480 	}
481 
482 	do {
483 		ret = mmc_device_state();
484 		if (ret < 0) {
485 			return ret;
486 		}
487 	} while (ret != MMC_STATE_TRAN);
488 
489 	ret = mmc_set_ios(clk, bus_width);
490 	if (ret != 0) {
491 		return ret;
492 	}
493 
494 	return mmc_fill_device_info();
495 }
496 
497 size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size)
498 {
499 	int ret;
500 	unsigned int cmd_idx, cmd_arg;
501 
502 	assert((ops != NULL) &&
503 	       (ops->read != NULL) &&
504 	       (size != 0U) &&
505 	       ((size & MMC_BLOCK_MASK) == 0U));
506 
507 	ret = ops->prepare(lba, buf, size);
508 	if (ret != 0) {
509 		return 0;
510 	}
511 
512 	if (is_cmd23_enabled()) {
513 		/* Set block count */
514 		ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
515 				   MMC_RESPONSE_R1, NULL);
516 		if (ret != 0) {
517 			return 0;
518 		}
519 
520 		cmd_idx = MMC_CMD(18);
521 	} else {
522 		if (size > MMC_BLOCK_SIZE) {
523 			cmd_idx = MMC_CMD(18);
524 		} else {
525 			cmd_idx = MMC_CMD(17);
526 		}
527 	}
528 
529 	if (((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) &&
530 	    (mmc_dev_info->mmc_dev_type != MMC_IS_SD_HC)) {
531 		cmd_arg = lba * MMC_BLOCK_SIZE;
532 	} else {
533 		cmd_arg = lba;
534 	}
535 
536 	ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
537 	if (ret != 0) {
538 		return 0;
539 	}
540 
541 	ret = ops->read(lba, buf, size);
542 	if (ret != 0) {
543 		return 0;
544 	}
545 
546 	/* Wait buffer empty */
547 	do {
548 		ret = mmc_device_state();
549 		if (ret < 0) {
550 			return 0;
551 		}
552 	} while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_DATA));
553 
554 	if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
555 		ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
556 		if (ret != 0) {
557 			return 0;
558 		}
559 	}
560 
561 	return size;
562 }
563 
564 size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size)
565 {
566 	int ret;
567 	unsigned int cmd_idx, cmd_arg;
568 
569 	assert((ops != NULL) &&
570 	       (ops->write != NULL) &&
571 	       (size != 0U) &&
572 	       ((buf & MMC_BLOCK_MASK) == 0U) &&
573 	       ((size & MMC_BLOCK_MASK) == 0U));
574 
575 	ret = ops->prepare(lba, buf, size);
576 	if (ret != 0) {
577 		return 0;
578 	}
579 
580 	if (is_cmd23_enabled()) {
581 		/* Set block count */
582 		ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
583 				   MMC_RESPONSE_R1, NULL);
584 		if (ret != 0) {
585 			return 0;
586 		}
587 
588 		cmd_idx = MMC_CMD(25);
589 	} else {
590 		if (size > MMC_BLOCK_SIZE) {
591 			cmd_idx = MMC_CMD(25);
592 		} else {
593 			cmd_idx = MMC_CMD(24);
594 		}
595 	}
596 
597 	if ((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) {
598 		cmd_arg = lba * MMC_BLOCK_SIZE;
599 	} else {
600 		cmd_arg = lba;
601 	}
602 
603 	ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
604 	if (ret != 0) {
605 		return 0;
606 	}
607 
608 	ret = ops->write(lba, buf, size);
609 	if (ret != 0) {
610 		return 0;
611 	}
612 
613 	/* Wait buffer empty */
614 	do {
615 		ret = mmc_device_state();
616 		if (ret < 0) {
617 			return 0;
618 		}
619 	} while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_RCV));
620 
621 	if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
622 		ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
623 		if (ret != 0) {
624 			return 0;
625 		}
626 	}
627 
628 	return size;
629 }
630 
631 size_t mmc_erase_blocks(int lba, size_t size)
632 {
633 	int ret;
634 
635 	assert(ops != NULL);
636 	assert((size != 0U) && ((size & MMC_BLOCK_MASK) == 0U));
637 
638 	ret = mmc_send_cmd(MMC_CMD(35), lba, MMC_RESPONSE_R1, NULL);
639 	if (ret != 0) {
640 		return 0;
641 	}
642 
643 	ret = mmc_send_cmd(MMC_CMD(36), lba + (size / MMC_BLOCK_SIZE) - 1U,
644 			   MMC_RESPONSE_R1, NULL);
645 	if (ret != 0) {
646 		return 0;
647 	}
648 
649 	ret = mmc_send_cmd(MMC_CMD(38), lba, MMC_RESPONSE_R1B, NULL);
650 	if (ret != 0) {
651 		return 0;
652 	}
653 
654 	do {
655 		ret = mmc_device_state();
656 		if (ret < 0) {
657 			return 0;
658 		}
659 	} while (ret != MMC_STATE_TRAN);
660 
661 	return size;
662 }
663 
664 static inline void mmc_rpmb_enable(void)
665 {
666 	mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
667 			PART_CFG_BOOT_PARTITION1_ENABLE |
668 			PART_CFG_PARTITION1_ACCESS);
669 }
670 
671 static inline void mmc_rpmb_disable(void)
672 {
673 	mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
674 			PART_CFG_BOOT_PARTITION1_ENABLE);
675 }
676 
677 size_t mmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size)
678 {
679 	size_t size_read;
680 
681 	mmc_rpmb_enable();
682 	size_read = mmc_read_blocks(lba, buf, size);
683 	mmc_rpmb_disable();
684 
685 	return size_read;
686 }
687 
688 size_t mmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size)
689 {
690 	size_t size_written;
691 
692 	mmc_rpmb_enable();
693 	size_written = mmc_write_blocks(lba, buf, size);
694 	mmc_rpmb_disable();
695 
696 	return size_written;
697 }
698 
699 size_t mmc_rpmb_erase_blocks(int lba, size_t size)
700 {
701 	size_t size_erased;
702 
703 	mmc_rpmb_enable();
704 	size_erased = mmc_erase_blocks(lba, size);
705 	mmc_rpmb_disable();
706 
707 	return size_erased;
708 }
709 
710 int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk,
711 	     unsigned int width, unsigned int flags,
712 	     struct mmc_device_info *device_info)
713 {
714 	assert((ops_ptr != NULL) &&
715 	       (ops_ptr->init != NULL) &&
716 	       (ops_ptr->send_cmd != NULL) &&
717 	       (ops_ptr->set_ios != NULL) &&
718 	       (ops_ptr->prepare != NULL) &&
719 	       (ops_ptr->read != NULL) &&
720 	       (ops_ptr->write != NULL) &&
721 	       (device_info != NULL) &&
722 	       (clk != 0) &&
723 	       ((width == MMC_BUS_WIDTH_1) ||
724 		(width == MMC_BUS_WIDTH_4) ||
725 		(width == MMC_BUS_WIDTH_8) ||
726 		(width == MMC_BUS_WIDTH_DDR_4) ||
727 		(width == MMC_BUS_WIDTH_DDR_8)));
728 
729 	ops = ops_ptr;
730 	mmc_flags = flags;
731 	mmc_dev_info = device_info;
732 
733 	return mmc_enumerate(clk, width);
734 }
735