1/* 2 * i.MX nand boot control block(bcb). 3 * 4 * Based on the common/imx-bbu-nand-fcb.c from barebox and imx kobs-ng 5 * 6 * Copyright (C) 2017 Jagan Teki <jagan@amarulasolutions.com> 7 * Copyright (C) 2016 Sergey Kubushyn <ksi@koi8.net> 8 * 9 * Reconstucted by Han Xu <han.xu@nxp.com> 10 * 11 * SPDX-License-Identifier: GPL-2.0+ 12 */ 13 14#include <common.h> 15#include <command.h> 16#include <log.h> 17#include <malloc.h> 18#include <nand.h> 19#include <dm/devres.h> 20#include <linux/bug.h> 21 22#include <asm/io.h> 23#include <jffs2/jffs2.h> 24#include <linux/bch.h> 25#include <linux/mtd/mtd.h> 26#include <linux/mtd/rawnand.h> 27 28#include <asm/arch/sys_proto.h> 29#include <asm/mach-imx/imx-nandbcb.h> 30#include <asm/mach-imx/imximage.cfg> 31#include <mxs_nand.h> 32#include <linux/mtd/mtd.h> 33#include <nand.h> 34#include <fuse.h> 35 36#include "../../../cmd/legacy-mtd-utils.h" 37 38/* FCB related flags */ 39/* FCB layout with leading 12B reserved */ 40#define FCB_LAYOUT_RESV_12B BIT(0) 41/* FCB layout with leading 32B meta data */ 42#define FCB_LAYOUT_META_32B BIT(1) 43/* FCB encrypted by Hamming code */ 44#define FCB_ENCODE_HAMMING BIT(2) 45/* FCB encrypted by 40bit BCH */ 46#define FCB_ENCODE_BCH_40b BIT(3) 47/* FCB encrypted by 62bit BCH */ 48#define FCB_ENCODE_BCH_62b BIT(4) 49/* FCB encrypted by BCH */ 50#define FCB_ENCODE_BCH (FCB_ENCODE_BCH_40b | FCB_ENCODE_BCH_62b) 51/* FCB data was randomized */ 52#define FCB_RANDON_ENABLED BIT(5) 53 54/* Firmware related flags */ 55/* No 1K padding */ 56#define FIRMWARE_NEED_PADDING BIT(8) 57/* Extra firmware*/ 58#define FIRMWARE_EXTRA_ONE BIT(9) 59/* Secondary firmware on fixed address */ 60#define FIRMWARE_SECONDARY_FIXED_ADDR BIT(10) 61 62/* Boot search related flags */ 63#define BT_SEARCH_CNT_FROM_FUSE BIT(16) 64 65struct platform_config { 66 int misc_flags; 67}; 68 69static struct platform_config plat_config; 70 71/* imx6q/dl/solo */ 72static struct platform_config imx6qdl_plat_config = { 73 .misc_flags = FCB_LAYOUT_RESV_12B | 74 FCB_ENCODE_HAMMING | 75 FIRMWARE_NEED_PADDING, 76}; 77 78static struct platform_config imx6sx_plat_config = { 79 .misc_flags = FCB_LAYOUT_META_32B | 80 FCB_ENCODE_BCH_62b | 81 FIRMWARE_NEED_PADDING | 82 FCB_RANDON_ENABLED, 83}; 84 85static struct platform_config imx7d_plat_config = { 86 .misc_flags = FCB_LAYOUT_META_32B | 87 FCB_ENCODE_BCH_62b | 88 FIRMWARE_NEED_PADDING | 89 FCB_RANDON_ENABLED, 90}; 91 92/* imx6ul/ull/ulz */ 93static struct platform_config imx6ul_plat_config = { 94 .misc_flags = FCB_LAYOUT_META_32B | 95 FCB_ENCODE_BCH_40b | 96 FIRMWARE_NEED_PADDING, 97}; 98 99static struct platform_config imx8mq_plat_config = { 100 .misc_flags = FCB_LAYOUT_META_32B | 101 FCB_ENCODE_BCH_62b | 102 FIRMWARE_NEED_PADDING | 103 FCB_RANDON_ENABLED | 104 FIRMWARE_EXTRA_ONE, 105}; 106 107/* all other imx8mm */ 108static struct platform_config imx8mm_plat_config = { 109 .misc_flags = FCB_LAYOUT_META_32B | 110 FCB_ENCODE_BCH_62b | 111 FIRMWARE_NEED_PADDING | 112 FCB_RANDON_ENABLED, 113}; 114 115/* imx8mn */ 116static struct platform_config imx8mn_plat_config = { 117 .misc_flags = FCB_LAYOUT_META_32B | 118 FCB_ENCODE_BCH_62b | 119 FCB_RANDON_ENABLED | 120 FIRMWARE_SECONDARY_FIXED_ADDR | 121 BT_SEARCH_CNT_FROM_FUSE, 122}; 123 124/* imx8qx/qm */ 125static struct platform_config imx8q_plat_config = { 126 .misc_flags = FCB_LAYOUT_META_32B | 127 FCB_ENCODE_BCH_62b | 128 FCB_RANDON_ENABLED | 129 FIRMWARE_SECONDARY_FIXED_ADDR | 130 BT_SEARCH_CNT_FROM_FUSE, 131}; 132 133/* boot search related variables and definitions */ 134static int g_boot_search_count = 4; 135static int g_boot_secondary_offset; 136static int g_boot_search_stride; 137static int g_pages_per_stride; 138 139/* mtd config structure */ 140struct boot_config { 141 int dev; 142 struct mtd_info *mtd; 143 loff_t maxsize; 144 loff_t input_size; 145 loff_t offset; 146 loff_t boot_stream1_address; 147 loff_t boot_stream2_address; 148 size_t boot_stream1_size; 149 size_t boot_stream2_size; 150 size_t max_boot_stream_size; 151 int stride_size_in_byte; 152 int search_area_size_in_bytes; 153 int search_area_size_in_pages; 154 int secondary_boot_stream_off_in_MB; 155}; 156 157/* boot_stream config structure */ 158struct boot_stream_config { 159 char bs_label[32]; 160 loff_t bs_addr; 161 size_t bs_size; 162 void *bs_buf; 163 loff_t next_bs_addr; 164 bool need_padding; 165}; 166 167/* FW index */ 168#define FW1_ONLY 1 169#define FW2_ONLY 2 170#define FW_ALL FW1_ONLY | FW2_ONLY 171#define FW_INX(x) (1 << (x)) 172 173/* NAND convert macros */ 174#define CONV_TO_PAGES(x) ((u32)(x) / (u32)(mtd->writesize)) 175#define CONV_TO_BLOCKS(x) ((u32)(x) / (u32)(mtd->erasesize)) 176 177#define GETBIT(v, n) (((v) >> (n)) & 0x1) 178#define IMX8MQ_SPL_SZ 0x3e000 179#define IMX8MQ_HDMI_FW_SZ 0x19c00 180 181static int nandbcb_get_info(int argc, char * const argv[], 182 struct boot_config *boot_cfg) 183{ 184 int dev; 185 struct mtd_info *mtd; 186 187 dev = nand_curr_device; 188 if (dev < 0) { 189 printf("failed to get nand_curr_device, run nand device\n"); 190 return CMD_RET_FAILURE; 191 } 192 193 mtd = get_nand_dev_by_index(dev); 194 if (!mtd) { 195 printf("failed to get mtd info\n"); 196 return CMD_RET_FAILURE; 197 } 198 199 boot_cfg->dev = dev; 200 boot_cfg->mtd = mtd; 201 202 return CMD_RET_SUCCESS; 203} 204 205static int nandbcb_get_size(int argc, char * const argv[], int num, 206 struct boot_config *boot_cfg) 207{ 208 int dev; 209 loff_t offset, size, maxsize; 210 struct mtd_info *mtd; 211 212 dev = boot_cfg->dev; 213 mtd = boot_cfg->mtd; 214 size = 0; 215 216 if (mtd_arg_off_size(argc - num, argv + num, &dev, &offset, &size, 217 &maxsize, MTD_DEV_TYPE_NAND, mtd->size)) 218 return CMD_RET_FAILURE; 219 220 boot_cfg->maxsize = maxsize; 221 boot_cfg->offset = offset; 222 223 debug("max: %llx, offset: %llx\n", maxsize, offset); 224 225 if (size && size != maxsize) 226 boot_cfg->input_size = size; 227 228 return CMD_RET_SUCCESS; 229} 230 231static int nandbcb_set_boot_config(int argc, char * const argv[], 232 struct boot_config *boot_cfg) 233{ 234 struct mtd_info *mtd; 235 loff_t maxsize; 236 loff_t boot_stream1_address, boot_stream2_address, max_boot_stream_size; 237 238 if (!boot_cfg->mtd) { 239 printf("Didn't get the mtd info, quit\n"); 240 return CMD_RET_FAILURE; 241 } 242 mtd = boot_cfg->mtd; 243 244 /* 245 * By default 246 * set the search count as 4 247 * set each FCB/DBBT/Firmware offset at the beginning of blocks 248 * customers may change the value as needed 249 */ 250 251 /* if need more compact layout, change these values */ 252 /* g_boot_search_count was set as 4 at the definition*/ 253 /* g_pages_per_stride was set as block size */ 254 255 g_pages_per_stride = mtd->erasesize / mtd->writesize; 256 257 g_boot_search_stride = mtd->writesize * g_pages_per_stride; 258 259 boot_cfg->stride_size_in_byte = g_boot_search_stride * mtd->writesize; 260 boot_cfg->search_area_size_in_bytes = 261 g_boot_search_count * g_boot_search_stride; 262 boot_cfg->search_area_size_in_pages = 263 boot_cfg->search_area_size_in_bytes / mtd->writesize; 264 265 /* after FCB/DBBT, split the rest of area for two Firmwares */ 266 if (!boot_cfg->maxsize) { 267 printf("Didn't get the maxsize, quit\n"); 268 return CMD_RET_FAILURE; 269 } 270 maxsize = boot_cfg->maxsize; 271 /* align to page boundary */ 272 maxsize = ((u32)(maxsize + mtd->writesize - 1)) / (u32)mtd->writesize 273 * mtd->writesize; 274 275 boot_stream1_address = 2 * boot_cfg->search_area_size_in_bytes; 276 boot_stream2_address = ((maxsize - boot_stream1_address) / 2 + 277 boot_stream1_address); 278 279 if (g_boot_secondary_offset) 280 boot_stream2_address = 281 (loff_t)g_boot_secondary_offset * 1024 * 1024; 282 283 max_boot_stream_size = boot_stream2_address - boot_stream1_address; 284 285 /* sanity check */ 286 if (max_boot_stream_size <= 0) { 287 debug("st1_addr: %llx, st2_addr: %llx, max: %llx\n", 288 boot_stream1_address, boot_stream2_address, 289 max_boot_stream_size); 290 printf("something wrong with firmware address settings\n"); 291 return CMD_RET_FAILURE; 292 } 293 boot_cfg->boot_stream1_address = boot_stream1_address; 294 boot_cfg->boot_stream2_address = boot_stream2_address; 295 boot_cfg->max_boot_stream_size = max_boot_stream_size; 296 297 /* set the boot_stream size as the input size now */ 298 if (boot_cfg->input_size) { 299 boot_cfg->boot_stream1_size = boot_cfg->input_size; 300 boot_cfg->boot_stream2_size = boot_cfg->input_size; 301 } 302 303 return CMD_RET_SUCCESS; 304} 305 306static int nandbcb_check_space(struct boot_config *boot_cfg) 307{ 308 size_t maxsize = boot_cfg->maxsize; 309 size_t max_boot_stream_size = boot_cfg->max_boot_stream_size; 310 loff_t boot_stream2_address = boot_cfg->boot_stream2_address; 311 312 if (boot_cfg->boot_stream1_size && 313 boot_cfg->boot_stream1_size > max_boot_stream_size) { 314 printf("boot stream1 doesn't fit, check partition size or settings\n"); 315 return CMD_RET_FAILURE; 316 } 317 318 if (boot_cfg->boot_stream2_size && 319 boot_cfg->boot_stream2_size > maxsize - boot_stream2_address) { 320 printf("boot stream2 doesn't fit, check partition size or settings\n"); 321 return CMD_RET_FAILURE; 322 } 323 324 return CMD_RET_SUCCESS; 325} 326 327#if defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL) 328static uint8_t reverse_bit(uint8_t b) 329{ 330 b = (b & 0xf0) >> 4 | (b & 0x0f) << 4; 331 b = (b & 0xcc) >> 2 | (b & 0x33) << 2; 332 b = (b & 0xaa) >> 1 | (b & 0x55) << 1; 333 334 return b; 335} 336 337static void encode_bch_ecc(void *buf, struct fcb_block *fcb, int eccbits) 338{ 339 int i, j, m = 13; 340 int blocksize = 128; 341 int numblocks = 8; 342 int ecc_buf_size = (m * eccbits + 7) / 8; 343 struct bch_control *bch = init_bch(m, eccbits, 0); 344 u8 *ecc_buf = kzalloc(ecc_buf_size, GFP_KERNEL); 345 u8 *tmp_buf = kzalloc(blocksize * numblocks, GFP_KERNEL); 346 u8 *psrc, *pdst; 347 348 /* 349 * The blocks here are bit aligned. If eccbits is a multiple of 8, 350 * we just can copy bytes. Otherwiese we must move the blocks to 351 * the next free bit position. 352 */ 353 WARN_ON(eccbits % 8); 354 355 memcpy(tmp_buf, fcb, sizeof(*fcb)); 356 357 for (i = 0; i < numblocks; i++) { 358 memset(ecc_buf, 0, ecc_buf_size); 359 psrc = tmp_buf + i * blocksize; 360 pdst = buf + i * (blocksize + ecc_buf_size); 361 362 /* copy data byte aligned to destination buf */ 363 memcpy(pdst, psrc, blocksize); 364 365 /* 366 * imx-kobs use a modified encode_bch which reverse the 367 * bit order of the data before calculating bch. 368 * Do this in the buffer and use the bch lib here. 369 */ 370 for (j = 0; j < blocksize; j++) 371 psrc[j] = reverse_bit(psrc[j]); 372 373 encode_bch(bch, psrc, blocksize, ecc_buf); 374 375 /* reverse ecc bit */ 376 for (j = 0; j < ecc_buf_size; j++) 377 ecc_buf[j] = reverse_bit(ecc_buf[j]); 378 379 /* Here eccbuf is byte aligned and we can just copy it */ 380 memcpy(pdst + blocksize, ecc_buf, ecc_buf_size); 381 } 382 383 kfree(ecc_buf); 384 kfree(tmp_buf); 385 free_bch(bch); 386} 387#else 388 389static u8 calculate_parity_13_8(u8 d) 390{ 391 u8 p = 0; 392 393 p |= (GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 3) ^ GETBIT(d, 2)) << 0; 394 p |= (GETBIT(d, 7) ^ GETBIT(d, 5) ^ GETBIT(d, 4) ^ GETBIT(d, 2) ^ 395 GETBIT(d, 1)) << 1; 396 p |= (GETBIT(d, 7) ^ GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 1) ^ 397 GETBIT(d, 0)) << 2; 398 p |= (GETBIT(d, 7) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 0)) << 3; 399 p |= (GETBIT(d, 6) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 2) ^ 400 GETBIT(d, 1) ^ GETBIT(d, 0)) << 4; 401 402 return p; 403} 404 405static void encode_hamming_13_8(void *_src, void *_ecc, size_t size) 406{ 407 int i; 408 u8 *src = _src; 409 u8 *ecc = _ecc; 410 411 for (i = 0; i < size; i++) 412 ecc[i] = calculate_parity_13_8(src[i]); 413} 414#endif 415 416static u32 calc_chksum(void *buf, size_t size) 417{ 418 u32 chksum = 0; 419 u8 *bp = buf; 420 size_t i; 421 422 for (i = 0; i < size; i++) 423 chksum += bp[i]; 424 425 return ~chksum; 426} 427 428static void fill_fcb(struct fcb_block *fcb, struct boot_config *boot_cfg) 429{ 430 struct mtd_info *mtd = boot_cfg->mtd; 431 struct nand_chip *chip = mtd_to_nand(mtd); 432 struct mxs_nand_info *nand_info = nand_get_controller_data(chip); 433 struct mxs_nand_layout l; 434 435 mxs_nand_get_layout(mtd, &l); 436 437 fcb->fingerprint = FCB_FINGERPRINT; 438 fcb->version = FCB_VERSION_1; 439 440 fcb->datasetup = 80; 441 fcb->datahold = 60; 442 fcb->addr_setup = 25; 443 fcb->dsample_time = 6; 444 445 fcb->pagesize = mtd->writesize; 446 fcb->oob_pagesize = mtd->writesize + mtd->oobsize; 447 fcb->sectors = mtd->erasesize / mtd->writesize; 448 449 fcb->meta_size = l.meta_size; 450 fcb->nr_blocks = l.nblocks; 451 fcb->ecc_nr = l.data0_size; 452 fcb->ecc_level = l.ecc0; 453 fcb->ecc_size = l.datan_size; 454 fcb->ecc_type = l.eccn; 455 fcb->bchtype = l.gf_len; 456 457 /* DBBT search area starts from the next block after all FCB */ 458 fcb->dbbt_start = boot_cfg->search_area_size_in_pages; 459 460 fcb->bb_byte = nand_info->bch_geometry.block_mark_byte_offset; 461 fcb->bb_start_bit = nand_info->bch_geometry.block_mark_bit_offset; 462 463 fcb->phy_offset = mtd->writesize; 464 465 fcb->disbbm = 0; 466 467 fcb->fw1_start = CONV_TO_PAGES(boot_cfg->boot_stream1_address); 468 fcb->fw2_start = CONV_TO_PAGES(boot_cfg->boot_stream2_address); 469 fcb->fw1_pages = CONV_TO_PAGES(boot_cfg->boot_stream1_size); 470 fcb->fw2_pages = CONV_TO_PAGES(boot_cfg->boot_stream2_size); 471 472 fcb->checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4); 473} 474 475static int fill_dbbt_data(struct mtd_info *mtd, void *buf, int num_blocks) 476{ 477 int n, n_bad_blocks = 0; 478 u32 *bb = buf + 0x8; 479 u32 *n_bad_blocksp = buf + 0x4; 480 481 for (n = 0; n < num_blocks; n++) { 482 loff_t offset = (loff_t)n * mtd->erasesize; 483 if (mtd_block_isbad(mtd, offset)) { 484 n_bad_blocks++; 485 *bb = n; 486 bb++; 487 } 488 } 489 490 *n_bad_blocksp = n_bad_blocks; 491 492 return n_bad_blocks; 493} 494 495/* 496 * return 1 - bad block 497 * return 0 - read successfully 498 * return < 0 - read failed 499 */ 500static int read_fcb(struct boot_config *boot_cfg, struct fcb_block *fcb, 501 loff_t off) 502{ 503 struct mtd_info *mtd; 504 void *fcb_raw_page; 505 size_t size; 506 int ret = 0; 507 508 mtd = boot_cfg->mtd; 509 510 fcb_raw_page = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); 511 if (!fcb_raw_page) { 512 debug("failed to allocate fcb_raw_page\n"); 513 ret = -ENOMEM; 514 return ret; 515 } 516 517 /* 518 * User BCH hardware to decode ECC for FCB 519 */ 520 if (plat_config.misc_flags & FCB_ENCODE_BCH) { 521 size = sizeof(struct fcb_block); 522 523 /* switch nand BCH to FCB compatible settings */ 524 if (plat_config.misc_flags & FCB_ENCODE_BCH_62b) 525 mxs_nand_mode_fcb_62bit(mtd); 526 else if (plat_config.misc_flags & FCB_ENCODE_BCH_40b) 527 mxs_nand_mode_fcb_40bit(mtd); 528 529 ret = nand_read_skip_bad(mtd, off, &size, NULL, mtd->size, (u_char *)fcb); 530 531 /* switch BCH back */ 532 mxs_nand_mode_normal(mtd); 533 printf("NAND FCB read from 0x%llx offset 0x%zx read: %s\n", 534 off, size, ret ? "ERROR" : "OK"); 535 536 } else if (plat_config.misc_flags & FCB_ENCODE_HAMMING) { 537 /* raw read*/ 538 mtd_oob_ops_t ops = { 539 .datbuf = (u8 *)fcb_raw_page, 540 .oobbuf = ((u8 *)fcb_raw_page) + mtd->writesize, 541 .len = mtd->writesize, 542 .ooblen = mtd->oobsize, 543 .mode = MTD_OPS_RAW 544 }; 545 546 ret = mtd_read_oob(mtd, off, &ops); 547 printf("NAND FCB read from 0x%llx offset 0x%zx read: %s\n", 548 off, ops.len, ret ? "ERROR" : "OK"); 549 } 550 551 if (ret) 552 goto fcb_raw_page_err; 553 554 if ((plat_config.misc_flags & FCB_ENCODE_HAMMING) && 555 (plat_config.misc_flags & FCB_LAYOUT_RESV_12B)) 556 memcpy(fcb, fcb_raw_page + 12, sizeof(struct fcb_block)); 557 558/* TODO: check if it can pass Hamming check */ 559 560fcb_raw_page_err: 561 kfree(fcb_raw_page); 562 563 return ret; 564} 565 566static int write_fcb(struct boot_config *boot_cfg, struct fcb_block *fcb) 567{ 568 struct mtd_info *mtd; 569 void *fcb_raw_page = NULL; 570 int i, ret = 0; 571 loff_t off; 572 size_t size; 573 574 mtd = boot_cfg->mtd; 575 576 /* 577 * We prepare raw page only for i.MX6, for i.MX7 we 578 * leverage BCH hw module instead 579 */ 580 if ((plat_config.misc_flags & FCB_ENCODE_HAMMING) && 581 (plat_config.misc_flags & FCB_LAYOUT_RESV_12B)) { 582 fcb_raw_page = kzalloc(mtd->writesize + mtd->oobsize, 583 GFP_KERNEL); 584 if (!fcb_raw_page) { 585 debug("failed to allocate fcb_raw_page\n"); 586 ret = -ENOMEM; 587 return ret; 588 } 589 590#if defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL) 591 /* 40 bit BCH, for i.MX6UL(L) */ 592 encode_bch_ecc(fcb_raw_page + 32, fcb, 40); 593#else 594 memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block)); 595 encode_hamming_13_8(fcb_raw_page + 12, 596 fcb_raw_page + 12 + 512, 512); 597#endif 598 /* 599 * Set the first and second byte of OOB data to 0xFF, 600 * not 0x00. These bytes are used as the Manufacturers Bad 601 * Block Marker (MBBM). Since the FCB is mostly written to 602 * the first page in a block, a scan for 603 * factory bad blocks will detect these blocks as bad, e.g. 604 * when function nand_scan_bbt() is executed to build a new 605 * bad block table. 606 */ 607 memset(fcb_raw_page + mtd->writesize, 0xFF, 2); 608 } 609 610 /* start writing FCB from the very beginning */ 611 off = 0; 612 613 for (i = 0; i < g_boot_search_count; i++) { 614 if (mtd_block_isbad(mtd, off)) { 615 printf("Block %d is bad, skipped\n", i); 616 off += mtd->erasesize; 617 continue; 618 } 619 620 /* 621 * User BCH hardware module to generate ECC for FCB 622 */ 623 if (plat_config.misc_flags & FCB_ENCODE_BCH) { 624 size = sizeof(struct fcb_block); 625 626 /* switch nand BCH to FCB compatible settings */ 627 if (plat_config.misc_flags & FCB_ENCODE_BCH_62b) 628 mxs_nand_mode_fcb_62bit(mtd); 629 else if (plat_config.misc_flags & FCB_ENCODE_BCH_40b) 630 mxs_nand_mode_fcb_40bit(mtd); 631 632 ret = nand_write(mtd, off, &size, (u_char *)fcb); 633 634 /* switch BCH back */ 635 mxs_nand_mode_normal(mtd); 636 printf("NAND FCB write to 0x%zx offset 0x%llx written: %s\n", 637 size, off, ret ? "ERROR" : "OK"); 638 639 } else if (plat_config.misc_flags & FCB_ENCODE_HAMMING) { 640 /* raw write */ 641 mtd_oob_ops_t ops = { 642 .datbuf = (u8 *)fcb_raw_page, 643 .oobbuf = ((u8 *)fcb_raw_page) + 644 mtd->writesize, 645 .len = mtd->writesize, 646 .ooblen = mtd->oobsize, 647 .mode = MTD_OPS_RAW 648 }; 649 650 ret = mtd_write_oob(mtd, off, &ops); 651 printf("NAND FCB write to 0x%llx offset 0x%zx written: %s\n", off, ops.len, ret ? "ERROR" : "OK"); 652 } 653 654 if (ret) 655 goto fcb_raw_page_err; 656 657 /* next writing location */ 658 off += g_boot_search_stride; 659 } 660 661fcb_raw_page_err: 662 kfree(fcb_raw_page); 663 664 return ret; 665} 666 667/* 668 * return 1 - bad block 669 * return 0 - read successfully 670 * return < 0 - read failed 671 */ 672static int read_dbbt(struct boot_config *boot_cfg, struct dbbt_block *dbbt, 673 void *dbbt_data_page, loff_t off) 674{ 675 size_t size; 676 size_t actual_size; 677 struct mtd_info *mtd; 678 loff_t to; 679 int ret; 680 681 mtd = boot_cfg->mtd; 682 683 size = sizeof(struct dbbt_block); 684 ret = nand_read_skip_bad(mtd, off, &size, &actual_size, mtd->size, (u_char *)dbbt); 685 printf("NAND DBBT read from 0x%llx offset 0x%zx read: %s\n", 686 off, size, ret ? "ERROR" : "OK"); 687 if (ret) 688 return ret; 689 690 /* dbbtpages == 0 if no bad blocks */ 691 if (dbbt->dbbtpages > 0) { 692 to = off + 4 * mtd->writesize + actual_size - size; 693 size = mtd->writesize; 694 ret = nand_read_skip_bad(mtd, to, &size, NULL, mtd->size, dbbt_data_page); 695 printf("DBBT data read from 0x%llx offset 0x%zx read: %s\n", 696 to, size, ret ? "ERROR" : "OK"); 697 698 if (ret) 699 return ret; 700 } 701 702 return 0; 703} 704 705static int write_dbbt(struct boot_config *boot_cfg, struct dbbt_block *dbbt, 706 void *dbbt_data_page) 707{ 708 int i; 709 loff_t off, to; 710 size_t size; 711 struct mtd_info *mtd; 712 int ret; 713 714 mtd = boot_cfg->mtd; 715 716 /* start writing DBBT after all FCBs */ 717 off = boot_cfg->search_area_size_in_bytes; 718 size = mtd->writesize; 719 720 for (i = 0; i < g_boot_search_count; i++) { 721 if (mtd_block_isbad(mtd, off)) { 722 printf("Block %d is bad, skipped\n", 723 (int)(i + CONV_TO_BLOCKS(off))); 724 off += mtd->erasesize; 725 continue; 726 } 727 728 ret = nand_write(mtd, off, &size, (u_char *)dbbt); 729 printf("NAND DBBT write to 0x%llx offset 0x%zx written: %s\n", 730 off, size, ret ? "ERROR" : "OK"); 731 if (ret) 732 return ret; 733 734 /* dbbtpages == 0 if no bad blocks */ 735 if (dbbt->dbbtpages > 0) { 736 to = off + 4 * mtd->writesize; 737 ret = nand_write(mtd, to, &size, dbbt_data_page); 738 printf("DBBT data write to 0x%llx offset 0x%zx written: %s\n", 739 to, size, ret ? "ERROR" : "OK"); 740 741 if (ret) 742 return ret; 743 } 744 745 /* next writing location */ 746 off += g_boot_search_stride; 747 } 748 749 return 0; 750} 751 752/* reuse the check_skip_len from nand_util.c with minor change*/ 753static int check_skip_length(struct boot_config *boot_cfg, loff_t offset, 754 size_t length, size_t *used) 755{ 756 struct mtd_info *mtd = boot_cfg->mtd; 757 size_t maxsize = boot_cfg->maxsize; 758 size_t len_excl_bad = 0; 759 int ret = 0; 760 761 while (len_excl_bad < length) { 762 size_t block_len, block_off; 763 loff_t block_start; 764 765 if (offset >= maxsize) 766 return -1; 767 768 block_start = offset & ~(loff_t)(mtd->erasesize - 1); 769 block_off = offset & (mtd->erasesize - 1); 770 block_len = mtd->erasesize - block_off; 771 772 if (!nand_block_isbad(mtd, block_start)) 773 len_excl_bad += block_len; 774 else 775 ret = 1; 776 777 offset += block_len; 778 *used += block_len; 779 } 780 781 /* If the length is not a multiple of block_len, adjust. */ 782 if (len_excl_bad > length) 783 *used -= (len_excl_bad - length); 784 785 return ret; 786} 787 788static int nandbcb_get_next_good_blk_addr(struct boot_config *boot_cfg, 789 struct boot_stream_config *bs_cfg) 790{ 791 struct mtd_info *mtd = boot_cfg->mtd; 792 loff_t offset = bs_cfg->bs_addr; 793 size_t length = bs_cfg->bs_size; 794 size_t used = 0; 795 int ret; 796 797 ret = check_skip_length(boot_cfg, offset, length, &used); 798 799 if (ret < 0) 800 return ret; 801 802 /* get next image address */ 803 bs_cfg->next_bs_addr = (u32)(offset + used + mtd->erasesize - 1) 804 / (u32)mtd->erasesize * mtd->erasesize; 805 806 return ret; 807} 808 809static int nandbcb_write_bs_skip_bad(struct boot_config *boot_cfg, 810 struct boot_stream_config *bs_cfg) 811{ 812 struct mtd_info *mtd; 813 void *buf; 814 loff_t offset, maxsize; 815 size_t size; 816 size_t length; 817 int ret; 818 bool padding_flag = false; 819 820 mtd = boot_cfg->mtd; 821 offset = bs_cfg->bs_addr; 822 maxsize = boot_cfg->maxsize; 823 size = bs_cfg->bs_size; 824 825 /* some boot images may need leading offset */ 826 if (bs_cfg->need_padding && 827 (plat_config.misc_flags & FIRMWARE_NEED_PADDING)) 828 padding_flag = 1; 829 830 if (padding_flag) 831 length = ALIGN(size + FLASH_OFFSET_STANDARD, mtd->writesize); 832 else 833 length = ALIGN(size, mtd->writesize); 834 835 buf = kzalloc(length, GFP_KERNEL); 836 if (!buf) { 837 printf("failed to allocate buffer for firmware\n"); 838 ret = -ENOMEM; 839 return ret; 840 } 841 842 if (padding_flag) 843 memcpy(buf + FLASH_OFFSET_STANDARD, bs_cfg->bs_buf, size); 844 else 845 memcpy(buf, bs_cfg->bs_buf, size); 846 847 ret = nand_write_skip_bad(mtd, offset, &length, NULL, maxsize, 848 (u_char *)buf, WITH_WR_VERIFY); 849 printf("Write %s @0x%llx offset, 0x%zx bytes written: %s\n", 850 bs_cfg->bs_label, offset, length, ret ? "ERROR" : "OK"); 851 852 if (ret) 853 /* write image failed, quit */ 854 goto err; 855 856 /* get next good blk address if needed */ 857 if (bs_cfg->need_padding) { 858 ret = nandbcb_get_next_good_blk_addr(boot_cfg, bs_cfg); 859 if (ret < 0) { 860 printf("Next image cannot fit in NAND partition\n"); 861 goto err; 862 } 863 } 864 865 /* now we know how the exact image size written to NAND */ 866 bs_cfg->bs_size = length; 867 return 0; 868err: 869 kfree(buf); 870 return ret; 871} 872 873static int nandbcb_write_fw(struct boot_config *boot_cfg, u_char *buf, 874 int index) 875{ 876 int i; 877 loff_t offset; 878 size_t size; 879 loff_t next_bs_addr; 880 struct boot_stream_config bs_cfg; 881 int ret; 882 883 for (i = 0; i < 2; ++i) { 884 if (!(FW_INX(i) & index)) 885 continue; 886 887 if (i == 0) { 888 offset = boot_cfg->boot_stream1_address; 889 size = boot_cfg->boot_stream1_size; 890 } else { 891 offset = boot_cfg->boot_stream2_address; 892 size = boot_cfg->boot_stream2_size; 893 } 894 895 /* write Firmware*/ 896 if (!(plat_config.misc_flags & FIRMWARE_EXTRA_ONE)) { 897 memset(&bs_cfg, 0, sizeof(struct boot_stream_config)); 898 sprintf(bs_cfg.bs_label, "firmware%d", i); 899 bs_cfg.bs_addr = offset; 900 bs_cfg.bs_size = size; 901 bs_cfg.bs_buf = buf; 902 bs_cfg.need_padding = 1; 903 904 ret = nandbcb_write_bs_skip_bad(boot_cfg, &bs_cfg); 905 if (ret) 906 return ret; 907 908 /* update the boot stream size */ 909 if (i == 0) 910 boot_cfg->boot_stream1_size = bs_cfg.bs_size; 911 else 912 boot_cfg->boot_stream2_size = bs_cfg.bs_size; 913 914 } else { 915 /* some platforms need extra firmware */ 916 memset(&bs_cfg, 0, sizeof(struct boot_stream_config)); 917 sprintf(bs_cfg.bs_label, "fw%d_part%d", i, 1); 918 bs_cfg.bs_addr = offset; 919 bs_cfg.bs_size = IMX8MQ_HDMI_FW_SZ; 920 bs_cfg.bs_buf = buf; 921 bs_cfg.need_padding = 1; 922 923 ret = nandbcb_write_bs_skip_bad(boot_cfg, &bs_cfg); 924 if (ret) 925 return ret; 926 927 /* update the boot stream size */ 928 if (i == 0) 929 boot_cfg->boot_stream1_size = bs_cfg.bs_size; 930 else 931 boot_cfg->boot_stream2_size = bs_cfg.bs_size; 932 933 /* get next image address */ 934 next_bs_addr = bs_cfg.next_bs_addr; 935 936 memset(&bs_cfg, 0, sizeof(struct boot_stream_config)); 937 sprintf(bs_cfg.bs_label, "fw%d_part%d", i, 2); 938 bs_cfg.bs_addr = next_bs_addr; 939 bs_cfg.bs_size = IMX8MQ_SPL_SZ; 940 bs_cfg.bs_buf = (u_char *)(buf + IMX8MQ_HDMI_FW_SZ); 941 bs_cfg.need_padding = 0; 942 943 ret = nandbcb_write_bs_skip_bad(boot_cfg, &bs_cfg); 944 if (ret) 945 return ret; 946 } 947 } 948 949 return 0; 950} 951 952static int nandbcb_init(struct boot_config *boot_cfg, u_char *buf) 953{ 954 struct mtd_info *mtd; 955 nand_erase_options_t opts; 956 struct fcb_block *fcb; 957 struct dbbt_block *dbbt; 958 void *dbbt_page, *dbbt_data_page; 959 int ret; 960 loff_t maxsize, off; 961 962 mtd = boot_cfg->mtd; 963 maxsize = boot_cfg->maxsize; 964 off = boot_cfg->offset; 965 966 /* erase */ 967 memset(&opts, 0, sizeof(opts)); 968 opts.offset = off; 969 opts.length = maxsize - 1; 970 ret = nand_erase_opts(mtd, &opts); 971 if (ret) { 972 printf("%s: erase failed (ret = %d)\n", __func__, ret); 973 return ret; 974 } 975 976 /* 977 * Reference documentation from i.MX6DQRM section 8.5.2.2 978 * 979 * Nand Boot Control Block(BCB) contains two data structures, 980 * - Firmware Configuration Block(FCB) 981 * - Discovered Bad Block Table(DBBT) 982 * 983 * FCB contains, 984 * - nand timings 985 * - DBBT search page address, 986 * - start page address of primary firmware 987 * - start page address of secondary firmware 988 * 989 * setup fcb: 990 * - number of blocks = mtd partition size / mtd erasesize 991 * - two firmware blocks, primary and secondary 992 * - first 4 block for FCB/DBBT 993 * - rest split in half for primary and secondary firmware 994 * - same firmware write twice 995 */ 996 997 /* write Firmware*/ 998 ret = nandbcb_write_fw(boot_cfg, buf, FW_ALL); 999 if (ret) 1000 goto err; 1001 1002 /* fill fcb */ 1003 fcb = kzalloc(sizeof(*fcb), GFP_KERNEL); 1004 if (!fcb) { 1005 debug("failed to allocate fcb\n"); 1006 ret = -ENOMEM; 1007 return ret; 1008 } 1009 fill_fcb(fcb, boot_cfg); 1010 1011 ret = write_fcb(boot_cfg, fcb); 1012 1013 /* fill dbbt */ 1014 dbbt_page = kzalloc(mtd->writesize, GFP_KERNEL); 1015 if (!dbbt_page) { 1016 debug("failed to allocate dbbt_page\n"); 1017 ret = -ENOMEM; 1018 goto fcb_err; 1019 } 1020 1021 dbbt_data_page = kzalloc(mtd->writesize, GFP_KERNEL); 1022 if (!dbbt_data_page) { 1023 debug("failed to allocate dbbt_data_page\n"); 1024 ret = -ENOMEM; 1025 goto dbbt_page_err; 1026 } 1027 1028 dbbt = dbbt_page; 1029 dbbt->checksum = 0; 1030 dbbt->fingerprint = DBBT_FINGERPRINT; 1031 dbbt->version = DBBT_VERSION_1; 1032 ret = fill_dbbt_data(mtd, dbbt_data_page, CONV_TO_BLOCKS(maxsize)); 1033 if (ret < 0) 1034 goto dbbt_data_page_err; 1035 else if (ret > 0) 1036 dbbt->dbbtpages = 1; 1037 1038 /* write dbbt */ 1039 ret = write_dbbt(boot_cfg, dbbt, dbbt_data_page); 1040 if (ret < 0) 1041 printf("failed to write FCB/DBBT\n"); 1042 1043dbbt_data_page_err: 1044 kfree(dbbt_data_page); 1045dbbt_page_err: 1046 kfree(dbbt_page); 1047fcb_err: 1048 kfree(fcb); 1049err: 1050 return ret; 1051} 1052 1053static int do_nandbcb_bcbonly(int argc, char *const argv[]) 1054{ 1055 struct fcb_block *fcb; 1056 struct dbbt_block *dbbt; 1057 struct mtd_info *mtd; 1058 nand_erase_options_t opts; 1059 size_t maxsize; 1060 loff_t off; 1061 void *dbbt_page, *dbbt_data_page; 1062 int ret; 1063 struct boot_config cfg; 1064 1065 if (argc < 4) 1066 return CMD_RET_USAGE; 1067 1068 memset(&cfg, 0, sizeof(struct boot_config)); 1069 if (nandbcb_get_info(argc, argv, &cfg)) 1070 return CMD_RET_FAILURE; 1071 1072 /* only get the partition info */ 1073 if (nandbcb_get_size(2, argv, 1, &cfg)) 1074 return CMD_RET_FAILURE; 1075 1076 if (nandbcb_set_boot_config(argc, argv, &cfg)) 1077 return CMD_RET_FAILURE; 1078 1079 mtd = cfg.mtd; 1080 1081 cfg.boot_stream1_address = hextoul(argv[2], NULL); 1082 cfg.boot_stream1_size = hextoul(argv[3], NULL); 1083 cfg.boot_stream1_size = ALIGN(cfg.boot_stream1_size, mtd->writesize); 1084 1085 if (argc > 5) { 1086 cfg.boot_stream2_address = hextoul(argv[4], NULL); 1087 cfg.boot_stream2_size = hextoul(argv[5], NULL); 1088 cfg.boot_stream2_size = ALIGN(cfg.boot_stream2_size, 1089 mtd->writesize); 1090 } 1091 1092 /* sanity check */ 1093 nandbcb_check_space(&cfg); 1094 1095 maxsize = cfg.maxsize; 1096 off = cfg.offset; 1097 1098 /* erase the previous FCB/DBBT */ 1099 memset(&opts, 0, sizeof(opts)); 1100 opts.offset = off; 1101 opts.length = g_boot_search_stride * 2; 1102 ret = nand_erase_opts(mtd, &opts); 1103 if (ret) { 1104 printf("%s: erase failed (ret = %d)\n", __func__, ret); 1105 return CMD_RET_FAILURE; 1106 } 1107 1108 /* fill fcb */ 1109 fcb = kzalloc(sizeof(*fcb), GFP_KERNEL); 1110 if (!fcb) { 1111 printf("failed to allocate fcb\n"); 1112 ret = -ENOMEM; 1113 return CMD_RET_FAILURE; 1114 } 1115 1116 fill_fcb(fcb, &cfg); 1117 1118 /* write fcb */ 1119 ret = write_fcb(&cfg, fcb); 1120 1121 /* fill dbbt */ 1122 dbbt_page = kzalloc(mtd->writesize, GFP_KERNEL); 1123 if (!dbbt_page) { 1124 printf("failed to allocate dbbt_page\n"); 1125 ret = -ENOMEM; 1126 goto fcb_err; 1127 } 1128 1129 dbbt_data_page = kzalloc(mtd->writesize, GFP_KERNEL); 1130 if (!dbbt_data_page) { 1131 printf("failed to allocate dbbt_data_page\n"); 1132 ret = -ENOMEM; 1133 goto dbbt_page_err; 1134 } 1135 1136 dbbt = dbbt_page; 1137 dbbt->checksum = 0; 1138 dbbt->fingerprint = DBBT_FINGERPRINT; 1139 dbbt->version = DBBT_VERSION_1; 1140 ret = fill_dbbt_data(mtd, dbbt_data_page, CONV_TO_BLOCKS(maxsize)); 1141 if (ret < 0) 1142 goto dbbt_data_page_err; 1143 else if (ret > 0) 1144 dbbt->dbbtpages = 1; 1145 1146 /* write dbbt */ 1147 ret = write_dbbt(&cfg, dbbt, dbbt_data_page); 1148 1149dbbt_data_page_err: 1150 kfree(dbbt_data_page); 1151dbbt_page_err: 1152 kfree(dbbt_page); 1153fcb_err: 1154 kfree(fcb); 1155 1156 if (ret < 0) { 1157 printf("failed to write FCB/DBBT\n"); 1158 return CMD_RET_FAILURE; 1159 } 1160 1161 return CMD_RET_SUCCESS; 1162} 1163 1164/* dump data which is read from NAND chip */ 1165void dump_structure(struct boot_config *boot_cfg, struct fcb_block *fcb, 1166 struct dbbt_block *dbbt, void *dbbt_data_page) 1167{ 1168 int i; 1169 struct mtd_info *mtd = boot_cfg->mtd; 1170 1171 #define P1(x) printf(" %s = 0x%08x\n", #x, fcb->x) 1172 printf("FCB\n"); 1173 P1(checksum); 1174 P1(fingerprint); 1175 P1(version); 1176 #undef P1 1177 #define P1(x) printf(" %s = %d\n", #x, fcb->x) 1178 P1(datasetup); 1179 P1(datahold); 1180 P1(addr_setup); 1181 P1(dsample_time); 1182 P1(pagesize); 1183 P1(oob_pagesize); 1184 P1(sectors); 1185 P1(nr_nand); 1186 P1(nr_die); 1187 P1(celltype); 1188 P1(ecc_type); 1189 P1(ecc_nr); 1190 P1(ecc_size); 1191 P1(ecc_level); 1192 P1(meta_size); 1193 P1(nr_blocks); 1194 P1(ecc_type_sdk); 1195 P1(ecc_nr_sdk); 1196 P1(ecc_size_sdk); 1197 P1(ecc_level_sdk); 1198 P1(nr_blocks_sdk); 1199 P1(meta_size_sdk); 1200 P1(erase_th); 1201 P1(bootpatch); 1202 P1(patch_size); 1203 P1(fw1_start); 1204 P1(fw2_start); 1205 P1(fw1_pages); 1206 P1(fw2_pages); 1207 P1(dbbt_start); 1208 P1(bb_byte); 1209 P1(bb_start_bit); 1210 P1(phy_offset); 1211 P1(bchtype); 1212 P1(readlatency); 1213 P1(predelay); 1214 P1(cedelay); 1215 P1(postdelay); 1216 P1(cmdaddpause); 1217 P1(datapause); 1218 P1(tmspeed); 1219 P1(busytimeout); 1220 P1(disbbm); 1221 P1(spare_offset); 1222#if !defined(CONFIG_MX6) || defined(CONFIG_MX6SX) || \ 1223 defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL) 1224 P1(onfi_sync_enable); 1225 P1(onfi_sync_speed); 1226 P1(onfi_sync_nand_data); 1227 P1(disbbm_search); 1228 P1(disbbm_search_limit); 1229 P1(read_retry_enable); 1230#endif 1231 #undef P1 1232 #define P1(x) printf(" %s = 0x%08x\n", #x, dbbt->x) 1233 printf("DBBT :\n"); 1234 P1(checksum); 1235 P1(fingerprint); 1236 P1(version); 1237 #undef P1 1238 #define P1(x) printf(" %s = %d\n", #x, dbbt->x) 1239 P1(dbbtpages); 1240 #undef P1 1241 1242 for (i = 0; i < dbbt->dbbtpages; ++i) 1243 printf("%d ", *((u32 *)(dbbt_data_page + i))); 1244 1245 if (!(plat_config.misc_flags & FIRMWARE_EXTRA_ONE)) { 1246 printf("Firmware: image #0 @ 0x%x size 0x%x\n", 1247 fcb->fw1_start, fcb->fw1_pages * mtd->writesize); 1248 printf("Firmware: image #1 @ 0x%x size 0x%x\n", 1249 fcb->fw2_start, fcb->fw2_pages * mtd->writesize); 1250 } else { 1251 printf("Firmware: image #0 @ 0x%x size 0x%x\n", 1252 fcb->fw1_start, fcb->fw1_pages * mtd->writesize); 1253 printf("Firmware: image #1 @ 0x%x size 0x%x\n", 1254 fcb->fw2_start, fcb->fw2_pages * mtd->writesize); 1255 /* TODO: Add extra image information */ 1256 } 1257} 1258 1259static bool check_fingerprint(void *data, int fingerprint) 1260{ 1261 int off = 4; 1262 1263 return (*(int *)(data + off) == fingerprint); 1264} 1265 1266static int fuse_secondary_boot(u32 bank, u32 word, u32 mask, u32 off) 1267{ 1268 int err; 1269 u32 val; 1270 int ret; 1271 1272 err = fuse_read(bank, word, &val); 1273 if (err) 1274 return 0; 1275 1276 val = (val & mask) >> off; 1277 1278 if (val > 10) 1279 return 0; 1280 1281 switch (val) { 1282 case 0: 1283 ret = 4; 1284 break; 1285 case 1: 1286 ret = 1; 1287 break; 1288 default: 1289 ret = 2 << val; 1290 break; 1291 } 1292 1293 return ret; 1294}; 1295 1296static int fuse_to_search_count(u32 bank, u32 word, u32 mask, u32 off) 1297{ 1298 int err; 1299 u32 val; 1300 int ret; 1301 1302 /* by default, the boot search count from fuse should be 2 */ 1303 err = fuse_read(bank, word, &val); 1304 if (err) 1305 return 2; 1306 1307 val = (val & mask) >> off; 1308 1309 switch (val) { 1310 case 0: 1311 ret = 2; 1312 break; 1313 case 1: 1314 case 2: 1315 case 3: 1316 ret = 1 << val; 1317 break; 1318 default: 1319 ret = 2; 1320 } 1321 1322 return ret; 1323} 1324 1325static int nandbcb_dump(struct boot_config *boot_cfg) 1326{ 1327 int i; 1328 loff_t off; 1329 struct mtd_info *mtd = boot_cfg->mtd; 1330 struct fcb_block fcb, fcb_copy; 1331 struct dbbt_block dbbt, dbbt_copy; 1332 void *dbbt_data_page, *dbbt_data_page_copy; 1333 bool fcb_not_found, dbbt_not_found; 1334 int ret = 0; 1335 1336 dbbt_data_page = kzalloc(mtd->writesize, GFP_KERNEL); 1337 if (!dbbt_data_page) { 1338 printf("failed to allocate dbbt_data_page\n"); 1339 ret = -ENOMEM; 1340 return ret; 1341 } 1342 1343 dbbt_data_page_copy = kzalloc(mtd->writesize, GFP_KERNEL); 1344 if (!dbbt_data_page_copy) { 1345 printf("failed to allocate dbbt_data_page\n"); 1346 ret = -ENOMEM; 1347 goto dbbt_page_err; 1348 } 1349 1350 /* read fcb */ 1351 fcb_not_found = 1; 1352 off = 0; 1353 for (i = 0; i < g_boot_search_count; ++i) { 1354 if (fcb_not_found) { 1355 ret = read_fcb(boot_cfg, &fcb, off); 1356 1357 if (ret < 0) 1358 goto dbbt_page_copy_err; 1359 else if (ret == 1) 1360 continue; 1361 else if (ret == 0) 1362 if (check_fingerprint(&fcb, FCB_FINGERPRINT)) 1363 fcb_not_found = 0; 1364 } else { 1365 ret = read_fcb(boot_cfg, &fcb_copy, off); 1366 1367 if (ret < 0) 1368 goto dbbt_page_copy_err; 1369 if (memcmp(&fcb, &fcb_copy, 1370 sizeof(struct fcb_block))) { 1371 printf("FCB copies are not identical\n"); 1372 ret = -EINVAL; 1373 goto dbbt_page_copy_err; 1374 } 1375 } 1376 1377 /* next read location */ 1378 off += g_boot_search_stride; 1379 } 1380 1381 /* read dbbt*/ 1382 dbbt_not_found = 1; 1383 off = boot_cfg->search_area_size_in_bytes; 1384 for (i = 0; i < g_boot_search_count; ++i) { 1385 if (dbbt_not_found) { 1386 ret = read_dbbt(boot_cfg, &dbbt, dbbt_data_page, off); 1387 1388 if (ret < 0) 1389 goto dbbt_page_copy_err; 1390 else if (ret == 1) 1391 continue; 1392 else if (ret == 0) 1393 if (check_fingerprint(&dbbt, DBBT_FINGERPRINT)) 1394 dbbt_not_found = 0; 1395 } else { 1396 ret = read_dbbt(boot_cfg, &dbbt_copy, 1397 dbbt_data_page_copy, off); 1398 1399 if (ret < 0) 1400 goto dbbt_page_copy_err; 1401 if (memcmp(&dbbt, &dbbt_copy, 1402 sizeof(struct dbbt_block))) { 1403 printf("DBBT copies are not identical\n"); 1404 ret = -EINVAL; 1405 goto dbbt_page_copy_err; 1406 } 1407 if (dbbt.dbbtpages > 0 && 1408 memcmp(dbbt_data_page, dbbt_data_page_copy, 1409 mtd->writesize)) { 1410 printf("DBBT data copies are not identical\n"); 1411 ret = -EINVAL; 1412 goto dbbt_page_copy_err; 1413 } 1414 } 1415 1416 /* next read location */ 1417 off += g_boot_search_stride; 1418 } 1419 1420 dump_structure(boot_cfg, &fcb, &dbbt, dbbt_data_page); 1421 1422dbbt_page_copy_err: 1423 kfree(dbbt_data_page_copy); 1424dbbt_page_err: 1425 kfree(dbbt_data_page); 1426 1427 return ret; 1428} 1429 1430static int do_nandbcb_dump(int argc, char * const argv[]) 1431{ 1432 struct boot_config cfg; 1433 int ret; 1434 1435 if (argc != 2) 1436 return CMD_RET_USAGE; 1437 1438 memset(&cfg, 0, sizeof(struct boot_config)); 1439 if (nandbcb_get_info(argc, argv, &cfg)) 1440 return CMD_RET_FAILURE; 1441 1442 if (nandbcb_get_size(argc, argv, 1, &cfg)) 1443 return CMD_RET_FAILURE; 1444 1445 if (nandbcb_set_boot_config(argc, argv, &cfg)) 1446 return CMD_RET_FAILURE; 1447 1448 ret = nandbcb_dump(&cfg); 1449 if (ret) 1450 return ret; 1451 1452 return ret; 1453} 1454 1455static int do_nandbcb_init(int argc, char * const argv[]) 1456{ 1457 u_char *buf; 1458 size_t size; 1459 loff_t addr; 1460 char *endp; 1461 int ret; 1462 struct boot_config cfg; 1463 1464 if (argc != 4) 1465 return CMD_RET_USAGE; 1466 1467 memset(&cfg, 0, sizeof(struct boot_config)); 1468 if (nandbcb_get_info(argc, argv, &cfg)) 1469 return CMD_RET_FAILURE; 1470 1471 if (nandbcb_get_size(argc, argv, 2, &cfg)) 1472 return CMD_RET_FAILURE; 1473 size = cfg.boot_stream1_size; 1474 1475 if (nandbcb_set_boot_config(argc, argv, &cfg)) 1476 return CMD_RET_FAILURE; 1477 1478 addr = hextoul(argv[1], &endp); 1479 if (*argv[1] == 0 || *endp != 0) 1480 return CMD_RET_FAILURE; 1481 1482 buf = map_physmem(addr, size, MAP_WRBACK); 1483 if (!buf) { 1484 puts("failed to map physical memory\n"); 1485 return CMD_RET_FAILURE; 1486 } 1487 1488 ret = nandbcb_init(&cfg, buf); 1489 1490 return ret == 0 ? CMD_RET_SUCCESS : CMD_RET_FAILURE; 1491} 1492 1493static int do_nandbcb(struct cmd_tbl *cmdtp, int flag, int argc, 1494 char *const argv[]) 1495{ 1496 const char *cmd; 1497 int ret = 0; 1498 1499 if (argc < 3) 1500 goto usage; 1501 1502 /* check the platform config first */ 1503 if (is_mx6sx()) { 1504 plat_config = imx6sx_plat_config; 1505 } else if (is_mx7()) { 1506 plat_config = imx7d_plat_config; 1507 } else if (is_mx6ul() || is_mx6ull()) { 1508 plat_config = imx6ul_plat_config; 1509 } else if (is_mx6() && !is_mx6sx() && !is_mx6ul() && !is_mx6ull()) { 1510 plat_config = imx6qdl_plat_config; 1511 } else if (is_imx8mq()) { 1512 plat_config = imx8mq_plat_config; 1513 } else if (is_imx8mm()) { 1514 plat_config = imx8mm_plat_config; 1515 } else if (is_imx8mn() || is_imx8mp()) { 1516 plat_config = imx8mn_plat_config; 1517 } else if (is_imx8qm() || is_imx8qxp()) { 1518 plat_config = imx8q_plat_config; 1519 } else { 1520 printf("ERROR: Unknown platform\n"); 1521 return CMD_RET_FAILURE; 1522 } 1523 1524 if ((plat_config.misc_flags) & BT_SEARCH_CNT_FROM_FUSE) { 1525 if (is_imx8qxp()) 1526 g_boot_search_count = fuse_to_search_count(0, 720, 0xc0, 6); 1527 if (is_imx8mn() || is_imx8mp()) 1528 g_boot_search_count = fuse_to_search_count(2, 2, 0x6000, 13); 1529 printf("search count set to %d from fuse\n", 1530 g_boot_search_count); 1531 } 1532 1533 if (plat_config.misc_flags & FIRMWARE_SECONDARY_FIXED_ADDR) { 1534 if (is_imx8mn()) 1535 g_boot_secondary_offset = fuse_secondary_boot(2, 1, 0xff0000, 16); 1536 } 1537 1538 cmd = argv[1]; 1539 --argc; 1540 ++argv; 1541 1542 if (strcmp(cmd, "init") == 0) { 1543 ret = do_nandbcb_init(argc, argv); 1544 goto done; 1545 } 1546 1547 if (strcmp(cmd, "dump") == 0) { 1548 ret = do_nandbcb_dump(argc, argv); 1549 goto done; 1550 } 1551 1552 if (strcmp(cmd, "bcbonly") == 0) { 1553 ret = do_nandbcb_bcbonly(argc, argv); 1554 goto done; 1555 } 1556 1557done: 1558 if (ret != -1) 1559 return ret; 1560usage: 1561 return CMD_RET_USAGE; 1562} 1563 1564U_BOOT_LONGHELP(nandbcb, 1565 "init addr off|partition len - update 'len' bytes starting at\n" 1566 " 'off|part' to memory address 'addr', skipping bad blocks\n" 1567 "nandbcb bcbonly off|partition fw1-off fw1-size [fw2-off fw2-size]\n" 1568 " - write BCB only (FCB and DBBT)\n" 1569 " where `fwx-size` is fw sizes in bytes, `fw1-off`\n" 1570 " and `fw2-off` - firmware offsets\n" 1571 " FIY, BCB isn't erased automatically, so mtd erase should\n" 1572 " be called in advance before writing new BCB:\n" 1573 " > mtd erase mx7-bcb\n" 1574 "nandbcb dump off|partition - dump/verify boot structures\n"); 1575 1576U_BOOT_CMD(nandbcb, 7, 1, do_nandbcb, 1577 "i.MX NAND Boot Control Blocks write", 1578 nandbcb_help_text 1579); 1580