mtd.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  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. /* MTD device information */
  109. printf(" - type: ");
  110. switch (mtd->type) {
  111. case MTD_RAM:
  112. printf("RAM\n");
  113. break;
  114. case MTD_ROM:
  115. printf("ROM\n");
  116. break;
  117. case MTD_NORFLASH:
  118. printf("NOR flash\n");
  119. break;
  120. case MTD_NANDFLASH:
  121. printf("NAND flash\n");
  122. break;
  123. case MTD_DATAFLASH:
  124. printf("Data flash\n");
  125. break;
  126. case MTD_UBIVOLUME:
  127. printf("UBI volume\n");
  128. break;
  129. case MTD_MLCNANDFLASH:
  130. printf("MLC NAND flash\n");
  131. break;
  132. case MTD_ABSENT:
  133. default:
  134. printf("Unknown\n");
  135. break;
  136. }
  137. printf(" - block size: 0x%x bytes\n", mtd->erasesize);
  138. printf(" - min I/O: 0x%x bytes\n", mtd->writesize);
  139. if (mtd->oobsize) {
  140. printf(" - OOB size: %u bytes\n", mtd->oobsize);
  141. printf(" - OOB available: %u bytes\n", mtd->oobavail);
  142. }
  143. if (mtd->ecc_strength) {
  144. printf(" - ECC strength: %u bits\n", mtd->ecc_strength);
  145. printf(" - ECC step size: %u bytes\n", mtd->ecc_step_size);
  146. printf(" - bitflip threshold: %u bits\n",
  147. mtd->bitflip_threshold);
  148. }
  149. printf(" - 0x%012llx-0x%012llx : \"%s\"\n",
  150. mtd->offset, mtd->offset + mtd->size, mtd->name);
  151. /* MTD partitions, if any */
  152. mtd_show_parts(mtd, 1);
  153. }
  154. /* Logic taken from fs/ubifs/recovery.c:is_empty() */
  155. static bool mtd_oob_write_is_empty(struct mtd_oob_ops *op)
  156. {
  157. int i;
  158. for (i = 0; i < op->len; i++)
  159. if (op->datbuf[i] != 0xff)
  160. return false;
  161. for (i = 0; i < op->ooblen; i++)
  162. if (op->oobbuf[i] != 0xff)
  163. return false;
  164. return true;
  165. }
  166. static int do_mtd_list(struct cmd_tbl *cmdtp, int flag, int argc,
  167. char *const argv[])
  168. {
  169. struct mtd_info *mtd;
  170. int dev_nb = 0;
  171. /* Ensure all devices (and their partitions) are probed */
  172. mtd_probe_devices();
  173. printf("List of MTD devices:\n");
  174. mtd_for_each_device(mtd) {
  175. if (!mtd_is_partition(mtd))
  176. mtd_show_device(mtd);
  177. dev_nb++;
  178. }
  179. if (!dev_nb) {
  180. printf("No MTD device found\n");
  181. return CMD_RET_FAILURE;
  182. }
  183. return CMD_RET_SUCCESS;
  184. }
  185. static int mtd_special_write_oob(struct mtd_info *mtd, u64 off,
  186. struct mtd_oob_ops *io_op,
  187. bool write_empty_pages, bool woob)
  188. {
  189. int ret = 0;
  190. /*
  191. * By default, do not write an empty page.
  192. * Skip it by simulating a successful write.
  193. */
  194. if (!write_empty_pages && mtd_oob_write_is_empty(io_op)) {
  195. io_op->retlen = mtd->writesize;
  196. io_op->oobretlen = woob ? mtd->oobsize : 0;
  197. } else {
  198. ret = mtd_write_oob(mtd, off, io_op);
  199. }
  200. return ret;
  201. }
  202. static int do_mtd_io(struct cmd_tbl *cmdtp, int flag, int argc,
  203. char *const argv[])
  204. {
  205. bool dump, read, raw, woob, write_empty_pages, has_pages = false;
  206. u64 start_off, off, len, remaining, default_len;
  207. struct mtd_oob_ops io_op = {};
  208. uint user_addr = 0, npages;
  209. const char *cmd = argv[0];
  210. struct mtd_info *mtd;
  211. u32 oob_len;
  212. u8 *buf;
  213. int ret;
  214. if (argc < 2)
  215. return CMD_RET_USAGE;
  216. mtd = get_mtd_by_name(argv[1]);
  217. if (IS_ERR_OR_NULL(mtd))
  218. return CMD_RET_FAILURE;
  219. if (mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH)
  220. has_pages = true;
  221. dump = !strncmp(cmd, "dump", 4);
  222. read = dump || !strncmp(cmd, "read", 4);
  223. raw = strstr(cmd, ".raw");
  224. woob = strstr(cmd, ".oob");
  225. write_empty_pages = !has_pages || strstr(cmd, ".dontskipff");
  226. argc -= 2;
  227. argv += 2;
  228. if (!dump) {
  229. if (!argc) {
  230. ret = CMD_RET_USAGE;
  231. goto out_put_mtd;
  232. }
  233. user_addr = simple_strtoul(argv[0], NULL, 16);
  234. argc--;
  235. argv++;
  236. }
  237. start_off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
  238. if (!mtd_is_aligned_with_min_io_size(mtd, start_off)) {
  239. printf("Offset not aligned with a page (0x%x)\n",
  240. mtd->writesize);
  241. ret = CMD_RET_FAILURE;
  242. goto out_put_mtd;
  243. }
  244. default_len = dump ? mtd->writesize : mtd->size;
  245. len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : default_len;
  246. if (!mtd_is_aligned_with_min_io_size(mtd, len)) {
  247. len = round_up(len, mtd->writesize);
  248. printf("Size not on a page boundary (0x%x), rounding to 0x%llx\n",
  249. mtd->writesize, len);
  250. }
  251. remaining = len;
  252. npages = mtd_len_to_pages(mtd, len);
  253. oob_len = woob ? npages * mtd->oobsize : 0;
  254. if (dump)
  255. buf = kmalloc(len + oob_len, GFP_KERNEL);
  256. else
  257. buf = map_sysmem(user_addr, 0);
  258. if (!buf) {
  259. printf("Could not map/allocate the user buffer\n");
  260. ret = CMD_RET_FAILURE;
  261. goto out_put_mtd;
  262. }
  263. if (has_pages)
  264. printf("%s %lld byte(s) (%d page(s)) at offset 0x%08llx%s%s%s\n",
  265. read ? "Reading" : "Writing", len, npages, start_off,
  266. raw ? " [raw]" : "", woob ? " [oob]" : "",
  267. !read && write_empty_pages ? " [dontskipff]" : "");
  268. else
  269. printf("%s %lld byte(s) at offset 0x%08llx\n",
  270. read ? "Reading" : "Writing", len, start_off);
  271. io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB;
  272. io_op.len = has_pages ? mtd->writesize : len;
  273. io_op.ooblen = woob ? mtd->oobsize : 0;
  274. io_op.datbuf = buf;
  275. io_op.oobbuf = woob ? &buf[len] : NULL;
  276. /* Search for the first good block after the given offset */
  277. off = start_off;
  278. while (mtd_block_isbad(mtd, off))
  279. off += mtd->erasesize;
  280. /* Loop over the pages to do the actual read/write */
  281. while (remaining) {
  282. /* Skip the block if it is bad */
  283. if (mtd_is_aligned_with_block_size(mtd, off) &&
  284. mtd_block_isbad(mtd, off)) {
  285. off += mtd->erasesize;
  286. continue;
  287. }
  288. if (read)
  289. ret = mtd_read_oob(mtd, off, &io_op);
  290. else
  291. ret = mtd_special_write_oob(mtd, off, &io_op,
  292. write_empty_pages, woob);
  293. if (ret) {
  294. printf("Failure while %s at offset 0x%llx\n",
  295. read ? "reading" : "writing", off);
  296. break;
  297. }
  298. off += io_op.retlen;
  299. remaining -= io_op.retlen;
  300. io_op.datbuf += io_op.retlen;
  301. io_op.oobbuf += io_op.oobretlen;
  302. }
  303. if (!ret && dump)
  304. mtd_dump_device_buf(mtd, start_off, buf, len, woob);
  305. if (dump)
  306. kfree(buf);
  307. else
  308. unmap_sysmem(buf);
  309. if (ret) {
  310. printf("%s on %s failed with error %d\n",
  311. read ? "Read" : "Write", mtd->name, ret);
  312. ret = CMD_RET_FAILURE;
  313. } else {
  314. ret = CMD_RET_SUCCESS;
  315. }
  316. out_put_mtd:
  317. put_mtd_device(mtd);
  318. return ret;
  319. }
  320. static int do_mtd_erase(struct cmd_tbl *cmdtp, int flag, int argc,
  321. char *const argv[])
  322. {
  323. struct erase_info erase_op = {};
  324. struct mtd_info *mtd;
  325. u64 off, len;
  326. bool scrub;
  327. int ret = 0;
  328. if (argc < 2)
  329. return CMD_RET_USAGE;
  330. mtd = get_mtd_by_name(argv[1]);
  331. if (IS_ERR_OR_NULL(mtd))
  332. return CMD_RET_FAILURE;
  333. scrub = strstr(argv[0], ".dontskipbad");
  334. argc -= 2;
  335. argv += 2;
  336. off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
  337. len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : mtd->size;
  338. if (!mtd_is_aligned_with_block_size(mtd, off)) {
  339. printf("Offset not aligned with a block (0x%x)\n",
  340. mtd->erasesize);
  341. ret = CMD_RET_FAILURE;
  342. goto out_put_mtd;
  343. }
  344. if (!mtd_is_aligned_with_block_size(mtd, len)) {
  345. printf("Size not a multiple of a block (0x%x)\n",
  346. mtd->erasesize);
  347. ret = CMD_RET_FAILURE;
  348. goto out_put_mtd;
  349. }
  350. printf("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n",
  351. off, off + len - 1, mtd_div_by_eb(len, mtd));
  352. erase_op.mtd = mtd;
  353. erase_op.addr = off;
  354. erase_op.len = mtd->erasesize;
  355. erase_op.scrub = scrub;
  356. while (len) {
  357. ret = mtd_erase(mtd, &erase_op);
  358. if (ret) {
  359. /* Abort if its not a bad block error */
  360. if (ret != -EIO)
  361. break;
  362. printf("Skipping bad block at 0x%08llx\n",
  363. erase_op.addr);
  364. }
  365. len -= mtd->erasesize;
  366. erase_op.addr += mtd->erasesize;
  367. }
  368. if (ret && ret != -EIO)
  369. ret = CMD_RET_FAILURE;
  370. else
  371. ret = CMD_RET_SUCCESS;
  372. out_put_mtd:
  373. put_mtd_device(mtd);
  374. return ret;
  375. }
  376. static int do_mtd_bad(struct cmd_tbl *cmdtp, int flag, int argc,
  377. char *const argv[])
  378. {
  379. struct mtd_info *mtd;
  380. loff_t off;
  381. if (argc < 2)
  382. return CMD_RET_USAGE;
  383. mtd = get_mtd_by_name(argv[1]);
  384. if (IS_ERR_OR_NULL(mtd))
  385. return CMD_RET_FAILURE;
  386. if (!mtd_can_have_bb(mtd)) {
  387. printf("Only NAND-based devices can have bad blocks\n");
  388. goto out_put_mtd;
  389. }
  390. printf("MTD device %s bad blocks list:\n", mtd->name);
  391. for (off = 0; off < mtd->size; off += mtd->erasesize) {
  392. if (mtd_block_isbad(mtd, off))
  393. printf("\t0x%08llx\n", off);
  394. }
  395. out_put_mtd:
  396. put_mtd_device(mtd);
  397. return CMD_RET_SUCCESS;
  398. }
  399. #ifdef CONFIG_AUTO_COMPLETE
  400. static int mtd_name_complete(int argc, char *const argv[], char last_char,
  401. int maxv, char *cmdv[])
  402. {
  403. int len = 0, n_found = 0;
  404. struct mtd_info *mtd;
  405. argc--;
  406. argv++;
  407. if (argc > 1 ||
  408. (argc == 1 && (last_char == '\0' || isblank(last_char))))
  409. return 0;
  410. if (argc)
  411. len = strlen(argv[0]);
  412. mtd_for_each_device(mtd) {
  413. if (argc &&
  414. (len > strlen(mtd->name) ||
  415. strncmp(argv[0], mtd->name, len)))
  416. continue;
  417. if (n_found >= maxv - 2) {
  418. cmdv[n_found++] = "...";
  419. break;
  420. }
  421. cmdv[n_found++] = mtd->name;
  422. }
  423. cmdv[n_found] = NULL;
  424. return n_found;
  425. }
  426. #endif /* CONFIG_AUTO_COMPLETE */
  427. #ifdef CONFIG_SYS_LONGHELP
  428. static char mtd_help_text[] =
  429. "- generic operations on memory technology devices\n\n"
  430. "mtd list\n"
  431. "mtd read[.raw][.oob] <name> <addr> [<off> [<size>]]\n"
  432. "mtd dump[.raw][.oob] <name> [<off> [<size>]]\n"
  433. "mtd write[.raw][.oob][.dontskipff] <name> <addr> [<off> [<size>]]\n"
  434. "mtd erase[.dontskipbad] <name> [<off> [<size>]]\n"
  435. "\n"
  436. "Specific functions:\n"
  437. "mtd bad <name>\n"
  438. "\n"
  439. "With:\n"
  440. "\t<name>: NAND partition/chip name\n"
  441. "\t<addr>: user address from/to which data will be retrieved/stored\n"
  442. "\t<off>: offset in <name> in bytes (default: start of the part)\n"
  443. "\t\t* must be block-aligned for erase\n"
  444. "\t\t* must be page-aligned otherwise\n"
  445. "\t<size>: length of the operation in bytes (default: the entire device)\n"
  446. "\t\t* must be a multiple of a block for erase\n"
  447. "\t\t* must be a multiple of a page otherwise (special case: default is a page with dump)\n"
  448. "\n"
  449. "The .dontskipff option forces writing empty pages, don't use it if unsure.\n";
  450. #endif
  451. U_BOOT_CMD_WITH_SUBCMDS(mtd, "MTD utils", mtd_help_text,
  452. U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mtd_list),
  453. U_BOOT_SUBCMD_MKENT_COMPLETE(read, 5, 0, do_mtd_io,
  454. mtd_name_complete),
  455. U_BOOT_SUBCMD_MKENT_COMPLETE(write, 5, 0, do_mtd_io,
  456. mtd_name_complete),
  457. U_BOOT_SUBCMD_MKENT_COMPLETE(dump, 4, 0, do_mtd_io,
  458. mtd_name_complete),
  459. U_BOOT_SUBCMD_MKENT_COMPLETE(erase, 4, 0, do_mtd_erase,
  460. mtd_name_complete),
  461. U_BOOT_SUBCMD_MKENT_COMPLETE(bad, 2, 1, do_mtd_bad,
  462. mtd_name_complete));