Commit 1d8a50993c2783892428c47cfe2e6241fd106caa

Authored by Alice Guo
Committed by Ye Li
1 parent b01b7e1d59

MLK-22582-2: nandbcb: add nandbcb dump command for i.MX8MM

Verify/dump boot structures written to NAND Flash chip.

Signed-off-by: Alice Guo <alice.guo@nxp.com>
(cherry picked from commit 215953009a0429705a3aaaa7c495e6ad7a0a8a3a)

Showing 1 changed file with 235 additions and 6 deletions Inline Diff

arch/arm/mach-imx/cmd_nandbcb.c
1 /* 1 /*
2 * i.MX6 nand boot control block(bcb). 2 * i.MX6 nand boot control block(bcb).
3 * 3 *
4 * Based on the common/imx-bbu-nand-fcb.c from barebox and imx kobs-ng 4 * Based on the common/imx-bbu-nand-fcb.c from barebox and imx kobs-ng
5 * 5 *
6 * Copyright (C) 2017 Jagan Teki <jagan@amarulasolutions.com> 6 * Copyright (C) 2017 Jagan Teki <jagan@amarulasolutions.com>
7 * Copyright (C) 2016 Sergey Kubushyn <ksi@koi8.net> 7 * Copyright (C) 2016 Sergey Kubushyn <ksi@koi8.net>
8 * 8 *
9 * SPDX-License-Identifier: GPL-2.0+ 9 * SPDX-License-Identifier: GPL-2.0+
10 */ 10 */
11 11
12 #include <common.h> 12 #include <common.h>
13 #include <nand.h> 13 #include <nand.h>
14 14
15 #include <asm/io.h> 15 #include <asm/io.h>
16 #include <jffs2/jffs2.h> 16 #include <jffs2/jffs2.h>
17 #include <linux/mtd/mtd.h> 17 #include <linux/mtd/mtd.h>
18 18
19 #include <asm/arch/sys_proto.h> 19 #include <asm/arch/sys_proto.h>
20 #include <asm/mach-imx/imx-nandbcb.h> 20 #include <asm/mach-imx/imx-nandbcb.h>
21 #include <asm/mach-imx/imximage.cfg> 21 #include <asm/mach-imx/imximage.cfg>
22 #include <mxs_nand.h> 22 #include <mxs_nand.h>
23 #include <linux/mtd/mtd.h> 23 #include <linux/mtd/mtd.h>
24 #include <nand.h> 24 #include <nand.h>
25 #include <div64.h>
25 26
26 #define BF_VAL(v, bf) (((v) & bf##_MASK) >> bf##_OFFSET) 27 #define BF_VAL(v, bf) (((v) & bf##_MASK) >> bf##_OFFSET)
27 #define GETBIT(v, n) (((v) >> (n)) & 0x1) 28 #define GETBIT(v, n) (((v) >> (n)) & 0x1)
28 #define IMX8MQ_SPL_SZ 0x3e000 29 #define IMX8MQ_SPL_SZ 0x3e000
29 #define IMX8MQ_HDMI_FW_SZ 0x19c00 30 #define IMX8MQ_HDMI_FW_SZ 0x19c00
31 #define BOOT_SEARCH_COUNT 2
30 32
33 struct mtd_info *dump_mtd;
34 static loff_t dump_nandboot_size;
35 static struct fcb_block dump_fill_fcb;
36 static struct dbbt_block dump_fill_dbbt;
37 static struct fcb_block dump_nand_fcb[BOOT_SEARCH_COUNT];
38 static struct dbbt_block dump_nand_dbbt[BOOT_SEARCH_COUNT];
39 static u32 dump_fcb_off[BOOT_SEARCH_COUNT];
40 static u32 dump_dbbt_off[BOOT_SEARCH_COUNT];
41
31 static u8 calculate_parity_13_8(u8 d) 42 static u8 calculate_parity_13_8(u8 d)
32 { 43 {
33 u8 p = 0; 44 u8 p = 0;
34 45
35 p |= (GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 3) ^ GETBIT(d, 2)) << 0; 46 p |= (GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 3) ^ GETBIT(d, 2)) << 0;
36 p |= (GETBIT(d, 7) ^ GETBIT(d, 5) ^ GETBIT(d, 4) ^ GETBIT(d, 2) ^ 47 p |= (GETBIT(d, 7) ^ GETBIT(d, 5) ^ GETBIT(d, 4) ^ GETBIT(d, 2) ^
37 GETBIT(d, 1)) << 1; 48 GETBIT(d, 1)) << 1;
38 p |= (GETBIT(d, 7) ^ GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 1) ^ 49 p |= (GETBIT(d, 7) ^ GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 1) ^
39 GETBIT(d, 0)) << 2; 50 GETBIT(d, 0)) << 2;
40 p |= (GETBIT(d, 7) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 0)) << 3; 51 p |= (GETBIT(d, 7) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 0)) << 3;
41 p |= (GETBIT(d, 6) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 2) ^ 52 p |= (GETBIT(d, 6) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 2) ^
42 GETBIT(d, 1) ^ GETBIT(d, 0)) << 4; 53 GETBIT(d, 1) ^ GETBIT(d, 0)) << 4;
43 54
44 return p; 55 return p;
45 } 56 }
46 57
47 static void encode_hamming_13_8(void *_src, void *_ecc, size_t size) 58 static void encode_hamming_13_8(void *_src, void *_ecc, size_t size)
48 { 59 {
49 int i; 60 int i;
50 u8 *src = _src; 61 u8 *src = _src;
51 u8 *ecc = _ecc; 62 u8 *ecc = _ecc;
52 63
53 for (i = 0; i < size; i++) 64 for (i = 0; i < size; i++)
54 ecc[i] = calculate_parity_13_8(src[i]); 65 ecc[i] = calculate_parity_13_8(src[i]);
55 } 66 }
56 67
57 static u32 calc_chksum(void *buf, size_t size) 68 static u32 calc_chksum(void *buf, size_t size)
58 { 69 {
59 u32 chksum = 0; 70 u32 chksum = 0;
60 u8 *bp = buf; 71 u8 *bp = buf;
61 size_t i; 72 size_t i;
62 73
63 for (i = 0; i < size; i++) 74 for (i = 0; i < size; i++)
64 chksum += bp[i]; 75 chksum += bp[i];
65 76
66 return ~chksum; 77 return ~chksum;
67 } 78 }
68 79
69 static void fill_fcb(struct fcb_block *fcb, struct mtd_info *mtd, 80 static void fill_fcb(struct fcb_block *fcb, struct mtd_info *mtd,
70 u32 fw1_start, u32 fw2_start, u32 fw_pages) 81 u32 fw1_start, u32 fw2_start, u32 fw_pages)
71 { 82 {
72 struct nand_chip *chip = mtd_to_nand(mtd); 83 struct nand_chip *chip = mtd_to_nand(mtd);
73 struct mxs_nand_info *nand_info = nand_get_controller_data(chip); 84 struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
74 struct mxs_nand_layout l; 85 struct mxs_nand_layout l;
75 86
76 mxs_nand_get_layout(mtd, &l); 87 mxs_nand_get_layout(mtd, &l);
77 88
78 fcb->fingerprint = FCB_FINGERPRINT; 89 fcb->fingerprint = FCB_FINGERPRINT;
79 fcb->version = FCB_VERSION_1; 90 fcb->version = FCB_VERSION_1;
80 91
81 fcb->pagesize = mtd->writesize; 92 fcb->pagesize = mtd->writesize;
82 fcb->oob_pagesize = mtd->writesize + mtd->oobsize; 93 fcb->oob_pagesize = mtd->writesize + mtd->oobsize;
83 fcb->sectors = mtd->erasesize / mtd->writesize; 94 fcb->sectors = mtd->erasesize / mtd->writesize;
84 95
85 fcb->meta_size = l.meta_size; 96 fcb->meta_size = l.meta_size;
86 fcb->nr_blocks = l.nblocks; 97 fcb->nr_blocks = l.nblocks;
87 fcb->ecc_nr = l.data0_size; 98 fcb->ecc_nr = l.data0_size;
88 fcb->ecc_level = l.ecc0; 99 fcb->ecc_level = l.ecc0;
89 fcb->ecc_size = l.datan_size; 100 fcb->ecc_size = l.datan_size;
90 fcb->ecc_type = l.eccn; 101 fcb->ecc_type = l.eccn;
91 fcb->bchtype = l.gf_len; 102 fcb->bchtype = l.gf_len;
92 103
93 /* Also hardcoded in kobs-ng */ 104 /* Also hardcoded in kobs-ng */
94 if (is_mx6() || is_imx8m()) { 105 if (is_mx6() || is_imx8m()) {
95 fcb->datasetup = 80; 106 fcb->datasetup = 80;
96 fcb->datahold = 60; 107 fcb->datahold = 60;
97 fcb->addr_setup = 25; 108 fcb->addr_setup = 25;
98 fcb->dsample_time = 6; 109 fcb->dsample_time = 6;
99 } else if (is_mx7()) { 110 } else if (is_mx7()) {
100 fcb->datasetup = 10; 111 fcb->datasetup = 10;
101 fcb->datahold = 7; 112 fcb->datahold = 7;
102 fcb->addr_setup = 15; 113 fcb->addr_setup = 15;
103 fcb->dsample_time = 6; 114 fcb->dsample_time = 6;
104 } 115 }
105 116
106 /* DBBT search area starts at second page on first block */ 117 /* DBBT search area starts at second page on first block */
107 fcb->dbbt_start = 1; 118 fcb->dbbt_start = 1;
108 119
109 fcb->bb_byte = nand_info->bch_geometry.block_mark_byte_offset; 120 fcb->bb_byte = nand_info->bch_geometry.block_mark_byte_offset;
110 fcb->bb_start_bit = nand_info->bch_geometry.block_mark_bit_offset; 121 fcb->bb_start_bit = nand_info->bch_geometry.block_mark_bit_offset;
111 122
112 fcb->phy_offset = mtd->writesize; 123 fcb->phy_offset = mtd->writesize;
113 124
114 fcb->nr_blocks = mtd->writesize / fcb->ecc_nr - 1; 125 fcb->nr_blocks = mtd->writesize / fcb->ecc_nr - 1;
115 126
116 fcb->disbbm = 0; 127 fcb->disbbm = 0;
117 fcb->disbbm_search = 0; 128 fcb->disbbm_search = 0;
118 129
119 fcb->fw1_start = fw1_start; /* Firmware image starts on this sector */ 130 fcb->fw1_start = fw1_start; /* Firmware image starts on this sector */
120 fcb->fw2_start = fw2_start; /* Secondary FW Image starting Sector */ 131 fcb->fw2_start = fw2_start; /* Secondary FW Image starting Sector */
121 fcb->fw1_pages = fw_pages; /* Number of sectors in firmware image */ 132 fcb->fw1_pages = fw_pages; /* Number of sectors in firmware image */
122 fcb->fw2_pages = fw_pages; /* Number of sector in secondary FW image */ 133 fcb->fw2_pages = fw_pages; /* Number of sector in secondary FW image */
123 134
124 fcb->checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4); 135 fcb->checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4);
125 } 136 }
126 137
127 static int dbbt_fill_data(struct mtd_info *mtd, void *buf, int num_blocks) 138 static int dbbt_fill_data(struct mtd_info *mtd, void *buf, int num_blocks)
128 { 139 {
129 int n, n_bad_blocks = 0; 140 int n, n_bad_blocks = 0;
130 u32 *bb = buf + 0x8; 141 u32 *bb = buf + 0x8;
131 u32 *n_bad_blocksp = buf + 0x4; 142 u32 *n_bad_blocksp = buf + 0x4;
132 143
133 for (n = 0; n < num_blocks; n++) { 144 for (n = 0; n < num_blocks; n++) {
134 loff_t offset = n * mtd->erasesize; 145 loff_t offset = n * mtd->erasesize;
135 if (mtd_block_isbad(mtd, offset)) { 146 if (mtd_block_isbad(mtd, offset)) {
136 n_bad_blocks++; 147 n_bad_blocks++;
137 *bb = n; 148 *bb = n;
138 bb++; 149 bb++;
139 } 150 }
140 } 151 }
141 152
142 *n_bad_blocksp = n_bad_blocks; 153 *n_bad_blocksp = n_bad_blocks;
143 154
144 return n_bad_blocks; 155 return n_bad_blocks;
145 } 156 }
146 157
147 static int write_fcb_dbbt(struct mtd_info *mtd, struct fcb_block *fcb, 158 static int write_fcb_dbbt_and_readback(struct mtd_info *mtd, struct fcb_block *fcb,
148 struct dbbt_block *dbbt, void *dbbt_data_page, 159 struct dbbt_block *dbbt, void *dbbt_data_page,
149 loff_t off) 160 loff_t off)
150 { 161 {
151 void *fcb_raw_page = 0; 162 void *fcb_raw_page = 0;
152 int i, ret; 163 int i, ret;
153 size_t dummy; 164 size_t dummy;
154 165
155 /* 166 /*
156 * We prepare raw page only for i.MX6, for i.MX7 we 167 * We prepare raw page only for i.MX6, for i.MX7 we
157 * leverage BCH hw module instead 168 * leverage BCH hw module instead
158 */ 169 */
159 if (is_mx6()) { 170 if (is_mx6()) {
160 /* write fcb/dbbt */ 171 /* write fcb/dbbt */
161 fcb_raw_page = kzalloc(mtd->writesize + mtd->oobsize, 172 fcb_raw_page = kzalloc(mtd->writesize + mtd->oobsize,
162 GFP_KERNEL); 173 GFP_KERNEL);
163 if (!fcb_raw_page) { 174 if (!fcb_raw_page) {
164 debug("failed to allocate fcb_raw_page\n"); 175 debug("failed to allocate fcb_raw_page\n");
165 ret = -ENOMEM; 176 ret = -ENOMEM;
166 return ret; 177 return ret;
167 } 178 }
168 179
169 memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block)); 180 memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
170 encode_hamming_13_8(fcb_raw_page + 12, fcb_raw_page + 181 encode_hamming_13_8(fcb_raw_page + 12, fcb_raw_page +
171 12 + 512, 512); 182 12 + 512, 512);
172 /* 183 /*
173 * Set the first and second byte of OOB data to 0xFF, 184 * Set the first and second byte of OOB data to 0xFF,
174 * not 0x00. These bytes are used as the Manufacturers Bad 185 * not 0x00. These bytes are used as the Manufacturers Bad
175 * Block Marker (MBBM). Since the FCB is mostly written to 186 * Block Marker (MBBM). Since the FCB is mostly written to
176 * the first page in a block, a scan for 187 * the first page in a block, a scan for
177 * factory bad blocks will detect these blocks as bad, e.g. 188 * factory bad blocks will detect these blocks as bad, e.g.
178 * when function nand_scan_bbt() is executed to build a new 189 * when function nand_scan_bbt() is executed to build a new
179 * bad block table. 190 * bad block table.
180 */ 191 */
181 memset(fcb_raw_page + mtd->writesize, 0xFF, 2); 192 memset(fcb_raw_page + mtd->writesize, 0xFF, 2);
182 } 193 }
183 for (i = 0; i < 2; i++) { 194 for (i = 0; i < 2; i++) {
184 if (mtd_block_isbad(mtd, off)) { 195 if (mtd_block_isbad(mtd, off)) {
185 printf("Block %d is bad, skipped\n", i); 196 printf("Block %d is bad, skipped\n", i);
186 continue; 197 continue;
187 } 198 }
188 199
189 /* 200 /*
190 * User BCH ECC hardware module for i.MX7 201 * User BCH ECC hardware module for i.MX7
191 */ 202 */
192 if (is_mx7() || is_imx8m()) { 203 if (is_mx7() || is_imx8m()) {
193 u32 off = i * mtd->erasesize; 204 u32 off = i * mtd->erasesize;
194 size_t rwsize = sizeof(*fcb); 205 size_t rwsize = sizeof(*fcb);
195 206
196 printf("Writing %zd bytes to 0x%x: ", rwsize, off); 207 printf("Writing %zd bytes to 0x%x: ", rwsize, off);
197 208
198 /* switch nand BCH to FCB compatible settings */ 209 /* switch nand BCH to FCB compatible settings */
199 mxs_nand_mode_fcb(mtd); 210 mxs_nand_mode_fcb(mtd);
200 ret = nand_write(mtd, off, &rwsize, 211 ret = nand_write(mtd, off, &rwsize,
201 (unsigned char *)fcb); 212 (unsigned char *)fcb);
213
214 dump_fcb_off[i] = off;
215 nand_read(mtd, off, &rwsize,
216 (unsigned char *)(dump_nand_fcb + i));
217
202 mxs_nand_mode_normal(mtd); 218 mxs_nand_mode_normal(mtd);
203 219
204 printf("%s\n", ret ? "ERROR" : "OK"); 220 printf("%s\n", ret ? "ERROR" : "OK");
205 } else if (is_mx6()) { 221 } else if (is_mx6()) {
206 /* raw write */ 222 /* raw write */
207 mtd_oob_ops_t ops = { 223 mtd_oob_ops_t ops = {
208 .datbuf = (u8 *)fcb_raw_page, 224 .datbuf = (u8 *)fcb_raw_page,
209 .oobbuf = ((u8 *)fcb_raw_page) + 225 .oobbuf = ((u8 *)fcb_raw_page) +
210 mtd->writesize, 226 mtd->writesize,
211 .len = mtd->writesize, 227 .len = mtd->writesize,
212 .ooblen = mtd->oobsize, 228 .ooblen = mtd->oobsize,
213 .mode = MTD_OPS_RAW 229 .mode = MTD_OPS_RAW
214 }; 230 };
215 231
216 ret = mtd_write_oob(mtd, mtd->erasesize * i, &ops); 232 ret = mtd_write_oob(mtd, mtd->erasesize * i, &ops);
217 if (ret) 233 if (ret)
218 goto fcb_raw_page_err; 234 goto fcb_raw_page_err;
219 debug("NAND fcb write: 0x%x offset 0x%zx written: %s\n", 235 debug("NAND fcb write: 0x%x offset 0x%zx written: %s\n",
220 mtd->erasesize * i, ops.len, ret ? 236 mtd->erasesize * i, ops.len, ret ?
221 "ERROR" : "OK"); 237 "ERROR" : "OK");
222 } 238 }
223 239
224 ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize, 240 ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize,
225 mtd->writesize, &dummy, (void *)dbbt); 241 mtd->writesize, &dummy, (void *)dbbt);
226 if (ret) 242 if (ret)
227 goto fcb_raw_page_err; 243 goto fcb_raw_page_err;
228 debug("NAND dbbt write: 0x%x offset, 0x%zx bytes written: %s\n", 244 debug("NAND dbbt write: 0x%x offset, 0x%zx bytes written: %s\n",
229 mtd->erasesize * i + mtd->writesize, dummy, 245 mtd->erasesize * i + mtd->writesize, dummy,
230 ret ? "ERROR" : "OK"); 246 ret ? "ERROR" : "OK");
231 247
248 dump_dbbt_off[i] = mtd->erasesize * i + mtd->writesize;
249 size_t rwsize = sizeof(*dbbt);
250
251 nand_read(mtd, dump_dbbt_off[i], &rwsize, (unsigned char *)(dump_nand_dbbt + i));
252
232 /* dbbtpages == 0 if no bad blocks */ 253 /* dbbtpages == 0 if no bad blocks */
233 if (dbbt->dbbtpages > 0) { 254 if (dbbt->dbbtpages > 0) {
234 loff_t to = (mtd->erasesize * i + mtd->writesize * 5); 255 loff_t to = (mtd->erasesize * i + mtd->writesize * 5);
235 256
236 ret = mtd_write(mtd, to, mtd->writesize, &dummy, 257 ret = mtd_write(mtd, to, mtd->writesize, &dummy,
237 dbbt_data_page); 258 dbbt_data_page);
238 if (ret) 259 if (ret)
239 goto fcb_raw_page_err; 260 goto fcb_raw_page_err;
240 } 261 }
241 } 262 }
242 263
243 fcb_raw_page_err: 264 fcb_raw_page_err:
244 if (is_mx6()) 265 if (is_mx6())
245 kfree(fcb_raw_page); 266 kfree(fcb_raw_page);
246 267
247 return ret; 268 return ret;
248 } 269 }
249 270
250 static int nandbcb_update(struct mtd_info *mtd, loff_t off, size_t size, 271 static int nandbcb_update(struct mtd_info *mtd, loff_t off, size_t size,
251 size_t maxsize, const u_char *buf) 272 size_t maxsize, const u_char *buf)
252 { 273 {
253 nand_erase_options_t opts; 274 nand_erase_options_t opts;
254 struct fcb_block *fcb; 275 struct fcb_block *fcb;
255 struct dbbt_block *dbbt; 276 struct dbbt_block *dbbt;
256 loff_t fw1_off; 277 loff_t fw1_off;
257 void *fwbuf, *dbbt_page, *dbbt_data_page; 278 void *fwbuf, *dbbt_page, *dbbt_data_page;
258 u32 fw1_start, fw1_pages; 279 u32 fw1_start, fw1_pages;
259 int nr_blks, nr_blks_fcb, fw1_blk; 280 int nr_blks, nr_blks_fcb, fw1_blk;
260 size_t fwsize; 281 size_t fwsize;
261 int ret; 282 int ret;
262 size_t extra_fwsize; 283 size_t extra_fwsize;
263 void *extra_fwbuf; 284 void *extra_fwbuf;
264 loff_t extra_fw1_off; 285 loff_t extra_fw1_off;
265 286
266 /* erase */ 287 /* erase */
267 memset(&opts, 0, sizeof(opts)); 288 memset(&opts, 0, sizeof(opts));
268 opts.offset = off; 289 opts.offset = off;
269 opts.length = maxsize - 1; 290 opts.length = maxsize - 1;
270 ret = nand_erase_opts(mtd, &opts); 291 ret = nand_erase_opts(mtd, &opts);
271 if (ret) { 292 if (ret) {
272 printf("%s: erase failed (ret = %d)\n", __func__, ret); 293 printf("%s: erase failed (ret = %d)\n", __func__, ret);
273 return ret; 294 return ret;
274 } 295 }
275 296
276 /* 297 /*
277 * Reference documentation from i.MX6DQRM section 8.5.2.2 298 * Reference documentation from i.MX6DQRM section 8.5.2.2
278 * 299 *
279 * Nand Boot Control Block(BCB) contains two data structures, 300 * Nand Boot Control Block(BCB) contains two data structures,
280 * - Firmware Configuration Block(FCB) 301 * - Firmware Configuration Block(FCB)
281 * - Discovered Bad Block Table(DBBT) 302 * - Discovered Bad Block Table(DBBT)
282 * 303 *
283 * FCB contains, 304 * FCB contains,
284 * - nand timings 305 * - nand timings
285 * - DBBT search page address, 306 * - DBBT search page address,
286 * - start page address of primary firmware 307 * - start page address of primary firmware
287 * - start page address of secondary firmware 308 * - start page address of secondary firmware
288 * 309 *
289 * setup fcb: 310 * setup fcb:
290 * - number of blocks = mtd partition size / mtd erasesize 311 * - number of blocks = mtd partition size / mtd erasesize
291 * - two firmware blocks, primary and secondary 312 * - two firmware blocks, primary and secondary
292 * - first 4 block for FCB/DBBT 313 * - first 4 block for FCB/DBBT
293 * - rest split in half for primary and secondary firmware 314 * - rest split in half for primary and secondary firmware
294 * - same firmware will write two times 315 * - same firmware will write two times
295 */ 316 */
296 nr_blks_fcb = 2; 317 nr_blks_fcb = BOOT_SEARCH_COUNT;
297 nr_blks = maxsize / mtd->erasesize; 318 nr_blks = maxsize / mtd->erasesize;
298 fw1_blk = nr_blks_fcb; 319 fw1_blk = nr_blks_fcb;
299 320
300 /* write fw */ 321 /* write fw */
301 fwbuf = NULL; 322 fwbuf = NULL;
302 if (is_mx6() || is_mx7()) { 323 if (is_mx6() || is_mx7()) {
303 fwsize = ALIGN(size + FLASH_OFFSET_STANDARD + mtd->writesize, 324 fwsize = ALIGN(size + FLASH_OFFSET_STANDARD + mtd->writesize,
304 mtd->writesize); 325 mtd->writesize);
305 fwbuf = kzalloc(fwsize, GFP_KERNEL); 326 fwbuf = kzalloc(fwsize, GFP_KERNEL);
306 if (!fwbuf) { 327 if (!fwbuf) {
307 debug("failed to allocate fwbuf\n"); 328 debug("failed to allocate fwbuf\n");
308 ret = -ENOMEM; 329 ret = -ENOMEM;
309 goto err; 330 goto err;
310 } 331 }
311 332
312 memcpy(fwbuf + FLASH_OFFSET_STANDARD, buf, size); 333 memcpy(fwbuf + FLASH_OFFSET_STANDARD, buf, size);
313 fw1_off = fw1_blk * mtd->erasesize; 334 fw1_off = fw1_blk * mtd->erasesize;
314 ret = nand_write_skip_bad(mtd, fw1_off, &fwsize, NULL, maxsize, 335 ret = nand_write_skip_bad(mtd, fw1_off, &fwsize, NULL, maxsize,
315 (u_char *)fwbuf, WITH_WR_VERIFY); 336 (u_char *)fwbuf, WITH_WR_VERIFY);
316 printf("NAND fw write: 0x%llx offset, 0x%zx bytes written: %s\n", 337 printf("NAND fw write: 0x%llx offset, 0x%zx bytes written: %s\n",
317 fw1_off, fwsize, ret ? "ERROR" : "OK"); 338 fw1_off, fwsize, ret ? "ERROR" : "OK");
318 if (ret) 339 if (ret)
319 goto fwbuf_err; 340 goto fwbuf_err;
320 } else if (is_imx8m()) { 341 } else if (is_imx8m()) {
321 fwsize = ALIGN(IMX8MQ_SPL_SZ + FLASH_OFFSET_STANDARD + mtd->writesize, mtd->writesize); 342 fwsize = ALIGN(IMX8MQ_SPL_SZ + FLASH_OFFSET_STANDARD + mtd->writesize, mtd->writesize);
322 fwbuf = kzalloc(fwsize, GFP_KERNEL); 343 fwbuf = kzalloc(fwsize, GFP_KERNEL);
323 if (!fwbuf) { 344 if (!fwbuf) {
324 debug("failed to allocate fwbuf\n"); 345 debug("failed to allocate fwbuf\n");
325 ret = -ENOMEM; 346 ret = -ENOMEM;
326 goto err; 347 goto err;
327 } 348 }
328 349
329 memcpy(fwbuf + FLASH_OFFSET_STANDARD, buf, IMX8MQ_SPL_SZ); 350 memcpy(fwbuf + FLASH_OFFSET_STANDARD, buf, IMX8MQ_SPL_SZ);
330 fw1_off = fw1_blk * mtd->erasesize; 351 fw1_off = fw1_blk * mtd->erasesize;
331 ret = nand_write_skip_bad(mtd, fw1_off, &fwsize, NULL, maxsize, 352 ret = nand_write_skip_bad(mtd, fw1_off, &fwsize, NULL, maxsize,
332 (u_char *)fwbuf, WITH_WR_VERIFY); 353 (u_char *)fwbuf, WITH_WR_VERIFY);
333 printf("NAND fw write: 0x%llx offset, 0x%zx bytes written: %s\n", 354 printf("NAND fw write: 0x%llx offset, 0x%zx bytes written: %s\n",
334 fw1_off, fwsize, ret ? "ERROR" : "OK"); 355 fw1_off, fwsize, ret ? "ERROR" : "OK");
335 if (ret) 356 if (ret)
336 goto fwbuf_err; 357 goto fwbuf_err;
337 358
338 extra_fwsize = ALIGN(IMX8MQ_SPL_SZ + mtd->writesize, mtd->writesize); 359 extra_fwsize = ALIGN(IMX8MQ_SPL_SZ + mtd->writesize, mtd->writesize);
339 extra_fwbuf = kzalloc(extra_fwsize, GFP_KERNEL); 360 extra_fwbuf = kzalloc(extra_fwsize, GFP_KERNEL);
340 extra_fw1_off = fw1_off + mtd->erasesize * ((IMX8MQ_SPL_SZ + mtd->erasesize - 1) / mtd->erasesize); 361 extra_fw1_off = fw1_off + mtd->erasesize * ((IMX8MQ_SPL_SZ + mtd->erasesize - 1) / mtd->erasesize);
341 if (!extra_fwbuf) { 362 if (!extra_fwbuf) {
342 debug("failed to allocate fwbuf\n"); 363 debug("failed to allocate fwbuf\n");
343 ret = -ENOMEM; 364 ret = -ENOMEM;
344 goto fwbuf_err; 365 goto fwbuf_err;
345 } 366 }
346 367
347 memcpy(extra_fwbuf, buf + IMX8MQ_HDMI_FW_SZ, IMX8MQ_SPL_SZ); 368 memcpy(extra_fwbuf, buf + IMX8MQ_HDMI_FW_SZ, IMX8MQ_SPL_SZ);
348 ret = nand_write_skip_bad(mtd, extra_fw1_off, &extra_fwsize, NULL, maxsize, 369 ret = nand_write_skip_bad(mtd, extra_fw1_off, &extra_fwsize, NULL, maxsize,
349 (u_char *)extra_fwbuf, WITH_WR_VERIFY); 370 (u_char *)extra_fwbuf, WITH_WR_VERIFY);
350 printf("NAND extra_fw write: 0x%llx offset, 0x%zx bytes written: %s\n", 371 printf("NAND extra_fw write: 0x%llx offset, 0x%zx bytes written: %s\n",
351 extra_fw1_off, extra_fwsize, ret ? "ERROR" : "OK"); 372 extra_fw1_off, extra_fwsize, ret ? "ERROR" : "OK");
352 if (ret) { 373 if (ret) {
353 kfree(extra_fwbuf); 374 kfree(extra_fwbuf);
354 goto fwbuf_err; 375 goto fwbuf_err;
355 } 376 }
356 } 377 }
357 378
358 /* fill fcb */ 379 /* fill fcb */
359 fcb = kzalloc(sizeof(*fcb), GFP_KERNEL); 380 fcb = kzalloc(sizeof(*fcb), GFP_KERNEL);
360 if (!fcb) { 381 if (!fcb) {
361 debug("failed to allocate fcb\n"); 382 debug("failed to allocate fcb\n");
362 ret = -ENOMEM; 383 ret = -ENOMEM;
363 goto fwbuf_err; 384 goto fwbuf_err;
364 } 385 }
365 386
366 fw1_start = (fw1_blk * mtd->erasesize) / mtd->writesize; 387 fw1_start = (fw1_blk * mtd->erasesize) / mtd->writesize;
367 fw1_pages = size / mtd->writesize + 1; 388 fw1_pages = size / mtd->writesize + 1;
368 if (is_imx8m()) 389 if (is_imx8m())
369 fw1_pages = (IMX8MQ_SPL_SZ + (mtd->writesize - 1)) / mtd->writesize; 390 fw1_pages = (IMX8MQ_SPL_SZ + (mtd->writesize - 1)) / mtd->writesize;
370 fill_fcb(fcb, mtd, fw1_start, 0, fw1_pages); 391 fill_fcb(fcb, mtd, fw1_start, 0, fw1_pages);
371 392
393 dump_fill_fcb = *fcb;
394
372 /* fill dbbt */ 395 /* fill dbbt */
373 dbbt_page = kzalloc(mtd->writesize, GFP_KERNEL); 396 dbbt_page = kzalloc(mtd->writesize, GFP_KERNEL);
374 if (!dbbt_page) { 397 if (!dbbt_page) {
375 debug("failed to allocate dbbt_page\n"); 398 debug("failed to allocate dbbt_page\n");
376 ret = -ENOMEM; 399 ret = -ENOMEM;
377 goto fcb_err; 400 goto fcb_err;
378 } 401 }
379 402
380 dbbt_data_page = kzalloc(mtd->writesize, GFP_KERNEL); 403 dbbt_data_page = kzalloc(mtd->writesize, GFP_KERNEL);
381 if (!dbbt_data_page) { 404 if (!dbbt_data_page) {
382 debug("failed to allocate dbbt_data_page\n"); 405 debug("failed to allocate dbbt_data_page\n");
383 ret = -ENOMEM; 406 ret = -ENOMEM;
384 goto dbbt_page_err; 407 goto dbbt_page_err;
385 } 408 }
386 409
387 dbbt = dbbt_page; 410 dbbt = dbbt_page;
388 dbbt->checksum = 0; 411 dbbt->checksum = 0;
389 dbbt->fingerprint = DBBT_FINGERPRINT2; 412 dbbt->fingerprint = DBBT_FINGERPRINT2;
390 dbbt->version = DBBT_VERSION_1; 413 dbbt->version = DBBT_VERSION_1;
391 ret = dbbt_fill_data(mtd, dbbt_data_page, nr_blks); 414 ret = dbbt_fill_data(mtd, dbbt_data_page, nr_blks);
392 if (ret < 0) 415 if (ret < 0)
393 goto dbbt_data_page_err; 416 goto dbbt_data_page_err;
394 else if (ret > 0) 417 else if (ret > 0)
395 dbbt->dbbtpages = 1; 418 dbbt->dbbtpages = 1;
396 419
420 dump_fill_dbbt = *dbbt;
421
397 /* write fcb and dbbt to nand */ 422 /* write fcb and dbbt to nand */
398 ret = write_fcb_dbbt(mtd, fcb, dbbt, dbbt_data_page, off); 423 ret = write_fcb_dbbt_and_readback(mtd, fcb, dbbt, dbbt_data_page, off);
399 if (ret < 0) 424 if (ret < 0)
400 printf("failed to write FCB/DBBT\n"); 425 printf("failed to write FCB/DBBT\n");
401 426
402 dbbt_data_page_err: 427 dbbt_data_page_err:
403 kfree(dbbt_data_page); 428 kfree(dbbt_data_page);
404 dbbt_page_err: 429 dbbt_page_err:
405 kfree(dbbt_page); 430 kfree(dbbt_page);
406 fcb_err: 431 fcb_err:
407 kfree(fcb); 432 kfree(fcb);
408 fwbuf_err: 433 fwbuf_err:
409 kfree(fwbuf); 434 kfree(fwbuf);
410 err: 435 err:
411 return ret; 436 return ret;
412 } 437 }
413 438
414 static int do_nandbcb_bcbonly(int argc, char * const argv[]) 439 static int do_nandbcb_bcbonly(int argc, char * const argv[])
415 { 440 {
416 struct fcb_block *fcb; 441 struct fcb_block *fcb;
417 struct dbbt_block *dbbt; 442 struct dbbt_block *dbbt;
418 u32 fw_len, fw1_off, fw2_off; 443 u32 fw_len, fw1_off, fw2_off;
419 struct mtd_info *mtd; 444 struct mtd_info *mtd;
420 void *dbbt_page, *dbbt_data_page; 445 void *dbbt_page, *dbbt_data_page;
421 int dev, ret; 446 int dev, ret;
422 447
423 dev = nand_curr_device; 448 dev = nand_curr_device;
424 if ((dev < 0) || (dev >= CONFIG_SYS_MAX_NAND_DEVICE) || 449 if ((dev < 0) || (dev >= CONFIG_SYS_MAX_NAND_DEVICE) ||
425 (!get_nand_dev_by_index(dev))) { 450 (!get_nand_dev_by_index(dev))) {
426 puts("No devices available\n"); 451 puts("No devices available\n");
427 return CMD_RET_FAILURE; 452 return CMD_RET_FAILURE;
428 } 453 }
429 454
430 mtd = get_nand_dev_by_index(dev); 455 mtd = get_nand_dev_by_index(dev);
431 456
432 if (argc < 3) 457 if (argc < 3)
433 return CMD_RET_FAILURE; 458 return CMD_RET_FAILURE;
434 459
435 fw_len = simple_strtoul(argv[1], NULL, 16); 460 fw_len = simple_strtoul(argv[1], NULL, 16);
436 fw1_off = simple_strtoul(argv[2], NULL, 16); 461 fw1_off = simple_strtoul(argv[2], NULL, 16);
437 462
438 if (argc > 3) 463 if (argc > 3)
439 fw2_off = simple_strtoul(argv[3], NULL, 16); 464 fw2_off = simple_strtoul(argv[3], NULL, 16);
440 else 465 else
441 fw2_off = fw1_off; 466 fw2_off = fw1_off;
442 467
443 /* fill fcb */ 468 /* fill fcb */
444 fcb = kzalloc(sizeof(*fcb), GFP_KERNEL); 469 fcb = kzalloc(sizeof(*fcb), GFP_KERNEL);
445 if (!fcb) { 470 if (!fcb) {
446 debug("failed to allocate fcb\n"); 471 debug("failed to allocate fcb\n");
447 ret = -ENOMEM; 472 ret = -ENOMEM;
448 return CMD_RET_FAILURE; 473 return CMD_RET_FAILURE;
449 } 474 }
450 475
451 fill_fcb(fcb, mtd, fw1_off / mtd->writesize, 476 fill_fcb(fcb, mtd, fw1_off / mtd->writesize,
452 fw2_off / mtd->writesize, fw_len / mtd->writesize); 477 fw2_off / mtd->writesize, fw_len / mtd->writesize);
453 478
454 /* fill dbbt */ 479 /* fill dbbt */
455 dbbt_page = kzalloc(mtd->writesize, GFP_KERNEL); 480 dbbt_page = kzalloc(mtd->writesize, GFP_KERNEL);
456 if (!dbbt_page) { 481 if (!dbbt_page) {
457 debug("failed to allocate dbbt_page\n"); 482 debug("failed to allocate dbbt_page\n");
458 ret = -ENOMEM; 483 ret = -ENOMEM;
459 goto fcb_err; 484 goto fcb_err;
460 } 485 }
461 486
462 dbbt_data_page = kzalloc(mtd->writesize, GFP_KERNEL); 487 dbbt_data_page = kzalloc(mtd->writesize, GFP_KERNEL);
463 if (!dbbt_data_page) { 488 if (!dbbt_data_page) {
464 debug("failed to allocate dbbt_data_page\n"); 489 debug("failed to allocate dbbt_data_page\n");
465 ret = -ENOMEM; 490 ret = -ENOMEM;
466 goto dbbt_page_err; 491 goto dbbt_page_err;
467 } 492 }
468 493
469 dbbt = dbbt_page; 494 dbbt = dbbt_page;
470 dbbt->checksum = 0; 495 dbbt->checksum = 0;
471 dbbt->fingerprint = DBBT_FINGERPRINT2; 496 dbbt->fingerprint = DBBT_FINGERPRINT2;
472 dbbt->version = DBBT_VERSION_1; 497 dbbt->version = DBBT_VERSION_1;
473 ret = dbbt_fill_data(mtd, dbbt_data_page, 0); 498 ret = dbbt_fill_data(mtd, dbbt_data_page, 0);
474 if (ret < 0) 499 if (ret < 0)
475 goto dbbt_data_page_err; 500 goto dbbt_data_page_err;
476 else if (ret > 0) 501 else if (ret > 0)
477 dbbt->dbbtpages = 1; 502 dbbt->dbbtpages = 1;
478 503
479 /* write fcb and dbbt to nand */ 504 /* write fcb and dbbt to nand */
480 ret = write_fcb_dbbt(mtd, fcb, dbbt, dbbt_data_page, 0); 505 ret = write_fcb_dbbt_and_readback(mtd, fcb, dbbt, dbbt_data_page, 0);
481 dbbt_data_page_err: 506 dbbt_data_page_err:
482 kfree(dbbt_data_page); 507 kfree(dbbt_data_page);
483 dbbt_page_err: 508 dbbt_page_err:
484 kfree(dbbt_page); 509 kfree(dbbt_page);
485 fcb_err: 510 fcb_err:
486 kfree(fcb); 511 kfree(fcb);
487 512
488 if (ret < 0) { 513 if (ret < 0) {
489 printf("failed to write FCB/DBBT\n"); 514 printf("failed to write FCB/DBBT\n");
490 return CMD_RET_FAILURE; 515 return CMD_RET_FAILURE;
491 } 516 }
492 517
493 return CMD_RET_SUCCESS; 518 return CMD_RET_SUCCESS;
494 } 519 }
495 520
521 /* dump data which is planned to be encoded and written to NAND chip */
522 void mtd_cfg_dump(void)
523 {
524 u64 blocks;
525
526 printf("MTD CONFIG:\n");
527 printf(" %s = %d\n", "data_setup_time", dump_fill_fcb.datasetup);
528 printf(" %s = %d\n", "data_hold_time", dump_fill_fcb.datahold);
529 printf(" %s = %d\n", "address_setup_time", dump_fill_fcb.addr_setup);
530 printf(" %s = %d\n", "data_sample_time", dump_fill_fcb.dsample_time);
531
532 printf("NFC geometry :\n");
533 printf("\tECC Strength : %d\n", dump_mtd->ecc_strength);
534 printf("\tPage Size in Bytes : %d\n", dump_fill_fcb.oob_pagesize);
535 printf("\tMetadata size : %d\n", dump_fill_fcb.meta_size);
536 printf("\tECC Chunk Size in byte : %d\n", dump_fill_fcb.ecc_size);
537 printf("\tECC Chunk count : %d\n", dump_fill_fcb.nr_blocks + 1);
538 printf("\tBlock Mark Byte Offset : %d\n", dump_fill_fcb.bb_byte);
539 printf("\tBlock Mark Bit Offset : %d\n", dump_fill_fcb.bb_start_bit);
540 printf("====================================================\n");
541
542 printf("mtd: partition #0\n");
543 printf(" %s = %d\n", "type", dump_mtd->type);
544 printf(" %s = %d\n", "flags", dump_mtd->flags);
545 printf(" %s = %llu\n", "size", dump_nandboot_size);
546 printf(" %s = %d\n", "erasesize", dump_mtd->erasesize);
547 printf(" %s = %d\n", "writesize", dump_mtd->writesize);
548 printf(" %s = %d\n", "oobsize", dump_mtd->oobsize);
549 blocks = dump_nandboot_size;
550 do_div(blocks, dump_mtd->erasesize);
551 printf(" %s = %llu\n", "blocks", blocks);
552 }
553
554 /* dump data which is read from NAND chip */
555 void mtd_dump_structure(int i)
556 {
557 #define P1(x) printf(" %s = 0x%08x\n", #x, dump_nand_fcb[i].x)
558 printf("FCB %d:\n", i);
559 P1(checksum);
560 P1(fingerprint);
561 P1(version);
562 #undef P1
563 #define P1(x) printf(" %s = %d\n", #x, dump_nand_fcb[i].x)
564 P1(datasetup);
565 P1(datahold);
566 P1(addr_setup);
567 P1(dsample_time);
568 P1(pagesize);
569 P1(oob_pagesize);
570 P1(sectors);
571 P1(nr_nand);
572 P1(nr_die);
573 P1(celltype);
574 P1(ecc_type);
575 P1(ecc_nr);
576 P1(ecc_size);
577 P1(ecc_level);
578 P1(meta_size);
579 P1(nr_blocks);
580 P1(ecc_type_sdk);
581 P1(ecc_nr_sdk);
582 P1(ecc_size_sdk);
583 P1(ecc_level_sdk);
584 P1(nr_blocks_sdk);
585 P1(meta_size_sdk);
586 P1(erase_th);
587 P1(bootpatch);
588 P1(patch_size);
589 P1(fw1_start);
590 P1(fw2_start);
591 P1(fw1_pages);
592 P1(fw2_pages);
593 P1(dbbt_start);
594 P1(bb_byte);
595 P1(bb_start_bit);
596 P1(phy_offset);
597 P1(bchtype);
598 P1(readlatency);
599 P1(predelay);
600 P1(cedelay);
601 P1(postdelay);
602 P1(cmdaddpause);
603 P1(datapause);
604 P1(tmspeed);
605 P1(busytimeout);
606 P1(disbbm);
607 P1(spare_offset);
608 P1(onfi_sync_enable);
609 P1(onfi_sync_speed);
610 P1(onfi_sync_nand_data);
611 P1(disbbm_search);
612 P1(disbbm_search_limit);
613 P1(read_retry_enable);
614 #undef P1
615 #define P1(x) printf(" %s = 0x%08x\n", #x, dump_nand_dbbt[i].x)
616 printf("DBBT %d:\n", i);
617 P1(checksum);
618 P1(fingerprint);
619 P1(version);
620 #undef P1
621 #define P1(x) printf(" %s = %d\n", #x, dump_nand_dbbt[i].x)
622 P1(numberbb);
623 #undef P1
624
625 printf("Firmware: image #0 @ 0x%x size 0x%x - available 0x%llx\n",
626 dump_nand_fcb[i].fw1_start * dump_nand_fcb[i].pagesize,
627 dump_nand_fcb[i].fw1_pages * dump_nand_fcb[i].pagesize,
628 dump_nandboot_size - dump_nand_fcb[i].fw1_start * dump_nand_fcb[i].pagesize);
629 if (is_imx8m())
630 printf("Extra Firmware: image #0 @ 0x%x size 0x%x - available 0x%llx\n",
631 dump_nand_fcb[i].fw1_start * dump_nand_fcb[i].pagesize + dump_mtd->erasesize * ((IMX8MQ_SPL_SZ + dump_mtd->erasesize - 1) / dump_mtd->erasesize),
632 dump_nand_fcb[i].fw1_pages * dump_nand_fcb[i].pagesize,
633 dump_nandboot_size - (dump_nand_fcb[i].fw1_start * dump_nand_fcb[i].pagesize + dump_mtd->erasesize * ((IMX8MQ_SPL_SZ + dump_mtd->erasesize - 1) / dump_mtd->erasesize)));
634 }
635
636 static int do_nandbcb_dump(int argc, char * const argv[])
637 {
638 int num;
639 int stride;
640 int search_area_sz;
641 bool bab_block_table[BOOT_SEARCH_COUNT];
642 int bab_block_flag;
643
644 if (argc != 2)
645 return CMD_RET_USAGE;
646
647 switch (argv[1][0]) {
648 case '0':
649 num = 0;
650 break;
651 case '1':
652 num = 1;
653 break;
654 default:
655 return CMD_RET_USAGE;
656 }
657
658 /* dump data which is planned to be encoded and written to NAND chip */
659 mtd_cfg_dump();
660
661 stride = dump_mtd->erasesize;
662 search_area_sz = BOOT_SEARCH_COUNT * stride;
663 printf("stride: %x, search_area_sz: %x\n", stride, search_area_sz);
664
665 bab_block_flag = 0;
666 for (int i = 0; i < BOOT_SEARCH_COUNT; i++) {
667 if (mtd_block_isbad(dump_mtd, (loff_t)(dump_mtd->erasesize * i))) {
668 bab_block_table[i] = 1;
669 bab_block_flag = 1;
670 continue;
671 }
672 bab_block_table[i] = 0;
673 if (memcpy(dump_nand_fcb + i, &dump_fill_fcb, sizeof(dump_fill_fcb)) != 0) {
674 printf("mtd: found FCB%d candidate version %08x @%d:0x%x\n",
675 i, dump_nand_fcb[i].version, i, dump_fcb_off[i]);
676 } else {
677 printf("mtd: FCB%d not found\n", i);
678 }
679 }
680
681 for (int i = 0; i < BOOT_SEARCH_COUNT; i++) {
682 if (mtd_block_isbad(dump_mtd, (loff_t)(dump_mtd->erasesize * i)))
683 continue;
684
685 if (memcpy(dump_nand_dbbt + i, &dump_fill_dbbt, sizeof(dump_fill_dbbt)) != 0) {
686 printf("mtd: DBBT%d found\n", i);
687 printf("mtd: Valid DBBT%d found @%d:0x%x\n", i, i, dump_dbbt_off[i]);
688
689 } else {
690 printf("mtd: DBBT%d not found\n", i);
691 }
692 }
693 if (bab_block_flag == 0)
694 printf("no bad block found, dbbt: %08x\n", dump_fill_dbbt.fingerprint);
695 else
696 for (int i = 0; i < BOOT_SEARCH_COUNT; i++)
697 if (bab_block_table[i] == 1)
698 printf("mtd: bad block @ 0x%llx\n", (loff_t)(dump_mtd->erasesize * i));
699
700 /* dump data which is read from NAND chip */
701 if (num > (BOOT_SEARCH_COUNT - 1))
702 return CMD_RET_USAGE;
703
704 if (bab_block_table[num] == 1) {
705 printf("mtd: bad block @ 0x%llx (FCB - DBBT)\n", (loff_t)(dump_mtd->erasesize * num));
706 return CMD_RET_USAGE;
707 }
708
709 mtd_dump_structure(num);
710
711 return 0;
712 }
713
496 static int do_nandbcb_update(int argc, char * const argv[]) 714 static int do_nandbcb_update(int argc, char * const argv[])
497 { 715 {
498 struct mtd_info *mtd; 716 struct mtd_info *mtd;
499 loff_t addr, offset, size, maxsize; 717 loff_t addr, offset, size, maxsize;
500 char *endp; 718 char *endp;
501 u_char *buf; 719 u_char *buf;
502 int dev; 720 int dev;
503 int ret; 721 int ret;
504 722
505 if (argc != 4) 723 if (argc != 4)
506 return CMD_RET_USAGE; 724 return CMD_RET_USAGE;
507 725
508 dev = nand_curr_device; 726 dev = nand_curr_device;
509 if (dev < 0) { 727 if (dev < 0) {
510 printf("failed to get nand_curr_device, run nand device\n"); 728 printf("failed to get nand_curr_device, run nand device\n");
511 return CMD_RET_FAILURE; 729 return CMD_RET_FAILURE;
512 } 730 }
513 731
514 addr = simple_strtoul(argv[1], &endp, 16); 732 addr = simple_strtoul(argv[1], &endp, 16);
515 if (*argv[1] == 0 || *endp != 0) 733 if (*argv[1] == 0 || *endp != 0)
516 return CMD_RET_FAILURE; 734 return CMD_RET_FAILURE;
517 735
518 mtd = get_nand_dev_by_index(dev); 736 mtd = get_nand_dev_by_index(dev);
519 if (mtd_arg_off_size(argc - 2, argv + 2, &dev, &offset, &size, 737 if (mtd_arg_off_size(argc - 2, argv + 2, &dev, &offset, &size,
520 &maxsize, MTD_DEV_TYPE_NAND, mtd->size)) 738 &maxsize, MTD_DEV_TYPE_NAND, mtd->size))
521 return CMD_RET_FAILURE; 739 return CMD_RET_FAILURE;
522 740
741 /* dump_mtd and dump_nandboot_size are used for "nandbcb dump [-v]" */
742 dump_mtd = mtd;
743 dump_nandboot_size = maxsize;
744
523 buf = map_physmem(addr, size, MAP_WRBACK); 745 buf = map_physmem(addr, size, MAP_WRBACK);
524 if (!buf) { 746 if (!buf) {
525 puts("failed to map physical memory\n"); 747 puts("failed to map physical memory\n");
526 return CMD_RET_FAILURE; 748 return CMD_RET_FAILURE;
527 } 749 }
528 750
529 ret = nandbcb_update(mtd, offset, size, maxsize, buf); 751 ret = nandbcb_update(mtd, offset, size, maxsize, buf);
530 752
531 return ret == 0 ? CMD_RET_SUCCESS : CMD_RET_FAILURE; 753 return ret == 0 ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
532 } 754 }
533 755
534 static int do_nandbcb(cmd_tbl_t *cmdtp, int flag, int argc, 756 static int do_nandbcb(cmd_tbl_t *cmdtp, int flag, int argc,
535 char * const argv[]) 757 char * const argv[])
536 { 758 {
537 const char *cmd; 759 const char *cmd;
538 int ret = 0; 760 int ret = 0;
539 761
540 if (argc < 5) 762 if (argc < 3)
541 goto usage; 763 goto usage;
542 764
543 cmd = argv[1]; 765 cmd = argv[1];
544 --argc; 766 --argc;
545 ++argv; 767 ++argv;
546 768
547 if (strcmp(cmd, "update") == 0) { 769 if (strcmp(cmd, "update") == 0) {
548 ret = do_nandbcb_update(argc, argv); 770 ret = do_nandbcb_update(argc, argv);
549 goto done; 771 goto done;
550 } 772 }
551 773
774 if (strcmp(cmd, "dump") == 0) {
775 ret = do_nandbcb_dump(argc, argv);
776 goto done;
777 }
778
552 if (strcmp(cmd, "bcbonly") == 0) { 779 if (strcmp(cmd, "bcbonly") == 0) {
553 ret = do_nandbcb_bcbonly(argc, argv); 780 ret = do_nandbcb_bcbonly(argc, argv);
554 goto done; 781 goto done;
555 } 782 }
556 783
557 done: 784 done:
558 if (ret != -1) 785 if (ret != -1)
559 return ret; 786 return ret;
560 usage: 787 usage:
561 return CMD_RET_USAGE; 788 return CMD_RET_USAGE;
562 } 789 }
563 790
564 static char nandbcb_help_text[] = 791 static char nandbcb_help_text[] =
565 "update addr off|partition len - update 'len' bytes starting at\n" 792 "update addr off|partition len - update 'len' bytes starting at\n"
566 " 'off|part' to memory address 'addr', skipping bad blocks\n" 793 " 'off|part' to memory address 'addr', skipping bad blocks\n"
567 "bcbonly fw-size fw1-off [fw2-off] - write only BCB (FCB and DBBT)\n" 794 "bcbonly fw-size fw1-off [fw2-off] - write only BCB (FCB and DBBT)\n"
568 " where `fw-size` is fw sizes in bytes, `fw1-off` and\n" 795 " where `fw-size` is fw sizes in bytes, `fw1-off` and\n"
569 " and `fw2-off` - firmware offsets "; 796 " and `fw2-off` - firmware offsets \n"
797 "nandbcb dump num - verify/dump boot structures\n"
798 " 'num' can be set to 0 and 1";
570 799
571 U_BOOT_CMD(nandbcb, 5, 1, do_nandbcb, 800 U_BOOT_CMD(nandbcb, 5, 1, do_nandbcb,
572 "i.MX6 Nand BCB", 801 "i.MX6 Nand BCB",
573 nandbcb_help_text 802 nandbcb_help_text
574 ); 803 );
575 804