xref: /rk3399_rockchip-uboot/drivers/misc/rockchip-otp.c (revision effae6d71544d6cab5ae01aa7160bb709b3a3e6e)
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_rv1126_otp_init(struct udevice *dev)
101 {
102 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
103 	u32 status = 0;
104 	int ret;
105 
106 	writel(0x0, otp->base + RV1126_OTP_NVM_CEB);
107 	ret = readl_poll_timeout(otp->base + RV1126_OTP_NVM_ST, status,
108 				 status & 0x1, OTPC_TIMEOUT);
109 	if (ret < 0) {
110 		printf("%s timeout during set ceb\n", __func__);
111 		return ret;
112 	}
113 
114 	writel(0x1, otp->base + RV1126_OTP_NVM_RSTB);
115 	ret = readl_poll_timeout(otp->base + RV1126_OTP_NVM_ST, status,
116 				 status & 0x4, OTPC_TIMEOUT);
117 	if (ret < 0) {
118 		printf("%s timeout during set rstb\n", __func__);
119 		return ret;
120 	}
121 
122 	return 0;
123 }
124 
125 static int rockchip_rv1126_otp_read(struct udevice *dev, int offset, void *buf,
126 				    int size)
127 {
128 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
129 	u32 status = 0;
130 	u8 *buffer = buf;
131 	int ret = 0;
132 
133 	while (size--) {
134 		writel(offset++, otp->base + RV1126_OTP_NVM_RADDR);
135 		writel(0x1, otp->base + RV1126_OTP_NVM_RSTART);
136 		ret = readl_poll_timeout(otp->base + RV1126_OTP_READ_ST,
137 					 status, status == 0, OTPC_TIMEOUT);
138 		if (ret < 0) {
139 			printf("%s timeout during read setup\n", __func__);
140 			return ret;
141 		}
142 
143 		*buffer++ = readb(otp->base + RV1126_OTP_NVM_RDATA);
144 	}
145 
146 	return 0;
147 }
148 
149 static int rockchip_otp_read(struct udevice *dev, int offset,
150 			     void *buf, int size)
151 {
152 	struct otp_data *data;
153 
154 	data = (struct otp_data *)dev_get_driver_data(dev);
155 	if (!data)
156 		return -ENOSYS;
157 
158 	return data->read(dev, offset, buf, size);
159 }
160 
161 static const struct misc_ops rockchip_otp_ops = {
162 	.read = rockchip_otp_read,
163 };
164 
165 static int rockchip_otp_ofdata_to_platdata(struct udevice *dev)
166 {
167 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
168 
169 	otp->base = dev_read_addr_ptr(dev);
170 
171 	return 0;
172 }
173 
174 static int rockchip_otp_probe(struct udevice *dev)
175 {
176 	struct otp_data *data;
177 
178 	data = (struct otp_data *)dev_get_driver_data(dev);
179 	if (!data)
180 		return -EINVAL;
181 
182 	if (data->init)
183 		return data->init(dev);
184 
185 	return 0;
186 }
187 
188 static const struct otp_data px30_data = {
189 	.read = rockchip_px30_otp_read,
190 };
191 
192 static const struct otp_data rv1126_data = {
193 	.init = rockchip_rv1126_otp_init,
194 	.read = rockchip_rv1126_otp_read,
195 };
196 
197 static const struct udevice_id rockchip_otp_ids[] = {
198 	{
199 		.compatible = "rockchip,px30-otp",
200 		.data = (ulong)&px30_data,
201 	},
202 	{
203 		.compatible = "rockchip,rk3308-otp",
204 		.data = (ulong)&px30_data,
205 	},
206 	{
207 		.compatible = "rockchip,rv1126-otp",
208 		.data = (ulong)&rv1126_data,
209 	},
210 	{}
211 };
212 
213 U_BOOT_DRIVER(rockchip_otp) = {
214 	.name = "rockchip_otp",
215 	.id = UCLASS_MISC,
216 	.of_match = rockchip_otp_ids,
217 	.ops = &rockchip_otp_ops,
218 	.ofdata_to_platdata = rockchip_otp_ofdata_to_platdata,
219 	.platdata_auto_alloc_size = sizeof(struct rockchip_otp_platdata),
220 	.probe = rockchip_otp_probe,
221 };
222