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