xref: /rk3399_rockchip-uboot/drivers/misc/rockchip-efuse.c (revision 2ba7147f8008e675b31a0a5c13b8366431ea09ae)
1 /*
2  * eFuse driver for Rockchip devices
3  *
4  * Copyright 2017, Theobroma Systems Design und Consulting GmbH
5  * Written by Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
6  *
7  * SPDX-License-Identifier:	GPL-2.0+
8  */
9 
10 #include <common.h>
11 #include <asm/io.h>
12 #include <command.h>
13 #include <display_options.h>
14 #include <dm.h>
15 #include <linux/bitops.h>
16 #include <linux/delay.h>
17 #include <misc.h>
18 
19 #define T_CSB_P_S		0
20 #define T_PGENB_P_S		0
21 #define T_LOAD_P_S		0
22 #define T_ADDR_P_S		0
23 #define T_STROBE_P_S		(0 + 110) /* 1.1us */
24 #define T_CSB_P_L		(0 + 110 + 1000 + 20) /* 200ns */
25 #define T_PGENB_P_L		(0 + 110 + 1000 + 20)
26 #define T_LOAD_P_L		(0 + 110 + 1000 + 20)
27 #define T_ADDR_P_L		(0 + 110 + 1000 + 20)
28 #define T_STROBE_P_L		(0 + 110 + 1000) /* 10us */
29 #define T_CSB_R_S		0
30 #define T_PGENB_R_S		0
31 #define T_LOAD_R_S		0
32 #define T_ADDR_R_S		2
33 #define T_STROBE_R_S		(2 + 3)
34 #define T_CSB_R_L		(2 + 3 + 3 + 3)
35 #define T_PGENB_R_L		(2 + 3 + 3 + 3)
36 #define T_LOAD_R_L		(2 + 3 + 3 + 3)
37 #define T_ADDR_R_L		(2 + 3 + 3 + 2)
38 #define T_STROBE_R_L		(2 + 3 + 3)
39 
40 #define T_CSB_P			0x28
41 #define T_PGENB_P		0x2c
42 #define T_LOAD_P		0x30
43 #define T_ADDR_P		0x34
44 #define T_STROBE_P		0x38
45 #define T_CSB_R			0x3c
46 #define T_PGENB_R		0x40
47 #define T_LOAD_R		0x44
48 #define T_ADDR_R		0x48
49 #define T_STROBE_R		0x4c
50 
51 #define RK1808_USER_MODE	BIT(0)
52 #define RK1808_INT_FINISH	BIT(0)
53 #define RK1808_AUTO_ENB		BIT(0)
54 #define RK1808_AUTO_RD		BIT(1)
55 #define RK1808_A_SHIFT		16
56 #define RK1808_A_MASK		0x3ff
57 #define RK1808_NBYTES		4
58 
59 #define RK3399_A_SHIFT          16
60 #define RK3399_A_MASK           0x3ff
61 #define RK3399_NFUSES           32
62 #define RK3399_BYTES_PER_FUSE   4
63 #define RK3399_STROBSFTSEL      BIT(9)
64 #define RK3399_RSB              BIT(7)
65 #define RK3399_PD               BIT(5)
66 #define RK3399_PGENB            BIT(3)
67 #define RK3399_LOAD             BIT(2)
68 #define RK3399_STROBE           BIT(1)
69 #define RK3399_CSB              BIT(0)
70 
71 #define RK3288_A_SHIFT          6
72 #define RK3288_A_MASK           0x3ff
73 #define RK3288_NFUSES           32
74 #define RK3288_BYTES_PER_FUSE   1
75 #define RK3288_PGENB            BIT(3)
76 #define RK3288_LOAD             BIT(2)
77 #define RK3288_STROBE           BIT(1)
78 #define RK3288_CSB              BIT(0)
79 
80 #define RK3328_INT_STATUS	0x0018
81 #define RK3328_DOUT		0x0020
82 #define RK3328_AUTO_CTRL	0x0024
83 #define RK3328_INT_FINISH	BIT(0)
84 #define RK3328_AUTO_ENB		BIT(0)
85 #define RK3328_AUTO_RD		BIT(1)
86 
87 typedef int (*EFUSE_READ)(struct udevice *dev, int offset, void *buf, int size);
88 
89 struct rockchip_efuse_regs {
90 	u32 ctrl;      /* 0x00  efuse control register */
91 	u32 dout;      /* 0x04  efuse data out register */
92 	u32 rf;        /* 0x08  efuse redundancy bit used register */
93 	u32 _rsvd0;
94 	u32 jtag_pass; /* 0x10  JTAG password */
95 	u32 strobe_finish_ctrl;
96 		       /* 0x14	efuse strobe finish control register */
97 	u32 int_status;/* 0x18 */
98 	u32 reserved;  /* 0x1c */
99 	u32 dout2;     /* 0x20 */
100 	u32 auto_ctrl; /* 0x24 */
101 };
102 
103 struct rockchip_efuse_platdata {
104 	void __iomem *base;
105 	struct clk *clk;
106 };
107 
108 #if defined(DEBUG)
109 static int dump_efuses(cmd_tbl_t *cmdtp, int flag,
110 		       int argc, char * const argv[])
111 {
112 	/*
113 	 * N.B.: This function is tailored towards the RK3399 and assumes that
114 	 *       there's always 32 fuses x 32 bits (i.e. 128 bytes of data) to
115 	 *       be read.
116 	 */
117 
118 	struct udevice *dev;
119 	u8 fuses[128] = {0};
120 	int ret;
121 
122 	/* retrieve the device */
123 	ret = uclass_get_device_by_driver(UCLASS_MISC,
124 					  DM_GET_DRIVER(rockchip_efuse), &dev);
125 	if (ret) {
126 		printf("%s: no misc-device found\n", __func__);
127 		return 0;
128 	}
129 
130 	ret = misc_read(dev, 0, &fuses, sizeof(fuses));
131 	if (ret) {
132 		printf("%s: misc_read failed\n", __func__);
133 		return 0;
134 	}
135 
136 	printf("efuse-contents:\n");
137 	print_buffer(0, fuses, 1, 128, 16);
138 
139 	return 0;
140 }
141 
142 U_BOOT_CMD(
143 	rockchip_dump_efuses, 1, 1, dump_efuses,
144 	"Dump the content of the efuses",
145 	""
146 );
147 #endif
148 
149 static void rk1808_efuse_timing_init(void __iomem *base)
150 {
151 	static bool init;
152 
153 	if (init)
154 		return;
155 
156 	/* enable auto mode */
157 	writel(readl(base) & (~RK1808_USER_MODE), base);
158 
159 	/* setup efuse timing */
160 	writel((T_CSB_P_S << 16) | T_CSB_P_L, base + T_CSB_P);
161 	writel((T_PGENB_P_S << 16) | T_PGENB_P_L, base + T_PGENB_P);
162 	writel((T_LOAD_P_S << 16) | T_LOAD_P_L, base + T_LOAD_P);
163 	writel((T_ADDR_P_S << 16) | T_ADDR_P_L, base + T_ADDR_P);
164 	writel((T_STROBE_P_S << 16) | T_STROBE_P_L, base + T_STROBE_P);
165 	writel((T_CSB_R_S << 16) | T_CSB_R_L, base + T_CSB_R);
166 	writel((T_PGENB_R_S << 16) | T_PGENB_R_L, base + T_PGENB_R);
167 	writel((T_LOAD_R_S << 16) | T_LOAD_R_L, base + T_LOAD_R);
168 	writel((T_ADDR_R_S << 16) | T_ADDR_R_L, base + T_ADDR_R);
169 	writel((T_STROBE_R_S << 16) | T_STROBE_R_L, base + T_STROBE_R);
170 
171 	init = true;
172 }
173 
174 static int rockchip_rk1808_efuse_read(struct udevice *dev, int offset,
175 				      void *buf, int size)
176 {
177 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
178 	struct rockchip_efuse_regs *efuse =
179 		(struct rockchip_efuse_regs *)plat->base;
180 	unsigned int addr_start, addr_end, addr_offset, addr_len;
181 	u32 out_value, status;
182 	u8 *buffer;
183 	int ret = 0, i = 0;
184 
185 	rk1808_efuse_timing_init(plat->base);
186 
187 	addr_start = rounddown(offset, RK1808_NBYTES) / RK1808_NBYTES;
188 	addr_end = roundup(offset + size, RK1808_NBYTES) / RK1808_NBYTES;
189 	addr_offset = offset % RK1808_NBYTES;
190 	addr_len = addr_end - addr_start;
191 
192 	buffer = calloc(1, sizeof(*buffer) * addr_len * RK1808_NBYTES);
193 	if (!buffer)
194 		return -ENOMEM;
195 
196 	while (addr_len--) {
197 		writel(RK1808_AUTO_RD | RK1808_AUTO_ENB |
198 		       ((addr_start++ & RK1808_A_MASK) << RK1808_A_SHIFT),
199 		       &efuse->auto_ctrl);
200 		udelay(2);
201 		status = readl(&efuse->int_status);
202 		if (!(status & RK1808_INT_FINISH)) {
203 			ret = -EIO;
204 			goto err;
205 		}
206 		out_value = readl(&efuse->dout2);
207 		writel(RK1808_INT_FINISH, &efuse->int_status);
208 
209 		memcpy(&buffer[i], &out_value, RK1808_NBYTES);
210 		i += RK1808_NBYTES;
211 	}
212 	memcpy(buf, buffer + addr_offset, size);
213 err:
214 	kfree(buffer);
215 
216 	return ret;
217 }
218 
219 static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset,
220 				      void *buf, int size)
221 {
222 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
223 	struct rockchip_efuse_regs *efuse =
224 		(struct rockchip_efuse_regs *)plat->base;
225 
226 	unsigned int addr_start, addr_end, addr_offset;
227 	u32 out_value;
228 	u8  bytes[RK3399_NFUSES * RK3399_BYTES_PER_FUSE];
229 	int i = 0;
230 	u32 addr;
231 
232 	addr_start = offset / RK3399_BYTES_PER_FUSE;
233 	addr_offset = offset % RK3399_BYTES_PER_FUSE;
234 	addr_end = DIV_ROUND_UP(offset + size, RK3399_BYTES_PER_FUSE);
235 
236 	/* cap to the size of the efuse block */
237 	if (addr_end > RK3399_NFUSES)
238 		addr_end = RK3399_NFUSES;
239 
240 	writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
241 	       &efuse->ctrl);
242 	udelay(1);
243 	for (addr = addr_start; addr < addr_end; addr++) {
244 		setbits_le32(&efuse->ctrl,
245 			     RK3399_STROBE | (addr << RK3399_A_SHIFT));
246 		udelay(1);
247 		out_value = readl(&efuse->dout);
248 		clrbits_le32(&efuse->ctrl, RK3399_STROBE);
249 		udelay(1);
250 
251 		memcpy(&bytes[i], &out_value, RK3399_BYTES_PER_FUSE);
252 		i += RK3399_BYTES_PER_FUSE;
253 	}
254 
255 	/* Switch to standby mode */
256 	writel(RK3399_PD | RK3399_CSB, &efuse->ctrl);
257 
258 	memcpy(buf, bytes + addr_offset, size);
259 
260 	return 0;
261 }
262 
263 static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset,
264 				      void *buf, int size)
265 {
266 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
267 	struct rockchip_efuse_regs *efuse =
268 		(struct rockchip_efuse_regs *)plat->base;
269 	u8 *buffer = buf;
270 	int max_size = RK3288_NFUSES * RK3288_BYTES_PER_FUSE;
271 
272 	if (size > (max_size - offset))
273 		size = max_size - offset;
274 
275 	/* Switch to read mode */
276 	writel(RK3288_LOAD | RK3288_PGENB, &efuse->ctrl);
277 	udelay(1);
278 
279 	while (size--) {
280 		writel(readl(&efuse->ctrl) &
281 				(~(RK3288_A_MASK << RK3288_A_SHIFT)),
282 				&efuse->ctrl);
283 		/* set addr */
284 		writel(readl(&efuse->ctrl) |
285 				((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT),
286 				&efuse->ctrl);
287 		udelay(1);
288 		/* strobe low to high */
289 		writel(readl(&efuse->ctrl) |
290 				RK3288_STROBE, &efuse->ctrl);
291 		ndelay(60);
292 		/* read data */
293 		*buffer++ = readl(&efuse->dout);
294 		/* reset strobe to low */
295 		writel(readl(&efuse->ctrl) &
296 				(~RK3288_STROBE), &efuse->ctrl);
297 		udelay(1);
298 	}
299 
300 	/* Switch to standby mode */
301 	writel(RK3288_PGENB | RK3288_CSB, &efuse->ctrl);
302 
303 	return 0;
304 }
305 
306 static int rockchip_rk3328_efuse_read(struct udevice *dev, int offset,
307 				      void *buf, int size)
308 {
309 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
310 	struct rockchip_efuse_regs *efuse =
311 		(struct rockchip_efuse_regs *)plat->base;
312 	unsigned int addr_start, addr_end, addr_offset, addr_len;
313 	u32 out_value, status;
314 	u8 *buffer;
315 	int ret = 0, i = 0, j = 0;
316 
317 	/* Max non-secure Byte */
318 	if (size > 32)
319 		size = 32;
320 
321 	/* 128 Byte efuse, 96 Byte for secure, 32 Byte for non-secure */
322 	offset += 96;
323 	addr_start = rounddown(offset, RK3399_BYTES_PER_FUSE) /
324 						RK3399_BYTES_PER_FUSE;
325 	addr_end = roundup(offset + size, RK3399_BYTES_PER_FUSE) /
326 						RK3399_BYTES_PER_FUSE;
327 	addr_offset = offset % RK3399_BYTES_PER_FUSE;
328 	addr_len = addr_end - addr_start;
329 
330 	buffer = calloc(1, sizeof(*buffer) * addr_len * RK3399_BYTES_PER_FUSE);
331 	if (!buffer)
332 		return -ENOMEM;
333 
334 	for (j = 0; j < addr_len; j++) {
335 		writel(RK3328_AUTO_RD | RK3328_AUTO_ENB |
336 		       ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT),
337 		         &efuse->auto_ctrl);
338 		udelay(5);
339 		status = readl(&efuse->int_status);
340 		if (!(status & RK3328_INT_FINISH)) {
341 			ret = -EIO;
342 			goto err;
343 		}
344 		out_value = readl(&efuse->dout2);
345 		writel(RK3328_INT_FINISH, &efuse->int_status);
346 
347 		memcpy(&buffer[i], &out_value, RK3399_BYTES_PER_FUSE);
348 		i += RK3399_BYTES_PER_FUSE;
349 	}
350 	memcpy(buf, buffer + addr_offset, size);
351 err:
352 	free(buffer);
353 
354 	return ret;
355 }
356 
357 static int rockchip_efuse_read(struct udevice *dev, int offset,
358 			       void *buf, int size)
359 {
360 	EFUSE_READ efuse_read = NULL;
361 
362 	efuse_read = (EFUSE_READ)dev_get_driver_data(dev);
363 	if (!efuse_read)
364 		return -ENOSYS;
365 
366 	return (*efuse_read)(dev, offset, buf, size);
367 }
368 
369 static const struct misc_ops rockchip_efuse_ops = {
370 	.read = rockchip_efuse_read,
371 };
372 
373 static int rockchip_efuse_ofdata_to_platdata(struct udevice *dev)
374 {
375 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
376 
377 	plat->base = dev_read_addr_ptr(dev);
378 	return 0;
379 }
380 
381 static const struct udevice_id rockchip_efuse_ids[] = {
382 	{
383 		.compatible = "rockchip,rk1808-efuse",
384 		.data = (ulong)&rockchip_rk1808_efuse_read,
385 	},
386 	{
387 		.compatible = "rockchip,rockchip-efuse",
388 		.data = (ulong)&rockchip_rk3288_efuse_read,
389 	},
390 	{
391 		.compatible = "rockchip,rk3066a-efuse",
392 		.data = (ulong)&rockchip_rk3288_efuse_read,
393 	},
394 	{
395 		.compatible = "rockchip,rk3188-efuse",
396 		.data = (ulong)&rockchip_rk3288_efuse_read,
397 	},
398 	{
399 		.compatible = "rockchip,rk322x-efuse",
400 		.data = (ulong)&rockchip_rk3288_efuse_read,
401 	},
402 	{
403 		.compatible = "rockchip,rk3328-efuse",
404 		.data = (ulong)&rockchip_rk3328_efuse_read,
405 	},
406 	{
407 		.compatible = "rockchip,rk3399-efuse",
408 		.data = (ulong)&rockchip_rk3399_efuse_read,
409 	},
410 	{}
411 };
412 
413 U_BOOT_DRIVER(rockchip_efuse) = {
414 	.name = "rockchip_efuse",
415 	.id = UCLASS_MISC,
416 	.of_match = rockchip_efuse_ids,
417 	.ofdata_to_platdata = rockchip_efuse_ofdata_to_platdata,
418 	.platdata_auto_alloc_size = sizeof(struct rockchip_efuse_platdata),
419 	.ops = &rockchip_efuse_ops,
420 };
421