uboot/drivers/misc/fsl_iim.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2009-2013 ADVANSEE
   4 * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
   5 *
   6 * Based on the mpc512x iim code:
   7 * Copyright 2008 Silicon Turnkey Express, Inc.
   8 * Martha Marx <mmarx@silicontkx.com>
   9 */
  10
  11#include <common.h>
  12#include <fuse.h>
  13#include <linux/delay.h>
  14#include <linux/errno.h>
  15#include <asm/io.h>
  16#include <asm/arch/imx-regs.h>
  17#if defined(CONFIG_MX51) || defined(CONFIG_MX53)
  18#include <asm/arch/clock.h>
  19#endif
  20
  21/* FSL IIM-specific constants */
  22#define STAT_BUSY               0x80
  23#define STAT_PRGD               0x02
  24#define STAT_SNSD               0x01
  25
  26#define STATM_PRGD_M            0x02
  27#define STATM_SNSD_M            0x01
  28
  29#define ERR_PRGE                0x80
  30#define ERR_WPE                 0x40
  31#define ERR_OPE                 0x20
  32#define ERR_RPE                 0x10
  33#define ERR_WLRE                0x08
  34#define ERR_SNSE                0x04
  35#define ERR_PARITYE             0x02
  36
  37#define EMASK_PRGE_M            0x80
  38#define EMASK_WPE_M             0x40
  39#define EMASK_OPE_M             0x20
  40#define EMASK_RPE_M             0x10
  41#define EMASK_WLRE_M            0x08
  42#define EMASK_SNSE_M            0x04
  43#define EMASK_PARITYE_M         0x02
  44
  45#define FCTL_DPC                0x80
  46#define FCTL_PRG_LENGTH_MASK    0x70
  47#define FCTL_ESNS_N             0x08
  48#define FCTL_ESNS_0             0x04
  49#define FCTL_ESNS_1             0x02
  50#define FCTL_PRG                0x01
  51
  52#define UA_A_BANK_MASK          0x38
  53#define UA_A_ROWH_MASK          0x07
  54
  55#define LA_A_ROWL_MASK          0xf8
  56#define LA_A_BIT_MASK           0x07
  57
  58#define PREV_PROD_REV_MASK      0xf8
  59#define PREV_PROD_VT_MASK       0x07
  60
  61/* Select the correct accessors depending on endianness */
  62#if __BYTE_ORDER == __LITTLE_ENDIAN
  63#define iim_read32              in_le32
  64#define iim_write32             out_le32
  65#define iim_clrsetbits32        clrsetbits_le32
  66#define iim_clrbits32           clrbits_le32
  67#define iim_setbits32           setbits_le32
  68#elif __BYTE_ORDER == __BIG_ENDIAN
  69#define iim_read32              in_be32
  70#define iim_write32             out_be32
  71#define iim_clrsetbits32        clrsetbits_be32
  72#define iim_clrbits32           clrbits_be32
  73#define iim_setbits32           setbits_be32
  74#else
  75#error Endianess is not defined: please fix to continue
  76#endif
  77
  78/* IIM control registers */
  79struct fsl_iim {
  80        u32 stat;
  81        u32 statm;
  82        u32 err;
  83        u32 emask;
  84        u32 fctl;
  85        u32 ua;
  86        u32 la;
  87        u32 sdat;
  88        u32 prev;
  89        u32 srev;
  90        u32 prg_p;
  91        u32 scs[0x1f5];
  92        struct {
  93                u32 word[0x100];
  94        } bank[8];
  95};
  96
  97#if !defined(CONFIG_MX51) && !defined(CONFIG_MX53)
  98#define enable_efuse_prog_supply(enable)
  99#endif
 100
 101static int prepare_access(struct fsl_iim **regs, u32 bank, u32 word, int assert,
 102                                const char *caller)
 103{
 104        *regs = (struct fsl_iim *)IIM_BASE_ADDR;
 105
 106        if (bank >= ARRAY_SIZE((*regs)->bank) ||
 107                        word >= ARRAY_SIZE((*regs)->bank[0].word) ||
 108                        !assert) {
 109                printf("fsl_iim %s(): Invalid argument\n", caller);
 110                return -EINVAL;
 111        }
 112
 113        return 0;
 114}
 115
 116static void clear_status(struct fsl_iim *regs)
 117{
 118        iim_setbits32(&regs->stat, 0);
 119        iim_setbits32(&regs->err, 0);
 120}
 121
 122static void finish_access(struct fsl_iim *regs, u32 *stat, u32 *err)
 123{
 124        *stat = iim_read32(&regs->stat);
 125        *err = iim_read32(&regs->err);
 126        clear_status(regs);
 127}
 128
 129static int prepare_read(struct fsl_iim **regs, u32 bank, u32 word, u32 *val,
 130                        const char *caller)
 131{
 132        int ret;
 133
 134        ret = prepare_access(regs, bank, word, val != NULL, caller);
 135        if (ret)
 136                return ret;
 137
 138        clear_status(*regs);
 139
 140        return 0;
 141}
 142
 143int fuse_read(u32 bank, u32 word, u32 *val)
 144{
 145        struct fsl_iim *regs;
 146        u32 stat, err;
 147        int ret;
 148
 149        ret = prepare_read(&regs, bank, word, val, __func__);
 150        if (ret)
 151                return ret;
 152
 153        *val = iim_read32(&regs->bank[bank].word[word]);
 154        finish_access(regs, &stat, &err);
 155
 156        if (err & ERR_RPE) {
 157                puts("fsl_iim fuse_read(): Read protect error\n");
 158                return -EIO;
 159        }
 160
 161        return 0;
 162}
 163
 164static void direct_access(struct fsl_iim *regs, u32 bank, u32 word, u32 bit,
 165                                u32 fctl, u32 *stat, u32 *err)
 166{
 167        iim_write32(&regs->ua, bank << 3 | word >> 5);
 168        iim_write32(&regs->la, (word << 3 | bit) & 0xff);
 169        if (fctl == FCTL_PRG)
 170                iim_write32(&regs->prg_p, 0xaa);
 171        iim_setbits32(&regs->fctl, fctl);
 172        while (iim_read32(&regs->stat) & STAT_BUSY)
 173                udelay(20);
 174        finish_access(regs, stat, err);
 175}
 176
 177int fuse_sense(u32 bank, u32 word, u32 *val)
 178{
 179        struct fsl_iim *regs;
 180        u32 stat, err;
 181        int ret;
 182
 183        ret = prepare_read(&regs, bank, word, val, __func__);
 184        if (ret)
 185                return ret;
 186
 187        direct_access(regs, bank, word, 0, FCTL_ESNS_N, &stat, &err);
 188
 189        if (err & ERR_SNSE) {
 190                puts("fsl_iim fuse_sense(): Explicit sense cycle error\n");
 191                return -EIO;
 192        }
 193
 194        if (!(stat & STAT_SNSD)) {
 195                puts("fsl_iim fuse_sense(): Explicit sense cycle did not complete\n");
 196                return -EIO;
 197        }
 198
 199        *val = iim_read32(&regs->sdat);
 200        return 0;
 201}
 202
 203static int prog_bit(struct fsl_iim *regs, u32 bank, u32 word, u32 bit)
 204{
 205        u32 stat, err;
 206
 207        clear_status(regs);
 208        direct_access(regs, bank, word, bit, FCTL_PRG, &stat, &err);
 209        iim_write32(&regs->prg_p, 0x00);
 210
 211        if (err & ERR_PRGE) {
 212                puts("fsl_iim fuse_prog(): Program error\n");
 213                return -EIO;
 214        }
 215
 216        if (err & ERR_WPE) {
 217                puts("fsl_iim fuse_prog(): Write protect error\n");
 218                return -EIO;
 219        }
 220
 221        if (!(stat & STAT_PRGD)) {
 222                puts("fsl_iim fuse_prog(): Program did not complete\n");
 223                return -EIO;
 224        }
 225
 226        return 0;
 227}
 228
 229static int prepare_write(struct fsl_iim **regs, u32 bank, u32 word, u32 val,
 230                                const char *caller)
 231{
 232        return prepare_access(regs, bank, word, !(val & ~0xff), caller);
 233}
 234
 235int fuse_prog(u32 bank, u32 word, u32 val)
 236{
 237        struct fsl_iim *regs;
 238        u32 bit;
 239        int ret;
 240
 241        ret = prepare_write(&regs, bank, word, val, __func__);
 242        if (ret)
 243                return ret;
 244
 245        enable_efuse_prog_supply(1);
 246        for (bit = 0; val; bit++, val >>= 1)
 247                if (val & 0x01) {
 248                        ret = prog_bit(regs, bank, word, bit);
 249                        if (ret) {
 250                                enable_efuse_prog_supply(0);
 251                                return ret;
 252                        }
 253                }
 254        enable_efuse_prog_supply(0);
 255
 256        return 0;
 257}
 258
 259int fuse_override(u32 bank, u32 word, u32 val)
 260{
 261        struct fsl_iim *regs;
 262        u32 stat, err;
 263        int ret;
 264
 265        ret = prepare_write(&regs, bank, word, val, __func__);
 266        if (ret)
 267                return ret;
 268
 269        clear_status(regs);
 270        iim_write32(&regs->bank[bank].word[word], val);
 271        finish_access(regs, &stat, &err);
 272
 273        if (err & ERR_OPE) {
 274                puts("fsl_iim fuse_override(): Override protect error\n");
 275                return -EIO;
 276        }
 277
 278        return 0;
 279}
 280