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