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