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