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