Message ID | 1968030200.2398353.1344948771924.JavaMail.root@advansee.com |
---|---|
State | Superseded |
Delegated to: | Stefano Babic |
Headers | show |
On 14/08/2012 14:52, Benoît Thébaudeau wrote: > Add a fsl_iim driver common to i.MX and MPC. > > Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau@advansee.com> > Cc: Wolfgang Denk <wd@denx.de> > Cc: Stefano Babic <sbabic@denx.de> > --- > .../drivers/misc/Makefile | 1 + > /dev/null => u-boot-4d3c95f/drivers/misc/fsl_iim.c | 318 ++++++++++++++++++++ > 2 files changed, 319 insertions(+) > create mode 100644 u-boot-4d3c95f/drivers/misc/fsl_iim.c > > diff --git u-boot-4d3c95f.orig/drivers/misc/Makefile u-boot-4d3c95f/drivers/misc/Makefile > index 271463c..31b8db8 100644 > --- u-boot-4d3c95f.orig/drivers/misc/Makefile > +++ u-boot-4d3c95f/drivers/misc/Makefile > @@ -27,6 +27,7 @@ LIB := $(obj)libmisc.o > > COBJS-$(CONFIG_ALI152X) += ali512x.o > COBJS-$(CONFIG_DS4510) += ds4510.o > +COBJS-$(CONFIG_FSL_IIM) += fsl_iim.o > COBJS-$(CONFIG_FSL_LAW) += fsl_law.o > COBJS-$(CONFIG_GPIO_LED) += gpio_led.o > COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o > diff --git u-boot-4d3c95f/drivers/misc/fsl_iim.c u-boot-4d3c95f/drivers/misc/fsl_iim.c > new file mode 100644 > index 0000000..1a3d5fc > --- /dev/null > +++ u-boot-4d3c95f/drivers/misc/fsl_iim.c > @@ -0,0 +1,318 @@ > +/* > + * (C) Copyright 2009-2012 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 row[0x100]; > + } bank[8]; > +}; > + > +int fuse_read_bit(u32 bank, u32 row, u32 bit, u32 *val) > +{ > + int ret; > + > + if (bit >= 8) { > + puts("fsl_iim fuse read: Invalid argument\n"); > + return -EINVAL; > + } > + > + ret = fuse_read_row(bank, row, val); > + if (ret) > + return ret; > + > + *val = !!(*val & 1 << bit); > + return 0; > +} > + > +int fuse_read_row(u32 bank, u32 row, u32 *val) > +{ > + volatile struct fsl_iim *regs = > + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; > + u32 err; > + > + if (bank >= ARRAY_SIZE(regs->bank) || > + row >= ARRAY_SIZE(regs->bank[0].row) || > + 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].row[row]); > + 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 row, u32 bit, u32 *val) > +{ > + int ret; > + > + if (bit >= 8) { > + puts("fsl_iim fuse sense: Invalid argument\n"); > + return -EINVAL; > + } > + > + ret = fuse_sense_row(bank, row, val); > + if (ret) > + return ret; > + > + *val = !!(*val & 1 << bit); > + return 0; > +} > + > +int fuse_sense_row(u32 bank, u32 row, u32 *val) > +{ > + volatile struct fsl_iim *regs = > + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; > + u32 stat, err; > + > + if (bank >= ARRAY_SIZE(regs->bank) || > + row >= ARRAY_SIZE(regs->bank[0].row) || > + 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 | row >> 5); > + iim_write32(®s->la, row << 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 row, u32 bit) > +{ > + volatile struct fsl_iim *regs = > + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; The address depends on the SOC, and is not a board configuration option. Should we not use IIM_BASE_ADDR ? Best regards, Stefano
Hi Stefano, > > Add a fsl_iim driver common to i.MX and MPC. > > > > Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau@advansee.com> > > Cc: Wolfgang Denk <wd@denx.de> > > Cc: Stefano Babic <sbabic@denx.de> > > --- > > .../drivers/misc/Makefile | 1 + > > /dev/null => u-boot-4d3c95f/drivers/misc/fsl_iim.c | 318 > > ++++++++++++++++++++ > > 2 files changed, 319 insertions(+) > > create mode 100644 u-boot-4d3c95f/drivers/misc/fsl_iim.c > > > > diff --git u-boot-4d3c95f.orig/drivers/misc/Makefile > > u-boot-4d3c95f/drivers/misc/Makefile > > index 271463c..31b8db8 100644 > > --- u-boot-4d3c95f.orig/drivers/misc/Makefile > > +++ u-boot-4d3c95f/drivers/misc/Makefile > > @@ -27,6 +27,7 @@ LIB := $(obj)libmisc.o > > > > COBJS-$(CONFIG_ALI152X) += ali512x.o > > COBJS-$(CONFIG_DS4510) += ds4510.o > > +COBJS-$(CONFIG_FSL_IIM) += fsl_iim.o > > COBJS-$(CONFIG_FSL_LAW) += fsl_law.o > > COBJS-$(CONFIG_GPIO_LED) += gpio_led.o > > COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o > > diff --git u-boot-4d3c95f/drivers/misc/fsl_iim.c > > u-boot-4d3c95f/drivers/misc/fsl_iim.c > > new file mode 100644 > > index 0000000..1a3d5fc > > --- /dev/null > > +++ u-boot-4d3c95f/drivers/misc/fsl_iim.c > > @@ -0,0 +1,318 @@ > > +/* > > + * (C) Copyright 2009-2012 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 row[0x100]; > > + } bank[8]; > > +}; > > + > > +int fuse_read_bit(u32 bank, u32 row, u32 bit, u32 *val) > > +{ > > + int ret; > > + > > + if (bit >= 8) { > > + puts("fsl_iim fuse read: Invalid argument\n"); > > + return -EINVAL; > > + } > > + > > + ret = fuse_read_row(bank, row, val); > > + if (ret) > > + return ret; > > + > > + *val = !!(*val & 1 << bit); > > + return 0; > > +} > > + > > +int fuse_read_row(u32 bank, u32 row, u32 *val) > > +{ > > + volatile struct fsl_iim *regs = > > + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; > > + u32 err; > > + > > + if (bank >= ARRAY_SIZE(regs->bank) || > > + row >= ARRAY_SIZE(regs->bank[0].row) || > > + 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].row[row]); > > + 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 row, u32 bit, u32 *val) > > +{ > > + int ret; > > + > > + if (bit >= 8) { > > + puts("fsl_iim fuse sense: Invalid argument\n"); > > + return -EINVAL; > > + } > > + > > + ret = fuse_sense_row(bank, row, val); > > + if (ret) > > + return ret; > > + > > + *val = !!(*val & 1 << bit); > > + return 0; > > +} > > + > > +int fuse_sense_row(u32 bank, u32 row, u32 *val) > > +{ > > + volatile struct fsl_iim *regs = > > + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; > > + u32 stat, err; > > + > > + if (bank >= ARRAY_SIZE(regs->bank) || > > + row >= ARRAY_SIZE(regs->bank[0].row) || > > + 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 | row >> 5); > > + iim_write32(®s->la, row << 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 row, u32 bit) > > +{ > > + volatile struct fsl_iim *regs = > > + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; > > The address depends on the SOC, and is not a board configuration > option. > Should we not use IIM_BASE_ADDR ? CONFIG_SYS_FSL_IIM_ADDR is supposed to be a board configuration option, just like CONFIG_SYS_I2C_BASE. This makes things easier since on MPC this address comes from a struct (&((immap_t *) CONFIG_SYS_IMMR)->iim). Or we could define a FSL_IIM_BASE_ADDR in all supported register definition files, but that would mean including conditionally these files in fsl_iim.c. Best regards, Benoît
On 21/08/2012 14:56, Benoît Thébaudeau wrote: > Hi Stefano, > Hi, >> The address depends on the SOC, and is not a board configuration >> option. >> Should we not use IIM_BASE_ADDR ? > > CONFIG_SYS_FSL_IIM_ADDR is supposed to be a board configuration option, just > like CONFIG_SYS_I2C_BASE. Ok, but the reason for CONFIG_SYS_I2C_BASE is that a SOC have multiple I2C controller, but u-boot supports only one of them (up now). Setting CONFIG_SYS_I2C_BASE we implicitely tell u-boot which controller is active. There is not multiple iim in the SOCs. For this reason I thought it is not a configuration option. > This makes things easier since on MPC this address > comes from a struct (&((immap_t *) CONFIG_SYS_IMMR)->iim). Or we could define a > FSL_IIM_BASE_ADDR in all supported register definition files, but that would > mean including conditionally these files in fsl_iim.c. I understood the point. Ok, let's see which is the Anatolji's opinion for the PowerPC side. If he thinks it is ok, we can leave it with CONFIG_SYS_FSL_IIM_ADDR. Regards, Stefano
diff --git u-boot-4d3c95f.orig/drivers/misc/Makefile u-boot-4d3c95f/drivers/misc/Makefile index 271463c..31b8db8 100644 --- u-boot-4d3c95f.orig/drivers/misc/Makefile +++ u-boot-4d3c95f/drivers/misc/Makefile @@ -27,6 +27,7 @@ LIB := $(obj)libmisc.o COBJS-$(CONFIG_ALI152X) += ali512x.o COBJS-$(CONFIG_DS4510) += ds4510.o +COBJS-$(CONFIG_FSL_IIM) += fsl_iim.o COBJS-$(CONFIG_FSL_LAW) += fsl_law.o COBJS-$(CONFIG_GPIO_LED) += gpio_led.o COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o diff --git u-boot-4d3c95f/drivers/misc/fsl_iim.c u-boot-4d3c95f/drivers/misc/fsl_iim.c new file mode 100644 index 0000000..1a3d5fc --- /dev/null +++ u-boot-4d3c95f/drivers/misc/fsl_iim.c @@ -0,0 +1,318 @@ +/* + * (C) Copyright 2009-2012 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 row[0x100]; + } bank[8]; +}; + +int fuse_read_bit(u32 bank, u32 row, u32 bit, u32 *val) +{ + int ret; + + if (bit >= 8) { + puts("fsl_iim fuse read: Invalid argument\n"); + return -EINVAL; + } + + ret = fuse_read_row(bank, row, val); + if (ret) + return ret; + + *val = !!(*val & 1 << bit); + return 0; +} + +int fuse_read_row(u32 bank, u32 row, u32 *val) +{ + volatile struct fsl_iim *regs = + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; + u32 err; + + if (bank >= ARRAY_SIZE(regs->bank) || + row >= ARRAY_SIZE(regs->bank[0].row) || + 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].row[row]); + 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 row, u32 bit, u32 *val) +{ + int ret; + + if (bit >= 8) { + puts("fsl_iim fuse sense: Invalid argument\n"); + return -EINVAL; + } + + ret = fuse_sense_row(bank, row, val); + if (ret) + return ret; + + *val = !!(*val & 1 << bit); + return 0; +} + +int fuse_sense_row(u32 bank, u32 row, u32 *val) +{ + volatile struct fsl_iim *regs = + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; + u32 stat, err; + + if (bank >= ARRAY_SIZE(regs->bank) || + row >= ARRAY_SIZE(regs->bank[0].row) || + 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 | row >> 5); + iim_write32(®s->la, row << 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 row, u32 bit) +{ + volatile struct fsl_iim *regs = + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; + u32 stat, err; + + if (bank >= ARRAY_SIZE(regs->bank) || + row >= ARRAY_SIZE(regs->bank[0].row) || + 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 | row >> 5); + iim_write32(®s->la, (row << 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_row(u32 bank, u32 row, 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, row, bit); + if (ret) + return ret; + } + + return 0; +} + +int fuse_override_bit(u32 bank, u32 row, u32 bit, u32 val) +{ + u32 row_val; + int ret; + + if (bit >= 8 || val > 1) { + puts("fsl_iim fuse override: Invalid argument\n"); + return -EINVAL; + } + + ret = fuse_read_row(bank, row, &row_val); + if (ret) + return ret; + + return fuse_override_row(bank, row, + (row_val & ~(1 << bit)) | val << bit); +} + +int fuse_override_row(u32 bank, u32 row, u32 val) +{ + volatile struct fsl_iim *regs = + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; + u32 err; + + if (bank >= ARRAY_SIZE(regs->bank) || + row >= ARRAY_SIZE(regs->bank[0].row) || + 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].row[row], 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; +}
Add a fsl_iim driver common to i.MX and MPC. Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau@advansee.com> Cc: Wolfgang Denk <wd@denx.de> Cc: Stefano Babic <sbabic@denx.de> --- .../drivers/misc/Makefile | 1 + /dev/null => u-boot-4d3c95f/drivers/misc/fsl_iim.c | 318 ++++++++++++++++++++ 2 files changed, 319 insertions(+) create mode 100644 u-boot-4d3c95f/drivers/misc/fsl_iim.c