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>
This commit is contained in:
Benoît Thébaudeau 2013-04-23 10:17:40 +00:00 committed by Stefano Babic
parent 6adbd30203
commit ccca7dfd02
6 changed files with 282 additions and 0 deletions

1
README
View file

@ -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

View file

@ -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

168
common/cmd_fuse.c Normal file
View file

@ -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'"
);

67
doc/README.fuse Normal file
View file

@ -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.

View file

@ -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 */

44
include/fuse.h Normal file
View file

@ -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_ */