mtd.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  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(cmd_tbl_t *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(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  203. {
  204. bool dump, read, raw, woob, write_empty_pages, has_pages = false;
  205. u64 start_off, off, len, remaining, default_len;
  206. struct mtd_oob_ops io_op = {};
  207. uint user_addr = 0, npages;
  208. const char *cmd = argv[0];
  209. struct mtd_info *mtd;
  210. u32 oob_len;
  211. u8 *buf;
  212. int ret;
  213. if (argc < 2)
  214. return CMD_RET_USAGE;
  215. mtd = get_mtd_by_name(argv[1]);
  216. if (IS_ERR_OR_NULL(mtd))
  217. return CMD_RET_FAILURE;
  218. if (mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH)
  219. has_pages = true;
  220. dump = !strncmp(cmd, "dump", 4);
  221. read = dump || !strncmp(cmd, "read", 4);
  222. raw = strstr(cmd, ".raw");
  223. woob = strstr(cmd, ".oob");
  224. write_empty_pages = !has_pages || strstr(cmd, ".dontskipff");
  225. argc -= 2;
  226. argv += 2;
  227. if (!dump) {
  228. if (!argc) {
  229. ret = CMD_RET_USAGE;
  230. goto out_put_mtd;
  231. }
  232. user_addr = simple_strtoul(argv[0], NULL, 16);
  233. argc--;
  234. argv++;
  235. }
  236. start_off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
  237. if (!mtd_is_aligned_with_min_io_size(mtd, start_off)) {
  238. printf("Offset not aligned with a page (0x%x)\n",
  239. mtd->writesize);
  240. ret = CMD_RET_FAILURE;
  241. goto out_put_mtd;
  242. }
  243. default_len = dump ? mtd->writesize : mtd->size;
  244. len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : default_len;
  245. if (!mtd_is_aligned_with_min_io_size(mtd, len)) {
  246. len = round_up(len, mtd->writesize);
  247. printf("Size not on a page boundary (0x%x), rounding to 0x%llx\n",
  248. mtd->writesize, len);
  249. }
  250. remaining = len;
  251. npages = mtd_len_to_pages(mtd, len);
  252. oob_len = woob ? npages * mtd->oobsize : 0;
  253. if (dump)
  254. buf = kmalloc(len + oob_len, GFP_KERNEL);
  255. else
  256. buf = map_sysmem(user_addr, 0);
  257. if (!buf) {
  258. printf("Could not map/allocate the user buffer\n");
  259. ret = CMD_RET_FAILURE;
  260. goto out_put_mtd;
  261. }
  262. if (has_pages)
  263. printf("%s %lld byte(s) (%d page(s)) at offset 0x%08llx%s%s%s\n",
  264. read ? "Reading" : "Writing", len, npages, start_off,
  265. raw ? " [raw]" : "", woob ? " [oob]" : "",
  266. !read && write_empty_pages ? " [dontskipff]" : "");
  267. else
  268. printf("%s %lld byte(s) at offset 0x%08llx\n",
  269. read ? "Reading" : "Writing", len, start_off);
  270. io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB;
  271. io_op.len = has_pages ? mtd->writesize : len;
  272. io_op.ooblen = woob ? mtd->oobsize : 0;
  273. io_op.datbuf = buf;
  274. io_op.oobbuf = woob ? &buf[len] : NULL;
  275. /* Search for the first good block after the given offset */
  276. off = start_off;
  277. while (mtd_block_isbad(mtd, off))
  278. off += mtd->erasesize;
  279. /* Loop over the pages to do the actual read/write */
  280. while (remaining) {
  281. /* Skip the block if it is bad */
  282. if (mtd_is_aligned_with_block_size(mtd, off) &&
  283. mtd_block_isbad(mtd, off)) {
  284. off += mtd->erasesize;
  285. continue;
  286. }
  287. if (read)
  288. ret = mtd_read_oob(mtd, off, &io_op);
  289. else
  290. ret = mtd_special_write_oob(mtd, off, &io_op,
  291. write_empty_pages, woob);
  292. if (ret) {
  293. printf("Failure while %s at offset 0x%llx\n",
  294. read ? "reading" : "writing", off);
  295. break;
  296. }
  297. off += io_op.retlen;
  298. remaining -= io_op.retlen;
  299. io_op.datbuf += io_op.retlen;
  300. io_op.oobbuf += io_op.oobretlen;
  301. }
  302. if (!ret && dump)
  303. mtd_dump_device_buf(mtd, start_off, buf, len, woob);
  304. if (dump)
  305. kfree(buf);
  306. else
  307. unmap_sysmem(buf);
  308. if (ret) {
  309. printf("%s on %s failed with error %d\n",
  310. read ? "Read" : "Write", mtd->name, ret);
  311. ret = CMD_RET_FAILURE;
  312. } else {
  313. ret = CMD_RET_SUCCESS;
  314. }
  315. out_put_mtd:
  316. put_mtd_device(mtd);
  317. return ret;
  318. }
  319. static int do_mtd_erase(cmd_tbl_t *cmdtp, int flag, int argc,
  320. char * const argv[])
  321. {
  322. struct erase_info erase_op = {};
  323. struct mtd_info *mtd;
  324. u64 off, len;
  325. bool scrub;
  326. int ret = 0;
  327. if (argc < 2)
  328. return CMD_RET_USAGE;
  329. mtd = get_mtd_by_name(argv[1]);
  330. if (IS_ERR_OR_NULL(mtd))
  331. return CMD_RET_FAILURE;
  332. scrub = strstr(argv[0], ".dontskipbad");
  333. argc -= 2;
  334. argv += 2;
  335. off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
  336. len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : mtd->size;
  337. if (!mtd_is_aligned_with_block_size(mtd, off)) {
  338. printf("Offset not aligned with a block (0x%x)\n",
  339. mtd->erasesize);
  340. ret = CMD_RET_FAILURE;
  341. goto out_put_mtd;
  342. }
  343. if (!mtd_is_aligned_with_block_size(mtd, len)) {
  344. printf("Size not a multiple of a block (0x%x)\n",
  345. mtd->erasesize);
  346. ret = CMD_RET_FAILURE;
  347. goto out_put_mtd;
  348. }
  349. printf("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n",
  350. off, off + len - 1, mtd_div_by_eb(len, mtd));
  351. erase_op.mtd = mtd;
  352. erase_op.addr = off;
  353. erase_op.len = mtd->erasesize;
  354. erase_op.scrub = scrub;
  355. while (len) {
  356. ret = mtd_erase(mtd, &erase_op);
  357. if (ret) {
  358. /* Abort if its not a bad block error */
  359. if (ret != -EIO)
  360. break;
  361. printf("Skipping bad block at 0x%08llx\n",
  362. erase_op.addr);
  363. }
  364. len -= mtd->erasesize;
  365. erase_op.addr += mtd->erasesize;
  366. }
  367. if (ret && ret != -EIO)
  368. ret = CMD_RET_FAILURE;
  369. else
  370. ret = CMD_RET_SUCCESS;
  371. out_put_mtd:
  372. put_mtd_device(mtd);
  373. return ret;
  374. }
  375. static int do_mtd_bad(cmd_tbl_t *cmdtp, int flag, int argc,
  376. char * const argv[])
  377. {
  378. struct mtd_info *mtd;
  379. loff_t off;
  380. if (argc < 2)
  381. return CMD_RET_USAGE;
  382. mtd = get_mtd_by_name(argv[1]);
  383. if (IS_ERR_OR_NULL(mtd))
  384. return CMD_RET_FAILURE;
  385. if (!mtd_can_have_bb(mtd)) {
  386. printf("Only NAND-based devices can have bad blocks\n");
  387. goto out_put_mtd;
  388. }
  389. printf("MTD device %s bad blocks list:\n", mtd->name);
  390. for (off = 0; off < mtd->size; off += mtd->erasesize) {
  391. if (mtd_block_isbad(mtd, off))
  392. printf("\t0x%08llx\n", off);
  393. }
  394. out_put_mtd:
  395. put_mtd_device(mtd);
  396. return CMD_RET_SUCCESS;
  397. }
  398. #ifdef CONFIG_AUTO_COMPLETE
  399. static int mtd_name_complete(int argc, char * const argv[], char last_char,
  400. int maxv, char *cmdv[])
  401. {
  402. int len = 0, n_found = 0;
  403. struct mtd_info *mtd;
  404. argc--;
  405. argv++;
  406. if (argc > 1 ||
  407. (argc == 1 && (last_char == '\0' || isblank(last_char))))
  408. return 0;
  409. if (argc)
  410. len = strlen(argv[0]);
  411. mtd_for_each_device(mtd) {
  412. if (argc &&
  413. (len > strlen(mtd->name) ||
  414. strncmp(argv[0], mtd->name, len)))
  415. continue;
  416. if (n_found >= maxv - 2) {
  417. cmdv[n_found++] = "...";
  418. break;
  419. }
  420. cmdv[n_found++] = mtd->name;
  421. }
  422. cmdv[n_found] = NULL;
  423. return n_found;
  424. }
  425. #endif /* CONFIG_AUTO_COMPLETE */
  426. #ifdef CONFIG_SYS_LONGHELP
  427. static char mtd_help_text[] =
  428. "- generic operations on memory technology devices\n\n"
  429. "mtd list\n"
  430. "mtd read[.raw][.oob] <name> <addr> [<off> [<size>]]\n"
  431. "mtd dump[.raw][.oob] <name> [<off> [<size>]]\n"
  432. "mtd write[.raw][.oob][.dontskipff] <name> <addr> [<off> [<size>]]\n"
  433. "mtd erase[.dontskipbad] <name> [<off> [<size>]]\n"
  434. "\n"
  435. "Specific functions:\n"
  436. "mtd bad <name>\n"
  437. "\n"
  438. "With:\n"
  439. "\t<name>: NAND partition/chip name\n"
  440. "\t<addr>: user address from/to which data will be retrieved/stored\n"
  441. "\t<off>: offset in <name> in bytes (default: start of the part)\n"
  442. "\t\t* must be block-aligned for erase\n"
  443. "\t\t* must be page-aligned otherwise\n"
  444. "\t<size>: length of the operation in bytes (default: the entire device)\n"
  445. "\t\t* must be a multiple of a block for erase\n"
  446. "\t\t* must be a multiple of a page otherwise (special case: default is a page with dump)\n"
  447. "\n"
  448. "The .dontskipff option forces writing empty pages, don't use it if unsure.\n";
  449. #endif
  450. U_BOOT_CMD_WITH_SUBCMDS(mtd, "MTD utils", mtd_help_text,
  451. U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mtd_list),
  452. U_BOOT_SUBCMD_MKENT_COMPLETE(read, 5, 0, do_mtd_io,
  453. mtd_name_complete),
  454. U_BOOT_SUBCMD_MKENT_COMPLETE(write, 5, 0, do_mtd_io,
  455. mtd_name_complete),
  456. U_BOOT_SUBCMD_MKENT_COMPLETE(dump, 4, 0, do_mtd_io,
  457. mtd_name_complete),
  458. U_BOOT_SUBCMD_MKENT_COMPLETE(erase, 4, 0, do_mtd_erase,
  459. mtd_name_complete),
  460. U_BOOT_SUBCMD_MKENT_COMPLETE(bad, 2, 1, do_mtd_bad,
  461. mtd_name_complete));