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