From patchwork Tue Aug 14 12:52:51 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Beno=C3=AEt_Th=C3=A9baudeau?= X-Patchwork-Id: 177245 X-Patchwork-Delegate: sbabic@denx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id C60B02C0080 for ; Tue, 14 Aug 2012 22:47:40 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 86A9628134; Tue, 14 Aug 2012 14:47:39 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 85IOWFd8Y2CL; Tue, 14 Aug 2012 14:47:39 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B2B4828122; Tue, 14 Aug 2012 14:47:36 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id A443E28122 for ; Tue, 14 Aug 2012 14:47:34 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id MaRhUifGicxG for ; Tue, 14 Aug 2012 14:47:34 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from zose-mta11.web4all.fr (zose-mta-11.w4a.fr [178.33.204.86]) by theia.denx.de (Postfix) with ESMTP id 0954028117 for ; Tue, 14 Aug 2012 14:47:32 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by zose-mta11.web4all.fr (Postfix) with ESMTP id DC0454600E; Tue, 14 Aug 2012 14:52:18 +0200 (CEST) X-Virus-Scanned: amavisd-new at zose1.web4all.fr Received: from zose-mta11.web4all.fr ([127.0.0.1]) by localhost (zose-mta11.web4all.fr [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id X-juIT4KXcvF; Tue, 14 Aug 2012 14:52:18 +0200 (CEST) Received: from zose-store12.web4all.fr (zose-store12.web4all.fr [178.33.204.49]) by zose-mta11.web4all.fr (Postfix) with ESMTP id 3F4AC4600B; Tue, 14 Aug 2012 14:52:18 +0200 (CEST) Date: Tue, 14 Aug 2012 14:52:51 +0200 (CEST) From: =?utf-8?Q?Beno=C3=AEt_Th=C3=A9baudeau?= To: U-Boot-Users ML Message-ID: <1968030200.2398353.1344948771924.JavaMail.root@advansee.com> In-Reply-To: <1047085507.2398341.1344948708040.JavaMail.root@advansee.com> MIME-Version: 1.0 X-Originating-IP: [88.188.188.98] X-Mailer: Zimbra 7.2.0_GA_2669 (ZimbraWebClient - FF3.0 (Win)/7.2.0_GA_2669) Subject: [U-Boot] [PATCH 4/5] Add fsl_iim driver X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de Add a fsl_iim driver common to i.MX and MPC. Signed-off-by: Benoît Thébaudeau Cc: Wolfgang Denk Cc: Stefano Babic --- .../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 + * + * Based on the mpc512x iim code: + * Copyright 2008 Silicon Turnkey Express, Inc. + * Martha Marx + * + * 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 +#include +#include +#include +#include +#include +#include + +/* 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; +}