blob: 1fba3271db6120833dbc71dcb326c5ada860240b [file] [log] [blame]
Paul Burtonb5392c52018-12-16 19:25:19 -03001// 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>
Simon Glasscd93d622020-05-10 11:40:13 -060013#include <linux/bitops.h>
Paul Burtonb5392c52018-12-16 19:25:19 -030014#include <mach/jz4780.h>
15#include <wait_bit.h>
16
17#define EFUSE_EFUCTRL 0xd0
18#define EFUSE_EFUCFG 0xd4
19#define EFUSE_EFUSTATE 0xd8
20#define EFUSE_EFUDATA(n) (0xdc + ((n) * 4))
21
22#define EFUSE_EFUCTRL_RD_EN BIT(0)
23#define EFUSE_EFUCTRL_LEN_BIT 16
24#define EFUSE_EFUCTRL_LEN_MASK 0x1f
25#define EFUSE_EFUCTRL_ADDR_BIT 21
26#define EFUSE_EFUCTRL_ADDR_MASK 0x1ff
27#define EFUSE_EFUCTRL_CS BIT(30)
28
29#define EFUSE_EFUCFG_RD_STROBE_BIT 16
30#define EFUSE_EFUCFG_RD_STROBE_MASK 0xf
31#define EFUSE_EFUCFG_RD_ADJ_BIT 20
32#define EFUSE_EFUCFG_RD_ADJ_MASK 0xf
33
34#define EFUSE_EFUSTATE_RD_DONE BIT(0)
35
36static void jz4780_efuse_read_chunk(size_t addr, size_t count, u8 *buf)
37{
38 void __iomem *regs = (void __iomem *)NEMC_BASE;
39 size_t i;
40 u32 val;
41 int ret;
42
43 val = EFUSE_EFUCTRL_RD_EN |
44 ((count - 1) << EFUSE_EFUCTRL_LEN_BIT) |
45 (addr << EFUSE_EFUCTRL_ADDR_BIT) |
46 ((addr > 0x200) ? EFUSE_EFUCTRL_CS : 0);
47 writel(val, regs + EFUSE_EFUCTRL);
48
49 ret = wait_for_bit_le32(regs + EFUSE_EFUSTATE,
50 EFUSE_EFUSTATE_RD_DONE, true, 10000, false);
51 if (ret)
52 return;
53
54 if ((count % 4) == 0) {
55 for (i = 0; i < count / 4; i++) {
56 val = readl(regs + EFUSE_EFUDATA(i));
57 put_unaligned(val, (u32 *)(buf + (i * 4)));
58 }
59 } else {
60 val = readl(regs + EFUSE_EFUDATA(0));
61 if (count > 2)
62 buf[2] = (val >> 16) & 0xff;
63 if (count > 1)
64 buf[1] = (val >> 8) & 0xff;
65 buf[0] = val & 0xff;
66 }
67}
68
69static inline int jz4780_efuse_chunk_size(size_t count)
70{
71 if (count >= 32)
72 return 32;
73 else if ((count / 4) > 0)
74 return (count / 4) * 4;
75 else
76 return count % 4;
77}
78
79void jz4780_efuse_read(size_t addr, size_t count, u8 *buf)
80{
81 size_t chunk;
82
83 while (count > 0) {
84 chunk = jz4780_efuse_chunk_size(count);
85 jz4780_efuse_read_chunk(addr, chunk, buf);
86 addr += chunk;
87 buf += chunk;
88 count -= chunk;
89 }
90}
91
92void jz4780_efuse_init(u32 ahb2_rate)
93{
94 void __iomem *regs = (void __iomem *)NEMC_BASE;
95 u32 rd_adj, rd_strobe, tmp;
96
97 rd_adj = (((6500 * (ahb2_rate / 1000000)) / 1000000) + 0xf) / 2;
98 tmp = (((35000 * (ahb2_rate / 1000000)) / 1000000) - 4) - rd_adj;
99 rd_strobe = ((tmp + 0xf) / 2 < 7) ? 7 : (tmp + 0xf) / 2;
100
101 tmp = (rd_adj << EFUSE_EFUCFG_RD_ADJ_BIT) |
102 (rd_strobe << EFUSE_EFUCFG_RD_STROBE_BIT);
103 writel(tmp, regs + EFUSE_EFUCFG);
104}