arm64: mvebu: Add bubt command for flash image burn
[platform/kernel/u-boot.git] / cmd / mvebu / bubt.c
1 /*
2  * Copyright (C) 2016 Marvell International Ltd.
3  *
4  * SPDX-License-Identifier:     GPL-2.0
5  * https://spdx.org/licenses
6  */
7
8 #include <config.h>
9 #include <common.h>
10 #include <command.h>
11 #include <vsprintf.h>
12 #include <errno.h>
13 #include <dm.h>
14
15 #include <spi_flash.h>
16 #include <spi.h>
17 #include <nand.h>
18 #include <usb.h>
19 #include <fs.h>
20 #include <mmc.h>
21 #include <u-boot/sha1.h>
22 #include <u-boot/sha256.h>
23
24 #ifndef CONFIG_SYS_MMC_ENV_DEV
25 #define CONFIG_SYS_MMC_ENV_DEV  0
26 #endif
27
28 #if defined(CONFIG_ARMADA_8K)
29 #define MAIN_HDR_MAGIC          0xB105B002
30
31 struct mvebu_image_header {
32         u32     magic;                  /*  0-3  */
33         u32     prolog_size;            /*  4-7  */
34         u32     prolog_checksum;        /*  8-11 */
35         u32     boot_image_size;        /* 12-15 */
36         u32     boot_image_checksum;    /* 16-19 */
37         u32     rsrvd0;                 /* 20-23 */
38         u32     load_addr;              /* 24-27 */
39         u32     exec_addr;              /* 28-31 */
40         u8      uart_cfg;               /*  32   */
41         u8      baudrate;               /*  33   */
42         u8      ext_count;              /*  34   */
43         u8      aux_flags;              /*  35   */
44         u32     io_arg_0;               /* 36-39 */
45         u32     io_arg_1;               /* 40-43 */
46         u32     io_arg_2;               /* 43-47 */
47         u32     io_arg_3;               /* 48-51 */
48         u32     rsrvd1;                 /* 52-55 */
49         u32     rsrvd2;                 /* 56-59 */
50         u32     rsrvd3;                 /* 60-63 */
51 };
52 #elif defined(CONFIG_ARMADA_3700)       /* A3700 */
53 #define HASH_SUM_LEN            16
54 #define IMAGE_VERSION_3_6_0     0x030600
55 #define IMAGE_VERSION_3_5_0     0x030500
56
57 struct common_tim_data {
58         u32     version;
59         u32     identifier;
60         u32     trusted;
61         u32     issue_date;
62         u32     oem_unique_id;
63         u32     reserved[5];            /* Reserve 20 bytes */
64         u32     boot_flash_sign;
65         u32     num_images;
66         u32     num_keys;
67         u32     size_of_reserved;
68 };
69
70 struct mvebu_image_info {
71         u32     image_id;
72         u32     next_image_id;
73         u32     flash_entry_addr;
74         u32     load_addr;
75         u32     image_size;
76         u32     image_size_to_hash;
77         u32     hash_algorithm_id;
78         u32     hash[HASH_SUM_LEN];     /* Reserve 512 bits for the hash */
79         u32     partition_number;
80         u32     enc_algorithm_id;
81         u32     encrypt_start_offset;
82         u32     encrypt_size;
83 };
84 #endif /* CONFIG_ARMADA_XXX */
85
86 struct bubt_dev {
87         char name[8];
88         size_t (*read)(const char *file_name);
89         int (*write)(size_t image_size);
90         int (*active)(void);
91 };
92
93 static ulong get_load_addr(void)
94 {
95         const char *addr_str;
96         unsigned long addr;
97
98         addr_str = getenv("loadaddr");
99         if (addr_str)
100                 addr = simple_strtoul(addr_str, NULL, 16);
101         else
102                 addr = CONFIG_SYS_LOAD_ADDR;
103
104         return addr;
105 }
106
107 /********************************************************************
108  *     eMMC services
109  ********************************************************************/
110 #ifdef CONFIG_DM_MMC
111 static int mmc_burn_image(size_t image_size)
112 {
113         struct mmc      *mmc;
114         lbaint_t        start_lba;
115         lbaint_t        blk_count;
116         ulong           blk_written;
117         int             err;
118         const u8        mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
119
120         mmc = find_mmc_device(mmc_dev_num);
121         if (!mmc) {
122                 printf("No SD/MMC/eMMC card found\n");
123                 return -ENOMEDIUM;
124         }
125
126         err = mmc_init(mmc);
127         if (err) {
128                 printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
129                        mmc_dev_num);
130                 return err;
131         }
132
133 #ifdef CONFIG_SYS_MMC_ENV_PART
134         if (mmc->part_num != CONFIG_SYS_MMC_ENV_PART) {
135                 err = mmc_switch_part(mmc_dev_num, CONFIG_SYS_MMC_ENV_PART);
136                 if (err) {
137                         printf("MMC partition switch failed\n");
138                         return err;
139                 }
140         }
141 #endif
142
143         /* SD reserves LBA-0 for MBR and boots from LBA-1,
144          * MMC/eMMC boots from LBA-0
145          */
146         start_lba = IS_SD(mmc) ? 1 : 0;
147         blk_count = image_size / mmc->block_dev.blksz;
148         if (image_size % mmc->block_dev.blksz)
149                 blk_count += 1;
150
151         blk_written = mmc->block_dev.block_write(mmc_dev_num,
152                                                 start_lba, blk_count,
153                                                 (void *)get_load_addr());
154         if (blk_written != blk_count) {
155                 printf("Error - written %#lx blocks\n", blk_written);
156                 return -ENOSPC;
157         }
158         printf("Done!\n");
159
160 #ifdef CONFIG_SYS_MMC_ENV_PART
161         if (mmc->part_num != CONFIG_SYS_MMC_ENV_PART)
162                 mmc_switch_part(mmc_dev_num, mmc->part_num);
163 #endif
164
165         return 0;
166 }
167
168 static size_t mmc_read_file(const char *file_name)
169 {
170         loff_t          act_read = 0;
171         int             rc;
172         struct mmc      *mmc;
173         const u8        mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
174
175         mmc = find_mmc_device(mmc_dev_num);
176         if (!mmc) {
177                 printf("No SD/MMC/eMMC card found\n");
178                 return 0;
179         }
180
181         if (mmc_init(mmc)) {
182                 printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
183                        mmc_dev_num);
184                 return 0;
185         }
186
187         /* Load from data partition (0) */
188         if (fs_set_blk_dev("mmc", "0", FS_TYPE_ANY)) {
189                 printf("Error: MMC 0 not found\n");
190                 return 0;
191         }
192
193         /* Perfrom file read */
194         rc = fs_read(file_name, get_load_addr(), 0, 0, &act_read);
195         if (rc)
196                 return 0;
197
198         return act_read;
199 }
200
201 static int is_mmc_active(void)
202 {
203         return 1;
204 }
205 #else /* CONFIG_DM_MMC */
206 static int mmc_burn_image(size_t image_size)
207 {
208         return -ENODEV;
209 }
210
211 static size_t mmc_read_file(const char *file_name)
212 {
213         return 0;
214 }
215
216 static int is_mmc_active(void)
217 {
218         return 0;
219 }
220 #endif /* CONFIG_DM_MMC */
221
222 /********************************************************************
223  *     SPI services
224  ********************************************************************/
225 #ifdef CONFIG_SPI_FLASH
226 static int spi_burn_image(size_t image_size)
227 {
228         int ret;
229         struct spi_flash *flash;
230         u32 erase_bytes;
231
232         /* Probe the SPI bus to get the flash device */
233         flash = spi_flash_probe(CONFIG_ENV_SPI_BUS,
234                                 CONFIG_ENV_SPI_CS,
235                                 CONFIG_SF_DEFAULT_SPEED,
236                                 CONFIG_SF_DEFAULT_MODE);
237         if (!flash) {
238                 printf("Failed to probe SPI Flash\n");
239                 return -ENOMEDIUM;
240         }
241
242 #ifdef CONFIG_SPI_FLASH_PROTECTION
243         spi_flash_protect(flash, 0);
244 #endif
245         erase_bytes = image_size +
246                 (flash->erase_size - image_size % flash->erase_size);
247         printf("Erasing %d bytes (%d blocks) at offset 0 ...",
248                erase_bytes, erase_bytes / flash->erase_size);
249         ret = spi_flash_erase(flash, 0, erase_bytes);
250         if (ret)
251                 printf("Error!\n");
252         else
253                 printf("Done!\n");
254
255         printf("Writing %d bytes from 0x%lx to offset 0 ...",
256                (int)image_size, get_load_addr());
257         ret = spi_flash_write(flash, 0, image_size, (void *)get_load_addr());
258         if (ret)
259                 printf("Error!\n");
260         else
261                 printf("Done!\n");
262
263 #ifdef CONFIG_SPI_FLASH_PROTECTION
264         spi_flash_protect(flash, 1);
265 #endif
266
267         return ret;
268 }
269
270 static int is_spi_active(void)
271 {
272         return 1;
273 }
274
275 #else /* CONFIG_SPI_FLASH */
276 static int spi_burn_image(size_t image_size)
277 {
278         return -ENODEV;
279 }
280
281 static int is_spi_active(void)
282 {
283         return 0;
284 }
285 #endif /* CONFIG_SPI_FLASH */
286
287 /********************************************************************
288  *     NAND services
289  ********************************************************************/
290 #ifdef CONFIG_CMD_NAND
291 static int nand_burn_image(size_t image_size)
292 {
293         int ret, block_size;
294         nand_info_t *nand;
295         int dev = nand_curr_device;
296
297         if ((dev < 0) || (dev >= CONFIG_SYS_MAX_NAND_DEVICE) ||
298             (!nand_info[dev].name)) {
299                 puts("\nno devices available\n");
300                 return -ENOMEDIUM;
301         }
302         nand = &nand_info[dev];
303         block_size = nand->erasesize;
304
305         /* Align U-Boot size to currently used blocksize */
306         image_size = ((image_size + (block_size - 1)) & (~(block_size - 1)));
307
308         /* Erase the U-BOOT image space */
309         printf("Erasing 0x%x - 0x%x:...", 0, (int)image_size);
310         ret = nand_erase(nand, 0, image_size);
311         if (ret) {
312                 printf("Error!\n");
313                 goto error;
314         }
315         printf("Done!\n");
316
317         /* Write the image to flash */
318         printf("Writing image:...");
319         printf("&image_size = 0x%p\n", (void *)&image_size);
320         ret = nand_write(nand, 0, &image_size, (void *)get_load_addr());
321         if (ret)
322                 printf("Error!\n");
323         else
324                 printf("Done!\n");
325
326 error:
327         return ret;
328 }
329
330 static int is_nand_active(void)
331 {
332         return 1;
333 }
334
335 #else /* CONFIG_CMD_NAND */
336 static int nand_burn_image(size_t image_size)
337 {
338         return -ENODEV;
339 }
340
341 static int is_nand_active(void)
342 {
343         return 0;
344 }
345 #endif /* CONFIG_CMD_NAND */
346
347 /********************************************************************
348  *     USB services
349  ********************************************************************/
350 #if defined(CONFIG_USB_STORAGE) && defined(CONFIG_BLK)
351 static size_t usb_read_file(const char *file_name)
352 {
353         loff_t act_read = 0;
354         struct udevice *dev;
355         int rc;
356
357         usb_stop();
358
359         if (usb_init() < 0) {
360                 printf("Error: usb_init failed\n");
361                 return 0;
362         }
363
364         /* Try to recognize storage devices immediately */
365         blk_first_device(IF_TYPE_USB, &dev);
366         if (!dev) {
367                 printf("Error: USB storage device not found\n");
368                 return 0;
369         }
370
371         /* Always load from usb 0 */
372         if (fs_set_blk_dev("usb", "0", FS_TYPE_ANY)) {
373                 printf("Error: USB 0 not found\n");
374                 return 0;
375         }
376
377         /* Perfrom file read */
378         rc = fs_read(file_name, get_load_addr(), 0, 0, &act_read);
379         if (rc)
380                 return 0;
381
382         return act_read;
383 }
384
385 static int is_usb_active(void)
386 {
387         return 1;
388 }
389
390 #else /* defined(CONFIG_USB_STORAGE) && defined (CONFIG_BLK) */
391 static size_t usb_read_file(const char *file_name)
392 {
393         return 0;
394 }
395
396 static int is_usb_active(void)
397 {
398         return 0;
399 }
400 #endif /* defined(CONFIG_USB_STORAGE) && defined (CONFIG_BLK) */
401
402 /********************************************************************
403  *     Network services
404  ********************************************************************/
405 #ifdef CONFIG_CMD_NET
406 static size_t tftp_read_file(const char *file_name)
407 {
408         /* update global variable load_addr before tftp file from network */
409         load_addr = get_load_addr();
410         return net_loop(TFTPGET);
411 }
412
413 static int is_tftp_active(void)
414 {
415         return 1;
416 }
417
418 #else
419 static size_t tftp_read_file(const char *file_name)
420 {
421         return 0;
422 }
423
424 static int is_tftp_active(void)
425 {
426         return 0;
427 }
428 #endif /* CONFIG_CMD_NET */
429
430 enum bubt_devices {
431         BUBT_DEV_NET = 0,
432         BUBT_DEV_USB,
433         BUBT_DEV_MMC,
434         BUBT_DEV_SPI,
435         BUBT_DEV_NAND,
436
437         BUBT_MAX_DEV
438 };
439
440 struct bubt_dev bubt_devs[BUBT_MAX_DEV] = {
441         {"tftp", tftp_read_file, NULL, is_tftp_active},
442         {"usb",  usb_read_file,  NULL, is_usb_active},
443         {"mmc",  mmc_read_file,  mmc_burn_image, is_mmc_active},
444         {"spi",  NULL, spi_burn_image,  is_spi_active},
445         {"nand", NULL, nand_burn_image, is_nand_active},
446 };
447
448 static int bubt_write_file(struct bubt_dev *dst, size_t image_size)
449 {
450         if (!dst->write) {
451                 printf("Error: Write not supported on device %s\n", dst->name);
452                 return -ENOTSUPP;
453         }
454
455         return dst->write(image_size);
456 }
457
458 #if defined(CONFIG_ARMADA_8K)
459 u32 do_checksum32(u32 *start, int32_t len)
460 {
461         u32 sum = 0;
462         u32 *startp = start;
463
464         do {
465                 sum += *startp;
466                 startp++;
467                 len -= 4;
468         } while (len > 0);
469
470         return sum;
471 }
472
473 static int check_image_header(void)
474 {
475         struct mvebu_image_header *hdr =
476                         (struct mvebu_image_header *)get_load_addr();
477         u32 header_len = hdr->prolog_size;
478         u32 checksum;
479         u32 checksum_ref = hdr->prolog_checksum;
480
481         /*
482          * For now compare checksum, and magic. Later we can
483          * verify more stuff on the header like interface type, etc
484          */
485         if (hdr->magic != MAIN_HDR_MAGIC) {
486                 printf("ERROR: Bad MAGIC 0x%08x != 0x%08x\n",
487                        hdr->magic, MAIN_HDR_MAGIC);
488                 return -ENOEXEC;
489         }
490
491         /* The checksum value is discarded from checksum calculation */
492         hdr->prolog_checksum = 0;
493
494         checksum = do_checksum32((u32 *)hdr, header_len);
495         if (checksum != checksum_ref) {
496                 printf("Error: Bad Image checksum. 0x%x != 0x%x\n",
497                        checksum, checksum_ref);
498                 return -ENOEXEC;
499         }
500
501         /* Restore the checksum before writing */
502         hdr->prolog_checksum = checksum_ref;
503         printf("Image checksum...OK!\n");
504
505         return 0;
506 }
507 #elif defined(CONFIG_ARMADA_3700) /* Armada 3700 */
508 static int check_image_header(void)
509 {
510         struct common_tim_data *hdr = (struct common_tim_data *)get_load_addr();
511         int image_num;
512         u8 hash_160_output[SHA1_SUM_LEN];
513         u8 hash_256_output[SHA256_SUM_LEN];
514         sha1_context hash1_text;
515         sha256_context hash256_text;
516         u8 *hash_output;
517         u32 hash_algorithm_id;
518         u32 image_size_to_hash;
519         u32 flash_entry_addr;
520         u32 *hash_value;
521         u32 internal_hash[HASH_SUM_LEN];
522         const u8 *buff;
523         u32 num_of_image = hdr->num_images;
524         u32 version = hdr->version;
525         u32 trusted = hdr->trusted;
526
527         /* bubt checksum validation only supports nontrusted images */
528         if (trusted == 1) {
529                 printf("bypass image validation, ");
530                 printf("only untrusted image is supported now\n");
531                 return 0;
532         }
533         /* only supports image version 3.5 and 3.6 */
534         if (version != IMAGE_VERSION_3_5_0 && version != IMAGE_VERSION_3_6_0) {
535                 printf("Error: Unsupported Image version = 0x%08x\n", version);
536                 return -ENOEXEC;
537         }
538         /* validate images hash value */
539         for (image_num = 0; image_num < num_of_image; image_num++) {
540                 struct mvebu_image_info *info =
541                                 (struct mvebu_image_info *)(get_load_addr() +
542                                 sizeof(struct common_tim_data) +
543                                 image_num * sizeof(struct mvebu_image_info));
544                 hash_algorithm_id = info->hash_algorithm_id;
545                 image_size_to_hash = info->image_size_to_hash;
546                 flash_entry_addr = info->flash_entry_addr;
547                 hash_value = info->hash;
548                 buff = (const u8 *)(get_load_addr() + flash_entry_addr);
549
550                 if (image_num == 0) {
551                         /*
552                          * The first image includes hash values in its content.
553                          * For hash calculation, we need to save the original
554                          * hash values to a local variable that will be
555                          * copied back for comparsion and set all zeros to
556                          * the orignal hash values for calculating new value.
557                          * First image original format :
558                          * x...x (datum1) x...x(orig. hash values) x...x(datum2)
559                          * Replaced first image format :
560                          * x...x (datum1) 0...0(hash values) x...x(datum2)
561                          */
562                         memcpy(internal_hash, hash_value,
563                                sizeof(internal_hash));
564                         memset(hash_value, 0, sizeof(internal_hash));
565                 }
566                 if (image_size_to_hash == 0) {
567                         printf("Warning: Image_%d hash checksum is disabled, ",
568                                image_num);
569                         printf("skip the image validation.\n");
570                         continue;
571                 }
572                 switch (hash_algorithm_id) {
573                 case SHA1_SUM_LEN:
574                         sha1_starts(&hash1_text);
575                         sha1_update(&hash1_text, buff, image_size_to_hash);
576                         sha1_finish(&hash1_text, hash_160_output);
577                         hash_output = hash_160_output;
578                         break;
579                 case SHA256_SUM_LEN:
580                         sha256_starts(&hash256_text);
581                         sha256_update(&hash256_text, buff, image_size_to_hash);
582                         sha256_finish(&hash256_text, hash_256_output);
583                         hash_output = hash_256_output;
584                         break;
585                 default:
586                         printf("Error: Unsupported hash_algorithm_id = %d\n",
587                                hash_algorithm_id);
588                         return -ENOEXEC;
589                 }
590                 if (image_num == 0)
591                         memcpy(hash_value, internal_hash,
592                                sizeof(internal_hash));
593                 if (memcmp(hash_value, hash_output, hash_algorithm_id) != 0) {
594                         printf("Error: Image_%d checksum is not correct\n",
595                                image_num);
596                         return -ENOEXEC;
597                 }
598         }
599         printf("Image checksum...OK!\n");
600
601         return 0;
602 }
603
604 #else /* Not ARMADA? */
605 static int check_image_header(void)
606 {
607         printf("bubt cmd does not support this SoC device or family!\n");
608         return -ENOEXEC;
609 }
610 #endif
611
612 static int bubt_verify(size_t image_size)
613 {
614         int err;
615
616         /* Check a correct image header exists */
617         err = check_image_header();
618         if (err) {
619                 printf("Error: Image header verification failed\n");
620                 return err;
621         }
622
623         return 0;
624 }
625
626 static int bubt_read_file(struct bubt_dev *src)
627 {
628         size_t image_size;
629
630         if (!src->read) {
631                 printf("Error: Read not supported on device \"%s\"\n",
632                        src->name);
633                 return 0;
634         }
635
636         image_size = src->read(net_boot_file_name);
637         if (image_size <= 0) {
638                 printf("Error: Failed to read file %s from %s\n",
639                        net_boot_file_name, src->name);
640                 return 0;
641         }
642
643         return image_size;
644 }
645
646 static int bubt_is_dev_active(struct bubt_dev *dev)
647 {
648         if (!dev->active) {
649                 printf("Device \"%s\" not supported by U-BOOT image\n",
650                        dev->name);
651                 return 0;
652         }
653
654         if (!dev->active()) {
655                 printf("Device \"%s\" is inactive\n", dev->name);
656                 return 0;
657         }
658
659         return 1;
660 }
661
662 struct bubt_dev *find_bubt_dev(char *dev_name)
663 {
664         int dev;
665
666         for (dev = 0; dev < BUBT_MAX_DEV; dev++) {
667                 if (strcmp(bubt_devs[dev].name, dev_name) == 0)
668                         return &bubt_devs[dev];
669         }
670
671         return 0;
672 }
673
674 #define DEFAULT_BUBT_SRC "tftp"
675
676 #ifndef DEFAULT_BUBT_DST
677 #ifdef CONFIG_MVEBU_SPI_BOOT
678 #define DEFAULT_BUBT_DST "spi"
679 #elif defined(CONFIG_MVEBU_NAND_BOOT)
680 #define DEFAULT_BUBT_DST "nand"
681 #elif defined(CONFIG_MVEBU_MMC_BOOT)
682 #define DEFAULT_BUBT_DST "mmc"
683 else
684 #define DEFAULT_BUBT_DST "error"
685 #endif
686 #endif /* DEFAULT_BUBT_DST */
687
688 int do_bubt_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
689 {
690         struct bubt_dev *src, *dst;
691         size_t image_size;
692         char src_dev_name[8];
693         char dst_dev_name[8];
694         char *name;
695         int  err;
696
697         if (argc < 2)
698                 copy_filename(net_boot_file_name,
699                               CONFIG_MVEBU_UBOOT_DFLT_NAME,
700                               sizeof(net_boot_file_name));
701         else
702                 copy_filename(net_boot_file_name, argv[1],
703                               sizeof(net_boot_file_name));
704
705         if (argc >= 3) {
706                 strncpy(dst_dev_name, argv[2], 8);
707         } else {
708                 name = DEFAULT_BUBT_DST;
709                 strncpy(dst_dev_name, name, 8);
710         }
711
712         if (argc >= 4)
713                 strncpy(src_dev_name, argv[3], 8);
714         else
715                 strncpy(src_dev_name, DEFAULT_BUBT_SRC, 8);
716
717         /* Figure out the destination device */
718         dst = find_bubt_dev(dst_dev_name);
719         if (!dst) {
720                 printf("Error: Unknown destination \"%s\"\n", dst_dev_name);
721                 return -EINVAL;
722         }
723
724         if (!bubt_is_dev_active(dst))
725                 return -ENODEV;
726
727         /* Figure out the source device */
728         src = find_bubt_dev(src_dev_name);
729         if (!src) {
730                 printf("Error: Unknown source \"%s\"\n", src_dev_name);
731                 return 1;
732         }
733
734         if (!bubt_is_dev_active(src))
735                 return -ENODEV;
736
737         printf("Burning U-BOOT image \"%s\" from \"%s\" to \"%s\"\n",
738                net_boot_file_name, src->name, dst->name);
739
740         image_size = bubt_read_file(src);
741         if (!image_size)
742                 return -EIO;
743
744         err = bubt_verify(image_size);
745         if (err)
746                 return err;
747
748         err = bubt_write_file(dst, image_size);
749         if (err)
750                 return err;
751
752         return 0;
753 }
754
755 U_BOOT_CMD(
756         bubt, 4, 0, do_bubt_cmd,
757         "Burn a u-boot image to flash",
758         "[file-name] [destination [source]]\n"
759         "\t-file-name     The image file name to burn. Default = flash-image.bin\n"
760         "\t-destination   Flash to burn to [spi, nand, mmc]. Default = active boot device\n"
761         "\t-source        The source to load image from [tftp, usb, mmc]. Default = tftp\n"
762         "Examples:\n"
763         "\tbubt - Burn flash-image.bin from tftp to active boot device\n"
764         "\tbubt flash-image-new.bin nand - Burn flash-image-new.bin from tftp to NAND flash\n"
765         "\tbubt backup-flash-image.bin mmc usb - Burn backup-flash-image.bin from usb to MMC\n"
766
767 );