diff options
| author | Benoît Thébaudeau <benoit.thebaudeau@advansee.com> | 2013-04-23 10:17:40 +0000 | 
|---|---|---|
| committer | Stefano Babic <sbabic@denx.de> | 2013-04-28 11:07:40 +0200 | 
| commit | ccca7dfd0273af41e5b4bdec7f8731b177a20fde (patch) | |
| tree | 015f9912580d549ea1605d967d9ea56adf4ca161 | |
| parent | 6adbd30203a2839894d9b61f810d9fedc25a64ff (diff) | |
| download | olio-uboot-2014.01-ccca7dfd0273af41e5b4bdec7f8731b177a20fde.tar.xz olio-uboot-2014.01-ccca7dfd0273af41e5b4bdec7f8731b177a20fde.zip | |
Add fuse API and commands
This can be useful for fuse-like hardware, OTP SoC options, etc.
Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
| -rw-r--r-- | README | 1 | ||||
| -rw-r--r-- | common/Makefile | 1 | ||||
| -rw-r--r-- | common/cmd_fuse.c | 168 | ||||
| -rw-r--r-- | doc/README.fuse | 67 | ||||
| -rw-r--r-- | include/config_cmd_all.h | 1 | ||||
| -rw-r--r-- | include/fuse.h | 44 | 
6 files changed, 282 insertions, 0 deletions
| @@ -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 0e0fff1ff..1cfb13210 100644 --- a/common/Makefile +++ b/common/Makefile @@ -111,6 +111,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 000000000..f24c01c2d --- /dev/null +++ b/common/cmd_fuse.c @@ -0,0 +1,168 @@ +/* + * (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> + * + * 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, 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")) { +		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(bank, word, &val); +			if (ret) +				goto err; + +			printf(" %.8x", val); +		} +		putc('\n'); +	} else if (!strcmp(op, "sense")) { +		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(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++) { +			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(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++) { +			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(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 <bank> <word> [<cnt>] - read 1 or 'cnt' fuse words,\n" +	"    starting at 'word'\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'" +); diff --git a/doc/README.fuse b/doc/README.fuse new file mode 100644 index 000000000..1bc91c44a --- /dev/null +++ b/doc/README.fuse @@ -0,0 +1,67 @@ +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. + +Functions / commands: + +   int fuse_read(u32 bank, u32 word, u32 *val); +   fuse read <bank> <word> [<cnt>] +      Read fuse words from the shadow cache. + +   int fuse_sense(u32 bank, u32 word, u32 *val); +   fuse sense <bank> <word> [<cnt>] +      Sense - i.e. read directly from the fusebox, skipping the shadow cache - +      fuse words. This operation does not update the shadow cache. + +      This is useful to know the true value of fuses if an override has been +      performed (see below). + +   int fuse_prog(u32 bank, u32 word, u32 val); +   fuse prog [-y] <bank> <word> <hexval> [<hexval>...] +      Program fuse words. This operation directly affects the fusebox and is +      irreversible. The shadow cache is updated accordingly or not, depending on +      each IP. + +      Only the bits to be programmed should be set in the input value (i.e. for +      fuse bits that have already been programmed and hence should be left +      unchanged by a further programming, it is preferable to clear the +      corresponding bits in the input value in order not to perform a new +      hardware programming operation on these fuse bits). + +   int fuse_override(u32 bank, u32 word, u32 val); +   fuse override <bank> <word> <hexval> [<hexval>...] +      Override 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 53a2f054f..d84706969 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 000000000..b96413740 --- /dev/null +++ b/include/fuse.h @@ -0,0 +1,44 @@ +/* + * (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> + * + * 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 + *   val:     Value to read/write + * + *   Returns: 0 on success, not 0 on failure + */ +int fuse_read(u32 bank, u32 word, u32 *val); +int fuse_sense(u32 bank, u32 word, u32 *val); +int fuse_prog(u32 bank, u32 word, u32 val); +int fuse_override(u32 bank, u32 word, u32 val); + +#endif	/* _FUSE_H_ */ |