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 <display_options.h>
10 #include <dm.h>
11 #include <linux/bitops.h>
12 #include <linux/delay.h>
13 #include <linux/iopoll.h>
14 #include <malloc.h>
15 #include <misc.h>
16 
17 /* OTP Register Offsets */
18 #define OTPC_SBPI_CTRL			0x0020
19 #define OTPC_SBPI_CMD_VALID_PRE		0x0024
20 #define OTPC_SBPI_CS_VALID_PRE		0x0028
21 #define OTPC_SBPI_STATUS		0x002C
22 #define OTPC_USER_CTRL			0x0100
23 #define OTPC_USER_ADDR			0x0104
24 #define OTPC_USER_ENABLE		0x0108
25 #define OTPC_USER_QP			0x0120
26 #define OTPC_USER_Q			0x0124
27 #define OTPC_INT_STATUS			0x0304
28 #define OTPC_SBPI_CMD0_OFFSET		0x1000
29 #define OTPC_SBPI_CMD1_OFFSET		0x1004
30 
31 /* OTP Register bits and masks */
32 #define OTPC_USER_ADDR_MASK		GENMASK(31, 16)
33 #define OTPC_USE_USER			BIT(0)
34 #define OTPC_USE_USER_MASK		GENMASK(16, 16)
35 #define OTPC_USER_FSM_ENABLE		BIT(0)
36 #define OTPC_USER_FSM_ENABLE_MASK	GENMASK(16, 16)
37 #define OTPC_SBPI_DONE			BIT(1)
38 #define OTPC_USER_DONE			BIT(2)
39 
40 #define SBPI_DAP_ADDR			0x02
41 #define SBPI_DAP_ADDR_SHIFT		8
42 #define SBPI_DAP_ADDR_MASK		GENMASK(31, 24)
43 #define SBPI_CMD_VALID_MASK		GENMASK(31, 16)
44 #define SBPI_DAP_CMD_WRF		0xC0
45 #define SBPI_DAP_REG_ECC		0x3A
46 #define SBPI_ECC_ENABLE			0x00
47 #define SBPI_ECC_DISABLE		0x09
48 #define SBPI_ENABLE			BIT(0)
49 #define SBPI_ENABLE_MASK		GENMASK(16, 16)
50 
51 #define OTPC_TIMEOUT			10000
52 
53 #define RK3588_OTPC_AUTO_CTRL		0x0004
54 #define RK3588_ADDR_SHIFT		16
55 #define RK3588_ADDR(n)			((n) << RK3588_ADDR_SHIFT)
56 #define RK3588_BURST_SHIFT		8
57 #define RK3588_BURST(n)			((n) << RK3588_BURST_SHIFT)
58 #define RK3588_OTPC_AUTO_EN		0x0008
59 #define RK3588_AUTO_EN			BIT(0)
60 #define RK3588_OTPC_DOUT0		0x0020
61 #define RK3588_OTPC_INT_ST		0x0084
62 #define RK3588_RD_DONE			BIT(1)
63 
64 struct rockchip_otp_plat {
65 	void __iomem *base;
66 };
67 
68 struct rockchip_otp_data {
69 	int (*read)(struct udevice *dev, int offset, void *buf, int size);
70 	int offset;
71 	int size;
72 	int block_size;
73 };
74 
75 #if defined(DEBUG)
dump_otp(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])76 static int dump_otp(struct cmd_tbl *cmdtp, int flag,
77 		    int argc, char *const argv[])
78 {
79 	struct udevice *dev;
80 	u8 data[4];
81 	int ret, i;
82 
83 	ret = uclass_get_device_by_driver(UCLASS_MISC,
84 					  DM_DRIVER_GET(rockchip_otp), &dev);
85 	if (ret) {
86 		printf("%s: no misc-device found\n", __func__);
87 		return 0;
88 	}
89 
90 	for (i = 0; true; i += sizeof(data)) {
91 		ret = misc_read(dev, i, &data, sizeof(data));
92 		if (ret <= 0)
93 			return 0;
94 
95 		print_buffer(i, data, 1, sizeof(data), sizeof(data));
96 	}
97 
98 	return 0;
99 }
100 
101 U_BOOT_CMD(
102 	dump_otp, 1, 1, dump_otp,
103 	"Dump the content of the otp",
104 	""
105 );
106 #endif
107 
rockchip_otp_poll_timeout(struct rockchip_otp_plat * otp,u32 flag,u32 reg)108 static int rockchip_otp_poll_timeout(struct rockchip_otp_plat *otp,
109 				     u32 flag, u32 reg)
110 {
111 	u32 status;
112 	int ret;
113 
114 	ret = readl_poll_sleep_timeout(otp->base + reg, status,
115 				       (status & flag), 1, OTPC_TIMEOUT);
116 	if (ret)
117 		return ret;
118 
119 	/* Clear int flag */
120 	writel(flag, otp->base + reg);
121 
122 	return 0;
123 }
124 
rockchip_otp_ecc_enable(struct rockchip_otp_plat * otp,bool enable)125 static int rockchip_otp_ecc_enable(struct rockchip_otp_plat *otp, bool enable)
126 {
127 	writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
128 	       otp->base + OTPC_SBPI_CTRL);
129 
130 	writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
131 	writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
132 	       otp->base + OTPC_SBPI_CMD0_OFFSET);
133 
134 	if (enable)
135 		writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
136 	else
137 		writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
138 
139 	writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
140 
141 	return rockchip_otp_poll_timeout(otp, OTPC_SBPI_DONE, OTPC_INT_STATUS);
142 }
143 
rockchip_px30_otp_read(struct udevice * dev,int offset,void * buf,int size)144 static int rockchip_px30_otp_read(struct udevice *dev, int offset,
145 				  void *buf, int size)
146 {
147 	struct rockchip_otp_plat *otp = dev_get_plat(dev);
148 	u8 *buffer = buf;
149 	int ret;
150 
151 	ret = rockchip_otp_ecc_enable(otp, false);
152 	if (ret)
153 		return ret;
154 
155 	writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
156 	udelay(5);
157 
158 	while (size--) {
159 		writel(offset++ | OTPC_USER_ADDR_MASK,
160 		       otp->base + OTPC_USER_ADDR);
161 		writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
162 		       otp->base + OTPC_USER_ENABLE);
163 
164 		ret = rockchip_otp_poll_timeout(otp, OTPC_USER_DONE,
165 						OTPC_INT_STATUS);
166 		if (ret)
167 			goto read_end;
168 
169 		*buffer++ = (u8)(readl(otp->base + OTPC_USER_Q) & 0xFF);
170 	}
171 
172 read_end:
173 	writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
174 
175 	return ret;
176 }
177 
rockchip_rk3568_otp_read(struct udevice * dev,int offset,void * buf,int size)178 static int rockchip_rk3568_otp_read(struct udevice *dev, int offset,
179 				    void *buf, int size)
180 {
181 	struct rockchip_otp_plat *otp = dev_get_plat(dev);
182 	u16 *buffer = buf;
183 	int ret;
184 
185 	ret = rockchip_otp_ecc_enable(otp, false);
186 	if (ret)
187 		return ret;
188 
189 	writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
190 	udelay(5);
191 
192 	while (size--) {
193 		writel(offset++ | OTPC_USER_ADDR_MASK,
194 		       otp->base + OTPC_USER_ADDR);
195 		writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
196 		       otp->base + OTPC_USER_ENABLE);
197 
198 		ret = rockchip_otp_poll_timeout(otp, OTPC_USER_DONE,
199 						OTPC_INT_STATUS);
200 		if (ret)
201 			goto read_end;
202 
203 		*buffer++ = (u16)(readl(otp->base + OTPC_USER_Q) & 0xFFFF);
204 	}
205 
206 read_end:
207 	writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
208 
209 	return ret;
210 }
211 
rockchip_rk3588_otp_read(struct udevice * dev,int offset,void * buf,int size)212 static int rockchip_rk3588_otp_read(struct udevice *dev, int offset,
213 				    void *buf, int size)
214 {
215 	struct rockchip_otp_plat *otp = dev_get_plat(dev);
216 	u32 *buffer = buf;
217 	int ret;
218 
219 	while (size--) {
220 		writel(RK3588_ADDR(offset++) | RK3588_BURST(1),
221 		       otp->base + RK3588_OTPC_AUTO_CTRL);
222 		writel(RK3588_AUTO_EN, otp->base + RK3588_OTPC_AUTO_EN);
223 
224 		ret = rockchip_otp_poll_timeout(otp, RK3588_RD_DONE,
225 						RK3588_OTPC_INT_ST);
226 		if (ret)
227 			return ret;
228 
229 		*buffer++ = readl(otp->base + RK3588_OTPC_DOUT0);
230 	}
231 
232 	return 0;
233 }
234 
rockchip_otp_read(struct udevice * dev,int offset,void * buf,int size)235 static int rockchip_otp_read(struct udevice *dev, int offset,
236 			     void *buf, int size)
237 {
238 	const struct rockchip_otp_data *data =
239 		(void *)dev_get_driver_data(dev);
240 	u32 block_start, block_end, block_offset, blocks;
241 	u8 *buffer;
242 	int ret;
243 
244 	if (offset < 0 || !buf || size <= 0 || offset + size > data->size)
245 		return -EINVAL;
246 
247 	if (!data->read)
248 		return -ENOSYS;
249 
250 	offset += data->offset;
251 
252 	if (data->block_size <= 1) {
253 		ret = data->read(dev, offset, buf, size);
254 		goto done;
255 	}
256 
257 	block_start = offset / data->block_size;
258 	block_offset = offset % data->block_size;
259 	block_end = DIV_ROUND_UP(offset + size, data->block_size);
260 	blocks = block_end - block_start;
261 
262 	buffer = calloc(blocks, data->block_size);
263 	if (!buffer)
264 		return -ENOMEM;
265 
266 	ret = data->read(dev, block_start, buffer, blocks);
267 	if (!ret)
268 		memcpy(buf, buffer + block_offset, size);
269 
270 	free(buffer);
271 
272 done:
273 	return ret < 0 ? ret : size;
274 }
275 
276 static const struct misc_ops rockchip_otp_ops = {
277 	.read = rockchip_otp_read,
278 };
279 
rockchip_otp_of_to_plat(struct udevice * dev)280 static int rockchip_otp_of_to_plat(struct udevice *dev)
281 {
282 	struct rockchip_otp_plat *plat = dev_get_plat(dev);
283 
284 	plat->base = dev_read_addr_ptr(dev);
285 
286 	return 0;
287 }
288 
289 static const struct rockchip_otp_data px30_data = {
290 	.read = rockchip_px30_otp_read,
291 	.size = 0x40,
292 };
293 
294 static const struct rockchip_otp_data rk3568_data = {
295 	.read = rockchip_rk3568_otp_read,
296 	.size = 0x80,
297 	.block_size = 2,
298 };
299 
300 static const struct rockchip_otp_data rk3588_data = {
301 	.read = rockchip_rk3588_otp_read,
302 	.offset = 0xC00,
303 	.size = 0x400,
304 	.block_size = 4,
305 };
306 
307 static const struct udevice_id rockchip_otp_ids[] = {
308 	{
309 		.compatible = "rockchip,px30-otp",
310 		.data = (ulong)&px30_data,
311 	},
312 	{
313 		.compatible = "rockchip,rk3308-otp",
314 		.data = (ulong)&px30_data,
315 	},
316 	{
317 		.compatible = "rockchip,rk3568-otp",
318 		.data = (ulong)&rk3568_data,
319 	},
320 	{
321 		.compatible = "rockchip,rk3588-otp",
322 		.data = (ulong)&rk3588_data,
323 	},
324 	{}
325 };
326 
327 U_BOOT_DRIVER(rockchip_otp) = {
328 	.name = "rockchip_otp",
329 	.id = UCLASS_MISC,
330 	.of_match = rockchip_otp_ids,
331 	.of_to_plat = rockchip_otp_of_to_plat,
332 	.plat_auto = sizeof(struct rockchip_otp_plat),
333 	.ops = &rockchip_otp_ops,
334 };
335