Merge branch 'master' of git://git.denx.de/u-boot-usb
[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(cmd_tbl_t *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(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
244 {
245         bool dump, read, raw, woob, write_empty_pages, has_pages = false;
246         u64 start_off, off, len, remaining, default_len;
247         struct mtd_oob_ops io_op = {};
248         uint user_addr = 0, npages;
249         const char *cmd = argv[0];
250         struct mtd_info *mtd;
251         u32 oob_len;
252         u8 *buf;
253         int ret;
254
255         if (argc < 2)
256                 return CMD_RET_USAGE;
257
258         mtd = get_mtd_by_name(argv[1]);
259         if (IS_ERR_OR_NULL(mtd))
260                 return CMD_RET_FAILURE;
261
262         if (mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH)
263                 has_pages = true;
264
265         dump = !strncmp(cmd, "dump", 4);
266         read = dump || !strncmp(cmd, "read", 4);
267         raw = strstr(cmd, ".raw");
268         woob = strstr(cmd, ".oob");
269         write_empty_pages = !has_pages || strstr(cmd, ".dontskipff");
270
271         argc -= 2;
272         argv += 2;
273
274         if (!dump) {
275                 if (!argc) {
276                         ret = CMD_RET_USAGE;
277                         goto out_put_mtd;
278                 }
279
280                 user_addr = simple_strtoul(argv[0], NULL, 16);
281                 argc--;
282                 argv++;
283         }
284
285         start_off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
286         if (!mtd_is_aligned_with_min_io_size(mtd, start_off)) {
287                 printf("Offset not aligned with a page (0x%x)\n",
288                        mtd->writesize);
289                 ret = CMD_RET_FAILURE;
290                 goto out_put_mtd;
291         }
292
293         default_len = dump ? mtd->writesize : mtd->size;
294         len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : default_len;
295         if (!mtd_is_aligned_with_min_io_size(mtd, len)) {
296                 len = round_up(len, mtd->writesize);
297                 printf("Size not on a page boundary (0x%x), rounding to 0x%llx\n",
298                        mtd->writesize, len);
299         }
300
301         remaining = len;
302         npages = mtd_len_to_pages(mtd, len);
303         oob_len = woob ? npages * mtd->oobsize : 0;
304
305         if (dump)
306                 buf = kmalloc(len + oob_len, GFP_KERNEL);
307         else
308                 buf = map_sysmem(user_addr, 0);
309
310         if (!buf) {
311                 printf("Could not map/allocate the user buffer\n");
312                 ret = CMD_RET_FAILURE;
313                 goto out_put_mtd;
314         }
315
316         if (has_pages)
317                 printf("%s %lld byte(s) (%d page(s)) at offset 0x%08llx%s%s%s\n",
318                        read ? "Reading" : "Writing", len, npages, start_off,
319                        raw ? " [raw]" : "", woob ? " [oob]" : "",
320                        !read && write_empty_pages ? " [dontskipff]" : "");
321         else
322                 printf("%s %lld byte(s) at offset 0x%08llx\n",
323                        read ? "Reading" : "Writing", len, start_off);
324
325         io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB;
326         io_op.len = has_pages ? mtd->writesize : len;
327         io_op.ooblen = woob ? mtd->oobsize : 0;
328         io_op.datbuf = buf;
329         io_op.oobbuf = woob ? &buf[len] : NULL;
330
331         /* Search for the first good block after the given offset */
332         off = start_off;
333         while (mtd_block_isbad(mtd, off))
334                 off += mtd->erasesize;
335
336         /* Loop over the pages to do the actual read/write */
337         while (remaining) {
338                 /* Skip the block if it is bad */
339                 if (mtd_is_aligned_with_block_size(mtd, off) &&
340                     mtd_block_isbad(mtd, off)) {
341                         off += mtd->erasesize;
342                         continue;
343                 }
344
345                 if (read)
346                         ret = mtd_read_oob(mtd, off, &io_op);
347                 else
348                         ret = mtd_special_write_oob(mtd, off, &io_op,
349                                                     write_empty_pages, woob);
350
351                 if (ret) {
352                         printf("Failure while %s at offset 0x%llx\n",
353                                read ? "reading" : "writing", off);
354                         break;
355                 }
356
357                 off += io_op.retlen;
358                 remaining -= io_op.retlen;
359                 io_op.datbuf += io_op.retlen;
360                 io_op.oobbuf += io_op.oobretlen;
361         }
362
363         if (!ret && dump)
364                 mtd_dump_device_buf(mtd, start_off, buf, len, woob);
365
366         if (dump)
367                 kfree(buf);
368         else
369                 unmap_sysmem(buf);
370
371         if (ret) {
372                 printf("%s on %s failed with error %d\n",
373                        read ? "Read" : "Write", mtd->name, ret);
374                 ret = CMD_RET_FAILURE;
375         } else {
376                 ret = CMD_RET_SUCCESS;
377         }
378
379 out_put_mtd:
380         put_mtd_device(mtd);
381
382         return ret;
383 }
384
385 static int do_mtd_erase(cmd_tbl_t *cmdtp, int flag, int argc,
386                         char * const argv[])
387 {
388         struct erase_info erase_op = {};
389         struct mtd_info *mtd;
390         u64 off, len;
391         bool scrub;
392         int ret = 0;
393
394         if (argc < 2)
395                 return CMD_RET_USAGE;
396
397         mtd = get_mtd_by_name(argv[1]);
398         if (IS_ERR_OR_NULL(mtd))
399                 return CMD_RET_FAILURE;
400
401         scrub = strstr(argv[0], ".dontskipbad");
402
403         argc -= 2;
404         argv += 2;
405
406         off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
407         len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : mtd->size;
408
409         if (!mtd_is_aligned_with_block_size(mtd, off)) {
410                 printf("Offset not aligned with a block (0x%x)\n",
411                        mtd->erasesize);
412                 ret = CMD_RET_FAILURE;
413                 goto out_put_mtd;
414         }
415
416         if (!mtd_is_aligned_with_block_size(mtd, len)) {
417                 printf("Size not a multiple of a block (0x%x)\n",
418                        mtd->erasesize);
419                 ret = CMD_RET_FAILURE;
420                 goto out_put_mtd;
421         }
422
423         printf("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n",
424                off, off + len - 1, mtd_div_by_eb(len, mtd));
425
426         erase_op.mtd = mtd;
427         erase_op.addr = off;
428         erase_op.len = mtd->erasesize;
429         erase_op.scrub = scrub;
430
431         while (len) {
432                 ret = mtd_erase(mtd, &erase_op);
433
434                 if (ret) {
435                         /* Abort if its not a bad block error */
436                         if (ret != -EIO)
437                                 break;
438                         printf("Skipping bad block at 0x%08llx\n",
439                                erase_op.addr);
440                 }
441
442                 len -= mtd->erasesize;
443                 erase_op.addr += mtd->erasesize;
444         }
445
446         if (ret && ret != -EIO)
447                 ret = CMD_RET_FAILURE;
448         else
449                 ret = CMD_RET_SUCCESS;
450
451 out_put_mtd:
452         put_mtd_device(mtd);
453
454         return ret;
455 }
456
457 static int do_mtd_bad(cmd_tbl_t *cmdtp, int flag, int argc,
458                       char * const argv[])
459 {
460         struct mtd_info *mtd;
461         loff_t off;
462
463         if (argc < 2)
464                 return CMD_RET_USAGE;
465
466         mtd = get_mtd_by_name(argv[1]);
467         if (IS_ERR_OR_NULL(mtd))
468                 return CMD_RET_FAILURE;
469
470         if (!mtd_can_have_bb(mtd)) {
471                 printf("Only NAND-based devices can have bad blocks\n");
472                 goto out_put_mtd;
473         }
474
475         printf("MTD device %s bad blocks list:\n", mtd->name);
476         for (off = 0; off < mtd->size; off += mtd->erasesize) {
477                 if (mtd_block_isbad(mtd, off))
478                         printf("\t0x%08llx\n", off);
479         }
480
481 out_put_mtd:
482         put_mtd_device(mtd);
483
484         return CMD_RET_SUCCESS;
485 }
486
487 #ifdef CONFIG_AUTO_COMPLETE
488 static int mtd_name_complete(int argc, char * const argv[], char last_char,
489                              int maxv, char *cmdv[])
490 {
491         int len = 0, n_found = 0;
492         struct mtd_info *mtd;
493
494         argc--;
495         argv++;
496
497         if (argc > 1 ||
498             (argc == 1 && (last_char == '\0' || isblank(last_char))))
499                 return 0;
500
501         if (argc)
502                 len = strlen(argv[0]);
503
504         mtd_for_each_device(mtd) {
505                 if (argc &&
506                     (len > strlen(mtd->name) ||
507                      strncmp(argv[0], mtd->name, len)))
508                         continue;
509
510                 if (n_found >= maxv - 2) {
511                         cmdv[n_found++] = "...";
512                         break;
513                 }
514
515                 cmdv[n_found++] = mtd->name;
516         }
517
518         cmdv[n_found] = NULL;
519
520         return n_found;
521 }
522 #endif /* CONFIG_AUTO_COMPLETE */
523
524 #ifdef CONFIG_SYS_LONGHELP
525 static char mtd_help_text[] =
526         "- generic operations on memory technology devices\n\n"
527         "mtd list\n"
528         "mtd read[.raw][.oob]                  <name> <addr> [<off> [<size>]]\n"
529         "mtd dump[.raw][.oob]                  <name>        [<off> [<size>]]\n"
530         "mtd write[.raw][.oob][.dontskipff]    <name> <addr> [<off> [<size>]]\n"
531         "mtd erase[.dontskipbad]               <name>        [<off> [<size>]]\n"
532         "\n"
533         "Specific functions:\n"
534         "mtd bad                               <name>\n"
535         "\n"
536         "With:\n"
537         "\t<name>: NAND partition/chip name\n"
538         "\t<addr>: user address from/to which data will be retrieved/stored\n"
539         "\t<off>: offset in <name> in bytes (default: start of the part)\n"
540         "\t\t* must be block-aligned for erase\n"
541         "\t\t* must be page-aligned otherwise\n"
542         "\t<size>: length of the operation in bytes (default: the entire device)\n"
543         "\t\t* must be a multiple of a block for erase\n"
544         "\t\t* must be a multiple of a page otherwise (special case: default is a page with dump)\n"
545         "\n"
546         "The .dontskipff option forces writing empty pages, don't use it if unsure.\n";
547 #endif
548
549 U_BOOT_CMD_WITH_SUBCMDS(mtd, "MTD utils", mtd_help_text,
550                 U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mtd_list),
551                 U_BOOT_SUBCMD_MKENT_COMPLETE(read, 5, 0, do_mtd_io,
552                                              mtd_name_complete),
553                 U_BOOT_SUBCMD_MKENT_COMPLETE(write, 5, 0, do_mtd_io,
554                                              mtd_name_complete),
555                 U_BOOT_SUBCMD_MKENT_COMPLETE(dump, 4, 0, do_mtd_io,
556                                              mtd_name_complete),
557                 U_BOOT_SUBCMD_MKENT_COMPLETE(erase, 4, 0, do_mtd_erase,
558                                              mtd_name_complete),
559                 U_BOOT_SUBCMD_MKENT_COMPLETE(bad, 2, 1, do_mtd_bad,
560                                              mtd_name_complete));