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