Merge branch 'master' of git://git.denx.de/u-boot-sh
[platform/kernel/u-boot.git] / cmd / mmc.c
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
14 static int curr_device = -1;
15
16 static 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 }
95 static 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 }
110 static 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)
132 static 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 }
143 static 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 }
161 static 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 }
189 static 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 }
215 static 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
227 static 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
234 static 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
284 static 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)
312 static 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
320 static lbaint_t mmc_sparse_reserve(struct sparse_storage *info,
321                                    lbaint_t blk, lbaint_t blkcnt)
322 {
323         return blkcnt;
324 }
325
326 static 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)
377 static 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 }
407 static 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
437 static 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 }
448 static 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 }
467 static 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 }
508 static 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)
516 static 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
550 static 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
584 static 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
668 static 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 }
694 static 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
726 static 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
747 static 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 }
778 static 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
813 static 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
842 static 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
866 static 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
898 static 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
924 U_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' */
972 U_BOOT_CMD(
973         mmcinfo, 1, 0, do_mmcinfo,
974         "display MMC info",
975         "- display info of the current MMC device"
976 );