diff options
Diffstat (limited to 'cmd/fuse.c')
-rw-r--r-- | cmd/fuse.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/cmd/fuse.c b/cmd/fuse.c new file mode 100644 index 00000000000..e2206cdf0d5 --- /dev/null +++ b/cmd/fuse.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2009-2013 ADVANSEE + * Benoît Thébaudeau <benoit.thebaudeau@advansee.com> + * + * Based on the mpc512x iim code: + * Copyright 2008 Silicon Turnkey Express, Inc. + * Martha Marx <mmarx@silicontkx.com> + */ + +#include <command.h> +#include <console.h> +#include <fuse.h> +#include <mapmem.h> +#include <vsprintf.h> +#include <linux/errno.h> +#include <linux/string.h> + +static int confirm_prog(void) +{ + puts("Warning: Programming fuses is an irreversible operation!\n" + " This may brick your system.\n" + " Use this command only if you are sure of " + "what you are doing!\n" + "\nReally perform this fuse programming? <y/N>\n"); + + if (confirm_yesno()) + return 1; + + puts("Fuse programming aborted\n"); + return 0; +} + +static int do_fuse(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + const char *op = cmd_arg1(argc, argv); + int confirmed = argc >= 3 && !strcmp(argv[2], "-y"); + u32 bank, word, cnt, val, cmp; + ulong addr; + void *buf, *start; + int ret, i; + + argc -= 2 + confirmed; + argv += 2 + confirmed; + + if (IS_ENABLED(CONFIG_CMD_FUSE_WRITEBUFF) && !strcmp(op, "writebuff")) { + if (argc == 1) + addr = simple_strtoul(argv[0], NULL, 16); + else + return CMD_RET_USAGE; + } else { + if (argc < 2) + return CMD_RET_USAGE; + + bank = simple_strtoul(argv[0], NULL, 0); + word = simple_strtoul(argv[1], NULL, 0); + } + + if (!strcmp(op, "read")) { + if (argc == 2) + cnt = 1; + else if (argc == 3) + cnt = simple_strtoul(argv[2], NULL, 0); + else + return CMD_RET_USAGE; + + printf("Reading bank %u:\n", bank); + for (i = 0; i < cnt; i++, word++) { + if (!(i % 4)) + printf("\nWord 0x%.8x:", word); + + ret = fuse_read(bank, word, &val); + if (ret) + goto err; + + printf(" %.8x", val); + } + putc('\n'); + } else if (!strcmp(op, "readm")) { + if (argc == 3) + cnt = 1; + else if (argc == 4) + cnt = simple_strtoul(argv[3], NULL, 0); + else + return CMD_RET_USAGE; + + addr = simple_strtoul(argv[2], NULL, 16); + + start = map_sysmem(addr, 4); + buf = start; + + printf("Reading bank %u len %u to 0x%lx\n", bank, cnt, addr); + for (i = 0; i < cnt; i++, word++) { + ret = fuse_read(bank, word, &val); + if (ret) + goto err; + + *((u32 *)buf) = val; + buf += 4; + } + + unmap_sysmem(start); + } else if (!strcmp(op, "cmp")) { + if (argc == 3) + cmp = simple_strtoul(argv[2], NULL, 0); + else + return CMD_RET_USAGE; + + printf("Comparing bank %u:\n", bank); + printf("\nWord 0x%.8x:", word); + printf("\nValue 0x%.8x:", cmp); + + ret = fuse_read(bank, word, &val); + if (ret) + goto err; + + printf("0x%.8x\n", val); + if (val != cmp) { + printf("failed\n"); + return CMD_RET_FAILURE; + } + printf("passed\n"); + } else if (!strcmp(op, "sense")) { + if (argc == 2) + cnt = 1; + else if (argc == 3) + cnt = simple_strtoul(argv[2], NULL, 0); + else + return CMD_RET_USAGE; + + printf("Sensing bank %u:\n", bank); + for (i = 0; i < cnt; i++, word++) { + if (!(i % 4)) + printf("\nWord 0x%.8x:", word); + + ret = fuse_sense(bank, word, &val); + if (ret) + goto err; + + printf(" %.8x", val); + } + putc('\n'); + } else if (!strcmp(op, "prog")) { + if (argc < 3) + return CMD_RET_USAGE; + + for (i = 2; i < argc; i++, word++) { + val = simple_strtoul(argv[i], NULL, 16); + + printf("Programming bank %u word 0x%.8x to 0x%.8x...\n", + bank, word, val); + if (!confirmed && !confirm_prog()) + return CMD_RET_FAILURE; + ret = fuse_prog(bank, word, val); + if (ret) + goto err; + } + } else if (!strcmp(op, "override")) { + if (argc < 3) + return CMD_RET_USAGE; + + for (i = 2; i < argc; i++, word++) { + val = simple_strtoul(argv[i], NULL, 16); + + printf("Overriding bank %u word 0x%.8x with " + "0x%.8x...\n", bank, word, val); + ret = fuse_override(bank, word, val); + if (ret) + goto err; + } + } else if (IS_ENABLED(CONFIG_CMD_FUSE_WRITEBUFF) && !strcmp(op, "writebuff")) { + printf("Programming fuses using a structured buffer in memory " + "starting at addr 0x%lx\n", addr); + if (!confirmed && !confirm_prog()) + return CMD_RET_FAILURE; + + ret = fuse_writebuff(addr); + if (ret) + goto err; + } else { + return CMD_RET_USAGE; + } + + return 0; + +err: + puts("ERROR\n"); + return CMD_RET_FAILURE; +} + +U_BOOT_CMD( + fuse, CONFIG_SYS_MAXARGS, 0, do_fuse, + "Fuse sub-system", + "read <bank> <word> [<cnt>] - read 1 or 'cnt' fuse words,\n" + " starting at 'word'\n" + "fuse cmp <bank> <word> <hexval> - compare 'hexval' to fuse\n" + " at 'word'\n" + "fuse readm <bank> <word> <addr> [<cnt>] - read 1 or 'cnt' fuse words,\n" + " starting at 'word' into memory at 'addr'\n" + "fuse sense <bank> <word> [<cnt>] - sense 1 or 'cnt' fuse words,\n" + " starting at 'word'\n" + "fuse prog [-y] <bank> <word> <hexval> [<hexval>...] - program 1 or\n" + " several fuse words, starting at 'word' (PERMANENT)\n" + "fuse override <bank> <word> <hexval> [<hexval>...] - override 1 or\n" + " several fuse words, starting at 'word'\n" +#ifdef CONFIG_CMD_FUSE_WRITEBUFF + "fuse writebuff [-y] <addr> - program fuse data\n" + " using a structured buffer in memory starting at 'addr'\n" +#endif /* CONFIG_CMD_FUSE_WRITEBUFF */ +); |