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