xref: /rk3399_rockchip-uboot/drivers/misc/rockchip-otp.c (revision 052b7b0702f35f829079f4bb76581d8da55ff32f)
14973d825SFinley Xiao // SPDX-License-Identifier: GPL-2.0
24973d825SFinley Xiao /*
34973d825SFinley Xiao  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
44973d825SFinley Xiao  */
54973d825SFinley Xiao 
64973d825SFinley Xiao #include <common.h>
79fed581aSFinley Xiao #include <asm/arch/cpu.h>
84973d825SFinley Xiao #include <asm/io.h>
94973d825SFinley Xiao #include <command.h>
104973d825SFinley Xiao #include <dm.h>
114973d825SFinley Xiao #include <linux/bitops.h>
124973d825SFinley Xiao #include <linux/delay.h>
13a4c57e8aSFinley Xiao #include <linux/iopoll.h>
144973d825SFinley Xiao #include <misc.h>
156e12c1ddSJason Zhu #include <rockchip-otp.h>
164973d825SFinley Xiao 
17a4c57e8aSFinley Xiao struct otp_data {
18dd270bd4SXuhui Lin 	int size;
19dd270bd4SXuhui Lin 	int ns_offset;
20a4c57e8aSFinley Xiao 	int (*init)(struct udevice *dev);
21a4c57e8aSFinley Xiao 	int (*read)(struct udevice *dev, int offset, void *buf, int size);
22a4c57e8aSFinley Xiao };
23a4c57e8aSFinley Xiao 
rockchip_otp_wait_status(struct rockchip_otp_platdata * otp,u32 flag)244973d825SFinley Xiao static int rockchip_otp_wait_status(struct rockchip_otp_platdata *otp,
254973d825SFinley Xiao 				    u32 flag)
264973d825SFinley Xiao {
274973d825SFinley Xiao 	int delay = OTPC_TIMEOUT;
284973d825SFinley Xiao 
294973d825SFinley Xiao 	while (!(readl(otp->base + OTPC_INT_STATUS) & flag)) {
304973d825SFinley Xiao 		udelay(1);
314973d825SFinley Xiao 		delay--;
324973d825SFinley Xiao 		if (delay <= 0) {
334973d825SFinley Xiao 			printf("%s: wait init status timeout\n", __func__);
344973d825SFinley Xiao 			return -ETIMEDOUT;
354973d825SFinley Xiao 		}
364973d825SFinley Xiao 	}
374973d825SFinley Xiao 
384973d825SFinley Xiao 	/* clean int status */
394973d825SFinley Xiao 	writel(flag, otp->base + OTPC_INT_STATUS);
404973d825SFinley Xiao 
414973d825SFinley Xiao 	return 0;
424973d825SFinley Xiao }
434973d825SFinley Xiao 
rockchip_otp_ecc_enable(struct rockchip_otp_platdata * otp,bool enable)444973d825SFinley Xiao static int rockchip_otp_ecc_enable(struct rockchip_otp_platdata *otp,
454973d825SFinley Xiao 				   bool enable)
464973d825SFinley Xiao {
474973d825SFinley Xiao 	int ret = 0;
484973d825SFinley Xiao 
494973d825SFinley Xiao 	writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
504973d825SFinley Xiao 	       otp->base + OTPC_SBPI_CTRL);
514973d825SFinley Xiao 
524973d825SFinley Xiao 	writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
534973d825SFinley Xiao 	writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
544973d825SFinley Xiao 	       otp->base + OTPC_SBPI_CMD0_OFFSET);
554973d825SFinley Xiao 	if (enable)
564973d825SFinley Xiao 		writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
574973d825SFinley Xiao 	else
584973d825SFinley Xiao 		writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
594973d825SFinley Xiao 
604973d825SFinley Xiao 	writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
614973d825SFinley Xiao 
624973d825SFinley Xiao 	ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE);
634973d825SFinley Xiao 	if (ret < 0)
644973d825SFinley Xiao 		printf("%s timeout during ecc_enable\n", __func__);
654973d825SFinley Xiao 
664973d825SFinley Xiao 	return ret;
674973d825SFinley Xiao }
684973d825SFinley Xiao 
rockchip_px30_otp_read(struct udevice * dev,int offset,void * buf,int size)694973d825SFinley Xiao static int rockchip_px30_otp_read(struct udevice *dev, int offset,
704973d825SFinley Xiao 				  void *buf, int size)
714973d825SFinley Xiao {
724973d825SFinley Xiao 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
734973d825SFinley Xiao 	u8 *buffer = buf;
744973d825SFinley Xiao 	int ret = 0;
754973d825SFinley Xiao 
764973d825SFinley Xiao 	ret = rockchip_otp_ecc_enable(otp, false);
774973d825SFinley Xiao 	if (ret < 0) {
784973d825SFinley Xiao 		printf("%s rockchip_otp_ecc_enable err\n", __func__);
794973d825SFinley Xiao 		return ret;
804973d825SFinley Xiao 	}
814973d825SFinley Xiao 
824973d825SFinley Xiao 	writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
834973d825SFinley Xiao 	udelay(5);
844973d825SFinley Xiao 	while (size--) {
854973d825SFinley Xiao 		writel(offset++ | OTPC_USER_ADDR_MASK,
864973d825SFinley Xiao 		       otp->base + OTPC_USER_ADDR);
874973d825SFinley Xiao 		writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
884973d825SFinley Xiao 		       otp->base + OTPC_USER_ENABLE);
894973d825SFinley Xiao 		ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
904973d825SFinley Xiao 		if (ret < 0) {
914973d825SFinley Xiao 			printf("%s timeout during read setup\n", __func__);
924973d825SFinley Xiao 			goto read_end;
934973d825SFinley Xiao 		}
944973d825SFinley Xiao 		*buffer++ = readb(otp->base + OTPC_USER_Q);
954973d825SFinley Xiao 	}
964973d825SFinley Xiao 
974973d825SFinley Xiao read_end:
984973d825SFinley Xiao 	writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
994973d825SFinley Xiao 
1004973d825SFinley Xiao 	return ret;
1014973d825SFinley Xiao }
1024973d825SFinley Xiao 
rk3308bs_otp_wait_status(struct rockchip_otp_platdata * otp,u32 flag)1039fed581aSFinley Xiao static int rk3308bs_otp_wait_status(struct rockchip_otp_platdata *otp, u32 flag)
1049fed581aSFinley Xiao {
1059fed581aSFinley Xiao 	int delay = OTPC_TIMEOUT;
1069fed581aSFinley Xiao 
1079fed581aSFinley Xiao 	while (!(readl(otp->base + OTPC_IRQ_ST) & flag)) {
1089fed581aSFinley Xiao 		udelay(1);
1099fed581aSFinley Xiao 		delay--;
1109fed581aSFinley Xiao 		if (delay <= 0) {
1119fed581aSFinley Xiao 			printf("%s: wait init status timeout\n", __func__);
1129fed581aSFinley Xiao 			return -ETIMEDOUT;
1139fed581aSFinley Xiao 		}
1149fed581aSFinley Xiao 	}
1159fed581aSFinley Xiao 
1169fed581aSFinley Xiao 	/* clean int status */
1179fed581aSFinley Xiao 	writel(flag, otp->base + OTPC_IRQ_ST);
1189fed581aSFinley Xiao 
1199fed581aSFinley Xiao 	return 0;
1209fed581aSFinley Xiao }
1219fed581aSFinley Xiao 
rk3308bs_otp_active(struct rockchip_otp_platdata * otp)1229fed581aSFinley Xiao static int rk3308bs_otp_active(struct rockchip_otp_platdata *otp)
1239fed581aSFinley Xiao {
1249fed581aSFinley Xiao 	int ret = 0;
1259fed581aSFinley Xiao 	u32 mode;
1269fed581aSFinley Xiao 
1279fed581aSFinley Xiao 	mode = readl(otp->base + OTPC_MODE_CTRL);
1289fed581aSFinley Xiao 
1299fed581aSFinley Xiao 	switch (mode) {
1309fed581aSFinley Xiao 	case OTPC_DEEP_STANDBY:
1319fed581aSFinley Xiao 		writel(OTPC_STANDBY, otp->base + OTPC_MODE_CTRL);
1329fed581aSFinley Xiao 		ret = rk3308bs_otp_wait_status(otp, OTPC_DP2STB_IRQ_ST);
1339fed581aSFinley Xiao 		if (ret < 0) {
1349fed581aSFinley Xiao 			dev_err(otp->dev, "timeout during wait dp2stb\n");
1359fed581aSFinley Xiao 			return ret;
1369fed581aSFinley Xiao 		}
1379fed581aSFinley Xiao 	case OTPC_STANDBY:
1389fed581aSFinley Xiao 		writel(OTPC_ACTIVE, otp->base + OTPC_MODE_CTRL);
1399fed581aSFinley Xiao 		ret = rk3308bs_otp_wait_status(otp, OTPC_STB2ACT_IRQ_ST);
1409fed581aSFinley Xiao 		if (ret < 0) {
1419fed581aSFinley Xiao 			dev_err(otp->dev, "timeout during wait stb2act\n");
1429fed581aSFinley Xiao 			return ret;
1439fed581aSFinley Xiao 		}
1449fed581aSFinley Xiao 		break;
1459fed581aSFinley Xiao 	default:
1469fed581aSFinley Xiao 		break;
1479fed581aSFinley Xiao 	}
1489fed581aSFinley Xiao 
1499fed581aSFinley Xiao 	return ret;
1509fed581aSFinley Xiao }
1519fed581aSFinley Xiao 
rk3308bs_otp_standby(struct rockchip_otp_platdata * otp)1529fed581aSFinley Xiao static int rk3308bs_otp_standby(struct rockchip_otp_platdata *otp)
1539fed581aSFinley Xiao {
1549fed581aSFinley Xiao 	int ret = 0;
1559fed581aSFinley Xiao 	u32 mode;
1569fed581aSFinley Xiao 
1579fed581aSFinley Xiao 	mode = readl(otp->base + OTPC_MODE_CTRL);
1589fed581aSFinley Xiao 
1599fed581aSFinley Xiao 	switch (mode) {
1609fed581aSFinley Xiao 	case OTPC_ACTIVE:
1619fed581aSFinley Xiao 		writel(OTPC_STANDBY, otp->base + OTPC_MODE_CTRL);
1629fed581aSFinley Xiao 		ret = rk3308bs_otp_wait_status(otp, OTPC_ACT2STB_IRQ_ST);
1639fed581aSFinley Xiao 		if (ret < 0) {
1649fed581aSFinley Xiao 			dev_err(otp->dev, "timeout during wait act2stb\n");
1659fed581aSFinley Xiao 			return ret;
1669fed581aSFinley Xiao 		}
1679fed581aSFinley Xiao 	case OTPC_STANDBY:
1689fed581aSFinley Xiao 		writel(OTPC_DEEP_STANDBY, otp->base + OTPC_MODE_CTRL);
1699fed581aSFinley Xiao 		ret = rk3308bs_otp_wait_status(otp, OTPC_STB2DP_IRQ_ST);
1709fed581aSFinley Xiao 		if (ret < 0) {
1719fed581aSFinley Xiao 			dev_err(otp->dev, "timeout during wait stb2dp\n");
1729fed581aSFinley Xiao 			return ret;
1739fed581aSFinley Xiao 		}
1749fed581aSFinley Xiao 		break;
1759fed581aSFinley Xiao 	default:
1769fed581aSFinley Xiao 		break;
1779fed581aSFinley Xiao 	}
1789fed581aSFinley Xiao 
1799fed581aSFinley Xiao 	return ret;
1809fed581aSFinley Xiao }
1819fed581aSFinley Xiao 
rockchip_rk3308bs_otp_read(struct udevice * dev,int offset,void * buf,int size)1829fed581aSFinley Xiao static int rockchip_rk3308bs_otp_read(struct udevice *dev, int offset,
1839fed581aSFinley Xiao 				      void *buf, int size)
1849fed581aSFinley Xiao {
1859fed581aSFinley Xiao 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
1869fed581aSFinley Xiao 	unsigned int addr_start, addr_end, addr_offset, addr_len;
1879fed581aSFinley Xiao 	u32 out_value;
1889fed581aSFinley Xiao 	u8 *buffer;
1899fed581aSFinley Xiao 	int ret = 0, i = 0;
1909fed581aSFinley Xiao 
1919fed581aSFinley Xiao 	if (offset > RK3308BS_MAX_BYTES - 1)
1929fed581aSFinley Xiao 		return -ENOMEM;
1939fed581aSFinley Xiao 	if (offset + size > RK3308BS_MAX_BYTES)
1949fed581aSFinley Xiao 		size = RK3308BS_MAX_BYTES - offset;
1959fed581aSFinley Xiao 
1969fed581aSFinley Xiao 	ret = rk3308bs_otp_active(otp);
1979fed581aSFinley Xiao 	if (ret)
1989fed581aSFinley Xiao 		goto out;
1999fed581aSFinley Xiao 
2009fed581aSFinley Xiao 	addr_start = rounddown(offset, RK3308BS_NBYTES) / RK3308BS_NBYTES;
2019fed581aSFinley Xiao 	addr_end = roundup(offset + size, RK3308BS_NBYTES) / RK3308BS_NBYTES;
2029fed581aSFinley Xiao 	addr_offset = offset % RK3308BS_NBYTES;
2039fed581aSFinley Xiao 	addr_len = addr_end - addr_start;
2049fed581aSFinley Xiao 
2059fed581aSFinley Xiao 	buffer = calloc(1, sizeof(*buffer) * addr_len * RK3308BS_NBYTES);
2069fed581aSFinley Xiao 	if (!buffer) {
2079fed581aSFinley Xiao 		ret = -ENOMEM;
2089fed581aSFinley Xiao 		goto read_end;
2099fed581aSFinley Xiao 	}
2109fed581aSFinley Xiao 
2119fed581aSFinley Xiao 	while (addr_len--) {
2129fed581aSFinley Xiao 		writel(OTPC_TRANS_NUM, otp->base + OTPC_REPR_RD_TRANS_NUM);
2139fed581aSFinley Xiao 		writel(addr_start++, otp->base + OTPC_ACCESS_ADDR);
2149fed581aSFinley Xiao 		writel(OTPC_READ_ACCESS, otp->base + OTPC_MODE_CTRL);
2159fed581aSFinley Xiao 		ret = rk3308bs_otp_wait_status(otp, OTPC_RDM_IRQ_ST);
2169fed581aSFinley Xiao 		if (ret < 0) {
2179fed581aSFinley Xiao 			printf("timeout during wait rd\n");
2189fed581aSFinley Xiao 			goto read_end;
2199fed581aSFinley Xiao 		}
2209fed581aSFinley Xiao 		out_value = readl(otp->base + OTPC_RD_DATA);
2219fed581aSFinley Xiao 		memcpy(&buffer[i], &out_value, RK3308BS_NBYTES);
2229fed581aSFinley Xiao 		i += RK3308BS_NBYTES;
2239fed581aSFinley Xiao 	}
2249fed581aSFinley Xiao 	memcpy(buf, buffer + addr_offset, size);
2259fed581aSFinley Xiao 
2269fed581aSFinley Xiao read_end:
2279fed581aSFinley Xiao 	kfree(buffer);
2289fed581aSFinley Xiao 	rk3308bs_otp_standby(otp);
2299fed581aSFinley Xiao out:
2309fed581aSFinley Xiao 	return ret;
2319fed581aSFinley Xiao }
2329fed581aSFinley Xiao 
rockchip_rk3568_otp_read(struct udevice * dev,int offset,void * buf,int size)233fd7b5182SFinley Xiao static int rockchip_rk3568_otp_read(struct udevice *dev, int offset, void *buf,
234fd7b5182SFinley Xiao 				    int size)
235fd7b5182SFinley Xiao {
236fd7b5182SFinley Xiao 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
237fd7b5182SFinley Xiao 	unsigned int addr_start, addr_end, addr_offset, addr_len;
238fd7b5182SFinley Xiao 	u32 out_value;
239fd7b5182SFinley Xiao 	u8 *buffer;
240fd7b5182SFinley Xiao 	int ret = 0, i = 0;
241fd7b5182SFinley Xiao 
242fd7b5182SFinley Xiao 	addr_start = rounddown(offset, RK3568_NBYTES) / RK3568_NBYTES;
243fd7b5182SFinley Xiao 	addr_end = roundup(offset + size, RK3568_NBYTES) / RK3568_NBYTES;
244fd7b5182SFinley Xiao 	addr_offset = offset % RK3568_NBYTES;
245fd7b5182SFinley Xiao 	addr_len = addr_end - addr_start;
246fd7b5182SFinley Xiao 
247fd7b5182SFinley Xiao 	buffer = calloc(1, sizeof(*buffer) * addr_len * RK3568_NBYTES);
248fd7b5182SFinley Xiao 	if (!buffer)
249fd7b5182SFinley Xiao 		return -ENOMEM;
250fd7b5182SFinley Xiao 
251e51b7fb1SFinley Xiao 	ret = rockchip_otp_ecc_enable(otp, true);
252fd7b5182SFinley Xiao 	if (ret < 0) {
253fd7b5182SFinley Xiao 		printf("%s rockchip_otp_ecc_enable err\n", __func__);
254fd7b5182SFinley Xiao 		return ret;
255fd7b5182SFinley Xiao 	}
256fd7b5182SFinley Xiao 
257fd7b5182SFinley Xiao 	writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
258fd7b5182SFinley Xiao 	udelay(5);
259fd7b5182SFinley Xiao 	while (addr_len--) {
260fd7b5182SFinley Xiao 		writel(addr_start++ | OTPC_USER_ADDR_MASK,
261fd7b5182SFinley Xiao 		       otp->base + OTPC_USER_ADDR);
262fd7b5182SFinley Xiao 		writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
263fd7b5182SFinley Xiao 		       otp->base + OTPC_USER_ENABLE);
264fd7b5182SFinley Xiao 		ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
265fd7b5182SFinley Xiao 		if (ret < 0) {
266fd7b5182SFinley Xiao 			printf("%s timeout during read setup\n", __func__);
267fd7b5182SFinley Xiao 			goto read_end;
268fd7b5182SFinley Xiao 		}
269fd7b5182SFinley Xiao 		out_value = readl(otp->base + OTPC_USER_Q);
270fd7b5182SFinley Xiao 		memcpy(&buffer[i], &out_value, RK3568_NBYTES);
271fd7b5182SFinley Xiao 		i += RK3568_NBYTES;
272fd7b5182SFinley Xiao 	}
273fd7b5182SFinley Xiao 
274fd7b5182SFinley Xiao 	memcpy(buf, buffer + addr_offset, size);
275fd7b5182SFinley Xiao 
276fd7b5182SFinley Xiao read_end:
277fd7b5182SFinley Xiao 	writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
278fd7b5182SFinley Xiao 
279fd7b5182SFinley Xiao 	kfree(buffer);
280fd7b5182SFinley Xiao 
281fd7b5182SFinley Xiao 	return ret;
282fd7b5182SFinley Xiao }
283fd7b5182SFinley Xiao 
rockchip_rk3588_otp_read(struct udevice * dev,int offset,void * buf,int size)284975a7fc3SFinley Xiao static int rockchip_rk3588_otp_read(struct udevice *dev, int offset, void *buf,
285975a7fc3SFinley Xiao 				    int size)
286975a7fc3SFinley Xiao {
287975a7fc3SFinley Xiao 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
288dd270bd4SXuhui Lin 	struct otp_data *data;
289975a7fc3SFinley Xiao 	unsigned int addr_start, addr_end, addr_offset, addr_len;
290975a7fc3SFinley Xiao 	int ret = 0, i = 0;
291975a7fc3SFinley Xiao 	u32 out_value, st = 0;
292975a7fc3SFinley Xiao 	u8 *buffer;
293975a7fc3SFinley Xiao 
294dd270bd4SXuhui Lin 	data = (struct otp_data *)dev_get_driver_data(dev);
295dd270bd4SXuhui Lin 	if (!data)
296dd270bd4SXuhui Lin 		return -ENOSYS;
297dd270bd4SXuhui Lin 
298dd270bd4SXuhui Lin 	if (offset > data->size - 1)
299975a7fc3SFinley Xiao 		return -ENOMEM;
300dd270bd4SXuhui Lin 	if (offset + size > data->size)
301dd270bd4SXuhui Lin 		size = data->size - offset;
302975a7fc3SFinley Xiao 
303975a7fc3SFinley Xiao 	addr_start = rounddown(offset, RK3588_NBYTES) / RK3588_NBYTES;
304975a7fc3SFinley Xiao 	addr_end = roundup(offset + size, RK3588_NBYTES) / RK3588_NBYTES;
305975a7fc3SFinley Xiao 	addr_offset = offset % RK3588_NBYTES;
306975a7fc3SFinley Xiao 	addr_len = addr_end - addr_start;
307dd270bd4SXuhui Lin 	addr_start += data->ns_offset;
308975a7fc3SFinley Xiao 
309975a7fc3SFinley Xiao 	buffer = calloc(1, sizeof(*buffer) * addr_len * RK3588_NBYTES);
310975a7fc3SFinley Xiao 	if (!buffer)
311975a7fc3SFinley Xiao 		return -ENOMEM;
312975a7fc3SFinley Xiao 
313975a7fc3SFinley Xiao 	while (addr_len--) {
314975a7fc3SFinley Xiao 		writel((addr_start << RK3588_ADDR_SHIFT) |
315975a7fc3SFinley Xiao 		       (RK3588_BURST_NUM << RK3588_BURST_SHIFT),
316975a7fc3SFinley Xiao 		       otp->base + RK3588_OTPC_AUTO_CTRL);
317975a7fc3SFinley Xiao 		writel(RK3588_AUTO_EN, otp->base + RK3588_OTPC_AUTO_EN);
318975a7fc3SFinley Xiao 		ret = readl_poll_timeout(otp->base + RK3588_OTPC_INT_ST, st,
319975a7fc3SFinley Xiao 					 st & RK3588_RD_DONE, OTPC_TIMEOUT);
320975a7fc3SFinley Xiao 		if (ret < 0) {
321975a7fc3SFinley Xiao 			printf("%s timeout during read setup\n", __func__);
322975a7fc3SFinley Xiao 			goto read_end;
323975a7fc3SFinley Xiao 		}
324975a7fc3SFinley Xiao 		writel(RK3588_RD_DONE, otp->base + RK3588_OTPC_INT_ST);
325975a7fc3SFinley Xiao 
326975a7fc3SFinley Xiao 		out_value = readl(otp->base + RK3588_OTPC_DOUT0);
327975a7fc3SFinley Xiao 		memcpy(&buffer[i], &out_value, RK3588_NBYTES);
328975a7fc3SFinley Xiao 		i += RK3588_NBYTES;
329975a7fc3SFinley Xiao 		addr_start++;
330975a7fc3SFinley Xiao 	}
331975a7fc3SFinley Xiao 
332975a7fc3SFinley Xiao 	memcpy(buf, buffer + addr_offset, size);
333975a7fc3SFinley Xiao 
334975a7fc3SFinley Xiao read_end:
335975a7fc3SFinley Xiao 	kfree(buffer);
336975a7fc3SFinley Xiao 
337975a7fc3SFinley Xiao 	return ret;
338975a7fc3SFinley Xiao }
339975a7fc3SFinley Xiao 
rockchip_rv1126_otp_init(struct udevice * dev)340a4c57e8aSFinley Xiao static int rockchip_rv1126_otp_init(struct udevice *dev)
341a4c57e8aSFinley Xiao {
342a4c57e8aSFinley Xiao 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
343a4c57e8aSFinley Xiao 	u32 status = 0;
344a4c57e8aSFinley Xiao 	int ret;
345a4c57e8aSFinley Xiao 
346a4c57e8aSFinley Xiao 	writel(0x0, otp->base + RV1126_OTP_NVM_CEB);
347a4c57e8aSFinley Xiao 	ret = readl_poll_timeout(otp->base + RV1126_OTP_NVM_ST, status,
348a4c57e8aSFinley Xiao 				 status & 0x1, OTPC_TIMEOUT);
349a4c57e8aSFinley Xiao 	if (ret < 0) {
350a4c57e8aSFinley Xiao 		printf("%s timeout during set ceb\n", __func__);
351a4c57e8aSFinley Xiao 		return ret;
352a4c57e8aSFinley Xiao 	}
353a4c57e8aSFinley Xiao 
354a4c57e8aSFinley Xiao 	writel(0x1, otp->base + RV1126_OTP_NVM_RSTB);
355a4c57e8aSFinley Xiao 	ret = readl_poll_timeout(otp->base + RV1126_OTP_NVM_ST, status,
356a4c57e8aSFinley Xiao 				 status & 0x4, OTPC_TIMEOUT);
357a4c57e8aSFinley Xiao 	if (ret < 0) {
358a4c57e8aSFinley Xiao 		printf("%s timeout during set rstb\n", __func__);
359a4c57e8aSFinley Xiao 		return ret;
360a4c57e8aSFinley Xiao 	}
361a4c57e8aSFinley Xiao 
362a4c57e8aSFinley Xiao 	return 0;
363a4c57e8aSFinley Xiao }
364a4c57e8aSFinley Xiao 
rockchip_rv1126_otp_read(struct udevice * dev,int offset,void * buf,int size)365a4c57e8aSFinley Xiao static int rockchip_rv1126_otp_read(struct udevice *dev, int offset, void *buf,
366a4c57e8aSFinley Xiao 				    int size)
367a4c57e8aSFinley Xiao {
368a4c57e8aSFinley Xiao 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
369a4c57e8aSFinley Xiao 	u32 status = 0;
370a4c57e8aSFinley Xiao 	u8 *buffer = buf;
371a4c57e8aSFinley Xiao 	int ret = 0;
372a4c57e8aSFinley Xiao 
373a4c57e8aSFinley Xiao 	while (size--) {
374a4c57e8aSFinley Xiao 		writel(offset++, otp->base + RV1126_OTP_NVM_RADDR);
375a4c57e8aSFinley Xiao 		writel(0x1, otp->base + RV1126_OTP_NVM_RSTART);
376a4c57e8aSFinley Xiao 		ret = readl_poll_timeout(otp->base + RV1126_OTP_READ_ST,
377a4c57e8aSFinley Xiao 					 status, status == 0, OTPC_TIMEOUT);
378a4c57e8aSFinley Xiao 		if (ret < 0) {
379a4c57e8aSFinley Xiao 			printf("%s timeout during read setup\n", __func__);
380a4c57e8aSFinley Xiao 			return ret;
381a4c57e8aSFinley Xiao 		}
382a4c57e8aSFinley Xiao 
383a4c57e8aSFinley Xiao 		*buffer++ = readb(otp->base + RV1126_OTP_NVM_RDATA);
384a4c57e8aSFinley Xiao 	}
385a4c57e8aSFinley Xiao 
386a4c57e8aSFinley Xiao 	return 0;
387a4c57e8aSFinley Xiao }
388a4c57e8aSFinley Xiao 
rockchip_otp_read(struct udevice * dev,int offset,void * buf,int size)3894973d825SFinley Xiao static int rockchip_otp_read(struct udevice *dev, int offset,
3904973d825SFinley Xiao 			     void *buf, int size)
3914973d825SFinley Xiao {
392a4c57e8aSFinley Xiao 	struct otp_data *data;
3934973d825SFinley Xiao 
394a4c57e8aSFinley Xiao 	data = (struct otp_data *)dev_get_driver_data(dev);
395a4c57e8aSFinley Xiao 	if (!data)
3964973d825SFinley Xiao 		return -ENOSYS;
3974973d825SFinley Xiao 
398738773c6SFinley Xiao 	if (soc_is_rk3308bs() || soc_is_px30s())
3999fed581aSFinley Xiao 		return rockchip_rk3308bs_otp_read(dev, offset, buf, size);
4009fed581aSFinley Xiao 
401a4c57e8aSFinley Xiao 	return data->read(dev, offset, buf, size);
4024973d825SFinley Xiao }
4034973d825SFinley Xiao 
4044973d825SFinley Xiao static const struct misc_ops rockchip_otp_ops = {
4054973d825SFinley Xiao 	.read = rockchip_otp_read,
4064973d825SFinley Xiao };
4074973d825SFinley Xiao 
rockchip_otp_ofdata_to_platdata(struct udevice * dev)4084973d825SFinley Xiao static int rockchip_otp_ofdata_to_platdata(struct udevice *dev)
4094973d825SFinley Xiao {
4104973d825SFinley Xiao 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
4114973d825SFinley Xiao 
4124973d825SFinley Xiao 	otp->base = dev_read_addr_ptr(dev);
4134973d825SFinley Xiao 
4144973d825SFinley Xiao 	return 0;
4154973d825SFinley Xiao }
4164973d825SFinley Xiao 
rockchip_otp_probe(struct udevice * dev)417a4c57e8aSFinley Xiao static int rockchip_otp_probe(struct udevice *dev)
418a4c57e8aSFinley Xiao {
419a4c57e8aSFinley Xiao 	struct otp_data *data;
420a4c57e8aSFinley Xiao 
421a4c57e8aSFinley Xiao 	data = (struct otp_data *)dev_get_driver_data(dev);
422a4c57e8aSFinley Xiao 	if (!data)
423a4c57e8aSFinley Xiao 		return -EINVAL;
424a4c57e8aSFinley Xiao 
425a4c57e8aSFinley Xiao 	if (data->init)
426a4c57e8aSFinley Xiao 		return data->init(dev);
427a4c57e8aSFinley Xiao 
428a4c57e8aSFinley Xiao 	return 0;
429a4c57e8aSFinley Xiao }
430a4c57e8aSFinley Xiao 
431a4c57e8aSFinley Xiao static const struct otp_data px30_data = {
432a4c57e8aSFinley Xiao 	.read = rockchip_px30_otp_read,
433a4c57e8aSFinley Xiao };
434a4c57e8aSFinley Xiao 
4359fed581aSFinley Xiao static const struct otp_data rk3308bs_data = {
4369fed581aSFinley Xiao 	.read = rockchip_rk3308bs_otp_read,
4379fed581aSFinley Xiao };
4389fed581aSFinley Xiao 
439fd7b5182SFinley Xiao static const struct otp_data rk3568_data = {
440fd7b5182SFinley Xiao 	.read = rockchip_rk3568_otp_read,
441fd7b5182SFinley Xiao };
442fd7b5182SFinley Xiao 
443dd270bd4SXuhui Lin static const struct otp_data rk3576_data = {
444dd270bd4SXuhui Lin 	.size = 0x100,
445dd270bd4SXuhui Lin 	.ns_offset = RK3576_NO_SECURE_OFFSET,
446dd270bd4SXuhui Lin 	.read = rockchip_rk3588_otp_read,
447dd270bd4SXuhui Lin };
448dd270bd4SXuhui Lin 
449975a7fc3SFinley Xiao static const struct otp_data rk3588_data = {
450dd270bd4SXuhui Lin 	.size = 0x400,
451dd270bd4SXuhui Lin 	.ns_offset = RK3588_NO_SECURE_OFFSET,
452975a7fc3SFinley Xiao 	.read = rockchip_rk3588_otp_read,
453975a7fc3SFinley Xiao };
454975a7fc3SFinley Xiao 
455a4c57e8aSFinley Xiao static const struct otp_data rv1126_data = {
456a4c57e8aSFinley Xiao 	.init = rockchip_rv1126_otp_init,
457a4c57e8aSFinley Xiao 	.read = rockchip_rv1126_otp_read,
458a4c57e8aSFinley Xiao };
459a4c57e8aSFinley Xiao 
4604973d825SFinley Xiao static const struct udevice_id rockchip_otp_ids[] = {
4614973d825SFinley Xiao 	{
4624973d825SFinley Xiao 		.compatible = "rockchip,px30-otp",
463a4c57e8aSFinley Xiao 		.data = (ulong)&px30_data,
4644973d825SFinley Xiao 	},
4656be53b63SFinley Xiao 	{
466738773c6SFinley Xiao 		.compatible = "rockchip,px30s-otp",
467738773c6SFinley Xiao 		.data = (ulong)&rk3308bs_data,
468738773c6SFinley Xiao 	},
469738773c6SFinley Xiao 	{
4706be53b63SFinley Xiao 		.compatible = "rockchip,rk3308-otp",
471a4c57e8aSFinley Xiao 		.data = (ulong)&px30_data,
472a4c57e8aSFinley Xiao 	},
473a4c57e8aSFinley Xiao 	{
4749fed581aSFinley Xiao 		.compatible = "rockchip,rk3308bs-otp",
4759fed581aSFinley Xiao 		.data = (ulong)&rk3308bs_data,
4769fed581aSFinley Xiao 	},
4779fed581aSFinley Xiao 	{
4780e048a48SXuhui Lin 		.compatible = "rockchip,rk3506-otp",
4790e048a48SXuhui Lin 		.data = (ulong)&rk3568_data,
4800e048a48SXuhui Lin 	},
4810e048a48SXuhui Lin 	{
482abb97387SFinley Xiao 		.compatible = "rockchip,rk3528-otp",
483abb97387SFinley Xiao 		.data = (ulong)&rk3568_data,
484abb97387SFinley Xiao 	},
485abb97387SFinley Xiao 	{
4866e6ee2d7SFinley Xiao 		.compatible = "rockchip,rk3562-otp",
4876e6ee2d7SFinley Xiao 		.data = (ulong)&rk3568_data,
4886e6ee2d7SFinley Xiao 	},
4896e6ee2d7SFinley Xiao 	{
490fd7b5182SFinley Xiao 		.compatible = "rockchip,rk3568-otp",
491fd7b5182SFinley Xiao 		.data = (ulong)&rk3568_data,
492fd7b5182SFinley Xiao 	},
493fd7b5182SFinley Xiao 	{
494dd270bd4SXuhui Lin 		.compatible = "rockchip,rk3576-otp",
495dd270bd4SXuhui Lin 		.data = (ulong)&rk3576_data,
496dd270bd4SXuhui Lin 	},
497dd270bd4SXuhui Lin 	{
498975a7fc3SFinley Xiao 		.compatible = "rockchip,rk3588-otp",
499975a7fc3SFinley Xiao 		.data = (ulong)&rk3588_data,
500975a7fc3SFinley Xiao 	},
501975a7fc3SFinley Xiao 	{
5029fc67a2aSFinley Xiao 		.compatible = "rockchip,rv1106-otp",
5039fc67a2aSFinley Xiao 		.data = (ulong)&rk3568_data,
5049fc67a2aSFinley Xiao 	},
5059fc67a2aSFinley Xiao 	{
506a4c57e8aSFinley Xiao 		.compatible = "rockchip,rv1126-otp",
507a4c57e8aSFinley Xiao 		.data = (ulong)&rv1126_data,
5086be53b63SFinley Xiao 	},
509dbf5f0e7SXuhui Lin 	{
510*052b7b07SXuhui Lin 		.compatible = "rockchip,rv1126b-otp",
511*052b7b07SXuhui Lin 		.data = (ulong)&rk3568_data,
512*052b7b07SXuhui Lin 	},
513*052b7b07SXuhui Lin 	{
514dbf5f0e7SXuhui Lin 		.compatible = "rockchip,rv1103b-otp",
515dbf5f0e7SXuhui Lin 		.data = (ulong)&rk3568_data,
516dbf5f0e7SXuhui Lin 	},
5174973d825SFinley Xiao 	{}
5184973d825SFinley Xiao };
5194973d825SFinley Xiao 
5204973d825SFinley Xiao U_BOOT_DRIVER(rockchip_otp) = {
5214973d825SFinley Xiao 	.name = "rockchip_otp",
5224973d825SFinley Xiao 	.id = UCLASS_MISC,
5234973d825SFinley Xiao 	.of_match = rockchip_otp_ids,
5244973d825SFinley Xiao 	.ops = &rockchip_otp_ops,
5254973d825SFinley Xiao 	.ofdata_to_platdata = rockchip_otp_ofdata_to_platdata,
5264973d825SFinley Xiao 	.platdata_auto_alloc_size = sizeof(struct rockchip_otp_platdata),
527a4c57e8aSFinley Xiao 	.probe = rockchip_otp_probe,
5284973d825SFinley Xiao };
529