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