]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_mmc.c
afa87fe2a78b956195a1bfbc50fcc67a700e4f78
[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
661         if (argc != 5)
662                 return CMD_RET_USAGE;
663
664         dev = simple_strtoul(argv[1], NULL, 10);
665         width = simple_strtoul(argv[2], NULL, 10);
666         reset = simple_strtoul(argv[3], NULL, 10);
667         mode = simple_strtoul(argv[4], NULL, 10);
668
669         mmc = init_mmc_device(dev, false);
670         if (!mmc)
671                 return CMD_RET_FAILURE;
672
673         if (IS_SD(mmc)) {
674                 puts("BOOT_BUS_WIDTH only exists on eMMC\n");
675                 return CMD_RET_FAILURE;
676         }
677
678         return mmc_set_boot_bus_width(mmc, width, reset, mode);
679 }
680
681 static int do_mmc_boot_resize(cmd_tbl_t *cmdtp, int flag,
682                               int argc, char * const argv[])
683 {
684         int dev;
685         struct mmc *mmc;
686         u32 bootsize, rpmbsize;
687
688         if (argc != 4)
689                 return CMD_RET_USAGE;
690         dev = simple_strtoul(argv[1], NULL, 10);
691         bootsize = simple_strtoul(argv[2], NULL, 10);
692         rpmbsize = simple_strtoul(argv[3], NULL, 10);
693
694         mmc = init_mmc_device(dev, false);
695         if (!mmc)
696                 return CMD_RET_FAILURE;
697
698         if (IS_SD(mmc)) {
699                 printf("It is not a EMMC device\n");
700                 return CMD_RET_FAILURE;
701         }
702
703         if (mmc_boot_partition_size_change(mmc, bootsize, rpmbsize)) {
704                 printf("EMMC boot partition Size change Failed.\n");
705                 return CMD_RET_FAILURE;
706         }
707
708         printf("EMMC boot partition Size %d MB\n", bootsize);
709         printf("EMMC RPMB partition Size %d MB\n", rpmbsize);
710         return CMD_RET_SUCCESS;
711 }
712
713 static int do_mmc_partconf(cmd_tbl_t *cmdtp, int flag,
714                            int argc, char * const argv[])
715 {
716         int dev;
717         struct mmc *mmc;
718         u8 ack, part_num, access;
719
720         if (argc != 5)
721                 return CMD_RET_USAGE;
722
723         dev = simple_strtoul(argv[1], NULL, 10);
724         ack = simple_strtoul(argv[2], NULL, 10);
725         part_num = simple_strtoul(argv[3], NULL, 10);
726         access = simple_strtoul(argv[4], NULL, 10);
727
728         mmc = init_mmc_device(dev, false);
729         if (!mmc)
730                 return CMD_RET_FAILURE;
731
732         if (IS_SD(mmc)) {
733                 puts("PARTITION_CONFIG only exists on eMMC\n");
734                 return CMD_RET_FAILURE;
735         }
736
737         /* acknowledge to be sent during boot operation */
738         return mmc_set_part_conf(mmc, ack, part_num, access);
739 }
740
741 static int do_mmc_rst_func(cmd_tbl_t *cmdtp, int flag,
742                            int argc, char * const argv[])
743 {
744         int dev;
745         struct mmc *mmc;
746         u8 enable;
747
748         /*
749          * Set the RST_n_ENABLE bit of RST_n_FUNCTION
750          * The only valid values are 0x0, 0x1 and 0x2 and writing
751          * a value of 0x1 or 0x2 sets the value permanently.
752          */
753         if (argc != 3)
754                 return CMD_RET_USAGE;
755
756         dev = simple_strtoul(argv[1], NULL, 10);
757         enable = simple_strtoul(argv[2], NULL, 10);
758
759         if (enable > 2 || enable < 0) {
760                 puts("Invalid RST_n_ENABLE value\n");
761                 return CMD_RET_USAGE;
762         }
763
764         mmc = init_mmc_device(dev, false);
765         if (!mmc)
766                 return CMD_RET_FAILURE;
767
768         if (IS_SD(mmc)) {
769                 puts("RST_n_FUNCTION only exists on eMMC\n");
770                 return CMD_RET_FAILURE;
771         }
772
773         return mmc_set_rst_n_function(mmc, enable);
774 }
775 #endif
776
777 static int do_mmc_setdsr(cmd_tbl_t *cmdtp, int flag,
778                          int argc, char * const argv[])
779 {
780         struct mmc *mmc;
781         u32 val;
782         int ret;
783
784         if (argc != 2)
785                 return CMD_RET_USAGE;
786         val = simple_strtoul(argv[2], NULL, 16);
787
788         mmc = find_mmc_device(curr_device);
789         if (!mmc) {
790                 printf("no mmc device at slot %x\n", curr_device);
791                 return CMD_RET_FAILURE;
792         }
793         ret = mmc_set_dsr(mmc, val);
794         printf("set dsr %s\n", (!ret) ? "OK, force rescan" : "ERROR");
795         if (!ret) {
796                 mmc->has_init = 0;
797                 if (mmc_init(mmc))
798                         return CMD_RET_FAILURE;
799                 else
800                         return CMD_RET_SUCCESS;
801         }
802         return ret;
803 }
804
805 static cmd_tbl_t cmd_mmc[] = {
806         U_BOOT_CMD_MKENT(info, 1, 0, do_mmcinfo, "", ""),
807         U_BOOT_CMD_MKENT(read, 4, 1, do_mmc_read, "", ""),
808         U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""),
809         U_BOOT_CMD_MKENT(erase, 3, 0, do_mmc_erase, "", ""),
810         U_BOOT_CMD_MKENT(rescan, 1, 1, do_mmc_rescan, "", ""),
811         U_BOOT_CMD_MKENT(part, 1, 1, do_mmc_part, "", ""),
812         U_BOOT_CMD_MKENT(dev, 3, 0, do_mmc_dev, "", ""),
813         U_BOOT_CMD_MKENT(list, 1, 1, do_mmc_list, "", ""),
814         U_BOOT_CMD_MKENT(hwpartition, 28, 0, do_mmc_hwpartition, "", ""),
815 #ifdef CONFIG_SUPPORT_EMMC_BOOT
816         U_BOOT_CMD_MKENT(bootbus, 5, 0, do_mmc_bootbus, "", ""),
817         U_BOOT_CMD_MKENT(bootpart-resize, 4, 0, do_mmc_boot_resize, "", ""),
818         U_BOOT_CMD_MKENT(partconf, 5, 0, do_mmc_partconf, "", ""),
819         U_BOOT_CMD_MKENT(rst-function, 3, 0, do_mmc_rst_func, "", ""),
820 #endif
821 #ifdef CONFIG_SUPPORT_EMMC_RPMB
822         U_BOOT_CMD_MKENT(rpmb, CONFIG_SYS_MAXARGS, 1, do_mmcrpmb, "", ""),
823 #endif
824         U_BOOT_CMD_MKENT(setdsr, 2, 0, do_mmc_setdsr, "", ""),
825 };
826
827 static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
828 {
829         cmd_tbl_t *cp;
830
831         cp = find_cmd_tbl(argv[1], cmd_mmc, ARRAY_SIZE(cmd_mmc));
832
833         /* Drop the mmc command */
834         argc--;
835         argv++;
836
837         if (cp == NULL || argc > cp->maxargs)
838                 return CMD_RET_USAGE;
839         if (flag == CMD_FLAG_REPEAT && !cp->repeatable)
840                 return CMD_RET_SUCCESS;
841
842         if (curr_device < 0) {
843                 if (get_mmc_num() > 0) {
844                         curr_device = 0;
845                 } else {
846                         puts("No MMC device available\n");
847                         return CMD_RET_FAILURE;
848                 }
849         }
850         return cp->cmd(cmdtp, flag, argc, argv);
851 }
852
853 U_BOOT_CMD(
854         mmc, 29, 1, do_mmcops,
855         "MMC sub system",
856         "info - display info of the current MMC device\n"
857         "mmc read addr blk# cnt\n"
858         "mmc write addr blk# cnt\n"
859         "mmc erase blk# cnt\n"
860         "mmc rescan\n"
861         "mmc part - lists available partition on current mmc device\n"
862         "mmc dev [dev] [part] - show or set current mmc device [partition]\n"
863         "mmc list - lists available devices\n"
864         "mmc hwpartition [args...] - does hardware partitioning\n"
865         "  arguments (sizes in 512-byte blocks):\n"
866         "    [user [enh start cnt] [wrrel {on|off}]] - sets user data area attributes\n"
867         "    [gp1|gp2|gp3|gp4 cnt [enh] [wrrel {on|off}]] - general purpose partition\n"
868         "    [check|set|complete] - mode, complete set partitioning completed\n"
869         "  WARNING: Partitioning is a write-once setting once it is set to complete.\n"
870         "  Power cycling is required to initialize partitions after set to complete.\n"
871 #ifdef CONFIG_SUPPORT_EMMC_BOOT
872         "mmc bootbus dev boot_bus_width reset_boot_bus_width boot_mode\n"
873         " - Set the BOOT_BUS_WIDTH field of the specified device\n"
874         "mmc bootpart-resize <dev> <boot part size MB> <RPMB part size MB>\n"
875         " - Change sizes of boot and RPMB partitions of specified device\n"
876         "mmc partconf dev boot_ack boot_partition partition_access\n"
877         " - Change the bits of the PARTITION_CONFIG field of the specified device\n"
878         "mmc rst-function dev value\n"
879         " - Change the RST_n_FUNCTION field of the specified device\n"
880         "   WARNING: This is a write-once field and 0 / 1 / 2 are the only valid values.\n"
881 #endif
882 #ifdef CONFIG_SUPPORT_EMMC_RPMB
883         "mmc rpmb read addr blk# cnt [address of auth-key] - block size is 256 bytes\n"
884         "mmc rpmb write addr blk# cnt <address of auth-key> - block size is 256 bytes\n"
885         "mmc rpmb key <address of auth-key> - program the RPMB authentication key.\n"
886         "mmc rpmb counter - read the value of the write counter\n"
887 #endif
888         "mmc setdsr <value> - set DSR register value\n"
889         );
890
891 /* Old command kept for compatibility. Same as 'mmc info' */
892 U_BOOT_CMD(
893         mmcinfo, 1, 0, do_mmcinfo,
894         "display MMC info",
895         "- display info of the current MMC device"
896 );
897
898 #endif /* !CONFIG_GENERIC_MMC */