1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2003
4 * Kyle Harris, kharris@nexus-tech.net
5 */
6
7#include <common.h>
8#include <blk.h>
9#include <command.h>
10#include <console.h>
11#include <display_options.h>
12#include <memalign.h>
13#include <mmc.h>
14#include <part.h>
15#include <sparse_format.h>
16#include <image-sparse.h>
17
18static int curr_device = -1;
19
20static void print_mmcinfo(struct mmc *mmc)
21{
22	int i;
23
24	printf("Device: %s\n", mmc->cfg->name);
25	printf("Manufacturer ID: %x\n", mmc->cid[0] >> 24);
26	if (IS_SD(mmc)) {
27		printf("OEM: %x\n", (mmc->cid[0] >> 8) & 0xffff);
28		printf("Name: %c%c%c%c%c \n", mmc->cid[0] & 0xff,
29		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
30		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
31	} else {
32		printf("OEM: %x\n", (mmc->cid[0] >> 8) & 0xff);
33		printf("Name: %c%c%c%c%c%c \n", mmc->cid[0] & 0xff,
34		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
35		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
36		(mmc->cid[2] >> 24));
37	}
38
39	printf("Bus Speed: %d\n", mmc->clock);
40#if CONFIG_IS_ENABLED(MMC_VERBOSE)
41	printf("Mode: %s\n", mmc_mode_name(mmc->selected_mode));
42	mmc_dump_capabilities("card capabilities", mmc->card_caps);
43	mmc_dump_capabilities("host capabilities", mmc->host_caps);
44#endif
45	printf("Rd Block Len: %d\n", mmc->read_bl_len);
46
47	printf("%s version %d.%d", IS_SD(mmc) ? "SD" : "MMC",
48			EXTRACT_SDMMC_MAJOR_VERSION(mmc->version),
49			EXTRACT_SDMMC_MINOR_VERSION(mmc->version));
50	if (EXTRACT_SDMMC_CHANGE_VERSION(mmc->version) != 0)
51		printf(".%d", EXTRACT_SDMMC_CHANGE_VERSION(mmc->version));
52	printf("\n");
53
54	printf("High Capacity: %s\n", mmc->high_capacity ? "Yes" : "No");
55	puts("Capacity: ");
56	print_size(mmc->capacity, "\n");
57
58	printf("Bus Width: %d-bit%s\n", mmc->bus_width,
59			mmc->ddr_mode ? " DDR" : "");
60
61#if CONFIG_IS_ENABLED(MMC_WRITE)
62	puts("Erase Group Size: ");
63	print_size(((u64)mmc->erase_grp_size) << 9, "\n");
64#endif
65
66	if (!IS_SD(mmc) && mmc->version >= MMC_VERSION_4_41) {
67		bool has_enh = (mmc->part_support & ENHNCD_SUPPORT) != 0;
68		bool usr_enh = has_enh && (mmc->part_attr & EXT_CSD_ENH_USR);
69		ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
70		u8 wp;
71		int ret;
72
73#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
74		puts("HC WP Group Size: ");
75		print_size(((u64)mmc->hc_wp_grp_size) << 9, "\n");
76#endif
77
78		puts("User Capacity: ");
79		print_size(mmc->capacity_user, usr_enh ? " ENH" : "");
80		if (mmc->wr_rel_set & EXT_CSD_WR_DATA_REL_USR)
81			puts(" WRREL\n");
82		else
83			putc('\n');
84		if (usr_enh) {
85			puts("User Enhanced Start: ");
86			print_size(mmc->enh_user_start, "\n");
87			puts("User Enhanced Size: ");
88			print_size(mmc->enh_user_size, "\n");
89		}
90		puts("Boot Capacity: ");
91		print_size(mmc->capacity_boot, has_enh ? " ENH\n" : "\n");
92		puts("RPMB Capacity: ");
93		print_size(mmc->capacity_rpmb, has_enh ? " ENH\n" : "\n");
94
95		for (i = 0; i < ARRAY_SIZE(mmc->capacity_gp); i++) {
96			bool is_enh = has_enh &&
97				(mmc->part_attr & EXT_CSD_ENH_GP(i));
98			if (mmc->capacity_gp[i]) {
99				printf("GP%i Capacity: ", i+1);
100				print_size(mmc->capacity_gp[i],
101					   is_enh ? " ENH" : "");
102				if (mmc->wr_rel_set & EXT_CSD_WR_DATA_REL_GP(i))
103					puts(" WRREL\n");
104				else
105					putc('\n');
106			}
107		}
108		ret = mmc_send_ext_csd(mmc, ext_csd);
109		if (ret)
110			return;
111		wp = ext_csd[EXT_CSD_BOOT_WP_STATUS];
112		for (i = 0; i < 2; ++i) {
113			printf("Boot area %d is ", i);
114			switch (wp & 3) {
115			case 0:
116				printf("not write protected\n");
117				break;
118			case 1:
119				printf("power on protected\n");
120				break;
121			case 2:
122				printf("permanently protected\n");
123				break;
124			default:
125				printf("in reserved protection state\n");
126				break;
127			}
128			wp >>= 2;
129		}
130	}
131}
132
133static struct mmc *__init_mmc_device(int dev, bool force_init,
134				     enum bus_mode speed_mode)
135{
136	struct mmc *mmc;
137	mmc = find_mmc_device(dev);
138	if (!mmc) {
139		printf("no mmc device at slot %x\n", dev);
140		return NULL;
141	}
142
143	if (!mmc_getcd(mmc))
144		force_init = true;
145
146	if (force_init)
147		mmc->has_init = 0;
148
149	if (IS_ENABLED(CONFIG_MMC_SPEED_MODE_SET))
150		mmc->user_speed_mode = speed_mode;
151
152	if (mmc_init(mmc))
153		return NULL;
154
155#ifdef CONFIG_BLOCK_CACHE
156	struct blk_desc *bd = mmc_get_blk_desc(mmc);
157	blkcache_invalidate(bd->uclass_id, bd->devnum);
158#endif
159
160	return mmc;
161}
162
163static struct mmc *init_mmc_device(int dev, bool force_init)
164{
165	return __init_mmc_device(dev, force_init, MMC_MODES_END);
166}
167
168static int do_mmcinfo(struct cmd_tbl *cmdtp, int flag, int argc,
169		      char *const argv[])
170{
171	struct mmc *mmc;
172
173	if (curr_device < 0) {
174		if (get_mmc_num() > 0)
175			curr_device = 0;
176		else {
177			puts("No MMC device available\n");
178			return CMD_RET_FAILURE;
179		}
180	}
181
182	mmc = init_mmc_device(curr_device, false);
183	if (!mmc)
184		return CMD_RET_FAILURE;
185
186	print_mmcinfo(mmc);
187	return CMD_RET_SUCCESS;
188}
189
190#if CONFIG_IS_ENABLED(CMD_MMC_RPMB)
191static int confirm_key_prog(void)
192{
193	puts("Warning: Programming authentication key can be done only once !\n"
194	     "         Use this command only if you are sure of what you are doing,\n"
195	     "Really perform the key programming? <y/N> ");
196	if (confirm_yesno())
197		return 1;
198
199	puts("Authentication key programming aborted\n");
200	return 0;
201}
202
203static int do_mmcrpmb_key(struct cmd_tbl *cmdtp, int flag,
204			  int argc, char *const argv[])
205{
206	void *key_addr;
207	struct mmc *mmc = find_mmc_device(curr_device);
208
209	if (argc != 2)
210		return CMD_RET_USAGE;
211
212	key_addr = (void *)hextoul(argv[1], NULL);
213	if (!confirm_key_prog())
214		return CMD_RET_FAILURE;
215	if (mmc_rpmb_set_key(mmc, key_addr)) {
216		printf("ERROR - Key already programmed ?\n");
217		return CMD_RET_FAILURE;
218	}
219	return CMD_RET_SUCCESS;
220}
221
222static int do_mmcrpmb_read(struct cmd_tbl *cmdtp, int flag,
223			   int argc, char *const argv[])
224{
225	u16 blk, cnt;
226	void *addr;
227	int n;
228	void *key_addr = NULL;
229	struct mmc *mmc = find_mmc_device(curr_device);
230
231	if (argc < 4)
232		return CMD_RET_USAGE;
233
234	addr = (void *)hextoul(argv[1], NULL);
235	blk = hextoul(argv[2], NULL);
236	cnt = hextoul(argv[3], NULL);
237
238	if (argc == 5)
239		key_addr = (void *)hextoul(argv[4], NULL);
240
241	printf("\nMMC RPMB read: dev # %d, block # %d, count %d ... ",
242	       curr_device, blk, cnt);
243	n =  mmc_rpmb_read(mmc, addr, blk, cnt, key_addr);
244
245	printf("%d RPMB blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR");
246	if (n != cnt)
247		return CMD_RET_FAILURE;
248	return CMD_RET_SUCCESS;
249}
250
251static int do_mmcrpmb_write(struct cmd_tbl *cmdtp, int flag,
252			    int argc, char *const argv[])
253{
254	u16 blk, cnt;
255	void *addr;
256	int n;
257	void *key_addr;
258	struct mmc *mmc = find_mmc_device(curr_device);
259
260	if (argc != 5)
261		return CMD_RET_USAGE;
262
263	addr = (void *)hextoul(argv[1], NULL);
264	blk = hextoul(argv[2], NULL);
265	cnt = hextoul(argv[3], NULL);
266	key_addr = (void *)hextoul(argv[4], NULL);
267
268	printf("\nMMC RPMB write: dev # %d, block # %d, count %d ... ",
269	       curr_device, blk, cnt);
270	n =  mmc_rpmb_write(mmc, addr, blk, cnt, key_addr);
271
272	printf("%d RPMB blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR");
273	if (n != cnt)
274		return CMD_RET_FAILURE;
275	return CMD_RET_SUCCESS;
276}
277
278static int do_mmcrpmb_counter(struct cmd_tbl *cmdtp, int flag,
279			      int argc, char *const argv[])
280{
281	unsigned long counter;
282	struct mmc *mmc = find_mmc_device(curr_device);
283
284	if (mmc_rpmb_get_counter(mmc, &counter))
285		return CMD_RET_FAILURE;
286	printf("RPMB Write counter= %lx\n", counter);
287	return CMD_RET_SUCCESS;
288}
289
290static struct cmd_tbl cmd_rpmb[] = {
291	U_BOOT_CMD_MKENT(key, 2, 0, do_mmcrpmb_key, "", ""),
292	U_BOOT_CMD_MKENT(read, 5, 1, do_mmcrpmb_read, "", ""),
293	U_BOOT_CMD_MKENT(write, 5, 0, do_mmcrpmb_write, "", ""),
294	U_BOOT_CMD_MKENT(counter, 1, 1, do_mmcrpmb_counter, "", ""),
295};
296
297static int do_mmcrpmb(struct cmd_tbl *cmdtp, int flag,
298		      int argc, char *const argv[])
299{
300	struct cmd_tbl *cp;
301	struct mmc *mmc;
302	char original_part;
303	int ret;
304
305	cp = find_cmd_tbl(argv[1], cmd_rpmb, ARRAY_SIZE(cmd_rpmb));
306
307	/* Drop the rpmb subcommand */
308	argc--;
309	argv++;
310
311	if (cp == NULL || argc > cp->maxargs)
312		return CMD_RET_USAGE;
313	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
314		return CMD_RET_SUCCESS;
315
316	mmc = init_mmc_device(curr_device, false);
317	if (!mmc)
318		return CMD_RET_FAILURE;
319
320	if (!(mmc->version & MMC_VERSION_MMC)) {
321		printf("It is not an eMMC device\n");
322		return CMD_RET_FAILURE;
323	}
324	if (mmc->version < MMC_VERSION_4_41) {
325		printf("RPMB not supported before version 4.41\n");
326		return CMD_RET_FAILURE;
327	}
328	/* Switch to the RPMB partition */
329#ifndef CONFIG_BLK
330	original_part = mmc->block_dev.hwpart;
331#else
332	original_part = mmc_get_blk_desc(mmc)->hwpart;
333#endif
334	if (blk_select_hwpart_devnum(UCLASS_MMC, curr_device, MMC_PART_RPMB) !=
335	    0)
336		return CMD_RET_FAILURE;
337	ret = cp->cmd(cmdtp, flag, argc, argv);
338
339	/* Return to original partition */
340	if (blk_select_hwpart_devnum(UCLASS_MMC, curr_device, original_part) !=
341	    0)
342		return CMD_RET_FAILURE;
343	return ret;
344}
345#endif
346
347static int do_mmc_read(struct cmd_tbl *cmdtp, int flag,
348		       int argc, char *const argv[])
349{
350	struct mmc *mmc;
351	u32 blk, cnt, n;
352	void *addr;
353
354	if (argc != 4)
355		return CMD_RET_USAGE;
356
357	addr = (void *)hextoul(argv[1], NULL);
358	blk = hextoul(argv[2], NULL);
359	cnt = hextoul(argv[3], NULL);
360
361	mmc = init_mmc_device(curr_device, false);
362	if (!mmc)
363		return CMD_RET_FAILURE;
364
365	printf("\nMMC read: dev # %d, block # %d, count %d ... ",
366	       curr_device, blk, cnt);
367
368	n = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr);
369	printf("%d blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR");
370
371	return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
372}
373
374#if CONFIG_IS_ENABLED(CMD_MMC_SWRITE)
375static lbaint_t mmc_sparse_write(struct sparse_storage *info, lbaint_t blk,
376				 lbaint_t blkcnt, const void *buffer)
377{
378	struct blk_desc *dev_desc = info->priv;
379
380	return blk_dwrite(dev_desc, blk, blkcnt, buffer);
381}
382
383static lbaint_t mmc_sparse_reserve(struct sparse_storage *info,
384				   lbaint_t blk, lbaint_t blkcnt)
385{
386	return blkcnt;
387}
388
389static int do_mmc_sparse_write(struct cmd_tbl *cmdtp, int flag,
390			       int argc, char *const argv[])
391{
392	struct sparse_storage sparse;
393	struct blk_desc *dev_desc;
394	struct mmc *mmc;
395	char dest[11];
396	void *addr;
397	u32 blk;
398
399	if (argc != 3)
400		return CMD_RET_USAGE;
401
402	addr = (void *)hextoul(argv[1], NULL);
403	blk = hextoul(argv[2], NULL);
404
405	if (!is_sparse_image(addr)) {
406		printf("Not a sparse image\n");
407		return CMD_RET_FAILURE;
408	}
409
410	mmc = init_mmc_device(curr_device, false);
411	if (!mmc)
412		return CMD_RET_FAILURE;
413
414	printf("\nMMC Sparse write: dev # %d, block # %d ... ",
415	       curr_device, blk);
416
417	if (mmc_getwp(mmc) == 1) {
418		printf("Error: card is write protected!\n");
419		return CMD_RET_FAILURE;
420	}
421
422	dev_desc = mmc_get_blk_desc(mmc);
423	sparse.priv = dev_desc;
424	sparse.blksz = 512;
425	sparse.start = blk;
426	sparse.size = dev_desc->lba - blk;
427	sparse.write = mmc_sparse_write;
428	sparse.reserve = mmc_sparse_reserve;
429	sparse.mssg = NULL;
430	sprintf(dest, "0x" LBAF, sparse.start * sparse.blksz);
431
432	if (write_sparse_image(&sparse, dest, addr, NULL))
433		return CMD_RET_FAILURE;
434	else
435		return CMD_RET_SUCCESS;
436}
437#endif
438
439#if CONFIG_IS_ENABLED(MMC_WRITE)
440static int do_mmc_write(struct cmd_tbl *cmdtp, int flag,
441			int argc, char *const argv[])
442{
443	struct mmc *mmc;
444	u32 blk, cnt, n;
445	void *addr;
446
447	if (argc != 4)
448		return CMD_RET_USAGE;
449
450	addr = (void *)hextoul(argv[1], NULL);
451	blk = hextoul(argv[2], NULL);
452	cnt = hextoul(argv[3], NULL);
453
454	mmc = init_mmc_device(curr_device, false);
455	if (!mmc)
456		return CMD_RET_FAILURE;
457
458	printf("\nMMC write: dev # %d, block # %d, count %d ... ",
459	       curr_device, blk, cnt);
460
461	if (mmc_getwp(mmc) == 1) {
462		printf("Error: card is write protected!\n");
463		return CMD_RET_FAILURE;
464	}
465	n = blk_dwrite(mmc_get_blk_desc(mmc), blk, cnt, addr);
466	printf("%d blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR");
467
468	return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
469}
470
471static int do_mmc_erase(struct cmd_tbl *cmdtp, int flag,
472			int argc, char *const argv[])
473{
474	struct mmc *mmc;
475	u32 blk, cnt, n;
476
477	if (argc != 3)
478		return CMD_RET_USAGE;
479
480	blk = hextoul(argv[1], NULL);
481	cnt = hextoul(argv[2], NULL);
482
483	mmc = init_mmc_device(curr_device, false);
484	if (!mmc)
485		return CMD_RET_FAILURE;
486
487	printf("\nMMC erase: dev # %d, block # %d, count %d ... ",
488	       curr_device, blk, cnt);
489
490	if (mmc_getwp(mmc) == 1) {
491		printf("Error: card is write protected!\n");
492		return CMD_RET_FAILURE;
493	}
494	n = blk_derase(mmc_get_blk_desc(mmc), blk, cnt);
495	printf("%d blocks erased: %s\n", n, (n == cnt) ? "OK" : "ERROR");
496
497	return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
498}
499#endif
500
501static int do_mmc_rescan(struct cmd_tbl *cmdtp, int flag,
502			 int argc, char *const argv[])
503{
504	struct mmc *mmc;
505
506	if (argc == 1) {
507		mmc = init_mmc_device(curr_device, true);
508	} else if (argc == 2) {
509		enum bus_mode speed_mode;
510
511		speed_mode = (int)dectoul(argv[1], NULL);
512		mmc = __init_mmc_device(curr_device, true, speed_mode);
513	} else {
514		return CMD_RET_USAGE;
515	}
516
517	if (!mmc)
518		return CMD_RET_FAILURE;
519
520	return CMD_RET_SUCCESS;
521}
522
523static int do_mmc_part(struct cmd_tbl *cmdtp, int flag,
524		       int argc, char *const argv[])
525{
526	struct blk_desc *mmc_dev;
527	struct mmc *mmc;
528
529	mmc = init_mmc_device(curr_device, false);
530	if (!mmc)
531		return CMD_RET_FAILURE;
532
533	mmc_dev = blk_get_devnum_by_uclass_id(UCLASS_MMC, curr_device);
534	if (mmc_dev != NULL && mmc_dev->type != DEV_TYPE_UNKNOWN) {
535		part_print(mmc_dev);
536		return CMD_RET_SUCCESS;
537	}
538
539	puts("get mmc type error!\n");
540	return CMD_RET_FAILURE;
541}
542
543static int do_mmc_dev(struct cmd_tbl *cmdtp, int flag,
544		      int argc, char *const argv[])
545{
546	int dev, part = 0, ret;
547	struct mmc *mmc;
548
549	if (argc == 1) {
550		dev = curr_device;
551		mmc = init_mmc_device(dev, true);
552	} else if (argc == 2) {
553		dev = (int)dectoul(argv[1], NULL);
554		mmc = init_mmc_device(dev, true);
555	} else if (argc == 3) {
556		dev = (int)dectoul(argv[1], NULL);
557		part = (int)dectoul(argv[2], NULL);
558		if (part > PART_ACCESS_MASK) {
559			printf("#part_num shouldn't be larger than %d\n",
560			       PART_ACCESS_MASK);
561			return CMD_RET_FAILURE;
562		}
563		mmc = init_mmc_device(dev, true);
564	} else if (argc == 4) {
565		enum bus_mode speed_mode;
566
567		dev = (int)dectoul(argv[1], NULL);
568		part = (int)dectoul(argv[2], NULL);
569		if (part > PART_ACCESS_MASK) {
570			printf("#part_num shouldn't be larger than %d\n",
571			       PART_ACCESS_MASK);
572			return CMD_RET_FAILURE;
573		}
574		speed_mode = (int)dectoul(argv[3], NULL);
575		mmc = __init_mmc_device(dev, true, speed_mode);
576	} else {
577		return CMD_RET_USAGE;
578	}
579
580	if (!mmc)
581		return CMD_RET_FAILURE;
582
583	ret = blk_select_hwpart_devnum(UCLASS_MMC, dev, part);
584	printf("switch to partitions #%d, %s\n",
585	       part, (!ret) ? "OK" : "ERROR");
586	if (ret)
587		return 1;
588
589	curr_device = dev;
590	if (mmc->part_config == MMCPART_NOAVAILABLE)
591		printf("mmc%d is current device\n", curr_device);
592	else
593		printf("mmc%d(part %d) is current device\n",
594		       curr_device, mmc_get_blk_desc(mmc)->hwpart);
595
596	return CMD_RET_SUCCESS;
597}
598
599static int do_mmc_list(struct cmd_tbl *cmdtp, int flag,
600		       int argc, char *const argv[])
601{
602	print_mmc_devices('\n');
603	return CMD_RET_SUCCESS;
604}
605
606#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
607static void parse_hwpart_user_enh_size(struct mmc *mmc,
608				       struct mmc_hwpart_conf *pconf,
609				       char *argv)
610{
611	int i, ret;
612
613	pconf->user.enh_size = 0;
614
615	if (!strcmp(argv, "-"))	{ /* The rest of eMMC */
616		ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
617		ret = mmc_send_ext_csd(mmc, ext_csd);
618		if (ret)
619			return;
620		/* The enh_size value is in 512B block units */
621		pconf->user.enh_size =
622			((ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 2] << 16) +
623			(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 1] << 8) +
624			ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]) * 1024 *
625			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
626			ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
627		pconf->user.enh_size -= pconf->user.enh_start;
628		for (i = 0; i < ARRAY_SIZE(mmc->capacity_gp); i++) {
629			/*
630			 * If the eMMC already has GP partitions set,
631			 * subtract their size from the maximum USER
632			 * partition size.
633			 *
634			 * Else, if the command was used to configure new
635			 * GP partitions, subtract their size from maximum
636			 * USER partition size.
637			 */
638			if (mmc->capacity_gp[i]) {
639				/* The capacity_gp is in 1B units */
640				pconf->user.enh_size -= mmc->capacity_gp[i] >> 9;
641			} else if (pconf->gp_part[i].size) {
642				/* The gp_part[].size is in 512B units */
643				pconf->user.enh_size -= pconf->gp_part[i].size;
644			}
645		}
646	} else {
647		pconf->user.enh_size = dectoul(argv, NULL);
648	}
649}
650
651static int parse_hwpart_user(struct mmc *mmc, struct mmc_hwpart_conf *pconf,
652			     int argc, char *const argv[])
653{
654	int i = 0;
655
656	memset(&pconf->user, 0, sizeof(pconf->user));
657
658	while (i < argc) {
659		if (!strcmp(argv[i], "enh")) {
660			if (i + 2 >= argc)
661				return -1;
662			pconf->user.enh_start =
663				dectoul(argv[i + 1], NULL);
664			parse_hwpart_user_enh_size(mmc, pconf, argv[i + 2]);
665			i += 3;
666		} else if (!strcmp(argv[i], "wrrel")) {
667			if (i + 1 >= argc)
668				return -1;
669			pconf->user.wr_rel_change = 1;
670			if (!strcmp(argv[i+1], "on"))
671				pconf->user.wr_rel_set = 1;
672			else if (!strcmp(argv[i+1], "off"))
673				pconf->user.wr_rel_set = 0;
674			else
675				return -1;
676			i += 2;
677		} else {
678			break;
679		}
680	}
681	return i;
682}
683
684static int parse_hwpart_gp(struct mmc_hwpart_conf *pconf, int pidx,
685			   int argc, char *const argv[])
686{
687	int i;
688
689	memset(&pconf->gp_part[pidx], 0, sizeof(pconf->gp_part[pidx]));
690
691	if (1 >= argc)
692		return -1;
693	pconf->gp_part[pidx].size = dectoul(argv[0], NULL);
694
695	i = 1;
696	while (i < argc) {
697		if (!strcmp(argv[i], "enh")) {
698			pconf->gp_part[pidx].enhanced = 1;
699			i += 1;
700		} else if (!strcmp(argv[i], "wrrel")) {
701			if (i + 1 >= argc)
702				return -1;
703			pconf->gp_part[pidx].wr_rel_change = 1;
704			if (!strcmp(argv[i+1], "on"))
705				pconf->gp_part[pidx].wr_rel_set = 1;
706			else if (!strcmp(argv[i+1], "off"))
707				pconf->gp_part[pidx].wr_rel_set = 0;
708			else
709				return -1;
710			i += 2;
711		} else {
712			break;
713		}
714	}
715	return i;
716}
717
718static int do_mmc_hwpartition(struct cmd_tbl *cmdtp, int flag,
719			      int argc, char *const argv[])
720{
721	struct mmc *mmc;
722	struct mmc_hwpart_conf pconf = { };
723	enum mmc_hwpart_conf_mode mode = MMC_HWPART_CONF_CHECK;
724	int i, r, pidx;
725
726	mmc = init_mmc_device(curr_device, false);
727	if (!mmc)
728		return CMD_RET_FAILURE;
729
730	if (IS_SD(mmc)) {
731		puts("SD doesn't support partitioning\n");
732		return CMD_RET_FAILURE;
733	}
734
735	if (argc < 1)
736		return CMD_RET_USAGE;
737	i = 1;
738	while (i < argc) {
739		if (!strcmp(argv[i], "user")) {
740			i++;
741			r = parse_hwpart_user(mmc, &pconf, argc - i, &argv[i]);
742			if (r < 0)
743				return CMD_RET_USAGE;
744			i += r;
745		} else if (!strncmp(argv[i], "gp", 2) &&
746			   strlen(argv[i]) == 3 &&
747			   argv[i][2] >= '1' && argv[i][2] <= '4') {
748			pidx = argv[i][2] - '1';
749			i++;
750			r = parse_hwpart_gp(&pconf, pidx, argc-i, &argv[i]);
751			if (r < 0)
752				return CMD_RET_USAGE;
753			i += r;
754		} else if (!strcmp(argv[i], "check")) {
755			mode = MMC_HWPART_CONF_CHECK;
756			i++;
757		} else if (!strcmp(argv[i], "set")) {
758			mode = MMC_HWPART_CONF_SET;
759			i++;
760		} else if (!strcmp(argv[i], "complete")) {
761			mode = MMC_HWPART_CONF_COMPLETE;
762			i++;
763		} else {
764			return CMD_RET_USAGE;
765		}
766	}
767
768	puts("Partition configuration:\n");
769	if (pconf.user.enh_size) {
770		puts("\tUser Enhanced Start: ");
771		print_size(((u64)pconf.user.enh_start) << 9, "\n");
772		puts("\tUser Enhanced Size: ");
773		print_size(((u64)pconf.user.enh_size) << 9, "\n");
774	} else {
775		puts("\tNo enhanced user data area\n");
776	}
777	if (pconf.user.wr_rel_change)
778		printf("\tUser partition write reliability: %s\n",
779		       pconf.user.wr_rel_set ? "on" : "off");
780	for (pidx = 0; pidx < 4; pidx++) {
781		if (pconf.gp_part[pidx].size) {
782			printf("\tGP%i Capacity: ", pidx+1);
783			print_size(((u64)pconf.gp_part[pidx].size) << 9,
784				   pconf.gp_part[pidx].enhanced ?
785				   " ENH\n" : "\n");
786		} else {
787			printf("\tNo GP%i partition\n", pidx+1);
788		}
789		if (pconf.gp_part[pidx].wr_rel_change)
790			printf("\tGP%i write reliability: %s\n", pidx+1,
791			       pconf.gp_part[pidx].wr_rel_set ? "on" : "off");
792	}
793
794	if (!mmc_hwpart_config(mmc, &pconf, mode)) {
795		if (mode == MMC_HWPART_CONF_COMPLETE)
796			puts("Partitioning successful, "
797			     "power-cycle to make effective\n");
798		return CMD_RET_SUCCESS;
799	} else {
800		puts("Failed!\n");
801		return CMD_RET_FAILURE;
802	}
803}
804#endif
805
806#ifdef CONFIG_SUPPORT_EMMC_BOOT
807static int do_mmc_bootbus(struct cmd_tbl *cmdtp, int flag,
808			  int argc, char *const argv[])
809{
810	int dev;
811	struct mmc *mmc;
812	u8 width, reset, mode;
813
814	if (argc != 5)
815		return CMD_RET_USAGE;
816	dev = dectoul(argv[1], NULL);
817	width = dectoul(argv[2], NULL);
818	reset = dectoul(argv[3], NULL);
819	mode = dectoul(argv[4], NULL);
820
821	mmc = init_mmc_device(dev, false);
822	if (!mmc)
823		return CMD_RET_FAILURE;
824
825	if (IS_SD(mmc)) {
826		puts("BOOT_BUS_WIDTH only exists on eMMC\n");
827		return CMD_RET_FAILURE;
828	}
829
830	/*
831	 * BOOT_BUS_CONDITIONS[177]
832	 * BOOT_MODE[4:3]
833	 * 0x0 : Use SDR + Backward compatible timing in boot operation
834	 * 0x1 : Use SDR + High Speed Timing in boot operation mode
835	 * 0x2 : Use DDR in boot operation
836	 * RESET_BOOT_BUS_CONDITIONS
837	 * 0x0 : Reset bus width to x1, SDR, Backward compatible
838	 * 0x1 : Retain BOOT_BUS_WIDTH and BOOT_MODE
839	 * BOOT_BUS_WIDTH
840	 * 0x0 : x1(sdr) or x4 (ddr) buswidth
841	 * 0x1 : x4(sdr/ddr) buswith
842	 * 0x2 : x8(sdr/ddr) buswith
843	 *
844	 */
845	if (width >= 0x3) {
846		printf("boot_bus_width %d is invalid\n", width);
847		return CMD_RET_FAILURE;
848	}
849
850	if (reset >= 0x2) {
851		printf("reset_boot_bus_width %d is invalid\n", reset);
852		return CMD_RET_FAILURE;
853	}
854
855	if (mode >= 0x3) {
856		printf("reset_boot_bus_width %d is invalid\n", mode);
857		return CMD_RET_FAILURE;
858	}
859
860	/* acknowledge to be sent during boot operation */
861	if (mmc_set_boot_bus_width(mmc, width, reset, mode)) {
862		puts("BOOT_BUS_WIDTH is failed to change.\n");
863		return CMD_RET_FAILURE;
864	}
865
866	printf("Set to BOOT_BUS_WIDTH = 0x%x, RESET = 0x%x, BOOT_MODE = 0x%x\n",
867			width, reset, mode);
868	return CMD_RET_SUCCESS;
869}
870
871static int do_mmc_boot_resize(struct cmd_tbl *cmdtp, int flag,
872			      int argc, char *const argv[])
873{
874	int dev;
875	struct mmc *mmc;
876	u32 bootsize, rpmbsize;
877
878	if (argc != 4)
879		return CMD_RET_USAGE;
880	dev = dectoul(argv[1], NULL);
881	bootsize = dectoul(argv[2], NULL);
882	rpmbsize = dectoul(argv[3], NULL);
883
884	mmc = init_mmc_device(dev, false);
885	if (!mmc)
886		return CMD_RET_FAILURE;
887
888	if (IS_SD(mmc)) {
889		printf("It is not an eMMC device\n");
890		return CMD_RET_FAILURE;
891	}
892
893	if (mmc_boot_partition_size_change(mmc, bootsize, rpmbsize)) {
894		printf("EMMC boot partition Size change Failed.\n");
895		return CMD_RET_FAILURE;
896	}
897
898	printf("EMMC boot partition Size %d MB\n", bootsize);
899	printf("EMMC RPMB partition Size %d MB\n", rpmbsize);
900	return CMD_RET_SUCCESS;
901}
902
903static int mmc_partconf_print(struct mmc *mmc, const char *varname)
904{
905	u8 ack, access, part;
906
907	if (mmc->part_config == MMCPART_NOAVAILABLE) {
908		printf("No part_config info for ver. 0x%x\n", mmc->version);
909		return CMD_RET_FAILURE;
910	}
911
912	access = EXT_CSD_EXTRACT_PARTITION_ACCESS(mmc->part_config);
913	ack = EXT_CSD_EXTRACT_BOOT_ACK(mmc->part_config);
914	part = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config);
915
916	if(varname)
917		env_set_hex(varname, part);
918
919	printf("EXT_CSD[179], PARTITION_CONFIG:\n"
920		"BOOT_ACK: 0x%x\n"
921		"BOOT_PARTITION_ENABLE: 0x%x\n"
922		"PARTITION_ACCESS: 0x%x\n", ack, part, access);
923
924	return CMD_RET_SUCCESS;
925}
926
927static int do_mmc_partconf(struct cmd_tbl *cmdtp, int flag,
928			   int argc, char *const argv[])
929{
930	int ret, dev;
931	struct mmc *mmc;
932	u8 ack, part_num, access;
933
934	if (argc != 2 && argc != 3 && argc != 5)
935		return CMD_RET_USAGE;
936
937	dev = dectoul(argv[1], NULL);
938
939	mmc = init_mmc_device(dev, false);
940	if (!mmc)
941		return CMD_RET_FAILURE;
942
943	if (IS_SD(mmc)) {
944		puts("PARTITION_CONFIG only exists on eMMC\n");
945		return CMD_RET_FAILURE;
946	}
947
948	if (argc == 2 || argc == 3)
949		return mmc_partconf_print(mmc, cmd_arg2(argc, argv));
950
951	ack = dectoul(argv[2], NULL);
952	part_num = dectoul(argv[3], NULL);
953	access = dectoul(argv[4], NULL);
954
955	/* acknowledge to be sent during boot operation */
956	ret = mmc_set_part_conf(mmc, ack, part_num, access);
957	if (ret != 0)
958		return CMD_RET_FAILURE;
959
960	return CMD_RET_SUCCESS;
961}
962
963static int do_mmc_rst_func(struct cmd_tbl *cmdtp, int flag,
964			   int argc, char *const argv[])
965{
966	int ret, dev;
967	struct mmc *mmc;
968	u8 enable;
969
970	/*
971	 * Set the RST_n_ENABLE bit of RST_n_FUNCTION
972	 * The only valid values are 0x0, 0x1 and 0x2 and writing
973	 * a value of 0x1 or 0x2 sets the value permanently.
974	 */
975	if (argc != 3)
976		return CMD_RET_USAGE;
977
978	dev = dectoul(argv[1], NULL);
979	enable = dectoul(argv[2], NULL);
980
981	if (enable > 2) {
982		puts("Invalid RST_n_ENABLE value\n");
983		return CMD_RET_USAGE;
984	}
985
986	mmc = init_mmc_device(dev, false);
987	if (!mmc)
988		return CMD_RET_FAILURE;
989
990	if (IS_SD(mmc)) {
991		puts("RST_n_FUNCTION only exists on eMMC\n");
992		return CMD_RET_FAILURE;
993	}
994
995	ret = mmc_set_rst_n_function(mmc, enable);
996	if (ret != 0)
997		return CMD_RET_FAILURE;
998
999	return CMD_RET_SUCCESS;
1000}
1001#endif
1002static int do_mmc_setdsr(struct cmd_tbl *cmdtp, int flag,
1003			 int argc, char *const argv[])
1004{
1005	struct mmc *mmc;
1006	u32 val;
1007	int ret;
1008
1009	if (argc != 2)
1010		return CMD_RET_USAGE;
1011	val = hextoul(argv[1], NULL);
1012
1013	mmc = find_mmc_device(curr_device);
1014	if (!mmc) {
1015		printf("no mmc device at slot %x\n", curr_device);
1016		return CMD_RET_FAILURE;
1017	}
1018	ret = mmc_set_dsr(mmc, val);
1019	printf("set dsr %s\n", (!ret) ? "OK, force rescan" : "ERROR");
1020	if (!ret) {
1021		mmc->has_init = 0;
1022		if (mmc_init(mmc))
1023			return CMD_RET_FAILURE;
1024		else
1025			return CMD_RET_SUCCESS;
1026	}
1027	return ret;
1028}
1029
1030#ifdef CONFIG_CMD_BKOPS_ENABLE
1031static int mmc_bkops_common(char *device, bool autobkops, bool enable)
1032{
1033	struct mmc *mmc;
1034	int dev;
1035
1036	dev = dectoul(device, NULL);
1037
1038	mmc = init_mmc_device(dev, false);
1039	if (!mmc)
1040		return CMD_RET_FAILURE;
1041
1042	if (IS_SD(mmc)) {
1043		puts("BKOPS_EN only exists on eMMC\n");
1044		return CMD_RET_FAILURE;
1045	}
1046
1047	return mmc_set_bkops_enable(mmc, autobkops, enable);
1048}
1049
1050static int do_mmc_bkops(struct cmd_tbl *cmdtp, int flag,
1051			int argc, char * const argv[])
1052{
1053	bool autobkops, enable;
1054
1055	if (argc != 4)
1056		return CMD_RET_USAGE;
1057
1058	if (!strcmp(argv[2], "manual"))
1059		autobkops = false;
1060	else if (!strcmp(argv[2], "auto"))
1061		autobkops = true;
1062	else
1063		return CMD_RET_FAILURE;
1064
1065	if (!strcmp(argv[3], "disable"))
1066		enable = false;
1067	else if (!strcmp(argv[3], "enable"))
1068		enable = true;
1069	else
1070		return CMD_RET_FAILURE;
1071
1072	return mmc_bkops_common(argv[1], autobkops, enable);
1073}
1074
1075static int do_mmc_bkops_enable(struct cmd_tbl *cmdtp, int flag,
1076			       int argc, char * const argv[])
1077{
1078	if (argc != 2)
1079		return CMD_RET_USAGE;
1080
1081	return mmc_bkops_common(argv[1], false, true);
1082}
1083#endif
1084
1085static int do_mmc_boot_wp(struct cmd_tbl *cmdtp, int flag,
1086			  int argc, char * const argv[])
1087{
1088	int err;
1089	struct mmc *mmc;
1090	int part;
1091
1092	mmc = init_mmc_device(curr_device, false);
1093	if (!mmc)
1094		return CMD_RET_FAILURE;
1095	if (IS_SD(mmc)) {
1096		printf("It is not an eMMC device\n");
1097		return CMD_RET_FAILURE;
1098	}
1099
1100	if (argc == 2) {
1101		part = dectoul(argv[1], NULL);
1102		err = mmc_boot_wp_single_partition(mmc, part);
1103	} else {
1104		err = mmc_boot_wp(mmc);
1105	}
1106
1107	if (err)
1108		return CMD_RET_FAILURE;
1109	printf("boot areas protected\n");
1110	return CMD_RET_SUCCESS;
1111}
1112
1113#if CONFIG_IS_ENABLED(CMD_MMC_REG)
1114static int do_mmc_reg(struct cmd_tbl *cmdtp, int flag,
1115		      int argc, char *const argv[])
1116{
1117	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
1118	struct mmc *mmc;
1119	int i, ret;
1120	u32 off;
1121
1122	if (argc < 3 || argc > 5)
1123		return CMD_RET_USAGE;
1124
1125	mmc = find_mmc_device(curr_device);
1126	if (!mmc) {
1127		printf("no mmc device at slot %x\n", curr_device);
1128		return CMD_RET_FAILURE;
1129	}
1130
1131	if (IS_SD(mmc)) {
1132		printf("SD registers are not supported\n");
1133		return CMD_RET_FAILURE;
1134	}
1135
1136	off = simple_strtoul(argv[3], NULL, 10);
1137	if (!strcmp(argv[2], "cid")) {
1138		if (off > 3)
1139			return CMD_RET_USAGE;
1140		printf("CID[%i]: 0x%08x\n", off, mmc->cid[off]);
1141		if (argv[4])
1142			env_set_hex(argv[4], mmc->cid[off]);
1143		return CMD_RET_SUCCESS;
1144	}
1145	if (!strcmp(argv[2], "csd")) {
1146		if (off > 3)
1147			return CMD_RET_USAGE;
1148		printf("CSD[%i]: 0x%08x\n", off, mmc->csd[off]);
1149		if (argv[4])
1150			env_set_hex(argv[4], mmc->csd[off]);
1151		return CMD_RET_SUCCESS;
1152	}
1153	if (!strcmp(argv[2], "dsr")) {
1154		printf("DSR: 0x%08x\n", mmc->dsr);
1155		if (argv[4])
1156			env_set_hex(argv[4], mmc->dsr);
1157		return CMD_RET_SUCCESS;
1158	}
1159	if (!strcmp(argv[2], "ocr")) {
1160		printf("OCR: 0x%08x\n", mmc->ocr);
1161		if (argv[4])
1162			env_set_hex(argv[4], mmc->ocr);
1163		return CMD_RET_SUCCESS;
1164	}
1165	if (!strcmp(argv[2], "rca")) {
1166		printf("RCA: 0x%08x\n", mmc->rca);
1167		if (argv[4])
1168			env_set_hex(argv[4], mmc->rca);
1169		return CMD_RET_SUCCESS;
1170	}
1171	if (!strcmp(argv[2], "extcsd") &&
1172	    mmc->version >= MMC_VERSION_4_41) {
1173		ret = mmc_send_ext_csd(mmc, ext_csd);
1174		if (ret)
1175			return CMD_RET_FAILURE;
1176		if (!strcmp(argv[3], "all")) {
1177			/* Dump the entire register */
1178			printf("EXT_CSD:");
1179			for (i = 0; i < MMC_MAX_BLOCK_LEN; i++) {
1180				if (!(i % 10))
1181					printf("\n%03i: ", i);
1182				printf(" %02x", ext_csd[i]);
1183			}
1184			printf("\n");
1185			return CMD_RET_SUCCESS;
1186		}
1187		off = simple_strtoul(argv[3], NULL, 10);
1188		if (off > 512)
1189			return CMD_RET_USAGE;
1190		printf("EXT_CSD[%i]: 0x%02x\n", off, ext_csd[off]);
1191		if (argv[4])
1192			env_set_hex(argv[4], ext_csd[off]);
1193		return CMD_RET_SUCCESS;
1194	}
1195
1196	return CMD_RET_FAILURE;
1197}
1198#endif
1199
1200static struct cmd_tbl cmd_mmc[] = {
1201	U_BOOT_CMD_MKENT(info, 1, 0, do_mmcinfo, "", ""),
1202	U_BOOT_CMD_MKENT(read, 4, 1, do_mmc_read, "", ""),
1203	U_BOOT_CMD_MKENT(wp, 2, 0, do_mmc_boot_wp, "", ""),
1204#if CONFIG_IS_ENABLED(MMC_WRITE)
1205	U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""),
1206	U_BOOT_CMD_MKENT(erase, 3, 0, do_mmc_erase, "", ""),
1207#endif
1208#if CONFIG_IS_ENABLED(CMD_MMC_SWRITE)
1209	U_BOOT_CMD_MKENT(swrite, 3, 0, do_mmc_sparse_write, "", ""),
1210#endif
1211	U_BOOT_CMD_MKENT(rescan, 2, 1, do_mmc_rescan, "", ""),
1212	U_BOOT_CMD_MKENT(part, 1, 1, do_mmc_part, "", ""),
1213	U_BOOT_CMD_MKENT(dev, 4, 0, do_mmc_dev, "", ""),
1214	U_BOOT_CMD_MKENT(list, 1, 1, do_mmc_list, "", ""),
1215#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
1216	U_BOOT_CMD_MKENT(hwpartition, 28, 0, do_mmc_hwpartition, "", ""),
1217#endif
1218#ifdef CONFIG_SUPPORT_EMMC_BOOT
1219	U_BOOT_CMD_MKENT(bootbus, 5, 0, do_mmc_bootbus, "", ""),
1220	U_BOOT_CMD_MKENT(bootpart-resize, 4, 0, do_mmc_boot_resize, "", ""),
1221	U_BOOT_CMD_MKENT(partconf, 5, 0, do_mmc_partconf, "", ""),
1222	U_BOOT_CMD_MKENT(rst-function, 3, 0, do_mmc_rst_func, "", ""),
1223#endif
1224#if CONFIG_IS_ENABLED(CMD_MMC_RPMB)
1225	U_BOOT_CMD_MKENT(rpmb, CONFIG_SYS_MAXARGS, 1, do_mmcrpmb, "", ""),
1226#endif
1227	U_BOOT_CMD_MKENT(setdsr, 2, 0, do_mmc_setdsr, "", ""),
1228#ifdef CONFIG_CMD_BKOPS_ENABLE
1229	U_BOOT_CMD_MKENT(bkops-enable, 2, 0, do_mmc_bkops_enable, "", ""),
1230	U_BOOT_CMD_MKENT(bkops, 4, 0, do_mmc_bkops, "", ""),
1231#endif
1232#if CONFIG_IS_ENABLED(CMD_MMC_REG)
1233	U_BOOT_CMD_MKENT(reg, 5, 0, do_mmc_reg, "", ""),
1234#endif
1235};
1236
1237static int do_mmcops(struct cmd_tbl *cmdtp, int flag, int argc,
1238		     char *const argv[])
1239{
1240	struct cmd_tbl *cp;
1241
1242	cp = find_cmd_tbl(argv[1], cmd_mmc, ARRAY_SIZE(cmd_mmc));
1243
1244	/* Drop the mmc command */
1245	argc--;
1246	argv++;
1247
1248	if (cp == NULL || argc > cp->maxargs)
1249		return CMD_RET_USAGE;
1250	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
1251		return CMD_RET_SUCCESS;
1252
1253	if (curr_device < 0) {
1254		if (get_mmc_num() > 0) {
1255			curr_device = 0;
1256		} else {
1257			puts("No MMC device available\n");
1258			return CMD_RET_FAILURE;
1259		}
1260	}
1261	return cp->cmd(cmdtp, flag, argc, argv);
1262}
1263
1264U_BOOT_CMD(
1265	mmc, 29, 1, do_mmcops,
1266	"MMC sub system",
1267	"info - display info of the current MMC device\n"
1268	"mmc read addr blk# cnt\n"
1269	"mmc write addr blk# cnt\n"
1270#if CONFIG_IS_ENABLED(CMD_MMC_SWRITE)
1271	"mmc swrite addr blk#\n"
1272#endif
1273	"mmc erase blk# cnt\n"
1274	"mmc rescan [mode]\n"
1275	"mmc part - lists available partition on current mmc device\n"
1276	"mmc dev [dev] [part] [mode] - show or set current mmc device [partition] and set mode\n"
1277	"  - the required speed mode is passed as the index from the following list\n"
1278	"    [MMC_LEGACY, MMC_HS, SD_HS, MMC_HS_52, MMC_DDR_52, UHS_SDR12, UHS_SDR25,\n"
1279	"    UHS_SDR50, UHS_DDR50, UHS_SDR104, MMC_HS_200, MMC_HS_400, MMC_HS_400_ES]\n"
1280	"mmc list - lists available devices\n"
1281	"mmc wp [PART] - power on write protect boot partitions\n"
1282	"  arguments:\n"
1283	"   PART - [0|1]\n"
1284	"       : 0 - first boot partition, 1 - second boot partition\n"
1285	"         if not assigned, write protect all boot partitions\n"
1286#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
1287	"mmc hwpartition <USER> <GP> <MODE> - does hardware partitioning\n"
1288	"  arguments (sizes in 512-byte blocks):\n"
1289	"   USER - <user> <enh> <start> <cnt> <wrrel> <{on|off}>\n"
1290	"	: sets user data area attributes\n"
1291	"   GP - <{gp1|gp2|gp3|gp4}> <cnt> <enh> <wrrel> <{on|off}>\n"
1292	"	: general purpose partition\n"
1293	"   MODE - <{check|set|complete}>\n"
1294	"	: mode, complete set partitioning completed\n"
1295	"  WARNING: Partitioning is a write-once setting once it is set to complete.\n"
1296	"  Power cycling is required to initialize partitions after set to complete.\n"
1297#endif
1298#ifdef CONFIG_SUPPORT_EMMC_BOOT
1299	"mmc bootbus <dev> <boot_bus_width> <reset_boot_bus_width> <boot_mode>\n"
1300	" - Set the BOOT_BUS_WIDTH field of the specified device\n"
1301	"mmc bootpart-resize <dev> <boot part size MB> <RPMB part size MB>\n"
1302	" - Change sizes of boot and RPMB partitions of specified device\n"
1303	"mmc partconf <dev> [[varname] | [<boot_ack> <boot_partition> <partition_access>]]\n"
1304	" - Show or change the bits of the PARTITION_CONFIG field of the specified device\n"
1305	"   If showing the bits, optionally store the boot_partition field into varname\n"
1306	"mmc rst-function <dev> <value>\n"
1307	" - Change the RST_n_FUNCTION field of the specified device\n"
1308	"   WARNING: This is a write-once field and 0 / 1 / 2 are the only valid values.\n"
1309#endif
1310#if CONFIG_IS_ENABLED(CMD_MMC_RPMB)
1311	"mmc rpmb read addr blk# cnt [address of auth-key] - block size is 256 bytes\n"
1312	"mmc rpmb write addr blk# cnt <address of auth-key> - block size is 256 bytes\n"
1313	"mmc rpmb key <address of auth-key> - program the RPMB authentication key.\n"
1314	"mmc rpmb counter - read the value of the write counter\n"
1315#endif
1316	"mmc setdsr <value> - set DSR register value\n"
1317#ifdef CONFIG_CMD_BKOPS_ENABLE
1318	"mmc bkops-enable <dev> - enable background operations handshake on device\n"
1319	"   WARNING: This is a write-once setting.\n"
1320	"mmc bkops <dev> [auto|manual] [enable|disable]\n"
1321	" - configure background operations handshake on device\n"
1322#endif
1323#if CONFIG_IS_ENABLED(CMD_MMC_REG)
1324	"mmc reg read <reg> <offset> [env] - read card register <reg> offset <offset>\n"
1325	"                                    (optionally into [env] variable)\n"
1326	" - reg: cid/csd/dsr/ocr/rca/extcsd\n"
1327	" - offset: for cid/csd [0..3], for extcsd [0..511,all]\n"
1328#endif
1329	);
1330
1331/* Old command kept for compatibility. Same as 'mmc info' */
1332U_BOOT_CMD(
1333	mmcinfo, 1, 0, do_mmcinfo,
1334	"display MMC info",
1335	"- display info of the current MMC device"
1336);
1337