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