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