1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * eFuse driver for Rockchip devices
4 *
5 * Copyright 2017, Theobroma Systems Design und Consulting GmbH
6 * Written by Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
7 */
8
9 #include <asm/io.h>
10 #include <command.h>
11 #include <display_options.h>
12 #include <dm.h>
13 #include <linux/bitops.h>
14 #include <linux/delay.h>
15 #include <linux/iopoll.h>
16 #include <malloc.h>
17 #include <misc.h>
18
19 #define EFUSE_CTRL 0x0000
20 #define RK3036_A_SHIFT 8
21 #define RK3036_A_MASK GENMASK(15, 8)
22 #define RK3036_ADDR(n) ((n) << RK3036_A_SHIFT)
23 #define RK3128_A_SHIFT 7
24 #define RK3128_A_MASK GENMASK(15, 7)
25 #define RK3128_ADDR(n) ((n) << RK3128_A_SHIFT)
26 #define RK3288_A_SHIFT 6
27 #define RK3288_A_MASK GENMASK(15, 6)
28 #define RK3288_ADDR(n) ((n) << RK3288_A_SHIFT)
29 #define RK3399_A_SHIFT 16
30 #define RK3399_A_MASK GENMASK(25, 16)
31 #define RK3399_ADDR(n) ((n) << RK3399_A_SHIFT)
32 #define RK3399_STROBSFTSEL BIT(9)
33 #define RK3399_RSB BIT(7)
34 #define RK3399_PD BIT(5)
35 #define EFUSE_PGENB BIT(3)
36 #define EFUSE_LOAD BIT(2)
37 #define EFUSE_STROBE BIT(1)
38 #define EFUSE_CSB BIT(0)
39 #define EFUSE_DOUT 0x0004
40 #define RK3328_INT_STATUS 0x0018
41 #define RK3328_INT_FINISH BIT(0)
42 #define RK3328_DOUT 0x0020
43 #define RK3328_AUTO_CTRL 0x0024
44 #define RK3328_AUTO_RD BIT(1)
45 #define RK3328_AUTO_ENB BIT(0)
46
47 struct rockchip_efuse_plat {
48 void __iomem *base;
49 };
50
51 struct rockchip_efuse_data {
52 int (*read)(struct udevice *dev, int offset, void *buf, int size);
53 int offset;
54 int size;
55 int block_size;
56 };
57
58 #if defined(DEBUG)
dump_efuse(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])59 static int dump_efuse(struct cmd_tbl *cmdtp, int flag,
60 int argc, char *const argv[])
61 {
62 struct udevice *dev;
63 u8 data[4];
64 int ret, i;
65
66 ret = uclass_get_device_by_driver(UCLASS_MISC,
67 DM_DRIVER_GET(rockchip_efuse), &dev);
68 if (ret) {
69 printf("%s: no misc-device found\n", __func__);
70 return 0;
71 }
72
73 for (i = 0; true; i += sizeof(data)) {
74 ret = misc_read(dev, i, &data, sizeof(data));
75 if (ret <= 0)
76 return 0;
77
78 print_buffer(i, data, 1, sizeof(data), sizeof(data));
79 }
80
81 return 0;
82 }
83
84 U_BOOT_CMD(
85 dump_efuse, 1, 1, dump_efuse,
86 "Dump the content of the efuse",
87 ""
88 );
89 #endif
90
rockchip_rk3036_efuse_read(struct udevice * dev,int offset,void * buf,int size)91 static int rockchip_rk3036_efuse_read(struct udevice *dev, int offset,
92 void *buf, int size)
93 {
94 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
95 u8 *buffer = buf;
96
97 /* Switch to read mode */
98 writel(EFUSE_LOAD, efuse->base + EFUSE_CTRL);
99 udelay(2);
100
101 while (size--) {
102 clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3036_A_MASK,
103 RK3036_ADDR(offset++));
104 udelay(2);
105 setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
106 udelay(2);
107 *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
108 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
109 udelay(2);
110 }
111
112 /* Switch to inactive mode */
113 writel(0x0, efuse->base + EFUSE_CTRL);
114
115 return 0;
116 }
117
rockchip_rk3128_efuse_read(struct udevice * dev,int offset,void * buf,int size)118 static int rockchip_rk3128_efuse_read(struct udevice *dev, int offset,
119 void *buf, int size)
120 {
121 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
122 u8 *buffer = buf;
123
124 /* Switch to read mode */
125 writel(EFUSE_LOAD, efuse->base + EFUSE_CTRL);
126 udelay(2);
127
128 while (size--) {
129 clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3128_A_MASK,
130 RK3128_ADDR(offset++));
131 udelay(2);
132 setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
133 udelay(2);
134 *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
135 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
136 udelay(2);
137 }
138
139 /* Switch to inactive mode */
140 writel(0x0, efuse->base + EFUSE_CTRL);
141
142 return 0;
143 }
144
rockchip_rk3288_efuse_read(struct udevice * dev,int offset,void * buf,int size)145 static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset,
146 void *buf, int size)
147 {
148 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
149 u8 *buffer = buf;
150
151 /* Switch to read mode */
152 writel(EFUSE_CSB, efuse->base + EFUSE_CTRL);
153 writel(EFUSE_LOAD | EFUSE_PGENB, efuse->base + EFUSE_CTRL);
154 udelay(2);
155
156 while (size--) {
157 clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3288_A_MASK,
158 RK3288_ADDR(offset++));
159 udelay(2);
160 setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
161 udelay(2);
162 *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
163 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
164 udelay(2);
165 }
166
167 /* Switch to standby mode */
168 writel(EFUSE_CSB | EFUSE_PGENB, efuse->base + EFUSE_CTRL);
169
170 return 0;
171 }
172
rockchip_rk3328_efuse_read(struct udevice * dev,int offset,void * buf,int size)173 static int rockchip_rk3328_efuse_read(struct udevice *dev, int offset,
174 void *buf, int size)
175 {
176 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
177 u32 status, *buffer = buf;
178 int ret;
179
180 while (size--) {
181 writel(RK3328_AUTO_RD | RK3328_AUTO_ENB | RK3399_ADDR(offset++),
182 efuse->base + RK3328_AUTO_CTRL);
183 udelay(1);
184
185 ret = readl_poll_sleep_timeout(efuse->base + RK3328_INT_STATUS,
186 status, (status & RK3328_INT_FINISH), 1, 50);
187 if (ret)
188 return ret;
189
190 *buffer++ = readl(efuse->base + RK3328_DOUT);
191 writel(RK3328_INT_FINISH, efuse->base + RK3328_INT_STATUS);
192 }
193
194 return 0;
195 }
196
rockchip_rk3399_efuse_read(struct udevice * dev,int offset,void * buf,int size)197 static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset,
198 void *buf, int size)
199 {
200 struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
201 u32 *buffer = buf;
202
203 /* Switch to array read mode */
204 writel(EFUSE_LOAD | EFUSE_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
205 efuse->base + EFUSE_CTRL);
206 udelay(1);
207
208 while (size--) {
209 setbits_le32(efuse->base + EFUSE_CTRL,
210 EFUSE_STROBE | RK3399_ADDR(offset++));
211 udelay(1);
212 *buffer++ = readl(efuse->base + EFUSE_DOUT);
213 clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
214 udelay(1);
215 }
216
217 /* Switch to power-down mode */
218 writel(RK3399_PD | EFUSE_CSB, efuse->base + EFUSE_CTRL);
219
220 return 0;
221 }
222
rockchip_efuse_read(struct udevice * dev,int offset,void * buf,int size)223 static int rockchip_efuse_read(struct udevice *dev, int offset,
224 void *buf, int size)
225 {
226 const struct rockchip_efuse_data *data =
227 (void *)dev_get_driver_data(dev);
228 u32 block_start, block_end, block_offset, blocks;
229 u8 *buffer;
230 int ret;
231
232 if (offset < 0 || !buf || size <= 0 || offset + size > data->size)
233 return -EINVAL;
234
235 if (!data->read)
236 return -ENOSYS;
237
238 offset += data->offset;
239
240 if (data->block_size <= 1) {
241 ret = data->read(dev, offset, buf, size);
242 goto done;
243 }
244
245 block_start = offset / data->block_size;
246 block_offset = offset % data->block_size;
247 block_end = DIV_ROUND_UP(offset + size, data->block_size);
248 blocks = block_end - block_start;
249
250 buffer = calloc(blocks, data->block_size);
251 if (!buffer)
252 return -ENOMEM;
253
254 ret = data->read(dev, block_start, buffer, blocks);
255 if (!ret)
256 memcpy(buf, buffer + block_offset, size);
257
258 free(buffer);
259
260 done:
261 return ret < 0 ? ret : size;
262 }
263
264 static const struct misc_ops rockchip_efuse_ops = {
265 .read = rockchip_efuse_read,
266 };
267
rockchip_efuse_of_to_plat(struct udevice * dev)268 static int rockchip_efuse_of_to_plat(struct udevice *dev)
269 {
270 struct rockchip_efuse_plat *plat = dev_get_plat(dev);
271
272 plat->base = dev_read_addr_ptr(dev);
273
274 return 0;
275 }
276
277 static const struct rockchip_efuse_data rk3036_data = {
278 .read = rockchip_rk3036_efuse_read,
279 .size = 0x20,
280 };
281
282 static const struct rockchip_efuse_data rk3128_data = {
283 .read = rockchip_rk3128_efuse_read,
284 .size = 0x40,
285 };
286
287 static const struct rockchip_efuse_data rk3288_data = {
288 .read = rockchip_rk3288_efuse_read,
289 .size = 0x20,
290 };
291
292 static const struct rockchip_efuse_data rk3328_data = {
293 .read = rockchip_rk3328_efuse_read,
294 .offset = 0x60,
295 .size = 0x20,
296 .block_size = 4,
297 };
298
299 static const struct rockchip_efuse_data rk3399_data = {
300 .read = rockchip_rk3399_efuse_read,
301 .size = 0x80,
302 .block_size = 4,
303 };
304
305 static const struct udevice_id rockchip_efuse_ids[] = {
306 {
307 .compatible = "rockchip,rk3036-efuse",
308 .data = (ulong)&rk3036_data,
309 },
310 {
311 .compatible = "rockchip,rk3066a-efuse",
312 .data = (ulong)&rk3288_data,
313 },
314 {
315 .compatible = "rockchip,rk3128-efuse",
316 .data = (ulong)&rk3128_data,
317 },
318 {
319 .compatible = "rockchip,rk3188-efuse",
320 .data = (ulong)&rk3288_data,
321 },
322 {
323 .compatible = "rockchip,rk3228-efuse",
324 .data = (ulong)&rk3288_data,
325 },
326 {
327 .compatible = "rockchip,rk3288-efuse",
328 .data = (ulong)&rk3288_data,
329 },
330 {
331 .compatible = "rockchip,rk3328-efuse",
332 .data = (ulong)&rk3328_data,
333 },
334 {
335 .compatible = "rockchip,rk3399-efuse",
336 .data = (ulong)&rk3399_data,
337 },
338 {}
339 };
340
341 U_BOOT_DRIVER(rockchip_efuse) = {
342 .name = "rockchip_efuse",
343 .id = UCLASS_MISC,
344 .of_match = rockchip_efuse_ids,
345 .of_to_plat = rockchip_efuse_of_to_plat,
346 .plat_auto = sizeof(struct rockchip_efuse_plat),
347 .ops = &rockchip_efuse_ops,
348 };
349