Commit 1d8a50993c2783892428c47cfe2e6241fd106caa
Committed by
Ye Li
1 parent
b01b7e1d59
Exists in
smarc_8mm-imx_v2019.04_4.19.35_1.1.0
and in
1 other branch
MLK-22582-2: nandbcb: add nandbcb dump command for i.MX8MM
Verify/dump boot structures written to NAND Flash chip. Signed-off-by: Alice Guo <alice.guo@nxp.com> (cherry picked from commit 215953009a0429705a3aaaa7c495e6ad7a0a8a3a)
Showing 1 changed file with 235 additions and 6 deletions Side-by-side Diff
arch/arm/mach-imx/cmd_nandbcb.c
... | ... | @@ -22,12 +22,23 @@ |
22 | 22 | #include <mxs_nand.h> |
23 | 23 | #include <linux/mtd/mtd.h> |
24 | 24 | #include <nand.h> |
25 | +#include <div64.h> | |
25 | 26 | |
26 | 27 | #define BF_VAL(v, bf) (((v) & bf##_MASK) >> bf##_OFFSET) |
27 | 28 | #define GETBIT(v, n) (((v) >> (n)) & 0x1) |
28 | 29 | #define IMX8MQ_SPL_SZ 0x3e000 |
29 | 30 | #define IMX8MQ_HDMI_FW_SZ 0x19c00 |
31 | +#define BOOT_SEARCH_COUNT 2 | |
30 | 32 | |
33 | +struct mtd_info *dump_mtd; | |
34 | +static loff_t dump_nandboot_size; | |
35 | +static struct fcb_block dump_fill_fcb; | |
36 | +static struct dbbt_block dump_fill_dbbt; | |
37 | +static struct fcb_block dump_nand_fcb[BOOT_SEARCH_COUNT]; | |
38 | +static struct dbbt_block dump_nand_dbbt[BOOT_SEARCH_COUNT]; | |
39 | +static u32 dump_fcb_off[BOOT_SEARCH_COUNT]; | |
40 | +static u32 dump_dbbt_off[BOOT_SEARCH_COUNT]; | |
41 | + | |
31 | 42 | static u8 calculate_parity_13_8(u8 d) |
32 | 43 | { |
33 | 44 | u8 p = 0; |
... | ... | @@ -144,7 +155,7 @@ |
144 | 155 | return n_bad_blocks; |
145 | 156 | } |
146 | 157 | |
147 | -static int write_fcb_dbbt(struct mtd_info *mtd, struct fcb_block *fcb, | |
158 | +static int write_fcb_dbbt_and_readback(struct mtd_info *mtd, struct fcb_block *fcb, | |
148 | 159 | struct dbbt_block *dbbt, void *dbbt_data_page, |
149 | 160 | loff_t off) |
150 | 161 | { |
... | ... | @@ -199,6 +210,11 @@ |
199 | 210 | mxs_nand_mode_fcb(mtd); |
200 | 211 | ret = nand_write(mtd, off, &rwsize, |
201 | 212 | (unsigned char *)fcb); |
213 | + | |
214 | + dump_fcb_off[i] = off; | |
215 | + nand_read(mtd, off, &rwsize, | |
216 | + (unsigned char *)(dump_nand_fcb + i)); | |
217 | + | |
202 | 218 | mxs_nand_mode_normal(mtd); |
203 | 219 | |
204 | 220 | printf("%s\n", ret ? "ERROR" : "OK"); |
... | ... | @@ -229,6 +245,11 @@ |
229 | 245 | mtd->erasesize * i + mtd->writesize, dummy, |
230 | 246 | ret ? "ERROR" : "OK"); |
231 | 247 | |
248 | + dump_dbbt_off[i] = mtd->erasesize * i + mtd->writesize; | |
249 | + size_t rwsize = sizeof(*dbbt); | |
250 | + | |
251 | + nand_read(mtd, dump_dbbt_off[i], &rwsize, (unsigned char *)(dump_nand_dbbt + i)); | |
252 | + | |
232 | 253 | /* dbbtpages == 0 if no bad blocks */ |
233 | 254 | if (dbbt->dbbtpages > 0) { |
234 | 255 | loff_t to = (mtd->erasesize * i + mtd->writesize * 5); |
... | ... | @@ -293,7 +314,7 @@ |
293 | 314 | * - rest split in half for primary and secondary firmware |
294 | 315 | * - same firmware will write two times |
295 | 316 | */ |
296 | - nr_blks_fcb = 2; | |
317 | + nr_blks_fcb = BOOT_SEARCH_COUNT; | |
297 | 318 | nr_blks = maxsize / mtd->erasesize; |
298 | 319 | fw1_blk = nr_blks_fcb; |
299 | 320 | |
... | ... | @@ -369,6 +390,8 @@ |
369 | 390 | fw1_pages = (IMX8MQ_SPL_SZ + (mtd->writesize - 1)) / mtd->writesize; |
370 | 391 | fill_fcb(fcb, mtd, fw1_start, 0, fw1_pages); |
371 | 392 | |
393 | + dump_fill_fcb = *fcb; | |
394 | + | |
372 | 395 | /* fill dbbt */ |
373 | 396 | dbbt_page = kzalloc(mtd->writesize, GFP_KERNEL); |
374 | 397 | if (!dbbt_page) { |
375 | 398 | |
... | ... | @@ -394,8 +417,10 @@ |
394 | 417 | else if (ret > 0) |
395 | 418 | dbbt->dbbtpages = 1; |
396 | 419 | |
420 | + dump_fill_dbbt = *dbbt; | |
421 | + | |
397 | 422 | /* write fcb and dbbt to nand */ |
398 | - ret = write_fcb_dbbt(mtd, fcb, dbbt, dbbt_data_page, off); | |
423 | + ret = write_fcb_dbbt_and_readback(mtd, fcb, dbbt, dbbt_data_page, off); | |
399 | 424 | if (ret < 0) |
400 | 425 | printf("failed to write FCB/DBBT\n"); |
401 | 426 | |
... | ... | @@ -477,7 +502,7 @@ |
477 | 502 | dbbt->dbbtpages = 1; |
478 | 503 | |
479 | 504 | /* write fcb and dbbt to nand */ |
480 | - ret = write_fcb_dbbt(mtd, fcb, dbbt, dbbt_data_page, 0); | |
505 | + ret = write_fcb_dbbt_and_readback(mtd, fcb, dbbt, dbbt_data_page, 0); | |
481 | 506 | dbbt_data_page_err: |
482 | 507 | kfree(dbbt_data_page); |
483 | 508 | dbbt_page_err: |
... | ... | @@ -493,6 +518,199 @@ |
493 | 518 | return CMD_RET_SUCCESS; |
494 | 519 | } |
495 | 520 | |
521 | +/* dump data which is planned to be encoded and written to NAND chip */ | |
522 | +void mtd_cfg_dump(void) | |
523 | +{ | |
524 | + u64 blocks; | |
525 | + | |
526 | + printf("MTD CONFIG:\n"); | |
527 | + printf(" %s = %d\n", "data_setup_time", dump_fill_fcb.datasetup); | |
528 | + printf(" %s = %d\n", "data_hold_time", dump_fill_fcb.datahold); | |
529 | + printf(" %s = %d\n", "address_setup_time", dump_fill_fcb.addr_setup); | |
530 | + printf(" %s = %d\n", "data_sample_time", dump_fill_fcb.dsample_time); | |
531 | + | |
532 | + printf("NFC geometry :\n"); | |
533 | + printf("\tECC Strength : %d\n", dump_mtd->ecc_strength); | |
534 | + printf("\tPage Size in Bytes : %d\n", dump_fill_fcb.oob_pagesize); | |
535 | + printf("\tMetadata size : %d\n", dump_fill_fcb.meta_size); | |
536 | + printf("\tECC Chunk Size in byte : %d\n", dump_fill_fcb.ecc_size); | |
537 | + printf("\tECC Chunk count : %d\n", dump_fill_fcb.nr_blocks + 1); | |
538 | + printf("\tBlock Mark Byte Offset : %d\n", dump_fill_fcb.bb_byte); | |
539 | + printf("\tBlock Mark Bit Offset : %d\n", dump_fill_fcb.bb_start_bit); | |
540 | + printf("====================================================\n"); | |
541 | + | |
542 | + printf("mtd: partition #0\n"); | |
543 | + printf(" %s = %d\n", "type", dump_mtd->type); | |
544 | + printf(" %s = %d\n", "flags", dump_mtd->flags); | |
545 | + printf(" %s = %llu\n", "size", dump_nandboot_size); | |
546 | + printf(" %s = %d\n", "erasesize", dump_mtd->erasesize); | |
547 | + printf(" %s = %d\n", "writesize", dump_mtd->writesize); | |
548 | + printf(" %s = %d\n", "oobsize", dump_mtd->oobsize); | |
549 | + blocks = dump_nandboot_size; | |
550 | + do_div(blocks, dump_mtd->erasesize); | |
551 | + printf(" %s = %llu\n", "blocks", blocks); | |
552 | +} | |
553 | + | |
554 | +/* dump data which is read from NAND chip */ | |
555 | +void mtd_dump_structure(int i) | |
556 | +{ | |
557 | + #define P1(x) printf(" %s = 0x%08x\n", #x, dump_nand_fcb[i].x) | |
558 | + printf("FCB %d:\n", i); | |
559 | + P1(checksum); | |
560 | + P1(fingerprint); | |
561 | + P1(version); | |
562 | + #undef P1 | |
563 | + #define P1(x) printf(" %s = %d\n", #x, dump_nand_fcb[i].x) | |
564 | + P1(datasetup); | |
565 | + P1(datahold); | |
566 | + P1(addr_setup); | |
567 | + P1(dsample_time); | |
568 | + P1(pagesize); | |
569 | + P1(oob_pagesize); | |
570 | + P1(sectors); | |
571 | + P1(nr_nand); | |
572 | + P1(nr_die); | |
573 | + P1(celltype); | |
574 | + P1(ecc_type); | |
575 | + P1(ecc_nr); | |
576 | + P1(ecc_size); | |
577 | + P1(ecc_level); | |
578 | + P1(meta_size); | |
579 | + P1(nr_blocks); | |
580 | + P1(ecc_type_sdk); | |
581 | + P1(ecc_nr_sdk); | |
582 | + P1(ecc_size_sdk); | |
583 | + P1(ecc_level_sdk); | |
584 | + P1(nr_blocks_sdk); | |
585 | + P1(meta_size_sdk); | |
586 | + P1(erase_th); | |
587 | + P1(bootpatch); | |
588 | + P1(patch_size); | |
589 | + P1(fw1_start); | |
590 | + P1(fw2_start); | |
591 | + P1(fw1_pages); | |
592 | + P1(fw2_pages); | |
593 | + P1(dbbt_start); | |
594 | + P1(bb_byte); | |
595 | + P1(bb_start_bit); | |
596 | + P1(phy_offset); | |
597 | + P1(bchtype); | |
598 | + P1(readlatency); | |
599 | + P1(predelay); | |
600 | + P1(cedelay); | |
601 | + P1(postdelay); | |
602 | + P1(cmdaddpause); | |
603 | + P1(datapause); | |
604 | + P1(tmspeed); | |
605 | + P1(busytimeout); | |
606 | + P1(disbbm); | |
607 | + P1(spare_offset); | |
608 | + P1(onfi_sync_enable); | |
609 | + P1(onfi_sync_speed); | |
610 | + P1(onfi_sync_nand_data); | |
611 | + P1(disbbm_search); | |
612 | + P1(disbbm_search_limit); | |
613 | + P1(read_retry_enable); | |
614 | + #undef P1 | |
615 | + #define P1(x) printf(" %s = 0x%08x\n", #x, dump_nand_dbbt[i].x) | |
616 | + printf("DBBT %d:\n", i); | |
617 | + P1(checksum); | |
618 | + P1(fingerprint); | |
619 | + P1(version); | |
620 | + #undef P1 | |
621 | + #define P1(x) printf(" %s = %d\n", #x, dump_nand_dbbt[i].x) | |
622 | + P1(numberbb); | |
623 | + #undef P1 | |
624 | + | |
625 | + printf("Firmware: image #0 @ 0x%x size 0x%x - available 0x%llx\n", | |
626 | + dump_nand_fcb[i].fw1_start * dump_nand_fcb[i].pagesize, | |
627 | + dump_nand_fcb[i].fw1_pages * dump_nand_fcb[i].pagesize, | |
628 | + dump_nandboot_size - dump_nand_fcb[i].fw1_start * dump_nand_fcb[i].pagesize); | |
629 | + if (is_imx8m()) | |
630 | + printf("Extra Firmware: image #0 @ 0x%x size 0x%x - available 0x%llx\n", | |
631 | + dump_nand_fcb[i].fw1_start * dump_nand_fcb[i].pagesize + dump_mtd->erasesize * ((IMX8MQ_SPL_SZ + dump_mtd->erasesize - 1) / dump_mtd->erasesize), | |
632 | + dump_nand_fcb[i].fw1_pages * dump_nand_fcb[i].pagesize, | |
633 | + dump_nandboot_size - (dump_nand_fcb[i].fw1_start * dump_nand_fcb[i].pagesize + dump_mtd->erasesize * ((IMX8MQ_SPL_SZ + dump_mtd->erasesize - 1) / dump_mtd->erasesize))); | |
634 | +} | |
635 | + | |
636 | +static int do_nandbcb_dump(int argc, char * const argv[]) | |
637 | +{ | |
638 | + int num; | |
639 | + int stride; | |
640 | + int search_area_sz; | |
641 | + bool bab_block_table[BOOT_SEARCH_COUNT]; | |
642 | + int bab_block_flag; | |
643 | + | |
644 | + if (argc != 2) | |
645 | + return CMD_RET_USAGE; | |
646 | + | |
647 | + switch (argv[1][0]) { | |
648 | + case '0': | |
649 | + num = 0; | |
650 | + break; | |
651 | + case '1': | |
652 | + num = 1; | |
653 | + break; | |
654 | + default: | |
655 | + return CMD_RET_USAGE; | |
656 | + } | |
657 | + | |
658 | + /* dump data which is planned to be encoded and written to NAND chip */ | |
659 | + mtd_cfg_dump(); | |
660 | + | |
661 | + stride = dump_mtd->erasesize; | |
662 | + search_area_sz = BOOT_SEARCH_COUNT * stride; | |
663 | + printf("stride: %x, search_area_sz: %x\n", stride, search_area_sz); | |
664 | + | |
665 | + bab_block_flag = 0; | |
666 | + for (int i = 0; i < BOOT_SEARCH_COUNT; i++) { | |
667 | + if (mtd_block_isbad(dump_mtd, (loff_t)(dump_mtd->erasesize * i))) { | |
668 | + bab_block_table[i] = 1; | |
669 | + bab_block_flag = 1; | |
670 | + continue; | |
671 | + } | |
672 | + bab_block_table[i] = 0; | |
673 | + if (memcpy(dump_nand_fcb + i, &dump_fill_fcb, sizeof(dump_fill_fcb)) != 0) { | |
674 | + printf("mtd: found FCB%d candidate version %08x @%d:0x%x\n", | |
675 | + i, dump_nand_fcb[i].version, i, dump_fcb_off[i]); | |
676 | + } else { | |
677 | + printf("mtd: FCB%d not found\n", i); | |
678 | + } | |
679 | + } | |
680 | + | |
681 | + for (int i = 0; i < BOOT_SEARCH_COUNT; i++) { | |
682 | + if (mtd_block_isbad(dump_mtd, (loff_t)(dump_mtd->erasesize * i))) | |
683 | + continue; | |
684 | + | |
685 | + if (memcpy(dump_nand_dbbt + i, &dump_fill_dbbt, sizeof(dump_fill_dbbt)) != 0) { | |
686 | + printf("mtd: DBBT%d found\n", i); | |
687 | + printf("mtd: Valid DBBT%d found @%d:0x%x\n", i, i, dump_dbbt_off[i]); | |
688 | + | |
689 | + } else { | |
690 | + printf("mtd: DBBT%d not found\n", i); | |
691 | + } | |
692 | + } | |
693 | + if (bab_block_flag == 0) | |
694 | + printf("no bad block found, dbbt: %08x\n", dump_fill_dbbt.fingerprint); | |
695 | + else | |
696 | + for (int i = 0; i < BOOT_SEARCH_COUNT; i++) | |
697 | + if (bab_block_table[i] == 1) | |
698 | + printf("mtd: bad block @ 0x%llx\n", (loff_t)(dump_mtd->erasesize * i)); | |
699 | + | |
700 | + /* dump data which is read from NAND chip */ | |
701 | + if (num > (BOOT_SEARCH_COUNT - 1)) | |
702 | + return CMD_RET_USAGE; | |
703 | + | |
704 | + if (bab_block_table[num] == 1) { | |
705 | + printf("mtd: bad block @ 0x%llx (FCB - DBBT)\n", (loff_t)(dump_mtd->erasesize * num)); | |
706 | + return CMD_RET_USAGE; | |
707 | + } | |
708 | + | |
709 | + mtd_dump_structure(num); | |
710 | + | |
711 | + return 0; | |
712 | +} | |
713 | + | |
496 | 714 | static int do_nandbcb_update(int argc, char * const argv[]) |
497 | 715 | { |
498 | 716 | struct mtd_info *mtd; |
... | ... | @@ -520,6 +738,10 @@ |
520 | 738 | &maxsize, MTD_DEV_TYPE_NAND, mtd->size)) |
521 | 739 | return CMD_RET_FAILURE; |
522 | 740 | |
741 | + /* dump_mtd and dump_nandboot_size are used for "nandbcb dump [-v]" */ | |
742 | + dump_mtd = mtd; | |
743 | + dump_nandboot_size = maxsize; | |
744 | + | |
523 | 745 | buf = map_physmem(addr, size, MAP_WRBACK); |
524 | 746 | if (!buf) { |
525 | 747 | puts("failed to map physical memory\n"); |
... | ... | @@ -537,7 +759,7 @@ |
537 | 759 | const char *cmd; |
538 | 760 | int ret = 0; |
539 | 761 | |
540 | - if (argc < 5) | |
762 | + if (argc < 3) | |
541 | 763 | goto usage; |
542 | 764 | |
543 | 765 | cmd = argv[1]; |
... | ... | @@ -549,6 +771,11 @@ |
549 | 771 | goto done; |
550 | 772 | } |
551 | 773 | |
774 | + if (strcmp(cmd, "dump") == 0) { | |
775 | + ret = do_nandbcb_dump(argc, argv); | |
776 | + goto done; | |
777 | + } | |
778 | + | |
552 | 779 | if (strcmp(cmd, "bcbonly") == 0) { |
553 | 780 | ret = do_nandbcb_bcbonly(argc, argv); |
554 | 781 | goto done; |
... | ... | @@ -566,7 +793,9 @@ |
566 | 793 | " 'off|part' to memory address 'addr', skipping bad blocks\n" |
567 | 794 | "bcbonly fw-size fw1-off [fw2-off] - write only BCB (FCB and DBBT)\n" |
568 | 795 | " where `fw-size` is fw sizes in bytes, `fw1-off` and\n" |
569 | - " and `fw2-off` - firmware offsets "; | |
796 | + " and `fw2-off` - firmware offsets \n" | |
797 | + "nandbcb dump num - verify/dump boot structures\n" | |
798 | + " 'num' can be set to 0 and 1"; | |
570 | 799 | |
571 | 800 | U_BOOT_CMD(nandbcb, 5, 1, do_nandbcb, |
572 | 801 | "i.MX6 Nand BCB", |