xref: /rk3399_rockchip-uboot/drivers/misc/rockchip-efuse.c (revision 6aa65bb1ee0951865e27da81dde1de76c6d4687e)
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 RK3399_A_SHIFT          16
20 #define RK3399_A_MASK           0x3ff
21 #define RK3399_NFUSES           32
22 #define RK3399_BYTES_PER_FUSE   4
23 #define RK3399_STROBSFTSEL      BIT(9)
24 #define RK3399_RSB              BIT(7)
25 #define RK3399_PD               BIT(5)
26 #define RK3399_PGENB            BIT(3)
27 #define RK3399_LOAD             BIT(2)
28 #define RK3399_STROBE           BIT(1)
29 #define RK3399_CSB              BIT(0)
30 
31 #define RK3288_A_SHIFT          6
32 #define RK3288_A_MASK           0x3ff
33 #define RK3288_NFUSES           32
34 #define RK3288_BYTES_PER_FUSE   1
35 #define RK3288_PGENB            BIT(3)
36 #define RK3288_LOAD             BIT(2)
37 #define RK3288_STROBE           BIT(1)
38 #define RK3288_CSB              BIT(0)
39 
40 #define RK3328_INT_STATUS	0x0018
41 #define RK3328_DOUT		0x0020
42 #define RK3328_AUTO_CTRL	0x0024
43 #define RK3328_INT_FINISH	BIT(0)
44 #define RK3328_AUTO_ENB		BIT(0)
45 #define RK3328_AUTO_RD		BIT(1)
46 
47 typedef int (*EFUSE_READ)(struct udevice *dev, int offset, void *buf, int size);
48 
49 struct rockchip_efuse_regs {
50 	u32 ctrl;      /* 0x00  efuse control register */
51 	u32 dout;      /* 0x04  efuse data out register */
52 	u32 rf;        /* 0x08  efuse redundancy bit used register */
53 	u32 _rsvd0;
54 	u32 jtag_pass; /* 0x10  JTAG password */
55 	u32 strobe_finish_ctrl;
56 		       /* 0x14	efuse strobe finish control register */
57 	u32 int_status;/* 0x18 */
58 	u32 reserved;  /* 0x1c */
59 	u32 dout2;     /* 0x20 */
60 	u32 auto_ctrl; /* 0x24 */
61 };
62 
63 struct rockchip_efuse_platdata {
64 	void __iomem *base;
65 	struct clk *clk;
66 };
67 
68 #if defined(DEBUG)
69 static int dump_efuses(cmd_tbl_t *cmdtp, int flag,
70 		       int argc, char * const argv[])
71 {
72 	/*
73 	 * N.B.: This function is tailored towards the RK3399 and assumes that
74 	 *       there's always 32 fuses x 32 bits (i.e. 128 bytes of data) to
75 	 *       be read.
76 	 */
77 
78 	struct udevice *dev;
79 	u8 fuses[128] = {0};
80 	int ret;
81 
82 	/* retrieve the device */
83 	ret = uclass_get_device_by_driver(UCLASS_MISC,
84 					  DM_GET_DRIVER(rockchip_efuse), &dev);
85 	if (ret) {
86 		printf("%s: no misc-device found\n", __func__);
87 		return 0;
88 	}
89 
90 	ret = misc_read(dev, 0, &fuses, sizeof(fuses));
91 	if (ret) {
92 		printf("%s: misc_read failed\n", __func__);
93 		return 0;
94 	}
95 
96 	printf("efuse-contents:\n");
97 	print_buffer(0, fuses, 1, 128, 16);
98 
99 	return 0;
100 }
101 
102 U_BOOT_CMD(
103 	rockchip_dump_efuses, 1, 1, dump_efuses,
104 	"Dump the content of the efuses",
105 	""
106 );
107 #endif
108 
109 static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset,
110 				      void *buf, int size)
111 {
112 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
113 	struct rockchip_efuse_regs *efuse =
114 		(struct rockchip_efuse_regs *)plat->base;
115 
116 	unsigned int addr_start, addr_end, addr_offset;
117 	u32 out_value;
118 	u8  bytes[RK3399_NFUSES * RK3399_BYTES_PER_FUSE];
119 	int i = 0;
120 	u32 addr;
121 
122 	addr_start = offset / RK3399_BYTES_PER_FUSE;
123 	addr_offset = offset % RK3399_BYTES_PER_FUSE;
124 	addr_end = DIV_ROUND_UP(offset + size, RK3399_BYTES_PER_FUSE);
125 
126 	/* cap to the size of the efuse block */
127 	if (addr_end > RK3399_NFUSES)
128 		addr_end = RK3399_NFUSES;
129 
130 	writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
131 	       &efuse->ctrl);
132 	udelay(1);
133 	for (addr = addr_start; addr < addr_end; addr++) {
134 		setbits_le32(&efuse->ctrl,
135 			     RK3399_STROBE | (addr << RK3399_A_SHIFT));
136 		udelay(1);
137 		out_value = readl(&efuse->dout);
138 		clrbits_le32(&efuse->ctrl, RK3399_STROBE);
139 		udelay(1);
140 
141 		memcpy(&bytes[i], &out_value, RK3399_BYTES_PER_FUSE);
142 		i += RK3399_BYTES_PER_FUSE;
143 	}
144 
145 	/* Switch to standby mode */
146 	writel(RK3399_PD | RK3399_CSB, &efuse->ctrl);
147 
148 	memcpy(buf, bytes + addr_offset, size);
149 
150 	return 0;
151 }
152 
153 static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset,
154 				      void *buf, int size)
155 {
156 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
157 	struct rockchip_efuse_regs *efuse =
158 		(struct rockchip_efuse_regs *)plat->base;
159 	u8 *buffer = buf;
160 	int max_size = RK3288_NFUSES * RK3288_BYTES_PER_FUSE;
161 
162 	if (size > (max_size - offset))
163 		size = max_size - offset;
164 
165 	/* Switch to read mode */
166 	writel(RK3288_LOAD | RK3288_PGENB, &efuse->ctrl);
167 	udelay(1);
168 
169 	while (size--) {
170 		writel(readl(&efuse->ctrl) &
171 				(~(RK3288_A_MASK << RK3288_A_SHIFT)),
172 				&efuse->ctrl);
173 		/* set addr */
174 		writel(readl(&efuse->ctrl) |
175 				((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT),
176 				&efuse->ctrl);
177 		udelay(1);
178 		/* strobe low to high */
179 		writel(readl(&efuse->ctrl) |
180 				RK3288_STROBE, &efuse->ctrl);
181 		ndelay(60);
182 		/* read data */
183 		*buffer++ = readl(&efuse->dout);
184 		/* reset strobe to low */
185 		writel(readl(&efuse->ctrl) &
186 				(~RK3288_STROBE), &efuse->ctrl);
187 		udelay(1);
188 	}
189 
190 	/* Switch to standby mode */
191 	writel(RK3288_PGENB | RK3288_CSB, &efuse->ctrl);
192 
193 	return 0;
194 }
195 
196 static int rockchip_rk3328_efuse_read(struct udevice *dev, int offset,
197 				      void *buf, int size)
198 {
199 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
200 	struct rockchip_efuse_regs *efuse =
201 		(struct rockchip_efuse_regs *)plat->base;
202 	unsigned int addr_start, addr_end, addr_offset, addr_len;
203 	u32 out_value, status;
204 	u8 *buffer;
205 	int ret = 0, i = 0, j = 0;
206 
207 	/* Max non-secure Byte */
208 	if (size > 32)
209 		size = 32;
210 
211 	/* 128 Byte efuse, 96 Byte for secure, 32 Byte for non-secure */
212 	offset += 96;
213 	addr_start = rounddown(offset, RK3399_BYTES_PER_FUSE) /
214 						RK3399_BYTES_PER_FUSE;
215 	addr_end = roundup(offset + size, RK3399_BYTES_PER_FUSE) /
216 						RK3399_BYTES_PER_FUSE;
217 	addr_offset = offset % RK3399_BYTES_PER_FUSE;
218 	addr_len = addr_end - addr_start;
219 
220 	buffer = calloc(1, sizeof(*buffer) * addr_len * RK3399_BYTES_PER_FUSE);
221 	if (!buffer)
222 		return -ENOMEM;
223 
224 	for (j = 0; j < addr_len; j++) {
225 		writel(RK3328_AUTO_RD | RK3328_AUTO_ENB |
226 		       ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT),
227 		         &efuse->auto_ctrl);
228 		udelay(5);
229 		status = readl(&efuse->int_status);
230 		if (!(status & RK3328_INT_FINISH)) {
231 			ret = -EIO;
232 			goto err;
233 		}
234 		out_value = readl(&efuse->dout2);
235 		writel(RK3328_INT_FINISH, &efuse->int_status);
236 
237 		memcpy(&buffer[i], &out_value, RK3399_BYTES_PER_FUSE);
238 		i += RK3399_BYTES_PER_FUSE;
239 	}
240 	memcpy(buf, buffer + addr_offset, size);
241 err:
242 	free(buffer);
243 
244 	return ret;
245 }
246 
247 static int rockchip_efuse_read(struct udevice *dev, int offset,
248 			       void *buf, int size)
249 {
250 	EFUSE_READ efuse_read = NULL;
251 
252 	efuse_read = (EFUSE_READ)dev_get_driver_data(dev);
253 	if (!efuse_read)
254 		return -ENOSYS;
255 
256 	return (*efuse_read)(dev, offset, buf, size);
257 }
258 
259 static const struct misc_ops rockchip_efuse_ops = {
260 	.read = rockchip_efuse_read,
261 };
262 
263 static int rockchip_efuse_ofdata_to_platdata(struct udevice *dev)
264 {
265 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
266 
267 	plat->base = dev_read_addr_ptr(dev);
268 	return 0;
269 }
270 
271 static const struct udevice_id rockchip_efuse_ids[] = {
272 	{
273 		.compatible = "rockchip,rockchip-efuse",
274 		.data = (ulong)&rockchip_rk3288_efuse_read,
275 	},
276 	{
277 		.compatible = "rockchip,rk3066a-efuse",
278 		.data = (ulong)&rockchip_rk3288_efuse_read,
279 	},
280 	{
281 		.compatible = "rockchip,rk3188-efuse",
282 		.data = (ulong)&rockchip_rk3288_efuse_read,
283 	},
284 	{
285 		.compatible = "rockchip,rk322x-efuse",
286 		.data = (ulong)&rockchip_rk3288_efuse_read,
287 	},
288 	{
289 		.compatible = "rockchip,rk3328-efuse",
290 		.data = (ulong)&rockchip_rk3328_efuse_read,
291 	},
292 	{
293 		.compatible = "rockchip,rk3399-efuse",
294 		.data = (ulong)&rockchip_rk3399_efuse_read,
295 	},
296 	{}
297 };
298 
299 U_BOOT_DRIVER(rockchip_efuse) = {
300 	.name = "rockchip_efuse",
301 	.id = UCLASS_MISC,
302 	.of_match = rockchip_efuse_ids,
303 	.ofdata_to_platdata = rockchip_efuse_ofdata_to_platdata,
304 	.platdata_auto_alloc_size = sizeof(struct rockchip_efuse_platdata),
305 	.ops = &rockchip_efuse_ops,
306 };
307