]> Git Repo - u-boot.git/blob - cmd/mtd.c
Merge patch series "Enable OF_UPSTREAM for J721s2 and AM68"
[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 <[email protected]>
9  */
10
11 #include <command.h>
12 #include <console.h>
13 #if CONFIG_IS_ENABLED(CMD_MTD_OTP)
14 #include <hexdump.h>
15 #endif
16 #include <malloc.h>
17 #include <mapmem.h>
18 #include <mtd.h>
19 #include <dm/devres.h>
20 #include <linux/err.h>
21
22 #include <linux/ctype.h>
23
24 static struct mtd_info *get_mtd_by_name(const char *name)
25 {
26         struct mtd_info *mtd;
27
28         mtd_probe_devices();
29
30         mtd = get_mtd_device_nm(name);
31         if (IS_ERR_OR_NULL(mtd))
32                 printf("MTD device %s not found, ret %ld\n", name,
33                        PTR_ERR(mtd));
34
35         return mtd;
36 }
37
38 static uint mtd_len_to_pages(struct mtd_info *mtd, u64 len)
39 {
40         do_div(len, mtd->writesize);
41
42         return len;
43 }
44
45 static bool mtd_is_aligned_with_min_io_size(struct mtd_info *mtd, u64 size)
46 {
47         return !do_div(size, mtd->writesize);
48 }
49
50 static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
51 {
52         return !do_div(size, mtd->erasesize);
53 }
54
55 static void mtd_dump_buf(const u8 *buf, uint len, uint offset)
56 {
57         int i, j;
58
59         for (i = 0; i < len; ) {
60                 printf("0x%08x:\t", offset + i);
61                 for (j = 0; j < 8; j++)
62                         printf("%02x ", buf[i + j]);
63                 printf(" ");
64                 i += 8;
65                 for (j = 0; j < 8; j++)
66                         printf("%02x ", buf[i + j]);
67                 printf("\n");
68                 i += 8;
69         }
70 }
71
72 static void mtd_dump_device_buf(struct mtd_info *mtd, u64 start_off,
73                                 const u8 *buf, u64 len, bool woob)
74 {
75         bool has_pages = mtd->type == MTD_NANDFLASH ||
76                 mtd->type == MTD_MLCNANDFLASH;
77         int npages = mtd_len_to_pages(mtd, len);
78         uint page;
79
80         if (has_pages) {
81                 for (page = 0; page < npages; page++) {
82                         u64 data_off = (u64)page * mtd->writesize;
83
84                         printf("\nDump %d data bytes from 0x%08llx:\n",
85                                mtd->writesize, start_off + data_off);
86                         mtd_dump_buf(&buf[data_off],
87                                      mtd->writesize, start_off + data_off);
88
89                         if (woob) {
90                                 u64 oob_off = (u64)page * mtd->oobsize;
91
92                                 printf("Dump %d OOB bytes from page at 0x%08llx:\n",
93                                        mtd->oobsize, start_off + data_off);
94                                 mtd_dump_buf(&buf[len + oob_off],
95                                              mtd->oobsize, 0);
96                         }
97                 }
98         } else {
99                 printf("\nDump %lld data bytes from 0x%llx:\n",
100                        len, start_off);
101                 mtd_dump_buf(buf, len, start_off);
102         }
103 }
104
105 static void mtd_show_parts(struct mtd_info *mtd, int level)
106 {
107         struct mtd_info *part;
108         int i;
109
110         list_for_each_entry(part, &mtd->partitions, node) {
111                 for (i = 0; i < level; i++)
112                         printf("\t");
113                 printf("  - 0x%012llx-0x%012llx : \"%s\"\n",
114                        part->offset, part->offset + part->size, part->name);
115
116                 mtd_show_parts(part, level + 1);
117         }
118 }
119
120 static void mtd_show_device(struct mtd_info *mtd)
121 {
122         /* Device */
123         printf("* %s\n", mtd->name);
124 #if defined(CONFIG_DM)
125         if (mtd->dev) {
126                 printf("  - device: %s\n", mtd->dev->name);
127                 printf("  - parent: %s\n", mtd->dev->parent->name);
128                 printf("  - driver: %s\n", mtd->dev->driver->name);
129         }
130 #endif
131         if (IS_ENABLED(CONFIG_OF_CONTROL) && mtd->dev) {
132                 char buf[256];
133                 int res;
134
135                 res = ofnode_get_path(mtd_get_ofnode(mtd), buf, 256);
136                 printf("  - path: %s\n", res == 0 ? buf : "unavailable");
137         }
138
139         /* MTD device information */
140         printf("  - type: ");
141         switch (mtd->type) {
142         case MTD_RAM:
143                 printf("RAM\n");
144                 break;
145         case MTD_ROM:
146                 printf("ROM\n");
147                 break;
148         case MTD_NORFLASH:
149                 printf("NOR flash\n");
150                 break;
151         case MTD_NANDFLASH:
152                 printf("NAND flash\n");
153                 break;
154         case MTD_DATAFLASH:
155                 printf("Data flash\n");
156                 break;
157         case MTD_UBIVOLUME:
158                 printf("UBI volume\n");
159                 break;
160         case MTD_MLCNANDFLASH:
161                 printf("MLC NAND flash\n");
162                 break;
163         case MTD_ABSENT:
164         default:
165                 printf("Unknown\n");
166                 break;
167         }
168
169         printf("  - block size: 0x%x bytes\n", mtd->erasesize);
170         printf("  - min I/O: 0x%x bytes\n", mtd->writesize);
171
172         if (mtd->oobsize) {
173                 printf("  - OOB size: %u bytes\n", mtd->oobsize);
174                 printf("  - OOB available: %u bytes\n", mtd->oobavail);
175         }
176
177         if (mtd->ecc_strength) {
178                 printf("  - ECC strength: %u bits\n", mtd->ecc_strength);
179                 printf("  - ECC step size: %u bytes\n", mtd->ecc_step_size);
180                 printf("  - bitflip threshold: %u bits\n",
181                        mtd->bitflip_threshold);
182         }
183
184         printf("  - 0x%012llx-0x%012llx : \"%s\"\n",
185                mtd->offset, mtd->offset + mtd->size, mtd->name);
186
187         /* MTD partitions, if any */
188         mtd_show_parts(mtd, 1);
189 }
190
191 /* Logic taken from fs/ubifs/recovery.c:is_empty() */
192 static bool mtd_oob_write_is_empty(struct mtd_oob_ops *op)
193 {
194         int i;
195
196         for (i = 0; i < op->len; i++)
197                 if (op->datbuf[i] != 0xff)
198                         return false;
199
200         for (i = 0; i < op->ooblen; i++)
201                 if (op->oobbuf[i] != 0xff)
202                         return false;
203
204         return true;
205 }
206
207 #if CONFIG_IS_ENABLED(CMD_MTD_OTP)
208 static int do_mtd_otp_read(struct cmd_tbl *cmdtp, int flag, int argc,
209                            char *const argv[])
210 {
211         struct mtd_info *mtd;
212         size_t retlen;
213         off_t from;
214         size_t len;
215         bool user;
216         int ret;
217         u8 *buf;
218
219         if (argc != 5)
220                 return CMD_RET_USAGE;
221
222         if (!strcmp(argv[2], "u"))
223                 user = true;
224         else if (!strcmp(argv[2], "f"))
225                 user = false;
226         else
227                 return CMD_RET_USAGE;
228
229         mtd = get_mtd_by_name(argv[1]);
230         if (IS_ERR_OR_NULL(mtd))
231                 return CMD_RET_FAILURE;
232
233         from = simple_strtoul(argv[3], NULL, 0);
234         len = simple_strtoul(argv[4], NULL, 0);
235
236         ret = CMD_RET_FAILURE;
237
238         buf = malloc(len);
239         if (!buf)
240                 goto put_mtd;
241
242         printf("Reading %s OTP from 0x%lx, %zu bytes\n",
243                user ? "user" : "factory", from, len);
244
245         if (user)
246                 ret = mtd_read_user_prot_reg(mtd, from, len, &retlen, buf);
247         else
248                 ret = mtd_read_fact_prot_reg(mtd, from, len, &retlen, buf);
249         if (ret) {
250                 free(buf);
251                 pr_err("OTP read failed: %d\n", ret);
252                 ret = CMD_RET_FAILURE;
253                 goto put_mtd;
254         }
255
256         if (retlen != len)
257                 pr_err("OTP read returns %zu, but %zu expected\n",
258                        retlen, len);
259
260         print_hex_dump("", 0, 16, 1, buf, retlen, true);
261
262         free(buf);
263
264         ret = CMD_RET_SUCCESS;
265
266 put_mtd:
267         put_mtd_device(mtd);
268
269         return ret;
270 }
271
272 static int do_mtd_otp_lock(struct cmd_tbl *cmdtp, int flag, int argc,
273                            char *const argv[])
274 {
275         struct mtd_info *mtd;
276         off_t from;
277         size_t len;
278         int ret;
279
280         if (argc != 4)
281                 return CMD_RET_USAGE;
282
283         mtd = get_mtd_by_name(argv[1]);
284         if (IS_ERR_OR_NULL(mtd))
285                 return CMD_RET_FAILURE;
286
287         from = simple_strtoul(argv[2], NULL, 0);
288         len = simple_strtoul(argv[3], NULL, 0);
289
290         ret = mtd_lock_user_prot_reg(mtd, from, len);
291         if (ret) {
292                 pr_err("OTP lock failed: %d\n", ret);
293                 ret = CMD_RET_FAILURE;
294                 goto put_mtd;
295         }
296
297         ret = CMD_RET_SUCCESS;
298
299 put_mtd:
300         put_mtd_device(mtd);
301
302         return ret;
303 }
304
305 static int do_mtd_otp_write(struct cmd_tbl *cmdtp, int flag, int argc,
306                             char *const argv[])
307 {
308         struct mtd_info *mtd;
309         size_t retlen;
310         size_t binlen;
311         u8 *binbuf;
312         off_t from;
313         int ret;
314
315         if (argc != 4)
316                 return CMD_RET_USAGE;
317
318         mtd = get_mtd_by_name(argv[1]);
319         if (IS_ERR_OR_NULL(mtd))
320                 return CMD_RET_FAILURE;
321
322         from = simple_strtoul(argv[2], NULL, 0);
323         binlen = strlen(argv[3]) / 2;
324
325         ret = CMD_RET_FAILURE;
326         binbuf = malloc(binlen);
327         if (!binbuf)
328                 goto put_mtd;
329
330         hex2bin(binbuf, argv[3], binlen);
331
332         printf("Will write:\n");
333
334         print_hex_dump("", 0, 16, 1, binbuf, binlen, true);
335
336         printf("to 0x%lx\n", from);
337
338         printf("Continue (y/n)?\n");
339
340         if (confirm_yesno() != 1) {
341                 pr_err("OTP write canceled\n");
342                 ret = CMD_RET_SUCCESS;
343                 goto put_mtd;
344         }
345
346         ret = mtd_write_user_prot_reg(mtd, from, binlen, &retlen, binbuf);
347         if (ret) {
348                 pr_err("OTP write failed: %d\n", ret);
349                 ret = CMD_RET_FAILURE;
350                 goto put_mtd;
351         }
352
353         if (retlen != binlen)
354                 pr_err("OTP write returns %zu, but %zu expected\n",
355                        retlen, binlen);
356
357         ret = CMD_RET_SUCCESS;
358
359 put_mtd:
360         free(binbuf);
361         put_mtd_device(mtd);
362
363         return ret;
364 }
365
366 static int do_mtd_otp_info(struct cmd_tbl *cmdtp, int flag, int argc,
367                            char *const argv[])
368 {
369         struct otp_info otp_info;
370         struct mtd_info *mtd;
371         size_t retlen;
372         bool user;
373         int ret;
374
375         if (argc != 3)
376                 return CMD_RET_USAGE;
377
378         if (!strcmp(argv[2], "u"))
379                 user = true;
380         else if (!strcmp(argv[2], "f"))
381                 user = false;
382         else
383                 return CMD_RET_USAGE;
384
385         mtd = get_mtd_by_name(argv[1]);
386         if (IS_ERR_OR_NULL(mtd))
387                 return CMD_RET_FAILURE;
388
389         if (user)
390                 ret = mtd_get_user_prot_info(mtd, sizeof(otp_info), &retlen,
391                                              &otp_info);
392         else
393                 ret = mtd_get_fact_prot_info(mtd, sizeof(otp_info), &retlen,
394                                              &otp_info);
395         if (ret) {
396                 pr_err("OTP info failed: %d\n", ret);
397                 ret = CMD_RET_FAILURE;
398                 goto put_mtd;
399         }
400
401         if (retlen != sizeof(otp_info)) {
402                 pr_err("OTP info returns %zu, but %zu expected\n",
403                        retlen, sizeof(otp_info));
404                 ret = CMD_RET_FAILURE;
405                 goto put_mtd;
406         }
407
408         printf("%s OTP region info:\n", user ? "User" : "Factory");
409         printf("\tstart: %u\n", otp_info.start);
410         printf("\tlength: %u\n", otp_info.length);
411         printf("\tlocked: %u\n", otp_info.locked);
412
413         ret = CMD_RET_SUCCESS;
414
415 put_mtd:
416         put_mtd_device(mtd);
417
418         return ret;
419 }
420 #endif
421
422 static int do_mtd_list(struct cmd_tbl *cmdtp, int flag, int argc,
423                        char *const argv[])
424 {
425         struct mtd_info *mtd;
426         int dev_nb = 0;
427
428         /* Ensure all devices (and their partitions) are probed */
429         mtd_probe_devices();
430
431         printf("List of MTD devices:\n");
432         mtd_for_each_device(mtd) {
433                 if (!mtd_is_partition(mtd))
434                         mtd_show_device(mtd);
435
436                 dev_nb++;
437         }
438
439         if (!dev_nb) {
440                 printf("No MTD device found\n");
441                 return CMD_RET_FAILURE;
442         }
443
444         return CMD_RET_SUCCESS;
445 }
446
447 static int mtd_special_write_oob(struct mtd_info *mtd, u64 off,
448                                  struct mtd_oob_ops *io_op,
449                                  bool write_empty_pages, bool woob)
450 {
451         int ret = 0;
452
453         /*
454          * By default, do not write an empty page.
455          * Skip it by simulating a successful write.
456          */
457         if (!write_empty_pages && mtd_oob_write_is_empty(io_op)) {
458                 io_op->retlen = mtd->writesize;
459                 io_op->oobretlen = woob ? mtd->oobsize : 0;
460         } else {
461                 ret = mtd_write_oob(mtd, off, io_op);
462         }
463
464         return ret;
465 }
466
467 static int do_mtd_io(struct cmd_tbl *cmdtp, int flag, int argc,
468                      char *const argv[])
469 {
470         bool dump, read, raw, woob, write_empty_pages, has_pages = false;
471         u64 start_off, off, len, remaining, default_len;
472         struct mtd_oob_ops io_op = {};
473         uint user_addr = 0, npages;
474         const char *cmd = argv[0];
475         struct mtd_info *mtd;
476         u32 oob_len;
477         u8 *buf;
478         int ret;
479
480         if (argc < 2)
481                 return CMD_RET_USAGE;
482
483         mtd = get_mtd_by_name(argv[1]);
484         if (IS_ERR_OR_NULL(mtd))
485                 return CMD_RET_FAILURE;
486
487         if (mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH)
488                 has_pages = true;
489
490         dump = !strncmp(cmd, "dump", 4);
491         read = dump || !strncmp(cmd, "read", 4);
492         raw = strstr(cmd, ".raw");
493         woob = strstr(cmd, ".oob");
494         write_empty_pages = !has_pages || strstr(cmd, ".dontskipff");
495
496         argc -= 2;
497         argv += 2;
498
499         if (!dump) {
500                 if (!argc) {
501                         ret = CMD_RET_USAGE;
502                         goto out_put_mtd;
503                 }
504
505                 user_addr = hextoul(argv[0], NULL);
506                 argc--;
507                 argv++;
508         }
509
510         start_off = argc > 0 ? hextoul(argv[0], NULL) : 0;
511         if (!mtd_is_aligned_with_min_io_size(mtd, start_off)) {
512                 printf("Offset not aligned with a page (0x%x)\n",
513                        mtd->writesize);
514                 ret = CMD_RET_FAILURE;
515                 goto out_put_mtd;
516         }
517
518         default_len = dump ? mtd->writesize : mtd->size;
519         len = argc > 1 ? hextoul(argv[1], NULL) : default_len;
520         if (!mtd_is_aligned_with_min_io_size(mtd, len)) {
521                 len = round_up(len, mtd->writesize);
522                 printf("Size not on a page boundary (0x%x), rounding to 0x%llx\n",
523                        mtd->writesize, len);
524         }
525
526         remaining = len;
527         npages = mtd_len_to_pages(mtd, len);
528         oob_len = woob ? npages * mtd->oobsize : 0;
529
530         if (dump)
531                 buf = kmalloc(len + oob_len, GFP_KERNEL);
532         else
533                 buf = map_sysmem(user_addr, 0);
534
535         if (!buf) {
536                 printf("Could not map/allocate the user buffer\n");
537                 ret = CMD_RET_FAILURE;
538                 goto out_put_mtd;
539         }
540
541         if (has_pages)
542                 printf("%s %lld byte(s) (%d page(s)) at offset 0x%08llx%s%s%s\n",
543                        read ? "Reading" : "Writing", len, npages, start_off,
544                        raw ? " [raw]" : "", woob ? " [oob]" : "",
545                        !read && write_empty_pages ? " [dontskipff]" : "");
546         else
547                 printf("%s %lld byte(s) at offset 0x%08llx\n",
548                        read ? "Reading" : "Writing", len, start_off);
549
550         io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB;
551         io_op.len = has_pages ? mtd->writesize : len;
552         io_op.ooblen = woob ? mtd->oobsize : 0;
553         io_op.datbuf = buf;
554         io_op.oobbuf = woob ? &buf[len] : NULL;
555
556         /* Search for the first good block after the given offset */
557         off = start_off;
558         while (mtd_block_isbad(mtd, off))
559                 off += mtd->erasesize;
560
561         /* Loop over the pages to do the actual read/write */
562         while (remaining) {
563                 /* Skip the block if it is bad */
564                 if (mtd_is_aligned_with_block_size(mtd, off) &&
565                     mtd_block_isbad(mtd, off)) {
566                         off += mtd->erasesize;
567                         continue;
568                 }
569
570                 if (read)
571                         ret = mtd_read_oob(mtd, off, &io_op);
572                 else
573                         ret = mtd_special_write_oob(mtd, off, &io_op,
574                                                     write_empty_pages, woob);
575
576                 if (ret) {
577                         printf("Failure while %s at offset 0x%llx\n",
578                                read ? "reading" : "writing", off);
579                         break;
580                 }
581
582                 off += io_op.retlen;
583                 remaining -= io_op.retlen;
584                 io_op.datbuf += io_op.retlen;
585                 io_op.oobbuf += io_op.oobretlen;
586         }
587
588         if (!ret && dump)
589                 mtd_dump_device_buf(mtd, start_off, buf, len, woob);
590
591         if (dump)
592                 kfree(buf);
593         else
594                 unmap_sysmem(buf);
595
596         if (ret) {
597                 printf("%s on %s failed with error %d\n",
598                        read ? "Read" : "Write", mtd->name, ret);
599                 ret = CMD_RET_FAILURE;
600         } else {
601                 ret = CMD_RET_SUCCESS;
602         }
603
604 out_put_mtd:
605         put_mtd_device(mtd);
606
607         return ret;
608 }
609
610 static int do_mtd_erase(struct cmd_tbl *cmdtp, int flag, int argc,
611                         char *const argv[])
612 {
613         struct erase_info erase_op = {};
614         struct mtd_info *mtd;
615         u64 off, len;
616         bool scrub;
617         int ret = 0;
618
619         if (argc < 2)
620                 return CMD_RET_USAGE;
621
622         mtd = get_mtd_by_name(argv[1]);
623         if (IS_ERR_OR_NULL(mtd))
624                 return CMD_RET_FAILURE;
625
626         scrub = strstr(argv[0], ".dontskipbad");
627
628         argc -= 2;
629         argv += 2;
630
631         off = argc > 0 ? hextoul(argv[0], NULL) : 0;
632         len = argc > 1 ? hextoul(argv[1], NULL) : mtd->size;
633
634         if (!mtd_is_aligned_with_block_size(mtd, off)) {
635                 printf("Offset not aligned with a block (0x%x)\n",
636                        mtd->erasesize);
637                 ret = CMD_RET_FAILURE;
638                 goto out_put_mtd;
639         }
640
641         if (!mtd_is_aligned_with_block_size(mtd, len)) {
642                 printf("Size not a multiple of a block (0x%x)\n",
643                        mtd->erasesize);
644                 ret = CMD_RET_FAILURE;
645                 goto out_put_mtd;
646         }
647
648         printf("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n",
649                off, off + len - 1, mtd_div_by_eb(len, mtd));
650
651         erase_op.mtd = mtd;
652         erase_op.addr = off;
653         erase_op.len = mtd->erasesize;
654
655         while (len) {
656                 if (!scrub) {
657                         ret = mtd_block_isbad(mtd, erase_op.addr);
658                         if (ret < 0) {
659                                 printf("Failed to get bad block at 0x%08llx\n",
660                                        erase_op.addr);
661                                 ret = CMD_RET_FAILURE;
662                                 goto out_put_mtd;
663                         }
664
665                         if (ret > 0) {
666                                 printf("Skipping bad block at 0x%08llx\n",
667                                        erase_op.addr);
668                                 ret = 0;
669                                 len -= mtd->erasesize;
670                                 erase_op.addr += mtd->erasesize;
671                                 continue;
672                         }
673                 }
674
675                 ret = mtd_erase(mtd, &erase_op);
676                 if (ret && ret != -EIO)
677                         break;
678
679                 len -= mtd->erasesize;
680                 erase_op.addr += mtd->erasesize;
681         }
682
683         if (ret && ret != -EIO)
684                 ret = CMD_RET_FAILURE;
685         else
686                 ret = CMD_RET_SUCCESS;
687
688 out_put_mtd:
689         put_mtd_device(mtd);
690
691         return ret;
692 }
693
694 static int do_mtd_bad(struct cmd_tbl *cmdtp, int flag, int argc,
695                       char *const argv[])
696 {
697         struct mtd_info *mtd;
698         loff_t off;
699
700         if (argc < 2)
701                 return CMD_RET_USAGE;
702
703         mtd = get_mtd_by_name(argv[1]);
704         if (IS_ERR_OR_NULL(mtd))
705                 return CMD_RET_FAILURE;
706
707         if (!mtd_can_have_bb(mtd)) {
708                 printf("Only NAND-based devices can have bad blocks\n");
709                 goto out_put_mtd;
710         }
711
712         printf("MTD device %s bad blocks list:\n", mtd->name);
713         for (off = 0; off < mtd->size; off += mtd->erasesize) {
714                 if (mtd_block_isbad(mtd, off))
715                         printf("\t0x%08llx\n", off);
716         }
717
718 out_put_mtd:
719         put_mtd_device(mtd);
720
721         return CMD_RET_SUCCESS;
722 }
723
724 #ifdef CONFIG_AUTO_COMPLETE
725 static int mtd_name_complete(int argc, char *const argv[], char last_char,
726                              int maxv, char *cmdv[])
727 {
728         int len = 0, n_found = 0;
729         struct mtd_info *mtd;
730
731         argc--;
732         argv++;
733
734         if (argc > 1 ||
735             (argc == 1 && (last_char == '\0' || isblank(last_char))))
736                 return 0;
737
738         if (argc)
739                 len = strlen(argv[0]);
740
741         mtd_for_each_device(mtd) {
742                 if (argc &&
743                     (len > strlen(mtd->name) ||
744                      strncmp(argv[0], mtd->name, len)))
745                         continue;
746
747                 if (n_found >= maxv - 2) {
748                         cmdv[n_found++] = "...";
749                         break;
750                 }
751
752                 cmdv[n_found++] = mtd->name;
753         }
754
755         cmdv[n_found] = NULL;
756
757         return n_found;
758 }
759 #endif /* CONFIG_AUTO_COMPLETE */
760
761 U_BOOT_LONGHELP(mtd,
762         "- generic operations on memory technology devices\n\n"
763         "mtd list\n"
764         "mtd read[.raw][.oob]                  <name> <addr> [<off> [<size>]]\n"
765         "mtd dump[.raw][.oob]                  <name>        [<off> [<size>]]\n"
766         "mtd write[.raw][.oob][.dontskipff]    <name> <addr> [<off> [<size>]]\n"
767         "mtd erase[.dontskipbad]               <name>        [<off> [<size>]]\n"
768         "\n"
769         "Specific functions:\n"
770         "mtd bad                               <name>\n"
771 #if CONFIG_IS_ENABLED(CMD_MTD_OTP)
772         "mtd otpread                           <name> [u|f] <off> <size>\n"
773         "mtd otpwrite                          <name> <off> <hex string>\n"
774         "mtd otplock                           <name> <off> <size>\n"
775         "mtd otpinfo                           <name> [u|f]\n"
776 #endif
777         "\n"
778         "With:\n"
779         "\t<name>: NAND partition/chip name (or corresponding DM device name or OF path)\n"
780         "\t<addr>: user address from/to which data will be retrieved/stored\n"
781         "\t<off>: offset in <name> in bytes (default: start of the part)\n"
782         "\t\t* must be block-aligned for erase\n"
783         "\t\t* must be page-aligned otherwise\n"
784         "\t<size>: length of the operation in bytes (default: the entire device)\n"
785         "\t\t* must be a multiple of a block for erase\n"
786         "\t\t* must be a multiple of a page otherwise (special case: default is a page with dump)\n"
787 #if CONFIG_IS_ENABLED(CMD_MTD_OTP)
788         "\t<hex string>: hex string without '0x' and spaces. Example: ABCD1234\n"
789         "\t[u|f]: user or factory OTP region\n"
790 #endif
791         "\n"
792         "The .dontskipff option forces writing empty pages, don't use it if unsure.\n");
793
794 U_BOOT_CMD_WITH_SUBCMDS(mtd, "MTD utils", mtd_help_text,
795 #if CONFIG_IS_ENABLED(CMD_MTD_OTP)
796                 U_BOOT_SUBCMD_MKENT(otpread, 5, 1, do_mtd_otp_read),
797                 U_BOOT_SUBCMD_MKENT(otpwrite, 4, 1, do_mtd_otp_write),
798                 U_BOOT_SUBCMD_MKENT(otplock, 4, 1, do_mtd_otp_lock),
799                 U_BOOT_SUBCMD_MKENT(otpinfo, 3, 1, do_mtd_otp_info),
800 #endif
801                 U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mtd_list),
802                 U_BOOT_SUBCMD_MKENT_COMPLETE(read, 5, 0, do_mtd_io,
803                                              mtd_name_complete),
804                 U_BOOT_SUBCMD_MKENT_COMPLETE(write, 5, 0, do_mtd_io,
805                                              mtd_name_complete),
806                 U_BOOT_SUBCMD_MKENT_COMPLETE(dump, 4, 0, do_mtd_io,
807                                              mtd_name_complete),
808                 U_BOOT_SUBCMD_MKENT_COMPLETE(erase, 4, 0, do_mtd_erase,
809                                              mtd_name_complete),
810                 U_BOOT_SUBCMD_MKENT_COMPLETE(bad, 2, 1, do_mtd_bad,
811                                              mtd_name_complete));
This page took 0.072988 seconds and 4 git commands to generate.