Add Broadcom / Netgear changes from RAXE 1.0.0.48
[project/bcm63xx/u-boot.git] / board / broadcom / bcmbca / reimage.c
1 /* SPDX-License-Identifier: GPL-2.0+ */
2 /*
3 * Copyright 2019 Broadcom Ltd.
4 */
5
6 #include <common.h>
7
8 #include <asm/arch/ddr.h>
9 #include <linux/ctype.h>
10 #include <mtd.h>
11 #include <nand.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <environment.h>
15 #include <cli.h>
16 #include <linux/bitops.h>
17 #include <linux/crc32.h>
18 #include <ubi_uboot.h>
19 #include "bca_common.h"
20 #include "bca_sdk.h"
21 #include "reimage.h"
22 #include "spl_env.h"
23
24 static struct reimager rei = { 0 };
25
26 DECLARE_GLOBAL_DATA_PTR;
27
28 __weak void boost_cpu_clock(void)
29 {
30 }
31
32 int board_sdk_late_init_e(void)
33 {
34 boost_cpu_clock();
35
36 /* CUSTOMIZE -- set default behavior here */
37 env_set("bootdelay", "5");
38 env_set("bootcmd", "reimage auto");
39 return 0;
40 }
41
42 void hook_dram_init(void)
43 {
44 int shift;
45 u64 size;
46 #if defined(CONFIG_BCM63138) || defined(CONFIG_BCM63148) || defined(CONFIG_BCM4908) || defined(CONFIG_BCM6858)
47 shift =
48 (MEMC->GLB_GCFG & MEMC_GLB_GCFG_SIZE1_MASK) >>
49 MEMC_GLB_GCFG_SIZE1_SHIFT;
50 #else
51 shift =
52 (MEMC->GLB_FSBL_STATE & MEMC_GLB_FSBL_DRAM_SIZE_MASK) >>
53 MEMC_GLB_FSBL_DRAM_SIZE_SHIFT;
54 #endif
55 size = 1 << shift; // in MB
56 printf("DDR size from controller %dMB\n", size);
57 gd->ram_size = (phys_size_t) (size << 20);
58 gd->ram_base = 0;
59 gd->bd->bi_dram[0].start = 0;
60 gd->bd->bi_dram[0].size = (phys_size_t) gd->ram_size;
61 }
62
63 static int check_nv_crc(struct nvram_s *nv);
64
65 static int check_nv_crc(struct nvram_s *nv)
66 {
67 int orig, new;
68 printf("original CRC 0x%x\n", nv->ulCheckSum);
69 orig = nv->ulCheckSum;
70 nv->ulCheckSum = 0;
71 /* use crc32_le to get standard CRC rather than the unusual one
72 * used for uboot environment files */
73 new = crc32_le(0xffffffff, nv, 1024);
74 printf("computed CRC 0x%x\n", new);
75 nv->ulCheckSum = orig;
76 return (new == orig);
77 }
78
79 static int ubi_dev_scan(struct mtd_info *info, const char *vid_header_offset);
80
81 static int ubi_dev_scan(struct mtd_info *info, const char *vid_header_offset)
82 {
83 char ubi_mtd_param_buffer[80];
84 int err;
85
86 if (!vid_header_offset)
87 sprintf(ubi_mtd_param_buffer, "%s", info->name);
88 else
89 sprintf(ubi_mtd_param_buffer, "%s,%s", info->name,
90 vid_header_offset);
91
92 err = ubi_mtd_param_parse(ubi_mtd_param_buffer, NULL);
93 if (err)
94 return -err;
95
96 err = ubi_init();
97 if (err)
98 return -err;
99
100 return 0;
101 }
102
103 static int erase(struct mtd_info *mtd, int first, int blocks);
104
105 static int erase(struct mtd_info *mtd, int first, int blocks)
106 {
107 struct erase_info erase_op = { };
108 int ret;
109
110 erase_op.mtd = mtd;
111 erase_op.addr = first * mtd->erasesize;
112 erase_op.len = blocks * mtd->erasesize;
113 erase_op.scrub = 0;
114 printf("Erasing %d blocks from block %d\n", blocks, first);
115
116 while (erase_op.len) {
117 ret = mtd_erase(mtd, &erase_op);
118
119 /* Abort if its not a bad block error */
120 if (ret != -EIO)
121 break;
122
123 printf("Skipping bad block at 0x%08llx\n", erase_op.fail_addr);
124
125 /* Skip bad block and continue behind it */
126 erase_op.len -= erase_op.fail_addr - erase_op.addr;
127 erase_op.len -= mtd->erasesize;
128 erase_op.addr = erase_op.fail_addr + mtd->erasesize;
129 }
130
131 if (ret && ret != -EIO)
132 ret = -1;
133 else
134 ret = 0;
135 return (ret);
136 };
137
138 static int do_nvram_parse(cmd_tbl_t * cmdtp, int flag, int argc,
139 char *const argv[]);
140 static int do_prepare(cmd_tbl_t * cmdtp, int flag, int argc,
141 char *const argv[]);
142 static int do_finish(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
143
144 static int do_prepare(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[])
145 {
146 struct erase_info erase_op = { };
147 char more_env[1024];
148 int more_env_size;
149 int i, ret;
150 size_t sz = 0;
151 int rblk, wblk;
152 char *bp;
153 char *cp;
154 int block;
155 int err;
156 long offset;
157 if (!rei.payload_blocks) {
158 printf("parse first\n");
159 return (-1);
160 }
161 struct mtd_info *mtd = NULL;
162 wblk = rei.burn_first_start;
163 bp = rei.loader_payload =
164 malloc(rei.blocksizeK * 1024 * rei.loader_blocks);
165 if (!bp) {
166 printf("loader payload malloc failed\n");
167 return (-1);
168 }
169 mtd_probe_devices();
170 if (rei.pure_payload_image) {
171 int count = 0;
172 int leb = 0;
173 int offset = 0;
174 int m, s;
175 m = rei.pure_payload_volume_index;
176 s = rei.ubi->volumes[m]->usable_leb_size;
177 cp = CONFIG_SYS_LOAD_ADDR;
178 for (leb = 0;
179 leb * s < 2048 + rei.blocksizeK * 1024 * rei.loader_blocks;
180 leb++) {
181 err =
182 ubi_eba_read_leb(rei.ubi, rei.ubi->volumes[m], leb,
183 cp + leb * s, 0, s, 0);
184 }
185 memcpy(rei.loader_payload, cp + 2048,
186 rei.blocksizeK * 1024 * rei.loader_blocks);
187 printf("start of image device = 0x%x\n",
188 2048 + rei.blocksizeK * 1024 * rei.loader_blocks);
189 leb = (2048 + rei.blocksizeK * 1024 * rei.loader_blocks) / s;
190 offset = (2048 + rei.blocksizeK * 1024 * rei.loader_blocks) % s;
191 count = 0;
192 mtd = get_mtd_device_nm("nand0");
193 if (IS_ERR_OR_NULL(mtd)) {
194 printf("failed to get mtd\n");
195 return (-1);
196 }
197 erase(mtd, rei.erase_first_start, rei.erase_first_blocks);
198 put_mtd_device(mtd);
199 while (count < rei.payload_blocks * rei.blocksizeK * 1024) {
200 cp = CONFIG_SYS_LOAD_ADDR;
201 while (((int)cp < CONFIG_SYS_LOAD_ADDR + SZ_16M)
202 && (count <
203 rei.payload_blocks * rei.blocksizeK *
204 1024)) {
205 err =
206 ubi_eba_read_leb(rei.ubi,
207 rei.ubi->volumes[m], leb,
208 cp, offset, s - offset, 0);
209 printf("R");
210 // printf
211 // (" leb %d off 0x%x new 0x%x count %x --> %p\n",
212 // leb, offset, s - offset, count, cp);
213 count = count + s - offset;
214 cp = cp + s - offset;
215 offset = 0;
216 leb++;
217 }
218 // printf("final cp is %p next leb %d\n", cp, leb);
219 if ((int)cp > CONFIG_SYS_LOAD_ADDR + SZ_16M) {
220 offset =
221 s - ((int)cp -
222 (CONFIG_SYS_LOAD_ADDR + SZ_16M));
223 leb--;
224 // printf
225 // ("adjusted offset to 0x%x and next leb to %d\n",
226 // offset, leb);
227 }
228 mtd = get_mtd_device_nm("nand0");
229 if (IS_ERR_OR_NULL(mtd)) {
230 printf("failed to get mtd\n");
231 return (-1);
232 }
233 cp = CONFIG_SYS_LOAD_ADDR;
234 while (((int)cp + mtd->erasesize) <=
235 CONFIG_SYS_LOAD_ADDR + SZ_16M) {
236 if (wblk <
237 (rei.burn_first_start +
238 rei.burn_first_blocks)) {
239 if (!mtd_block_isbad
240 (mtd, wblk * mtd->erasesize)) {
241 i = mtd_write(mtd,
242 wblk *
243 mtd->erasesize,
244 mtd->erasesize,
245 &sz, cp);
246 printf("W");
247 // printf
248 // (" 0x%x bytes at %p -> blk %d\n",
249 // sz, cp, wblk);
250 cp += sz;
251 } else {
252 printf("bad");
253 }
254 wblk++;
255 } else {
256 printf
257 ("\nFIXME -- remainder not implemented\n");
258 }
259 }
260 put_mtd_device(mtd);
261 }
262 }
263
264 else {
265 mtd = get_mtd_device_nm("nand0");
266 if (IS_ERR_OR_NULL(mtd)) {
267 printf("failed to get mtd\n");
268 return (-1);
269 }
270 // FIXME -- loop on payload until we have enough data
271 // first --> loader (DDR)
272 // next --> burn_first (until exhausted)
273 // finally --> allocate remainder and copy to DDR
274 rblk = rei.payload_start;
275 while (bp <
276 (rei.loader_payload +
277 mtd->erasesize * rei.loader_blocks)) {
278 i = mtd_read(mtd, rblk * mtd->erasesize, mtd->erasesize,
279 &sz,
280 rei.loader_payload +
281 mtd->erasesize * (rblk -
282 rei.payload_start));
283 printf("read loader -> mem %d bytes ret %d\n", sz, i);
284 rblk++;
285 bp += sz;
286 }
287 printf("loader in memory buffer at 0x%x and size 0x%x\n",
288 rei.loader_payload, mtd->erasesize * rei.loader_blocks);
289 erase(mtd, rei.erase_first_start, rei.erase_first_blocks);
290 // rblk = rei.payload_start + rei.loader_blocks;
291 block = rei.loader_blocks;
292 while (block < (rei.loader_blocks + rei.payload_blocks)) {
293 i = mtd_read(mtd, rblk * mtd->erasesize, mtd->erasesize,
294 &sz, (char *)CONFIG_SYS_LOAD_ADDR);
295 printf("R");
296 if (sz) {
297 block++;
298 i = 1;
299 while (i) {
300 if (wblk <
301 (rei.burn_first_start +
302 rei.burn_first_blocks)) {
303 if (!mtd_block_isbad
304 (mtd,
305 wblk * mtd->erasesize)) {
306 i = mtd_write(mtd,
307 wblk *
308 mtd->
309 erasesize,
310 mtd->
311 erasesize,
312 &sz,
313 (char *)
314 CONFIG_SYS_LOAD_ADDR);
315 printf("W", sz, i);
316 } else {
317 printf("bad");
318 }
319 wblk++;
320 } else {
321 if (!rei.remaining_payload) {
322 rei.remaining_payload =
323 malloc
324 (mtd->erasesize *
325 (rei.loader_blocks
326 +
327 rei.payload_blocks
328 - block + 1));
329 rei.remaining_payload_len = 0;
330 if (!rei.
331 remaining_payload) {
332 printf
333 ("malloc for remaining failed\n");
334 return (1);
335 }
336 }
337 memcpy(rei.remaining_payload +
338 rei.
339 remaining_payload_len,
340 (char *)
341 CONFIG_SYS_LOAD_ADDR,
342 mtd->erasesize);
343 rei.remaining_payload_len +=
344 mtd->erasesize;
345 printf("M");
346 i = 0;
347 }
348 }
349 }
350 rblk++;
351
352 }
353 printf("\n");
354 put_mtd_device(mtd);
355
356 }
357
358 cp = more_env;
359
360 cp += sprintf(cp, "ethaddr=%x:%x:%x:%x:%x:%x",
361 rei.nvram.ucaBaseMacAddr[0],
362 rei.nvram.ucaBaseMacAddr[1],
363 rei.nvram.ucaBaseMacAddr[2],
364 rei.nvram.ucaBaseMacAddr[3],
365 rei.nvram.ucaBaseMacAddr[4], rei.nvram.ucaBaseMacAddr[5]);
366 *(cp++) = '\0';
367
368 cp +=
369 sprintf(cp,
370 "bootcmd=printenv;run once;run check_flashback;printenv;sdk boot_img");
371 *(cp++) = '\0';
372
373 cp += sprintf(cp, "tries=3");
374 *(cp++) = '\0';
375
376 cp +=
377 sprintf(cp,
378 "check_flashback=test $tries -eq 0 || echo $tries ; setexpr tries $tries - 1 ; saveenv ; test $tries -eq 0 && run do_flashback");
379 *(cp++) = '\0';
380
381 cp +=
382 sprintf(cp,
383 "do_flashback=echo here is where I would have run flashback");
384 *(cp++) = '\0';
385
386 cp += sprintf(cp, "once=sdk metadata 1 1;setenv once true;saveenv");
387 *(cp++) = '\0';
388
389 *(cp++) = '\0';
390 more_env_size = cp - more_env + 1;
391
392 for (bp = rei.loader_payload;
393 bp < rei.loader_payload + mtd->erasesize * rei.loader_blocks;
394 bp += 4096) {
395 int *tenv;
396 env_t *ep;
397 uint32_t new, crc;
398 tenv = (int *)bp;
399 printf("env check at %x\r", bp - rei.loader_payload);
400 if (tenv[0] == BOOT_MAGIC_MAGIC) {
401 printf("\nGOT IT\n");
402 ep = (env_t *) & tenv[2];
403 memcpy(&crc, &ep->crc, sizeof(crc));
404 /* specifically use uboot's env crc function
405 * even though we have included the standard
406 * linux crc32 */
407 new = the_env_crc32(0, ep->data, tenv[1] - 4);
408 if (new != crc) {
409 printf("bad\n");
410 } else {
411 printf("good\n");
412
413 for (i = 0; i < tenv[1] - 4; i++) {
414 if ((ep->data[i] == '\0')
415 && (ep->data[i + 1] == '\0')) {
416 memcpy(&ep->data[i + 1],
417 more_env, more_env_size);
418 break;
419 }
420 }
421 new = the_env_crc32(0, ep->data, tenv[1] - 4);
422 memcpy(&ep->crc, &new, sizeof(new));
423 }
424 }
425 }
426
427 printf("\n");
428 return (0);
429 }
430
431 static int do_finish(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[])
432 {
433 int i, ret;
434 unsigned long time_start, time_mid, time_end;
435 size_t sz = 0;
436 int rblk, wblk;
437 char *bp;
438 char cmd[256];
439 int block;
440 long offset;
441 if (!rei.payload_blocks) {
442 printf("parse first\n");
443 return (-1);
444 }
445 run_command("ubifsumount", 0);
446 run_command("ubi detach", 0);
447 struct mtd_info *mtd = NULL;
448 mtd_probe_devices();
449 mtd = get_mtd_device_nm("nand0");
450 if (IS_ERR_OR_NULL(mtd)) {
451 printf("failed to get mtd\n");
452 return (-1);
453 }
454 if (!rei.loader_payload) {
455 printf("loader payload isn't set\n");
456 return (-1);
457 }
458 time_start = get_timer(0);
459 erase(mtd, 0, rei.loader_blocks);
460 for (i = 0; i < rei.loader_blocks; i++) {
461 offset = i * mtd->erasesize;
462 ret = mtd_write(mtd,
463 i * mtd->erasesize,
464 mtd->erasesize, &sz,
465 &rei.loader_payload[i * mtd->erasesize]);
466 printf("w mem->ldr %d b ret %d\n", sz, ret);
467 }
468 erase(mtd, rei.burn_remaining_start, rei.burn_remaining_blocks);
469 wblk = rei.burn_remaining_start;
470 i = 0;
471 while (i < rei.remaining_payload_len) {
472 printf("rp %x => %d\n", i, wblk);
473 ret = mtd_write(mtd,
474 wblk * mtd->erasesize,
475 mtd->erasesize, &sz, &rei.remaining_payload[i]);
476 i += sz;
477 wblk++;
478 }
479
480 erase(mtd, rei.erase_last_start, rei.erase_last_blocks);
481 put_mtd_device(mtd);
482 time_mid = get_timer(0);
483 sprintf(cmd, "%s:%lld(loader),%lld@%lld(image)",
484 "brcmnand.0",
485 (long long)(rei.loader_blocks * (long long)mtd->erasesize),
486 (long long)(mtd->size -
487 (rei.loader_blocks + 8) * mtd->erasesize),
488 (long long)(rei.loader_blocks * mtd->erasesize));
489 run_command("mtdparts delall", 0);
490 env_set("mtdparts", cmd);
491 run_command("mtdparts", 0);
492 if (rei.preserved_data_max_len) {
493 run_command("ubi part image", 0);
494
495 sprintf(cmd, "ubi create transition 0x%x dynamic 33",
496 rei.preserved_data_max_len);
497 run_command(cmd, 0);
498 sprintf(cmd, "ubi write 0x%x transition 0x%x",
499 rei.preserved_data, rei.preserved_data_max_len);
500 run_command(cmd, 0);
501 }
502
503 time_end = get_timer(0);
504 run_command("ubi detach", 0);
505 printf("start %ld\nsafe %ld\ndone %\ld\nHZ %d\n", time_start,
506 time_mid, time_end, CONFIG_SYS_HZ);
507 return (0);
508
509 }
510
511 static void set_rei_ranges(int i);
512
513 static void set_rei_ranges(int i)
514 {
515 char *cp;
516 struct nvram_s *nv;
517 nv = &rei.nvram;
518 printf("ranges for image %d\n", i);
519 rei.erase_first_start = nv->ulNandPartOfsKb[3 - i] / rei.blocksizeK;
520 rei.erase_first_blocks = nv->ulNandPartSizeKb[3 - i] / rei.blocksizeK;
521 if (rei.erase_first_start < rei.loader_blocks) {
522 rei.burn_first_start = rei.loader_blocks;
523 rei.burn_first_blocks =
524 rei.erase_first_blocks -
525 (rei.loader_blocks - rei.erase_first_start);
526 } else {
527 rei.burn_first_start = rei.erase_first_start;
528 rei.burn_first_blocks = rei.erase_first_blocks;
529 }
530 if (cp = env_get("burn_first_blocks")) {
531 rei.burn_first_blocks = simple_strtoul(cp, NULL, 0);
532 }
533 printf("rei.erase_first_start=%d\n", rei.erase_first_start);
534 printf("rei.erase_first_blocks=%d\n", rei.erase_first_blocks);
535 printf("rei.burn_first_start=%d\n", rei.burn_first_start);
536 printf("rei.burn_first_blocks=%d\n", rei.burn_first_blocks);
537 rei.burn_remaining_start = nv->ulNandPartOfsKb[i] / rei.blocksizeK;
538 rei.burn_remaining_blocks = nv->ulNandPartSizeKb[i] / rei.blocksizeK;
539 if (rei.burn_remaining_start < rei.loader_blocks) {
540 rei.burn_remaining_start = rei.loader_blocks;
541 rei.burn_remaining_blocks =
542 rei.burn_remaining_blocks -
543 (rei.loader_blocks - rei.burn_remaining_start);
544 }
545 }
546
547 static int do_nvram_parse(cmd_tbl_t * cmdtp, int flag, int argc,
548 char *const argv[])
549 {
550 // int *haystack = (int *)0x1000000;
551 int i, j, k, m;
552 int ret = 0;
553 u_char *cp;
554 int blocksize;
555 int err;
556 long int needle;
557 char split[128];
558 int payload_loader_size = 0;
559 int payload_size = 0;
560 struct nvram_s *nv;
561 u_char tmp[2048];
562 // char cmd[256];
563 long int *ip;
564 struct mtd_info *mtd;
565 size_t sz = 0;
566 int crc;
567
568 memcpy(&needle, NVRAM_MAGIC, 8);
569 mtd_probe_devices();
570 mtd = get_mtd_device_nm("nand0");
571 if (IS_ERR_OR_NULL(mtd)) {
572 printf("failed to get mtd\n");
573 return (-1);
574 }
575 i = mtd_read(mtd, 0, 2 << 20, &sz, (u_char *) CONFIG_SYS_LOAD_ADDR);
576 nv = 0x1010580;
577 if (!check_nv_crc(nv)) {
578 nv = NULL;
579 for (ip = (long int *)CONFIG_SYS_LOAD_ADDR;
580 ip < (long int *)(CONFIG_SYS_LOAD_ADDR + SZ_2M);
581 ip = ip + (2048 / sizeof(long int))) {
582 if (*ip == needle) {
583 printf("got it %p\n", ip);
584 nv = &ip[1];
585 if (check_nv_crc(nv)) {
586 printf("nvram CRC OK\n");
587 } else {
588 printf("nvram CRC failed\n");
589 }
590 }
591 }
592 }
593 if (!nv) {
594 printf("failed\n");
595 return (1);
596 }
597 memcpy(&rei.nvram, nv, sizeof(rei.nvram));
598 printf("version %d\n", nv->version);
599 memset(tmp, 0, 24);
600 strncpy(tmp, nv->boardid, 16);
601 printf("boardid %s\n", tmp);
602 printf("bootline %s\n", nv->bootline);
603 printf("afeids %x,%x\n", nv->afeId[0], nv->afeId[1]);
604 printf("MCB %x\n", nv->ulMemoryConfig);
605 for (i = 0; i < NP_TOTAL; i++) {
606 printf("part %d offset %dK size %dK\n", i,
607 nv->ulNandPartOfsKb[i], nv->ulNandPartSizeKb[i]);
608 }
609 memset(tmp, 0, 24);
610 strncpy(tmp, nv->szVoiceBoardId, 16);
611 printf("voiceboardid %s\n", tmp);
612
613 blocksize = mtd->erasesize;
614 rei.blocksizeK = mtd->erasesize >> 10;
615 put_mtd_device(mtd);
616 env_set("mtdids", "nand0=brcmnand.0");
617 sprintf(tmp, "%s:%dK@%dK(nvram)ro,%dK@%dK(image1)ro,%dK@%dK(image2)ro,",
618 "brcmnand.0",
619 nv->ulNandPartSizeKb[0], nv->ulNandPartOfsKb[0],
620 nv->ulNandPartSizeKb[1], nv->ulNandPartOfsKb[1],
621 nv->ulNandPartSizeKb[2], nv->ulNandPartOfsKb[2]
622 );
623 k = nv->ulNandPartSizeKb[2] + nv->ulNandPartOfsKb[2];
624 for (i = 0; i < 3; i++) {
625 j = nv->part_info[i].size;
626 j = (j & 0xc000 == 0xc000) ? 0 : j;
627 printf("misc%d size is %d\n", i + 1, j);
628 if (j) {
629 sprintf(tmp + strlen(tmp), "%dK@%dK(misc%d),",
630 j * 1024, k, i + 1);
631 k = k + j * 1024;
632 }
633 }
634 sprintf(tmp + strlen(tmp), "%dK@%dK(data)",
635 nv->ulNandPartSizeKb[3], nv->ulNandPartOfsKb[3]
636 );
637 printf("setting mtdparts to %s\n", tmp);
638 env_set("mtdparts", tmp);
639 run_command("mtdparts", 0);
640 sprintf(tmp, "0x%x", nv->ulNandPartSizeKb[0] * 1024);
641 env_set("nvram_size", tmp);
642 run_command("nand info", 0);
643 printf("erase block %d\n", blocksize);
644 strcpy(split, MASQ_SPLIT_A);
645 strcat(split, MASQ_SPLIT_B);
646 mtd_probe_devices();
647 for (i = 1; i < 3; i++) {
648 sprintf(tmp, "image%d", i);
649 mtd = get_mtd_device_nm(tmp);
650 if (IS_ERR_OR_NULL(mtd)) {
651 printf("failed to get mtd\n");
652 return (-1);
653 }
654 for (j = 0; j < 20; j++) {
655 // printf("read i=%d j=%d\n",i,j);
656 ret = mtd_read(mtd, j * blocksize, 2048, &sz, tmp);
657 // printf("ret %d read %d\n",ret,sz);
658 if (0 == strncmp(split, tmp, strlen(split) + 1)) {
659 printf("found image%d block %d\n", i, j);
660 cp = &tmp[strlen(split) + 1];
661 payload_loader_size =
662 simple_strtoul(cp, NULL, 0);
663 cp = cp + strlen(cp) + 1;
664 payload_size = simple_strtoul(cp, NULL, 0);
665 printf("loader size %d payload size %d\n",
666 payload_loader_size, payload_size);
667 rei.loader_blocks =
668 payload_loader_size / blocksize;
669 rei.payload_blocks = payload_size / blocksize;
670 rei.split_image_start =
671 (nv->ulNandPartOfsKb[i] / rei.blocksizeK);
672 rei.split_image_end =
673 (nv->ulNandPartOfsKb[i] +
674 nv->ulNandPartSizeKb[i]) / rei.blocksizeK -
675 1;
676 rei.payload_start =
677 (nv->ulNandPartOfsKb[i] / rei.blocksizeK) +
678 j + 1;
679 /////
680 set_rei_ranges(i);
681 i = j = 30;
682 break;
683 }
684
685 }
686 put_mtd_device(mtd);
687 /* the following will probably be removed ... reimage will always be packaged as a split image */
688 /* if we do keep it, after attaching, it needs to check for volumes other than the rootfs */
689 /* or the number of volumes */
690 if ((0 == 1) && (i < 3)) {
691 if (rei.ubi)
692 ubi_exit();
693
694 rei.ubi = NULL;
695 /* didn't find marker yet */
696 err = ubi_dev_scan(mtd, NULL);
697 if (err) {
698 printf("UBI init error %d\n", err);
699 printf
700 ("Please check, if the correct MTD partition is used (size big enough?)\n");
701 }
702
703 rei.ubi = ubi_devices[0];
704
705 sprintf(tmp, "image%d", i);
706 if (rei.ubi) {
707 printf("part %s attaches as ubi\n", tmp);
708 for (m = 0; m < (rei.ubi->vtbl_slots + 1); m++) {
709 if (!rei.ubi->volumes[m])
710 continue; /* Empty record */
711 printf("name %s\n",
712 rei.ubi->volumes[m]->name);
713 if (0 ==
714 strcmp("payload",
715 rei.ubi->volumes[m]->name)) {
716 /* found payload volume */
717 rei.pure_payload_image = i;
718 rei.pure_payload_volume_index =
719 m;
720 i = 30;
721 }
722 }
723 }
724 }
725 if (rei.pure_payload_image) {
726 int m, s, t;
727 m = rei.pure_payload_volume_index;
728 s = rei.ubi->volumes[m]->usable_leb_size;
729 err =
730 ubi_eba_read_leb(rei.ubi, rei.ubi->volumes[m],
731 0, CONFIG_SYS_LOAD_ADDR, 0, s, 0);
732 cp = CONFIG_SYS_LOAD_ADDR;
733 t = simple_strtoul(cp, &cp, 0);
734 rei.loader_blocks = t / blocksize;
735 printf("loader size %d is %d blocks\n", t, blocksize);
736 cp++;
737 t = simple_strtoul(cp, &cp, 0);
738 rei.payload_blocks = t / blocksize;
739 printf("payload size %d is %d blocks\n", t, blocksize);
740 set_rei_ranges(rei.pure_payload_image);
741
742 }
743
744 }
745
746 nv = &rei.nvram;
747 rei.erase_last_start =
748 (nv->ulNandPartOfsKb[2] + nv->ulNandPartSizeKb[2]) / rei.blocksizeK;
749 rei.erase_last_blocks =
750 ((nv->ulNandPartOfsKb[3] +
751 nv->ulNandPartSizeKb[3]) / rei.blocksizeK) - rei.erase_last_start;
752 return (ret);
753 }
754
755 static int do_preserve_allocate(cmd_tbl_t * cmdtp, int flag, int argc,
756 char *const argv[]);
757
758 static int do_preserve_save(cmd_tbl_t * cmdtp, int flag, int argc,
759 char *const argv[]);
760 static int do_preserve_allocate(cmd_tbl_t * cmdtp, int flag, int argc,
761 char *const argv[])
762 {
763 int len;
764 char *cp;
765 len = simple_strtoul(argv[1], NULL, 0);
766 cp = malloc(len);
767 if (!cp) {
768 printf("malloc failed\n");
769 return (1);
770 }
771 cp[0] = '\0';
772 rei.preserved_data = cp;
773 rei.preserved_data_len = 0;
774 rei.preserved_data_max_len = len;
775 printf("allocated 0x%x bytes at %x\n", len, cp);
776 return (0);
777 }
778
779 static int do_preserve_save(cmd_tbl_t * cmdtp, int flag, int argc,
780 char *const argv[])
781 {
782 char *cp;
783 int len;
784 if (argc != 2) {
785 printf("filename required\n");
786 return (-1);
787 }
788 if (cp = env_get("filesize")) {
789 len = simple_strtoul(cp, NULL, 16);
790 } else {
791 printf("filesize in env is not set\n");
792 return (1);
793 }
794 if (rei.preserved_data_len + strlen(argv[1]) + 16 + len >
795 rei.preserved_data_max_len) {
796 printf("allocated space exhausted\n");
797 return (1);
798 }
799 rei.preserved_data_len +=
800 sprintf(rei.preserved_data + rei.preserved_data_len, "%s\n%d\n",
801 argv[1], len);
802 memcpy(rei.preserved_data + rei.preserved_data_len,
803 CONFIG_SYS_LOAD_ADDR, len);
804 rei.preserved_data_len += len;
805 *((char *)(rei.preserved_data + rei.preserved_data_len)) = '\n';
806 printf("preserved %d bytes as %s\n", len, argv[1]);
807 return (0);
808 }
809
810 static int do_commit(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
811 static int do_commit(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[])
812 {
813 struct mtd_info *mtd = NULL;
814 long offset;
815 int i;
816 size_t sz = 0;
817 int ret = 0;
818 int rblk;
819 if (!rei.loader_payload) {
820 printf("prepare revertable first\n");
821 return (-1);
822 }
823 mtd_probe_devices();
824 mtd = get_mtd_device_nm("nand0");
825 erase(mtd, rei.erase_first_start, rei.erase_first_blocks);
826 erase(mtd, rei.erase_last_start, rei.erase_last_blocks);
827 erase(mtd, 0, rei.loader_blocks);
828 rblk = 0;
829 for (i = 0; i < rei.loader_blocks; i++) {
830 if (mtd_block_isbad(mtd, (uint64_t) i * mtd->erasesize)) {
831 printf("skip bad block %d\n", i);
832 } else {
833 offset = i * mtd->erasesize;
834 ret = mtd_write(mtd,
835 i * mtd->erasesize,
836 mtd->erasesize, &sz,
837 &rei.loader_payload[rblk * mtd->erasesize]);
838 printf("w mem->ldr %d b ret %d\n", sz, ret);
839 if (ret == 0) {
840 rblk++;
841 }
842 }
843 }
844 put_mtd_device(mtd);
845 return (ret);
846 }
847
848 static int do_revertable(cmd_tbl_t * cmdtp, int flag, int argc,
849 char *const argv[]);
850 static int do_revertable(cmd_tbl_t * cmdtp, int flag, int argc,
851 char *const argv[])
852 {
853 struct mtd_info *mtd = NULL;
854 char *bp;
855 int rblk;
856 int i, ret = 0;
857 size_t sz = 0;
858 char more_env[1024];
859 int more_env_size;
860 // parse nvram
861 if (!rei.payload_blocks) {
862 printf("parse first\n");
863 return (-1);
864 }
865 mtd_probe_devices();
866 mtd = get_mtd_device_nm("nand0");
867 if (IS_ERR_OR_NULL(mtd)) {
868 printf("failed to get mtd\n");
869 return (-1);
870 }
871 erase(mtd, rei.split_image_start,
872 rei.payload_start - rei.split_image_start);
873 // read loader to ddr
874 bp = rei.loader_payload =
875 malloc(rei.blocksizeK * 1024 * rei.loader_blocks);
876 if (!bp) {
877 printf("loader payload malloc failed\n");
878 return (-1);
879 }
880 rblk = rei.payload_start;
881 while (bp < (rei.loader_payload + mtd->erasesize * rei.loader_blocks)) {
882 i = mtd_read(mtd, rblk * mtd->erasesize, mtd->erasesize,
883 &sz,
884 rei.loader_payload +
885 mtd->erasesize * (rblk - rei.payload_start));
886 printf("read loader -> mem %d bytes ret %d\n", (int)sz, i);
887 rblk++;
888 bp += sz;
889 }
890 // erase start of reimage image to end of loader
891 erase(mtd, rei.payload_start, rei.loader_blocks);
892 // preserve files
893 // update loader in ddr (env)
894 reimage_env_append(&rei);
895 put_mtd_device(mtd);
896 return (ret);
897 }
898
899 static int do_read_recovery(cmd_tbl_t * cmdtp, int flag, int argc,
900 char *const argv[]);
901 static int do_read_recovery(cmd_tbl_t * cmdtp, int flag, int argc,
902 char *const argv[])
903 {
904 struct mtd_info *mtd = NULL;
905 char *bp;
906 int rblk;
907 int blocks;
908 int pages;
909 int chunk = 0;
910 size_t sz = 0;
911 loff_t off;
912 int i, j, n, z, ret = 0;
913 u32 *up32;
914 int block = 0;
915 int page = 0;
916 struct mtd_oob_ops oob_ops;
917 u32 spare[200];
918 mtd = get_mtd_device_nm("nand0");
919 blocks = (mtd->size / mtd->erasesize);
920 pages = (mtd->erasesize / mtd->writesize);
921 rei.recovery_chunks_list = CONFIG_SYS_LOAD_ADDR;
922 rei.recovery_data_buf =
923 CONFIG_SYS_LOAD_ADDR + (blocks * pages +
924 1) * sizeof(struct recovery_chunks);
925 rei.recovery_data_len = 0;
926 if (!rei.recovery_chunks_list) {
927 printf("recovery chunks malloc failed\n");
928 return (-1);
929 }
930 printf("Flash device is %d blocks of %d pages of %d bytes\n", blocks,
931 pages, mtd->writesize);
932 while (block < blocks) {
933 if ((block >= rei.split_image_start)
934 && (block <= rei.split_image_end)) {
935 // printf("block %d is part of reimage\n", block);
936 block++;
937 continue;
938 }
939 off =
940 (uint64_t) page *mtd->writesize +
941 (uint64_t) block *mtd->erasesize;
942 if (page == 0) {
943 if (mtd_block_isbad
944 (mtd, (uint64_t) block * mtd->erasesize)) {
945 /* check for bad block */
946 printf("block %d is bad\n", block);
947 block++;
948 continue;
949 }
950 }
951 sz = 0;
952 /* read to buffer ... may not keep it */
953 bp = rei.recovery_data_buf + rei.recovery_data_len;
954 oob_ops.mode = MTD_OPS_PLACE_OOB;
955 oob_ops.len = mtd->writesize;
956 oob_ops.retlen = 0;
957 oob_ops.ooblen = mtd->oobsize;
958 oob_ops.oobretlen = 0;
959 oob_ops.ooboffs = 0;
960 oob_ops.datbuf = bp;
961 oob_ops.oobbuf = spare;
962 i = mtd_read_oob(mtd, off, &oob_ops);
963 sz = oob_ops.retlen;
964
965 n = 0;
966 j = 0;
967 if (i != 0) {
968 printf("%d/%d return %d sz %d\n", block, page, i, sz);
969 }
970 if (page == 0) {
971 //printf("%d/%d ", block, page, i, sz);
972 printf(".");
973 // printf("%d/%d r %d sz %d", block, page, i, sz);
974 }
975 while ((n < 2) && (j < sz)) {
976 up32 = bp + j;
977 n = n + 32 - generic_hweight32(*up32);
978 j = j + 4;
979 /* check if not blank ... otherwise read oob too */
980 }
981 if (page == 0) {
982 // printf(" zeros %d", n);
983 }
984 z = 0;
985 if (n < 2) {
986 /* check for zeros in oob */
987 for (j = 0; j < oob_ops.oobretlen >> 2; j++) {
988 z = z + 32 - generic_hweight32(spare[j]);
989 }
990 if (page == 0) {
991 // printf(" spare zeros %d\n", z);
992 }
993 } else {
994 if (page == 0) {
995 // printf("\n");
996 }
997 }
998 /* deal with this page */
999 // if (n + z > 2) {
1000 if ((i == 0) && (n != 0)) {
1001 // not blank
1002 rei.recovery_chunks_list[chunk].flashpage =
1003 block * pages + page;
1004 rei.recovery_chunks_list[chunk].size = mtd->writesize;
1005 rei.recovery_chunks_list[chunk].type = 0x00;
1006 chunk++;
1007 rei.recovery_data_len += mtd->writesize;
1008 }
1009 page = (page + 1) % pages;
1010 if (page == 0) {
1011 block++;
1012 }
1013 }
1014 rei.recovery_chunks_list[chunk].type = 0x7fffffff;
1015 printf("chunks %d len 0x%x\n", chunk, rei.recovery_data_len);
1016 // load old blocks (everything but reimage image) to ddr
1017 put_mtd_device(mtd);
1018 return (ret);
1019 }
1020
1021 // erase everything except the reimage payload (after loader)
1022 // burn loader
1023 // attach image
1024 // store preserved files
1025 // store old blocks
1026
1027 static int do_flashback(cmd_tbl_t * cmdtp, int flag, int argc,
1028 char *const argv[]);
1029 static int do_flashback(cmd_tbl_t * cmdtp, int flag, int argc,
1030 char *const argv[])
1031 {
1032 struct mtd_info *mtd = NULL;
1033 long offset;
1034 int i;
1035 size_t sz = 0;
1036 int blocks, pages;
1037 int ret = 0;
1038 char *bp;
1039 int chunk;
1040 if (rei.recovery_data_len == 0) {
1041 printf("read recovery chunks first\n");
1042 return (2);
1043 }
1044 mtd = get_mtd_device_nm("nand0");
1045 blocks = (mtd->size / mtd->erasesize);
1046 pages = (mtd->erasesize / mtd->writesize);
1047 erase(mtd, 0, blocks);
1048 chunk = 0;
1049 bp = rei.recovery_data_buf;
1050 while (rei.recovery_chunks_list[chunk].type < 0x1000) {
1051 i = mtd_write(mtd,
1052 rei.recovery_chunks_list[chunk].flashpage *
1053 mtd->writesize, mtd->writesize, &sz, bp);
1054 bp += rei.recovery_chunks_list[chunk].size;
1055 chunk++;
1056 printf("%d ", chunk);
1057 }
1058 put_mtd_device(mtd);
1059 }
1060
1061 static int do_store_preserved(cmd_tbl_t * cmdtp, int flag, int argc,
1062 char *const argv[]);
1063 static int do_store_preserved(cmd_tbl_t * cmdtp, int flag, int argc,
1064 char *const argv[])
1065 {
1066 char cmd[256];
1067 struct mtd_info *mtd = NULL;
1068 mtd = get_mtd_device_nm("nand0");
1069 if (IS_ERR_OR_NULL(mtd)) {
1070 printf("failed to get mtd\n");
1071 return (-1);
1072 }
1073 sprintf(cmd, "%s:%lld(loader),%lld@%lld(image)",
1074 "brcmnand.0",
1075 (long long)(rei.loader_blocks * (long long)mtd->erasesize),
1076 (long long)(mtd->size -
1077 (rei.loader_blocks + 8) * mtd->erasesize),
1078 (long long)(rei.loader_blocks * mtd->erasesize));
1079 run_command("mtdparts delall", 0);
1080 env_set("mtdparts", cmd);
1081 run_command("mtdparts", 0);
1082 run_command("ubi part image", 0);
1083 if (rei.preserved_data_max_len) {
1084 sprintf(cmd, "ubi create transition 0x%x dynamic 33",
1085 rei.preserved_data_max_len);
1086 run_command(cmd, 0);
1087 sprintf(cmd, "ubi write 0x%x transition 0x%x",
1088 rei.preserved_data, rei.preserved_data_max_len);
1089 run_command(cmd, 0);
1090 }
1091 if (rei.recovery_data_len) {
1092 sprintf(cmd, "ubi create recovery 0x%x dynamic 34",
1093 rei.recovery_data_len + (void *)rei.recovery_data_buf -
1094 (void *)rei.recovery_chunks_list);
1095 run_command(cmd, 0);
1096 sprintf(cmd, "ubi write 0x%x recovery 0x%x",
1097 rei.recovery_chunks_list,
1098 rei.recovery_data_len + (void *)rei.recovery_data_buf -
1099 (void *)rei.recovery_chunks_list);
1100 run_command(cmd, 0);
1101 }
1102 }
1103
1104 void reimage_splice_env(struct reimager *r, char *more_env, int more_env_size)
1105 {
1106 char *bp;
1107 int i;
1108 for (bp = r->loader_payload;
1109 bp <
1110 r->loader_payload + r->blocksizeK * 1024 * r->loader_blocks;
1111 bp += 4096) {
1112 int *tenv;
1113 env_t *ep;
1114 uint32_t new, crc;
1115 tenv = (int *)bp;
1116 printf("env check at %x\r", bp - r->loader_payload);
1117 if (tenv[0] == BOOT_MAGIC_MAGIC) {
1118 printf("\nGOT IT\n");
1119 ep = (env_t *) & tenv[2];
1120 memcpy(&crc, &ep->crc, sizeof(crc));
1121 /* specifically use uboot's env crc function
1122 * even though we have included the standard
1123 * linux crc32 */
1124 new = the_env_crc32(0, ep->data, tenv[1] - 4);
1125 if (new != crc) {
1126 printf("bad\n");
1127 } else {
1128 printf("good\n");
1129
1130 for (i = 0; i < tenv[1] - 4; i++) {
1131 if ((ep->data[i] == '\0')
1132 && (ep->data[i + 1] == '\0')) {
1133 memcpy(&ep->data[i + 1],
1134 more_env, more_env_size);
1135 break;
1136 }
1137 }
1138 new = the_env_crc32(0, ep->data, tenv[1] - 4);
1139 memcpy(&ep->crc, &new, sizeof(new));
1140 }
1141 }
1142 }
1143 }
1144
1145 static char usage[] = "line 1...\n" "line 2...\n";
1146
1147 U_BOOT_CMD_WITH_SUBCMDS(safeimage, "safe reimage commands", usage,
1148 U_BOOT_SUBCMD_MKENT(commit, 5, 0, do_commit),
1149 U_BOOT_SUBCMD_MKENT(flashback, 5, 0, do_flashback),
1150 U_BOOT_SUBCMD_MKENT(read_recovery, 5, 0,
1151 do_read_recovery),
1152 U_BOOT_SUBCMD_MKENT(revertable, 5, 0, do_revertable),
1153 U_BOOT_SUBCMD_MKENT(nvram, 1, 0, do_nvram_parse),
1154 U_BOOT_SUBCMD_MKENT(store_preserved, 1, 0,
1155 do_store_preserved));
1156
1157 U_BOOT_CMD_WITH_SUBCMDS(reimage, "reimage commands", usage,
1158 U_BOOT_SUBCMD_MKENT(auto, 1, 0, do_reimage_auto),
1159 U_BOOT_SUBCMD_MKENT(finish, 5, 0, do_finish),
1160 U_BOOT_SUBCMD_MKENT(prepare, 5, 0, do_prepare),
1161 U_BOOT_SUBCMD_MKENT(nvram, 1, 0, do_nvram_parse));
1162
1163 U_BOOT_CMD_WITH_SUBCMDS(preserve, "preserve data commands", usage,
1164 U_BOOT_SUBCMD_MKENT(allocate, 5, 0,
1165 do_preserve_allocate),
1166 U_BOOT_SUBCMD_MKENT(save, 5, 0, do_preserve_save));