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