[U-Boot] [PATCH] Add IC Identif Module (IIM) support for ADS5121

Martha Marx mmarx at silicontkx.com
Sat Oct 11 21:34:22 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.  These are
turned off by default.  Fusebox commands include the ability to read
the protection status, read the register cache, override the register cache,
program the fuses and explicitly sense them.

Signed-off-by: Martha Marx <mmarx at silicontkx.com>
---
 board/ads5121/ads5121.c      |    3 +
 cpu/mpc512x/Makefile         |    3 +
 cpu/mpc512x/iim.c            |  387 ++++++++++++++++++++++++++++++++++++++++++
 include/asm-ppc/immap_512x.h |   20 ++-
 include/configs/ads5121.h    |    6 +
 include/mpc512x.h            |   24 +++
 6 files changed, 442 insertions(+), 1 deletions(-)
 create mode 100644 cpu/mpc512x/iim.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/cpu/mpc512x/Makefile b/cpu/mpc512x/Makefile
index e8f1060..e09eb1b 100644
--- a/cpu/mpc512x/Makefile
+++ b/cpu/mpc512x/Makefile
@@ -26,6 +26,9 @@ LIB	= $(obj)lib$(CPU).a
 
 START	= start.o
 COBJS	= traps.o cpu.o cpu_init.o speed.o interrupts.o serial.o i2c.o iopin.o
+ifdef CONFIG_IIM
+COBJS	+= iim.o
+endif 
 
 SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
diff --git a/cpu/mpc512x/iim.c b/cpu/mpc512x/iim.c
new file mode 100644
index 0000000..86b4919
--- /dev/null
+++ b/cpu/mpc512x/iim.c
@@ -0,0 +1,387 @@
+/*
+ * 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 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 *) 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 = in_be32(&iim_fb[0]);
+	if (in_be32(&iim->err) & IIM_ERR_RPE) {
+		printf("\tRead protect fuse is set\n");
+		out_be32(&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)
+{
+	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 = 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, 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++)
+			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 *) CFG_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->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, 0);
+	}
+#endif
+}
+
+int ads5121_fuse_sense(int bank, int fstart, int num)
+{
+	iim512x_t *iim = &((immap_t *) CFG_IMMR)->iim;
+	u32 iim_fbac;
+	u32 stat, err, err_hold = 0;
+	int f, ctr;
+
+	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, 0);
+		return 1;
+	}
+	err = in_be32(&iim->err);
+	if (err) {
+		iim_err_msg(err);
+		out_be32(&iim->err, 0);
+		err_hold |= err;
+	}
+	if (err & IIM_ERR_RPE)
+		printf("\tRead protect fuse is set; "
+			"Sense Protect may be set but will be attempted\n");
+	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, 0);
+			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, 0);
+		}
+	}
+	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 *) CFG_IMMR)->iim;
+	u32 iim_fbac;
+	u32 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, 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)
+			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, CFG_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\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..3753168 100644
--- a/include/configs/ads5121.h
+++ b/include/configs/ads5121.h
@@ -294,6 +294,11 @@
 #endif
 
 /*
+ * IIM - IC Identification Module
+ */
+#undef 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
+#undef CONFIG_CMD_FUSE
 
 #if defined(CONFIG_PCI)
 #define CONFIG_CMD_PCI
diff --git a/include/mpc512x.h b/include/mpc512x.h
index cb418d1..201782f 100644
--- a/include/mpc512x.h
+++ b/include/mpc512x.h
@@ -574,6 +574,30 @@ 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_FBESP		0x00000008
+#define IIM_PROTECTION		0x000000e8
+#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