[U-Boot] [PATCH v3 3/7] Add fuse API and commands
Benoît Thébaudeau
benoit.thebaudeau at advansee.com
Tue Mar 26 22:24:52 CET 2013
This can be useful for fuse-like hardware, OTP SoC options, etc.
Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau at advansee.com>
---
Changes in v3:
- Rebase against latest u-boot-imx/master.
- Update copyright years.
- Rename the "ovride" command to "override" as it is nicer to read.
- For obvious safety reasons, ask the user to confirm each fuse programming
operation, unless the '-y' command line option was given, which can be used
in scripts.
- Rename "row" to "word" since it is less confusing and it is vocabulary common
to iim and ocotp in the reference manuals.
- Add doc/README.fuse.
Changes in v2:
- Rebase against latest master.
README | 1 +
common/Makefile | 1 +
common/cmd_fuse.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++
doc/README.fuse | 73 ++++++++++++++++
include/config_cmd_all.h | 1 +
include/fuse.h | 49 +++++++++++
6 files changed, 339 insertions(+)
create mode 100644 common/cmd_fuse.c
create mode 100644 doc/README.fuse
create mode 100644 include/fuse.h
diff --git a/README b/README
index e45ae4a..14ab9df 100644
--- a/README
+++ b/README
@@ -844,6 +844,7 @@ The following options need to be configured:
CONFIG_CMD_FDOS * Dos diskette Support
CONFIG_CMD_FLASH flinfo, erase, protect
CONFIG_CMD_FPGA FPGA device initialization support
+ CONFIG_CMD_FUSE Device fuse support
CONFIG_CMD_GETTIME * Get time since boot
CONFIG_CMD_GO * the 'go' command (exec code)
CONFIG_CMD_GREPENV * search environment
diff --git a/common/Makefile b/common/Makefile
index 719fc23..7207ad7 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -105,6 +105,7 @@ ifdef CONFIG_FPGA
COBJS-$(CONFIG_CMD_FPGA) += cmd_fpga.o
endif
COBJS-$(CONFIG_CMD_FS_GENERIC) += cmd_fs.o
+COBJS-$(CONFIG_CMD_FUSE) += cmd_fuse.o
COBJS-$(CONFIG_CMD_GETTIME) += cmd_gettime.o
COBJS-$(CONFIG_CMD_GPIO) += cmd_gpio.o
COBJS-$(CONFIG_CMD_I2C) += cmd_i2c.o
diff --git a/common/cmd_fuse.c b/common/cmd_fuse.c
new file mode 100644
index 0000000..862efda
--- /dev/null
+++ b/common/cmd_fuse.c
@@ -0,0 +1,214 @@
+/*
+ * (C) Copyright 2009-2013 ADVANSEE
+ * Benoît Thébaudeau <benoit.thebaudeau at advansee.com>
+ *
+ * Based on the mpc512x iim code:
+ * Copyright 2008 Silicon Turnkey Express, Inc.
+ * Martha Marx <mmarx at silicontkx.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <fuse.h>
+#include <asm/errno.h>
+
+static int strtou32(const char *str, unsigned int base, u32 *result)
+{
+ char *ep;
+
+ *result = simple_strtoul(str, &ep, base);
+ if (ep == str || *ep != '\0')
+ return -EINVAL;
+
+ return 0;
+}
+
+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 (getc() == 'y') {
+ int c;
+
+ putc('y');
+ c = getc();
+ putc('\n');
+ if (c == '\r')
+ return 1;
+ }
+
+ puts("Fuse programming aborted\n");
+ return 0;
+}
+
+static int do_fuse(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ const char *op = argc >= 2 ? argv[1] : NULL;
+ int confirmed = argc >= 3 && !strcmp(argv[2], "-y");
+ u32 bank, word, bit, cnt, val;
+ int ret, i;
+
+ argc -= 2 + confirmed;
+ argv += 2 + confirmed;
+
+ if (argc < 2 || strtou32(argv[0], 0, &bank) ||
+ strtou32(argv[1], 0, &word))
+ return CMD_RET_USAGE;
+
+ if (!strcmp(op, "read.bit")) {
+ if (argc != 3 || strtou32(argv[2], 0, &bit))
+ return CMD_RET_USAGE;
+
+ printf("Reading bank %u word 0x%.8x bit %u: ", bank, word, bit);
+ ret = fuse_read_bit(bank, word, bit, &val);
+ if (ret)
+ goto err;
+
+ printf("%u\n", val);
+ } else if (!strcmp(op, "read.word")) {
+ if (argc == 2)
+ cnt = 1;
+ else if (argc != 3 || strtou32(argv[2], 0, &cnt))
+ 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_word(bank, word, &val);
+ if (ret)
+ goto err;
+
+ printf(" %.8x", val);
+ }
+ putc('\n');
+ } else if (!strcmp(op, "sense.bit")) {
+ if (argc != 3 || strtou32(argv[2], 0, &bit))
+ return CMD_RET_USAGE;
+
+ printf("Sensing bank %u word 0x%.8x bit %u: ", bank, word, bit);
+ ret = fuse_sense_bit(bank, word, bit, &val);
+ if (ret)
+ goto err;
+
+ printf("%u\n", val);
+ } else if (!strcmp(op, "sense.word")) {
+ if (argc == 2)
+ cnt = 1;
+ else if (argc != 3 || strtou32(argv[2], 0, &cnt))
+ 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_word(bank, word, &val);
+ if (ret)
+ goto err;
+
+ printf(" %.8x", val);
+ }
+ putc('\n');
+ } else if (!strcmp(op, "prog.bit")) {
+ if (argc != 3 || strtou32(argv[2], 0, &bit))
+ return CMD_RET_USAGE;
+
+ printf("Programming bank %u word 0x%.8x bit %u...\n",
+ bank, word, bit);
+ if (!confirmed && !confirm_prog())
+ return CMD_RET_FAILURE;
+ ret = fuse_prog_bit(bank, word, bit);
+ if (ret)
+ goto err;
+ } else if (!strcmp(op, "prog.word")) {
+ if (argc < 3)
+ return CMD_RET_USAGE;
+
+ for (i = 2; i < argc; i++, word++) {
+ if (strtou32(argv[i], 16, &val))
+ return CMD_RET_USAGE;
+
+ 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_word(bank, word, val);
+ if (ret)
+ goto err;
+ }
+ } else if (!strcmp(op, "override.bit")) {
+ if (argc != 4 || strtou32(argv[2], 0, &bit) ||
+ strtou32(argv[3], 0, &val) || val > 1)
+ return CMD_RET_USAGE;
+
+ printf("Overriding bank %u word 0x%.8x bit %u with %u...\n",
+ bank, word, bit, val);
+ ret = fuse_override_bit(bank, word, bit, val);
+ if (ret)
+ goto err;
+ } else if (!strcmp(op, "override.word")) {
+ if (argc < 3)
+ return CMD_RET_USAGE;
+
+ for (i = 2; i < argc; i++, word++) {
+ if (strtou32(argv[i], 16, &val))
+ return CMD_RET_USAGE;
+
+ printf("Overriding bank %u word 0x%.8x with "
+ "0x%.8x...\n", bank, word, val);
+ ret = fuse_override_word(bank, word, val);
+ if (ret)
+ goto err;
+ }
+ } else {
+ return CMD_RET_USAGE;
+ }
+
+ return 0;
+
+err:
+ puts("ERROR\n");
+ return ret;
+}
+
+U_BOOT_CMD(
+ fuse, CONFIG_SYS_MAXARGS, 0, do_fuse,
+ "Fuse sub-system",
+ "read.bit <bank> <word> <bit> - read a fuse bit\n"
+ "fuse read.word <bank> <word> [<cnt>] - read 1 or 'cnt' fuse words,\n"
+ " starting at 'word'\n"
+ "fuse sense.bit <bank> <word> <bit> - sense a fuse bit\n"
+ "fuse sense.word <bank> <word> [<cnt>] - sense 1 or 'cnt' fuse words,\n"
+ " starting at 'word'\n"
+ "fuse prog.bit [-y] <bank> <word> <bit> - program a fuse bit\n"
+ " (PERMANENT)\n"
+ "fuse prog.word [-y] <bank> <word> <hexval> [<hexval>...] - program 1\n"
+ " or several fuse words, starting at 'word' (PERMANENT)\n"
+ "fuse override.bit <bank> <word> <bit> <val> - override a fuse bit\n"
+ "fuse override.word <bank> <word> <hexval> [<hexval>...] - override 1\n"
+ " or several fuse words, starting at 'word'"
+);
diff --git a/doc/README.fuse b/doc/README.fuse
new file mode 100644
index 0000000..ee365ff
--- /dev/null
+++ b/doc/README.fuse
@@ -0,0 +1,73 @@
+Fuse API functions and commands
+
+The fuse API allows to control a fusebox and how it is used by the upper
+hardware layers.
+
+A fuse corresponds to a single non-volatile memory bit that can be programmed
+(i.e. blown, set to 1) only once. The programming operation is irreversible. A
+fuse that has not been programmed reads 0.
+
+Fuses can be used by SoCs to store various permanent configuration and data,
+e.g. boot configuration, security configuration, MAC addresses, etc.
+
+A fuse word is the smallest group of fuses that can be read at once from the
+fusebox control IP registers. This is limited to 32 bits with the current API.
+
+A fuse bank is the smallest group of fuse words having a common ID, as defined
+by each SoC.
+
+Upon startup, the fusebox control IP reads the fuse values and stores them to a
+volatile shadow cache.
+
+See the README files of the drivers implementing this API in order to know the
+SoC- and implementation-specific details.
+
+The API provides both bit and word accesses because the access type may change
+depending on the IP, and it is safer to manipulate only bits (when no more is
+needed) in order to avoid programming a wrong value.
+
+Functions / commands:
+
+ int fuse_read_bit(u32 bank, u32 word, u32 bit, u32 *val);
+ fuse read.bit <bank> <word> <bit>
+ int fuse_read_word(u32 bank, u32 word, u32 *val);
+ fuse read.word <bank> <word> [<cnt>]
+ Read a fuse bit or fuse words from the shadow cache.
+
+ int fuse_sense_bit(u32 bank, u32 word, u32 bit, u32 *val);
+ fuse sense.bit <bank> <word> <bit>
+ int fuse_sense_word(u32 bank, u32 word, u32 *val);
+ fuse sense.word <bank> <word> [<cnt>]
+ Sense - i.e. read directly from the fusebox, skipping the shadow cache - a
+ fuse bit or fuse words. This operation does not update the shadow cache.
+
+ This is useful to know the true value of a fuse if an override has been
+ performed (see below).
+
+ int fuse_prog_bit(u32 bank, u32 word, u32 bit);
+ fuse prog.bit [-y] <bank> <word> <bit>
+ int fuse_prog_word(u32 bank, u32 word, u32 val);
+ fuse prog.word [-y] <bank> <word> <hexval> [<hexval>...]
+ Program a fuse bit or fuse words. This operation directly affects the
+ fusebox and is irreversible. The shadow cache is updated accordingly or
+ not, depending on each IP.
+
+ int fuse_override_bit(u32 bank, u32 word, u32 bit, u32 val);
+ fuse override.bit <bank> <word> <bit> <val>
+ int fuse_override_word(u32 bank, u32 word, u32 val);
+ fuse override.word <bank> <word> <hexval> [<hexval>...]
+ Override a fuse bit or fuse words in the shadow cache.
+
+ The fusebox is unaffected, so following this operation, the shadow cache
+ may differ from the fusebox values. Read or sense operations can then be
+ used to get the values from the shadow cache or from the fusebox.
+
+ This is useful to change the behaviors linked to some cached fuse values,
+ either because this is needed only temporarily, or because some of the
+ fuses have already been programmed or are locked (if the SoC allows to
+ override a locked fuse).
+
+Configuration:
+
+ CONFIG_CMD_FUSE
+ Define this to enable the fuse commands.
diff --git a/include/config_cmd_all.h b/include/config_cmd_all.h
index 0930781..041b18e 100644
--- a/include/config_cmd_all.h
+++ b/include/config_cmd_all.h
@@ -40,6 +40,7 @@
#define CONFIG_CMD_FDOS /* Floppy DOS support */
#define CONFIG_CMD_FLASH /* flinfo, erase, protect */
#define CONFIG_CMD_FPGA /* FPGA configuration Support */
+#define CONFIG_CMD_FUSE /* Device fuse support */
#define CONFIG_CMD_GETTIME /* Get time since boot */
#define CONFIG_CMD_HASH /* calculate hash / digest */
#define CONFIG_CMD_HWFLOW /* RTS/CTS hw flow control */
diff --git a/include/fuse.h b/include/fuse.h
new file mode 100644
index 0000000..97dc569
--- /dev/null
+++ b/include/fuse.h
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2009-2013 ADVANSEE
+ * Benoît Thébaudeau <benoit.thebaudeau at advansee.com>
+ *
+ * Based on the mpc512x iim code:
+ * Copyright 2008 Silicon Turnkey Express, Inc.
+ * Martha Marx <mmarx at silicontkx.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _FUSE_H_
+#define _FUSE_H_
+
+/*
+ * Read/Sense/Program/Override interface:
+ * bank: Fuse bank
+ * word: Fuse word within the bank
+ * bit: Fuse bit within the word
+ * val: Value to read/write
+ *
+ * Returns: 0 on success, not 0 on failure
+ */
+int fuse_read_bit(u32 bank, u32 word, u32 bit, u32 *val);
+int fuse_read_word(u32 bank, u32 word, u32 *val);
+int fuse_sense_bit(u32 bank, u32 word, u32 bit, u32 *val);
+int fuse_sense_word(u32 bank, u32 word, u32 *val);
+int fuse_prog_bit(u32 bank, u32 word, u32 bit);
+int fuse_prog_word(u32 bank, u32 word, u32 val);
+int fuse_override_bit(u32 bank, u32 word, u32 bit, u32 val);
+int fuse_override_word(u32 bank, u32 word, u32 val);
+
+#endif /* _FUSE_H_ */
--
1.7.10.4
More information about the U-Boot
mailing list