]> git.sur5r.net Git - u-boot/blob - cmd/mmc.c
Merge branch 'master' of git://git.denx.de/u-boot-video
[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         original_part = mmc->block_dev.hwpart;
257         if (blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, MMC_PART_RPMB) !=
258             0)
259                 return CMD_RET_FAILURE;
260         ret = cp->cmd(cmdtp, flag, argc, argv);
261
262         /* Return to original partition */
263         if (blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, original_part) !=
264             0)
265                 return CMD_RET_FAILURE;
266         return ret;
267 }
268 #endif
269
270 static int do_mmc_read(cmd_tbl_t *cmdtp, int flag,
271                        int argc, char * const argv[])
272 {
273         struct mmc *mmc;
274         u32 blk, cnt, n;
275         void *addr;
276
277         if (argc != 4)
278                 return CMD_RET_USAGE;
279
280         addr = (void *)simple_strtoul(argv[1], NULL, 16);
281         blk = simple_strtoul(argv[2], NULL, 16);
282         cnt = simple_strtoul(argv[3], NULL, 16);
283
284         mmc = init_mmc_device(curr_device, false);
285         if (!mmc)
286                 return CMD_RET_FAILURE;
287
288         printf("\nMMC read: dev # %d, block # %d, count %d ... ",
289                curr_device, blk, cnt);
290
291         n = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr);
292         /* flush cache after read */
293         flush_cache((ulong)addr, cnt * 512); /* FIXME */
294         printf("%d blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR");
295
296         return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
297 }
298 static int do_mmc_write(cmd_tbl_t *cmdtp, int flag,
299                         int argc, char * const argv[])
300 {
301         struct mmc *mmc;
302         u32 blk, cnt, n;
303         void *addr;
304
305         if (argc != 4)
306                 return CMD_RET_USAGE;
307
308         addr = (void *)simple_strtoul(argv[1], NULL, 16);
309         blk = simple_strtoul(argv[2], NULL, 16);
310         cnt = simple_strtoul(argv[3], NULL, 16);
311
312         mmc = init_mmc_device(curr_device, false);
313         if (!mmc)
314                 return CMD_RET_FAILURE;
315
316         printf("\nMMC write: dev # %d, block # %d, count %d ... ",
317                curr_device, blk, cnt);
318
319         if (mmc_getwp(mmc) == 1) {
320                 printf("Error: card is write protected!\n");
321                 return CMD_RET_FAILURE;
322         }
323         n = blk_dwrite(mmc_get_blk_desc(mmc), blk, cnt, addr);
324         printf("%d blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR");
325
326         return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
327 }
328 static int do_mmc_erase(cmd_tbl_t *cmdtp, int flag,
329                         int argc, char * const argv[])
330 {
331         struct mmc *mmc;
332         u32 blk, cnt, n;
333
334         if (argc != 3)
335                 return CMD_RET_USAGE;
336
337         blk = simple_strtoul(argv[1], NULL, 16);
338         cnt = simple_strtoul(argv[2], NULL, 16);
339
340         mmc = init_mmc_device(curr_device, false);
341         if (!mmc)
342                 return CMD_RET_FAILURE;
343
344         printf("\nMMC erase: dev # %d, block # %d, count %d ... ",
345                curr_device, blk, cnt);
346
347         if (mmc_getwp(mmc) == 1) {
348                 printf("Error: card is write protected!\n");
349                 return CMD_RET_FAILURE;
350         }
351         n = blk_derase(mmc_get_blk_desc(mmc), blk, cnt);
352         printf("%d blocks erased: %s\n", n, (n == cnt) ? "OK" : "ERROR");
353
354         return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
355 }
356 static int do_mmc_rescan(cmd_tbl_t *cmdtp, int flag,
357                          int argc, char * const argv[])
358 {
359         struct mmc *mmc;
360
361         mmc = init_mmc_device(curr_device, true);
362         if (!mmc)
363                 return CMD_RET_FAILURE;
364
365         return CMD_RET_SUCCESS;
366 }
367 static int do_mmc_part(cmd_tbl_t *cmdtp, int flag,
368                        int argc, char * const argv[])
369 {
370         struct blk_desc *mmc_dev;
371         struct mmc *mmc;
372
373         mmc = init_mmc_device(curr_device, false);
374         if (!mmc)
375                 return CMD_RET_FAILURE;
376
377         mmc_dev = blk_get_devnum_by_type(IF_TYPE_MMC, curr_device);
378         if (mmc_dev != NULL && mmc_dev->type != DEV_TYPE_UNKNOWN) {
379                 part_print(mmc_dev);
380                 return CMD_RET_SUCCESS;
381         }
382
383         puts("get mmc type error!\n");
384         return CMD_RET_FAILURE;
385 }
386 static int do_mmc_dev(cmd_tbl_t *cmdtp, int flag,
387                       int argc, char * const argv[])
388 {
389         int dev, part = 0, ret;
390         struct mmc *mmc;
391
392         if (argc == 1) {
393                 dev = curr_device;
394         } else if (argc == 2) {
395                 dev = simple_strtoul(argv[1], NULL, 10);
396         } else if (argc == 3) {
397                 dev = (int)simple_strtoul(argv[1], NULL, 10);
398                 part = (int)simple_strtoul(argv[2], NULL, 10);
399                 if (part > PART_ACCESS_MASK) {
400                         printf("#part_num shouldn't be larger than %d\n",
401                                PART_ACCESS_MASK);
402                         return CMD_RET_FAILURE;
403                 }
404         } else {
405                 return CMD_RET_USAGE;
406         }
407
408         mmc = init_mmc_device(dev, true);
409         if (!mmc)
410                 return CMD_RET_FAILURE;
411
412         ret = blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part);
413         printf("switch to partitions #%d, %s\n",
414                part, (!ret) ? "OK" : "ERROR");
415         if (ret)
416                 return 1;
417
418         curr_device = dev;
419         if (mmc->part_config == MMCPART_NOAVAILABLE)
420                 printf("mmc%d is current device\n", curr_device);
421         else
422                 printf("mmc%d(part %d) is current device\n",
423                        curr_device, mmc_get_blk_desc(mmc)->hwpart);
424
425         return CMD_RET_SUCCESS;
426 }
427 static int do_mmc_list(cmd_tbl_t *cmdtp, int flag,
428                        int argc, char * const argv[])
429 {
430         print_mmc_devices('\n');
431         return CMD_RET_SUCCESS;
432 }
433
434 static int parse_hwpart_user(struct mmc_hwpart_conf *pconf,
435                              int argc, char * const argv[])
436 {
437         int i = 0;
438
439         memset(&pconf->user, 0, sizeof(pconf->user));
440
441         while (i < argc) {
442                 if (!strcmp(argv[i], "enh")) {
443                         if (i + 2 >= argc)
444                                 return -1;
445                         pconf->user.enh_start =
446                                 simple_strtoul(argv[i+1], NULL, 10);
447                         pconf->user.enh_size =
448                                 simple_strtoul(argv[i+2], NULL, 10);
449                         i += 3;
450                 } else if (!strcmp(argv[i], "wrrel")) {
451                         if (i + 1 >= argc)
452                                 return -1;
453                         pconf->user.wr_rel_change = 1;
454                         if (!strcmp(argv[i+1], "on"))
455                                 pconf->user.wr_rel_set = 1;
456                         else if (!strcmp(argv[i+1], "off"))
457                                 pconf->user.wr_rel_set = 0;
458                         else
459                                 return -1;
460                         i += 2;
461                 } else {
462                         break;
463                 }
464         }
465         return i;
466 }
467
468 static int parse_hwpart_gp(struct mmc_hwpart_conf *pconf, int pidx,
469                            int argc, char * const argv[])
470 {
471         int i;
472
473         memset(&pconf->gp_part[pidx], 0, sizeof(pconf->gp_part[pidx]));
474
475         if (1 >= argc)
476                 return -1;
477         pconf->gp_part[pidx].size = simple_strtoul(argv[0], NULL, 10);
478
479         i = 1;
480         while (i < argc) {
481                 if (!strcmp(argv[i], "enh")) {
482                         pconf->gp_part[pidx].enhanced = 1;
483                         i += 1;
484                 } else if (!strcmp(argv[i], "wrrel")) {
485                         if (i + 1 >= argc)
486                                 return -1;
487                         pconf->gp_part[pidx].wr_rel_change = 1;
488                         if (!strcmp(argv[i+1], "on"))
489                                 pconf->gp_part[pidx].wr_rel_set = 1;
490                         else if (!strcmp(argv[i+1], "off"))
491                                 pconf->gp_part[pidx].wr_rel_set = 0;
492                         else
493                                 return -1;
494                         i += 2;
495                 } else {
496                         break;
497                 }
498         }
499         return i;
500 }
501
502 static int do_mmc_hwpartition(cmd_tbl_t *cmdtp, int flag,
503                               int argc, char * const argv[])
504 {
505         struct mmc *mmc;
506         struct mmc_hwpart_conf pconf = { };
507         enum mmc_hwpart_conf_mode mode = MMC_HWPART_CONF_CHECK;
508         int i, r, pidx;
509
510         mmc = init_mmc_device(curr_device, false);
511         if (!mmc)
512                 return CMD_RET_FAILURE;
513
514         if (argc < 1)
515                 return CMD_RET_USAGE;
516         i = 1;
517         while (i < argc) {
518                 if (!strcmp(argv[i], "user")) {
519                         i++;
520                         r = parse_hwpart_user(&pconf, argc-i, &argv[i]);
521                         if (r < 0)
522                                 return CMD_RET_USAGE;
523                         i += r;
524                 } else if (!strncmp(argv[i], "gp", 2) &&
525                            strlen(argv[i]) == 3 &&
526                            argv[i][2] >= '1' && argv[i][2] <= '4') {
527                         pidx = argv[i][2] - '1';
528                         i++;
529                         r = parse_hwpart_gp(&pconf, pidx, argc-i, &argv[i]);
530                         if (r < 0)
531                                 return CMD_RET_USAGE;
532                         i += r;
533                 } else if (!strcmp(argv[i], "check")) {
534                         mode = MMC_HWPART_CONF_CHECK;
535                         i++;
536                 } else if (!strcmp(argv[i], "set")) {
537                         mode = MMC_HWPART_CONF_SET;
538                         i++;
539                 } else if (!strcmp(argv[i], "complete")) {
540                         mode = MMC_HWPART_CONF_COMPLETE;
541                         i++;
542                 } else {
543                         return CMD_RET_USAGE;
544                 }
545         }
546
547         puts("Partition configuration:\n");
548         if (pconf.user.enh_size) {
549                 puts("\tUser Enhanced Start: ");
550                 print_size(((u64)pconf.user.enh_start) << 9, "\n");
551                 puts("\tUser Enhanced Size: ");
552                 print_size(((u64)pconf.user.enh_size) << 9, "\n");
553         } else {
554                 puts("\tNo enhanced user data area\n");
555         }
556         if (pconf.user.wr_rel_change)
557                 printf("\tUser partition write reliability: %s\n",
558                        pconf.user.wr_rel_set ? "on" : "off");
559         for (pidx = 0; pidx < 4; pidx++) {
560                 if (pconf.gp_part[pidx].size) {
561                         printf("\tGP%i Capacity: ", pidx+1);
562                         print_size(((u64)pconf.gp_part[pidx].size) << 9,
563                                    pconf.gp_part[pidx].enhanced ?
564                                    " ENH\n" : "\n");
565                 } else {
566                         printf("\tNo GP%i partition\n", pidx+1);
567                 }
568                 if (pconf.gp_part[pidx].wr_rel_change)
569                         printf("\tGP%i write reliability: %s\n", pidx+1,
570                                pconf.gp_part[pidx].wr_rel_set ? "on" : "off");
571         }
572
573         if (!mmc_hwpart_config(mmc, &pconf, mode)) {
574                 if (mode == MMC_HWPART_CONF_COMPLETE)
575                         puts("Partitioning successful, "
576                              "power-cycle to make effective\n");
577                 return CMD_RET_SUCCESS;
578         } else {
579                 puts("Failed!\n");
580                 return CMD_RET_FAILURE;
581         }
582 }
583
584 #ifdef CONFIG_SUPPORT_EMMC_BOOT
585 static int do_mmc_bootbus(cmd_tbl_t *cmdtp, int flag,
586                           int argc, char * const argv[])
587 {
588         int dev;
589         struct mmc *mmc;
590         u8 width, reset, mode;
591
592         if (argc != 5)
593                 return CMD_RET_USAGE;
594         dev = simple_strtoul(argv[1], NULL, 10);
595         width = simple_strtoul(argv[2], NULL, 10);
596         reset = simple_strtoul(argv[3], NULL, 10);
597         mode = simple_strtoul(argv[4], NULL, 10);
598
599         mmc = init_mmc_device(dev, false);
600         if (!mmc)
601                 return CMD_RET_FAILURE;
602
603         if (IS_SD(mmc)) {
604                 puts("BOOT_BUS_WIDTH only exists on eMMC\n");
605                 return CMD_RET_FAILURE;
606         }
607
608         /* acknowledge to be sent during boot operation */
609         return mmc_set_boot_bus_width(mmc, width, reset, mode);
610 }
611 static int do_mmc_boot_resize(cmd_tbl_t *cmdtp, int flag,
612                               int argc, char * const argv[])
613 {
614         int dev;
615         struct mmc *mmc;
616         u32 bootsize, rpmbsize;
617
618         if (argc != 4)
619                 return CMD_RET_USAGE;
620         dev = simple_strtoul(argv[1], NULL, 10);
621         bootsize = simple_strtoul(argv[2], NULL, 10);
622         rpmbsize = simple_strtoul(argv[3], NULL, 10);
623
624         mmc = init_mmc_device(dev, false);
625         if (!mmc)
626                 return CMD_RET_FAILURE;
627
628         if (IS_SD(mmc)) {
629                 printf("It is not a EMMC device\n");
630                 return CMD_RET_FAILURE;
631         }
632
633         if (mmc_boot_partition_size_change(mmc, bootsize, rpmbsize)) {
634                 printf("EMMC boot partition Size change Failed.\n");
635                 return CMD_RET_FAILURE;
636         }
637
638         printf("EMMC boot partition Size %d MB\n", bootsize);
639         printf("EMMC RPMB partition Size %d MB\n", rpmbsize);
640         return CMD_RET_SUCCESS;
641 }
642 static int do_mmc_partconf(cmd_tbl_t *cmdtp, int flag,
643                            int argc, char * const argv[])
644 {
645         int dev;
646         struct mmc *mmc;
647         u8 ack, part_num, access;
648
649         if (argc != 5)
650                 return CMD_RET_USAGE;
651
652         dev = simple_strtoul(argv[1], NULL, 10);
653         ack = simple_strtoul(argv[2], NULL, 10);
654         part_num = simple_strtoul(argv[3], NULL, 10);
655         access = simple_strtoul(argv[4], NULL, 10);
656
657         mmc = init_mmc_device(dev, false);
658         if (!mmc)
659                 return CMD_RET_FAILURE;
660
661         if (IS_SD(mmc)) {
662                 puts("PARTITION_CONFIG only exists on eMMC\n");
663                 return CMD_RET_FAILURE;
664         }
665
666         /* acknowledge to be sent during boot operation */
667         return mmc_set_part_conf(mmc, ack, part_num, access);
668 }
669 static int do_mmc_rst_func(cmd_tbl_t *cmdtp, int flag,
670                            int argc, char * const argv[])
671 {
672         int dev;
673         struct mmc *mmc;
674         u8 enable;
675
676         /*
677          * Set the RST_n_ENABLE bit of RST_n_FUNCTION
678          * The only valid values are 0x0, 0x1 and 0x2 and writing
679          * a value of 0x1 or 0x2 sets the value permanently.
680          */
681         if (argc != 3)
682                 return CMD_RET_USAGE;
683
684         dev = simple_strtoul(argv[1], NULL, 10);
685         enable = simple_strtoul(argv[2], NULL, 10);
686
687         if (enable > 2) {
688                 puts("Invalid RST_n_ENABLE value\n");
689                 return CMD_RET_USAGE;
690         }
691
692         mmc = init_mmc_device(dev, false);
693         if (!mmc)
694                 return CMD_RET_FAILURE;
695
696         if (IS_SD(mmc)) {
697                 puts("RST_n_FUNCTION only exists on eMMC\n");
698                 return CMD_RET_FAILURE;
699         }
700
701         return mmc_set_rst_n_function(mmc, enable);
702 }
703 #endif
704 static int do_mmc_setdsr(cmd_tbl_t *cmdtp, int flag,
705                          int argc, char * const argv[])
706 {
707         struct mmc *mmc;
708         u32 val;
709         int ret;
710
711         if (argc != 2)
712                 return CMD_RET_USAGE;
713         val = simple_strtoul(argv[1], NULL, 16);
714
715         mmc = find_mmc_device(curr_device);
716         if (!mmc) {
717                 printf("no mmc device at slot %x\n", curr_device);
718                 return CMD_RET_FAILURE;
719         }
720         ret = mmc_set_dsr(mmc, val);
721         printf("set dsr %s\n", (!ret) ? "OK, force rescan" : "ERROR");
722         if (!ret) {
723                 mmc->has_init = 0;
724                 if (mmc_init(mmc))
725                         return CMD_RET_FAILURE;
726                 else
727                         return CMD_RET_SUCCESS;
728         }
729         return ret;
730 }
731
732 #ifdef CONFIG_CMD_BKOPS_ENABLE
733 static int do_mmc_bkops_enable(cmd_tbl_t *cmdtp, int flag,
734                                    int argc, char * const argv[])
735 {
736         int dev;
737         struct mmc *mmc;
738
739         if (argc != 2)
740                 return CMD_RET_USAGE;
741
742         dev = simple_strtoul(argv[1], NULL, 10);
743
744         mmc = init_mmc_device(dev, false);
745         if (!mmc)
746                 return CMD_RET_FAILURE;
747
748         if (IS_SD(mmc)) {
749                 puts("BKOPS_EN only exists on eMMC\n");
750                 return CMD_RET_FAILURE;
751         }
752
753         return mmc_set_bkops_enable(mmc);
754 }
755 #endif
756
757 static cmd_tbl_t cmd_mmc[] = {
758         U_BOOT_CMD_MKENT(info, 1, 0, do_mmcinfo, "", ""),
759         U_BOOT_CMD_MKENT(read, 4, 1, do_mmc_read, "", ""),
760         U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""),
761         U_BOOT_CMD_MKENT(erase, 3, 0, do_mmc_erase, "", ""),
762         U_BOOT_CMD_MKENT(rescan, 1, 1, do_mmc_rescan, "", ""),
763         U_BOOT_CMD_MKENT(part, 1, 1, do_mmc_part, "", ""),
764         U_BOOT_CMD_MKENT(dev, 3, 0, do_mmc_dev, "", ""),
765         U_BOOT_CMD_MKENT(list, 1, 1, do_mmc_list, "", ""),
766         U_BOOT_CMD_MKENT(hwpartition, 28, 0, do_mmc_hwpartition, "", ""),
767 #ifdef CONFIG_SUPPORT_EMMC_BOOT
768         U_BOOT_CMD_MKENT(bootbus, 5, 0, do_mmc_bootbus, "", ""),
769         U_BOOT_CMD_MKENT(bootpart-resize, 4, 0, do_mmc_boot_resize, "", ""),
770         U_BOOT_CMD_MKENT(partconf, 5, 0, do_mmc_partconf, "", ""),
771         U_BOOT_CMD_MKENT(rst-function, 3, 0, do_mmc_rst_func, "", ""),
772 #endif
773 #ifdef CONFIG_SUPPORT_EMMC_RPMB
774         U_BOOT_CMD_MKENT(rpmb, CONFIG_SYS_MAXARGS, 1, do_mmcrpmb, "", ""),
775 #endif
776         U_BOOT_CMD_MKENT(setdsr, 2, 0, do_mmc_setdsr, "", ""),
777 #ifdef CONFIG_CMD_BKOPS_ENABLE
778         U_BOOT_CMD_MKENT(bkops-enable, 2, 0, do_mmc_bkops_enable, "", ""),
779 #endif
780 };
781
782 static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
783 {
784         cmd_tbl_t *cp;
785
786         cp = find_cmd_tbl(argv[1], cmd_mmc, ARRAY_SIZE(cmd_mmc));
787
788         /* Drop the mmc command */
789         argc--;
790         argv++;
791
792         if (cp == NULL || argc > cp->maxargs)
793                 return CMD_RET_USAGE;
794         if (flag == CMD_FLAG_REPEAT && !cp->repeatable)
795                 return CMD_RET_SUCCESS;
796
797         if (curr_device < 0) {
798                 if (get_mmc_num() > 0) {
799                         curr_device = 0;
800                 } else {
801                         puts("No MMC device available\n");
802                         return CMD_RET_FAILURE;
803                 }
804         }
805         return cp->cmd(cmdtp, flag, argc, argv);
806 }
807
808 U_BOOT_CMD(
809         mmc, 29, 1, do_mmcops,
810         "MMC sub system",
811         "info - display info of the current MMC device\n"
812         "mmc read addr blk# cnt\n"
813         "mmc write addr blk# cnt\n"
814         "mmc erase blk# cnt\n"
815         "mmc rescan\n"
816         "mmc part - lists available partition on current mmc device\n"
817         "mmc dev [dev] [part] - show or set current mmc device [partition]\n"
818         "mmc list - lists available devices\n"
819         "mmc hwpartition [args...] - does hardware partitioning\n"
820         "  arguments (sizes in 512-byte blocks):\n"
821         "    [user [enh start cnt] [wrrel {on|off}]] - sets user data area attributes\n"
822         "    [gp1|gp2|gp3|gp4 cnt [enh] [wrrel {on|off}]] - general purpose partition\n"
823         "    [check|set|complete] - mode, complete set partitioning completed\n"
824         "  WARNING: Partitioning is a write-once setting once it is set to complete.\n"
825         "  Power cycling is required to initialize partitions after set to complete.\n"
826 #ifdef CONFIG_SUPPORT_EMMC_BOOT
827         "mmc bootbus dev boot_bus_width reset_boot_bus_width boot_mode\n"
828         " - Set the BOOT_BUS_WIDTH field of the specified device\n"
829         "mmc bootpart-resize <dev> <boot part size MB> <RPMB part size MB>\n"
830         " - Change sizes of boot and RPMB partitions of specified device\n"
831         "mmc partconf dev boot_ack boot_partition partition_access\n"
832         " - Change the bits of the PARTITION_CONFIG field of the specified device\n"
833         "mmc rst-function dev value\n"
834         " - Change the RST_n_FUNCTION field of the specified device\n"
835         "   WARNING: This is a write-once field and 0 / 1 / 2 are the only valid values.\n"
836 #endif
837 #ifdef CONFIG_SUPPORT_EMMC_RPMB
838         "mmc rpmb read addr blk# cnt [address of auth-key] - block size is 256 bytes\n"
839         "mmc rpmb write addr blk# cnt <address of auth-key> - block size is 256 bytes\n"
840         "mmc rpmb key <address of auth-key> - program the RPMB authentication key.\n"
841         "mmc rpmb counter - read the value of the write counter\n"
842 #endif
843         "mmc setdsr <value> - set DSR register value\n"
844 #ifdef CONFIG_CMD_BKOPS_ENABLE
845         "mmc bkops-enable <dev> - enable background operations handshake on device\n"
846         "   WARNING: This is a write-once setting.\n"
847 #endif
848         );
849
850 /* Old command kept for compatibility. Same as 'mmc info' */
851 U_BOOT_CMD(
852         mmcinfo, 1, 0, do_mmcinfo,
853         "display MMC info",
854         "- display info of the current MMC device"
855 );