From f30bf0601b3eb2918cf1f5883a254a3e38b56d44 Mon Sep 17 00:00:00 2001 From: Leif Middelschulte Date: Wed, 14 Apr 2021 00:00:24 +0200 Subject: [PATCH 01/14] introduce BCB flags Make the BCB handling (BCB, LDLB, FCB, DBBT) configurable. Some SoCs, like the i.MX6, might use the modern gpmi-nand. This moved error code implementation and some bad block handling to the hardware or, at least, driver. This is preparatory work to leverage these interfaces. Signed-off-by: Leif Middelschulte --- src/BootControlBlocks.h | 7 ++ src/mtd.c | 271 +++++++++++++++++++++++++++------------- src/plat_boot_config.c | 12 ++ src/plat_boot_config.h | 1 + 4 files changed, 201 insertions(+), 90 deletions(-) diff --git a/src/BootControlBlocks.h b/src/BootControlBlocks.h index 4ca79d8..bfbb3b2 100644 --- a/src/BootControlBlocks.h +++ b/src/BootControlBlocks.h @@ -44,6 +44,13 @@ #define TYPICAL_NAND_READ_SIZE 2048 #define BCB_MAGIC_OFFSET 12 +#define FCB_OFFSET 2 // I do not know the reason for the two bytes. + +#define BCB_READ_VIA_FILE_API (1 << 0) +#define BCB_READ_NCB (1 << 1) +#define BCB_READ_LDLB (1 << 2) +#define BCB_READ_DBBT (1 << 3) +#define BCB_READ_FCB (1 << 4) #define MAXSEQLEN 183 diff --git a/src/mtd.c b/src/mtd.c index 53ed5a5..7b3231f 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -1480,29 +1480,13 @@ void *mtd_load_boot_structure(struct mtd_data *md, int chip, loff_t *ofsp, loff_ return md->buf; } -/* single chip version */ -int mtd_load_all_boot_structures(struct mtd_data *md) +static int mtd_load_nand_control_block(struct mtd_data *md, int stride, int search_area_sz) { loff_t ofs, end; - int search_area_sz, stride; - int i, j, r, no, sz; + int i; void *buf; - BadBlockTableNand_t *bbtn; - struct mtd_part *mp; int chip; - stride = PAGES_PER_STRIDE * mtd_writesize(md); - search_area_sz = (1 << md->cfg.search_exponent) * stride; - - /* make sure it fits */ - if (search_area_sz * 6 > mtd_size(md)) { - fprintf(stderr, "mtd: search areas too large\n" - "\tsearch_area_sz * 6 > mtd_size\n" - "\t%#x * 6 > %#x", - search_area_sz, mtd_size(md)); - return -1; - } - /* NCBs are NCB1, NCB2 */ for (i = 0; i < 2; i++) { @@ -1575,6 +1559,16 @@ int mtd_load_all_boot_structures(struct mtd_data *md) else md->curr_ncb = &md->ncb[1]; + return 0; +} + +static int mtd_load_logical_drive_layout_block(struct mtd_data *md, int stride, int search_area_sz) +{ + loff_t ofs, end; + int i; + void *buf; + int chip; + /* LDLBs are right after the NCBs */ for (i = 0; i < 2; i++) { @@ -1625,95 +1619,129 @@ int mtd_load_all_boot_structures(struct mtd_data *md) else md->curr_ldlb = &md->ldlb[1]; - /* DBBTs are right after the LDLBs */ - for (i = 0; i < 2; i++) { - - if (multichip(md)) { - ofs = 2 * search_area_sz; - chip = i; - } else { - ofs = (4 + i) * search_area_sz; - chip = 0; - } + return 0; +} - end = ofs + search_area_sz; - md->curr_dbbt = NULL; - md->dbbt_ofs[i] = -1; +static int mtd_load_discoverable_bad_block_table(struct mtd_data *md, int stride, int search_area_sz) +{ + loff_t ofs, end; + int i, j, r, no, sz; + void *buf; + int chip; - buf = mtd_load_boot_structure(md, chip, &ofs, end, - DBBT_FINGERPRINT1, - plat_config_data->m_u32DBBT_FingerPrint, - DBBT_FINGERPRINT3, - 1, 0); - if (buf == NULL) { - fprintf(stderr, "mtd: DBBT%d not found\n", i); - continue; + if (plat_config_data->m_u32BCBBlocksFlags & (BCB_READ_FCB || BCB_READ_VIA_FILE_API)) { + loff_t dbbt_offset = md->fcb.FCB_Block.m_u32DBBTSearchAreaStartAddress * md->fcb.FCB_Block.m_u32PageDataSize; + const size_t dbbt_size = sizeof(md->dbbt50.DBBT_Block.v3) + offsetof(BCB_ROM_BootBlockStruct_t, DBBT_Block); + for (i = 0; i < 3; i++) { + r = mtd_read(md, 0, &md->dbbt50, dbbt_size, dbbt_offset); + if (r != dbbt_size) + return -1; + /* there is no checksum inside the dbbt structure */ + if (md->dbbt50.m_u32FingerPrint == plat_config_data->m_u32DBBT_FingerPrint) + return 0; + dbbt_offset += md->fcb.FCB_Block.m_u32PageDataSize; } - md->curr_dbbt = buf; + return -1; + } else { + /* DBBTs are right after the LDLBs */ + for (i = 0; i < 2; i++) { - if (md->flags & F_VERBOSE) - printf("mtd: Valid DBBT%d found @%d:0x%llx\n", i, chip, ofs); + if (multichip(md)) { + ofs = 2 * search_area_sz; + chip = i; + } else { + ofs = (4 + i) * search_area_sz; + chip = 0; + } - md->dbbt[i] = *md->curr_dbbt; - md->curr_dbbt = NULL; - md->dbbt_ofs[i] = ofs; - } + end = ofs + search_area_sz; + md->curr_dbbt = NULL; + md->dbbt_ofs[i] = -1; - if (md->dbbt_ofs[0] != -1 && md->dbbt_ofs[1] != -1) { - if (memcmp(&md->dbbt[0], &md->dbbt[1], sizeof(md->dbbt[0])) != 0) - printf("mtd: warning DBBT1 != DBBT2, using DBBT2\n"); - } + buf = mtd_load_boot_structure(md, chip, &ofs, end, + DBBT_FINGERPRINT1, + plat_config_data->m_u32DBBT_FingerPrint, + DBBT_FINGERPRINT3, + 1, 0); + if (buf == NULL) { + fprintf(stderr, "mtd: DBBT%d not found\n", i); + continue; + } + md->curr_dbbt = buf; - if (md->dbbt_ofs[0] == -1 && md->dbbt_ofs[1] == -1) { - fprintf(stderr, "mtd: neither DBBT1 or DBBT2 found ERROR\n"); - return -1; - } + if (md->flags & F_VERBOSE) + printf("mtd: Valid DBBT%d found @%d:0x%llx\n", i, chip, ofs); - /* prefer 0 */ - if (md->dbbt_ofs[0] != -1) - md->curr_dbbt = &md->dbbt[0]; - else - md->curr_dbbt = &md->dbbt[1]; + md->dbbt[i] = *md->curr_dbbt; + md->curr_dbbt = NULL; + md->dbbt_ofs[i] = ofs; + } - /* no bad blocks what-so-ever */ - if (md->curr_dbbt->DBBT_Block1.m_u32Number2KPagesBB_NAND0 == 0 && - md->curr_dbbt->DBBT_Block1.m_u32Number2KPagesBB_NAND1 == 0) - return 0; + if (md->dbbt_ofs[0] != -1 && md->dbbt_ofs[1] != -1) { + if (memcmp(&md->dbbt[0], &md->dbbt[1], sizeof(md->dbbt[0])) != 0) + printf("mtd: warning DBBT1 != DBBT2, using DBBT2\n"); + } - /* find DBBT to read from */ - if (md->curr_dbbt == &md->dbbt[0]) { - ofs = md->dbbt_ofs[0]; - chip = 0; - } - else { - ofs = md->dbbt_ofs[1]; - if (multichip(md)) - chip = 1; - } + if (md->dbbt_ofs[0] == -1 && md->dbbt_ofs[1] == -1) { + fprintf(stderr, "mtd: neither DBBT1 or DBBT2 found ERROR\n"); + return -1; + } - /* BBTNs start here */ - ofs += 4 * 2048; - for (j = 0; j < 2; j++, ofs += sz) { - if (j == 0) - sz = md->curr_dbbt->DBBT_Block1.m_u32Number2KPagesBB_NAND0; + /* prefer 0 */ + if (md->dbbt_ofs[0] != -1) + md->curr_dbbt = &md->dbbt[0]; else - sz = md->curr_dbbt->DBBT_Block1.m_u32Number2KPagesBB_NAND1; - if (sz == 0) - continue; - sz *= 2048; - md->bbtn[j] = malloc(sz); - if (md->bbtn[j] == NULL) { - printf("mtd: UNABLE to allocate %d bytes for BBTN%d\n", sz, j); - continue; + md->curr_dbbt = &md->dbbt[1]; + + /* no bad blocks what-so-ever */ + if (md->curr_dbbt->DBBT_Block1.m_u32Number2KPagesBB_NAND0 == 0 && + md->curr_dbbt->DBBT_Block1.m_u32Number2KPagesBB_NAND1 == 0) + return 0; + + /* find DBBT to read from */ + if (md->curr_dbbt == &md->dbbt[0]) { + ofs = md->dbbt_ofs[0]; + chip = 0; } - r = mtd_read(md, chip, md->bbtn[j], sz, ofs); - if (r != sz) { - printf("mtd: UNABLE to read %d bytes for BBTN%d\n", sz, j); - continue; + else { + ofs = md->dbbt_ofs[1]; + if (multichip(md)) + chip = 1; } + /* BBTNs start here */ + ofs += 4 * 2048; + for (j = 0; j < 2; j++, ofs += sz) { + if (j == 0) + sz = md->curr_dbbt->DBBT_Block1.m_u32Number2KPagesBB_NAND0; + else + sz = md->curr_dbbt->DBBT_Block1.m_u32Number2KPagesBB_NAND1; + if (sz == 0) + continue; + sz *= 2048; + md->bbtn[j] = malloc(sz); + if (md->bbtn[j] == NULL) { + printf("mtd: UNABLE to allocate %d bytes for BBTN%d\n", sz, j); + continue; + } + r = mtd_read(md, chip, md->bbtn[j], sz, ofs); + if (r != sz) { + printf("mtd: UNABLE to read %d bytes for BBTN%d\n", sz, j); + continue; + } + + } } + return 0; +} + +void mtd_update_discoverable_bad_block_table(struct mtd_data *md) +{ + BadBlockTableNand_t *bbtn; + struct mtd_part *mp; + int i, j, no; + /* update bad block table */ for (j = 0; j < 2; j++) { @@ -1743,6 +1771,69 @@ int mtd_load_all_boot_structures(struct mtd_data *md) printf("mtd: '%s' bad block @ 0x%llx (DBBT)\n", mp->name, (loff_t)no * mtd_erasesize(md)); } } +} + +static int mtd_load_firmware_control_block(struct mtd_data *md) +{ + const size_t size_of_fcb = sizeof(md->fcb.FCB_Block) + offsetof(BCB_ROM_BootBlockStruct_t, FCB_Block); + int r = 0; + r = mtd_read(md, 0, &md->fcb, size_of_fcb, FCB_OFFSET); + if (r != size_of_fcb) + return -1; + if (md->fcb.m_u32FingerPrint != FCB_FINGERPRINT) + return -1; + return 0; +} + +/* single chip version */ +int mtd_load_all_boot_structures(struct mtd_data *md) +{ + loff_t ofs, end; + int search_area_sz, stride; + int i, j, r, no, sz; + void *buf; + BadBlockTableNand_t *bbtn; + struct mtd_part *mp; + int chip; + + stride = PAGES_PER_STRIDE * mtd_writesize(md); + search_area_sz = (1 << md->cfg.search_exponent) * stride; + + /* make sure it fits */ + if (search_area_sz * 6 > mtd_size(md)) { + fprintf(stderr, "mtd: search areas too large\n" + "\tsearch_area_sz * 6 > mtd_size\n" + "\t%#x * 6 > %#x", + search_area_sz, mtd_size(md)); + return -1; + } + + if (plat_config_data->m_u32BCBBlocksFlags & BCB_READ_NCB) { + r = mtd_load_nand_control_block(md, stride, search_area_sz); + if (r) + return r; + } + + if (plat_config_data->m_u32BCBBlocksFlags & BCB_READ_LDLB) { + r = mtd_load_logical_drive_layout_block(md, stride, search_area_sz); + if (r) + return r; + } + + if (plat_config_data->m_u32BCBBlocksFlags & BCB_READ_FCB) { + r = mtd_load_firmware_control_block(md); + if (r) + return r; + } + + if (plat_config_data->m_u32BCBBlocksFlags & BCB_READ_DBBT) { + r = mtd_load_discoverable_bad_block_table(md, stride, search_area_sz); + if (r) + return r; + } + + mtd_update_discoverable_bad_block_table(md); + return 0; } diff --git a/src/plat_boot_config.c b/src/plat_boot_config.c index 4dc6c2e..2b07d74 100644 --- a/src/plat_boot_config.c +++ b/src/plat_boot_config.c @@ -38,6 +38,7 @@ static platform_config mx23_boot_config = { .m_u32UseSinglePageStride = 0, .m_u32DBBT_FingerPrint = DBBT_FINGERPRINT2, .m_u32MaxEccStrength = 20, + .m_u32BCBBlocksFlags = (BCB_READ_NCB | BCB_READ_LDLB), .rom_mtd_init = v0_rom_mtd_init, .rom_mtd_commit_structures = v0_rom_mtd_commit_structures, }; @@ -52,6 +53,7 @@ static platform_config mx28_boot_config = { .m_u32UseSinglePageStride = 1, .m_u32DBBT_FingerPrint = DBBT_FINGERPRINT2, .m_u32MaxEccStrength = 20, + .m_u32BCBBlocksFlags = (BCB_READ_NCB | BCB_READ_LDLB), .rom_mtd_init = v1_rom_mtd_init, .rom_mtd_commit_structures = v1_rom_mtd_commit_structures, }; @@ -66,6 +68,7 @@ static platform_config mx53to1_boot_config = { .m_u32UseSinglePageStride = 0, .m_u32DBBT_FingerPrint = DBBT_FINGERPRINT2_V2, .m_u32MaxEccStrength = 40, + .m_u32BCBBlocksFlags = (BCB_READ_NCB | BCB_READ_LDLB), .rom_mtd_init = v2_rom_mtd_init, .rom_mtd_commit_structures = v2_rom_mtd_commit_structures, }; @@ -80,6 +83,7 @@ static platform_config mx53to2_boot_config = { .m_u32UseSinglePageStride = 0, .m_u32DBBT_FingerPrint = DBBT_FINGERPRINT2_V2, .m_u32MaxEccStrength = 40, + .m_u32BCBBlocksFlags = (BCB_READ_NCB | BCB_READ_LDLB), .rom_mtd_init = v2_rom_mtd_init, .rom_mtd_commit_structures = v2_rom_mtd_commit_structures, }; @@ -94,6 +98,7 @@ static platform_config mx50_boot_config = { .m_u32UseSinglePageStride = 0, .m_u32DBBT_FingerPrint = DBBT_FINGERPRINT2, .m_u32MaxEccStrength = 40, + .m_u32BCBBlocksFlags = (BCB_READ_NCB | BCB_READ_LDLB), .rom_mtd_init = v4_rom_mtd_init, .rom_mtd_commit_structures = v4_rom_mtd_commit_structures, }; @@ -107,6 +112,7 @@ static platform_config mx6q_boot_config = { .m_u32UseSinglePageStride = 0, .m_u32DBBT_FingerPrint = DBBT_FINGERPRINT2, .m_u32MaxEccStrength = 40, + .m_u32BCBBlocksFlags = (BCB_READ_FCB | BCB_READ_VIA_FILE_API), .rom_mtd_init = v4_rom_mtd_init, .rom_mtd_commit_structures = v4_rom_mtd_commit_structures, }; @@ -120,6 +126,7 @@ static platform_config mx6sx_boot_config = { .m_u32UseSinglePageStride = 0, .m_u32DBBT_FingerPrint = DBBT_FINGERPRINT2, .m_u32MaxEccStrength = 62, + .m_u32BCBBlocksFlags = (BCB_READ_NCB | BCB_READ_LDLB), .rom_mtd_init = v4_rom_mtd_init, .rom_mtd_commit_structures = v4_rom_mtd_commit_structures, }; @@ -133,6 +140,7 @@ static platform_config mx6sx_to_1_2_boot_config = { .m_u32UseSinglePageStride = 0, .m_u32DBBT_FingerPrint = DBBT_FINGERPRINT2, .m_u32MaxEccStrength = 62, + .m_u32BCBBlocksFlags = (BCB_READ_NCB | BCB_READ_LDLB), .rom_mtd_init = v4_rom_mtd_init, .rom_mtd_commit_structures = v5_rom_mtd_commit_structures, }; @@ -146,6 +154,7 @@ static platform_config mx7d_boot_config = { .m_u32UseSinglePageStride = 0, .m_u32DBBT_FingerPrint = DBBT_FINGERPRINT2, .m_u32MaxEccStrength = 62, + .m_u32BCBBlocksFlags = (BCB_READ_NCB | BCB_READ_LDLB), .rom_mtd_init = v4_rom_mtd_init, .rom_mtd_commit_structures = v5_rom_mtd_commit_structures, }; @@ -159,6 +168,7 @@ static platform_config mx6ul_boot_config = { .m_u32UseSinglePageStride = 0, .m_u32DBBT_FingerPrint = DBBT_FINGERPRINT2, .m_u32MaxEccStrength = 40, + .m_u32BCBBlocksFlags = (BCB_READ_NCB | BCB_READ_LDLB), .rom_mtd_init = v4_rom_mtd_init, .rom_mtd_commit_structures = v6_rom_mtd_commit_structures, }; @@ -172,6 +182,7 @@ static platform_config mx8mq_boot_config = { .m_u32UseSinglePageStride = 0, .m_u32DBBT_FingerPrint = DBBT_FINGERPRINT2, .m_u32MaxEccStrength = 62, + .m_u32BCBBlocksFlags = (BCB_READ_NCB | BCB_READ_LDLB), .rom_mtd_init = v4_rom_mtd_init, .rom_mtd_commit_structures = v7_rom_mtd_commit_structures, }; @@ -185,6 +196,7 @@ static platform_config mx8q_boot_config = { .m_u32UseSinglePageStride = 0, .m_u32DBBT_FingerPrint = DBBT_FINGERPRINT2, .m_u32MaxEccStrength = 62, + .m_u32BCBBlocksFlags = (BCB_READ_NCB | BCB_READ_LDLB), .rom_mtd_init = v4_rom_mtd_init, .rom_mtd_commit_structures = v5_rom_mtd_commit_structures, }; diff --git a/src/plat_boot_config.h b/src/plat_boot_config.h index 3d43283..3ecd73a 100644 --- a/src/plat_boot_config.h +++ b/src/plat_boot_config.h @@ -62,6 +62,7 @@ typedef struct _platform_config_t { uint32_t m_u32Arm_type; uint32_t m_u32DBBT_FingerPrint; uint32_t m_u32MaxEccStrength; + uint32_t m_u32BCBBlocksFlags; int (* rom_mtd_init)(struct mtd_data *md, FILE *fp); int (* rom_mtd_commit_structures)(struct mtd_data *md, FILE *fp, int flags); } platform_config; From ba9858c198cc4b3bd7e8f9d9c9d6d50a30e61279 Mon Sep 17 00:00:00 2001 From: Leif Middelschulte Date: Sun, 18 Apr 2021 15:08:38 +0200 Subject: [PATCH 02/14] dbbt: handle DBBTs from FCB differently Signed-off-by: Leif Middelschulte --- src/BootControlBlocks.h | 3 ++- src/mtd.c | 2 +- src/plat_boot_config.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/BootControlBlocks.h b/src/BootControlBlocks.h index bfbb3b2..676d4a7 100644 --- a/src/BootControlBlocks.h +++ b/src/BootControlBlocks.h @@ -50,7 +50,8 @@ #define BCB_READ_NCB (1 << 1) #define BCB_READ_LDLB (1 << 2) #define BCB_READ_DBBT (1 << 3) -#define BCB_READ_FCB (1 << 4) +#define BCB_READ_DBBT_FROM_FCB (1 << 4) +#define BCB_READ_FCB (1 << 5) #define MAXSEQLEN 183 diff --git a/src/mtd.c b/src/mtd.c index 7b3231f..eabd0b3 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -1629,7 +1629,7 @@ static int mtd_load_discoverable_bad_block_table(struct mtd_data *md, int stride void *buf; int chip; - if (plat_config_data->m_u32BCBBlocksFlags & (BCB_READ_FCB || BCB_READ_VIA_FILE_API)) { + if (plat_config_data->m_u32BCBBlocksFlags & (BCB_READ_FCB || BCB_READ_VIA_FILE_API || BCB_READ_DBBT_FROM_FCB)) { loff_t dbbt_offset = md->fcb.FCB_Block.m_u32DBBTSearchAreaStartAddress * md->fcb.FCB_Block.m_u32PageDataSize; const size_t dbbt_size = sizeof(md->dbbt50.DBBT_Block.v3) + offsetof(BCB_ROM_BootBlockStruct_t, DBBT_Block); for (i = 0; i < 3; i++) { diff --git a/src/plat_boot_config.c b/src/plat_boot_config.c index 2b07d74..5f4f301 100644 --- a/src/plat_boot_config.c +++ b/src/plat_boot_config.c @@ -112,7 +112,7 @@ static platform_config mx6q_boot_config = { .m_u32UseSinglePageStride = 0, .m_u32DBBT_FingerPrint = DBBT_FINGERPRINT2, .m_u32MaxEccStrength = 40, - .m_u32BCBBlocksFlags = (BCB_READ_FCB | BCB_READ_VIA_FILE_API), + .m_u32BCBBlocksFlags = (BCB_READ_FCB | BCB_READ_DBBT | BCB_READ_DBBT_FROM_FCB | BCB_READ_VIA_FILE_API), .rom_mtd_init = v4_rom_mtd_init, .rom_mtd_commit_structures = v4_rom_mtd_commit_structures, }; From a13588d6c0f13e57c5d72115c7fa480e910c8933 Mon Sep 17 00:00:00 2001 From: Leif Middelschulte Date: Sun, 18 Apr 2021 15:09:46 +0200 Subject: [PATCH 03/14] handle i.MX6DL/Q DBBT search area fuses Signed-off-by: Leif Middelschulte --- src/mtd.c | 68 ++++++++++++++++++++++++++++++------------ src/plat_boot_config.c | 12 +++++++- 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/src/mtd.c b/src/mtd.c index eabd0b3..3182611 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -50,6 +50,10 @@ #define IMX8QM_SPL_OFF 0x19c00 #define IMX8QM_FIT_OFF 0x57c00 +/* define 6QDL FUSE value location */ +#define MX6QDL_FUSE_NAND_SEARCH_CNT_OFFS 0x50 // this offset is relative to 0x400, hardcoded into the imx-ocotp driver. +#define MX6QDL_FUSE_NAND_SEARCH_CNT_BIT_OFFS (3+8) +#define MX6QDL_FUSE_NAND_SEARCH_CNT_MASK 3 /* define 8Q FUSE value location */ #define MX8Q_FUSE_NAND_SEARCH_CNT_OFFS 0x700 #define MX8Q_FUSE_NAND_SEARCH_CNT_BIT_OFFS 6 @@ -826,7 +830,7 @@ struct mtd_data *mtd_open(const struct mtd_config *cfg, int flags) int i, k, j, r, no; loff_t ofs; FILE *fp; - char tmp; + uint32_t word; int fuse_off, fuse_bit, fuse_mask; md = malloc(sizeof(*md)); @@ -871,7 +875,8 @@ struct mtd_data *mtd_open(const struct mtd_config *cfg, int flags) */ if (plat_config_data->m_u32Arm_type == MX8Q || plat_config_data->m_u32Arm_type == MX8MN - || plat_config_data->m_u32Arm_type == MX8MP) { + || plat_config_data->m_u32Arm_type == MX6Q + || plat_config_data->m_u32Arm_type == MX6DL) { md->cfg.search_exponent = 1; vp(md, "mtd: search_exponent set to 1 by default\n"); @@ -890,25 +895,43 @@ struct mtd_data *mtd_open(const struct mtd_config *cfg, int flags) fuse_bit = MX8MN_FUSE_NAND_SEARCH_CNT_BIT_OFFS; fuse_mask = MX8MN_FUSE_NAND_SEARCH_CNT_MASK; } + if (plat_config_data->m_u32Arm_type == MX6DL || + plat_config_data->m_u32Arm_type == MX6Q) { + fp = fopen("/sys/bus/nvmem/devices/imx-ocotp0/nvmem", "rb"); + fuse_off = MX6QDL_FUSE_NAND_SEARCH_CNT_OFFS; + fuse_bit = MX6QDL_FUSE_NAND_SEARCH_CNT_BIT_OFFS; + fuse_mask = MX6QDL_FUSE_NAND_SEARCH_CNT_MASK; + } if (fp) { /* move to the nand_boot_search_count offset */ if (!fseek(fp, fuse_off, SEEK_SET)) { /* read out the nand_boot_search_count from fuse */ - if (fread(&tmp, 1, 1, fp) == 1) { - vp(md, "read back from fuse: %x\n", tmp); - switch ((tmp >> fuse_bit) && fuse_mask) { - case 0: - case 1: - md->cfg.search_exponent = 1; - break; - case 2: - md->cfg.search_exponent = 2; - break; - case 3: - md->cfg.search_exponent = 3; - break; - default: - md->cfg.search_exponent = 1; + /* The kernel nvmem driver `imx-ocotp` has a bug, which was fixed by + * 3311bf18467272388039922a5e29c4925b291f73, that will make it + * ignore reads that are shorter than 4 bytes. + */ + if (fread(&word, sizeof(word), 1, fp) == 1) { + // see linux kernel's imx-ocotp.c:imx_ocotp_read + if (word == 0xBADABADA) { + vp(md, "mtd: read back a \"read locked\" register. Got invalid value: 0x%x\n", word); + md->cfg.search_exponent = 1; + } else { + word &= 0x000f; + vp(md, "mtd: read back from fuse: %x\n", word); + switch ((word >> fuse_bit) && fuse_mask) { + case 0: + case 1: + md->cfg.search_exponent = 1; + break; + case 2: + md->cfg.search_exponent = 2; + break; + case 3: + md->cfg.search_exponent = 3; + break; + default: + md->cfg.search_exponent = 1; + } } vp(md, "mtd: search_exponent was set by fuse as %d\n" , md->cfg.search_exponent); @@ -1632,13 +1655,20 @@ static int mtd_load_discoverable_bad_block_table(struct mtd_data *md, int stride if (plat_config_data->m_u32BCBBlocksFlags & (BCB_READ_FCB || BCB_READ_VIA_FILE_API || BCB_READ_DBBT_FROM_FCB)) { loff_t dbbt_offset = md->fcb.FCB_Block.m_u32DBBTSearchAreaStartAddress * md->fcb.FCB_Block.m_u32PageDataSize; const size_t dbbt_size = sizeof(md->dbbt50.DBBT_Block.v3) + offsetof(BCB_ROM_BootBlockStruct_t, DBBT_Block); + /* The search limit _should_ be read from an OTP (fuse) */ for (i = 0; i < 3; i++) { r = mtd_read(md, 0, &md->dbbt50, dbbt_size, dbbt_offset); if (r != dbbt_size) - return -1; + continue; /* there is no checksum inside the dbbt structure */ - if (md->dbbt50.m_u32FingerPrint == plat_config_data->m_u32DBBT_FingerPrint) + if (md->dbbt50.m_u32FingerPrint == plat_config_data->m_u32DBBT_FingerPrint) { + /* i.MX 6 DQRM 8.5.2.4 - DBBT Structure */ + uint32_t *bad_block_number_ptr = &md->dbbt50.DBBT_Block.v3 + (4 * md->fcb.FCB_Block.m_u32PageDataSize) + 8; + for (j = 0; j < md->dbbt50.DBBT_Block.v3.m_u32DBBTNumOfPages; j++) { + md->bbtn[0]->u32BadBlock[bad_block_number_ptr[i]] = 1; + } return 0; + } dbbt_offset += md->fcb.FCB_Block.m_u32PageDataSize; } return -1; diff --git a/src/plat_boot_config.c b/src/plat_boot_config.c index 5f4f301..0f32daf 100644 --- a/src/plat_boot_config.c +++ b/src/plat_boot_config.c @@ -209,6 +209,8 @@ int discover_boot_rom_version(void) char line_buffer[100]; static char *banner = "Revision"; static char *banner_hw = "Hardware"; + static char *plat_imx6q = "i.MX6Q"; + static char *plat_imx6dl = "i.MX6DL"; static char *plat_imx6sx = "i.MX6SX"; static char *plat_imx6ul = "i.MX6UL"; static char *plat_imx6ull = "i.MX6ULL"; @@ -346,6 +348,13 @@ int discover_boot_rom_version(void) if (!strncmp(line_buffer, plat_imx6ul, strlen(plat_imx6ul)) || !strncmp(line_buffer, plat_imx6ull, strlen(plat_imx6ull))) plat_config_data = &mx6ul_boot_config; + + /* system_rev is not specific enough */ + if (!strncmp(line_buffer, plat_imx6dl, strlen(plat_imx6dl))) + plat_config_data->m_u32Arm_type = MX6DL; + else if (!strncmp(line_buffer, plat_imx6q, strlen(plat_imx6q))) + plat_config_data->m_u32Arm_type = MX6Q; + break; case MX7: @@ -359,7 +368,8 @@ int discover_boot_rom_version(void) fclose(cpuinfo); if (plat_config_data) { - plat_config_data->m_u32Arm_type = system_rev; + if (!plat_config_data->m_u32Arm_type) + plat_config_data->m_u32Arm_type = system_rev; return 0; } return -1; From 8b11579f8285b803a17a57ea0a2ba3a38b16c51f Mon Sep 17 00:00:00 2001 From: Leif Middelschulte Date: Sun, 18 Apr 2021 15:30:37 +0200 Subject: [PATCH 04/14] search count fuse mask: fix mask usage Signed-off-by: Leif Middelschulte --- src/mtd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mtd.c b/src/mtd.c index 3182611..235e4d5 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -918,7 +918,7 @@ struct mtd_data *mtd_open(const struct mtd_config *cfg, int flags) } else { word &= 0x000f; vp(md, "mtd: read back from fuse: %x\n", word); - switch ((word >> fuse_bit) && fuse_mask) { + switch ((word >> fuse_bit) & fuse_mask) { case 0: case 1: md->cfg.search_exponent = 1; From 48674ddfc880d4294b727fda680530e38bea021d Mon Sep 17 00:00:00 2001 From: Leif Middelschulte Date: Sun, 18 Apr 2021 15:31:32 +0200 Subject: [PATCH 05/14] search count fuse: adjust info message Signed-off-by: Leif Middelschulte --- src/mtd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mtd.c b/src/mtd.c index 235e4d5..006fcf4 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -933,7 +933,7 @@ struct mtd_data *mtd_open(const struct mtd_config *cfg, int flags) md->cfg.search_exponent = 1; } } - vp(md, "mtd: search_exponent was set by fuse as %d\n" + vp(md, "mtd: search_exponent was set as %d\n" , md->cfg.search_exponent); } } From 306112f837e60308a0cb3797131bcfcc8e02967a Mon Sep 17 00:00:00 2001 From: Leif Middelschulte Date: Mon, 19 Apr 2021 10:19:45 +0200 Subject: [PATCH 06/14] mtd: load dbbt: query boot fuse Query the boot fuses to determine the search area count. Signed-off-by: Leif Middelschulte --- src/mtd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mtd.c b/src/mtd.c index 006fcf4..2d6e6c1 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -1655,8 +1655,7 @@ static int mtd_load_discoverable_bad_block_table(struct mtd_data *md, int stride if (plat_config_data->m_u32BCBBlocksFlags & (BCB_READ_FCB || BCB_READ_VIA_FILE_API || BCB_READ_DBBT_FROM_FCB)) { loff_t dbbt_offset = md->fcb.FCB_Block.m_u32DBBTSearchAreaStartAddress * md->fcb.FCB_Block.m_u32PageDataSize; const size_t dbbt_size = sizeof(md->dbbt50.DBBT_Block.v3) + offsetof(BCB_ROM_BootBlockStruct_t, DBBT_Block); - /* The search limit _should_ be read from an OTP (fuse) */ - for (i = 0; i < 3; i++) { + for (i = 0; i < (1 << md->cfg.search_exponent); i++) { r = mtd_read(md, 0, &md->dbbt50, dbbt_size, dbbt_offset); if (r != dbbt_size) continue; From f4bc5d9479627bdb6ad2e74106d41e72720beea6 Mon Sep 17 00:00:00 2001 From: Leif Middelschulte Date: Mon, 19 Apr 2021 10:26:04 +0200 Subject: [PATCH 07/14] mtd: load dbbt: warn on multibootarea Warn the user if she targets a multiarea chip. The i.MX manual does not explicitly mention those in the FCB context. Signed-off-by: Leif Middelschulte --- src/mtd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mtd.c b/src/mtd.c index 2d6e6c1..064b0b4 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -1655,6 +1655,9 @@ static int mtd_load_discoverable_bad_block_table(struct mtd_data *md, int stride if (plat_config_data->m_u32BCBBlocksFlags & (BCB_READ_FCB || BCB_READ_VIA_FILE_API || BCB_READ_DBBT_FROM_FCB)) { loff_t dbbt_offset = md->fcb.FCB_Block.m_u32DBBTSearchAreaStartAddress * md->fcb.FCB_Block.m_u32PageDataSize; const size_t dbbt_size = sizeof(md->dbbt50.DBBT_Block.v3) + offsetof(BCB_ROM_BootBlockStruct_t, DBBT_Block); + if (plat_config_data->m_u32UseMultiBootArea) { + fprintf(stderr, "mtd: warning examining only first FCB.\n"); + } for (i = 0; i < (1 << md->cfg.search_exponent); i++) { r = mtd_read(md, 0, &md->dbbt50, dbbt_size, dbbt_offset); if (r != dbbt_size) From 79a72c6ab90e4dd7bcb1682affd48ad7e774a177 Mon Sep 17 00:00:00 2001 From: Leif Middelschulte Date: Mon, 19 Apr 2021 11:05:51 +0200 Subject: [PATCH 08/14] mtd: factor `checksum` computation It is eventually used by dbbt _and_ fcb. On the i.MX 6 it is documented to be only used by the fcb. Signed-off-by: Leif Middelschulte --- src/mtd.c | 15 ++++++++++----- src/mtd.h | 2 ++ src/ncb.c | 23 +++-------------------- 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/mtd.c b/src/mtd.c index 064b0b4..f3f0aad 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -3516,7 +3516,7 @@ int v0_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) return 0; } -static void dbbt_checksum(struct mtd_data *md, BCB_ROM_BootBlockStruct_t *dbbt) +uint32_t checksum(const uint8_t *ptr, size_t size) { uint32_t accumulator = 0; uint8_t *p, *q; @@ -3525,15 +3525,20 @@ static void dbbt_checksum(struct mtd_data *md, BCB_ROM_BootBlockStruct_t *dbbt) * The checksum should do 508 bytes. But if the rest of the buffer is * zero. We can only add the non-zero data for the checksum. */ - p = ((uint8_t *) dbbt) + 4; - q = (uint8_t *) (dbbt + 1); - vp(md, "DBBT checksum length : %d\n", q - p); + p = ((uint8_t *) boot_block_structure) + 4; + q = (uint8_t *) (boot_block_structure + 1); + vp(md, "checksum length : %d\n", q - p); for (; p < q; p++) accumulator += *p; accumulator ^= 0xffffffff; - dbbt->m_u32Checksum = accumulator; + return accumulator; +} + +static void dbbt_checksum(struct mtd_data *md, BCB_ROM_BootBlockStruct_t *boot_block_structure) +{ + boot_block_structure->m_u32Checksum = checksum(md, boot_block_structure); } static void write_dbbt(struct mtd_data *md, int dbbt_num) diff --git a/src/mtd.h b/src/mtd.h index a36ff59..7aa0831 100644 --- a/src/mtd.h +++ b/src/mtd.h @@ -323,6 +323,8 @@ void mtd_parse_args(struct mtd_config *cfg, int argc, char **argv); void mtd_parse_kobs(struct mtd_config *cfg, const char *name, int verbose); void mtd_cfg_dump(struct mtd_config *cfg); +uint32_t checksum(const uint8_t *ptr, size_t size); + int ncb_get_version(void *ncb_candidate, NCB_BootBlockStruct_t **result); int ncb_encrypt(NCB_BootBlockStruct_t *ncb, void *target, size_t size, int version); int fcb_encrypt(BCB_ROM_BootBlockStruct_t *fcb, void *target, size_t size, int version); diff --git a/src/ncb.c b/src/ncb.c index cb00a8e..ac5fb4e 100644 --- a/src/ncb.c +++ b/src/ncb.c @@ -357,7 +357,7 @@ int ncb_encrypt(NCB_BootBlockStruct_t *ncb, void *target, size_t size, int versi * fcb_encrypt - Encrypt the FCB block, assuming that target system uses NCB * version 'version' * - * fcb: Points to valid imx28_BootBlockStruct_t structure. + * fcb: Points to valid BCB_ROM_BootBlockStruct_t structure. * target: Points to a buffer large enough to contain an entire NAND Flash page * (both data and OOB). * size: The size of an entire NAND Flash page (both data and OOB). @@ -366,10 +366,7 @@ int ncb_encrypt(NCB_BootBlockStruct_t *ncb, void *target, size_t size, int versi */ int fcb_encrypt(BCB_ROM_BootBlockStruct_t *fcb, void *target, size_t size, int version) { - uint32_t accumulator; - uint8_t *p; - uint8_t *q; - int fcb_size; + const int fcb_size = MAX_HAMMING_FCB_SZ < sizeof(*fcb) ? MAX_HAMMING_FCB_SZ : sizeof(*fcb); //---------------------------------------------------------------------- // Check for nonsense. @@ -392,21 +389,7 @@ int fcb_encrypt(BCB_ROM_BootBlockStruct_t *fcb, void *target, size_t size, int v // ECC bytes. However, the entire space between the top of the FCB and // the base of the ECC bytes will be all zeros, so this is OK. //---------------------------------------------------------------------- - - p = ((uint8_t *) fcb) + 4; - q = (uint8_t *) (fcb + 1); - - accumulator = 0; - - for (; p < q; p++) { - accumulator += *p; - } - - accumulator ^= 0xffffffff; - - fcb->m_u32Checksum = accumulator; - - fcb_size = MAX_HAMMING_FCB_SZ < sizeof(*fcb) ? MAX_HAMMING_FCB_SZ : sizeof(*fcb); + fcb->m_u32Checksum = checksum(&fcb->m_u32FingerPrint, fcb_size - offsetof(BCB_ROM_BootBlockStruct_t, m_u32FingerPrint)); //---------------------------------------------------------------------- // Compute the ECC bytes. From 1d5d9f56f3f7c2cdd937a70dd551d73887ce1412 Mon Sep 17 00:00:00 2001 From: Leif Middelschulte Date: Wed, 9 Jun 2021 15:00:06 +0200 Subject: [PATCH 09/14] bcb: Fix reading-in of FCB and DBBT Signed-off-by: Leif Middelschulte --- src/BootControlBlocks.h | 4 ++ src/main.c | 33 +++++++++++---- src/mtd.c | 92 +++++++++++++++++++++++++++-------------- 3 files changed, 88 insertions(+), 41 deletions(-) diff --git a/src/BootControlBlocks.h b/src/BootControlBlocks.h index 676d4a7..1919466 100644 --- a/src/BootControlBlocks.h +++ b/src/BootControlBlocks.h @@ -348,6 +348,10 @@ typedef struct { union { struct fcb_block FCB_Block; union { + struct { + uint32_t m_u32res; + uint32_t m_u32DBBTNumOfPages; + }; struct { uint32_t m_u32NumberBB; //!< # Bad Blocks stored in this table for NAND0. uint32_t m_u32Number2KPagesBB; //!< Bad Blocks for NAND0 consume this # of 2K pages. diff --git a/src/main.c b/src/main.c index 7a2b941..74b54c1 100644 --- a/src/main.c +++ b/src/main.c @@ -263,20 +263,35 @@ int extract_main(int argc, char **argv) } chip = 0; - startpage = image == 0 ? - md->curr_ldlb->LDLB_Block2.m_u32Firmware_startingSector : - md->curr_ldlb->LDLB_Block2.m_u32Firmware_startingSector2; - size = image == 0 ? - md->curr_ldlb->LDLB_Block2.m_uSectorsInFirmware : - md->curr_ldlb->LDLB_Block2.m_uSectorsInFirmware2 ; + if (plat_config_data->m_u32BCBBlocksFlags & BCB_READ_DBBT_FROM_FCB) { + if (image != 0) { + fprintf(stderr, "Multichip NAND behavior not supported.\n"); + exit(5); + } + startpage = md->fcb.FCB_Block.m_u32Firmware1_startingPage; + size = md->fcb.FCB_Block.m_u32PagesInFirmware1; + } else { + startpage = image == 0 ? + md->curr_ldlb->LDLB_Block2.m_u32Firmware_startingSector : + md->curr_ldlb->LDLB_Block2.m_u32Firmware_startingSector2; + size = image == 0 ? + md->curr_ldlb->LDLB_Block2.m_uSectorsInFirmware : + md->curr_ldlb->LDLB_Block2.m_uSectorsInFirmware2; + } if (md->flags & F_MULTICHIP) chip = image; if (flags & F_VERBOSE) printf("startpage=%u, size=%u\n", startpage, size); - start = startpage * 2048; - size = size * 2048; + + if (plat_config_data->m_u32BCBBlocksFlags & BCB_READ_FCB) { + start = startpage * md->fcb.FCB_Block.m_u32PageDataSize; + size = size * md->fcb.FCB_Block.m_u32PageDataSize; + } else { + start = startpage * 2048; + size = size * 2048; + } while (size > 0) { /* skip bad blocks */ @@ -292,7 +307,7 @@ int extract_main(int argc, char **argv) exit(5); } r = fwrite(buf, sizeof(buf), 1, outfp); - if (sizeof(buf) != 1) + if (r != 1) fprintf(stderr, "Write to file failed\n"); start += sizeof(buf); diff --git a/src/mtd.c b/src/mtd.c index f3f0aad..21ba4ce 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -1647,31 +1647,43 @@ static int mtd_load_logical_drive_layout_block(struct mtd_data *md, int stride, static int mtd_load_discoverable_bad_block_table(struct mtd_data *md, int stride, int search_area_sz) { + const loff_t dbbt_offset = md->fcb.FCB_Block.m_u32DBBTSearchAreaStartAddress * md->fcb.FCB_Block.m_u32PageDataSize; + const off_t bad_block_index_relative_offset = offsetof(BCB_ROM_BootBlockStruct_t, DBBT_Block); + const loff_t bad_block_index_offset = dbbt_offset + bad_block_index_relative_offset; loff_t ofs, end; int i, j, r, no, sz; void *buf; int chip; if (plat_config_data->m_u32BCBBlocksFlags & (BCB_READ_FCB || BCB_READ_VIA_FILE_API || BCB_READ_DBBT_FROM_FCB)) { - loff_t dbbt_offset = md->fcb.FCB_Block.m_u32DBBTSearchAreaStartAddress * md->fcb.FCB_Block.m_u32PageDataSize; - const size_t dbbt_size = sizeof(md->dbbt50.DBBT_Block.v3) + offsetof(BCB_ROM_BootBlockStruct_t, DBBT_Block); + /* Read the DBBT in two steps: + 1. Read the checksum, fingerprint, version and size of the dynamic part (=20 bytes). + 2. Read the dynamic part, but ignore Tables sizes >1 and read right into md->bttn[NAND_CHIP]. + */ + const size_t dbbt_size = 20; if (plat_config_data->m_u32UseMultiBootArea) { fprintf(stderr, "mtd: warning examining only first FCB.\n"); } - for (i = 0; i < (1 << md->cfg.search_exponent); i++) { - r = mtd_read(md, 0, &md->dbbt50, dbbt_size, dbbt_offset); + for (i = 0; (i * md->cfg.stride_size_in_bytes) < md->cfg.search_area_size_in_bytes; i++) { + r = mtd_read(md, 0, &md->dbbt50, dbbt_size, dbbt_offset + (i * md->cfg.stride_size_in_bytes)); if (r != dbbt_size) continue; /* there is no checksum inside the dbbt structure */ - if (md->dbbt50.m_u32FingerPrint == plat_config_data->m_u32DBBT_FingerPrint) { - /* i.MX 6 DQRM 8.5.2.4 - DBBT Structure */ - uint32_t *bad_block_number_ptr = &md->dbbt50.DBBT_Block.v3 + (4 * md->fcb.FCB_Block.m_u32PageDataSize) + 8; - for (j = 0; j < md->dbbt50.DBBT_Block.v3.m_u32DBBTNumOfPages; j++) { - md->bbtn[0]->u32BadBlock[bad_block_number_ptr[i]] = 1; - } - return 0; - } - dbbt_offset += md->fcb.FCB_Block.m_u32PageDataSize; + if (md->dbbt50.m_u32FingerPrint != plat_config_data->m_u32DBBT_FingerPrint) + continue; + /* i.MX 6 DQRM 8.5.2.4 - DBBT Structure + The following would be the _correct_ thing to do: + 1. read the table size + 2. allocate the necessary memory to read the entire table + However, every tool (imx-kobs, barebox, uboot) seems to go with the assumption, + that there is at most a single page (4byte/entry) worth of bad blocks entries (=512). + const size_t bad_block_table_in_bytes = md->dbbt50.DBBT_Block.v3.m_u32DBBTNumOfPages * mtd_writesize(md); + */ + md->bbtn[0] = malloc(sizeof(*md->bbtn[0])); + r = mtd_read(md, 0, md->bbtn[0], sizeof(*md->bbtn[0]), bad_block_index_offset); + if (r != TYPICAL_NAND_READ_SIZE) + return -1; + return 0; } return -1; } else { @@ -1807,13 +1819,36 @@ void mtd_update_discoverable_bad_block_table(struct mtd_data *md) static int mtd_load_firmware_control_block(struct mtd_data *md) { - const size_t size_of_fcb = sizeof(md->fcb.FCB_Block) + offsetof(BCB_ROM_BootBlockStruct_t, FCB_Block); - int r = 0; - r = mtd_read(md, 0, &md->fcb, size_of_fcb, FCB_OFFSET); - if (r != size_of_fcb) - return -1; - if (md->fcb.m_u32FingerPrint != FCB_FINGERPRINT) + // the checksum does _not_ include the checksum itself, so add the offset. + size_t size_of_fcb; + const uint8_t *checksum_ptr; + uint32_t calculated_checksum; + int i, r = 0; + switch (plat_config_data->m_u32Arm_type) { + case MX6DL: + case MX6Q: + // the reference manual specifies a smaller FCB + size_of_fcb = offsetof(struct fcb_block, m_u32RandomizerEnable) + + offsetof(BCB_ROM_BootBlockStruct_t, FCB_Block); + break; + default: + size_of_fcb = sizeof(md->fcb.FCB_Block) + offsetof(BCB_ROM_BootBlockStruct_t, FCB_Block); + } + for (i = 0; (i * md->cfg.stride_size_in_bytes) < md->cfg.search_area_size_in_bytes; i++) { + r = mtd_read(md, 0, &md->fcb, size_of_fcb, FCB_OFFSET + (i * md->cfg.stride_size_in_bytes)); + if (r != size_of_fcb) + return -1; + if (md->fcb.m_u32FingerPrint != FCB_FINGERPRINT) + return -1; + checksum_ptr = &md->fcb.m_u32FingerPrint; + calculated_checksum = checksum(checksum_ptr, size_of_fcb - offsetof(BCB_ROM_BootBlockStruct_t, m_u32FingerPrint)); + if (md->fcb.m_u32Checksum == calculated_checksum) + break; + } + if (md->fcb.m_u32Checksum != calculated_checksum) { + fprintf(stderr, "mtd: could not find intact FCB.\n"); return -1; + } return 0; } @@ -3519,26 +3554,19 @@ int v0_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) uint32_t checksum(const uint8_t *ptr, size_t size) { uint32_t accumulator = 0; - uint8_t *p, *q; + size_t i; - /* - * The checksum should do 508 bytes. But if the rest of the buffer is - * zero. We can only add the non-zero data for the checksum. - */ - p = ((uint8_t *) boot_block_structure) + 4; - q = (uint8_t *) (boot_block_structure + 1); - vp(md, "checksum length : %d\n", q - p); + printf("mtd: checksum start: %p; length : %d\n", ptr, size); - for (; p < q; p++) - accumulator += *p; - accumulator ^= 0xffffffff; + for (i = 0; i < size; i++) + accumulator += ptr[i]; - return accumulator; + return ~accumulator; } static void dbbt_checksum(struct mtd_data *md, BCB_ROM_BootBlockStruct_t *boot_block_structure) { - boot_block_structure->m_u32Checksum = checksum(md, boot_block_structure); + boot_block_structure->m_u32Checksum = checksum((uint8_t*)boot_block_structure + offsetof(BCB_ROM_BootBlockStruct_t, m_u32Checksum), sizeof(md->dbbt50)); } static void write_dbbt(struct mtd_data *md, int dbbt_num) From c7639410f20427680ddac5d02ae7edd278644426 Mon Sep 17 00:00:00 2001 From: Leif Middelschulte Date: Tue, 15 Jun 2021 12:41:37 +0200 Subject: [PATCH 10/14] bootstream: skip LDLB update on some platforms The LDLB is not supported on many platforms. So, eventually, skip its update. Signed-off-by: Leif Middelschulte --- src/main.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/main.c b/src/main.c index 74b54c1..ba19d45 100644 --- a/src/main.c +++ b/src/main.c @@ -425,26 +425,28 @@ static int perform_bootstream_update(struct mtd_data *md, FILE *infp, int image_ if ((image_mask & (1 << i)) == 0) continue; - /* first verify it fits */ - if (i == 0) { - start = md->curr_ldlb->LDLB_Block2.m_u32Firmware_startingSector * 2048; - end = md->curr_ldlb->LDLB_Block2.m_u32Firmware_startingSector2 * 2048; - } else { - start = md->curr_ldlb->LDLB_Block2.m_u32Firmware_startingSector2 * 2048; - end = mtd_size(md); - } - avail = end - start; + if (plat_config_data->m_u32BCBBlocksFlags & BCB_READ_LDLB) { + /* first verify it fits */ + if (i == 0) { + start = md->curr_ldlb->LDLB_Block2.m_u32Firmware_startingSector * 2048; + end = md->curr_ldlb->LDLB_Block2.m_u32Firmware_startingSector2 * 2048; + } else { + start = md->curr_ldlb->LDLB_Block2.m_u32Firmware_startingSector2 * 2048; + end = mtd_size(md); + } + avail = end - start; - if (avail <= size) { - fprintf(stderr, "image #d does not fit (avail = %u, size = %u)\n", avail, size); - exit(5); - } + if (avail <= size) { + fprintf(stderr, "image #d does not fit (avail = %u, size = %u)\n", avail, size); + exit(5); + } - /* now update size */ - if (i == 0) - md->curr_ldlb->LDLB_Block2.m_uSectorsInFirmware = (size + 2047) / 2048; - else - md->curr_ldlb->LDLB_Block2.m_uSectorsInFirmware2 = (size + 2047) / 2048; + /* now update size */ + if (i == 0) + md->curr_ldlb->LDLB_Block2.m_uSectorsInFirmware = (size + 2047) / 2048; + else + md->curr_ldlb->LDLB_Block2.m_uSectorsInFirmware2 = (size + 2047) / 2048; + } update |= UPDATE_BS(i); } From 862ebbb6df19cc0377f4fd6db11d246578e80310 Mon Sep 17 00:00:00 2001 From: Leif Middelschulte Date: Mon, 14 Jun 2021 10:47:41 +0200 Subject: [PATCH 11/14] fix uninitialized variable usage. Signed-off-by: Leif Middelschulte --- src/main.c | 2 +- src/mtd.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.c b/src/main.c index ba19d45..c8770b3 100644 --- a/src/main.c +++ b/src/main.c @@ -179,7 +179,7 @@ int extract_main(int argc, char **argv) char buf[512]; struct mtd_config cfg; uint8_t key[16]; - long end_of_file, pos; + long end_of_file = 0, pos; char ascii[20 * 2 + 1]; FILE *tfp; int readn, chunk, curr; diff --git a/src/mtd.c b/src/mtd.c index 21ba4ce..bcd8da6 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -329,7 +329,7 @@ int mtd_read_page(struct mtd_data *md, int chip, loff_t ofs, int ecc) struct nfc_geometry *nfc_geo = &md->nfc_geometry; int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len; int chunksize = nfc_geo->ecc_chunkn_size_in_bytes; - int dst_bit_off; + int dst_bit_off = 0; int oob_bit_off; int oob_bit_left; int ecc_chunk_count; @@ -445,7 +445,7 @@ int mtd_write_page(struct mtd_data *md, int chip, loff_t ofs, int ecc) struct nfc_geometry *nfc_geo = &md->nfc_geometry; int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len; int chunksize = nfc_geo->ecc_chunkn_size_in_bytes; - int src_bit_off; + int src_bit_off = 0; int oob_bit_off; int oob_bit_left; int ecc_chunk_count; From fb82de0c40a9e5a25da633dd6327a1b158c1ded3 Mon Sep 17 00:00:00 2001 From: Bernd Westermann Date: Tue, 15 Jun 2021 14:39:46 +0200 Subject: [PATCH 12/14] Add barebox compatible slot switch Adds switch to select on of the two firmware slots. This allow to safely update on slot while the other slot is still valid. Behavior taken from barebox. Signed-off-by: Jan Remmet Taken from: https://git.phytec.de/meta-phytec/tree/recipes-bsp/imx-kobs/imx-kobs/0001-Slot-switch.patch?h=zeus&id=72ef16bdeef886e9939ef25b66ad68bc50810a78 --- src/main.c | 4 ++++ src/mtd.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++--- src/mtd.h | 1 + 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/main.c b/src/main.c index c8770b3..bfb2425 100644 --- a/src/main.c +++ b/src/main.c @@ -82,6 +82,7 @@ void usage(void) " -x .................................... Add 1k-padding in the head\n" " -n .................................... Dry run (don't commit to flash)\n" " -w .................................... Commit to flash\n" + " -s .................................... Switch Firmware_startingPages 1<->2\n" "\n" " update [-v] [KEY] [KOBS] [-0|1] .. Update a single bootstream\n" " -v .................................... Verbose mode\n" @@ -676,6 +677,9 @@ int init_main(int argc, char **argv) case 'v': flags |= F_VERBOSE; break; + case 's': + flags |= F_FW_SLOT_SWITCH; + break; } } diff --git a/src/mtd.c b/src/mtd.c index bcd8da6..c845cff 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -737,7 +737,8 @@ int parse_nfc_geometry(struct mtd_data *md) if (!plat_config_data->m_u32UseNfcGeo) { /* fsl kernel patch provides bch_geometry via debugfs */ if (!(node = fopen(dbg_geometry_node_path, "r"))) { - fprintf(stderr, "Cannot open BCH geometry node: \"%s\"\n", + fprintf(stderr, "Cannot open BCH geometry node: \"%s\"" + ", but we can calculate it ourselves.\n", dbg_geometry_node_path); return cal_nfc_geometry(md); } @@ -1445,6 +1446,43 @@ void dump(const void *data, int size) printf("\n"); } +static int mtd_fw_load_low(struct mtd_data *md) +{ + int r; + BCB_ROM_BootBlockStruct_t *bbs; + + if (md == NULL) { + fprintf(stderr, "mtd: md == NULL\n"); + return -1; + } + r = mtd_read_page(md, 0, 0, 1); + if (r <= 0) { + fprintf(stderr, "mtd: read FCB failed\n"); + return -1; + } + switch (plat_config_data->m_u32RomVer) { + case ROM_Version_3: + bbs = md->buf + 2; + break; + case ROM_Version_5: + bbs = md->buf + 22; + break; + default: + fprintf(stderr, "mtd: Unknown RomVer.\n"); + return -1; + } + if (FCB_FINGERPRINT != bbs->m_u32FingerPrint) { + fprintf(stderr, "mtd: FCB Fingerprint not found\n"); + return -1; + } + if (bbs->FCB_Block.m_u32Firmware1_startingPage < bbs->FCB_Block.m_u32Firmware2_startingPage) + { + return 1; + } else { + return 0; + } +} + void *mtd_load_boot_structure(struct mtd_data *md, int chip, loff_t *ofsp, loff_t end, uint32_t magic1, uint32_t magic2, uint32_t magic3, int use_ecc, int magic_offset) @@ -2258,6 +2296,7 @@ static int fill_fcb(struct mtd_data *md, FILE *fp) unsigned int boot_stream_size_in_blocks; unsigned int boot_stream1_pos; unsigned int boot_stream2_pos; + unsigned int boot_stream_pos; unsigned int sbs_off_byte; /* secondary_boot_stream_off_in_byte */ int valid_offset_flag; @@ -2465,6 +2504,21 @@ static int fill_fcb(struct mtd_data *md, FILE *fp) boot_stream2_pos + max_boot_stream_size_in_bytes, boot_stream2_pos + boot_stream_size_in_bytes); + /* Compute slot switch feature */ + if (md->flags & F_FW_SLOT_SWITCH) { + if (1 == mtd_fw_load_low(md)) { + vp(md,"FW slot switch to HIGH!!!\n"); + boot_stream_pos = boot_stream1_pos; + boot_stream1_pos = boot_stream2_pos; + boot_stream2_pos = boot_stream_pos; + boot_stream_pos = extra_boot_stream1_pos; + extra_boot_stream1_pos = extra_boot_stream2_pos; + extra_boot_stream2_pos = boot_stream_pos; + } else { + vp(md,"FW slot switch to LOW!!!\n"); + } + } + memset(fcb, 0, sizeof(*fcb)); fcb->m_u32FingerPrint = FCB_FINGERPRINT; @@ -3317,11 +3371,19 @@ int write_boot_stream(struct mtd_data *md, FILE *fp) if (i == 0) { startpage = fcb->m_u32Firmware1_startingPage; size = fcb->m_u32PagesInFirmware1; - end = fcb->m_u32Firmware2_startingPage; + if (fcb->m_u32Firmware2_startingPage > fcb->m_u32Firmware1_startingPage) { + end = fcb->m_u32Firmware2_startingPage; + } else { + end = mtd_size(md) / mtd_writesize(md); + } } else { startpage = fcb->m_u32Firmware2_startingPage; size = fcb->m_u32PagesInFirmware2; - end = mtd_size(md) / mtd_writesize(md); + if (fcb->m_u32Firmware1_startingPage > fcb->m_u32Firmware2_startingPage) { + end = fcb->m_u32Firmware1_startingPage; + } else { + end = mtd_size(md) / mtd_writesize(md); + } } start = startpage * mtd_writesize(md); diff --git a/src/mtd.h b/src/mtd.h index 7aa0831..6da405d 100644 --- a/src/mtd.h +++ b/src/mtd.h @@ -47,6 +47,7 @@ #define F_VERBOSE 0x01 #define F_MULTICHIP 0x02 #define F_AUTO_MULTICHIP 0x04 +#define F_FW_SLOT_SWITCH 0x08 #define vp(x, ...) \ do { \ From 1fed1a9cd31db65e32db94837cc392a2b90f9e57 Mon Sep 17 00:00:00 2001 From: Jan Remmet Date: Tue, 15 Jun 2021 15:02:28 +0200 Subject: [PATCH 13/14] mtd: write boot streams separately The slot feature allows to switch the two boot streams. So we can write the "unused" slot first. But in mtd_commit_structures first the FCB is written and thereafter the boot streams. If a power cut occurs, the FCB may point to a partial written boot stream. Now first the "unused" bootstream is written, than the FCB table and the "actual" boot stream. Making the update is power cut tolerant. Taken from: https://git.phytec.de/meta-phytec/tree/recipes-bsp/imx-kobs/imx-kobs/0001-mtd-write-boot-streams-separately.patch?h=zeus&id=72ef16bdeef886e9939ef25b66ad68bc50810a78 --- src/mtd.c | 226 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 139 insertions(+), 87 deletions(-) diff --git a/src/mtd.c b/src/mtd.c index c845cff..ecec023 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -3354,110 +3354,117 @@ int write_extra_boot_stream(struct mtd_data *md, FILE *fp) return 0; } - -int write_boot_stream(struct mtd_data *md, FILE *fp) +int _write_boot_stream(struct mtd_data *md, FILE *fp, int slot) { int startpage, start, size; loff_t ofs, end; - int i, r, chunk; + int i = slot, r, chunk; int chip = 0; struct fcb_block *fcb = &md->fcb.FCB_Block; - vp(md, "---------- Start to write the [ %s ]----\n", (char*)md->private); - for (i = 0; i < 2; i++) { - if (fp == NULL) - continue; - - if (i == 0) { - startpage = fcb->m_u32Firmware1_startingPage; - size = fcb->m_u32PagesInFirmware1; - if (fcb->m_u32Firmware2_startingPage > fcb->m_u32Firmware1_startingPage) { - end = fcb->m_u32Firmware2_startingPage; - } else { - end = mtd_size(md) / mtd_writesize(md); - } + if (i == 0) { + startpage = fcb->m_u32Firmware1_startingPage; + size = fcb->m_u32PagesInFirmware1; + if (fcb->m_u32Firmware2_startingPage > fcb->m_u32Firmware1_startingPage) { + end = fcb->m_u32Firmware2_startingPage; } else { - startpage = fcb->m_u32Firmware2_startingPage; - size = fcb->m_u32PagesInFirmware2; - if (fcb->m_u32Firmware1_startingPage > fcb->m_u32Firmware2_startingPage) { - end = fcb->m_u32Firmware1_startingPage; - } else { - end = mtd_size(md) / mtd_writesize(md); - } + end = mtd_size(md) / mtd_writesize(md); } + } else { + startpage = fcb->m_u32Firmware2_startingPage; + size = fcb->m_u32PagesInFirmware2; + if (fcb->m_u32Firmware1_startingPage > fcb->m_u32Firmware2_startingPage) { + end = fcb->m_u32Firmware1_startingPage; + } else { + end = mtd_size(md) / mtd_writesize(md); + } + } - start = startpage * mtd_writesize(md); - size = size * mtd_writesize(md); - end = end * mtd_writesize(md); - - vp(md, "mtd: Writting %s: #%d @%d: 0x%08x - 0x%08x\n", - (char*)md->private, i, chip, start, start + size); + start = startpage * mtd_writesize(md); + size = size * mtd_writesize(md); + end = end * mtd_writesize(md); - /* Begin to write the image. */ - rewind(fp); + vp(md, "mtd: Writting %s: #%d @%d: 0x%08x - 0x%08x\n", + (char*)md->private, i, chip, start, start + size); - ofs = start; - while (ofs < end && size > 0) { - while (mtd_isbad(md, chip, ofs) == 1) { - vp(md, "mtd: Skipping bad block at 0x%llx\n", ofs); - ofs += mtd_erasesize(md); - } - - chunk = size; + /* Begin to write the image. */ + rewind(fp); - /* - * Check if we've entered a new block and, if so, erase - * it before beginning to write it. - */ - if ((ofs % mtd_erasesize(md)) == 0) { - r = mtd_erase_block(md, chip, ofs); - if (r < 0) { - fprintf(stderr, "mtd: Failed to erase block" - "@0x%llx\n", ofs); - ofs += mtd_erasesize(md); - continue; - } - } + ofs = start; + while (ofs < end && size > 0) { + while (mtd_isbad(md, chip, ofs) == 1) { + vp(md, "mtd: Skipping bad block at 0x%llx\n", ofs); + ofs += mtd_erasesize(md); + } - if (chunk > mtd_writesize(md)) - chunk = mtd_writesize(md); + chunk = size; - r = fread(md->buf, 1, chunk, fp); + /* + * Check if we've entered a new block and, if so, erase + * it before beginning to write it. + */ + if ((ofs % mtd_erasesize(md)) == 0) { + r = mtd_erase_block(md, chip, ofs); if (r < 0) { - fprintf(stderr, "mtd: Failed %d (fread %d)\n", r, chunk); - return -1; - } - if (r < chunk) { - memset(md->buf + r, 0, chunk - r); - vp(md, "mtd: The last page is not full : %d\n", r); + fprintf(stderr, "mtd: Failed to erase block" + "@0x%llx\n", ofs); + ofs += mtd_erasesize(md); + continue; } + } - /* write page */ - r = mtd_write_page(md, chip, ofs, 1); - if (r != mtd_writesize(md)) - fprintf(stderr, "mtd: Failed to write BS @0x%llx (%d)\n", - ofs, r); + if (chunk > mtd_writesize(md)) + chunk = mtd_writesize(md); - ofs += mtd_writesize(md); - size -= chunk; + r = fread(md->buf, 1, chunk, fp); + if (r < 0) { + fprintf(stderr, "mtd: Failed %d (fread %d)\n", r, chunk); + return -1; + } + if (r < chunk) { + memset(md->buf + r, 0, chunk - r); + vp(md, "mtd: The last page is not full : %d\n", r); } - /* - * Write one safe guard page: - * The Image_len of uboot is bigger then the real size of - * uboot by 1K. The ROM will get all 0xff error in this case. - * So we write one more page for safe guard. - */ - memset(md->buf, 0, mtd_writesize(md)); + /* write page */ r = mtd_write_page(md, chip, ofs, 1); if (r != mtd_writesize(md)) - fprintf(stderr, "Failed to write safe page\n"); - vp(md, "mtd: We write one page for save guard. *\n"); + fprintf(stderr, "mtd: Failed to write BS @0x%llx (%d)\n", + ofs, r); - if (ofs >= end) { - fprintf(stderr, "mtd: Failed to write BS#%d\n", i); - return -1; - } + ofs += mtd_writesize(md); + size -= chunk; + } + + /* + * Write one safe guard page: + * The Image_len of uboot is bigger then the real size of + * uboot by 1K. The ROM will get all 0xff error in this case. + * So we write one more page for safe guard. + */ + memset(md->buf, 0, mtd_writesize(md)); + r = mtd_write_page(md, chip, ofs, 1); + if (r != mtd_writesize(md)) + fprintf(stderr, "Failed to write safe page\n"); + vp(md, "mtd: We write one page for save guard. *\n"); + + if (ofs >= end) { + fprintf(stderr, "mtd: Failed to write BS#%d\n", i); + return -1; + } + + return 0; +} + +int write_boot_stream(struct mtd_data *md, FILE *fp) +{ + int i, r; + + vp(md, "---------- Start to write the [ %s ]----\n", (char*)md->private); + for (i = 0; i < 2; i++) { + r = _write_boot_stream(md, fp, i); + if(r) + return r; } return 0; } @@ -3884,6 +3891,14 @@ int v4_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) loff_t ofs; struct mtd_config *cfg = &md->cfg; + if (md->flags & F_FW_SLOT_SWITCH) { + /* [0] Write the 1st boot streams. */ + vp(md, "---------- Start to write the [ %s ]----\n", (char*)md->private); + r = _write_boot_stream(md, fp, 0); + if (r) + return r; + } + /* [1] Write the FCB search area. */ size = mtd_writesize(md) + mtd_oobsize(md); memset(md->buf, 0, size); @@ -3915,8 +3930,15 @@ int v4_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) } } - /* [3] Write the two boot streams. */ - return write_boot_stream(md, fp); + if (md->flags & F_FW_SLOT_SWITCH) { + /* [3] Write the 2nd boot streams. */ + vp(md, "---------- Start to write the [ %s ]----\n", (char*)md->private); + r = _write_boot_stream(md, fp, 1); + return r; + } else { + /* [3] Write the two boot streams. */ + return write_boot_stream(md, fp); + } } int v5_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) @@ -3925,6 +3947,14 @@ int v5_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) loff_t ofs; struct mtd_config *cfg = &md->cfg; + if (md->flags & F_FW_SLOT_SWITCH) { + /* [0] Write the 1st boot streams. */ + vp(md, "---------- Start to write the [ %s ]----\n", (char*)md->private); + r = _write_boot_stream(md, fp, 0); + if (r) + return r; + } + /* [1] Write the FCB search area. */ size = mtd_writesize(md) + mtd_oobsize(md); memset(md->buf, 0, size); @@ -3961,8 +3991,15 @@ int v5_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) } } - /* [3] Write the two boot streams. */ - return write_boot_stream(md, fp); + if (md->flags & F_FW_SLOT_SWITCH) { + /* [3] Write the 2nd boot streams. */ + vp(md, "---------- Start to write the [ %s ]----\n", (char*)md->private); + r = _write_boot_stream(md, fp, 1); + return r; + } else { + /* [3] Write the two boot streams. */ + return write_boot_stream(md, fp); + } } int v6_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) @@ -3971,6 +4008,14 @@ int v6_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) loff_t ofs; struct mtd_config *cfg = &md->cfg; + if (md->flags & F_FW_SLOT_SWITCH) { + /* [0] Write the 1st boot streams. */ + vp(md, "---------- Start to write the [ %s ]----\n", (char*)md->private); + r = _write_boot_stream(md, fp, 0); + if (r) + return r; + } + /* [1] Write the FCB search area. */ size = mtd_writesize(md) + mtd_oobsize(md); memset(md->buf, 0, size); @@ -4003,8 +4048,15 @@ int v6_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) } } - /* [3] Write the two boot streams. */ - return write_boot_stream(md, fp); + if (md->flags & F_FW_SLOT_SWITCH) { + /* [3] Write the 2nd boot streams. */ + vp(md, "---------- Start to write the [ %s ]----\n", (char*)md->private); + r = _write_boot_stream(md, fp, 1); + return r; + } else { + /* [3] Write the two boot streams. */ + return write_boot_stream(md, fp); + } } int v7_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) From 88c0de40f21c267f276fef4f3e5d800c596b18a0 Mon Sep 17 00:00:00 2001 From: Leif Middelschulte Date: Fri, 7 Jan 2022 13:44:46 +0100 Subject: [PATCH 14/14] search_exponent: do not overwrite passed argument The search exponent as passed by the user shall not be overwritten. --- src/mtd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mtd.c b/src/mtd.c index ecec023..f70be55 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -879,9 +879,6 @@ struct mtd_data *mtd_open(const struct mtd_config *cfg, int flags) || plat_config_data->m_u32Arm_type == MX6Q || plat_config_data->m_u32Arm_type == MX6DL) { - md->cfg.search_exponent = 1; - vp(md, "mtd: search_exponent set to 1 by default\n"); - /* open the nvmem file */ if (plat_config_data->m_u32Arm_type == MX8Q) { fp = fopen("/sys/bus/nvmem/devices/imx-ocotp0/nvmem", "rb"); @@ -891,6 +888,8 @@ struct mtd_data *mtd_open(const struct mtd_config *cfg, int flags) } if (plat_config_data->m_u32Arm_type == MX8MN || plat_config_data->m_u32Arm_type == MX8MP) { + md->cfg.search_exponent = 1; + vp(md, "mtd: search_exponent set to 1 by default\n"); fp = fopen("/sys/bus/nvmem/devices/imx-ocotp0/nvmem", "rb"); fuse_off = MX8MN_FUSE_NAND_SEARCH_CNT_OFFS; fuse_bit = MX8MN_FUSE_NAND_SEARCH_CNT_BIT_OFFS; @@ -915,7 +914,6 @@ struct mtd_data *mtd_open(const struct mtd_config *cfg, int flags) // see linux kernel's imx-ocotp.c:imx_ocotp_read if (word == 0xBADABADA) { vp(md, "mtd: read back a \"read locked\" register. Got invalid value: 0x%x\n", word); - md->cfg.search_exponent = 1; } else { word &= 0x000f; vp(md, "mtd: read back from fuse: %x\n", word);