[U-Boot] [PATCH v3 1/7] imx: Homogenize and fix fuse register definitions

IIM: - Homogenize prg_p naming (the reference manuals are not always self-consistent for that). - Add missing SCSx and bank registers. - Fix the number of banks on i.MX53.
OCOTP: - Rename iim to ocotp in order to avoid confusion. - Rename fuse_data to read_fuse_data, and sticky to sw_sticky, according to the reference manual. - Merge the existing spinoff gp1 fuse definition on i.MX6. - Fix the number of banks on i.MX6.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com --- Changes in v3: - Rebase against latest u-boot-imx/master. - Fix the number of banks on i.MX6. - Rename iim to ocotp on i.MX6 in order to avoid confusion, and merge in the existing gp1 fuse definition. - Rename fuse_data to read_fuse_data, and sticky to sw_sticky, according to the reference manual.
Changes in v2: - Rebase against latest master.
arch/arm/cpu/armv7/mx6/soc.c | 4 ++-- arch/arm/include/asm/arch-mx25/imx-regs.h | 8 ++++++-- arch/arm/include/asm/arch-mx27/imx-regs.h | 2 +- arch/arm/include/asm/arch-mx31/imx-regs.h | 9 +++++++-- arch/arm/include/asm/arch-mx35/imx-regs.h | 7 ++++++- arch/arm/include/asm/arch-mx5/imx-regs.h | 6 +++++- arch/arm/include/asm/arch-mx6/imx-regs.h | 19 +++++++------------ board/freescale/mx6qsabreauto/mx6qsabreauto.c | 5 ++++- 8 files changed, 38 insertions(+), 22 deletions(-)
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 193ba12..dd32969 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -153,8 +153,8 @@ void enable_caches(void) #if defined(CONFIG_FEC_MXC) void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) { - struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; - struct fuse_bank *bank = &iim->bank[4]; + struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; + struct fuse_bank *bank = &ocotp->bank[4]; struct fuse_bank4_regs *fuse = (struct fuse_bank4_regs *)bank->fuse_regs;
diff --git a/arch/arm/include/asm/arch-mx25/imx-regs.h b/arch/arm/include/asm/arch-mx25/imx-regs.h index 5f4b543..99c32d4 100644 --- a/arch/arm/include/asm/arch-mx25/imx-regs.h +++ b/arch/arm/include/asm/arch-mx25/imx-regs.h @@ -113,8 +113,12 @@ struct iim_regs { u32 iim_sdat; u32 iim_prev; u32 iim_srev; - u32 iim_prog_p; - u32 res1[0x1f5]; + u32 iim_prg_p; + u32 iim_scs0; + u32 iim_scs1; + u32 iim_scs2; + u32 iim_scs3; + u32 res1[0x1f1]; struct fuse_bank { u32 fuse_regs[0x20]; u32 fuse_rsvd[0xe0]; diff --git a/arch/arm/include/asm/arch-mx27/imx-regs.h b/arch/arm/include/asm/arch-mx27/imx-regs.h index 2f6c823..aee058f 100644 --- a/arch/arm/include/asm/arch-mx27/imx-regs.h +++ b/arch/arm/include/asm/arch-mx27/imx-regs.h @@ -176,7 +176,7 @@ struct iim_regs { u32 iim_sdat; u32 iim_prev; u32 iim_srev; - u32 iim_prog_p; + u32 iim_prg_p; u32 iim_scs0; u32 iim_scs1; u32 iim_scs2; diff --git a/arch/arm/include/asm/arch-mx31/imx-regs.h b/arch/arm/include/asm/arch-mx31/imx-regs.h index 3f58318..f67f49c 100644 --- a/arch/arm/include/asm/arch-mx31/imx-regs.h +++ b/arch/arm/include/asm/arch-mx31/imx-regs.h @@ -68,7 +68,7 @@ struct cspi_regs { u32 test; };
-/* IIM Control Registers */ +/* IIM control registers */ struct iim_regs { u32 iim_stat; u32 iim_statm; @@ -80,11 +80,16 @@ struct iim_regs { u32 iim_sdat; u32 iim_prev; u32 iim_srev; - u32 iim_prog_p; + u32 iim_prg_p; u32 iim_scs0; u32 iim_scs1; u32 iim_scs2; u32 iim_scs3; + u32 res[0x1f1]; + struct fuse_bank { + u32 fuse_regs[0x20]; + u32 fuse_rsvd[0xe0]; + } bank[3]; };
struct iomuxc_regs { diff --git a/arch/arm/include/asm/arch-mx35/imx-regs.h b/arch/arm/include/asm/arch-mx35/imx-regs.h index 7f337be..64546d2 100644 --- a/arch/arm/include/asm/arch-mx35/imx-regs.h +++ b/arch/arm/include/asm/arch-mx35/imx-regs.h @@ -262,11 +262,16 @@ struct iim_regs { u32 iim_sdat; u32 iim_prev; u32 iim_srev; - u32 iim_prog_p; + u32 iim_prg_p; u32 iim_scs0; u32 iim_scs1; u32 iim_scs2; u32 iim_scs3; + u32 res1[0x1f1]; + struct fuse_bank { + u32 fuse_regs[0x20]; + u32 fuse_rsvd[0xe0]; + } bank[3]; };
/* General Purpose Timer (GPT) registers */ diff --git a/arch/arm/include/asm/arch-mx5/imx-regs.h b/arch/arm/include/asm/arch-mx5/imx-regs.h index 249d15a..f457b4e 100644 --- a/arch/arm/include/asm/arch-mx5/imx-regs.h +++ b/arch/arm/include/asm/arch-mx5/imx-regs.h @@ -498,7 +498,7 @@ struct iim_regs { u32 sdat; u32 prev; u32 srev; - u32 preg_p; + u32 prg_p; u32 scs0; u32 scs1; u32 scs2; @@ -507,7 +507,11 @@ struct iim_regs { struct fuse_bank { u32 fuse_regs[0x20]; u32 fuse_rsvd[0xe0]; +#if defined(CONFIG_MX51) } bank[4]; +#elif defined(CONFIG_MX53) + } bank[5]; +#endif };
struct fuse_bank0_regs { diff --git a/arch/arm/include/asm/arch-mx6/imx-regs.h b/arch/arm/include/asm/arch-mx6/imx-regs.h index eaa7439..cdaf5f8 100644 --- a/arch/arm/include/asm/arch-mx6/imx-regs.h +++ b/arch/arm/include/asm/arch-mx6/imx-regs.h @@ -171,7 +171,6 @@
#define CHIP_REV_1_0 0x10 #define IRAM_SIZE 0x00040000 -#define IMX_IIM_BASE OCOTP_BASE_ADDR #define FEC_QUIRK_ENET_MAC
#if !(defined(__KERNEL_STRICT_NAMES) || defined(__ASSEMBLY__)) @@ -200,12 +199,6 @@ struct src { u32 gpr10; };
-/* OCOTP Registers */ -struct ocotp_regs { - u32 reserved[0x198]; - u32 gp1; /* 0x660 */ -}; - /* GPR3 bitfields */ #define IOMUXC_GPR3_GPU_DBG_OFFSET 29 #define IOMUXC_GPR3_GPU_DBG_MASK (3<<IOMUXC_GPR3_GPU_DBG_OFFSET) @@ -371,7 +364,7 @@ struct cspi_regs { ECSPI4_BASE_ADDR, \ ECSPI5_BASE_ADDR
-struct iim_regs { +struct ocotp_regs { u32 ctrl; u32 ctrl_set; u32 ctrl_clr; @@ -382,9 +375,9 @@ struct iim_regs { u32 rsvd1[3]; u32 read_ctrl; u32 rsvd2[3]; - u32 fuse_data; + u32 read_fuse_data; u32 rsvd3[3]; - u32 sticky; + u32 sw_sticky; u32 rsvd4[3]; u32 scs; u32 scs_set; @@ -399,7 +392,7 @@ struct iim_regs {
struct fuse_bank { u32 fuse_regs[0x20]; - } bank[15]; + } bank[16]; };
struct fuse_bank4_regs { @@ -410,7 +403,9 @@ struct fuse_bank4_regs { u32 mac_addr_low; u32 rsvd2[3]; u32 mac_addr_high; - u32 rsvd3[0x13]; + u32 rsvd3[0xb]; + u32 gp1; + u32 rsvd4[7]; };
struct aipstz_regs { diff --git a/board/freescale/mx6qsabreauto/mx6qsabreauto.c b/board/freescale/mx6qsabreauto/mx6qsabreauto.c index 91cc007..d7ac62a 100644 --- a/board/freescale/mx6qsabreauto/mx6qsabreauto.c +++ b/board/freescale/mx6qsabreauto/mx6qsabreauto.c @@ -178,7 +178,10 @@ static int mx6sabre_rev(void) * i.MX6Q ARD RevB: 0x02 */ struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; - int reg = readl(&ocotp->gp1); + struct fuse_bank *bank = &ocotp->bank[4]; + struct fuse_bank4_regs *fuse = + (struct fuse_bank4_regs *)bank->fuse_regs; + int reg = readl(&fuse->gp1); int ret;
switch (reg >> 8 & 0x0F) {

Define the UID (SoC unique ID) fuses, and the fuses available for the user.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com --- Changes in v3: - Add i.MX6 GP2.
Changes in v2: - Rebase against latest master.
arch/arm/include/asm/arch-mx25/imx-regs.h | 11 ++++++++++- arch/arm/include/asm/arch-mx31/imx-regs.h | 12 ++++++++++++ arch/arm/include/asm/arch-mx35/imx-regs.h | 12 ++++++++++++ arch/arm/include/asm/arch-mx5/imx-regs.h | 16 +++++++++++++++- arch/arm/include/asm/arch-mx6/imx-regs.h | 4 +++- 5 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/arch/arm/include/asm/arch-mx25/imx-regs.h b/arch/arm/include/asm/arch-mx25/imx-regs.h index 99c32d4..cf7bb5a 100644 --- a/arch/arm/include/asm/arch-mx25/imx-regs.h +++ b/arch/arm/include/asm/arch-mx25/imx-regs.h @@ -126,10 +126,19 @@ struct iim_regs { };
struct fuse_bank0_regs { - u32 fuse0_25[0x1a]; + u32 fuse0_7[8]; + u32 uid[8]; + u32 fuse16_25[0xa]; u32 mac_addr[6]; };
+struct fuse_bank1_regs { + u32 fuse0_21[0x16]; + u32 usr5; + u32 fuse23_29[7]; + u32 usr6[2]; +}; + /* Multi-Layer AHB Crossbar Switch (MAX) registers */ struct max_regs { u32 mpr0; diff --git a/arch/arm/include/asm/arch-mx31/imx-regs.h b/arch/arm/include/asm/arch-mx31/imx-regs.h index f67f49c..5d8d8f4 100644 --- a/arch/arm/include/asm/arch-mx31/imx-regs.h +++ b/arch/arm/include/asm/arch-mx31/imx-regs.h @@ -92,6 +92,18 @@ struct iim_regs { } bank[3]; };
+struct fuse_bank0_regs { + u32 fuse0_5[6]; + u32 usr; + u32 fuse7_15[9]; +}; + +struct fuse_bank2_regs { + u32 fuse0; + u32 uid[8]; + u32 fuse9_15[7]; +}; + struct iomuxc_regs { u32 unused1; u32 unused2; diff --git a/arch/arm/include/asm/arch-mx35/imx-regs.h b/arch/arm/include/asm/arch-mx35/imx-regs.h index 64546d2..63c6e24 100644 --- a/arch/arm/include/asm/arch-mx35/imx-regs.h +++ b/arch/arm/include/asm/arch-mx35/imx-regs.h @@ -274,6 +274,18 @@ struct iim_regs { } bank[3]; };
+struct fuse_bank0_regs { + u32 fuse0_7[8]; + u32 uid[8]; + u32 fuse16_31[0x10]; +}; + +struct fuse_bank1_regs { + u32 fuse0_21[0x16]; + u32 usr; + u32 fuse23_31[9]; +}; + /* General Purpose Timer (GPT) registers */ struct gpt_regs { u32 ctrl; /* control */ diff --git a/arch/arm/include/asm/arch-mx5/imx-regs.h b/arch/arm/include/asm/arch-mx5/imx-regs.h index f457b4e..8fce11b 100644 --- a/arch/arm/include/asm/arch-mx5/imx-regs.h +++ b/arch/arm/include/asm/arch-mx5/imx-regs.h @@ -515,8 +515,14 @@ struct iim_regs { };
struct fuse_bank0_regs { - u32 fuse0_23[24]; + u32 fuse0_7[8]; + u32 uid[8]; + u32 fuse16_23[8]; +#if defined(CONFIG_MX51) + u32 imei[8]; +#elif defined(CONFIG_MX53) u32 gp[8]; +#endif };
struct fuse_bank1_regs { @@ -525,6 +531,14 @@ struct fuse_bank1_regs { u32 fuse15_31[0x11]; };
+#if defined(CONFIG_MX53) +struct fuse_bank4_regs { + u32 fuse0_4[5]; + u32 gp[3]; + u32 fuse8_31[0x18]; +}; +#endif + #endif /* __ASSEMBLER__*/
#endif /* __ASM_ARCH_MX5_IMX_REGS_H__ */ diff --git a/arch/arm/include/asm/arch-mx6/imx-regs.h b/arch/arm/include/asm/arch-mx6/imx-regs.h index cdaf5f8..efab943 100644 --- a/arch/arm/include/asm/arch-mx6/imx-regs.h +++ b/arch/arm/include/asm/arch-mx6/imx-regs.h @@ -405,7 +405,9 @@ struct fuse_bank4_regs { u32 mac_addr_high; u32 rsvd3[0xb]; u32 gp1; - u32 rsvd4[7]; + u32 rsvd4[3]; + u32 gp2; + u32 rsvd5[3]; };
struct aipstz_regs {

This can be useful for fuse-like hardware, OTP SoC options, etc.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@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@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, 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@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 + * 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_ */

Add a fsl_iim driver common to i.MX and MPC.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com --- Changes in v3: - Update copyright years. - 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.fsl_iim.
Changes in v2: - Rebase against latest master.
doc/README.fsl_iim | 51 ++++++++ drivers/misc/Makefile | 1 + drivers/misc/fsl_iim.c | 318 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 370 insertions(+) create mode 100644 doc/README.fsl_iim create mode 100644 drivers/misc/fsl_iim.c
diff --git a/doc/README.fsl_iim b/doc/README.fsl_iim new file mode 100644 index 0000000..2472521 --- /dev/null +++ b/doc/README.fsl_iim @@ -0,0 +1,51 @@ +Driver implementing the fuse API for Freescale's IC Identification Module (IIM) + +This IP can be found on the following SoCs: + - MPC512x, + - i.MX25, + - i.MX27, + - i.MX31, + - i.MX35, + - i.MX51, + - i.MX53. + +The section numbers in this file refer to the i.MX25 Reference Manual. + +A fuse word contains 8 fuse bit slots, as explained in 30.4.2.2.1. + +A bank contains 256 fuse word slots, as shown by the memory map in 30.3.1. + +Some fuse bit or word slots may not have the corresponding fuses actually +implemented in the fusebox. + +See the README files of the SoCs using this driver in order to know the +conventions used by U-Boot to store some specific data in the fuses, e.g. MAC +addresses. + +Fuse operations: + + Read + Read operations are implemented as read accesses to the shadow registers, + using "Word y of Bank x" from the register summary in 30.3.2. This is + explained in detail in 30.4.5.1. + + Sense + Sense operations are implemented as explained in 30.4.5.2. + + Program + Program operations are implemented as explained in 30.4.5.3. Following + this operation, the shadow registers are reloaded by the hardware (not + immediately, but this does not make any difference for a user reading + these registers). + + Override + Override operations are implemented as write accesses to the shadow + registers, as explained in 30.4.5.4. + +Configuration: + + CONFIG_FSL_IIM + Define this to enable the fsl_iim driver. + + CONFIG_SYS_FSL_IIM_ADDR + This should be defined to the base address of the IIM IP. diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 8cdc3b6..c6dadd4 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -28,6 +28,7 @@ LIB := $(obj)libmisc.o COBJS-$(CONFIG_ALI152X) += ali512x.o COBJS-$(CONFIG_DS4510) += ds4510.o COBJS-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o +COBJS-$(CONFIG_FSL_IIM) += fsl_iim.o COBJS-$(CONFIG_GPIO_LED) += gpio_led.o COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o COBJS-$(CONFIG_NS87308) += ns87308.o diff --git a/drivers/misc/fsl_iim.c b/drivers/misc/fsl_iim.c new file mode 100644 index 0000000..33b9c9a --- /dev/null +++ b/drivers/misc/fsl_iim.c @@ -0,0 +1,318 @@ +/* + * (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 <config.h> +#include <common.h> +#include <hwconfig.h> +#include <fuse.h> +#include <asm/errno.h> +#include <asm/byteorder.h> +#include <asm/io.h> + +/* FSL IIM-specific constants */ +#define STAT_BUSY 0x80 +#define STAT_PRGD 0x02 +#define STAT_SNSD 0x01 + +#define STATM_PRGD_M 0x02 +#define STATM_SNSD_M 0x01 + +#define ERR_PRGE 0x80 +#define ERR_WPE 0x40 +#define ERR_OPE 0x20 +#define ERR_RPE 0x10 +#define ERR_WLRE 0x08 +#define ERR_SNSE 0x04 +#define ERR_PARITYE 0x02 + +#define EMASK_PRGE_M 0x80 +#define EMASK_WPE_M 0x40 +#define EMASK_OPE_M 0x20 +#define EMASK_RPE_M 0x10 +#define EMASK_WLRE_M 0x08 +#define EMASK_SNSE_M 0x04 +#define EMASK_PARITYE_M 0x02 + +#define FCTL_DPC 0x80 +#define FCTL_PRG_LENGTH_MASK 0x70 +#define FCTL_ESNS_N 0x08 +#define FCTL_ESNS_0 0x04 +#define FCTL_ESNS_1 0x02 +#define FCTL_PRG 0x01 + +#define UA_A_BANK_MASK 0x38 +#define UA_A_ROWH_MASK 0x07 + +#define LA_A_ROWL_MASK 0xf8 +#define LA_A_BIT_MASK 0x07 + +#define PREV_PROD_REV_MASK 0xf8 +#define PREV_PROD_VT_MASK 0x07 + +/* Select the correct accessors depending on endianness */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define iim_read32 in_le32 +#define iim_write32 out_le32 +#define iim_clrsetbits32 clrsetbits_le32 +#define iim_clrbits32 clrbits_le32 +#define iim_setbits32 setbits_le32 +#elif __BYTE_ORDER == __BIG_ENDIAN +#define iim_read32 in_be32 +#define iim_write32 out_be32 +#define iim_clrsetbits32 clrsetbits_be32 +#define iim_clrbits32 clrbits_be32 +#define iim_setbits32 setbits_be32 +#else +#error "Endianess is not defined: please fix to continue" +#endif + +/* IIM control registers */ +struct fsl_iim { + u32 stat; + u32 statm; + u32 err; + u32 emask; + u32 fctl; + u32 ua; + u32 la; + u32 sdat; + u32 prev; + u32 srev; + u32 prg_p; + u32 scs[0x1f5]; + struct { + u32 word[0x100]; + } bank[8]; +}; + +int fuse_read_bit(u32 bank, u32 word, u32 bit, u32 *val) +{ + int ret; + + if (bit >= 8) { + puts("fsl_iim fuse read: Invalid argument\n"); + return -EINVAL; + } + + ret = fuse_read_word(bank, word, val); + if (ret) + return ret; + + *val = !!(*val & 1 << bit); + return 0; +} + +int fuse_read_word(u32 bank, u32 word, u32 *val) +{ + volatile struct fsl_iim *regs = + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; + u32 err; + + if (bank >= ARRAY_SIZE(regs->bank) || + word >= ARRAY_SIZE(regs->bank[0].word) || + val == NULL) { + puts("fsl_iim fuse read: Invalid argument\n"); + return -EINVAL; + } + + iim_write32(®s->err, iim_read32(®s->err)); + *val = iim_read32(®s->bank[bank].word[word]); + err = iim_read32(®s->err); + iim_write32(®s->err, iim_read32(®s->err)); + + if (err & ERR_RPE) { + puts("fsl_iim fuse read: Read protect error\n"); + return -EIO; + } + + return 0; +} + +int fuse_sense_bit(u32 bank, u32 word, u32 bit, u32 *val) +{ + int ret; + + if (bit >= 8) { + puts("fsl_iim fuse sense: Invalid argument\n"); + return -EINVAL; + } + + ret = fuse_sense_word(bank, word, val); + if (ret) + return ret; + + *val = !!(*val & 1 << bit); + return 0; +} + +int fuse_sense_word(u32 bank, u32 word, u32 *val) +{ + volatile struct fsl_iim *regs = + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; + u32 stat, err; + + if (bank >= ARRAY_SIZE(regs->bank) || + word >= ARRAY_SIZE(regs->bank[0].word) || + val == NULL) { + puts("fsl_iim fuse sense: Invalid argument\n"); + return -EINVAL; + } + + iim_write32(®s->stat, iim_read32(®s->stat)); + iim_write32(®s->err, iim_read32(®s->err)); + iim_write32(®s->ua, bank << 3 | word >> 5); + iim_write32(®s->la, word << 3 & 0xff); + iim_write32(®s->fctl, iim_read32(®s->fctl) | FCTL_ESNS_N); + while (iim_read32(®s->stat) & STAT_BUSY) + udelay(20); + stat = iim_read32(®s->stat); + err = iim_read32(®s->err); + iim_write32(®s->stat, iim_read32(®s->stat)); + iim_write32(®s->err, iim_read32(®s->err)); + + if (err & ERR_SNSE) { + puts("fsl_iim fuse sense: Explicit sense cycle error\n"); + return -EIO; + } + + if (!(stat & STAT_SNSD)) { + puts("fsl_iim fuse sense: Explicit sense cycle " + "did not complete\n"); + return -EIO; + } + + *val = iim_read32(®s->sdat); + return 0; +} + +int fuse_prog_bit(u32 bank, u32 word, u32 bit) +{ + volatile struct fsl_iim *regs = + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; + u32 stat, err; + + if (bank >= ARRAY_SIZE(regs->bank) || + word >= ARRAY_SIZE(regs->bank[0].word) || + bit >= 8) { + puts("fsl_iim fuse program: Invalid argument\n"); + return -EINVAL; + } + + iim_write32(®s->stat, iim_read32(®s->stat)); + iim_write32(®s->err, iim_read32(®s->err)); + iim_write32(®s->ua, bank << 3 | word >> 5); + iim_write32(®s->la, (word << 3 | bit) & 0xff); + iim_write32(®s->prg_p, 0xaa); + iim_write32(®s->fctl, iim_read32(®s->fctl) | FCTL_PRG); + while (iim_read32(®s->stat) & STAT_BUSY) + udelay(20); + stat = iim_read32(®s->stat); + err = iim_read32(®s->err); + iim_write32(®s->stat, iim_read32(®s->stat)); + iim_write32(®s->err, iim_read32(®s->err)); + iim_write32(®s->prg_p, 0x00); + + if (err & ERR_PRGE) { + puts("fsl_iim fuse program: Program error\n"); + return -EIO; + } + + if (err & ERR_WPE) { + puts("fsl_iim fuse program: Write protect error\n"); + return -EIO; + } + + if (!(stat & STAT_PRGD)) { + puts("fsl_iim fuse program: Program did not complete\n"); + return -EIO; + } + + return 0; +} + +int fuse_prog_word(u32 bank, u32 word, u32 val) +{ + int bit, ret; + + if (val & ~0xff) { + puts("fsl_iim fuse program: Invalid argument\n"); + return -EINVAL; + } + + for (bit = 0; val; bit++, val >>= 1) + if (val & 0x01) { + ret = fuse_prog_bit(bank, word, bit); + if (ret) + return ret; + } + + return 0; +} + +int fuse_override_bit(u32 bank, u32 word, u32 bit, u32 val) +{ + u32 word_val; + int ret; + + if (bit >= 8 || val > 1) { + puts("fsl_iim fuse override: Invalid argument\n"); + return -EINVAL; + } + + ret = fuse_read_word(bank, word, &word_val); + if (ret) + return ret; + + return fuse_override_word(bank, word, + (word_val & ~(1 << bit)) | val << bit); +} + +int fuse_override_word(u32 bank, u32 word, u32 val) +{ + volatile struct fsl_iim *regs = + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; + u32 err; + + if (bank >= ARRAY_SIZE(regs->bank) || + word >= ARRAY_SIZE(regs->bank[0].word) || + val & ~0xff) { + puts("fsl_iim fuse override: Invalid argument\n"); + return -EINVAL; + } + + iim_write32(®s->err, iim_read32(®s->err)); + iim_write32(®s->bank[bank].word[word], val); + err = iim_read32(®s->err); + iim_write32(®s->err, iim_read32(®s->err)); + + if (err & ERR_OPE) { + puts("fsl_iim fuse override: Override protect error\n"); + return -EIO; + } + + return 0; +}

Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com --- Changes in v3: None Changes in v2: - Rebase against latest master.
arch/powerpc/cpu/mpc512x/Makefile | 1 - arch/powerpc/cpu/mpc512x/iim.c | 394 ------------------------------- board/davedenx/aria/aria.c | 2 +- board/esd/mecp5123/mecp5123.c | 2 +- board/freescale/mpc5121ads/mpc5121ads.c | 2 +- board/pdm360ng/pdm360ng.c | 2 +- include/configs/aria.h | 2 +- include/configs/mecp5123.h | 2 +- include/configs/mpc5121ads.h | 2 +- 9 files changed, 7 insertions(+), 402 deletions(-) delete mode 100644 arch/powerpc/cpu/mpc512x/iim.c
diff --git a/arch/powerpc/cpu/mpc512x/Makefile b/arch/powerpc/cpu/mpc512x/Makefile index b53232f..4f4c9ec 100644 --- a/arch/powerpc/cpu/mpc512x/Makefile +++ b/arch/powerpc/cpu/mpc512x/Makefile @@ -38,7 +38,6 @@ COBJS-y += serial.o COBJS-y += speed.o COBJS-$(CONFIG_FSL_DIU_FB) += diu.o COBJS-$(CONFIG_CMD_IDE) += ide.o -COBJS-$(CONFIG_IIM) += iim.o COBJS-$(CONFIG_PCI) += pci.o
# Stub implementations of cache management functions for USB diff --git a/arch/powerpc/cpu/mpc512x/iim.c b/arch/powerpc/cpu/mpc512x/iim.c deleted file mode 100644 index abec8f6..0000000 --- a/arch/powerpc/cpu/mpc512x/iim.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright 2008 Silicon Turnkey Express, Inc. - * Martha Marx mmarx@silicontkx.com - * - * ADS5121 IIM (Fusebox) Interface - * - * 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 <asm/io.h> - -#ifdef CONFIG_CMD_FUSE - -DECLARE_GLOBAL_DATA_PTR; - -static char cur_bank = '1'; - -char *iim_err_msg(u32 err) -{ - static char *IIM_errs[] = { - "Parity Error in cache", - "Explicit Sense Cycle Error", - "Write to Locked Register Error", - "Read Protect Error", - "Override Protect Error", - "Write Protect Error"}; - - int i; - - if (!err) - return ""; - for (i = 1; i < 8; i++) - if (err & (1 << i)) - printf("IIM - %s\n", IIM_errs[i-1]); - return ""; -} - -int in_range(int n, int min, int max, char *err, char *usg) -{ - if (n > max || n < min) { - printf(err); - printf("Usage:\n%s\n", usg); - return 0; - } - return 1; -} - -int ads5121_fuse_read(int bank, int fstart, int num) -{ - iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim; - u32 *iim_fb, dummy; - int f, ctr; - - out_be32(&iim->err, in_be32(&iim->err)); - if (bank == 0) - iim_fb = (u32 *)&(iim->fbac0); - else - iim_fb = (u32 *)&(iim->fbac1); -/* try a read to see if Read Protect is set */ - dummy = in_be32(&iim_fb[0]); - if (in_be32(&iim->err) & IIM_ERR_RPE) { - printf("\tRead protect fuse is set\n"); - out_be32(&iim->err, IIM_ERR_RPE); - return 0; - } - printf("Reading Bank %d cache\n", bank); - for (f = fstart, ctr = 0; num > 0; ctr++, num--, f++) { - if (ctr % 4 == 0) - printf("F%2d:", f); - printf("\t%#04x", (u8)(iim_fb[f])); - if (ctr % 4 == 3) - printf("\n"); - } - if (ctr % 4 != 0) - printf("\n"); -} - -int ads5121_fuse_override(int bank, int f, u8 val) -{ - iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim; - u32 *iim_fb; - u32 iim_stat; - int i; - - out_be32(&iim->err, in_be32(&iim->err)); - if (bank == 0) - iim_fb = (u32 *)&(iim->fbac0); - else - iim_fb = (u32 *)&(iim->fbac1); -/* try a read to see if Read Protect is set */ - iim_stat = in_be32(&iim_fb[0]); - if (in_be32(&iim->err) & IIM_ERR_RPE) { - printf("Read protect fuse is set on bank %d;" - "Override protect may also be set\n", bank); - printf("An attempt will be made to override\n"); - out_be32(&iim->err, IIM_ERR_RPE); - } - if (iim_stat & IIM_FBAC_FBOP) { - printf("Override protect fuse is set on bank %d\n", bank); - return 1; - } - if (f > IIM_FMAX) /* reset the entire bank */ - for (i = 0; i < IIM_FMAX + 1; i++) - out_be32(&iim_fb[i], 0); - else - out_be32(&iim_fb[f], val); - return 0; -} - -int ads5121_fuse_prog(cmd_tbl_t *cmdtp, int bank, char *fuseno_bitno) -{ - iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim; - int f, i, bitno; - u32 stat, err; - - f = simple_strtol(fuseno_bitno, NULL, 10); - if (f == 0 && fuseno_bitno[0] != '0') - f = -1; - if (!in_range(f, 0, IIM_FMAX, - "<frow> must be between 0-31\n\n", cmdtp->usage)) - return 1; - bitno = -1; - for (i = 0; i < 6; i++) { - if (fuseno_bitno[i] == '_') { - bitno = simple_strtol(&(fuseno_bitno[i+1]), NULL, 10); - if (bitno == 0 && fuseno_bitno[i+1] != '0') - bitno = -1; - break; - } - } - if (!in_range(bitno, 0, 7, "Bit number ranges from 0-7\n" - "Example of <frow_bitno>: "18_4" sets bit 4 of row 18\n", - cmdtp->usage)) - return 1; - out_be32(&iim->err, in_be32(&iim->err)); - out_be32(&iim->prg_p, IIM_PRG_P_SET); - out_be32(&iim->ua, IIM_SET_UA(bank, f)); - out_be32(&iim->la, IIM_SET_LA(f, bitno)); -#ifdef DEBUG - printf("Programming disabled with DEBUG defined \n"); - printf(""Set up to pro - printf("iim.ua = %x; iim.la = %x\n", iim->ua, iim->la); -#else - out_be32(&iim->fctl, IIM_FCTL_PROG_PULSE | IIM_FCTL_PROG); - do - udelay(20); - while ((stat = in_be32(&iim->stat)) & IIM_STAT_BUSY); - out_be32(&iim->prg_p, 0); - err = in_be32(&iim->err); - if (stat & IIM_STAT_PRGD) { - if (!(err & (IIM_ERR_WPE | IIM_ERR_WPE))) { - printf("Fuse is successfully set"); - if (err) - printf(" - however there are other errors"); - printf("\n"); - } - iim->stat = 0; - } - if (err) { - iim_err_msg(err); - out_be32(&iim->err, in_be32(&iim->err)); - } -#endif -} - -int ads5121_fuse_sense(int bank, int fstart, int num) -{ - iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim; - u32 iim_fbac; - u32 stat, err, err_hold = 0; - int f, ctr; - - out_be32(&iim->err, in_be32(&iim->err)); - if (bank == 0) - iim_fbac = in_be32(&iim->fbac0); - else - iim_fbac = in_be32(&iim->fbac1); - if (iim_fbac & IIM_FBAC_FBESP) { - printf("\tSense Protect disallows this operation\n"); - out_be32(&iim->err, IIM_FBAC_FBESP); - return 1; - } - err = in_be32(&iim->err); - if (err) { - iim_err_msg(err); - err_hold |= err; - } - if (err & IIM_ERR_RPE) - printf("\tRead protect fuse is set; " - "Sense Protect may be set but will be attempted\n"); - if (err) - out_be32(&iim->err, err); - printf("Sensing fuse(s) on Bank %d\n", bank); - for (f = fstart, ctr = 0; num > 0; ctr++, f++, num--) { - out_be32(&iim->ua, IIM_SET_UA(bank, f)); - out_be32(&iim->la, IIM_SET_LA(f, 0)); - out_be32(&iim->fctl, IIM_FCTL_ESNS_N); - do - udelay(20); - while ((stat = in_be32(&iim->stat)) & IIM_STAT_BUSY); - err = in_be32(&iim->err); - if (err & IIM_ERR_SNSE) { - iim_err_msg(err); - out_be32(&iim->err, IIM_ERR_SNSE); - return 1; - } - if (stat & IIM_STAT_SNSD) { - out_be32(&iim->stat, 0); - if (ctr % 4 == 0) - printf("F%2d:", f); - printf("\t%#04x", (u8)iim->sdat); - if (ctr % 4 == 3) - printf("\n"); - } - if (err) { - err_hold |= err; - out_be32(&iim->err, err); - } - } - if (ctr % 4 != 0) - printf("\n"); - if (err_hold) - iim_err_msg(err_hold); - - return 0; -} - -int ads5121_fuse_stat(int bank) -{ - iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim; - u32 iim_fbac; - u32 err; - - out_be32(&iim->err, in_be32(&iim->err)); - if (bank == 0) - iim_fbac = in_be32(&iim->fbac0); - else - iim_fbac = in_be32(&iim->fbac1); - err = in_be32(&iim->err); - if (err) - iim_err_msg(err); - if (err & IIM_ERR_RPE || iim_fbac & IIM_FBAC_FBRP) { - if (iim_fbac == 0) - printf("Since protection settings can't be read - " - "try sensing fuse row 0;\n"); - return 0; - } - if (iim_fbac & IIM_PROTECTION) - printf("Protection Fuses Bank %d = %#04x:\n", bank, iim_fbac); - else if (!(err & IIM_ERR_RPE)) - printf("No Protection fuses are set\n"); - if (iim_fbac & IIM_FBAC_FBWP) - printf("\tWrite Protect fuse is set\n"); - if (iim_fbac & IIM_FBAC_FBOP) - printf("\tOverride Protect fuse is set\n"); - if (iim_fbac & IIM_FBAC_FBESP) - printf("\tSense Protect Fuse is set\n"); - out_be32(&iim->err, in_be32(&iim->err)); - - return 0; -} - -int do_ads5121_fuse(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) -{ - int frow, n, v, bank; - - if (cur_bank == '0') - bank = 0; - else - bank = 1; - - switch (argc) { - case 0: - case 1: - printf("Usage:\n%s\n", cmdtp->usage); - return 1; - case 2: - if (strncmp(argv[1], "stat", 4) == 0) - return ads5121_fuse_stat(bank); - if (strncmp(argv[1], "read", 4) == 0) - return ads5121_fuse_read(bank, 0, IIM_FMAX + 1); - if (strncmp(argv[1], "sense", 5) == 0) - return ads5121_fuse_sense(bank, 0, IIM_FMAX + 1); - if (strncmp(argv[1], "ovride", 6) == 0) - return ads5121_fuse_override(bank, IIM_FMAX + 1, 0); - if (strncmp(argv[1], "bank", 4) == 0) { - printf("Active Fuse Bank is %c\n", cur_bank); - return 0; - } - printf("Usage:\n%s\n", cmdtp->usage); - return 1; - case 3: - if (strncmp(argv[1], "bank", 4) == 0) { - if (argv[2][0] == '0') - cur_bank = '0'; - else if (argv[2][0] == '1') - cur_bank = '1'; - else { - printf("Usage:\n%s\n", cmdtp->usage); - return 1; - } - - printf("Setting Active Fuse Bank to %c\n", cur_bank); - return 0; - } - if (strncmp(argv[1], "prog", 4) == 0) - return ads5121_fuse_prog(cmdtp, bank, argv[2]); - - frow = (int)simple_strtol(argv[2], NULL, 10); - if (frow == 0 && argv[2][0] != '0') - frow = -1; - if (!in_range(frow, 0, IIM_FMAX, - "<frow> must be between 0-31\n\n", cmdtp->usage)) - return 1; - if (strncmp(argv[1], "read", 4) == 0) - return ads5121_fuse_read(bank, frow, 1); - if (strncmp(argv[1], "ovride", 6) == 0) - return ads5121_fuse_override(bank, frow, 0); - if (strncmp(argv[1], "sense", 5) == 0) - return ads5121_fuse_sense(bank, frow, 1); - printf("Usage:\n%s\n", cmdtp->usage); - return 1; - case 4: - frow = (int)simple_strtol(argv[2], NULL, 10); - if (frow == 0 && argv[2][0] != '0') - frow = -1; - if (!in_range(frow, 0, IIM_FMAX, - "<frow> must be between 0-31\n\n", cmdtp->usage)) - return 1; - if (strncmp(argv[1], "read", 4) == 0) { - n = (int)simple_strtol(argv[3], NULL, 10); - if (!in_range(frow + n, frow + 1, IIM_FMAX + 1, - "<frow>+<n> must be between 1-32\n\n", - cmdtp->usage)) - return 1; - return ads5121_fuse_read(bank, frow, n); - } - if (strncmp(argv[1], "ovride", 6) == 0) { - v = (int)simple_strtol(argv[3], NULL, 10); - return ads5121_fuse_override(bank, frow, v); - } - if (strncmp(argv[1], "sense", 5) == 0) { - n = (int)simple_strtol(argv[3], NULL, 10); - if (!in_range(frow + n, frow + 1, IIM_FMAX + 1, - "<frow>+<n> must be between 1-32\n\n", - cmdtp->usage)) - return 1; - return ads5121_fuse_sense(bank, frow, n); - } - printf("Usage:\n%s\n", cmdtp->usage); - return 1; - default: /* at least 5 args */ - printf("Usage:\n%s\n", cmdtp->usage); - return 1; - } -} - -U_BOOT_CMD( - fuse, CONFIG_SYS_MAXARGS, 0, do_ads5121_fuse, - " - Read, Sense, Override or Program Fuses\n", - "bank <n> - sets active Fuse Bank to 0 or 1\n" - " no args shows current active bank\n" - "fuse stat - print active fuse bank's protection status\n" - "fuse read [<frow> [<n>]] - print <n> fuse rows starting at <frow>\n" - " no args to print entire bank's fuses\n" - "fuse ovride [<frow> [<v>]]- override fuses at <frow> with <v>\n" - " no <v> defaults to 0 for the row\n" - " no args resets entire bank to 0\n" - " NOTE - settings persist until hard reset\n" - "fuse sense [<frow>] - senses current fuse at <frow>\n" - " no args for entire bank\n" - "fuse prog <frow_bit> - program fuse at row <frow>, bit <_bit>\n" - " <frow> is 0-31, <bit> is 0-7; eg. 13_2 \n" - " WARNING - this is permanent" -); -#endif /* CONFIG_CMD_FUSE */ diff --git a/board/davedenx/aria/aria.c b/board/davedenx/aria/aria.c index 31b079b..d2ffba4 100644 --- a/board/davedenx/aria/aria.c +++ b/board/davedenx/aria/aria.c @@ -92,7 +92,7 @@ int board_early_init_f(void) */ out_be32(&im->clk.sccr[0], SCCR1_CLOCKS_EN); out_be32(&im->clk.sccr[1], SCCR2_CLOCKS_EN); -#if defined(CONFIG_IIM) || defined(CONFIG_CMD_FUSE) +#if defined(CONFIG_FSL_IIM) || defined(CONFIG_CMD_FUSE) setbits_be32(&im->clk.sccr[1], CLOCK_SCCR2_IIM_EN); #endif
diff --git a/board/esd/mecp5123/mecp5123.c b/board/esd/mecp5123/mecp5123.c index 748ad7c..804a022 100644 --- a/board/esd/mecp5123/mecp5123.c +++ b/board/esd/mecp5123/mecp5123.c @@ -110,7 +110,7 @@ int board_early_init_f(void) */ out_be32(&im->clk.sccr[0], SCCR1_CLOCKS_EN); out_be32(&im->clk.sccr[1], SCCR2_CLOCKS_EN); -#if defined(CONFIG_IIM) || defined(CONFIG_CMD_FUSE) +#if defined(CONFIG_FSL_IIM) || defined(CONFIG_CMD_FUSE) setbits_be32(&im->clk.sccr[1], CLOCK_SCCR2_IIM_EN); #endif
diff --git a/board/freescale/mpc5121ads/mpc5121ads.c b/board/freescale/mpc5121ads/mpc5121ads.c index 97eeab3..0d33680 100644 --- a/board/freescale/mpc5121ads/mpc5121ads.c +++ b/board/freescale/mpc5121ads/mpc5121ads.c @@ -129,7 +129,7 @@ int board_early_init_f(void) */ out_be32 (&im->clk.sccr[0], SCCR1_CLOCKS_EN); out_be32 (&im->clk.sccr[1], SCCR2_CLOCKS_EN); -#if defined(CONFIG_IIM) || defined(CONFIG_CMD_FUSE) +#if defined(CONFIG_FSL_IIM) || defined(CONFIG_CMD_FUSE) setbits_be32 (&im->clk.sccr[1], CLOCK_SCCR2_IIM_EN); #endif
diff --git a/board/pdm360ng/pdm360ng.c b/board/pdm360ng/pdm360ng.c index a2a1323..da81590 100644 --- a/board/pdm360ng/pdm360ng.c +++ b/board/pdm360ng/pdm360ng.c @@ -94,7 +94,7 @@ int board_early_init_f(void) */ out_be32(&im->clk.sccr[0], SCCR1_CLOCKS_EN); out_be32(&im->clk.sccr[1], SCCR2_CLOCKS_EN); -#if defined(CONFIG_IIM) || defined(CONFIG_CMD_FUSE) +#if defined(CONFIG_FSL_IIM) || defined(CONFIG_CMD_FUSE) setbits_be32(&im->clk.sccr[1], CLOCK_SCCR2_IIM_EN); #endif
diff --git a/include/configs/aria.h b/include/configs/aria.h index 0b31c50..7905e45 100644 --- a/include/configs/aria.h +++ b/include/configs/aria.h @@ -379,7 +379,7 @@ /* * IIM - IC Identification Module */ -#undef CONFIG_IIM +#undef CONFIG_FSL_IIM
/* * EEPROM configuration for Atmel AT24C32A-10TQ-2.7: diff --git a/include/configs/mecp5123.h b/include/configs/mecp5123.h index cafc273..8db47ed 100644 --- a/include/configs/mecp5123.h +++ b/include/configs/mecp5123.h @@ -251,7 +251,7 @@ /* * IIM - IC Identification Module */ -#undef CONFIG_IIM +#undef CONFIG_FSL_IIM
/* * EEPROM configuration diff --git a/include/configs/mpc5121ads.h b/include/configs/mpc5121ads.h index 3f55d35..5b34124 100644 --- a/include/configs/mpc5121ads.h +++ b/include/configs/mpc5121ads.h @@ -347,7 +347,7 @@ /* * IIM - IC Identification Module */ -#undef CONFIG_IIM +#undef CONFIG_FSL_IIM
/* * EEPROM configuration

This allows to test the iim driver in the mainline tree.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com --- Changes in v3: - New patch.
Changes in v2: None
include/configs/mx51evk.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/include/configs/mx51evk.h b/include/configs/mx51evk.h index cb3d938..cdd72cc 100644 --- a/include/configs/mx51evk.h +++ b/include/configs/mx51evk.h @@ -53,6 +53,10 @@ /* * Hardware drivers */ +#define CONFIG_FSL_IIM +#define CONFIG_SYS_FSL_IIM_ADDR IIM_BASE_ADDR +#define CONFIG_CMD_FUSE + #define CONFIG_MXC_UART #define CONFIG_MXC_UART_BASE UART1_BASE #define CONFIG_MXC_GPIO

Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com --- Changes in v3: - New patch.
Changes in v2: None
doc/README.imx25 | 10 ++++++++++ doc/README.imx27 | 10 ++++++++++ doc/README.imx5 | 6 ++++++ doc/README.imx6 | 10 ++++++++++ 4 files changed, 36 insertions(+) create mode 100644 doc/README.imx25 create mode 100644 doc/README.imx27 create mode 100644 doc/README.imx6
diff --git a/doc/README.imx25 b/doc/README.imx25 new file mode 100644 index 0000000..0ca21b6 --- /dev/null +++ b/doc/README.imx25 @@ -0,0 +1,10 @@ +U-Boot for Freescale i.MX25 + +This file contains information for the port of U-Boot to the Freescale i.MX25 +SoC. + +1. CONVENTIONS FOR FUSE ASSIGNMENTS +----------------------------------- + +1.1 MAC Address: It is stored in the words 26 to 31 of fuse bank 0, using the + natural MAC byte order (i.e. MSB first). diff --git a/doc/README.imx27 b/doc/README.imx27 new file mode 100644 index 0000000..6f92cb4 --- /dev/null +++ b/doc/README.imx27 @@ -0,0 +1,10 @@ +U-Boot for Freescale i.MX27 + +This file contains information for the port of U-Boot to the Freescale i.MX27 +SoC. + +1. CONVENTIONS FOR FUSE ASSIGNMENTS +----------------------------------- + +1.1 MAC Address: It is stored in the words 4 to 9 of fuse bank 0, using the + reversed MAC byte order (i.e. LSB first). diff --git a/doc/README.imx5 b/doc/README.imx5 index e08941e..c5312b6 100644 --- a/doc/README.imx5 +++ b/doc/README.imx5 @@ -20,3 +20,9 @@ i.MX5x SoCs. This option should be enabled for boards having a SYS_ON_OFF_CTL signal connected to GPIO1[23] and triggering the MAIN_PWR_ON signal like in the reference designs. + +2. CONVENTIONS FOR FUSE ASSIGNMENTS +----------------------------------- + +2.1 MAC Address: It is stored in the words 9 to 14 of fuse bank 1, using the + natural MAC byte order (i.e. MSB first). diff --git a/doc/README.imx6 b/doc/README.imx6 new file mode 100644 index 0000000..d20c3e1 --- /dev/null +++ b/doc/README.imx6 @@ -0,0 +1,10 @@ +U-Boot for Freescale i.MX6x + +This file contains information for the port of U-Boot to the Freescale i.MX6x +SoCs. + +1. CONVENTIONS FOR FUSE ASSIGNMENTS +----------------------------------- + +1.1 MAC Address: It is stored in fuse bank 4, with the 32 lsbs in word 2 and the + 16 msbs in word 3.
participants (1)
-
Benoît Thébaudeau