1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <common.h>
7*4882a593Smuzhiyun #include <asm/arch/cpu.h>
8*4882a593Smuzhiyun #include <asm/io.h>
9*4882a593Smuzhiyun #include <command.h>
10*4882a593Smuzhiyun #include <dm.h>
11*4882a593Smuzhiyun #include <linux/bitops.h>
12*4882a593Smuzhiyun #include <linux/delay.h>
13*4882a593Smuzhiyun #include <linux/iopoll.h>
14*4882a593Smuzhiyun #include <misc.h>
15*4882a593Smuzhiyun #include <rockchip-otp.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun struct otp_data {
18*4882a593Smuzhiyun int (*init)(struct udevice *dev);
19*4882a593Smuzhiyun int (*read)(struct udevice *dev, int offset, void *buf, int size);
20*4882a593Smuzhiyun };
21*4882a593Smuzhiyun
rockchip_otp_wait_status(struct rockchip_otp_platdata * otp,u32 flag)22*4882a593Smuzhiyun static int rockchip_otp_wait_status(struct rockchip_otp_platdata *otp,
23*4882a593Smuzhiyun u32 flag)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun int delay = OTPC_TIMEOUT;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun while (!(readl(otp->base + OTPC_INT_STATUS) & flag)) {
28*4882a593Smuzhiyun udelay(1);
29*4882a593Smuzhiyun delay--;
30*4882a593Smuzhiyun if (delay <= 0) {
31*4882a593Smuzhiyun printf("%s: wait init status timeout\n", __func__);
32*4882a593Smuzhiyun return -ETIMEDOUT;
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun /* clean int status */
37*4882a593Smuzhiyun writel(flag, otp->base + OTPC_INT_STATUS);
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun return 0;
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun
rockchip_otp_ecc_enable(struct rockchip_otp_platdata * otp,bool enable)42*4882a593Smuzhiyun static int rockchip_otp_ecc_enable(struct rockchip_otp_platdata *otp,
43*4882a593Smuzhiyun bool enable)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun int ret = 0;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
48*4882a593Smuzhiyun otp->base + OTPC_SBPI_CTRL);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
51*4882a593Smuzhiyun writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
52*4882a593Smuzhiyun otp->base + OTPC_SBPI_CMD0_OFFSET);
53*4882a593Smuzhiyun if (enable)
54*4882a593Smuzhiyun writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
55*4882a593Smuzhiyun else
56*4882a593Smuzhiyun writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE);
61*4882a593Smuzhiyun if (ret < 0)
62*4882a593Smuzhiyun printf("%s timeout during ecc_enable\n", __func__);
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun return ret;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
rockchip_px30_otp_read(struct udevice * dev,int offset,void * buf,int size)67*4882a593Smuzhiyun static int rockchip_px30_otp_read(struct udevice *dev, int offset,
68*4882a593Smuzhiyun void *buf, int size)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
71*4882a593Smuzhiyun u8 *buffer = buf;
72*4882a593Smuzhiyun int ret = 0;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun ret = rockchip_otp_ecc_enable(otp, false);
75*4882a593Smuzhiyun if (ret < 0) {
76*4882a593Smuzhiyun printf("%s rockchip_otp_ecc_enable err\n", __func__);
77*4882a593Smuzhiyun return ret;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
81*4882a593Smuzhiyun udelay(5);
82*4882a593Smuzhiyun while (size--) {
83*4882a593Smuzhiyun writel(offset++ | OTPC_USER_ADDR_MASK,
84*4882a593Smuzhiyun otp->base + OTPC_USER_ADDR);
85*4882a593Smuzhiyun writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
86*4882a593Smuzhiyun otp->base + OTPC_USER_ENABLE);
87*4882a593Smuzhiyun ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
88*4882a593Smuzhiyun if (ret < 0) {
89*4882a593Smuzhiyun printf("%s timeout during read setup\n", __func__);
90*4882a593Smuzhiyun goto read_end;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun *buffer++ = readb(otp->base + OTPC_USER_Q);
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun read_end:
96*4882a593Smuzhiyun writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun return ret;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
rk3308bs_otp_wait_status(struct rockchip_otp_platdata * otp,u32 flag)101*4882a593Smuzhiyun static int rk3308bs_otp_wait_status(struct rockchip_otp_platdata *otp, u32 flag)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun int delay = OTPC_TIMEOUT;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun while (!(readl(otp->base + OTPC_IRQ_ST) & flag)) {
106*4882a593Smuzhiyun udelay(1);
107*4882a593Smuzhiyun delay--;
108*4882a593Smuzhiyun if (delay <= 0) {
109*4882a593Smuzhiyun printf("%s: wait init status timeout\n", __func__);
110*4882a593Smuzhiyun return -ETIMEDOUT;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun /* clean int status */
115*4882a593Smuzhiyun writel(flag, otp->base + OTPC_IRQ_ST);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun return 0;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
rk3308bs_otp_active(struct rockchip_otp_platdata * otp)120*4882a593Smuzhiyun static int rk3308bs_otp_active(struct rockchip_otp_platdata *otp)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun int ret = 0;
123*4882a593Smuzhiyun u32 mode;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun mode = readl(otp->base + OTPC_MODE_CTRL);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun switch (mode) {
128*4882a593Smuzhiyun case OTPC_DEEP_STANDBY:
129*4882a593Smuzhiyun writel(OTPC_STANDBY, otp->base + OTPC_MODE_CTRL);
130*4882a593Smuzhiyun ret = rk3308bs_otp_wait_status(otp, OTPC_DP2STB_IRQ_ST);
131*4882a593Smuzhiyun if (ret < 0) {
132*4882a593Smuzhiyun dev_err(otp->dev, "timeout during wait dp2stb\n");
133*4882a593Smuzhiyun return ret;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun case OTPC_STANDBY:
136*4882a593Smuzhiyun writel(OTPC_ACTIVE, otp->base + OTPC_MODE_CTRL);
137*4882a593Smuzhiyun ret = rk3308bs_otp_wait_status(otp, OTPC_STB2ACT_IRQ_ST);
138*4882a593Smuzhiyun if (ret < 0) {
139*4882a593Smuzhiyun dev_err(otp->dev, "timeout during wait stb2act\n");
140*4882a593Smuzhiyun return ret;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun break;
143*4882a593Smuzhiyun default:
144*4882a593Smuzhiyun break;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun return ret;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
rk3308bs_otp_standby(struct rockchip_otp_platdata * otp)150*4882a593Smuzhiyun static int rk3308bs_otp_standby(struct rockchip_otp_platdata *otp)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun int ret = 0;
153*4882a593Smuzhiyun u32 mode;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun mode = readl(otp->base + OTPC_MODE_CTRL);
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun switch (mode) {
158*4882a593Smuzhiyun case OTPC_ACTIVE:
159*4882a593Smuzhiyun writel(OTPC_STANDBY, otp->base + OTPC_MODE_CTRL);
160*4882a593Smuzhiyun ret = rk3308bs_otp_wait_status(otp, OTPC_ACT2STB_IRQ_ST);
161*4882a593Smuzhiyun if (ret < 0) {
162*4882a593Smuzhiyun dev_err(otp->dev, "timeout during wait act2stb\n");
163*4882a593Smuzhiyun return ret;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun case OTPC_STANDBY:
166*4882a593Smuzhiyun writel(OTPC_DEEP_STANDBY, otp->base + OTPC_MODE_CTRL);
167*4882a593Smuzhiyun ret = rk3308bs_otp_wait_status(otp, OTPC_STB2DP_IRQ_ST);
168*4882a593Smuzhiyun if (ret < 0) {
169*4882a593Smuzhiyun dev_err(otp->dev, "timeout during wait stb2dp\n");
170*4882a593Smuzhiyun return ret;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun break;
173*4882a593Smuzhiyun default:
174*4882a593Smuzhiyun break;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun return ret;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
rockchip_rk3308bs_otp_read(struct udevice * dev,int offset,void * buf,int size)180*4882a593Smuzhiyun static int rockchip_rk3308bs_otp_read(struct udevice *dev, int offset,
181*4882a593Smuzhiyun void *buf, int size)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
184*4882a593Smuzhiyun unsigned int addr_start, addr_end, addr_offset, addr_len;
185*4882a593Smuzhiyun u32 out_value;
186*4882a593Smuzhiyun u8 *buffer;
187*4882a593Smuzhiyun int ret = 0, i = 0;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun if (offset > RK3308BS_MAX_BYTES - 1)
190*4882a593Smuzhiyun return -ENOMEM;
191*4882a593Smuzhiyun if (offset + size > RK3308BS_MAX_BYTES)
192*4882a593Smuzhiyun size = RK3308BS_MAX_BYTES - offset;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun ret = rk3308bs_otp_active(otp);
195*4882a593Smuzhiyun if (ret)
196*4882a593Smuzhiyun goto out;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun addr_start = rounddown(offset, RK3308BS_NBYTES) / RK3308BS_NBYTES;
199*4882a593Smuzhiyun addr_end = roundup(offset + size, RK3308BS_NBYTES) / RK3308BS_NBYTES;
200*4882a593Smuzhiyun addr_offset = offset % RK3308BS_NBYTES;
201*4882a593Smuzhiyun addr_len = addr_end - addr_start;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun buffer = calloc(1, sizeof(*buffer) * addr_len * RK3308BS_NBYTES);
204*4882a593Smuzhiyun if (!buffer) {
205*4882a593Smuzhiyun ret = -ENOMEM;
206*4882a593Smuzhiyun goto read_end;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun while (addr_len--) {
210*4882a593Smuzhiyun writel(OTPC_TRANS_NUM, otp->base + OTPC_REPR_RD_TRANS_NUM);
211*4882a593Smuzhiyun writel(addr_start++, otp->base + OTPC_ACCESS_ADDR);
212*4882a593Smuzhiyun writel(OTPC_READ_ACCESS, otp->base + OTPC_MODE_CTRL);
213*4882a593Smuzhiyun ret = rk3308bs_otp_wait_status(otp, OTPC_RDM_IRQ_ST);
214*4882a593Smuzhiyun if (ret < 0) {
215*4882a593Smuzhiyun printf("timeout during wait rd\n");
216*4882a593Smuzhiyun goto read_end;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun out_value = readl(otp->base + OTPC_RD_DATA);
219*4882a593Smuzhiyun memcpy(&buffer[i], &out_value, RK3308BS_NBYTES);
220*4882a593Smuzhiyun i += RK3308BS_NBYTES;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun memcpy(buf, buffer + addr_offset, size);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun read_end:
225*4882a593Smuzhiyun kfree(buffer);
226*4882a593Smuzhiyun rk3308bs_otp_standby(otp);
227*4882a593Smuzhiyun out:
228*4882a593Smuzhiyun return ret;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
rockchip_rk3568_otp_read(struct udevice * dev,int offset,void * buf,int size)231*4882a593Smuzhiyun static int rockchip_rk3568_otp_read(struct udevice *dev, int offset, void *buf,
232*4882a593Smuzhiyun int size)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
235*4882a593Smuzhiyun unsigned int addr_start, addr_end, addr_offset, addr_len;
236*4882a593Smuzhiyun u32 out_value;
237*4882a593Smuzhiyun u8 *buffer;
238*4882a593Smuzhiyun int ret = 0, i = 0;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun addr_start = rounddown(offset, RK3568_NBYTES) / RK3568_NBYTES;
241*4882a593Smuzhiyun addr_end = roundup(offset + size, RK3568_NBYTES) / RK3568_NBYTES;
242*4882a593Smuzhiyun addr_offset = offset % RK3568_NBYTES;
243*4882a593Smuzhiyun addr_len = addr_end - addr_start;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun buffer = calloc(1, sizeof(*buffer) * addr_len * RK3568_NBYTES);
246*4882a593Smuzhiyun if (!buffer)
247*4882a593Smuzhiyun return -ENOMEM;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun ret = rockchip_otp_ecc_enable(otp, true);
250*4882a593Smuzhiyun if (ret < 0) {
251*4882a593Smuzhiyun printf("%s rockchip_otp_ecc_enable err\n", __func__);
252*4882a593Smuzhiyun return ret;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
256*4882a593Smuzhiyun udelay(5);
257*4882a593Smuzhiyun while (addr_len--) {
258*4882a593Smuzhiyun writel(addr_start++ | OTPC_USER_ADDR_MASK,
259*4882a593Smuzhiyun otp->base + OTPC_USER_ADDR);
260*4882a593Smuzhiyun writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
261*4882a593Smuzhiyun otp->base + OTPC_USER_ENABLE);
262*4882a593Smuzhiyun ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
263*4882a593Smuzhiyun if (ret < 0) {
264*4882a593Smuzhiyun printf("%s timeout during read setup\n", __func__);
265*4882a593Smuzhiyun goto read_end;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun out_value = readl(otp->base + OTPC_USER_Q);
268*4882a593Smuzhiyun memcpy(&buffer[i], &out_value, RK3568_NBYTES);
269*4882a593Smuzhiyun i += RK3568_NBYTES;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun memcpy(buf, buffer + addr_offset, size);
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun read_end:
275*4882a593Smuzhiyun writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun kfree(buffer);
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun return ret;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
rockchip_rk3588_otp_read(struct udevice * dev,int offset,void * buf,int size)282*4882a593Smuzhiyun static int rockchip_rk3588_otp_read(struct udevice *dev, int offset, void *buf,
283*4882a593Smuzhiyun int size)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
286*4882a593Smuzhiyun unsigned int addr_start, addr_end, addr_offset, addr_len;
287*4882a593Smuzhiyun int ret = 0, i = 0;
288*4882a593Smuzhiyun u32 out_value, st = 0;
289*4882a593Smuzhiyun u8 *buffer;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun if (offset > RK3588_MAX_BYTES - 1)
292*4882a593Smuzhiyun return -ENOMEM;
293*4882a593Smuzhiyun if (offset + size > RK3588_MAX_BYTES)
294*4882a593Smuzhiyun size = RK3588_MAX_BYTES - offset;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun addr_start = rounddown(offset, RK3588_NBYTES) / RK3588_NBYTES;
297*4882a593Smuzhiyun addr_end = roundup(offset + size, RK3588_NBYTES) / RK3588_NBYTES;
298*4882a593Smuzhiyun addr_offset = offset % RK3588_NBYTES;
299*4882a593Smuzhiyun addr_len = addr_end - addr_start;
300*4882a593Smuzhiyun addr_start += RK3588_NO_SECURE_OFFSET;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun buffer = calloc(1, sizeof(*buffer) * addr_len * RK3588_NBYTES);
303*4882a593Smuzhiyun if (!buffer)
304*4882a593Smuzhiyun return -ENOMEM;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun while (addr_len--) {
307*4882a593Smuzhiyun writel((addr_start << RK3588_ADDR_SHIFT) |
308*4882a593Smuzhiyun (RK3588_BURST_NUM << RK3588_BURST_SHIFT),
309*4882a593Smuzhiyun otp->base + RK3588_OTPC_AUTO_CTRL);
310*4882a593Smuzhiyun writel(RK3588_AUTO_EN, otp->base + RK3588_OTPC_AUTO_EN);
311*4882a593Smuzhiyun ret = readl_poll_timeout(otp->base + RK3588_OTPC_INT_ST, st,
312*4882a593Smuzhiyun st & RK3588_RD_DONE, OTPC_TIMEOUT);
313*4882a593Smuzhiyun if (ret < 0) {
314*4882a593Smuzhiyun printf("%s timeout during read setup\n", __func__);
315*4882a593Smuzhiyun goto read_end;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun writel(RK3588_RD_DONE, otp->base + RK3588_OTPC_INT_ST);
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun out_value = readl(otp->base + RK3588_OTPC_DOUT0);
320*4882a593Smuzhiyun memcpy(&buffer[i], &out_value, RK3588_NBYTES);
321*4882a593Smuzhiyun i += RK3588_NBYTES;
322*4882a593Smuzhiyun addr_start++;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun memcpy(buf, buffer + addr_offset, size);
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun read_end:
328*4882a593Smuzhiyun kfree(buffer);
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun return ret;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
rockchip_rv1126_otp_init(struct udevice * dev)333*4882a593Smuzhiyun static int rockchip_rv1126_otp_init(struct udevice *dev)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
336*4882a593Smuzhiyun u32 status = 0;
337*4882a593Smuzhiyun int ret;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun writel(0x0, otp->base + RV1126_OTP_NVM_CEB);
340*4882a593Smuzhiyun ret = readl_poll_timeout(otp->base + RV1126_OTP_NVM_ST, status,
341*4882a593Smuzhiyun status & 0x1, OTPC_TIMEOUT);
342*4882a593Smuzhiyun if (ret < 0) {
343*4882a593Smuzhiyun printf("%s timeout during set ceb\n", __func__);
344*4882a593Smuzhiyun return ret;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun writel(0x1, otp->base + RV1126_OTP_NVM_RSTB);
348*4882a593Smuzhiyun ret = readl_poll_timeout(otp->base + RV1126_OTP_NVM_ST, status,
349*4882a593Smuzhiyun status & 0x4, OTPC_TIMEOUT);
350*4882a593Smuzhiyun if (ret < 0) {
351*4882a593Smuzhiyun printf("%s timeout during set rstb\n", __func__);
352*4882a593Smuzhiyun return ret;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun return 0;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
rockchip_rv1126_otp_read(struct udevice * dev,int offset,void * buf,int size)358*4882a593Smuzhiyun static int rockchip_rv1126_otp_read(struct udevice *dev, int offset, void *buf,
359*4882a593Smuzhiyun int size)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
362*4882a593Smuzhiyun u32 status = 0;
363*4882a593Smuzhiyun u8 *buffer = buf;
364*4882a593Smuzhiyun int ret = 0;
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun while (size--) {
367*4882a593Smuzhiyun writel(offset++, otp->base + RV1126_OTP_NVM_RADDR);
368*4882a593Smuzhiyun writel(0x1, otp->base + RV1126_OTP_NVM_RSTART);
369*4882a593Smuzhiyun ret = readl_poll_timeout(otp->base + RV1126_OTP_READ_ST,
370*4882a593Smuzhiyun status, status == 0, OTPC_TIMEOUT);
371*4882a593Smuzhiyun if (ret < 0) {
372*4882a593Smuzhiyun printf("%s timeout during read setup\n", __func__);
373*4882a593Smuzhiyun return ret;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun *buffer++ = readb(otp->base + RV1126_OTP_NVM_RDATA);
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun return 0;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
rockchip_otp_read(struct udevice * dev,int offset,void * buf,int size)382*4882a593Smuzhiyun static int rockchip_otp_read(struct udevice *dev, int offset,
383*4882a593Smuzhiyun void *buf, int size)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun struct otp_data *data;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun data = (struct otp_data *)dev_get_driver_data(dev);
388*4882a593Smuzhiyun if (!data)
389*4882a593Smuzhiyun return -ENOSYS;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun if (soc_is_rk3308bs() || soc_is_px30s())
392*4882a593Smuzhiyun return rockchip_rk3308bs_otp_read(dev, offset, buf, size);
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun return data->read(dev, offset, buf, size);
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun static const struct misc_ops rockchip_otp_ops = {
398*4882a593Smuzhiyun .read = rockchip_otp_read,
399*4882a593Smuzhiyun };
400*4882a593Smuzhiyun
rockchip_otp_ofdata_to_platdata(struct udevice * dev)401*4882a593Smuzhiyun static int rockchip_otp_ofdata_to_platdata(struct udevice *dev)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun otp->base = dev_read_addr_ptr(dev);
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun return 0;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
rockchip_otp_probe(struct udevice * dev)410*4882a593Smuzhiyun static int rockchip_otp_probe(struct udevice *dev)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun struct otp_data *data;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun data = (struct otp_data *)dev_get_driver_data(dev);
415*4882a593Smuzhiyun if (!data)
416*4882a593Smuzhiyun return -EINVAL;
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun if (data->init)
419*4882a593Smuzhiyun return data->init(dev);
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun return 0;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun static const struct otp_data px30_data = {
425*4882a593Smuzhiyun .read = rockchip_px30_otp_read,
426*4882a593Smuzhiyun };
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun static const struct otp_data rk3308bs_data = {
429*4882a593Smuzhiyun .read = rockchip_rk3308bs_otp_read,
430*4882a593Smuzhiyun };
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun static const struct otp_data rk3568_data = {
433*4882a593Smuzhiyun .read = rockchip_rk3568_otp_read,
434*4882a593Smuzhiyun };
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun static const struct otp_data rk3588_data = {
437*4882a593Smuzhiyun .read = rockchip_rk3588_otp_read,
438*4882a593Smuzhiyun };
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun static const struct otp_data rv1126_data = {
441*4882a593Smuzhiyun .init = rockchip_rv1126_otp_init,
442*4882a593Smuzhiyun .read = rockchip_rv1126_otp_read,
443*4882a593Smuzhiyun };
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun static const struct udevice_id rockchip_otp_ids[] = {
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun .compatible = "rockchip,px30-otp",
448*4882a593Smuzhiyun .data = (ulong)&px30_data,
449*4882a593Smuzhiyun },
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun .compatible = "rockchip,px30s-otp",
452*4882a593Smuzhiyun .data = (ulong)&rk3308bs_data,
453*4882a593Smuzhiyun },
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun .compatible = "rockchip,rk3308-otp",
456*4882a593Smuzhiyun .data = (ulong)&px30_data,
457*4882a593Smuzhiyun },
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun .compatible = "rockchip,rk3308bs-otp",
460*4882a593Smuzhiyun .data = (ulong)&rk3308bs_data,
461*4882a593Smuzhiyun },
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun .compatible = "rockchip,rk3528-otp",
464*4882a593Smuzhiyun .data = (ulong)&rk3568_data,
465*4882a593Smuzhiyun },
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun .compatible = "rockchip,rk3562-otp",
468*4882a593Smuzhiyun .data = (ulong)&rk3568_data,
469*4882a593Smuzhiyun },
470*4882a593Smuzhiyun {
471*4882a593Smuzhiyun .compatible = "rockchip,rk3568-otp",
472*4882a593Smuzhiyun .data = (ulong)&rk3568_data,
473*4882a593Smuzhiyun },
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun .compatible = "rockchip,rk3588-otp",
476*4882a593Smuzhiyun .data = (ulong)&rk3588_data,
477*4882a593Smuzhiyun },
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun .compatible = "rockchip,rv1106-otp",
480*4882a593Smuzhiyun .data = (ulong)&rk3568_data,
481*4882a593Smuzhiyun },
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun .compatible = "rockchip,rv1126-otp",
484*4882a593Smuzhiyun .data = (ulong)&rv1126_data,
485*4882a593Smuzhiyun },
486*4882a593Smuzhiyun {}
487*4882a593Smuzhiyun };
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun U_BOOT_DRIVER(rockchip_otp) = {
490*4882a593Smuzhiyun .name = "rockchip_otp",
491*4882a593Smuzhiyun .id = UCLASS_MISC,
492*4882a593Smuzhiyun .of_match = rockchip_otp_ids,
493*4882a593Smuzhiyun .ops = &rockchip_otp_ops,
494*4882a593Smuzhiyun .ofdata_to_platdata = rockchip_otp_ofdata_to_platdata,
495*4882a593Smuzhiyun .platdata_auto_alloc_size = sizeof(struct rockchip_otp_platdata),
496*4882a593Smuzhiyun .probe = rockchip_otp_probe,
497*4882a593Smuzhiyun };
498