mmc.c 23 KB

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