xref: /rk3399_rockchip-uboot/drivers/misc/rockchip-efuse.c (revision b13cc84cd1500488737e1936da4a4015d6bb7b6d)
149cd8e85SPhilipp Tomsich /*
249cd8e85SPhilipp Tomsich  * eFuse driver for Rockchip devices
349cd8e85SPhilipp Tomsich  *
449cd8e85SPhilipp Tomsich  * Copyright 2017, Theobroma Systems Design und Consulting GmbH
549cd8e85SPhilipp Tomsich  * Written by Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
649cd8e85SPhilipp Tomsich  *
749cd8e85SPhilipp Tomsich  * SPDX-License-Identifier:	GPL-2.0+
849cd8e85SPhilipp Tomsich  */
949cd8e85SPhilipp Tomsich 
1049cd8e85SPhilipp Tomsich #include <common.h>
1149cd8e85SPhilipp Tomsich #include <asm/io.h>
1249cd8e85SPhilipp Tomsich #include <command.h>
1349cd8e85SPhilipp Tomsich #include <display_options.h>
1449cd8e85SPhilipp Tomsich #include <dm.h>
1549cd8e85SPhilipp Tomsich #include <linux/bitops.h>
1649cd8e85SPhilipp Tomsich #include <linux/delay.h>
1749cd8e85SPhilipp Tomsich #include <misc.h>
1849cd8e85SPhilipp Tomsich 
19*b13cc84cSFinley Xiao #define T_CSB_P_S		0
20*b13cc84cSFinley Xiao #define T_PGENB_P_S		0
21*b13cc84cSFinley Xiao #define T_LOAD_P_S		0
22*b13cc84cSFinley Xiao #define T_ADDR_P_S		0
23*b13cc84cSFinley Xiao #define T_STROBE_P_S		(0 + 110) /* 1.1us */
24*b13cc84cSFinley Xiao #define T_CSB_P_L		(0 + 110 + 1000 + 20) /* 200ns */
25*b13cc84cSFinley Xiao #define T_PGENB_P_L		(0 + 110 + 1000 + 20)
26*b13cc84cSFinley Xiao #define T_LOAD_P_L		(0 + 110 + 1000 + 20)
27*b13cc84cSFinley Xiao #define T_ADDR_P_L		(0 + 110 + 1000 + 20)
28*b13cc84cSFinley Xiao #define T_STROBE_P_L		(0 + 110 + 1000) /* 10us */
29*b13cc84cSFinley Xiao #define T_CSB_R_S		0
30*b13cc84cSFinley Xiao #define T_PGENB_R_S		0
31*b13cc84cSFinley Xiao #define T_LOAD_R_S		0
32*b13cc84cSFinley Xiao #define T_ADDR_R_S		2
33*b13cc84cSFinley Xiao #define T_STROBE_R_S		(2 + 3)
34*b13cc84cSFinley Xiao #define T_CSB_R_L		(2 + 3 + 3 + 3)
35*b13cc84cSFinley Xiao #define T_PGENB_R_L		(2 + 3 + 3 + 3)
36*b13cc84cSFinley Xiao #define T_LOAD_R_L		(2 + 3 + 3 + 3)
37*b13cc84cSFinley Xiao #define T_ADDR_R_L		(2 + 3 + 3 + 2)
38*b13cc84cSFinley Xiao #define T_STROBE_R_L		(2 + 3 + 3)
39*b13cc84cSFinley Xiao 
40*b13cc84cSFinley Xiao #define T_CSB_P			0x28
41*b13cc84cSFinley Xiao #define T_PGENB_P		0x2c
42*b13cc84cSFinley Xiao #define T_LOAD_P		0x30
43*b13cc84cSFinley Xiao #define T_ADDR_P		0x34
44*b13cc84cSFinley Xiao #define T_STROBE_P		0x38
45*b13cc84cSFinley Xiao #define T_CSB_R			0x3c
46*b13cc84cSFinley Xiao #define T_PGENB_R		0x40
47*b13cc84cSFinley Xiao #define T_LOAD_R		0x44
48*b13cc84cSFinley Xiao #define T_ADDR_R		0x48
49*b13cc84cSFinley Xiao #define T_STROBE_R		0x4c
50*b13cc84cSFinley Xiao 
51*b13cc84cSFinley Xiao #define RK1808_USER_MODE	BIT(0)
52*b13cc84cSFinley Xiao #define RK1808_INT_FINISH	BIT(0)
53*b13cc84cSFinley Xiao #define RK1808_AUTO_ENB		BIT(0)
54*b13cc84cSFinley Xiao #define RK1808_AUTO_RD		BIT(1)
55*b13cc84cSFinley Xiao #define RK1808_A_SHIFT		16
56*b13cc84cSFinley Xiao #define RK1808_A_MASK		0x3ff
57*b13cc84cSFinley Xiao #define RK1808_NBYTES		4
58*b13cc84cSFinley Xiao 
5949cd8e85SPhilipp Tomsich #define RK3399_A_SHIFT          16
6049cd8e85SPhilipp Tomsich #define RK3399_A_MASK           0x3ff
6149cd8e85SPhilipp Tomsich #define RK3399_NFUSES           32
6249cd8e85SPhilipp Tomsich #define RK3399_BYTES_PER_FUSE   4
6349cd8e85SPhilipp Tomsich #define RK3399_STROBSFTSEL      BIT(9)
6449cd8e85SPhilipp Tomsich #define RK3399_RSB              BIT(7)
6549cd8e85SPhilipp Tomsich #define RK3399_PD               BIT(5)
6649cd8e85SPhilipp Tomsich #define RK3399_PGENB            BIT(3)
6749cd8e85SPhilipp Tomsich #define RK3399_LOAD             BIT(2)
6849cd8e85SPhilipp Tomsich #define RK3399_STROBE           BIT(1)
6949cd8e85SPhilipp Tomsich #define RK3399_CSB              BIT(0)
7049cd8e85SPhilipp Tomsich 
71b4fa32f0SFrancis Fan #define RK3288_A_SHIFT          6
72b4fa32f0SFrancis Fan #define RK3288_A_MASK           0x3ff
73b4fa32f0SFrancis Fan #define RK3288_NFUSES           32
74b4fa32f0SFrancis Fan #define RK3288_BYTES_PER_FUSE   1
75b4fa32f0SFrancis Fan #define RK3288_PGENB            BIT(3)
76b4fa32f0SFrancis Fan #define RK3288_LOAD             BIT(2)
77b4fa32f0SFrancis Fan #define RK3288_STROBE           BIT(1)
78b4fa32f0SFrancis Fan #define RK3288_CSB              BIT(0)
79b4fa32f0SFrancis Fan 
8059a83996SJoseph Chen #define RK3328_INT_STATUS	0x0018
8159a83996SJoseph Chen #define RK3328_DOUT		0x0020
8259a83996SJoseph Chen #define RK3328_AUTO_CTRL	0x0024
8359a83996SJoseph Chen #define RK3328_INT_FINISH	BIT(0)
8459a83996SJoseph Chen #define RK3328_AUTO_ENB		BIT(0)
8559a83996SJoseph Chen #define RK3328_AUTO_RD		BIT(1)
8659a83996SJoseph Chen 
87b4fa32f0SFrancis Fan typedef int (*EFUSE_READ)(struct udevice *dev, int offset, void *buf, int size);
88b4fa32f0SFrancis Fan 
8949cd8e85SPhilipp Tomsich struct rockchip_efuse_regs {
9049cd8e85SPhilipp Tomsich 	u32 ctrl;      /* 0x00  efuse control register */
9149cd8e85SPhilipp Tomsich 	u32 dout;      /* 0x04  efuse data out register */
9249cd8e85SPhilipp Tomsich 	u32 rf;        /* 0x08  efuse redundancy bit used register */
9349cd8e85SPhilipp Tomsich 	u32 _rsvd0;
9449cd8e85SPhilipp Tomsich 	u32 jtag_pass; /* 0x10  JTAG password */
9549cd8e85SPhilipp Tomsich 	u32 strobe_finish_ctrl;
9649cd8e85SPhilipp Tomsich 		       /* 0x14	efuse strobe finish control register */
9759a83996SJoseph Chen 	u32 int_status;/* 0x18 */
9859a83996SJoseph Chen 	u32 reserved;  /* 0x1c */
9959a83996SJoseph Chen 	u32 dout2;     /* 0x20 */
10059a83996SJoseph Chen 	u32 auto_ctrl; /* 0x24 */
10149cd8e85SPhilipp Tomsich };
10249cd8e85SPhilipp Tomsich 
10349cd8e85SPhilipp Tomsich struct rockchip_efuse_platdata {
10449cd8e85SPhilipp Tomsich 	void __iomem *base;
10549cd8e85SPhilipp Tomsich 	struct clk *clk;
10649cd8e85SPhilipp Tomsich };
10749cd8e85SPhilipp Tomsich 
10849cd8e85SPhilipp Tomsich #if defined(DEBUG)
10949cd8e85SPhilipp Tomsich static int dump_efuses(cmd_tbl_t *cmdtp, int flag,
11049cd8e85SPhilipp Tomsich 		       int argc, char * const argv[])
11149cd8e85SPhilipp Tomsich {
11249cd8e85SPhilipp Tomsich 	/*
11349cd8e85SPhilipp Tomsich 	 * N.B.: This function is tailored towards the RK3399 and assumes that
11449cd8e85SPhilipp Tomsich 	 *       there's always 32 fuses x 32 bits (i.e. 128 bytes of data) to
11549cd8e85SPhilipp Tomsich 	 *       be read.
11649cd8e85SPhilipp Tomsich 	 */
11749cd8e85SPhilipp Tomsich 
11849cd8e85SPhilipp Tomsich 	struct udevice *dev;
119b4fa32f0SFrancis Fan 	u8 fuses[128] = {0};
12049cd8e85SPhilipp Tomsich 	int ret;
12149cd8e85SPhilipp Tomsich 
12249cd8e85SPhilipp Tomsich 	/* retrieve the device */
12349cd8e85SPhilipp Tomsich 	ret = uclass_get_device_by_driver(UCLASS_MISC,
12449cd8e85SPhilipp Tomsich 					  DM_GET_DRIVER(rockchip_efuse), &dev);
12549cd8e85SPhilipp Tomsich 	if (ret) {
12649cd8e85SPhilipp Tomsich 		printf("%s: no misc-device found\n", __func__);
12749cd8e85SPhilipp Tomsich 		return 0;
12849cd8e85SPhilipp Tomsich 	}
12949cd8e85SPhilipp Tomsich 
13049cd8e85SPhilipp Tomsich 	ret = misc_read(dev, 0, &fuses, sizeof(fuses));
13149cd8e85SPhilipp Tomsich 	if (ret) {
13249cd8e85SPhilipp Tomsich 		printf("%s: misc_read failed\n", __func__);
13349cd8e85SPhilipp Tomsich 		return 0;
13449cd8e85SPhilipp Tomsich 	}
13549cd8e85SPhilipp Tomsich 
13649cd8e85SPhilipp Tomsich 	printf("efuse-contents:\n");
13749cd8e85SPhilipp Tomsich 	print_buffer(0, fuses, 1, 128, 16);
13849cd8e85SPhilipp Tomsich 
13949cd8e85SPhilipp Tomsich 	return 0;
14049cd8e85SPhilipp Tomsich }
14149cd8e85SPhilipp Tomsich 
14249cd8e85SPhilipp Tomsich U_BOOT_CMD(
143b4fa32f0SFrancis Fan 	rockchip_dump_efuses, 1, 1, dump_efuses,
14449cd8e85SPhilipp Tomsich 	"Dump the content of the efuses",
14549cd8e85SPhilipp Tomsich 	""
14649cd8e85SPhilipp Tomsich );
14749cd8e85SPhilipp Tomsich #endif
14849cd8e85SPhilipp Tomsich 
149*b13cc84cSFinley Xiao static void rk1808_efuse_timing_init(void __iomem *base)
150*b13cc84cSFinley Xiao {
151*b13cc84cSFinley Xiao 	static bool init;
152*b13cc84cSFinley Xiao 
153*b13cc84cSFinley Xiao 	if (init)
154*b13cc84cSFinley Xiao 		return;
155*b13cc84cSFinley Xiao 
156*b13cc84cSFinley Xiao 	/* enable auto mode */
157*b13cc84cSFinley Xiao 	writel(readl(base) & (~RK1808_USER_MODE), base);
158*b13cc84cSFinley Xiao 
159*b13cc84cSFinley Xiao 	/* setup efuse timing */
160*b13cc84cSFinley Xiao 	writel((T_CSB_P_S << 16) | T_CSB_P_L, base + T_CSB_P);
161*b13cc84cSFinley Xiao 	writel((T_PGENB_P_S << 16) | T_PGENB_P_L, base + T_PGENB_P);
162*b13cc84cSFinley Xiao 	writel((T_LOAD_P_S << 16) | T_LOAD_P_L, base + T_LOAD_P);
163*b13cc84cSFinley Xiao 	writel((T_ADDR_P_S << 16) | T_ADDR_P_L, base + T_ADDR_P);
164*b13cc84cSFinley Xiao 	writel((T_STROBE_P_S << 16) | T_STROBE_P_L, base + T_STROBE_P);
165*b13cc84cSFinley Xiao 	writel((T_CSB_R_S << 16) | T_CSB_R_L, base + T_CSB_R);
166*b13cc84cSFinley Xiao 	writel((T_PGENB_R_S << 16) | T_PGENB_R_L, base + T_PGENB_R);
167*b13cc84cSFinley Xiao 	writel((T_LOAD_R_S << 16) | T_LOAD_R_L, base + T_LOAD_R);
168*b13cc84cSFinley Xiao 	writel((T_ADDR_R_S << 16) | T_ADDR_R_L, base + T_ADDR_R);
169*b13cc84cSFinley Xiao 	writel((T_STROBE_R_S << 16) | T_STROBE_R_L, base + T_STROBE_R);
170*b13cc84cSFinley Xiao 
171*b13cc84cSFinley Xiao 	init = true;
172*b13cc84cSFinley Xiao }
173*b13cc84cSFinley Xiao 
174*b13cc84cSFinley Xiao static int rockchip_rk1808_efuse_read(struct udevice *dev, int offset,
175*b13cc84cSFinley Xiao 				      void *buf, int size)
176*b13cc84cSFinley Xiao {
177*b13cc84cSFinley Xiao 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
178*b13cc84cSFinley Xiao 	struct rockchip_efuse_regs *efuse =
179*b13cc84cSFinley Xiao 		(struct rockchip_efuse_regs *)plat->base;
180*b13cc84cSFinley Xiao 	unsigned int addr_start, addr_end, addr_offset, addr_len;
181*b13cc84cSFinley Xiao 	u32 out_value, status;
182*b13cc84cSFinley Xiao 	u8 *buffer;
183*b13cc84cSFinley Xiao 	int ret = 0, i = 0;
184*b13cc84cSFinley Xiao 
185*b13cc84cSFinley Xiao 	rk1808_efuse_timing_init(plat->base);
186*b13cc84cSFinley Xiao 
187*b13cc84cSFinley Xiao 	addr_start = rounddown(offset, RK1808_NBYTES) / RK1808_NBYTES;
188*b13cc84cSFinley Xiao 	addr_end = roundup(offset + size, RK1808_NBYTES) / RK1808_NBYTES;
189*b13cc84cSFinley Xiao 	addr_offset = offset % RK1808_NBYTES;
190*b13cc84cSFinley Xiao 	addr_len = addr_end - addr_start;
191*b13cc84cSFinley Xiao 
192*b13cc84cSFinley Xiao 	buffer = calloc(1, sizeof(*buffer) * addr_len * RK1808_NBYTES);
193*b13cc84cSFinley Xiao 	if (!buffer)
194*b13cc84cSFinley Xiao 		return -ENOMEM;
195*b13cc84cSFinley Xiao 
196*b13cc84cSFinley Xiao 	while (addr_len--) {
197*b13cc84cSFinley Xiao 		writel(RK1808_AUTO_RD | RK1808_AUTO_ENB |
198*b13cc84cSFinley Xiao 		       ((addr_start++ & RK1808_A_MASK) << RK1808_A_SHIFT),
199*b13cc84cSFinley Xiao 		       &efuse->auto_ctrl);
200*b13cc84cSFinley Xiao 		udelay(2);
201*b13cc84cSFinley Xiao 		status = readl(&efuse->int_status);
202*b13cc84cSFinley Xiao 		if (!(status & RK1808_INT_FINISH)) {
203*b13cc84cSFinley Xiao 			ret = -EIO;
204*b13cc84cSFinley Xiao 			goto err;
205*b13cc84cSFinley Xiao 		}
206*b13cc84cSFinley Xiao 		out_value = readl(&efuse->dout2);
207*b13cc84cSFinley Xiao 		writel(RK1808_INT_FINISH, &efuse->int_status);
208*b13cc84cSFinley Xiao 
209*b13cc84cSFinley Xiao 		memcpy(&buffer[i], &out_value, RK1808_NBYTES);
210*b13cc84cSFinley Xiao 		i += RK1808_NBYTES;
211*b13cc84cSFinley Xiao 	}
212*b13cc84cSFinley Xiao 	memcpy(buf, buffer + addr_offset, size);
213*b13cc84cSFinley Xiao err:
214*b13cc84cSFinley Xiao 	kfree(buffer);
215*b13cc84cSFinley Xiao 
216*b13cc84cSFinley Xiao 	return ret;
217*b13cc84cSFinley Xiao }
218*b13cc84cSFinley Xiao 
21949cd8e85SPhilipp Tomsich static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset,
22049cd8e85SPhilipp Tomsich 				      void *buf, int size)
22149cd8e85SPhilipp Tomsich {
22249cd8e85SPhilipp Tomsich 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
22349cd8e85SPhilipp Tomsich 	struct rockchip_efuse_regs *efuse =
22449cd8e85SPhilipp Tomsich 		(struct rockchip_efuse_regs *)plat->base;
22549cd8e85SPhilipp Tomsich 
22649cd8e85SPhilipp Tomsich 	unsigned int addr_start, addr_end, addr_offset;
22749cd8e85SPhilipp Tomsich 	u32 out_value;
22849cd8e85SPhilipp Tomsich 	u8  bytes[RK3399_NFUSES * RK3399_BYTES_PER_FUSE];
22949cd8e85SPhilipp Tomsich 	int i = 0;
23049cd8e85SPhilipp Tomsich 	u32 addr;
23149cd8e85SPhilipp Tomsich 
23249cd8e85SPhilipp Tomsich 	addr_start = offset / RK3399_BYTES_PER_FUSE;
23349cd8e85SPhilipp Tomsich 	addr_offset = offset % RK3399_BYTES_PER_FUSE;
23449cd8e85SPhilipp Tomsich 	addr_end = DIV_ROUND_UP(offset + size, RK3399_BYTES_PER_FUSE);
23549cd8e85SPhilipp Tomsich 
23649cd8e85SPhilipp Tomsich 	/* cap to the size of the efuse block */
23749cd8e85SPhilipp Tomsich 	if (addr_end > RK3399_NFUSES)
23849cd8e85SPhilipp Tomsich 		addr_end = RK3399_NFUSES;
23949cd8e85SPhilipp Tomsich 
24049cd8e85SPhilipp Tomsich 	writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
24149cd8e85SPhilipp Tomsich 	       &efuse->ctrl);
24249cd8e85SPhilipp Tomsich 	udelay(1);
24349cd8e85SPhilipp Tomsich 	for (addr = addr_start; addr < addr_end; addr++) {
24449cd8e85SPhilipp Tomsich 		setbits_le32(&efuse->ctrl,
24549cd8e85SPhilipp Tomsich 			     RK3399_STROBE | (addr << RK3399_A_SHIFT));
24649cd8e85SPhilipp Tomsich 		udelay(1);
24749cd8e85SPhilipp Tomsich 		out_value = readl(&efuse->dout);
24849cd8e85SPhilipp Tomsich 		clrbits_le32(&efuse->ctrl, RK3399_STROBE);
24949cd8e85SPhilipp Tomsich 		udelay(1);
25049cd8e85SPhilipp Tomsich 
25149cd8e85SPhilipp Tomsich 		memcpy(&bytes[i], &out_value, RK3399_BYTES_PER_FUSE);
25249cd8e85SPhilipp Tomsich 		i += RK3399_BYTES_PER_FUSE;
25349cd8e85SPhilipp Tomsich 	}
25449cd8e85SPhilipp Tomsich 
25549cd8e85SPhilipp Tomsich 	/* Switch to standby mode */
25649cd8e85SPhilipp Tomsich 	writel(RK3399_PD | RK3399_CSB, &efuse->ctrl);
25749cd8e85SPhilipp Tomsich 
25849cd8e85SPhilipp Tomsich 	memcpy(buf, bytes + addr_offset, size);
25949cd8e85SPhilipp Tomsich 
26049cd8e85SPhilipp Tomsich 	return 0;
26149cd8e85SPhilipp Tomsich }
26249cd8e85SPhilipp Tomsich 
263b4fa32f0SFrancis Fan static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset,
264b4fa32f0SFrancis Fan 				      void *buf, int size)
265b4fa32f0SFrancis Fan {
266b4fa32f0SFrancis Fan 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
267b4fa32f0SFrancis Fan 	struct rockchip_efuse_regs *efuse =
268b4fa32f0SFrancis Fan 		(struct rockchip_efuse_regs *)plat->base;
269b4fa32f0SFrancis Fan 	u8 *buffer = buf;
270b4fa32f0SFrancis Fan 	int max_size = RK3288_NFUSES * RK3288_BYTES_PER_FUSE;
271b4fa32f0SFrancis Fan 
272b4fa32f0SFrancis Fan 	if (size > (max_size - offset))
273b4fa32f0SFrancis Fan 		size = max_size - offset;
274b4fa32f0SFrancis Fan 
275b4fa32f0SFrancis Fan 	/* Switch to read mode */
276b4fa32f0SFrancis Fan 	writel(RK3288_LOAD | RK3288_PGENB, &efuse->ctrl);
277b4fa32f0SFrancis Fan 	udelay(1);
278b4fa32f0SFrancis Fan 
279b4fa32f0SFrancis Fan 	while (size--) {
280b4fa32f0SFrancis Fan 		writel(readl(&efuse->ctrl) &
281b4fa32f0SFrancis Fan 				(~(RK3288_A_MASK << RK3288_A_SHIFT)),
282b4fa32f0SFrancis Fan 				&efuse->ctrl);
283b4fa32f0SFrancis Fan 		/* set addr */
284b4fa32f0SFrancis Fan 		writel(readl(&efuse->ctrl) |
285b4fa32f0SFrancis Fan 				((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT),
286b4fa32f0SFrancis Fan 				&efuse->ctrl);
287b4fa32f0SFrancis Fan 		udelay(1);
288b4fa32f0SFrancis Fan 		/* strobe low to high */
289b4fa32f0SFrancis Fan 		writel(readl(&efuse->ctrl) |
290b4fa32f0SFrancis Fan 				RK3288_STROBE, &efuse->ctrl);
291b4fa32f0SFrancis Fan 		ndelay(60);
292b4fa32f0SFrancis Fan 		/* read data */
293b4fa32f0SFrancis Fan 		*buffer++ = readl(&efuse->dout);
294b4fa32f0SFrancis Fan 		/* reset strobe to low */
295b4fa32f0SFrancis Fan 		writel(readl(&efuse->ctrl) &
296b4fa32f0SFrancis Fan 				(~RK3288_STROBE), &efuse->ctrl);
297b4fa32f0SFrancis Fan 		udelay(1);
298b4fa32f0SFrancis Fan 	}
299b4fa32f0SFrancis Fan 
300b4fa32f0SFrancis Fan 	/* Switch to standby mode */
301b4fa32f0SFrancis Fan 	writel(RK3288_PGENB | RK3288_CSB, &efuse->ctrl);
302b4fa32f0SFrancis Fan 
303b4fa32f0SFrancis Fan 	return 0;
304b4fa32f0SFrancis Fan }
305b4fa32f0SFrancis Fan 
30659a83996SJoseph Chen static int rockchip_rk3328_efuse_read(struct udevice *dev, int offset,
30759a83996SJoseph Chen 				      void *buf, int size)
30859a83996SJoseph Chen {
30959a83996SJoseph Chen 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
31059a83996SJoseph Chen 	struct rockchip_efuse_regs *efuse =
31159a83996SJoseph Chen 		(struct rockchip_efuse_regs *)plat->base;
31259a83996SJoseph Chen 	unsigned int addr_start, addr_end, addr_offset, addr_len;
31359a83996SJoseph Chen 	u32 out_value, status;
31459a83996SJoseph Chen 	u8 *buffer;
31559a83996SJoseph Chen 	int ret = 0, i = 0, j = 0;
31659a83996SJoseph Chen 
31759a83996SJoseph Chen 	/* Max non-secure Byte */
31859a83996SJoseph Chen 	if (size > 32)
31959a83996SJoseph Chen 		size = 32;
32059a83996SJoseph Chen 
32159a83996SJoseph Chen 	/* 128 Byte efuse, 96 Byte for secure, 32 Byte for non-secure */
32259a83996SJoseph Chen 	offset += 96;
32359a83996SJoseph Chen 	addr_start = rounddown(offset, RK3399_BYTES_PER_FUSE) /
32459a83996SJoseph Chen 						RK3399_BYTES_PER_FUSE;
32559a83996SJoseph Chen 	addr_end = roundup(offset + size, RK3399_BYTES_PER_FUSE) /
32659a83996SJoseph Chen 						RK3399_BYTES_PER_FUSE;
32759a83996SJoseph Chen 	addr_offset = offset % RK3399_BYTES_PER_FUSE;
32859a83996SJoseph Chen 	addr_len = addr_end - addr_start;
32959a83996SJoseph Chen 
33059a83996SJoseph Chen 	buffer = calloc(1, sizeof(*buffer) * addr_len * RK3399_BYTES_PER_FUSE);
33159a83996SJoseph Chen 	if (!buffer)
33259a83996SJoseph Chen 		return -ENOMEM;
33359a83996SJoseph Chen 
33459a83996SJoseph Chen 	for (j = 0; j < addr_len; j++) {
33559a83996SJoseph Chen 		writel(RK3328_AUTO_RD | RK3328_AUTO_ENB |
33659a83996SJoseph Chen 		       ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT),
33759a83996SJoseph Chen 		         &efuse->auto_ctrl);
33859a83996SJoseph Chen 		udelay(5);
33959a83996SJoseph Chen 		status = readl(&efuse->int_status);
34059a83996SJoseph Chen 		if (!(status & RK3328_INT_FINISH)) {
34159a83996SJoseph Chen 			ret = -EIO;
34259a83996SJoseph Chen 			goto err;
34359a83996SJoseph Chen 		}
34459a83996SJoseph Chen 		out_value = readl(&efuse->dout2);
34559a83996SJoseph Chen 		writel(RK3328_INT_FINISH, &efuse->int_status);
34659a83996SJoseph Chen 
34759a83996SJoseph Chen 		memcpy(&buffer[i], &out_value, RK3399_BYTES_PER_FUSE);
34859a83996SJoseph Chen 		i += RK3399_BYTES_PER_FUSE;
34959a83996SJoseph Chen 	}
35059a83996SJoseph Chen 	memcpy(buf, buffer + addr_offset, size);
35159a83996SJoseph Chen err:
35259a83996SJoseph Chen 	free(buffer);
35359a83996SJoseph Chen 
35459a83996SJoseph Chen 	return ret;
35559a83996SJoseph Chen }
35659a83996SJoseph Chen 
35749cd8e85SPhilipp Tomsich static int rockchip_efuse_read(struct udevice *dev, int offset,
35849cd8e85SPhilipp Tomsich 			       void *buf, int size)
35949cd8e85SPhilipp Tomsich {
360b4fa32f0SFrancis Fan 	EFUSE_READ efuse_read = NULL;
361b4fa32f0SFrancis Fan 
362b4fa32f0SFrancis Fan 	efuse_read = (EFUSE_READ)dev_get_driver_data(dev);
363b4fa32f0SFrancis Fan 	if (!efuse_read)
364b4fa32f0SFrancis Fan 		return -ENOSYS;
365b4fa32f0SFrancis Fan 
366b4fa32f0SFrancis Fan 	return (*efuse_read)(dev, offset, buf, size);
36749cd8e85SPhilipp Tomsich }
36849cd8e85SPhilipp Tomsich 
36949cd8e85SPhilipp Tomsich static const struct misc_ops rockchip_efuse_ops = {
37049cd8e85SPhilipp Tomsich 	.read = rockchip_efuse_read,
37149cd8e85SPhilipp Tomsich };
37249cd8e85SPhilipp Tomsich 
37349cd8e85SPhilipp Tomsich static int rockchip_efuse_ofdata_to_platdata(struct udevice *dev)
37449cd8e85SPhilipp Tomsich {
37549cd8e85SPhilipp Tomsich 	struct rockchip_efuse_platdata *plat = dev_get_platdata(dev);
37649cd8e85SPhilipp Tomsich 
37763a453e6SPhilipp Tomsich 	plat->base = dev_read_addr_ptr(dev);
37849cd8e85SPhilipp Tomsich 	return 0;
37949cd8e85SPhilipp Tomsich }
38049cd8e85SPhilipp Tomsich 
38149cd8e85SPhilipp Tomsich static const struct udevice_id rockchip_efuse_ids[] = {
382b4fa32f0SFrancis Fan 	{
383*b13cc84cSFinley Xiao 		.compatible = "rockchip,rk1808-efuse",
384*b13cc84cSFinley Xiao 		.data = (ulong)&rockchip_rk1808_efuse_read,
385*b13cc84cSFinley Xiao 	},
386*b13cc84cSFinley Xiao 	{
387b4fa32f0SFrancis Fan 		.compatible = "rockchip,rockchip-efuse",
388e9cfb932SCody Xie 		.data = (ulong)&rockchip_rk3288_efuse_read,
389b4fa32f0SFrancis Fan 	},
390b4fa32f0SFrancis Fan 	{
391b4fa32f0SFrancis Fan 		.compatible = "rockchip,rk3066a-efuse",
392e9cfb932SCody Xie 		.data = (ulong)&rockchip_rk3288_efuse_read,
393b4fa32f0SFrancis Fan 	},
394b4fa32f0SFrancis Fan 	{
395b4fa32f0SFrancis Fan 		.compatible = "rockchip,rk3188-efuse",
396e9cfb932SCody Xie 		.data = (ulong)&rockchip_rk3288_efuse_read,
397b4fa32f0SFrancis Fan 	},
398b4fa32f0SFrancis Fan 	{
399b4fa32f0SFrancis Fan 		.compatible = "rockchip,rk322x-efuse",
400e9cfb932SCody Xie 		.data = (ulong)&rockchip_rk3288_efuse_read,
401b4fa32f0SFrancis Fan 	},
402b4fa32f0SFrancis Fan 	{
40359a83996SJoseph Chen 		.compatible = "rockchip,rk3328-efuse",
40459a83996SJoseph Chen 		.data = (ulong)&rockchip_rk3328_efuse_read,
40559a83996SJoseph Chen 	},
40659a83996SJoseph Chen 	{
407b4fa32f0SFrancis Fan 		.compatible = "rockchip,rk3399-efuse",
408b4fa32f0SFrancis Fan 		.data = (ulong)&rockchip_rk3399_efuse_read,
409b4fa32f0SFrancis Fan 	},
41049cd8e85SPhilipp Tomsich 	{}
41149cd8e85SPhilipp Tomsich };
41249cd8e85SPhilipp Tomsich 
41349cd8e85SPhilipp Tomsich U_BOOT_DRIVER(rockchip_efuse) = {
41449cd8e85SPhilipp Tomsich 	.name = "rockchip_efuse",
41549cd8e85SPhilipp Tomsich 	.id = UCLASS_MISC,
41649cd8e85SPhilipp Tomsich 	.of_match = rockchip_efuse_ids,
41749cd8e85SPhilipp Tomsich 	.ofdata_to_platdata = rockchip_efuse_ofdata_to_platdata,
41849cd8e85SPhilipp Tomsich 	.platdata_auto_alloc_size = sizeof(struct rockchip_efuse_platdata),
41949cd8e85SPhilipp Tomsich 	.ops = &rockchip_efuse_ops,
42049cd8e85SPhilipp Tomsich };
421