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