uboot/drivers/misc/mxc_ocotp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2013 ADVANSEE
   4 * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
   5 *
   6 * Based on Dirk Behme's
   7 * https://github.com/dirkbehme/u-boot-imx6/blob/28b17e9/drivers/misc/imx_otp.c,
   8 * which is based on Freescale's
   9 * http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/tree/drivers/misc/imx_otp.c?h=imx_v2009.08_1.1.0&id=9aa74e6,
  10 * which is:
  11 * Copyright (C) 2011 Freescale Semiconductor, Inc.
  12 */
  13
  14#include <common.h>
  15#include <fuse.h>
  16#include <linux/delay.h>
  17#include <linux/errno.h>
  18#include <asm/io.h>
  19#include <asm/arch/clock.h>
  20#include <asm/arch/imx-regs.h>
  21#include <asm/mach-imx/sys_proto.h>
  22
  23#define BO_CTRL_WR_UNLOCK               16
  24#define BM_CTRL_WR_UNLOCK               0xffff0000
  25#define BV_CTRL_WR_UNLOCK_KEY           0x3e77
  26#define BM_CTRL_ERROR                   0x00000200
  27#define BM_CTRL_BUSY                    0x00000100
  28#define BO_CTRL_ADDR                    0
  29#ifdef CONFIG_MX7
  30#define BM_CTRL_ADDR                    0x0000000f
  31#define BM_CTRL_RELOAD                  0x00000400
  32#elif defined(CONFIG_MX7ULP)
  33#define BM_CTRL_ADDR                    0x000000FF
  34#define BM_CTRL_RELOAD                  0x00000400
  35#define BM_OUT_STATUS_DED                               0x00000400
  36#define BM_OUT_STATUS_LOCKED                    0x00000800
  37#define BM_OUT_STATUS_PROGFAIL                  0x00001000
  38#elif defined(CONFIG_IMX8M)
  39#ifdef CONFIG_IMX8MP
  40#undef BM_CTRL_ADDR
  41#undef BM_CTRL_ERROR
  42#undef BM_CTRL_BUSY
  43#define BM_CTRL_ADDR                    0x000001ff
  44#define BM_CTRL_ERROR                   0x00000400
  45#define BM_CTRL_BUSY                    0x00000200
  46#else
  47#define BM_CTRL_ADDR                    0x000000ff
  48#endif
  49#else
  50#define BM_CTRL_ADDR                    0x0000007f
  51#endif
  52
  53#ifdef CONFIG_MX7
  54#define BO_TIMING_FSOURCE               12
  55#define BM_TIMING_FSOURCE               0x0007f000
  56#define BV_TIMING_FSOURCE_NS            1001
  57#define BO_TIMING_PROG                  0
  58#define BM_TIMING_PROG                  0x00000fff
  59#define BV_TIMING_PROG_US               10
  60#else
  61#define BO_TIMING_STROBE_READ           16
  62#define BM_TIMING_STROBE_READ           0x003f0000
  63#define BV_TIMING_STROBE_READ_NS        37
  64#define BO_TIMING_RELAX                 12
  65#define BM_TIMING_RELAX                 0x0000f000
  66#define BV_TIMING_RELAX_NS              17
  67#define BO_TIMING_STROBE_PROG           0
  68#define BM_TIMING_STROBE_PROG           0x00000fff
  69#define BV_TIMING_STROBE_PROG_US        10
  70#endif
  71
  72#define BM_READ_CTRL_READ_FUSE          0x00000001
  73
  74#define BF(value, field)                (((value) << BO_##field) & BM_##field)
  75
  76#define WRITE_POSTAMBLE_US              2
  77
  78#if defined(CONFIG_MX6) || defined(CONFIG_VF610)
  79#define FUSE_BANK_SIZE  0x80
  80#ifdef CONFIG_MX6SL
  81#define FUSE_BANKS      8
  82#elif defined(CONFIG_MX6ULL) || defined(CONFIG_MX6SLL)
  83#define FUSE_BANKS      9
  84#else
  85#define FUSE_BANKS      16
  86#endif
  87#elif defined CONFIG_MX7
  88#define FUSE_BANK_SIZE  0x40
  89#define FUSE_BANKS      16
  90#elif defined(CONFIG_MX7ULP)
  91#define FUSE_BANK_SIZE  0x80
  92#define FUSE_BANKS      31
  93#elif defined(CONFIG_IMX8M)
  94#define FUSE_BANK_SIZE  0x40
  95#ifdef CONFIG_IMX8MP
  96#define FUSE_BANKS      96
  97#else
  98#define FUSE_BANKS      64
  99#endif
 100#else
 101#error "Unsupported architecture\n"
 102#endif
 103
 104#if defined(CONFIG_MX6)
 105
 106/*
 107 * There is a hole in shadow registers address map of size 0x100
 108 * between bank 5 and bank 6 on iMX6QP, iMX6DQ, iMX6SDL, iMX6SX,
 109 * iMX6UL, i.MX6ULL and i.MX6SLL.
 110 * Bank 5 ends at 0x6F0 and Bank 6 starts at 0x800. When reading the fuses,
 111 * we should account for this hole in address space.
 112 *
 113 * Similar hole exists between bank 14 and bank 15 of size
 114 * 0x80 on iMX6QP, iMX6DQ, iMX6SDL and iMX6SX.
 115 * Note: iMX6SL has only 0-7 banks and there is no hole.
 116 * Note: iMX6UL doesn't have this one.
 117 *
 118 * This function is to covert user input to physical bank index.
 119 * Only needed when read fuse, because we use register offset, so
 120 * need to calculate real register offset.
 121 * When write, no need to consider hole, always use the bank/word
 122 * index from fuse map.
 123 */
 124u32 fuse_bank_physical(int index)
 125{
 126        u32 phy_index;
 127
 128        if (is_mx6sl() || is_mx7ulp()) {
 129                phy_index = index;
 130        } else if (is_mx6ul() || is_mx6ull() || is_mx6sll()) {
 131                if ((is_mx6ull() || is_mx6sll()) && index == 8)
 132                        index = 7;
 133
 134                if (index >= 6)
 135                        phy_index = fuse_bank_physical(5) + (index - 6) + 3;
 136                else
 137                        phy_index = index;
 138        } else {
 139                if (index >= 15)
 140                        phy_index = fuse_bank_physical(14) + (index - 15) + 2;
 141                else if (index >= 6)
 142                        phy_index = fuse_bank_physical(5) + (index - 6) + 3;
 143                else
 144                        phy_index = index;
 145        }
 146        return phy_index;
 147}
 148
 149u32 fuse_word_physical(u32 bank, u32 word_index)
 150{
 151        if (is_mx6ull() || is_mx6sll()) {
 152                if (bank == 8)
 153                        word_index = word_index + 4;
 154        }
 155
 156        return word_index;
 157}
 158#else
 159u32 fuse_bank_physical(int index)
 160{
 161        return index;
 162}
 163
 164u32 fuse_word_physical(u32 bank, u32 word_index)
 165{
 166        return word_index;
 167}
 168
 169#endif
 170
 171static void wait_busy(struct ocotp_regs *regs, unsigned int delay_us)
 172{
 173        while (readl(&regs->ctrl) & BM_CTRL_BUSY)
 174                udelay(delay_us);
 175}
 176
 177static void clear_error(struct ocotp_regs *regs)
 178{
 179        writel(BM_CTRL_ERROR, &regs->ctrl_clr);
 180}
 181
 182static int prepare_access(struct ocotp_regs **regs, u32 bank, u32 word,
 183                                int assert, const char *caller)
 184{
 185        *regs = (struct ocotp_regs *)OCOTP_BASE_ADDR;
 186
 187        if (bank >= FUSE_BANKS ||
 188            word >= ARRAY_SIZE((*regs)->bank[0].fuse_regs) >> 2 ||
 189            !assert) {
 190                printf("mxc_ocotp %s(): Invalid argument\n", caller);
 191                return -EINVAL;
 192        }
 193
 194        if (is_mx6ull() || is_mx6sll()) {
 195                if ((bank == 7 || bank == 8) &&
 196                    word >= ARRAY_SIZE((*regs)->bank[0].fuse_regs) >> 3) {
 197                        printf("mxc_ocotp %s(): Invalid argument\n", caller);
 198                        return -EINVAL;
 199                }
 200        }
 201
 202        enable_ocotp_clk(1);
 203
 204        wait_busy(*regs, 1);
 205        clear_error(*regs);
 206
 207        return 0;
 208}
 209
 210static int finish_access(struct ocotp_regs *regs, const char *caller)
 211{
 212        u32 err;
 213
 214        err = !!(readl(&regs->ctrl) & BM_CTRL_ERROR);
 215        clear_error(regs);
 216
 217#ifdef CONFIG_MX7ULP
 218        /* Need to power down the OTP memory */
 219        writel(1, &regs->pdn);
 220#endif
 221        if (err) {
 222                printf("mxc_ocotp %s(): Access protect error\n", caller);
 223                return -EIO;
 224        }
 225
 226        return 0;
 227}
 228
 229static int prepare_read(struct ocotp_regs **regs, u32 bank, u32 word, u32 *val,
 230                        const char *caller)
 231{
 232        return prepare_access(regs, bank, word, val != NULL, caller);
 233}
 234
 235int fuse_read(u32 bank, u32 word, u32 *val)
 236{
 237        struct ocotp_regs *regs;
 238        int ret;
 239        u32 phy_bank;
 240        u32 phy_word;
 241
 242        ret = prepare_read(&regs, bank, word, val, __func__);
 243        if (ret)
 244                return ret;
 245
 246        phy_bank = fuse_bank_physical(bank);
 247        phy_word = fuse_word_physical(bank, word);
 248
 249        *val = readl(&regs->bank[phy_bank].fuse_regs[phy_word << 2]);
 250
 251#ifdef CONFIG_MX7ULP
 252        if (readl(&regs->out_status) & BM_OUT_STATUS_DED) {
 253                writel(BM_OUT_STATUS_DED, &regs->out_status_clr);
 254                printf("mxc_ocotp %s(): fuse read wrong\n", __func__);
 255                return -EIO;
 256        }
 257#endif
 258        return finish_access(regs, __func__);
 259}
 260
 261#ifdef CONFIG_MX7
 262static void set_timing(struct ocotp_regs *regs)
 263{
 264        u32 ipg_clk;
 265        u32 fsource, prog;
 266        u32 timing;
 267
 268        ipg_clk = mxc_get_clock(MXC_IPG_CLK);
 269
 270        fsource = DIV_ROUND_UP((ipg_clk / 1000) * BV_TIMING_FSOURCE_NS,
 271                        +       1000000) + 1;
 272        prog = DIV_ROUND_CLOSEST(ipg_clk * BV_TIMING_PROG_US, 1000000) + 1;
 273
 274        timing = BF(fsource, TIMING_FSOURCE) | BF(prog, TIMING_PROG);
 275
 276        clrsetbits_le32(&regs->timing, BM_TIMING_FSOURCE | BM_TIMING_PROG,
 277                        timing);
 278}
 279#elif defined(CONFIG_MX7ULP)
 280static void set_timing(struct ocotp_regs *regs)
 281{
 282        /* No timing set for MX7ULP */
 283}
 284
 285#else
 286static void set_timing(struct ocotp_regs *regs)
 287{
 288        u32 ipg_clk;
 289        u32 relax, strobe_read, strobe_prog;
 290        u32 timing;
 291
 292        ipg_clk = mxc_get_clock(MXC_IPG_CLK);
 293
 294        relax = DIV_ROUND_UP(ipg_clk * BV_TIMING_RELAX_NS, 1000000000) - 1;
 295        strobe_read = DIV_ROUND_UP(ipg_clk * BV_TIMING_STROBE_READ_NS,
 296                                        1000000000) + 2 * (relax + 1) - 1;
 297        strobe_prog = DIV_ROUND_CLOSEST(ipg_clk * BV_TIMING_STROBE_PROG_US,
 298                                                1000000) + 2 * (relax + 1) - 1;
 299
 300        timing = BF(strobe_read, TIMING_STROBE_READ) |
 301                        BF(relax, TIMING_RELAX) |
 302                        BF(strobe_prog, TIMING_STROBE_PROG);
 303
 304        clrsetbits_le32(&regs->timing, BM_TIMING_STROBE_READ | BM_TIMING_RELAX |
 305                        BM_TIMING_STROBE_PROG, timing);
 306}
 307#endif
 308
 309static void setup_direct_access(struct ocotp_regs *regs, u32 bank, u32 word,
 310                                int write)
 311{
 312        u32 wr_unlock = write ? BV_CTRL_WR_UNLOCK_KEY : 0;
 313#ifdef CONFIG_MX7
 314        u32 addr = bank;
 315#elif defined CONFIG_IMX8M
 316        u32 addr = bank << 2 | word;
 317#else
 318        u32 addr;
 319        /* Bank 7 and Bank 8 only supports 4 words each for i.MX6ULL */
 320        if ((is_mx6ull() || is_mx6sll()) && (bank > 7)) {
 321                bank = bank - 1;
 322                word += 4;
 323        }
 324        addr = bank << 3 | word;
 325#endif
 326
 327        set_timing(regs);
 328        clrsetbits_le32(&regs->ctrl, BM_CTRL_WR_UNLOCK | BM_CTRL_ADDR,
 329                        BF(wr_unlock, CTRL_WR_UNLOCK) |
 330                        BF(addr, CTRL_ADDR));
 331}
 332
 333int fuse_sense(u32 bank, u32 word, u32 *val)
 334{
 335        struct ocotp_regs *regs;
 336        int ret;
 337
 338        if (is_imx8mq() && is_soc_rev(CHIP_REV_2_1)) {
 339                printf("mxc_ocotp %s(): fuse sense is disabled\n", __func__);
 340                return -EPERM;
 341        }
 342
 343        ret = prepare_read(&regs, bank, word, val, __func__);
 344        if (ret)
 345                return ret;
 346
 347        setup_direct_access(regs, bank, word, false);
 348        writel(BM_READ_CTRL_READ_FUSE, &regs->read_ctrl);
 349        wait_busy(regs, 1);
 350#ifdef CONFIG_MX7
 351        *val = readl((&regs->read_fuse_data0) + (word << 2));
 352#else
 353        *val = readl(&regs->read_fuse_data);
 354#endif
 355
 356#ifdef CONFIG_MX7ULP
 357        if (readl(&regs->out_status) & BM_OUT_STATUS_DED) {
 358                writel(BM_OUT_STATUS_DED, &regs->out_status_clr);
 359                printf("mxc_ocotp %s(): fuse read wrong\n", __func__);
 360                return -EIO;
 361        }
 362#endif
 363
 364        return finish_access(regs, __func__);
 365}
 366
 367static int prepare_write(struct ocotp_regs **regs, u32 bank, u32 word,
 368                                const char *caller)
 369{
 370#ifdef CONFIG_MX7ULP
 371        u32 val;
 372        int ret;
 373
 374        /* Only bank 0 and 1 are redundancy mode, others are ECC mode */
 375        if (bank != 0 && bank != 1) {
 376                if ((soc_rev() < CHIP_REV_2_0) ||
 377                    ((soc_rev() >= CHIP_REV_2_0) &&
 378                    bank != 9 && bank != 10 && bank != 28)) {
 379                        ret = fuse_sense(bank, word, &val);
 380                        if (ret)
 381                                return ret;
 382
 383                        if (val != 0) {
 384                                printf("mxc_ocotp: The word has been programmed, no more write\n");
 385                                return -EPERM;
 386                        }
 387                }
 388        }
 389#endif
 390
 391        return prepare_access(regs, bank, word, true, caller);
 392}
 393
 394int fuse_prog(u32 bank, u32 word, u32 val)
 395{
 396        struct ocotp_regs *regs;
 397        int ret;
 398
 399        ret = prepare_write(&regs, bank, word, __func__);
 400        if (ret)
 401                return ret;
 402
 403        setup_direct_access(regs, bank, word, true);
 404#ifdef CONFIG_MX7
 405        switch (word) {
 406        case 0:
 407                writel(0, &regs->data1);
 408                writel(0, &regs->data2);
 409                writel(0, &regs->data3);
 410                writel(val, &regs->data0);
 411                break;
 412        case 1:
 413                writel(val, &regs->data1);
 414                writel(0, &regs->data2);
 415                writel(0, &regs->data3);
 416                writel(0, &regs->data0);
 417                break;
 418        case 2:
 419                writel(0, &regs->data1);
 420                writel(val, &regs->data2);
 421                writel(0, &regs->data3);
 422                writel(0, &regs->data0);
 423                break;
 424        case 3:
 425                writel(0, &regs->data1);
 426                writel(0, &regs->data2);
 427                writel(val, &regs->data3);
 428                writel(0, &regs->data0);
 429                break;
 430        }
 431        wait_busy(regs, BV_TIMING_PROG_US);
 432#else
 433        writel(val, &regs->data);
 434        wait_busy(regs, BV_TIMING_STROBE_PROG_US);
 435#endif
 436        udelay(WRITE_POSTAMBLE_US);
 437
 438#ifdef CONFIG_MX7ULP
 439        if (readl(&regs->out_status) & (BM_OUT_STATUS_PROGFAIL | BM_OUT_STATUS_LOCKED)) {
 440                writel((BM_OUT_STATUS_PROGFAIL | BM_OUT_STATUS_LOCKED), &regs->out_status_clr);
 441                printf("mxc_ocotp %s(): fuse write is failed\n", __func__);
 442                return -EIO;
 443        }
 444#endif
 445
 446        return finish_access(regs, __func__);
 447}
 448
 449int fuse_override(u32 bank, u32 word, u32 val)
 450{
 451        struct ocotp_regs *regs;
 452        int ret;
 453        u32 phy_bank;
 454        u32 phy_word;
 455
 456        ret = prepare_write(&regs, bank, word, __func__);
 457        if (ret)
 458                return ret;
 459
 460        phy_bank = fuse_bank_physical(bank);
 461        phy_word = fuse_word_physical(bank, word);
 462
 463        writel(val, &regs->bank[phy_bank].fuse_regs[phy_word << 2]);
 464
 465#ifdef CONFIG_MX7ULP
 466        if (readl(&regs->out_status) & (BM_OUT_STATUS_PROGFAIL | BM_OUT_STATUS_LOCKED)) {
 467                writel((BM_OUT_STATUS_PROGFAIL | BM_OUT_STATUS_LOCKED), &regs->out_status_clr);
 468                printf("mxc_ocotp %s(): fuse write is failed\n", __func__);
 469                return -EIO;
 470        }
 471#endif
 472
 473        return finish_access(regs, __func__);
 474}
 475