From patchwork Tue Mar 26 21:24:53 2013 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: 231536 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 86B012C008E for ; Wed, 27 Mar 2013 08:26:23 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 785E34A051; Tue, 26 Mar 2013 22:26:08 +0100 (CET) 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 FUBesTYHl0pP; Tue, 26 Mar 2013 22:26:08 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 5EF544A030; Tue, 26 Mar 2013 22:25:49 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 1E56F4A01E for ; Tue, 26 Mar 2013 22:25:45 +0100 (CET) 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 pFCRazpbLY-p for ; Tue, 26 Mar 2013 22:25:42 +0100 (CET) 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-mta11.web4all.fr [178.33.204.87]) by theia.denx.de (Postfix) with ESMTPS id 4A6164A020 for ; Tue, 26 Mar 2013 22:25:38 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by zose-mta11.web4all.fr (Postfix) with ESMTP id 879942A050; Tue, 26 Mar 2013 22:25:38 +0100 (CET) X-Virus-Scanned: amavisd-new at zose-mta11.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 tedX-RSuAImq; Tue, 26 Mar 2013 22:25:37 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by zose-mta11.web4all.fr (Postfix) with ESMTP id D84C52A058; Tue, 26 Mar 2013 22:25:36 +0100 (CET) X-Virus-Scanned: amavisd-new at zose-mta11.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 10026) with ESMTP id bapNCValaD0A; Tue, 26 Mar 2013 22:25:35 +0100 (CET) Received: from advdt005-ubuntu.?none? (cie44-1-88-188-188-98.fbx.proxad.net [88.188.188.98]) by zose-mta11.web4all.fr (Postfix) with ESMTPA id 564432A02A; Tue, 26 Mar 2013 22:25:35 +0100 (CET) From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= To: u-boot@lists.denx.de, Stefano Babic , Wolfgang Denk Date: Tue, 26 Mar 2013 22:24:53 +0100 Message-Id: <1364333096-3698-4-git-send-email-benoit.thebaudeau@advansee.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1364333096-3698-1-git-send-email-benoit.thebaudeau@advansee.com> References: <1364333096-3698-1-git-send-email-benoit.thebaudeau@advansee.com> MIME-Version: 1.0 Subject: [U-Boot] [PATCH v3 4/7] 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 --- Changes in v3: - Update copyright years. - Rename "row" to "word" since it is less confusing and it is vocabulary common to iim and ocotp in the reference manuals. - Add doc/README.fsl_iim. Changes in v2: - Rebase against latest master. doc/README.fsl_iim | 51 ++++++++ drivers/misc/Makefile | 1 + drivers/misc/fsl_iim.c | 318 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 370 insertions(+) create mode 100644 doc/README.fsl_iim create mode 100644 drivers/misc/fsl_iim.c diff --git a/doc/README.fsl_iim b/doc/README.fsl_iim new file mode 100644 index 0000000..2472521 --- /dev/null +++ b/doc/README.fsl_iim @@ -0,0 +1,51 @@ +Driver implementing the fuse API for Freescale's IC Identification Module (IIM) + +This IP can be found on the following SoCs: + - MPC512x, + - i.MX25, + - i.MX27, + - i.MX31, + - i.MX35, + - i.MX51, + - i.MX53. + +The section numbers in this file refer to the i.MX25 Reference Manual. + +A fuse word contains 8 fuse bit slots, as explained in 30.4.2.2.1. + +A bank contains 256 fuse word slots, as shown by the memory map in 30.3.1. + +Some fuse bit or word slots may not have the corresponding fuses actually +implemented in the fusebox. + +See the README files of the SoCs using this driver in order to know the +conventions used by U-Boot to store some specific data in the fuses, e.g. MAC +addresses. + +Fuse operations: + + Read + Read operations are implemented as read accesses to the shadow registers, + using "Word y of Bank x" from the register summary in 30.3.2. This is + explained in detail in 30.4.5.1. + + Sense + Sense operations are implemented as explained in 30.4.5.2. + + Program + Program operations are implemented as explained in 30.4.5.3. Following + this operation, the shadow registers are reloaded by the hardware (not + immediately, but this does not make any difference for a user reading + these registers). + + Override + Override operations are implemented as write accesses to the shadow + registers, as explained in 30.4.5.4. + +Configuration: + + CONFIG_FSL_IIM + Define this to enable the fsl_iim driver. + + CONFIG_SYS_FSL_IIM_ADDR + This should be defined to the base address of the IIM IP. diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 8cdc3b6..c6dadd4 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -28,6 +28,7 @@ LIB := $(obj)libmisc.o COBJS-$(CONFIG_ALI152X) += ali512x.o COBJS-$(CONFIG_DS4510) += ds4510.o COBJS-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o +COBJS-$(CONFIG_FSL_IIM) += fsl_iim.o COBJS-$(CONFIG_GPIO_LED) += gpio_led.o COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o COBJS-$(CONFIG_NS87308) += ns87308.o diff --git a/drivers/misc/fsl_iim.c b/drivers/misc/fsl_iim.c new file mode 100644 index 0000000..33b9c9a --- /dev/null +++ b/drivers/misc/fsl_iim.c @@ -0,0 +1,318 @@ +/* + * (C) Copyright 2009-2013 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 word[0x100]; + } bank[8]; +}; + +int fuse_read_bit(u32 bank, u32 word, u32 bit, u32 *val) +{ + int ret; + + if (bit >= 8) { + puts("fsl_iim fuse read: Invalid argument\n"); + return -EINVAL; + } + + ret = fuse_read_word(bank, word, val); + if (ret) + return ret; + + *val = !!(*val & 1 << bit); + return 0; +} + +int fuse_read_word(u32 bank, u32 word, u32 *val) +{ + volatile struct fsl_iim *regs = + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; + u32 err; + + if (bank >= ARRAY_SIZE(regs->bank) || + word >= ARRAY_SIZE(regs->bank[0].word) || + 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].word[word]); + 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 word, u32 bit, u32 *val) +{ + int ret; + + if (bit >= 8) { + puts("fsl_iim fuse sense: Invalid argument\n"); + return -EINVAL; + } + + ret = fuse_sense_word(bank, word, val); + if (ret) + return ret; + + *val = !!(*val & 1 << bit); + return 0; +} + +int fuse_sense_word(u32 bank, u32 word, u32 *val) +{ + volatile struct fsl_iim *regs = + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; + u32 stat, err; + + if (bank >= ARRAY_SIZE(regs->bank) || + word >= ARRAY_SIZE(regs->bank[0].word) || + 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 | word >> 5); + iim_write32(®s->la, word << 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 word, u32 bit) +{ + volatile struct fsl_iim *regs = + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; + u32 stat, err; + + if (bank >= ARRAY_SIZE(regs->bank) || + word >= ARRAY_SIZE(regs->bank[0].word) || + 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 | word >> 5); + iim_write32(®s->la, (word << 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_word(u32 bank, u32 word, 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, word, bit); + if (ret) + return ret; + } + + return 0; +} + +int fuse_override_bit(u32 bank, u32 word, u32 bit, u32 val) +{ + u32 word_val; + int ret; + + if (bit >= 8 || val > 1) { + puts("fsl_iim fuse override: Invalid argument\n"); + return -EINVAL; + } + + ret = fuse_read_word(bank, word, &word_val); + if (ret) + return ret; + + return fuse_override_word(bank, word, + (word_val & ~(1 << bit)) | val << bit); +} + +int fuse_override_word(u32 bank, u32 word, u32 val) +{ + volatile struct fsl_iim *regs = + (struct fsl_iim *)CONFIG_SYS_FSL_IIM_ADDR; + u32 err; + + if (bank >= ARRAY_SIZE(regs->bank) || + word >= ARRAY_SIZE(regs->bank[0].word) || + 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].word[word], 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; +}