Commit 0f67e09e9ef354ae2d282091adb3dc531f2aef7d

Authored by Benoît Thébaudeau
Committed by Stefano Babic
1 parent ccca7dfd02

Add fsl_iim driver

Add a fsl_iim driver common to i.MX and MPC.

Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau@advansee.com>

Showing 7 changed files with 340 additions and 0 deletions Side-by-side Diff

arch/arm/include/asm/arch-mx25/imx-regs.h
... ... @@ -253,6 +253,7 @@
253 253 #define IMX_PWM1_BASE (0x53FE0000)
254 254 #define IMX_RTIC_BASE (0x53FEC000)
255 255 #define IMX_IIM_BASE (0x53FF0000)
  256 +#define IIM_BASE_ADDR IMX_IIM_BASE
256 257 #define IMX_USB_BASE (0x53FF4000)
257 258 #define IMX_USB_PORT_OFFSET 0x200
258 259 #define IMX_CSI_BASE (0x53FF8000)
arch/arm/include/asm/arch-mx27/imx-regs.h
... ... @@ -222,6 +222,7 @@
222 222 #define IMX_PLL_BASE (0x27000 + IMX_IO_BASE)
223 223 #define IMX_SYSTEM_CTL_BASE (0x27800 + IMX_IO_BASE)
224 224 #define IMX_IIM_BASE (0x28000 + IMX_IO_BASE)
  225 +#define IIM_BASE_ADDR IMX_IIM_BASE
225 226 #define IMX_FEC_BASE (0x2b000 + IMX_IO_BASE)
226 227  
227 228 #define IMX_ESD_BASE (0xD8001000)
arch/arm/include/asm/arch-mx31/imx-regs.h
... ... @@ -574,6 +574,7 @@
574 574 #define CCMR_CKIH (2 << 1)
575 575  
576 576 #define MX31_IIM_BASE_ADDR 0x5001C000
  577 +#define IIM_BASE_ADDR MX31_IIM_BASE_ADDR
577 578  
578 579 #define PDR0_CSI_PODF(x) (((x) & 0x3f) << 26)
579 580 #define PDR0_CSI_PRDF(x) (((x) & 0x7) << 23)
arch/powerpc/include/asm/immap_512x.h
... ... @@ -1272,5 +1272,7 @@
1272 1272 #define CONFIG_SYS_MPC512x_USB_ADDR \
1273 1273 (CONFIG_SYS_IMMR + CONFIG_SYS_MPC512x_USB_OFFSET)
1274 1274  
  1275 +#define IIM_BASE_ADDR (CONFIG_SYS_IMMR + offsetof(immap_t, iim))
  1276 +
1275 1277 #endif /* __IMMAP_512x__ */
  1 +Driver implementing the fuse API for Freescale's IC Identification Module (IIM)
  2 +
  3 +This IP can be found on the following SoCs:
  4 + - MPC512x,
  5 + - i.MX25,
  6 + - i.MX27,
  7 + - i.MX31,
  8 + - i.MX35,
  9 + - i.MX51,
  10 + - i.MX53.
  11 +
  12 +The section numbers in this file refer to the i.MX25 Reference Manual.
  13 +
  14 +A fuse word contains 8 fuse bit slots, as explained in 30.4.2.2.1.
  15 +
  16 +A bank contains 256 fuse word slots, as shown by the memory map in 30.3.1.
  17 +
  18 +Some fuse bit or word slots may not have the corresponding fuses actually
  19 +implemented in the fusebox.
  20 +
  21 +See the README files of the SoCs using this driver in order to know the
  22 +conventions used by U-Boot to store some specific data in the fuses, e.g. MAC
  23 +addresses.
  24 +
  25 +Fuse operations:
  26 +
  27 + Read
  28 + Read operations are implemented as read accesses to the shadow registers,
  29 + using "Word y of Bank x" from the register summary in 30.3.2. This is
  30 + explained in detail in 30.4.5.1.
  31 +
  32 + Sense
  33 + Sense operations are implemented as explained in 30.4.5.2.
  34 +
  35 + Program
  36 + Program operations are implemented as explained in 30.4.5.3. Following
  37 + this operation, the shadow registers are reloaded by the hardware (not
  38 + immediately, but this does not make any difference for a user reading
  39 + these registers).
  40 +
  41 + Override
  42 + Override operations are implemented as write accesses to the shadow
  43 + registers, as explained in 30.4.5.4.
  44 +
  45 +Configuration:
  46 +
  47 + CONFIG_FSL_IIM
  48 + Define this to enable the fsl_iim driver.
drivers/misc/Makefile
... ... @@ -28,6 +28,7 @@
28 28 COBJS-$(CONFIG_ALI152X) += ali512x.o
29 29 COBJS-$(CONFIG_DS4510) += ds4510.o
30 30 COBJS-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
  31 +COBJS-$(CONFIG_FSL_IIM) += fsl_iim.o
31 32 COBJS-$(CONFIG_GPIO_LED) += gpio_led.o
32 33 COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
33 34 COBJS-$(CONFIG_NS87308) += ns87308.o
drivers/misc/fsl_iim.c
  1 +/*
  2 + * (C) Copyright 2009-2013 ADVANSEE
  3 + * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
  4 + *
  5 + * Based on the mpc512x iim code:
  6 + * Copyright 2008 Silicon Turnkey Express, Inc.
  7 + * Martha Marx <mmarx@silicontkx.com>
  8 + *
  9 + * See file CREDITS for list of people who contributed to this
  10 + * project.
  11 + *
  12 + * This program is free software; you can redistribute it and/or
  13 + * modify it under the terms of the GNU General Public License as
  14 + * published by the Free Software Foundation; either version 2 of
  15 + * the License, or (at your option) any later version.
  16 + *
  17 + * This program is distributed in the hope that it will be useful,
  18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20 + * GNU General Public License for more details.
  21 + *
  22 + * You should have received a copy of the GNU General Public License
  23 + * along with this program; if not, write to the Free Software
  24 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  25 + * MA 02111-1307 USA
  26 + */
  27 +
  28 +#include <common.h>
  29 +#include <fuse.h>
  30 +#include <asm/errno.h>
  31 +#include <asm/io.h>
  32 +#ifndef CONFIG_MPC512X
  33 +#include <asm/arch/imx-regs.h>
  34 +#endif
  35 +
  36 +/* FSL IIM-specific constants */
  37 +#define STAT_BUSY 0x80
  38 +#define STAT_PRGD 0x02
  39 +#define STAT_SNSD 0x01
  40 +
  41 +#define STATM_PRGD_M 0x02
  42 +#define STATM_SNSD_M 0x01
  43 +
  44 +#define ERR_PRGE 0x80
  45 +#define ERR_WPE 0x40
  46 +#define ERR_OPE 0x20
  47 +#define ERR_RPE 0x10
  48 +#define ERR_WLRE 0x08
  49 +#define ERR_SNSE 0x04
  50 +#define ERR_PARITYE 0x02
  51 +
  52 +#define EMASK_PRGE_M 0x80
  53 +#define EMASK_WPE_M 0x40
  54 +#define EMASK_OPE_M 0x20
  55 +#define EMASK_RPE_M 0x10
  56 +#define EMASK_WLRE_M 0x08
  57 +#define EMASK_SNSE_M 0x04
  58 +#define EMASK_PARITYE_M 0x02
  59 +
  60 +#define FCTL_DPC 0x80
  61 +#define FCTL_PRG_LENGTH_MASK 0x70
  62 +#define FCTL_ESNS_N 0x08
  63 +#define FCTL_ESNS_0 0x04
  64 +#define FCTL_ESNS_1 0x02
  65 +#define FCTL_PRG 0x01
  66 +
  67 +#define UA_A_BANK_MASK 0x38
  68 +#define UA_A_ROWH_MASK 0x07
  69 +
  70 +#define LA_A_ROWL_MASK 0xf8
  71 +#define LA_A_BIT_MASK 0x07
  72 +
  73 +#define PREV_PROD_REV_MASK 0xf8
  74 +#define PREV_PROD_VT_MASK 0x07
  75 +
  76 +/* Select the correct accessors depending on endianness */
  77 +#if __BYTE_ORDER == __LITTLE_ENDIAN
  78 +#define iim_read32 in_le32
  79 +#define iim_write32 out_le32
  80 +#define iim_clrsetbits32 clrsetbits_le32
  81 +#define iim_clrbits32 clrbits_le32
  82 +#define iim_setbits32 setbits_le32
  83 +#elif __BYTE_ORDER == __BIG_ENDIAN
  84 +#define iim_read32 in_be32
  85 +#define iim_write32 out_be32
  86 +#define iim_clrsetbits32 clrsetbits_be32
  87 +#define iim_clrbits32 clrbits_be32
  88 +#define iim_setbits32 setbits_be32
  89 +#else
  90 +#error Endianess is not defined: please fix to continue
  91 +#endif
  92 +
  93 +/* IIM control registers */
  94 +struct fsl_iim {
  95 + u32 stat;
  96 + u32 statm;
  97 + u32 err;
  98 + u32 emask;
  99 + u32 fctl;
  100 + u32 ua;
  101 + u32 la;
  102 + u32 sdat;
  103 + u32 prev;
  104 + u32 srev;
  105 + u32 prg_p;
  106 + u32 scs[0x1f5];
  107 + struct {
  108 + u32 word[0x100];
  109 + } bank[8];
  110 +};
  111 +
  112 +static int prepare_access(struct fsl_iim **regs, u32 bank, u32 word, int assert,
  113 + const char *caller)
  114 +{
  115 + *regs = (struct fsl_iim *)IIM_BASE_ADDR;
  116 +
  117 + if (bank >= ARRAY_SIZE((*regs)->bank) ||
  118 + word >= ARRAY_SIZE((*regs)->bank[0].word) ||
  119 + !assert) {
  120 + printf("fsl_iim %s(): Invalid argument\n", caller);
  121 + return -EINVAL;
  122 + }
  123 +
  124 + return 0;
  125 +}
  126 +
  127 +static void clear_status(struct fsl_iim *regs)
  128 +{
  129 + iim_setbits32(&regs->stat, 0);
  130 + iim_setbits32(&regs->err, 0);
  131 +}
  132 +
  133 +static void finish_access(struct fsl_iim *regs, u32 *stat, u32 *err)
  134 +{
  135 + *stat = iim_read32(&regs->stat);
  136 + *err = iim_read32(&regs->err);
  137 + clear_status(regs);
  138 +}
  139 +
  140 +static int prepare_read(struct fsl_iim **regs, u32 bank, u32 word, u32 *val,
  141 + const char *caller)
  142 +{
  143 + int ret;
  144 +
  145 + ret = prepare_access(regs, bank, word, val != NULL, caller);
  146 + if (ret)
  147 + return ret;
  148 +
  149 + clear_status(*regs);
  150 +
  151 + return 0;
  152 +}
  153 +
  154 +int fuse_read(u32 bank, u32 word, u32 *val)
  155 +{
  156 + struct fsl_iim *regs;
  157 + u32 stat, err;
  158 + int ret;
  159 +
  160 + ret = prepare_read(&regs, bank, word, val, __func__);
  161 + if (ret)
  162 + return ret;
  163 +
  164 + *val = iim_read32(&regs->bank[bank].word[word]);
  165 + finish_access(regs, &stat, &err);
  166 +
  167 + if (err & ERR_RPE) {
  168 + puts("fsl_iim fuse_read(): Read protect error\n");
  169 + return -EIO;
  170 + }
  171 +
  172 + return 0;
  173 +}
  174 +
  175 +static void direct_access(struct fsl_iim *regs, u32 bank, u32 word, u32 bit,
  176 + u32 fctl, u32 *stat, u32 *err)
  177 +{
  178 + iim_write32(&regs->ua, bank << 3 | word >> 5);
  179 + iim_write32(&regs->la, (word << 3 | bit) & 0xff);
  180 + if (fctl == FCTL_PRG)
  181 + iim_write32(&regs->prg_p, 0xaa);
  182 + iim_setbits32(&regs->fctl, fctl);
  183 + while (iim_read32(&regs->stat) & STAT_BUSY)
  184 + udelay(20);
  185 + finish_access(regs, stat, err);
  186 +}
  187 +
  188 +int fuse_sense(u32 bank, u32 word, u32 *val)
  189 +{
  190 + struct fsl_iim *regs;
  191 + u32 stat, err;
  192 + int ret;
  193 +
  194 + ret = prepare_read(&regs, bank, word, val, __func__);
  195 + if (ret)
  196 + return ret;
  197 +
  198 + direct_access(regs, bank, word, 0, FCTL_ESNS_N, &stat, &err);
  199 +
  200 + if (err & ERR_SNSE) {
  201 + puts("fsl_iim fuse_sense(): Explicit sense cycle error\n");
  202 + return -EIO;
  203 + }
  204 +
  205 + if (!(stat & STAT_SNSD)) {
  206 + puts("fsl_iim fuse_sense(): Explicit sense cycle did not complete\n");
  207 + return -EIO;
  208 + }
  209 +
  210 + *val = iim_read32(&regs->sdat);
  211 + return 0;
  212 +}
  213 +
  214 +static int prog_bit(struct fsl_iim *regs, u32 bank, u32 word, u32 bit)
  215 +{
  216 + u32 stat, err;
  217 +
  218 + clear_status(regs);
  219 + direct_access(regs, bank, word, bit, FCTL_PRG, &stat, &err);
  220 + iim_write32(&regs->prg_p, 0x00);
  221 +
  222 + if (err & ERR_PRGE) {
  223 + puts("fsl_iim fuse_prog(): Program error\n");
  224 + return -EIO;
  225 + }
  226 +
  227 + if (err & ERR_WPE) {
  228 + puts("fsl_iim fuse_prog(): Write protect error\n");
  229 + return -EIO;
  230 + }
  231 +
  232 + if (!(stat & STAT_PRGD)) {
  233 + puts("fsl_iim fuse_prog(): Program did not complete\n");
  234 + return -EIO;
  235 + }
  236 +
  237 + return 0;
  238 +}
  239 +
  240 +static int prepare_write(struct fsl_iim **regs, u32 bank, u32 word, u32 val,
  241 + const char *caller)
  242 +{
  243 + return prepare_access(regs, bank, word, !(val & ~0xff), caller);
  244 +}
  245 +
  246 +int fuse_prog(u32 bank, u32 word, u32 val)
  247 +{
  248 + struct fsl_iim *regs;
  249 + u32 bit;
  250 + int ret;
  251 +
  252 + ret = prepare_write(&regs, bank, word, val, __func__);
  253 + if (ret)
  254 + return ret;
  255 +
  256 + for (bit = 0; val; bit++, val >>= 1)
  257 + if (val & 0x01) {
  258 + ret = prog_bit(regs, bank, word, bit);
  259 + if (ret)
  260 + return ret;
  261 + }
  262 +
  263 + return 0;
  264 +}
  265 +
  266 +int fuse_override(u32 bank, u32 word, u32 val)
  267 +{
  268 + struct fsl_iim *regs;
  269 + u32 stat, err;
  270 + int ret;
  271 +
  272 + ret = prepare_write(&regs, bank, word, val, __func__);
  273 + if (ret)
  274 + return ret;
  275 +
  276 + clear_status(regs);
  277 + iim_write32(&regs->bank[bank].word[word], val);
  278 + finish_access(regs, &stat, &err);
  279 +
  280 + if (err & ERR_OPE) {
  281 + puts("fsl_iim fuse_override(): Override protect error\n");
  282 + return -EIO;
  283 + }
  284 +
  285 + return 0;
  286 +}