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