]>
Commit | Line | Data |
---|---|---|
b5392c50 PB |
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 | ||
35 | static 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 | ||
68 | static 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 | ||
78 | void 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 | ||
91 | void 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 | } |