xref: /rk3399_rockchip-uboot/drivers/misc/rockchip-otp.c (revision 548715c7d5ed761875cc95bcb03b9b4519687db6)
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 <linux/iopoll.h>
13 #include <misc.h>
14 #include <rockchip-otp.h>
15 
16 struct otp_data {
17 	int (*init)(struct udevice *dev);
18 	int (*read)(struct udevice *dev, int offset, void *buf, int size);
19 };
20 
21 static int rockchip_otp_wait_status(struct rockchip_otp_platdata *otp,
22 				    u32 flag)
23 {
24 	int delay = OTPC_TIMEOUT;
25 
26 	while (!(readl(otp->base + OTPC_INT_STATUS) & flag)) {
27 		udelay(1);
28 		delay--;
29 		if (delay <= 0) {
30 			printf("%s: wait init status timeout\n", __func__);
31 			return -ETIMEDOUT;
32 		}
33 	}
34 
35 	/* clean int status */
36 	writel(flag, otp->base + OTPC_INT_STATUS);
37 
38 	return 0;
39 }
40 
41 static int rockchip_otp_ecc_enable(struct rockchip_otp_platdata *otp,
42 				   bool enable)
43 {
44 	int ret = 0;
45 
46 	writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
47 	       otp->base + OTPC_SBPI_CTRL);
48 
49 	writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
50 	writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
51 	       otp->base + OTPC_SBPI_CMD0_OFFSET);
52 	if (enable)
53 		writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
54 	else
55 		writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
56 
57 	writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
58 
59 	ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE);
60 	if (ret < 0)
61 		printf("%s timeout during ecc_enable\n", __func__);
62 
63 	return ret;
64 }
65 
66 static int rockchip_px30_otp_read(struct udevice *dev, int offset,
67 				  void *buf, int size)
68 {
69 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
70 	u8 *buffer = buf;
71 	int ret = 0;
72 
73 	ret = rockchip_otp_ecc_enable(otp, false);
74 	if (ret < 0) {
75 		printf("%s rockchip_otp_ecc_enable err\n", __func__);
76 		return ret;
77 	}
78 
79 	writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
80 	udelay(5);
81 	while (size--) {
82 		writel(offset++ | OTPC_USER_ADDR_MASK,
83 		       otp->base + OTPC_USER_ADDR);
84 		writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
85 		       otp->base + OTPC_USER_ENABLE);
86 		ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
87 		if (ret < 0) {
88 			printf("%s timeout during read setup\n", __func__);
89 			goto read_end;
90 		}
91 		*buffer++ = readb(otp->base + OTPC_USER_Q);
92 	}
93 
94 read_end:
95 	writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
96 
97 	return ret;
98 }
99 
100 static int rockchip_rk3568_otp_read(struct udevice *dev, int offset, void *buf,
101 				    int size)
102 {
103 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
104 	unsigned int addr_start, addr_end, addr_offset, addr_len;
105 	u32 out_value;
106 	u8 *buffer;
107 	int ret = 0, i = 0;
108 
109 	addr_start = rounddown(offset, RK3568_NBYTES) / RK3568_NBYTES;
110 	addr_end = roundup(offset + size, RK3568_NBYTES) / RK3568_NBYTES;
111 	addr_offset = offset % RK3568_NBYTES;
112 	addr_len = addr_end - addr_start;
113 
114 	buffer = calloc(1, sizeof(*buffer) * addr_len * RK3568_NBYTES);
115 	if (!buffer)
116 		return -ENOMEM;
117 
118 	ret = rockchip_otp_ecc_enable(otp, false);
119 	if (ret < 0) {
120 		printf("%s rockchip_otp_ecc_enable err\n", __func__);
121 		return ret;
122 	}
123 
124 	writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
125 	udelay(5);
126 	while (addr_len--) {
127 		writel(addr_start++ | OTPC_USER_ADDR_MASK,
128 		       otp->base + OTPC_USER_ADDR);
129 		writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
130 		       otp->base + OTPC_USER_ENABLE);
131 		ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
132 		if (ret < 0) {
133 			printf("%s timeout during read setup\n", __func__);
134 			goto read_end;
135 		}
136 		out_value = readl(otp->base + OTPC_USER_Q);
137 		memcpy(&buffer[i], &out_value, RK3568_NBYTES);
138 		i += RK3568_NBYTES;
139 	}
140 
141 	memcpy(buf, buffer + addr_offset, size);
142 
143 read_end:
144 	writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
145 
146 	kfree(buffer);
147 
148 	return ret;
149 }
150 
151 static int rockchip_rv1126_otp_init(struct udevice *dev)
152 {
153 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
154 	u32 status = 0;
155 	int ret;
156 
157 	writel(0x0, otp->base + RV1126_OTP_NVM_CEB);
158 	ret = readl_poll_timeout(otp->base + RV1126_OTP_NVM_ST, status,
159 				 status & 0x1, OTPC_TIMEOUT);
160 	if (ret < 0) {
161 		printf("%s timeout during set ceb\n", __func__);
162 		return ret;
163 	}
164 
165 	writel(0x1, otp->base + RV1126_OTP_NVM_RSTB);
166 	ret = readl_poll_timeout(otp->base + RV1126_OTP_NVM_ST, status,
167 				 status & 0x4, OTPC_TIMEOUT);
168 	if (ret < 0) {
169 		printf("%s timeout during set rstb\n", __func__);
170 		return ret;
171 	}
172 
173 	return 0;
174 }
175 
176 static int rockchip_rv1126_otp_read(struct udevice *dev, int offset, void *buf,
177 				    int size)
178 {
179 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
180 	u32 status = 0;
181 	u8 *buffer = buf;
182 	int ret = 0;
183 
184 	while (size--) {
185 		writel(offset++, otp->base + RV1126_OTP_NVM_RADDR);
186 		writel(0x1, otp->base + RV1126_OTP_NVM_RSTART);
187 		ret = readl_poll_timeout(otp->base + RV1126_OTP_READ_ST,
188 					 status, status == 0, OTPC_TIMEOUT);
189 		if (ret < 0) {
190 			printf("%s timeout during read setup\n", __func__);
191 			return ret;
192 		}
193 
194 		*buffer++ = readb(otp->base + RV1126_OTP_NVM_RDATA);
195 	}
196 
197 	return 0;
198 }
199 
200 static int rockchip_otp_read(struct udevice *dev, int offset,
201 			     void *buf, int size)
202 {
203 	struct otp_data *data;
204 
205 	data = (struct otp_data *)dev_get_driver_data(dev);
206 	if (!data)
207 		return -ENOSYS;
208 
209 	return data->read(dev, offset, buf, size);
210 }
211 
212 static const struct misc_ops rockchip_otp_ops = {
213 	.read = rockchip_otp_read,
214 };
215 
216 static int rockchip_otp_ofdata_to_platdata(struct udevice *dev)
217 {
218 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
219 
220 	otp->base = dev_read_addr_ptr(dev);
221 
222 	return 0;
223 }
224 
225 static int rockchip_otp_probe(struct udevice *dev)
226 {
227 	struct otp_data *data;
228 
229 	data = (struct otp_data *)dev_get_driver_data(dev);
230 	if (!data)
231 		return -EINVAL;
232 
233 	if (data->init)
234 		return data->init(dev);
235 
236 	return 0;
237 }
238 
239 static const struct otp_data px30_data = {
240 	.read = rockchip_px30_otp_read,
241 };
242 
243 static const struct otp_data rk3568_data = {
244 	.read = rockchip_rk3568_otp_read,
245 };
246 
247 static const struct otp_data rv1126_data = {
248 	.init = rockchip_rv1126_otp_init,
249 	.read = rockchip_rv1126_otp_read,
250 };
251 
252 static const struct udevice_id rockchip_otp_ids[] = {
253 	{
254 		.compatible = "rockchip,px30-otp",
255 		.data = (ulong)&px30_data,
256 	},
257 	{
258 		.compatible = "rockchip,rk3308-otp",
259 		.data = (ulong)&px30_data,
260 	},
261 	{
262 		.compatible = "rockchip,rk3568-otp",
263 		.data = (ulong)&rk3568_data,
264 	},
265 	{
266 		.compatible = "rockchip,rv1126-otp",
267 		.data = (ulong)&rv1126_data,
268 	},
269 	{}
270 };
271 
272 U_BOOT_DRIVER(rockchip_otp) = {
273 	.name = "rockchip_otp",
274 	.id = UCLASS_MISC,
275 	.of_match = rockchip_otp_ids,
276 	.ops = &rockchip_otp_ops,
277 	.ofdata_to_platdata = rockchip_otp_ofdata_to_platdata,
278 	.platdata_auto_alloc_size = sizeof(struct rockchip_otp_platdata),
279 	.probe = rockchip_otp_probe,
280 };
281