1 /* 2 * (C) Copyright 2003 3 * Kyle Harris, kharris@nexus-tech.net 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <command.h> 10 #include <console.h> 11 #include <mmc.h> 12 13 static int curr_device = -1; 14 15 static void print_mmcinfo(struct mmc *mmc) 16 { 17 int i; 18 19 printf("Device: %s\n", mmc->cfg->name); 20 printf("Manufacturer ID: %x\n", mmc->cid[0] >> 24); 21 printf("OEM: %x\n", (mmc->cid[0] >> 8) & 0xffff); 22 printf("Name: %c%c%c%c%c \n", mmc->cid[0] & 0xff, 23 (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 24 (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff); 25 26 printf("Bus Speed: %d\n", mmc->clock); 27 #if CONFIG_IS_ENABLED(MMC_VERBOSE) 28 printf("Mode : %s\n", mmc_mode_name(mmc->selected_mode)); 29 mmc_dump_capabilities("card capabilities", mmc->card_caps); 30 mmc_dump_capabilities("host capabilities", mmc->host_caps); 31 #endif 32 printf("Rd Block Len: %d\n", mmc->read_bl_len); 33 34 printf("%s version %d.%d", IS_SD(mmc) ? "SD" : "MMC", 35 EXTRACT_SDMMC_MAJOR_VERSION(mmc->version), 36 EXTRACT_SDMMC_MINOR_VERSION(mmc->version)); 37 if (EXTRACT_SDMMC_CHANGE_VERSION(mmc->version) != 0) 38 printf(".%d", EXTRACT_SDMMC_CHANGE_VERSION(mmc->version)); 39 printf("\n"); 40 41 printf("High Capacity: %s\n", mmc->high_capacity ? "Yes" : "No"); 42 puts("Capacity: "); 43 print_size(mmc->capacity, "\n"); 44 45 printf("Bus Width: %d-bit%s\n", mmc->bus_width, 46 mmc->ddr_mode ? " DDR" : ""); 47 48 puts("Erase Group Size: "); 49 print_size(((u64)mmc->erase_grp_size) << 9, "\n"); 50 51 if (!IS_SD(mmc) && mmc->version >= MMC_VERSION_4_41) { 52 bool has_enh = (mmc->part_support & ENHNCD_SUPPORT) != 0; 53 bool usr_enh = has_enh && (mmc->part_attr & EXT_CSD_ENH_USR); 54 55 puts("HC WP Group Size: "); 56 print_size(((u64)mmc->hc_wp_grp_size) << 9, "\n"); 57 58 puts("User Capacity: "); 59 print_size(mmc->capacity_user, usr_enh ? " ENH" : ""); 60 if (mmc->wr_rel_set & EXT_CSD_WR_DATA_REL_USR) 61 puts(" WRREL\n"); 62 else 63 putc('\n'); 64 if (usr_enh) { 65 puts("User Enhanced Start: "); 66 print_size(mmc->enh_user_start, "\n"); 67 puts("User Enhanced Size: "); 68 print_size(mmc->enh_user_size, "\n"); 69 } 70 puts("Boot Capacity: "); 71 print_size(mmc->capacity_boot, has_enh ? " ENH\n" : "\n"); 72 puts("RPMB Capacity: "); 73 print_size(mmc->capacity_rpmb, has_enh ? " ENH\n" : "\n"); 74 75 for (i = 0; i < ARRAY_SIZE(mmc->capacity_gp); i++) { 76 bool is_enh = has_enh && 77 (mmc->part_attr & EXT_CSD_ENH_GP(i)); 78 if (mmc->capacity_gp[i]) { 79 printf("GP%i Capacity: ", i+1); 80 print_size(mmc->capacity_gp[i], 81 is_enh ? " ENH" : ""); 82 if (mmc->wr_rel_set & EXT_CSD_WR_DATA_REL_GP(i)) 83 puts(" WRREL\n"); 84 else 85 putc('\n'); 86 } 87 } 88 } 89 } 90 static struct mmc *init_mmc_device(int dev, bool force_init) 91 { 92 struct mmc *mmc; 93 mmc = find_mmc_device(dev); 94 if (!mmc) { 95 printf("no mmc device at slot %x\n", dev); 96 return NULL; 97 } 98 99 if (force_init) 100 mmc->has_init = 0; 101 if (mmc_init(mmc)) 102 return NULL; 103 return mmc; 104 } 105 static int do_mmcinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 106 { 107 struct mmc *mmc; 108 109 if (curr_device < 0) { 110 if (get_mmc_num() > 0) 111 curr_device = 0; 112 else { 113 puts("No MMC device available\n"); 114 return 1; 115 } 116 } 117 118 mmc = init_mmc_device(curr_device, false); 119 if (!mmc) 120 return CMD_RET_FAILURE; 121 122 print_mmcinfo(mmc); 123 return CMD_RET_SUCCESS; 124 } 125 126 #ifdef CONFIG_SUPPORT_EMMC_RPMB 127 static int confirm_key_prog(void) 128 { 129 puts("Warning: Programming authentication key can be done only once !\n" 130 " Use this command only if you are sure of what you are doing,\n" 131 "Really perform the key programming? <y/N> "); 132 if (confirm_yesno()) 133 return 1; 134 135 puts("Authentication key programming aborted\n"); 136 return 0; 137 } 138 static int do_mmcrpmb_key(cmd_tbl_t *cmdtp, int flag, 139 int argc, char * const argv[]) 140 { 141 void *key_addr; 142 struct mmc *mmc = find_mmc_device(curr_device); 143 144 if (argc != 2) 145 return CMD_RET_USAGE; 146 147 key_addr = (void *)simple_strtoul(argv[1], NULL, 16); 148 if (!confirm_key_prog()) 149 return CMD_RET_FAILURE; 150 if (mmc_rpmb_set_key(mmc, key_addr)) { 151 printf("ERROR - Key already programmed ?\n"); 152 return CMD_RET_FAILURE; 153 } 154 return CMD_RET_SUCCESS; 155 } 156 static int do_mmcrpmb_read(cmd_tbl_t *cmdtp, int flag, 157 int argc, char * const argv[]) 158 { 159 u16 blk, cnt; 160 void *addr; 161 int n; 162 void *key_addr = NULL; 163 struct mmc *mmc = find_mmc_device(curr_device); 164 165 if (argc < 4) 166 return CMD_RET_USAGE; 167 168 addr = (void *)simple_strtoul(argv[1], NULL, 16); 169 blk = simple_strtoul(argv[2], NULL, 16); 170 cnt = simple_strtoul(argv[3], NULL, 16); 171 172 if (argc == 5) 173 key_addr = (void *)simple_strtoul(argv[4], NULL, 16); 174 175 printf("\nMMC RPMB read: dev # %d, block # %d, count %d ... ", 176 curr_device, blk, cnt); 177 n = mmc_rpmb_read(mmc, addr, blk, cnt, key_addr); 178 179 printf("%d RPMB blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR"); 180 if (n != cnt) 181 return CMD_RET_FAILURE; 182 return CMD_RET_SUCCESS; 183 } 184 static int do_mmcrpmb_write(cmd_tbl_t *cmdtp, int flag, 185 int argc, char * const argv[]) 186 { 187 u16 blk, cnt; 188 void *addr; 189 int n; 190 void *key_addr; 191 struct mmc *mmc = find_mmc_device(curr_device); 192 193 if (argc != 5) 194 return CMD_RET_USAGE; 195 196 addr = (void *)simple_strtoul(argv[1], NULL, 16); 197 blk = simple_strtoul(argv[2], NULL, 16); 198 cnt = simple_strtoul(argv[3], NULL, 16); 199 key_addr = (void *)simple_strtoul(argv[4], NULL, 16); 200 201 printf("\nMMC RPMB write: dev # %d, block # %d, count %d ... ", 202 curr_device, blk, cnt); 203 n = mmc_rpmb_write(mmc, addr, blk, cnt, key_addr); 204 205 printf("%d RPMB blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR"); 206 if (n != cnt) 207 return CMD_RET_FAILURE; 208 return CMD_RET_SUCCESS; 209 } 210 static int do_mmcrpmb_counter(cmd_tbl_t *cmdtp, int flag, 211 int argc, char * const argv[]) 212 { 213 unsigned long counter; 214 struct mmc *mmc = find_mmc_device(curr_device); 215 216 if (mmc_rpmb_get_counter(mmc, &counter)) 217 return CMD_RET_FAILURE; 218 printf("RPMB Write counter= %lx\n", counter); 219 return CMD_RET_SUCCESS; 220 } 221 222 static cmd_tbl_t cmd_rpmb[] = { 223 U_BOOT_CMD_MKENT(key, 2, 0, do_mmcrpmb_key, "", ""), 224 U_BOOT_CMD_MKENT(read, 5, 1, do_mmcrpmb_read, "", ""), 225 U_BOOT_CMD_MKENT(write, 5, 0, do_mmcrpmb_write, "", ""), 226 U_BOOT_CMD_MKENT(counter, 1, 1, do_mmcrpmb_counter, "", ""), 227 }; 228 229 static int do_mmcrpmb(cmd_tbl_t *cmdtp, int flag, 230 int argc, char * const argv[]) 231 { 232 cmd_tbl_t *cp; 233 struct mmc *mmc; 234 char original_part; 235 int ret; 236 237 cp = find_cmd_tbl(argv[1], cmd_rpmb, ARRAY_SIZE(cmd_rpmb)); 238 239 /* Drop the rpmb subcommand */ 240 argc--; 241 argv++; 242 243 if (cp == NULL || argc > cp->maxargs) 244 return CMD_RET_USAGE; 245 if (flag == CMD_FLAG_REPEAT && !cp->repeatable) 246 return CMD_RET_SUCCESS; 247 248 mmc = init_mmc_device(curr_device, false); 249 if (!mmc) 250 return CMD_RET_FAILURE; 251 252 if (!(mmc->version & MMC_VERSION_MMC)) { 253 printf("It is not a EMMC device\n"); 254 return CMD_RET_FAILURE; 255 } 256 if (mmc->version < MMC_VERSION_4_41) { 257 printf("RPMB not supported before version 4.41\n"); 258 return CMD_RET_FAILURE; 259 } 260 /* Switch to the RPMB partition */ 261 #ifndef CONFIG_BLK 262 original_part = mmc->block_dev.hwpart; 263 #else 264 original_part = mmc_get_blk_desc(mmc)->hwpart; 265 #endif 266 if (blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, MMC_PART_RPMB) != 267 0) 268 return CMD_RET_FAILURE; 269 ret = cp->cmd(cmdtp, flag, argc, argv); 270 271 /* Return to original partition */ 272 if (blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, original_part) != 273 0) 274 return CMD_RET_FAILURE; 275 return ret; 276 } 277 #endif 278 279 static int do_mmc_read(cmd_tbl_t *cmdtp, int flag, 280 int argc, char * const argv[]) 281 { 282 struct mmc *mmc; 283 u32 blk, cnt, n; 284 void *addr; 285 286 if (argc != 4) 287 return CMD_RET_USAGE; 288 289 addr = (void *)simple_strtoul(argv[1], NULL, 16); 290 blk = simple_strtoul(argv[2], NULL, 16); 291 cnt = simple_strtoul(argv[3], NULL, 16); 292 293 mmc = init_mmc_device(curr_device, false); 294 if (!mmc) 295 return CMD_RET_FAILURE; 296 297 printf("\nMMC read: dev # %d, block # %d, count %d ... ", 298 curr_device, blk, cnt); 299 300 n = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr); 301 printf("%d blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR"); 302 303 return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE; 304 } 305 static int do_mmc_write(cmd_tbl_t *cmdtp, int flag, 306 int argc, char * const argv[]) 307 { 308 struct mmc *mmc; 309 u32 blk, cnt, n; 310 void *addr; 311 312 if (argc != 4) 313 return CMD_RET_USAGE; 314 315 addr = (void *)simple_strtoul(argv[1], NULL, 16); 316 blk = simple_strtoul(argv[2], NULL, 16); 317 cnt = simple_strtoul(argv[3], NULL, 16); 318 319 mmc = init_mmc_device(curr_device, false); 320 if (!mmc) 321 return CMD_RET_FAILURE; 322 323 printf("\nMMC write: dev # %d, block # %d, count %d ... ", 324 curr_device, blk, cnt); 325 326 if (mmc_getwp(mmc) == 1) { 327 printf("Error: card is write protected!\n"); 328 return CMD_RET_FAILURE; 329 } 330 n = blk_dwrite(mmc_get_blk_desc(mmc), blk, cnt, addr); 331 printf("%d blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR"); 332 333 return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE; 334 } 335 static int do_mmc_erase(cmd_tbl_t *cmdtp, int flag, 336 int argc, char * const argv[]) 337 { 338 struct mmc *mmc; 339 u32 blk, cnt, n; 340 341 if (argc != 3) 342 return CMD_RET_USAGE; 343 344 blk = simple_strtoul(argv[1], NULL, 16); 345 cnt = simple_strtoul(argv[2], NULL, 16); 346 347 mmc = init_mmc_device(curr_device, false); 348 if (!mmc) 349 return CMD_RET_FAILURE; 350 351 printf("\nMMC erase: dev # %d, block # %d, count %d ... ", 352 curr_device, blk, cnt); 353 354 if (mmc_getwp(mmc) == 1) { 355 printf("Error: card is write protected!\n"); 356 return CMD_RET_FAILURE; 357 } 358 n = blk_derase(mmc_get_blk_desc(mmc), blk, cnt); 359 printf("%d blocks erased: %s\n", n, (n == cnt) ? "OK" : "ERROR"); 360 361 return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE; 362 } 363 static int do_mmc_rescan(cmd_tbl_t *cmdtp, int flag, 364 int argc, char * const argv[]) 365 { 366 struct mmc *mmc; 367 368 mmc = init_mmc_device(curr_device, true); 369 if (!mmc) 370 return CMD_RET_FAILURE; 371 372 return CMD_RET_SUCCESS; 373 } 374 static int do_mmc_part(cmd_tbl_t *cmdtp, int flag, 375 int argc, char * const argv[]) 376 { 377 struct blk_desc *mmc_dev; 378 struct mmc *mmc; 379 380 mmc = init_mmc_device(curr_device, false); 381 if (!mmc) 382 return CMD_RET_FAILURE; 383 384 mmc_dev = blk_get_devnum_by_type(IF_TYPE_MMC, curr_device); 385 if (mmc_dev != NULL && mmc_dev->type != DEV_TYPE_UNKNOWN) { 386 part_print(mmc_dev); 387 return CMD_RET_SUCCESS; 388 } 389 390 puts("get mmc type error!\n"); 391 return CMD_RET_FAILURE; 392 } 393 static int do_mmc_dev(cmd_tbl_t *cmdtp, int flag, 394 int argc, char * const argv[]) 395 { 396 int dev, part = 0, ret; 397 struct mmc *mmc; 398 399 if (argc == 1) { 400 dev = curr_device; 401 } else if (argc == 2) { 402 dev = simple_strtoul(argv[1], NULL, 10); 403 } else if (argc == 3) { 404 dev = (int)simple_strtoul(argv[1], NULL, 10); 405 part = (int)simple_strtoul(argv[2], NULL, 10); 406 if (part > PART_ACCESS_MASK) { 407 printf("#part_num shouldn't be larger than %d\n", 408 PART_ACCESS_MASK); 409 return CMD_RET_FAILURE; 410 } 411 } else { 412 return CMD_RET_USAGE; 413 } 414 415 mmc = init_mmc_device(dev, true); 416 if (!mmc) 417 return CMD_RET_FAILURE; 418 419 ret = blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part); 420 printf("switch to partitions #%d, %s\n", 421 part, (!ret) ? "OK" : "ERROR"); 422 if (ret) 423 return 1; 424 425 curr_device = dev; 426 if (mmc->part_config == MMCPART_NOAVAILABLE) 427 printf("mmc%d is current device\n", curr_device); 428 else 429 printf("mmc%d(part %d) is current device\n", 430 curr_device, mmc_get_blk_desc(mmc)->hwpart); 431 432 return CMD_RET_SUCCESS; 433 } 434 static int do_mmc_list(cmd_tbl_t *cmdtp, int flag, 435 int argc, char * const argv[]) 436 { 437 print_mmc_devices('\n'); 438 return CMD_RET_SUCCESS; 439 } 440 441 #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) 442 static int parse_hwpart_user(struct mmc_hwpart_conf *pconf, 443 int argc, char * const argv[]) 444 { 445 int i = 0; 446 447 memset(&pconf->user, 0, sizeof(pconf->user)); 448 449 while (i < argc) { 450 if (!strcmp(argv[i], "enh")) { 451 if (i + 2 >= argc) 452 return -1; 453 pconf->user.enh_start = 454 simple_strtoul(argv[i+1], NULL, 10); 455 pconf->user.enh_size = 456 simple_strtoul(argv[i+2], NULL, 10); 457 i += 3; 458 } else if (!strcmp(argv[i], "wrrel")) { 459 if (i + 1 >= argc) 460 return -1; 461 pconf->user.wr_rel_change = 1; 462 if (!strcmp(argv[i+1], "on")) 463 pconf->user.wr_rel_set = 1; 464 else if (!strcmp(argv[i+1], "off")) 465 pconf->user.wr_rel_set = 0; 466 else 467 return -1; 468 i += 2; 469 } else { 470 break; 471 } 472 } 473 return i; 474 } 475 476 static int parse_hwpart_gp(struct mmc_hwpart_conf *pconf, int pidx, 477 int argc, char * const argv[]) 478 { 479 int i; 480 481 memset(&pconf->gp_part[pidx], 0, sizeof(pconf->gp_part[pidx])); 482 483 if (1 >= argc) 484 return -1; 485 pconf->gp_part[pidx].size = simple_strtoul(argv[0], NULL, 10); 486 487 i = 1; 488 while (i < argc) { 489 if (!strcmp(argv[i], "enh")) { 490 pconf->gp_part[pidx].enhanced = 1; 491 i += 1; 492 } else if (!strcmp(argv[i], "wrrel")) { 493 if (i + 1 >= argc) 494 return -1; 495 pconf->gp_part[pidx].wr_rel_change = 1; 496 if (!strcmp(argv[i+1], "on")) 497 pconf->gp_part[pidx].wr_rel_set = 1; 498 else if (!strcmp(argv[i+1], "off")) 499 pconf->gp_part[pidx].wr_rel_set = 0; 500 else 501 return -1; 502 i += 2; 503 } else { 504 break; 505 } 506 } 507 return i; 508 } 509 510 static int do_mmc_hwpartition(cmd_tbl_t *cmdtp, int flag, 511 int argc, char * const argv[]) 512 { 513 struct mmc *mmc; 514 struct mmc_hwpart_conf pconf = { }; 515 enum mmc_hwpart_conf_mode mode = MMC_HWPART_CONF_CHECK; 516 int i, r, pidx; 517 518 mmc = init_mmc_device(curr_device, false); 519 if (!mmc) 520 return CMD_RET_FAILURE; 521 522 if (argc < 1) 523 return CMD_RET_USAGE; 524 i = 1; 525 while (i < argc) { 526 if (!strcmp(argv[i], "user")) { 527 i++; 528 r = parse_hwpart_user(&pconf, argc-i, &argv[i]); 529 if (r < 0) 530 return CMD_RET_USAGE; 531 i += r; 532 } else if (!strncmp(argv[i], "gp", 2) && 533 strlen(argv[i]) == 3 && 534 argv[i][2] >= '1' && argv[i][2] <= '4') { 535 pidx = argv[i][2] - '1'; 536 i++; 537 r = parse_hwpart_gp(&pconf, pidx, argc-i, &argv[i]); 538 if (r < 0) 539 return CMD_RET_USAGE; 540 i += r; 541 } else if (!strcmp(argv[i], "check")) { 542 mode = MMC_HWPART_CONF_CHECK; 543 i++; 544 } else if (!strcmp(argv[i], "set")) { 545 mode = MMC_HWPART_CONF_SET; 546 i++; 547 } else if (!strcmp(argv[i], "complete")) { 548 mode = MMC_HWPART_CONF_COMPLETE; 549 i++; 550 } else { 551 return CMD_RET_USAGE; 552 } 553 } 554 555 puts("Partition configuration:\n"); 556 if (pconf.user.enh_size) { 557 puts("\tUser Enhanced Start: "); 558 print_size(((u64)pconf.user.enh_start) << 9, "\n"); 559 puts("\tUser Enhanced Size: "); 560 print_size(((u64)pconf.user.enh_size) << 9, "\n"); 561 } else { 562 puts("\tNo enhanced user data area\n"); 563 } 564 if (pconf.user.wr_rel_change) 565 printf("\tUser partition write reliability: %s\n", 566 pconf.user.wr_rel_set ? "on" : "off"); 567 for (pidx = 0; pidx < 4; pidx++) { 568 if (pconf.gp_part[pidx].size) { 569 printf("\tGP%i Capacity: ", pidx+1); 570 print_size(((u64)pconf.gp_part[pidx].size) << 9, 571 pconf.gp_part[pidx].enhanced ? 572 " ENH\n" : "\n"); 573 } else { 574 printf("\tNo GP%i partition\n", pidx+1); 575 } 576 if (pconf.gp_part[pidx].wr_rel_change) 577 printf("\tGP%i write reliability: %s\n", pidx+1, 578 pconf.gp_part[pidx].wr_rel_set ? "on" : "off"); 579 } 580 581 if (!mmc_hwpart_config(mmc, &pconf, mode)) { 582 if (mode == MMC_HWPART_CONF_COMPLETE) 583 puts("Partitioning successful, " 584 "power-cycle to make effective\n"); 585 return CMD_RET_SUCCESS; 586 } else { 587 puts("Failed!\n"); 588 return CMD_RET_FAILURE; 589 } 590 } 591 #endif 592 593 #ifdef CONFIG_SUPPORT_EMMC_BOOT 594 static int do_mmc_bootbus(cmd_tbl_t *cmdtp, int flag, 595 int argc, char * const argv[]) 596 { 597 int dev; 598 struct mmc *mmc; 599 u8 width, reset, mode; 600 601 if (argc != 5) 602 return CMD_RET_USAGE; 603 dev = simple_strtoul(argv[1], NULL, 10); 604 width = simple_strtoul(argv[2], NULL, 10); 605 reset = simple_strtoul(argv[3], NULL, 10); 606 mode = simple_strtoul(argv[4], NULL, 10); 607 608 mmc = init_mmc_device(dev, false); 609 if (!mmc) 610 return CMD_RET_FAILURE; 611 612 if (IS_SD(mmc)) { 613 puts("BOOT_BUS_WIDTH only exists on eMMC\n"); 614 return CMD_RET_FAILURE; 615 } 616 617 /* acknowledge to be sent during boot operation */ 618 return mmc_set_boot_bus_width(mmc, width, reset, mode); 619 } 620 static int do_mmc_boot_resize(cmd_tbl_t *cmdtp, int flag, 621 int argc, char * const argv[]) 622 { 623 int dev; 624 struct mmc *mmc; 625 u32 bootsize, rpmbsize; 626 627 if (argc != 4) 628 return CMD_RET_USAGE; 629 dev = simple_strtoul(argv[1], NULL, 10); 630 bootsize = simple_strtoul(argv[2], NULL, 10); 631 rpmbsize = simple_strtoul(argv[3], NULL, 10); 632 633 mmc = init_mmc_device(dev, false); 634 if (!mmc) 635 return CMD_RET_FAILURE; 636 637 if (IS_SD(mmc)) { 638 printf("It is not a EMMC device\n"); 639 return CMD_RET_FAILURE; 640 } 641 642 if (mmc_boot_partition_size_change(mmc, bootsize, rpmbsize)) { 643 printf("EMMC boot partition Size change Failed.\n"); 644 return CMD_RET_FAILURE; 645 } 646 647 printf("EMMC boot partition Size %d MB\n", bootsize); 648 printf("EMMC RPMB partition Size %d MB\n", rpmbsize); 649 return CMD_RET_SUCCESS; 650 } 651 652 static int mmc_partconf_print(struct mmc *mmc) 653 { 654 u8 ack, access, part; 655 656 if (mmc->part_config == MMCPART_NOAVAILABLE) { 657 printf("No part_config info for ver. 0x%x\n", mmc->version); 658 return CMD_RET_FAILURE; 659 } 660 661 access = EXT_CSD_EXTRACT_PARTITION_ACCESS(mmc->part_config); 662 ack = EXT_CSD_EXTRACT_BOOT_ACK(mmc->part_config); 663 part = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config); 664 665 printf("EXT_CSD[179], PARTITION_CONFIG:\n" 666 "BOOT_ACK: 0x%x\n" 667 "BOOT_PARTITION_ENABLE: 0x%x\n" 668 "PARTITION_ACCESS: 0x%x\n", ack, part, access); 669 670 return CMD_RET_SUCCESS; 671 } 672 673 static int do_mmc_partconf(cmd_tbl_t *cmdtp, int flag, 674 int argc, char * const argv[]) 675 { 676 int dev; 677 struct mmc *mmc; 678 u8 ack, part_num, access; 679 680 if (argc != 2 && argc != 5) 681 return CMD_RET_USAGE; 682 683 dev = simple_strtoul(argv[1], NULL, 10); 684 685 mmc = init_mmc_device(dev, false); 686 if (!mmc) 687 return CMD_RET_FAILURE; 688 689 if (IS_SD(mmc)) { 690 puts("PARTITION_CONFIG only exists on eMMC\n"); 691 return CMD_RET_FAILURE; 692 } 693 694 if (argc == 2) 695 return mmc_partconf_print(mmc); 696 697 ack = simple_strtoul(argv[2], NULL, 10); 698 part_num = simple_strtoul(argv[3], NULL, 10); 699 access = simple_strtoul(argv[4], NULL, 10); 700 701 /* acknowledge to be sent during boot operation */ 702 return mmc_set_part_conf(mmc, ack, part_num, access); 703 } 704 static int do_mmc_rst_func(cmd_tbl_t *cmdtp, int flag, 705 int argc, char * const argv[]) 706 { 707 int dev; 708 struct mmc *mmc; 709 u8 enable; 710 711 /* 712 * Set the RST_n_ENABLE bit of RST_n_FUNCTION 713 * The only valid values are 0x0, 0x1 and 0x2 and writing 714 * a value of 0x1 or 0x2 sets the value permanently. 715 */ 716 if (argc != 3) 717 return CMD_RET_USAGE; 718 719 dev = simple_strtoul(argv[1], NULL, 10); 720 enable = simple_strtoul(argv[2], NULL, 10); 721 722 if (enable > 2) { 723 puts("Invalid RST_n_ENABLE value\n"); 724 return CMD_RET_USAGE; 725 } 726 727 mmc = init_mmc_device(dev, false); 728 if (!mmc) 729 return CMD_RET_FAILURE; 730 731 if (IS_SD(mmc)) { 732 puts("RST_n_FUNCTION only exists on eMMC\n"); 733 return CMD_RET_FAILURE; 734 } 735 736 return mmc_set_rst_n_function(mmc, enable); 737 } 738 #endif 739 static int do_mmc_setdsr(cmd_tbl_t *cmdtp, int flag, 740 int argc, char * const argv[]) 741 { 742 struct mmc *mmc; 743 u32 val; 744 int ret; 745 746 if (argc != 2) 747 return CMD_RET_USAGE; 748 val = simple_strtoul(argv[1], NULL, 16); 749 750 mmc = find_mmc_device(curr_device); 751 if (!mmc) { 752 printf("no mmc device at slot %x\n", curr_device); 753 return CMD_RET_FAILURE; 754 } 755 ret = mmc_set_dsr(mmc, val); 756 printf("set dsr %s\n", (!ret) ? "OK, force rescan" : "ERROR"); 757 if (!ret) { 758 mmc->has_init = 0; 759 if (mmc_init(mmc)) 760 return CMD_RET_FAILURE; 761 else 762 return CMD_RET_SUCCESS; 763 } 764 return ret; 765 } 766 767 #ifdef CONFIG_CMD_BKOPS_ENABLE 768 static int do_mmc_bkops_enable(cmd_tbl_t *cmdtp, int flag, 769 int argc, char * const argv[]) 770 { 771 int dev; 772 struct mmc *mmc; 773 774 if (argc != 2) 775 return CMD_RET_USAGE; 776 777 dev = simple_strtoul(argv[1], NULL, 10); 778 779 mmc = init_mmc_device(dev, false); 780 if (!mmc) 781 return CMD_RET_FAILURE; 782 783 if (IS_SD(mmc)) { 784 puts("BKOPS_EN only exists on eMMC\n"); 785 return CMD_RET_FAILURE; 786 } 787 788 return mmc_set_bkops_enable(mmc); 789 } 790 #endif 791 792 static cmd_tbl_t cmd_mmc[] = { 793 U_BOOT_CMD_MKENT(info, 1, 0, do_mmcinfo, "", ""), 794 U_BOOT_CMD_MKENT(read, 4, 1, do_mmc_read, "", ""), 795 U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""), 796 U_BOOT_CMD_MKENT(erase, 3, 0, do_mmc_erase, "", ""), 797 U_BOOT_CMD_MKENT(rescan, 1, 1, do_mmc_rescan, "", ""), 798 U_BOOT_CMD_MKENT(part, 1, 1, do_mmc_part, "", ""), 799 U_BOOT_CMD_MKENT(dev, 3, 0, do_mmc_dev, "", ""), 800 U_BOOT_CMD_MKENT(list, 1, 1, do_mmc_list, "", ""), 801 #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) 802 U_BOOT_CMD_MKENT(hwpartition, 28, 0, do_mmc_hwpartition, "", ""), 803 #endif 804 #ifdef CONFIG_SUPPORT_EMMC_BOOT 805 U_BOOT_CMD_MKENT(bootbus, 5, 0, do_mmc_bootbus, "", ""), 806 U_BOOT_CMD_MKENT(bootpart-resize, 4, 0, do_mmc_boot_resize, "", ""), 807 U_BOOT_CMD_MKENT(partconf, 5, 0, do_mmc_partconf, "", ""), 808 U_BOOT_CMD_MKENT(rst-function, 3, 0, do_mmc_rst_func, "", ""), 809 #endif 810 #ifdef CONFIG_SUPPORT_EMMC_RPMB 811 U_BOOT_CMD_MKENT(rpmb, CONFIG_SYS_MAXARGS, 1, do_mmcrpmb, "", ""), 812 #endif 813 U_BOOT_CMD_MKENT(setdsr, 2, 0, do_mmc_setdsr, "", ""), 814 #ifdef CONFIG_CMD_BKOPS_ENABLE 815 U_BOOT_CMD_MKENT(bkops-enable, 2, 0, do_mmc_bkops_enable, "", ""), 816 #endif 817 }; 818 819 static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 820 { 821 cmd_tbl_t *cp; 822 823 cp = find_cmd_tbl(argv[1], cmd_mmc, ARRAY_SIZE(cmd_mmc)); 824 825 /* Drop the mmc command */ 826 argc--; 827 argv++; 828 829 if (cp == NULL || argc > cp->maxargs) 830 return CMD_RET_USAGE; 831 if (flag == CMD_FLAG_REPEAT && !cp->repeatable) 832 return CMD_RET_SUCCESS; 833 834 if (curr_device < 0) { 835 if (get_mmc_num() > 0) { 836 curr_device = 0; 837 } else { 838 puts("No MMC device available\n"); 839 return CMD_RET_FAILURE; 840 } 841 } 842 return cp->cmd(cmdtp, flag, argc, argv); 843 } 844 845 U_BOOT_CMD( 846 mmc, 29, 1, do_mmcops, 847 "MMC sub system", 848 "info - display info of the current MMC device\n" 849 "mmc read addr blk# cnt\n" 850 "mmc write addr blk# cnt\n" 851 "mmc erase blk# cnt\n" 852 "mmc rescan\n" 853 "mmc part - lists available partition on current mmc device\n" 854 "mmc dev [dev] [part] - show or set current mmc device [partition]\n" 855 "mmc list - lists available devices\n" 856 "mmc hwpartition [args...] - does hardware partitioning\n" 857 " arguments (sizes in 512-byte blocks):\n" 858 " [user [enh start cnt] [wrrel {on|off}]] - sets user data area attributes\n" 859 " [gp1|gp2|gp3|gp4 cnt [enh] [wrrel {on|off}]] - general purpose partition\n" 860 " [check|set|complete] - mode, complete set partitioning completed\n" 861 " WARNING: Partitioning is a write-once setting once it is set to complete.\n" 862 " Power cycling is required to initialize partitions after set to complete.\n" 863 #ifdef CONFIG_SUPPORT_EMMC_BOOT 864 "mmc bootbus dev boot_bus_width reset_boot_bus_width boot_mode\n" 865 " - Set the BOOT_BUS_WIDTH field of the specified device\n" 866 "mmc bootpart-resize <dev> <boot part size MB> <RPMB part size MB>\n" 867 " - Change sizes of boot and RPMB partitions of specified device\n" 868 "mmc partconf dev [boot_ack boot_partition partition_access]\n" 869 " - Show or change the bits of the PARTITION_CONFIG field of the specified device\n" 870 "mmc rst-function dev value\n" 871 " - Change the RST_n_FUNCTION field of the specified device\n" 872 " WARNING: This is a write-once field and 0 / 1 / 2 are the only valid values.\n" 873 #endif 874 #ifdef CONFIG_SUPPORT_EMMC_RPMB 875 "mmc rpmb read addr blk# cnt [address of auth-key] - block size is 256 bytes\n" 876 "mmc rpmb write addr blk# cnt <address of auth-key> - block size is 256 bytes\n" 877 "mmc rpmb key <address of auth-key> - program the RPMB authentication key.\n" 878 "mmc rpmb counter - read the value of the write counter\n" 879 #endif 880 "mmc setdsr <value> - set DSR register value\n" 881 #ifdef CONFIG_CMD_BKOPS_ENABLE 882 "mmc bkops-enable <dev> - enable background operations handshake on device\n" 883 " WARNING: This is a write-once setting.\n" 884 #endif 885 ); 886 887 /* Old command kept for compatibility. Same as 'mmc info' */ 888 U_BOOT_CMD( 889 mmcinfo, 1, 0, do_mmcinfo, 890 "display MMC info", 891 "- display info of the current MMC device" 892 ); 893