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:
parent
6adbd30203
commit
ccca7dfd02
1
README
1
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
|
||||
|
@ -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
168
common/cmd_fuse.c
Normal 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
67
doc/README.fuse
Normal 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.
|
@ -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
44
include/fuse.h
Normal 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_ */
|
Loading…
Reference in New Issue
Block a user