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