[U-Boot] [PATCH] Add IC Ident. Module (IIM) support for ADS5121
Martha Marx
mmarx at silicontkx.com
Wed Oct 8 06:46:10 CEST 2008
IIM (IC Identification Module) is the fusebox for the mpc5121. Use #define CONFIG_IIM
to turn on the clock for this module, use #define CONFIG_CMD_FUSE
to add fusebox commands. Fusebox commands include the ability to read
the status, read the register cache, override the register cache, program the fuses
and sense them.
Signed-off-by: Martha Marx <mmarx at silicontkx.com>
---
board/ads5121/Makefile | 1 +
board/ads5121/ads5121.c | 3 +
board/ads5121/ads5121_iim.c | 367 ++++++++++++++++++++++++++++++++++++++++++
include/asm-ppc/immap_512x.h | 20 +++-
include/configs/ads5121.h | 6 +
include/mpc512x.h | 25 +++
6 files changed, 421 insertions(+), 1 deletions(-)
create mode 100644 board/ads5121/ads5121_iim.c
diff --git a/board/ads5121/Makefile b/board/ads5121/Makefile
index 52d0d3c..125ac60 100644
--- a/board/ads5121/Makefile
+++ b/board/ads5121/Makefile
@@ -32,6 +32,7 @@ COBJS-${CONFIG_FSL_DIU_FB} += ads5121_diu.o
COBJS-${CONFIG_FSL_DIU_FB} += ../freescale/common/fsl_diu_fb.o
COBJS-${CONFIG_FSL_DIU_FB} += ../freescale/common/fsl_logo_bmp.o
COBJS-$(CONFIG_PCI) += pci.o
+COBJS-$(CONFIG_IIM) += ads5121_iim.o
COBJS := $(COBJS-y)
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
diff --git a/board/ads5121/ads5121.c b/board/ads5121/ads5121.c
index deaa292..4198826 100644
--- a/board/ads5121/ads5121.c
+++ b/board/ads5121/ads5121.c
@@ -101,6 +101,9 @@ int board_early_init_f (void)
*/
im->clk.sccr[0] = SCCR1_CLOCKS_EN;
im->clk.sccr[1] = SCCR2_CLOCKS_EN;
+#if defined(CONFIG_IIM) || defined(CONFIG_CMD_FUSE)
+ im->clk.sccr[1] |= CLOCK_SCCR2_IIM_EN;
+#endif
return 0;
}
diff --git a/board/ads5121/ads5121_iim.c b/board/ads5121/ads5121_iim.c
new file mode 100644
index 0000000..2dd2493
--- /dev/null
+++ b/board/ads5121/ads5121_iim.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2008 Silicon Turnkey Express, Inc.
+ * Martha Marx <mmarx at 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 ads5121_fuse_read(int bank, int fstart, int num)
+{
+ volatile iim512x_t *iim = &((immap_t *) CFG_IMMR)->iim;
+ u32 *iim_fb, dummy;
+ int f, ctr;
+
+ 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 = iim_fb[0];
+ if (iim->err & IIM_ERR_RPE) {
+ printf("\tRead protect fuse is set\n");
+ iim->err = 0;
+ 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)
+{
+ volatile iim512x_t *iim = &((immap_t *) CFG_IMMR)->iim;
+ u32 *iim_fb;
+ u32 iim_stat;
+ int i;
+
+ 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 = iim_fb[0];
+ if (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");
+ iim->err = 0;
+ }
+ 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++)
+ iim_fb[i] = 0;
+ else
+ iim_fb[f] = val;
+
+ return 0;
+}
+
+int ads5121_fuse_prog(cmd_tbl_t *cmdtp, int bank, char *fuseno_bitno)
+{
+ volatile iim512x_t *iim = &((immap_t *) CFG_IMMR)->iim;
+ int f, i;
+ int bitno;
+
+ f = simple_strtoul(fuseno_bitno, NULL, 10);
+ if (f > IIM_FMAX) {
+ printf("Fuse row number ranges from 0-%d\n", IIM_FMAX);
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ }
+ bitno = -1;
+ for (i = 0; i < 8; i++) {
+ if (fuseno_bitno[i] == '_') {
+ bitno = simple_strtoul(&(fuseno_bitno[i+1]), NULL, 10);
+ break;
+ } else if (fuseno_bitno[i] == '\0')
+ break;
+ }
+ if (bitno > 8) {
+ printf("Bit number ranges from 0-7\n");
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ }
+ iim->prg_p = IIM_PRG_P_SET;
+ iim->ua = IIM_SET_UA(bank, f);
+ iim->la = IIM_SET_LA(f, bitno);
+#ifdef DEBUG
+ printf("Programming disabled with DEBUG defined \n");
+ printf("iim.ua = %x; iim.la = %x\n", iim->ua, iim->la);
+#else
+ iim->fctl = IIM_FCTL_PROG_PULSE | IIM_FCTL_PROG;
+ do
+ udelay(10);
+ while (iim->stat & IIM_STAT_BUSY);
+ if (iim->stat & IIM_STAT_PRGD) {
+ if (!(iim->err & (IIM_ERR_WPE | IIM_ERR_WPE))) {
+ printf("Fuse is successfully set ");
+ if (iim->err)
+ printf("- however there are other errors");
+ printf("\n");
+ }
+ iim->stat = 0;
+ }
+ if (iim->err) {
+ iim_err_msg(iim->err);
+ iim->err = 0;
+ }
+#endif
+}
+
+int ads5121_fuse_sense(int bank, int fstart, int num)
+{
+ volatile iim512x_t *iim = &((immap_t *) CFG_IMMR)->iim;
+ u32 iim_fbac;
+ u32 err_hold;
+ int f, ctr;
+
+ if (bank == 0)
+ iim_fbac = iim->fbac0;
+ else
+ iim_fbac = iim->fbac1;
+
+ if (iim_fbac & (IIM_FBAC_FBESP | IIM_FBAC_FBSP)) {
+ printf("Protection Fuses Bank %d = %#04x:\n", bank, (u8)iim_fbac);
+ printf("\tSense Protect is set\n");
+ return 1;
+ }
+ if (iim->err & IIM_ERR_RPE) {
+ printf("\tRead protect fuse is set; "
+ "Sense Protect may be set but will be attempted\n");
+ iim->err = 0;
+ }
+ printf("Sensing fuse(s) on Bank %d\n", bank);
+ for (f = fstart, ctr = 0; num > 0; ctr++, f++, num--) {
+ iim->ua = IIM_SET_UA(bank, f);
+ iim->la = IIM_SET_LA(f, 0);
+ iim->fctl = IIM_FCTL_ESNS_N;
+ do
+ udelay(100);
+ while (iim->stat & IIM_STAT_BUSY);
+ if (iim->err & IIM_ERR_SNSE) {
+ iim_err_msg(iim->err);
+ iim->err = 0;
+ return 1;
+ }
+ if (iim->stat & IIM_STAT_SNSD) {
+ iim->stat = 0;
+ if (ctr % 4 == 0)
+ printf("F%2d:", f);
+ printf("\t%#04x", (u8)(iim->sdat));
+ if (ctr % 4 == 3)
+ printf("\n");
+ }
+ if (iim->err) {
+ err_hold |= iim->err;
+ iim->err = 0;
+ }
+ }
+ if (ctr % 4 != 0)
+ printf("\n");
+ if (err_hold)
+ iim_err_msg(err_hold);
+
+ return 0;
+}
+
+int ads5121_fuse_stat(int bank)
+{
+ volatile iim512x_t *iim = &((immap_t *) CFG_IMMR)->iim;
+ u32 iim_fbac;
+
+ if (bank == 0)
+ iim_fbac = iim->fbac0;
+ else
+ iim_fbac = iim->fbac1;
+ if (iim->err)
+ iim_err_msg(iim->err);
+ if (iim_fbac & IIM_PROTECTION)
+ printf("Protection Fuses on Bank %d = %#04x:\n", bank, iim_fbac);
+ else if (!(iim->err & IIM_ERR_RPE))
+ printf("No Protection fuses set\n");
+ if (iim_fbac & IIM_FBAC_FBWP)
+ printf("\tWrite Protect is set\n");
+ if (iim_fbac & IIM_FBAC_FBOP)
+ printf("\tOverride Protect is set\n");
+ if (iim->err & IIM_ERR_RPE || iim_fbac & IIM_FBAC_FBRP) {
+ printf("\tRead protect fuse is set\n");
+ if (iim_fbac == 0)
+ printf(" Settings can't be read - try sensing fuse 0;\n");
+ }
+ if (iim_fbac & IIM_FBAC_FBESP || iim_fbac & IIM_FBAC_FBSP)
+ printf("\tSense Protect is set\n");
+ iim->err = 0;
+
+ return 0;
+}
+
+int do_ads5121_fuse(cmd_tbl_t *cmdtp,
+ int flag, int argc, char *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) {
+ ads5121_fuse_stat(bank);
+ return 0;
+ } else if (strncmp(argv[1], "read", 4) == 0) {
+ ads5121_fuse_read(bank, 0, IIM_FMAX + 1);
+ return 0;
+ } else if (strncmp(argv[1], "sense", 5) == 0) {
+ ads5121_fuse_sense(bank, 0, IIM_FMAX + 1);
+ return 0;
+ } else if (strncmp(argv[1], "ovride", 6) == 0) {
+ ads5121_fuse_override(bank, IIM_FMAX + 1, 0);
+ return 0;
+ } else 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;
+ } else if (strncmp(argv[1], "read", 4) == 0) {
+ frow = (int)simple_strtoul(argv[2], NULL, 10);
+ if (frow > IIM_FMAX || frow < 0) {
+ printf("<frow> is the fuse row, 0-31 decimal\n\n");
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ }
+ return ads5121_fuse_read(bank, frow, 1);
+ } else if (strncmp(argv[1], "ovride", 6) == 0) {
+ frow = (int)simple_strtoul(argv[2], NULL, 10);
+ return ads5121_fuse_override(bank, frow, 0);
+ } else if (strncmp(argv[1], "sense", 5) == 0) {
+ frow = (int)simple_strtoul(argv[2], NULL, 10);
+ return ads5121_fuse_sense(bank, frow, 1);
+ } else if (strncmp(argv[1], "prog", 4) == 0) {
+ return ads5121_fuse_prog(cmdtp, bank, argv[2]);
+ }
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ case 4:
+ if (strncmp(argv[1], "read", 4) == 0) {
+ frow = (int)simple_strtoul(argv[2], NULL, 10);
+ if (frow > IIM_FMAX || frow < 0) {
+ printf("<frow> is the fuse row, a decimal number 0-31\n\n");
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ }
+ n = (int)simple_strtoul(argv[3], NULL, 10);
+ if (frow + n > IIM_FMAX + 1) {
+ printf("There are %d fuses per bank\n\n", IIM_FMAX);
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ }
+ return ads5121_fuse_read(bank, frow, n);
+ } else if (strncmp(argv[1], "ovride", 6) == 0) {
+ frow = (int)simple_strtoul(argv[2], NULL, 10);
+ if (frow > IIM_FMAX || frow < 0) {
+ printf("<frow> is the fuse row, 0-31 decimal\n\n");
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ }
+ v = (int)simple_strtoul(argv[3], NULL, 10);
+ return ads5121_fuse_override(bank, frow, v);
+ }
+ 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, CFG_MAXARGS, 0, do_ads5121_fuse,
+ " - Read, Sense, Override or Program Fuses\n",
+ "bank <n> - Set the active Fuse Bank n (0 or 1) Default is 1\n"
+ "fuse stat - print active fuse bank's status\n"
+ "fuse read [<frow> [<num>]] - print <num> fuse rows starting at <frow>\n"
+ " - no args to print entire bank's fuses\n"
+ "fuse ovride [<frow> [<val>]] - override fuses at <frow> with <val> (default=0)\n"
+ " - no args resets entire bank\n"
+ "fuse sense [<frow>] - senses current fuse at <frow>, no args for entire bank\n"
+ "fuse prog <frow_bit> - program fuse at row <frow>, bit <_bit>\n"
+ " - <frow> ranges from 0-31, <bit> ranges from 0-7\n"
+ );
+#endif /* CONFIG_CMD_FUSE */
diff --git a/include/asm-ppc/immap_512x.h b/include/asm-ppc/immap_512x.h
index cd90945..222d713 100644
--- a/include/asm-ppc/immap_512x.h
+++ b/include/asm-ppc/immap_512x.h
@@ -415,7 +415,25 @@ typedef struct ioctrl512x {
* IIM
*/
typedef struct iim512x {
- u8 fixme[0x1000];
+ u32 stat; /* IIM status register */
+ u32 statm; /* IIM status IRQ mask */
+ u32 err; /* IIM errors register */
+ u32 emask; /* IIM error IRQ mask */
+ u32 fctl; /* IIM fuse control register */
+ u32 ua; /* IIM upper address register */
+ u32 la; /* IIM lower address register */
+ u32 sdat; /* IIM explicit sense data */
+ u8 res0[0x08];
+ u32 prg_p; /* IIM program protection register */
+ u8 res1[0x10];
+ u32 divide; /* IIM divide factor register */
+ u8 res2[0x7c0];
+ u32 fbac0; /* IIM fuse bank 0 protection (for Freescale use) */
+ u32 fb0w0[0x1f]; /* IIM fuse bank 0 data (for Freescale use) */
+ u8 res3[0x380];
+ u32 fbac1; /* IIM fuse bank 1 protection */
+ u32 fb1w1[0x01f]; /* IIM fuse bank 1 data */
+ u8 res4[0x380];
} iim512x_t;
/*
diff --git a/include/configs/ads5121.h b/include/configs/ads5121.h
index d6f7e02..1955fba 100644
--- a/include/configs/ads5121.h
+++ b/include/configs/ads5121.h
@@ -294,6 +294,11 @@
#endif
/*
+ * IIM - IC Identification Module
+ */
+#define CONFIG_IIM
+
+/*
* EEPROM configuration
*/
#define CFG_I2C_EEPROM_ADDR_LEN 2 /* 16-bit EEPROM address */
@@ -348,6 +353,7 @@
#define CONFIG_CMD_REGINFO
#define CONFIG_CMD_EEPROM
#define CONFIG_CMD_DATE
+#define CONFIG_CMD_FUSE
#if defined(CONFIG_PCI)
#define CONFIG_CMD_PCI
diff --git a/include/mpc512x.h b/include/mpc512x.h
index cb418d1..49f5cd2 100644
--- a/include/mpc512x.h
+++ b/include/mpc512x.h
@@ -574,6 +574,31 @@ void iopin_initialize(iopin_t *,int);
/* Register Offset Base */
#define MPC512X_FEC (CFG_IMMR + 0x02800)
+/* IIM control */
+#define IIM_SET_UA(bk, f) ((bk << 3) | (f >> 5))
+#define IIM_SET_LA(f, bit) (((f & 0x0000001f) << 3) | bit)
+#define IIM_STAT_BUSY 0x00000080
+#define IIM_STAT_PRGD 0x00000002
+#define IIM_STAT_SNSD 0x00000001
+#define IIM_ERR_WPE 0x00000040
+#define IIM_ERR_OPE 0x00000020
+#define IIM_ERR_RPE 0x00000010
+#define IIM_ERR_WLRE 0x00000008
+#define IIM_ERR_SNSE 0x00000004
+#define IIM_ERR_PARITYE 0x00000002
+#define IIM_PRG_P_SET 0x000000aa
+#define IIM_PRG_P_UNSET 0
+#define IIM_FCTL_PROG_PULSE 0x00000020
+#define IIM_FCTL_PROG 0x00000001
+#define IIM_FCTL_ESNS_N 0x00000008
+#define IIM_FBAC_FBWP 0x00000080
+#define IIM_FBAC_FBOP 0x00000040
+#define IIM_FBAC_FBRP 0x00000020
+#define IIM_FBAC_FBSP 0x00000010
+#define IIM_FBAC_FBESP 0x00000008
+#define IIM_PROTECTION 0x000000f8
+#define IIM_FMAX 31
+
/* Number of I2C buses */
#define I2C_BUS_CNT 3
--
1.5.2.4
More information about the U-Boot
mailing list