xref: /rk3399_rockchip-uboot/drivers/rng/rockchip_rng.c (revision c8a22fb85e7897da3a0a3ede4705e54e9f18eba3)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020 Fuzhou Rockchip Electronics Co., Ltd
4  */
5 #include <asm/arch-rockchip/hardware.h>
6 #include <asm/io.h>
7 #include <common.h>
8 #include <dm.h>
9 #include <linux/iopoll.h>
10 #include <linux/string.h>
11 #include <rng.h>
12 
13 #define RK_HW_RNG_MAX 32
14 
15 #define _SBF(s, v)	((v) << (s))
16 
17 /* start of CRYPTO V1 register define */
18 #define CRYPTO_V1_CTRL				0x0008
19 #define CRYPTO_V1_RNG_START			BIT(8)
20 #define CRYPTO_V1_RNG_FLUSH			BIT(9)
21 
22 #define CRYPTO_V1_TRNG_CTRL			0x0200
23 #define CRYPTO_V1_OSC_ENABLE			BIT(16)
24 #define CRYPTO_V1_TRNG_SAMPLE_PERIOD(x)		(x)
25 
26 #define CRYPTO_V1_TRNG_DOUT_0			0x0204
27 /* end of CRYPTO V1 register define */
28 
29 /* start of CRYPTO V2 register define */
30 #define CRYPTO_V2_RNG_CTL			0x0400
31 #define CRYPTO_V2_RNG_64_BIT_LEN		_SBF(4, 0x00)
32 #define CRYPTO_V2_RNG_128_BIT_LEN		_SBF(4, 0x01)
33 #define CRYPTO_V2_RNG_192_BIT_LEN		_SBF(4, 0x02)
34 #define CRYPTO_V2_RNG_256_BIT_LEN		_SBF(4, 0x03)
35 #define CRYPTO_V2_RNG_FATESY_SOC_RING		_SBF(2, 0x00)
36 #define CRYPTO_V2_RNG_SLOWER_SOC_RING_0		_SBF(2, 0x01)
37 #define CRYPTO_V2_RNG_SLOWER_SOC_RING_1		_SBF(2, 0x02)
38 #define CRYPTO_V2_RNG_SLOWEST_SOC_RING		_SBF(2, 0x03)
39 #define CRYPTO_V2_RNG_ENABLE			BIT(1)
40 #define CRYPTO_V2_RNG_START			BIT(0)
41 #define CRYPTO_V2_RNG_SAMPLE_CNT		0x0404
42 #define CRYPTO_V2_RNG_DOUT_0			0x0410
43 /* end of CRYPTO V2 register define */
44 
45 /* start of TRNG V1 register define */
46 #define TRNG_V1_CTRL				0x0000
47 #define TRNG_V1_CTRL_NOP			_SBF(0, 0x00)
48 #define TRNG_V1_CTRL_RAND			_SBF(0, 0x01)
49 #define TRNG_V1_CTRL_SEED			_SBF(0, 0x02)
50 
51 #define TRNG_V1_MODE				0x0008
52 #define TRNG_V1_MODE_128_BIT			_SBF(3, 0x00)
53 #define TRNG_V1_MODE_256_BIT			_SBF(3, 0x01)
54 
55 #define TRNG_V1_IE				0x0010
56 #define TRNG_V1_IE_GLBL_EN			BIT(31)
57 #define TRNG_V1_IE_SEED_DONE_EN			BIT(1)
58 #define TRNG_V1_IE_RAND_RDY_EN			BIT(0)
59 
60 #define TRNG_V1_ISTAT				0x0014
61 #define TRNG_V1_ISTAT_RAND_RDY			BIT(0)
62 
63 /* RAND0 ~ RAND7 */
64 #define TRNG_V1_RAND0				0x0020
65 #define TRNG_V1_RAND7				0x003C
66 
67 #define TRNG_V1_AUTO_RQSTS			0x0060
68 
69 #define TRNG_V1_VERSION				0x00F0
70 #define TRNG_v1_VERSION_CODE			0x46BC
71 /* end of TRNG V1 register define */
72 
73 #define RK_RNG_TIME_OUT	50000  /* max 50ms */
74 
75 #define trng_write(pdata, pos, val)	writel(val, (pdata)->base + (pos))
76 #define trng_read(pdata, pos)		readl((pdata)->base + (pos))
77 
78 struct rk_rng_soc_data {
79 	int (*rk_rng_init)(struct udevice *dev);
80 	int (*rk_rng_read)(struct udevice *dev, void *data, size_t len);
81 };
82 
83 struct rk_rng_platdata {
84 	fdt_addr_t base;
85 	struct rk_rng_soc_data *soc_data;
86 };
87 
88 static int rk_rng_read_regs(fdt_addr_t addr, void *buf, size_t size)
89 {
90 	u32 count = RK_HW_RNG_MAX / sizeof(u32);
91 	u32 reg, tmp_len;
92 
93 	if (size > RK_HW_RNG_MAX)
94 		return -EINVAL;
95 
96 	while (size && count) {
97 		reg = readl(addr);
98 		tmp_len = min(size, sizeof(u32));
99 		memcpy(buf, &reg, tmp_len);
100 		addr += sizeof(u32);
101 		buf += tmp_len;
102 		size -= tmp_len;
103 		count--;
104 	}
105 
106 	return 0;
107 }
108 
109 static int rk_cryptov1_rng_read(struct udevice *dev, void *data, size_t len)
110 {
111 	struct rk_rng_platdata *pdata = dev_get_priv(dev);
112 	u32 reg = 0;
113 	int retval;
114 
115 	if (len > RK_HW_RNG_MAX)
116 		return -EINVAL;
117 
118 	/* enable osc_ring to get entropy, sample period is set as 100 */
119 	writel(CRYPTO_V1_OSC_ENABLE | CRYPTO_V1_TRNG_SAMPLE_PERIOD(100),
120 	       pdata->base + CRYPTO_V1_TRNG_CTRL);
121 
122 	rk_clrsetreg(pdata->base + CRYPTO_V1_CTRL, CRYPTO_V1_RNG_START,
123 		     CRYPTO_V1_RNG_START);
124 
125 	retval = readl_poll_timeout(pdata->base + CRYPTO_V1_CTRL, reg,
126 				    !(reg & CRYPTO_V1_RNG_START),
127 				    RK_RNG_TIME_OUT);
128 	if (retval)
129 		goto exit;
130 
131 	rk_rng_read_regs(pdata->base + CRYPTO_V1_TRNG_DOUT_0, data, len);
132 
133 exit:
134 	/* close TRNG */
135 	rk_clrreg(pdata->base + CRYPTO_V1_CTRL, CRYPTO_V1_RNG_START);
136 
137 	return 0;
138 }
139 
140 static int rk_cryptov2_rng_read(struct udevice *dev, void *data, size_t len)
141 {
142 	struct rk_rng_platdata *pdata = dev_get_priv(dev);
143 	u32 reg = 0;
144 	int retval;
145 
146 	if (len > RK_HW_RNG_MAX)
147 		return -EINVAL;
148 
149 	/* enable osc_ring to get entropy, sample period is set as 100 */
150 	writel(100, pdata->base + CRYPTO_V2_RNG_SAMPLE_CNT);
151 
152 	reg |= CRYPTO_V2_RNG_256_BIT_LEN;
153 	reg |= CRYPTO_V2_RNG_SLOWER_SOC_RING_0;
154 	reg |= CRYPTO_V2_RNG_ENABLE;
155 	reg |= CRYPTO_V2_RNG_START;
156 
157 	rk_clrsetreg(pdata->base + CRYPTO_V2_RNG_CTL, 0xffff, reg);
158 
159 	retval = readl_poll_timeout(pdata->base + CRYPTO_V2_RNG_CTL, reg,
160 				    !(reg & CRYPTO_V2_RNG_START),
161 				    RK_RNG_TIME_OUT);
162 	if (retval)
163 		goto exit;
164 
165 	rk_rng_read_regs(pdata->base + CRYPTO_V2_RNG_DOUT_0, data, len);
166 
167 exit:
168 	/* close TRNG */
169 	rk_clrreg(pdata->base + CRYPTO_V2_RNG_CTL, 0xffff);
170 
171 	return retval;
172 }
173 
174 static int rk_trngv1_init(struct udevice *dev)
175 {
176 	u32 status, version;
177 	u32 auto_reseed_cnt = 1000;
178 	struct rk_rng_platdata *pdata = dev_get_priv(dev);
179 
180 	version = trng_read(pdata, TRNG_V1_VERSION);
181 	if (version != TRNG_v1_VERSION_CODE) {
182 		printf("wrong trng version, expected = %08x, actual = %08x",
183 		       TRNG_V1_VERSION, version);
184 		return -EFAULT;
185 	}
186 
187 	/* wait in case of RND_RDY triggered at firs power on */
188 	readl_poll_timeout(pdata->base + TRNG_V1_ISTAT, status,
189 			   (status & TRNG_V1_ISTAT_RAND_RDY),
190 			   RK_RNG_TIME_OUT);
191 
192 	/* clear RAND_RDY flag for first power on */
193 	trng_write(pdata, TRNG_V1_ISTAT, status);
194 
195 	/* auto reseed after (auto_reseed_cnt * 16) byte rand generate */
196 	trng_write(pdata, TRNG_V1_AUTO_RQSTS, auto_reseed_cnt);
197 
198 	return 0;
199 }
200 
201 static int rk_trngv1_rng_read(struct udevice *dev, void *data, size_t len)
202 {
203 	struct rk_rng_platdata *pdata = dev_get_priv(dev);
204 	u32 reg = 0;
205 	int retval;
206 
207 	if (len > RK_HW_RNG_MAX)
208 		return -EINVAL;
209 
210 	trng_write(pdata, TRNG_V1_MODE, TRNG_V1_MODE_256_BIT);
211 	trng_write(pdata, TRNG_V1_CTRL, TRNG_V1_CTRL_RAND);
212 
213 	retval = readl_poll_timeout(pdata->base + TRNG_V1_ISTAT, reg,
214 				    (reg & TRNG_V1_ISTAT_RAND_RDY),
215 				    RK_RNG_TIME_OUT);
216 	/* clear ISTAT */
217 	trng_write(pdata, TRNG_V1_ISTAT, reg);
218 
219 	if (retval)
220 		goto exit;
221 
222 	rk_rng_read_regs(pdata->base + TRNG_V1_RAND0, data, len);
223 
224 exit:
225 	/* close TRNG */
226 	trng_write(pdata, TRNG_V1_CTRL, TRNG_V1_CTRL_NOP);
227 
228 	return retval;
229 }
230 
231 static int rockchip_rng_read(struct udevice *dev, void *data, size_t len)
232 {
233 	unsigned char *buf = data;
234 	unsigned int i;
235 	int ret = -EIO;
236 
237 	struct rk_rng_platdata *pdata = dev_get_priv(dev);
238 
239 	if (!len)
240 		return 0;
241 
242 	if (!pdata->soc_data || !pdata->soc_data->rk_rng_read)
243 		return -EINVAL;
244 
245 	for (i = 0; i < len / RK_HW_RNG_MAX; i++, buf += RK_HW_RNG_MAX) {
246 		ret = pdata->soc_data->rk_rng_read(dev, buf, RK_HW_RNG_MAX);
247 		if (ret)
248 			goto exit;
249 	}
250 
251 	if (len % RK_HW_RNG_MAX)
252 		ret = pdata->soc_data->rk_rng_read(dev, buf,
253 						   len % RK_HW_RNG_MAX);
254 
255 exit:
256 	return ret;
257 }
258 
259 static int rockchip_rng_ofdata_to_platdata(struct udevice *dev)
260 {
261 	struct rk_rng_platdata *pdata = dev_get_priv(dev);
262 
263 	memset(pdata, 0x00, sizeof(*pdata));
264 
265 	pdata->base = (fdt_addr_t)dev_read_addr_ptr(dev);
266 	if (!pdata->base)
267 		return -ENOMEM;
268 
269 	return 0;
270 }
271 
272 static int rockchip_rng_probe(struct udevice *dev)
273 {
274 	struct rk_rng_platdata *pdata = dev_get_priv(dev);
275 	int ret = 0;
276 
277 	pdata->soc_data = (struct rk_rng_soc_data *)dev_get_driver_data(dev);
278 
279 	if (pdata->soc_data->rk_rng_init)
280 		ret = pdata->soc_data->rk_rng_init(dev);
281 
282 	return ret;
283 }
284 
285 static const struct rk_rng_soc_data rk_cryptov1_soc_data = {
286 	.rk_rng_read = rk_cryptov1_rng_read,
287 };
288 
289 static const struct rk_rng_soc_data rk_cryptov2_soc_data = {
290 	.rk_rng_read = rk_cryptov2_rng_read,
291 };
292 
293 static const struct rk_rng_soc_data rk_trngv1_soc_data = {
294 	.rk_rng_init = rk_trngv1_init,
295 	.rk_rng_read = rk_trngv1_rng_read,
296 };
297 
298 static const struct dm_rng_ops rockchip_rng_ops = {
299 	.read = rockchip_rng_read,
300 };
301 
302 static const struct udevice_id rockchip_rng_match[] = {
303 	{
304 		.compatible = "rockchip,cryptov1-rng",
305 		.data = (ulong)&rk_cryptov1_soc_data,
306 	},
307 	{
308 		.compatible = "rockchip,cryptov2-rng",
309 		.data = (ulong)&rk_cryptov2_soc_data,
310 	},
311 	{
312 		.compatible = "rockchip,trngv1",
313 		.data = (ulong)&rk_trngv1_soc_data,
314 	},
315 	{},
316 };
317 
318 U_BOOT_DRIVER(rockchip_rng) = {
319 	.name = "rockchip-rng",
320 	.id = UCLASS_RNG,
321 	.of_match = rockchip_rng_match,
322 	.ops = &rockchip_rng_ops,
323 	.probe = rockchip_rng_probe,
324 	.ofdata_to_platdata = rockchip_rng_ofdata_to_platdata,
325 	.priv_auto_alloc_size = sizeof(struct rk_rng_platdata),
326 };
327