uboot/drivers/misc/jz4780_efuse.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * JZ4780 EFUSE driver
   4 *
   5 * Copyright (c) 2014 Imagination Technologies
   6 * Author: Alex Smith <alex.smith@imgtec.com>
   7 */
   8
   9#include <common.h>
  10#include <asm/io.h>
  11#include <asm/unaligned.h>
  12#include <errno.h>
  13#include <mach/jz4780.h>
  14#include <wait_bit.h>
  15
  16#define EFUSE_EFUCTRL                   0xd0
  17#define EFUSE_EFUCFG                    0xd4
  18#define EFUSE_EFUSTATE                  0xd8
  19#define EFUSE_EFUDATA(n)                (0xdc + ((n) * 4))
  20
  21#define EFUSE_EFUCTRL_RD_EN             BIT(0)
  22#define EFUSE_EFUCTRL_LEN_BIT           16
  23#define EFUSE_EFUCTRL_LEN_MASK          0x1f
  24#define EFUSE_EFUCTRL_ADDR_BIT          21
  25#define EFUSE_EFUCTRL_ADDR_MASK         0x1ff
  26#define EFUSE_EFUCTRL_CS                BIT(30)
  27
  28#define EFUSE_EFUCFG_RD_STROBE_BIT      16
  29#define EFUSE_EFUCFG_RD_STROBE_MASK     0xf
  30#define EFUSE_EFUCFG_RD_ADJ_BIT         20
  31#define EFUSE_EFUCFG_RD_ADJ_MASK        0xf
  32
  33#define EFUSE_EFUSTATE_RD_DONE          BIT(0)
  34
  35static void jz4780_efuse_read_chunk(size_t addr, size_t count, u8 *buf)
  36{
  37        void __iomem *regs = (void __iomem *)NEMC_BASE;
  38        size_t i;
  39        u32 val;
  40        int ret;
  41
  42        val = EFUSE_EFUCTRL_RD_EN |
  43                ((count - 1) << EFUSE_EFUCTRL_LEN_BIT) |
  44                (addr << EFUSE_EFUCTRL_ADDR_BIT) |
  45                ((addr > 0x200) ? EFUSE_EFUCTRL_CS : 0);
  46        writel(val, regs + EFUSE_EFUCTRL);
  47
  48        ret = wait_for_bit_le32(regs + EFUSE_EFUSTATE,
  49                                EFUSE_EFUSTATE_RD_DONE, true, 10000, false);
  50        if (ret)
  51                return;
  52
  53        if ((count % 4) == 0) {
  54                for (i = 0; i < count / 4; i++) {
  55                        val = readl(regs + EFUSE_EFUDATA(i));
  56                        put_unaligned(val, (u32 *)(buf + (i * 4)));
  57                }
  58        } else {
  59                val = readl(regs + EFUSE_EFUDATA(0));
  60                if (count > 2)
  61                        buf[2] = (val >> 16) & 0xff;
  62                if (count > 1)
  63                        buf[1] = (val >> 8) & 0xff;
  64                buf[0] = val & 0xff;
  65        }
  66}
  67
  68static inline int jz4780_efuse_chunk_size(size_t count)
  69{
  70        if (count >= 32)
  71                return 32;
  72        else if ((count / 4) > 0)
  73                return (count / 4) * 4;
  74        else
  75                return count % 4;
  76}
  77
  78void jz4780_efuse_read(size_t addr, size_t count, u8 *buf)
  79{
  80        size_t chunk;
  81
  82        while (count > 0) {
  83                chunk = jz4780_efuse_chunk_size(count);
  84                jz4780_efuse_read_chunk(addr, chunk, buf);
  85                addr += chunk;
  86                buf += chunk;
  87                count -= chunk;
  88        }
  89}
  90
  91void jz4780_efuse_init(u32 ahb2_rate)
  92{
  93        void __iomem *regs = (void __iomem *)NEMC_BASE;
  94        u32 rd_adj, rd_strobe, tmp;
  95
  96        rd_adj = (((6500 * (ahb2_rate / 1000000)) / 1000000) + 0xf) / 2;
  97        tmp = (((35000 * (ahb2_rate / 1000000)) / 1000000) - 4) - rd_adj;
  98        rd_strobe = ((tmp + 0xf) / 2 < 7) ? 7 : (tmp + 0xf) / 2;
  99
 100        tmp = (rd_adj << EFUSE_EFUCFG_RD_ADJ_BIT) |
 101              (rd_strobe << EFUSE_EFUCFG_RD_STROBE_BIT);
 102        writel(tmp, regs + EFUSE_EFUCFG);
 103}
 104