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