mtd.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * mtd.c
  4. *
  5. * Generic command to handle basic operations on any memory device.
  6. *
  7. * Copyright: Bootlin, 2018
  8. * Author: Miquèl Raynal <miquel.raynal@bootlin.com>
  9. */
  10. #include <command.h>
  11. #include <common.h>
  12. #include <console.h>
  13. #include <malloc.h>
  14. #include <mapmem.h>
  15. #include <mtd.h>
  16. #include <dm/devres.h>
  17. #include <linux/err.h>
  18. #include <linux/ctype.h>
  19. static struct mtd_info *get_mtd_by_name(const char *name)
  20. {
  21. struct mtd_info *mtd;
  22. mtd_probe_devices();
  23. mtd = get_mtd_device_nm(name);
  24. if (IS_ERR_OR_NULL(mtd))
  25. printf("MTD device %s not found, ret %ld\n", name,
  26. PTR_ERR(mtd));
  27. return mtd;
  28. }
  29. static uint mtd_len_to_pages(struct mtd_info *mtd, u64 len)
  30. {
  31. do_div(len, mtd->writesize);
  32. return len;
  33. }
  34. static bool mtd_is_aligned_with_min_io_size(struct mtd_info *mtd, u64 size)
  35. {
  36. return !do_div(size, mtd->writesize);
  37. }
  38. static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
  39. {
  40. return !do_div(size, mtd->erasesize);
  41. }
  42. static void mtd_dump_buf(const u8 *buf, uint len, uint offset)
  43. {
  44. int i, j;
  45. for (i = 0; i < len; ) {
  46. printf("0x%08x:\t", offset + i);
  47. for (j = 0; j < 8; j++)
  48. printf("%02x ", buf[i + j]);
  49. printf(" ");
  50. i += 8;
  51. for (j = 0; j < 8; j++)
  52. printf("%02x ", buf[i + j]);
  53. printf("\n");
  54. i += 8;
  55. }
  56. }
  57. static void mtd_dump_device_buf(struct mtd_info *mtd, u64 start_off,
  58. const u8 *buf, u64 len, bool woob)
  59. {
  60. bool has_pages = mtd->type == MTD_NANDFLASH ||
  61. mtd->type == MTD_MLCNANDFLASH;
  62. int npages = mtd_len_to_pages(mtd, len);
  63. uint page;
  64. if (has_pages) {
  65. for (page = 0; page < npages; page++) {
  66. u64 data_off = page * mtd->writesize;
  67. printf("\nDump %d data bytes from 0x%08llx:\n",
  68. mtd->writesize, start_off + data_off);
  69. mtd_dump_buf(&buf[data_off],
  70. mtd->writesize, start_off + data_off);
  71. if (woob) {
  72. u64 oob_off = page * mtd->oobsize;
  73. printf("Dump %d OOB bytes from page at 0x%08llx:\n",
  74. mtd->oobsize, start_off + data_off);
  75. mtd_dump_buf(&buf[len + oob_off],
  76. mtd->oobsize, 0);
  77. }
  78. }
  79. } else {
  80. printf("\nDump %lld data bytes from 0x%llx:\n",
  81. len, start_off);
  82. mtd_dump_buf(buf, len, start_off);
  83. }
  84. }
  85. static void mtd_show_parts(struct mtd_info *mtd, int level)
  86. {
  87. struct mtd_info *part;
  88. int i;
  89. list_for_each_entry(part, &mtd->partitions, node) {
  90. for (i = 0; i < level; i++)
  91. printf("\t");
  92. printf(" - 0x%012llx-0x%012llx : \"%s\"\n",
  93. part->offset, part->offset + part->size, part->name);
  94. mtd_show_parts(part, level + 1);
  95. }
  96. }
  97. static void mtd_show_device(struct mtd_info *mtd)
  98. {
  99. /* Device */
  100. printf("* %s\n", mtd->name);
  101. #if defined(CONFIG_DM)
  102. if (mtd->dev) {
  103. printf(" - device: %s\n", mtd->dev->name);
  104. printf(" - parent: %s\n", mtd->dev->parent->name);
  105. printf(" - driver: %s\n", mtd->dev->driver->name);
  106. }
  107. #endif
  108. if (IS_ENABLED(CONFIG_OF_CONTROL) && mtd->dev) {
  109. char buf[256];
  110. int res;
  111. res = ofnode_get_path(mtd_get_ofnode(mtd), buf, 256);
  112. printf(" - path: %s\n", res == 0 ? buf : "unavailable");
  113. }
  114. /* MTD device information */
  115. printf(" - type: ");
  116. switch (mtd->type) {
  117. case MTD_RAM:
  118. printf("RAM\n");
  119. break;
  120. case MTD_ROM:
  121. printf("ROM\n");
  122. break;
  123. case MTD_NORFLASH:
  124. printf("NOR flash\n");
  125. break;
  126. case MTD_NANDFLASH:
  127. printf("NAND flash\n");
  128. break;
  129. case MTD_DATAFLASH:
  130. printf("Data flash\n");
  131. break;
  132. case MTD_UBIVOLUME:
  133. printf("UBI volume\n");
  134. break;
  135. case MTD_MLCNANDFLASH:
  136. printf("MLC NAND flash\n");
  137. break;
  138. case MTD_ABSENT:
  139. default:
  140. printf("Unknown\n");
  141. break;
  142. }
  143. printf(" - block size: 0x%x bytes\n", mtd->erasesize);
  144. printf(" - min I/O: 0x%x bytes\n", mtd->writesize);
  145. if (mtd->oobsize) {
  146. printf(" - OOB size: %u bytes\n", mtd->oobsize);
  147. printf(" - OOB available: %u bytes\n", mtd->oobavail);
  148. }
  149. if (mtd->ecc_strength) {
  150. printf(" - ECC strength: %u bits\n", mtd->ecc_strength);
  151. printf(" - ECC step size: %u bytes\n", mtd->ecc_step_size);
  152. printf(" - bitflip threshold: %u bits\n",
  153. mtd->bitflip_threshold);
  154. }
  155. printf(" - 0x%012llx-0x%012llx : \"%s\"\n",
  156. mtd->offset, mtd->offset + mtd->size, mtd->name);
  157. /* MTD partitions, if any */
  158. mtd_show_parts(mtd, 1);
  159. }
  160. /* Logic taken from fs/ubifs/recovery.c:is_empty() */
  161. static bool mtd_oob_write_is_empty(struct mtd_oob_ops *op)
  162. {
  163. int i;
  164. for (i = 0; i < op->len; i++)
  165. if (op->datbuf[i] != 0xff)
  166. return false;
  167. for (i = 0; i < op->ooblen; i++)
  168. if (op->oobbuf[i] != 0xff)
  169. return false;
  170. return true;
  171. }
  172. static int do_mtd_list(struct cmd_tbl *cmdtp, int flag, int argc,
  173. char *const argv[])
  174. {
  175. struct mtd_info *mtd;
  176. int dev_nb = 0;
  177. /* Ensure all devices (and their partitions) are probed */
  178. mtd_probe_devices();
  179. printf("List of MTD devices:\n");
  180. mtd_for_each_device(mtd) {
  181. if (!mtd_is_partition(mtd))
  182. mtd_show_device(mtd);
  183. dev_nb++;
  184. }
  185. if (!dev_nb) {
  186. printf("No MTD device found\n");
  187. return CMD_RET_FAILURE;
  188. }
  189. return CMD_RET_SUCCESS;
  190. }
  191. static int mtd_special_write_oob(struct mtd_info *mtd, u64 off,
  192. struct mtd_oob_ops *io_op,
  193. bool write_empty_pages, bool woob)
  194. {
  195. int ret = 0;
  196. /*
  197. * By default, do not write an empty page.
  198. * Skip it by simulating a successful write.
  199. */
  200. if (!write_empty_pages && mtd_oob_write_is_empty(io_op)) {
  201. io_op->retlen = mtd->writesize;
  202. io_op->oobretlen = woob ? mtd->oobsize : 0;
  203. } else {
  204. ret = mtd_write_oob(mtd, off, io_op);
  205. }
  206. return ret;
  207. }
  208. static int do_mtd_io(struct cmd_tbl *cmdtp, int flag, int argc,
  209. char *const argv[])
  210. {
  211. bool dump, read, raw, woob, write_empty_pages, has_pages = false;
  212. u64 start_off, off, len, remaining, default_len;
  213. struct mtd_oob_ops io_op = {};
  214. uint user_addr = 0, npages;
  215. const char *cmd = argv[0];
  216. struct mtd_info *mtd;
  217. u32 oob_len;
  218. u8 *buf;
  219. int ret;
  220. if (argc < 2)
  221. return CMD_RET_USAGE;
  222. mtd = get_mtd_by_name(argv[1]);
  223. if (IS_ERR_OR_NULL(mtd))
  224. return CMD_RET_FAILURE;
  225. if (mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH)
  226. has_pages = true;
  227. dump = !strncmp(cmd, "dump", 4);
  228. read = dump || !strncmp(cmd, "read", 4);
  229. raw = strstr(cmd, ".raw");
  230. woob = strstr(cmd, ".oob");
  231. write_empty_pages = !has_pages || strstr(cmd, ".dontskipff");
  232. argc -= 2;
  233. argv += 2;
  234. if (!dump) {
  235. if (!argc) {
  236. ret = CMD_RET_USAGE;
  237. goto out_put_mtd;
  238. }
  239. user_addr = hextoul(argv[0], NULL);
  240. argc--;
  241. argv++;
  242. }
  243. start_off = argc > 0 ? hextoul(argv[0], NULL) : 0;
  244. if (!mtd_is_aligned_with_min_io_size(mtd, start_off)) {
  245. printf("Offset not aligned with a page (0x%x)\n",
  246. mtd->writesize);
  247. ret = CMD_RET_FAILURE;
  248. goto out_put_mtd;
  249. }
  250. default_len = dump ? mtd->writesize : mtd->size;
  251. len = argc > 1 ? hextoul(argv[1], NULL) : default_len;
  252. if (!mtd_is_aligned_with_min_io_size(mtd, len)) {
  253. len = round_up(len, mtd->writesize);
  254. printf("Size not on a page boundary (0x%x), rounding to 0x%llx\n",
  255. mtd->writesize, len);
  256. }
  257. remaining = len;
  258. npages = mtd_len_to_pages(mtd, len);
  259. oob_len = woob ? npages * mtd->oobsize : 0;
  260. if (dump)
  261. buf = kmalloc(len + oob_len, GFP_KERNEL);
  262. else
  263. buf = map_sysmem(user_addr, 0);
  264. if (!buf) {
  265. printf("Could not map/allocate the user buffer\n");
  266. ret = CMD_RET_FAILURE;
  267. goto out_put_mtd;
  268. }
  269. if (has_pages)
  270. printf("%s %lld byte(s) (%d page(s)) at offset 0x%08llx%s%s%s\n",
  271. read ? "Reading" : "Writing", len, npages, start_off,
  272. raw ? " [raw]" : "", woob ? " [oob]" : "",
  273. !read && write_empty_pages ? " [dontskipff]" : "");
  274. else
  275. printf("%s %lld byte(s) at offset 0x%08llx\n",
  276. read ? "Reading" : "Writing", len, start_off);
  277. io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB;
  278. io_op.len = has_pages ? mtd->writesize : len;
  279. io_op.ooblen = woob ? mtd->oobsize : 0;
  280. io_op.datbuf = buf;
  281. io_op.oobbuf = woob ? &buf[len] : NULL;
  282. /* Search for the first good block after the given offset */
  283. off = start_off;
  284. while (mtd_block_isbad(mtd, off))
  285. off += mtd->erasesize;
  286. /* Loop over the pages to do the actual read/write */
  287. while (remaining) {
  288. /* Skip the block if it is bad */
  289. if (mtd_is_aligned_with_block_size(mtd, off) &&
  290. mtd_block_isbad(mtd, off)) {
  291. off += mtd->erasesize;
  292. continue;
  293. }
  294. if (read)
  295. ret = mtd_read_oob(mtd, off, &io_op);
  296. else
  297. ret = mtd_special_write_oob(mtd, off, &io_op,
  298. write_empty_pages, woob);
  299. if (ret) {
  300. printf("Failure while %s at offset 0x%llx\n",
  301. read ? "reading" : "writing", off);
  302. break;
  303. }
  304. off += io_op.retlen;
  305. remaining -= io_op.retlen;
  306. io_op.datbuf += io_op.retlen;
  307. io_op.oobbuf += io_op.oobretlen;
  308. }
  309. if (!ret && dump)
  310. mtd_dump_device_buf(mtd, start_off, buf, len, woob);
  311. if (dump)
  312. kfree(buf);
  313. else
  314. unmap_sysmem(buf);
  315. if (ret) {
  316. printf("%s on %s failed with error %d\n",
  317. read ? "Read" : "Write", mtd->name, ret);
  318. ret = CMD_RET_FAILURE;
  319. } else {
  320. ret = CMD_RET_SUCCESS;
  321. }
  322. out_put_mtd:
  323. put_mtd_device(mtd);
  324. return ret;
  325. }
  326. static int do_mtd_erase(struct cmd_tbl *cmdtp, int flag, int argc,
  327. char *const argv[])
  328. {
  329. struct erase_info erase_op = {};
  330. struct mtd_info *mtd;
  331. u64 off, len;
  332. bool scrub;
  333. int ret = 0;
  334. if (argc < 2)
  335. return CMD_RET_USAGE;
  336. mtd = get_mtd_by_name(argv[1]);
  337. if (IS_ERR_OR_NULL(mtd))
  338. return CMD_RET_FAILURE;
  339. scrub = strstr(argv[0], ".dontskipbad");
  340. argc -= 2;
  341. argv += 2;
  342. off = argc > 0 ? hextoul(argv[0], NULL) : 0;
  343. len = argc > 1 ? hextoul(argv[1], NULL) : mtd->size;
  344. if (!mtd_is_aligned_with_block_size(mtd, off)) {
  345. printf("Offset not aligned with a block (0x%x)\n",
  346. mtd->erasesize);
  347. ret = CMD_RET_FAILURE;
  348. goto out_put_mtd;
  349. }
  350. if (!mtd_is_aligned_with_block_size(mtd, len)) {
  351. printf("Size not a multiple of a block (0x%x)\n",
  352. mtd->erasesize);
  353. ret = CMD_RET_FAILURE;
  354. goto out_put_mtd;
  355. }
  356. printf("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n",
  357. off, off + len - 1, mtd_div_by_eb(len, mtd));
  358. erase_op.mtd = mtd;
  359. erase_op.addr = off;
  360. erase_op.len = mtd->erasesize;
  361. erase_op.scrub = scrub;
  362. while (len) {
  363. ret = mtd_erase(mtd, &erase_op);
  364. if (ret) {
  365. /* Abort if its not a bad block error */
  366. if (ret != -EIO)
  367. break;
  368. printf("Skipping bad block at 0x%08llx\n",
  369. erase_op.addr);
  370. }
  371. len -= mtd->erasesize;
  372. erase_op.addr += mtd->erasesize;
  373. }
  374. if (ret && ret != -EIO)
  375. ret = CMD_RET_FAILURE;
  376. else
  377. ret = CMD_RET_SUCCESS;
  378. out_put_mtd:
  379. put_mtd_device(mtd);
  380. return ret;
  381. }
  382. static int do_mtd_bad(struct cmd_tbl *cmdtp, int flag, int argc,
  383. char *const argv[])
  384. {
  385. struct mtd_info *mtd;
  386. loff_t off;
  387. if (argc < 2)
  388. return CMD_RET_USAGE;
  389. mtd = get_mtd_by_name(argv[1]);
  390. if (IS_ERR_OR_NULL(mtd))
  391. return CMD_RET_FAILURE;
  392. if (!mtd_can_have_bb(mtd)) {
  393. printf("Only NAND-based devices can have bad blocks\n");
  394. goto out_put_mtd;
  395. }
  396. printf("MTD device %s bad blocks list:\n", mtd->name);
  397. for (off = 0; off < mtd->size; off += mtd->erasesize) {
  398. if (mtd_block_isbad(mtd, off))
  399. printf("\t0x%08llx\n", off);
  400. }
  401. out_put_mtd:
  402. put_mtd_device(mtd);
  403. return CMD_RET_SUCCESS;
  404. }
  405. #ifdef CONFIG_AUTO_COMPLETE
  406. static int mtd_name_complete(int argc, char *const argv[], char last_char,
  407. int maxv, char *cmdv[])
  408. {
  409. int len = 0, n_found = 0;
  410. struct mtd_info *mtd;
  411. argc--;
  412. argv++;
  413. if (argc > 1 ||
  414. (argc == 1 && (last_char == '\0' || isblank(last_char))))
  415. return 0;
  416. if (argc)
  417. len = strlen(argv[0]);
  418. mtd_for_each_device(mtd) {
  419. if (argc &&
  420. (len > strlen(mtd->name) ||
  421. strncmp(argv[0], mtd->name, len)))
  422. continue;
  423. if (n_found >= maxv - 2) {
  424. cmdv[n_found++] = "...";
  425. break;
  426. }
  427. cmdv[n_found++] = mtd->name;
  428. }
  429. cmdv[n_found] = NULL;
  430. return n_found;
  431. }
  432. #endif /* CONFIG_AUTO_COMPLETE */
  433. #ifdef CONFIG_SYS_LONGHELP
  434. static char mtd_help_text[] =
  435. "- generic operations on memory technology devices\n\n"
  436. "mtd list\n"
  437. "mtd read[.raw][.oob] <name> <addr> [<off> [<size>]]\n"
  438. "mtd dump[.raw][.oob] <name> [<off> [<size>]]\n"
  439. "mtd write[.raw][.oob][.dontskipff] <name> <addr> [<off> [<size>]]\n"
  440. "mtd erase[.dontskipbad] <name> [<off> [<size>]]\n"
  441. "\n"
  442. "Specific functions:\n"
  443. "mtd bad <name>\n"
  444. "\n"
  445. "With:\n"
  446. "\t<name>: NAND partition/chip name (or corresponding DM device name or OF path)\n"
  447. "\t<addr>: user address from/to which data will be retrieved/stored\n"
  448. "\t<off>: offset in <name> in bytes (default: start of the part)\n"
  449. "\t\t* must be block-aligned for erase\n"
  450. "\t\t* must be page-aligned otherwise\n"
  451. "\t<size>: length of the operation in bytes (default: the entire device)\n"
  452. "\t\t* must be a multiple of a block for erase\n"
  453. "\t\t* must be a multiple of a page otherwise (special case: default is a page with dump)\n"
  454. "\n"
  455. "The .dontskipff option forces writing empty pages, don't use it if unsure.\n";
  456. #endif
  457. U_BOOT_CMD_WITH_SUBCMDS(mtd, "MTD utils", mtd_help_text,
  458. U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mtd_list),
  459. U_BOOT_SUBCMD_MKENT_COMPLETE(read, 5, 0, do_mtd_io,
  460. mtd_name_complete),
  461. U_BOOT_SUBCMD_MKENT_COMPLETE(write, 5, 0, do_mtd_io,
  462. mtd_name_complete),
  463. U_BOOT_SUBCMD_MKENT_COMPLETE(dump, 4, 0, do_mtd_io,
  464. mtd_name_complete),
  465. U_BOOT_SUBCMD_MKENT_COMPLETE(erase, 4, 0, do_mtd_erase,
  466. mtd_name_complete),
  467. U_BOOT_SUBCMD_MKENT_COMPLETE(bad, 2, 1, do_mtd_bad,
  468. mtd_name_complete));