[U-Boot] [PATCH 4/5] ADS5121 Add IC Ident Module (IIM) support

John Rigby jrigby at freescale.com
Mon Jan 26 21:07:07 CET 2009


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>
Signed-off-by: John Rigby <jrigby at freescale.com>
---
 board/ads5121/ads5121.c      |    3 +
 cpu/mpc512x/Makefile         |    3 +
 cpu/mpc512x/iim.c            |  394 ++++++++++++++++++++++++++++++++++++++++++
 include/asm-ppc/immap_512x.h |   20 ++-
 include/configs/ads5121.h    |    6 +
 include/mpc512x.h            |   24 +++
 6 files changed, 449 insertions(+), 1 deletions(-)
 create mode 100644 cpu/mpc512x/iim.c

diff --git a/board/ads5121/ads5121.c b/board/ads5121/ads5121.c
index 8e22719..ae1ccd9 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..6cdc422
--- /dev/null
+++ b/cpu/mpc512x/iim.c
@@ -0,0 +1,394 @@
+/*
+ * 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 *) 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 *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\n"
+	);
+#endif /* CONFIG_CMD_FUSE */
diff --git a/include/asm-ppc/immap_512x.h b/include/asm-ppc/immap_512x.h
index cd90945..4cef6a8 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 prot (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 bb38be6..0aca4a5 100644
--- a/include/configs/ads5121.h
+++ b/include/configs/ads5121.h
@@ -295,6 +295,11 @@
 #endif
 
 /*
+ * IIM - IC Identification Module
+ */
+#undef CONFIG_IIM
+
+/*
  * EEPROM configuration
  */
 #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN		2	/* 16-bit EEPROM address */
@@ -349,6 +354,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 05a2063..714287c 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		(CONFIG_SYS_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.6.2.255.gbed62



More information about the U-Boot mailing list