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