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