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