Merge tag 'u-boot-rockchip-20190729' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / arch / arm / mach-imx / cmd_nandbcb.c
1 /*
2  * i.MX6 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  * SPDX-License-Identifier:     GPL-2.0+
10  */
11
12 #include <common.h>
13 #include <nand.h>
14
15 #include <asm/io.h>
16 #include <jffs2/jffs2.h>
17 #include <linux/mtd/mtd.h>
18
19 #include <asm/mach-imx/imx-nandbcb.h>
20 #include <asm/mach-imx/imximage.cfg>
21 #include <mxs_nand.h>
22 #include <linux/mtd/mtd.h>
23 #include <nand.h>
24
25 #define BF_VAL(v, bf)           (((v) & bf##_MASK) >> bf##_OFFSET)
26 #define GETBIT(v, n)            (((v) >> (n)) & 0x1)
27
28 static u8 calculate_parity_13_8(u8 d)
29 {
30         u8 p = 0;
31
32         p |= (GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 3) ^ GETBIT(d, 2)) << 0;
33         p |= (GETBIT(d, 7) ^ GETBIT(d, 5) ^ GETBIT(d, 4) ^ GETBIT(d, 2) ^
34               GETBIT(d, 1)) << 1;
35         p |= (GETBIT(d, 7) ^ GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 1) ^
36               GETBIT(d, 0)) << 2;
37         p |= (GETBIT(d, 7) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 0)) << 3;
38         p |= (GETBIT(d, 6) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 2) ^
39               GETBIT(d, 1) ^ GETBIT(d, 0)) << 4;
40
41         return p;
42 }
43
44 static void encode_hamming_13_8(void *_src, void *_ecc, size_t size)
45 {
46         int i;
47         u8 *src = _src;
48         u8 *ecc = _ecc;
49
50         for (i = 0; i < size; i++)
51                 ecc[i] = calculate_parity_13_8(src[i]);
52 }
53
54 static u32 calc_chksum(void *buf, size_t size)
55 {
56         u32 chksum = 0;
57         u8 *bp = buf;
58         size_t i;
59
60         for (i = 0; i < size; i++)
61                 chksum += bp[i];
62
63         return ~chksum;
64 }
65
66 static void fill_fcb(struct fcb_block *fcb, struct mtd_info *mtd)
67 {
68         struct nand_chip *chip = mtd_to_nand(mtd);
69         struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
70
71         fcb->fingerprint = FCB_FINGERPRINT;
72         fcb->version = FCB_VERSION_1;
73         fcb->pagesize = mtd->writesize;
74         fcb->oob_pagesize = mtd->writesize + mtd->oobsize;
75         fcb->sectors = mtd->erasesize / mtd->writesize;
76
77         /* Divide ECC strength by two and save the value into FCB structure. */
78         fcb->ecc_level = nand_info->bch_geometry.ecc_strength >> 1;
79
80         fcb->ecc_type = fcb->ecc_level;
81
82         /* Also hardcoded in kobs-ng */
83         fcb->ecc_nr = 0x00000200;
84         fcb->ecc_size = 0x00000200;
85         fcb->datasetup = 80;
86         fcb->datahold = 60;
87         fcb->addr_setup = 25;
88         fcb->dsample_time = 6;
89         fcb->meta_size = 10;
90
91         /* DBBT search area starts at second page on first block */
92         fcb->dbbt_start = 1;
93
94         fcb->bb_byte = nand_info->bch_geometry.block_mark_byte_offset;
95         fcb->bb_start_bit = nand_info->bch_geometry.block_mark_bit_offset;
96
97         fcb->phy_offset = mtd->writesize;
98
99         fcb->nr_blocks = mtd->writesize / fcb->ecc_nr - 1;
100
101         fcb->checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4);
102 }
103
104 static int dbbt_fill_data(struct mtd_info *mtd, void *buf, int num_blocks)
105 {
106         int n, n_bad_blocks = 0;
107         u32 *bb = buf + 0x8;
108         u32 *n_bad_blocksp = buf + 0x4;
109
110         for (n = 0; n < num_blocks; n++) {
111                 loff_t offset = n * mtd->erasesize;
112                         if (mtd_block_isbad(mtd, offset)) {
113                                 n_bad_blocks++;
114                                 *bb = n;
115                                 bb++;
116                 }
117         }
118
119         *n_bad_blocksp = n_bad_blocks;
120
121         return n_bad_blocks;
122 }
123
124 static int nandbcb_update(struct mtd_info *mtd, loff_t off, size_t size,
125                           size_t maxsize, const u_char *buf)
126 {
127         nand_erase_options_t opts;
128         struct fcb_block *fcb;
129         struct dbbt_block *dbbt;
130         loff_t fw1_off;
131         void *fwbuf, *fcb_raw_page, *dbbt_page, *dbbt_data_page;
132         int nr_blks, nr_blks_fcb, fw1_blk;
133         size_t fwsize, dummy;
134         int i, ret;
135
136         /* erase */
137         memset(&opts, 0, sizeof(opts));
138         opts.offset = off;
139         opts.length = maxsize - 1;
140         ret = nand_erase_opts(mtd, &opts);
141         if (ret) {
142                 printf("%s: erase failed (ret = %d)\n", __func__, ret);
143                 return ret;
144         }
145
146         /*
147          * Reference documentation from i.MX6DQRM section 8.5.2.2
148          *
149          * Nand Boot Control Block(BCB) contains two data structures,
150          * - Firmware Configuration Block(FCB)
151          * - Discovered Bad Block Table(DBBT)
152          *
153          * FCB contains,
154          * - nand timings
155          * - DBBT search page address,
156          * - start page address of primary firmware
157          * - start page address of secondary firmware
158          *
159          * setup fcb:
160          * - number of blocks = mtd partition size / mtd erasesize
161          * - two firmware blocks, primary and secondary
162          * - first 4 block for FCB/DBBT
163          * - rest split in half for primary and secondary firmware
164          * - same firmware will write two times
165          */
166         nr_blks_fcb = 2;
167         nr_blks = maxsize / mtd->erasesize;
168         fw1_blk = nr_blks_fcb;
169
170         /* write fw */
171         fwsize = ALIGN(size + FLASH_OFFSET_STANDARD + mtd->writesize,
172                        mtd->writesize);
173         fwbuf = kzalloc(fwsize, GFP_KERNEL);
174         if (!fwbuf) {
175                 debug("failed to allocate fwbuf\n");
176                 ret = -ENOMEM;
177                 goto err;
178         }
179
180         memcpy(fwbuf + FLASH_OFFSET_STANDARD, buf, size);
181         fw1_off = fw1_blk * mtd->erasesize;
182         ret = nand_write_skip_bad(mtd, fw1_off, &fwsize, NULL, maxsize,
183                                   (u_char *)fwbuf, WITH_WR_VERIFY);
184         printf("NAND fw write: 0x%llx offset, 0x%x bytes written: %s\n",
185                fw1_off, fwsize, ret ? "ERROR" : "OK");
186         if (ret)
187                 goto fwbuf_err;
188
189         /* fill fcb */
190         fcb = kzalloc(sizeof(*fcb), GFP_KERNEL);
191         if (!fcb) {
192                 debug("failed to allocate fcb\n");
193                 ret = -ENOMEM;
194                 goto fwbuf_err;
195         }
196
197         fcb->fw1_start = (fw1_blk * mtd->erasesize) / mtd->writesize;
198         fcb->fw1_pages = size / mtd->writesize + 1;
199         fill_fcb(fcb, mtd);
200
201         /* fill dbbt */
202         dbbt_page = kzalloc(mtd->writesize, GFP_KERNEL);
203         if (!dbbt_page) {
204                 debug("failed to allocate dbbt_page\n");
205                 ret = -ENOMEM;
206                 goto fcb_err;
207         }
208
209         dbbt_data_page = kzalloc(mtd->writesize, GFP_KERNEL);
210         if (!dbbt_data_page) {
211                 debug("failed to allocate dbbt_data_page\n");
212                 ret = -ENOMEM;
213                 goto dbbt_page_err;
214         }
215
216         dbbt = dbbt_page;
217         dbbt->checksum = 0;
218         dbbt->fingerprint = DBBT_FINGERPRINT2;
219         dbbt->version = DBBT_VERSION_1;
220         ret = dbbt_fill_data(mtd, dbbt_data_page, nr_blks);
221         if (ret < 0)
222                 goto dbbt_data_page_err;
223         else if (ret > 0)
224                 dbbt->dbbtpages = 1;
225
226         /* write fcb/dbbt */
227         fcb_raw_page = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
228         if (!fcb_raw_page) {
229                 debug("failed to allocate fcb_raw_page\n");
230                 ret = -ENOMEM;
231                 goto dbbt_data_page_err;
232         }
233
234         memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
235         encode_hamming_13_8(fcb_raw_page + 12, fcb_raw_page + 12 + 512, 512);
236         /*
237          * Set the first and second byte of OOB data to 0xFF, not 0x00. These
238          * bytes are used as the Manufacturers Bad Block Marker (MBBM). Since
239          * the FCB is mostly written to the first page in a block, a scan for
240          * factory bad blocks will detect these blocks as bad, e.g. when
241          * function nand_scan_bbt() is executed to build a new bad block table.
242          */
243         memset(fcb_raw_page + mtd->writesize, 0xFF, 2);
244
245         for (i = 0; i < nr_blks_fcb; i++) {
246                 if (mtd_block_isbad(mtd, off)) {
247                         printf("Block %d is bad, skipped\n", i);
248                         continue;
249                 }
250
251                 /* raw write */
252                 mtd_oob_ops_t ops = {
253                         .datbuf = (u8 *)fcb_raw_page,
254                         .oobbuf = ((u8 *)fcb_raw_page) + mtd->writesize,
255                         .len = mtd->writesize,
256                         .ooblen = mtd->oobsize,
257                         .mode = MTD_OPS_RAW
258                 };
259
260                 ret = mtd_write_oob(mtd, mtd->erasesize * i, &ops);
261                 if (ret)
262                         goto fcb_raw_page_err;
263                 debug("NAND fcb write: 0x%x offset, 0x%x bytes written: %s\n",
264                       mtd->erasesize * i, ops.len, ret ? "ERROR" : "OK");
265
266                 ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize,
267                                 mtd->writesize, &dummy, dbbt_page);
268                 if (ret)
269                         goto fcb_raw_page_err;
270                 debug("NAND dbbt write: 0x%x offset, 0x%x bytes written: %s\n",
271                       mtd->erasesize * i + mtd->writesize, dummy,
272                       ret ? "ERROR" : "OK");
273
274                 /* dbbtpages == 0 if no bad blocks */
275                 if (dbbt->dbbtpages > 0) {
276                         loff_t to = (mtd->erasesize * i + mtd->writesize * 5);
277
278                         ret = mtd_write(mtd, to, mtd->writesize, &dummy,
279                                         dbbt_data_page);
280                         if (ret)
281                                 goto fcb_raw_page_err;
282                 }
283         }
284
285 fcb_raw_page_err:
286         kfree(fcb_raw_page);
287 dbbt_data_page_err:
288         kfree(dbbt_data_page);
289 dbbt_page_err:
290         kfree(dbbt_page);
291 fcb_err:
292         kfree(fcb);
293 fwbuf_err:
294         kfree(fwbuf);
295 err:
296         return ret;
297 }
298
299 static int do_nandbcb_update(int argc, char * const argv[])
300 {
301         struct mtd_info *mtd;
302         loff_t addr, offset, size, maxsize;
303         char *endp;
304         u_char *buf;
305         int dev;
306         int ret;
307
308         if (argc != 4)
309                 return CMD_RET_USAGE;
310
311         dev = nand_curr_device;
312         if (dev < 0) {
313                 printf("failed to get nand_curr_device, run nand device");
314                 return CMD_RET_FAILURE;
315         }
316
317         addr = simple_strtoul(argv[1], &endp, 16);
318         if (*argv[1] == 0 || *endp != 0)
319                 return CMD_RET_FAILURE;
320
321         mtd = get_nand_dev_by_index(dev);
322         if (mtd_arg_off_size(argc - 2, argv + 2, &dev, &offset, &size,
323                              &maxsize, MTD_DEV_TYPE_NAND, mtd->size))
324                 return CMD_RET_FAILURE;
325
326         buf = map_physmem(addr, size, MAP_WRBACK);
327         if (!buf) {
328                 puts("failed to map physical memory\n");
329                 return CMD_RET_FAILURE;
330         }
331
332         ret = nandbcb_update(mtd, offset, size, maxsize, buf);
333
334         return ret == 0 ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
335 }
336
337 static int do_nandbcb(cmd_tbl_t *cmdtp, int flag, int argc,
338                       char * const argv[])
339 {
340         const char *cmd;
341         int ret = 0;
342
343         if (argc < 5)
344                 goto usage;
345
346         cmd = argv[1];
347         --argc;
348         ++argv;
349
350         if (strcmp(cmd, "update") == 0) {
351                 ret = do_nandbcb_update(argc, argv);
352                 goto done;
353         }
354
355 done:
356         if (ret != -1)
357                 return ret;
358 usage:
359         return CMD_RET_USAGE;
360 }
361
362 static char nandbcb_help_text[] =
363         "update addr off|partition len  - update 'len' bytes starting at\n"
364         "       'off|part' to memory address 'addr', skipping  bad blocks";
365
366 U_BOOT_CMD(nandbcb, 5, 1, do_nandbcb,
367            "i.MX6 Nand BCB",
368            nandbcb_help_text
369 );