xref: /rk3399_rockchip-uboot/drivers/misc/rockchip-otp.c (revision b27ae02dfdf0e26d23901e9b898629d6ec470a60)
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/io.h>
8 #include <command.h>
9 #include <dm.h>
10 #include <linux/bitops.h>
11 #include <linux/delay.h>
12 #include <misc.h>
13 #include <rockchip-otp.h>
14 
15 static int rockchip_otp_wait_status(struct rockchip_otp_platdata *otp,
16 				    u32 flag)
17 {
18 	int delay = OTPC_TIMEOUT;
19 
20 	while (!(readl(otp->base + OTPC_INT_STATUS) & flag)) {
21 		udelay(1);
22 		delay--;
23 		if (delay <= 0) {
24 			printf("%s: wait init status timeout\n", __func__);
25 			return -ETIMEDOUT;
26 		}
27 	}
28 
29 	/* clean int status */
30 	writel(flag, otp->base + OTPC_INT_STATUS);
31 
32 	return 0;
33 }
34 
35 static int rockchip_otp_ecc_enable(struct rockchip_otp_platdata *otp,
36 				   bool enable)
37 {
38 	int ret = 0;
39 
40 	writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
41 	       otp->base + OTPC_SBPI_CTRL);
42 
43 	writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
44 	writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
45 	       otp->base + OTPC_SBPI_CMD0_OFFSET);
46 	if (enable)
47 		writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
48 	else
49 		writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
50 
51 	writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
52 
53 	ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE);
54 	if (ret < 0)
55 		printf("%s timeout during ecc_enable\n", __func__);
56 
57 	return ret;
58 }
59 
60 static int rockchip_px30_otp_read(struct udevice *dev, int offset,
61 				  void *buf, int size)
62 {
63 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
64 	u8 *buffer = buf;
65 	int ret = 0;
66 
67 	ret = rockchip_otp_ecc_enable(otp, false);
68 	if (ret < 0) {
69 		printf("%s rockchip_otp_ecc_enable err\n", __func__);
70 		return ret;
71 	}
72 
73 	writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
74 	udelay(5);
75 	while (size--) {
76 		writel(offset++ | OTPC_USER_ADDR_MASK,
77 		       otp->base + OTPC_USER_ADDR);
78 		writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
79 		       otp->base + OTPC_USER_ENABLE);
80 		ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
81 		if (ret < 0) {
82 			printf("%s timeout during read setup\n", __func__);
83 			goto read_end;
84 		}
85 		*buffer++ = readb(otp->base + OTPC_USER_Q);
86 	}
87 
88 read_end:
89 	writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
90 
91 	return ret;
92 }
93 
94 static int rockchip_otp_read(struct udevice *dev, int offset,
95 			     void *buf, int size)
96 {
97 	OTP_READ otp_read = NULL;
98 
99 	otp_read = (OTP_READ)dev_get_driver_data(dev);
100 	if (!otp_read)
101 		return -ENOSYS;
102 
103 	return (*otp_read)(dev, offset, buf, size);
104 }
105 
106 static const struct misc_ops rockchip_otp_ops = {
107 	.read = rockchip_otp_read,
108 };
109 
110 static int rockchip_otp_ofdata_to_platdata(struct udevice *dev)
111 {
112 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
113 
114 	otp->base = dev_read_addr_ptr(dev);
115 
116 	return 0;
117 }
118 
119 static const struct udevice_id rockchip_otp_ids[] = {
120 	{
121 		.compatible = "rockchip,px30-otp",
122 		.data = (ulong)&rockchip_px30_otp_read,
123 	},
124 	{
125 		.compatible = "rockchip,rk3308-otp",
126 		.data = (ulong)&rockchip_px30_otp_read,
127 	},
128 	{}
129 };
130 
131 U_BOOT_DRIVER(rockchip_otp) = {
132 	.name = "rockchip_otp",
133 	.id = UCLASS_MISC,
134 	.of_match = rockchip_otp_ids,
135 	.ops = &rockchip_otp_ops,
136 	.ofdata_to_platdata = rockchip_otp_ofdata_to_platdata,
137 	.platdata_auto_alloc_size = sizeof(struct rockchip_otp_platdata),
138 };
139