Commit 1d8a50993c2783892428c47cfe2e6241fd106caa

Authored by Alice Guo
Committed by Ye Li
1 parent b01b7e1d59

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",