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

John Rigby jrigby at freescale.com
Wed Oct 8 23:21:49 CEST 2008


Hi Martha,

First, please replace the volatile pointer accesses with io accessors
like in_bexx and out_bexx.  Second, chip stuff should go in
cpu/mpc512x.

John

On Tue, Oct 7, 2008 at 10:46 PM, Martha Marx <mmarx at silicontkx.com> wrote:
> 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
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>


More information about the U-Boot mailing list