Add Broadcom / Netgear changes from RAXE 1.0.0.48
[project/bcm63xx/u-boot.git] / board / broadcom / bcmbca / flashback.c
diff --git a/board/broadcom/bcmbca/flashback.c b/board/broadcom/bcmbca/flashback.c
new file mode 100644 (file)
index 0000000..40cc079
--- /dev/null
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 Broadcom Ltd.
+ */
+
+#include <common.h>
+
+#include <asm/arch/ddr.h>
+#include <linux/ctype.h>
+#include <mtd.h>
+#include <nand.h>
+#include <stdlib.h>
+#include <string.h>
+#include <environment.h>
+#include <cli.h>
+#include <linux/bitops.h>
+#include <linux/crc32.h>
+#include <ubi_uboot.h>
+#include "bca_common.h"
+#include "bca_sdk.h"
+#include "spl_env.h"
+
+struct recovery_chunks {
+       int flashpage;          // page in flash
+       int size;               // number of bytes before fill
+       int type;               // 0x0= fill with 0xff, 0x1 = fill with 0x00, 0x7fffffff = END
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int erase(struct mtd_info *mtd, int first, int blocks);
+
+static int erase(struct mtd_info *mtd, int first, int blocks)
+{
+       struct erase_info erase_op = { };
+       int ret;
+
+       erase_op.mtd = mtd;
+       erase_op.addr = first * mtd->erasesize;
+       erase_op.len = blocks * mtd->erasesize;
+       erase_op.scrub = 0;
+       printf("Erasing %d blocks from block %d\n", blocks, first);
+
+       while (erase_op.len) {
+               ret = mtd_erase(mtd, &erase_op);
+
+               /* Abort if its not a bad block error */
+               if (ret != -EIO)
+                       break;
+
+               printf("Skipping bad block at 0x%08llx\n", erase_op.fail_addr);
+
+               /* Skip bad block and continue behind it */
+               erase_op.len -= erase_op.fail_addr - erase_op.addr;
+               erase_op.len -= mtd->erasesize;
+               erase_op.addr = erase_op.fail_addr + mtd->erasesize;
+       }
+
+       if (ret && ret != -EIO)
+               ret = -1;
+       else
+               ret = 0;
+       return (ret);
+};
+
+
+static int do_flashback(cmd_tbl_t * cmdtp, int flag, int argc,
+                       char *const argv[]);
+static int do_flashback(cmd_tbl_t * cmdtp, int flag, int argc,
+                       char *const argv[])
+{
+       struct mtd_info *mtd = NULL;
+       struct recovery_chunks *recovery_chunks_list = CONFIG_SYS_LOAD_ADDR;
+       long offset;
+       int i;
+       size_t sz = 0;
+       int blocks, pages;
+       int ret = 0;
+       char *bp;
+       int chunk;
+       mtd = get_mtd_device_nm("nand0");
+       blocks = (mtd->size / mtd->erasesize);
+       pages = (mtd->erasesize / mtd->writesize);
+       erase(mtd, 0, blocks);
+       chunk = 0;
+       bp = &recovery_chunks_list[blocks * pages + 1];
+       while (recovery_chunks_list[chunk].type < 0x1000) {
+               i = mtd_write(mtd,
+                             recovery_chunks_list[chunk].flashpage *
+                             mtd->writesize, mtd->writesize, &sz, bp);
+               bp += recovery_chunks_list[chunk].size;
+               chunk++;
+               printf("%d ", chunk);
+       }
+       put_mtd_device(mtd);
+       return(0);
+}
+
+static char usage[] = "line 1...\n" "line 2...\n";
+
+U_BOOT_CMD_WITH_SUBCMDS(flashback_ops, "flashback commands", usage,
+                       U_BOOT_SUBCMD_MKENT(go_flashback, 1, 0, do_flashback)
+                                           );
+
+