blob: d854ea900442b0f0070f28d8543b4b957e5f4fc0 [file] [log] [blame]
Lin Jinhan20b78502020-03-31 17:39:59 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2020 Fuzhou Rockchip Electronics Co., Ltd
4 */
Heinrich Schuchardt10a45cc2024-02-13 00:44:47 +01005
6#include <dm.h>
7#include <rng.h>
Lin Jinhan20b78502020-03-31 17:39:59 +08008#include <asm/arch-rockchip/hardware.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -06009#include <linux/bitops.h>
Lin Jinhan20b78502020-03-31 17:39:59 +080010#include <linux/iopoll.h>
11#include <linux/string.h>
Lin Jinhan20b78502020-03-31 17:39:59 +080012
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
Chris Morganeb1ca2e2023-04-13 09:13:02 -050045/* 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
Lin Jinhan33a08de2025-04-07 22:46:58 +000073/* start of RKRNG register define */
74#define RKRNG_CTRL 0x0010
75#define RKRNG_CTRL_INST_REQ BIT(0)
76#define RKRNG_CTRL_RESEED_REQ BIT(1)
77#define RKRNG_CTRL_TEST_REQ BIT(2)
78#define RKRNG_CTRL_SW_DRNG_REQ BIT(3)
79#define RKRNG_CTRL_SW_TRNG_REQ BIT(4)
80
81#define RKRNG_STATE 0x0014
82#define RKRNG_STATE_INST_ACK BIT(0)
83#define RKRNG_STATE_RESEED_ACK BIT(1)
84#define RKRNG_STATE_TEST_ACK BIT(2)
85#define RKRNG_STATE_SW_DRNG_ACK BIT(3)
86#define RKRNG_STATE_SW_TRNG_ACK BIT(4)
87
88/* DRNG_DATA_0 ~ DNG_DATA_7 */
89#define RKRNG_DRNG_DATA_0 0x0070
90#define RKRNG_DRNG_DATA_7 0x008C
91
92/* end of RKRNG register define */
93
Lin Jinhan20b78502020-03-31 17:39:59 +080094#define RK_RNG_TIME_OUT 50000 /* max 50ms */
95
Chris Morganeb1ca2e2023-04-13 09:13:02 -050096#define trng_write(pdata, pos, val) writel(val, (pdata)->base + (pos))
97#define trng_read(pdata, pos) readl((pdata)->base + (pos))
98
Lin Jinhan20b78502020-03-31 17:39:59 +080099struct rk_rng_soc_data {
Chris Morganeb1ca2e2023-04-13 09:13:02 -0500100 int (*rk_rng_init)(struct udevice *dev);
Lin Jinhan20b78502020-03-31 17:39:59 +0800101 int (*rk_rng_read)(struct udevice *dev, void *data, size_t len);
102};
103
Simon Glassb75b15b2020-12-03 16:55:23 -0700104struct rk_rng_plat {
Lin Jinhan20b78502020-03-31 17:39:59 +0800105 fdt_addr_t base;
106 struct rk_rng_soc_data *soc_data;
107};
108
109static int rk_rng_read_regs(fdt_addr_t addr, void *buf, size_t size)
110{
111 u32 count = RK_HW_RNG_MAX / sizeof(u32);
112 u32 reg, tmp_len;
113
114 if (size > RK_HW_RNG_MAX)
115 return -EINVAL;
116
117 while (size && count) {
118 reg = readl(addr);
119 tmp_len = min(size, sizeof(u32));
120 memcpy(buf, &reg, tmp_len);
121 addr += sizeof(u32);
122 buf += tmp_len;
123 size -= tmp_len;
124 count--;
125 }
126
127 return 0;
128}
129
Chris Morganeb1ca2e2023-04-13 09:13:02 -0500130static int rk_cryptov1_rng_read(struct udevice *dev, void *data, size_t len)
Lin Jinhan20b78502020-03-31 17:39:59 +0800131{
Simon Glassb75b15b2020-12-03 16:55:23 -0700132 struct rk_rng_plat *pdata = dev_get_priv(dev);
Lin Jinhan20b78502020-03-31 17:39:59 +0800133 u32 reg = 0;
134 int retval;
135
136 if (len > RK_HW_RNG_MAX)
137 return -EINVAL;
138
139 /* enable osc_ring to get entropy, sample period is set as 100 */
140 writel(CRYPTO_V1_OSC_ENABLE | CRYPTO_V1_TRNG_SAMPLE_PERIOD(100),
141 pdata->base + CRYPTO_V1_TRNG_CTRL);
142
143 rk_clrsetreg(pdata->base + CRYPTO_V1_CTRL, CRYPTO_V1_RNG_START,
144 CRYPTO_V1_RNG_START);
145
146 retval = readl_poll_timeout(pdata->base + CRYPTO_V1_CTRL, reg,
147 !(reg & CRYPTO_V1_RNG_START),
148 RK_RNG_TIME_OUT);
149 if (retval)
150 goto exit;
151
152 rk_rng_read_regs(pdata->base + CRYPTO_V1_TRNG_DOUT_0, data, len);
153
154exit:
155 /* close TRNG */
156 rk_clrreg(pdata->base + CRYPTO_V1_CTRL, CRYPTO_V1_RNG_START);
157
158 return 0;
159}
160
Chris Morganeb1ca2e2023-04-13 09:13:02 -0500161static int rk_cryptov2_rng_read(struct udevice *dev, void *data, size_t len)
Lin Jinhan20b78502020-03-31 17:39:59 +0800162{
Simon Glassb75b15b2020-12-03 16:55:23 -0700163 struct rk_rng_plat *pdata = dev_get_priv(dev);
Lin Jinhan20b78502020-03-31 17:39:59 +0800164 u32 reg = 0;
165 int retval;
166
167 if (len > RK_HW_RNG_MAX)
168 return -EINVAL;
169
170 /* enable osc_ring to get entropy, sample period is set as 100 */
171 writel(100, pdata->base + CRYPTO_V2_RNG_SAMPLE_CNT);
172
173 reg |= CRYPTO_V2_RNG_256_BIT_LEN;
174 reg |= CRYPTO_V2_RNG_SLOWER_SOC_RING_0;
175 reg |= CRYPTO_V2_RNG_ENABLE;
176 reg |= CRYPTO_V2_RNG_START;
177
178 rk_clrsetreg(pdata->base + CRYPTO_V2_RNG_CTL, 0xffff, reg);
179
180 retval = readl_poll_timeout(pdata->base + CRYPTO_V2_RNG_CTL, reg,
181 !(reg & CRYPTO_V2_RNG_START),
182 RK_RNG_TIME_OUT);
183 if (retval)
184 goto exit;
185
186 rk_rng_read_regs(pdata->base + CRYPTO_V2_RNG_DOUT_0, data, len);
187
188exit:
189 /* close TRNG */
190 rk_clrreg(pdata->base + CRYPTO_V2_RNG_CTL, 0xffff);
191
192 return retval;
193}
194
Chris Morganeb1ca2e2023-04-13 09:13:02 -0500195static int rk_trngv1_init(struct udevice *dev)
196{
197 u32 status, version;
198 u32 auto_reseed_cnt = 1000;
199 struct rk_rng_plat *pdata = dev_get_priv(dev);
200
201 version = trng_read(pdata, TRNG_V1_VERSION);
202 if (version != TRNG_v1_VERSION_CODE) {
203 printf("wrong trng version, expected = %08x, actual = %08x",
204 TRNG_V1_VERSION, version);
205 return -EFAULT;
206 }
207
208 /* wait in case of RND_RDY triggered at firs power on */
209 readl_poll_timeout(pdata->base + TRNG_V1_ISTAT, status,
210 (status & TRNG_V1_ISTAT_RAND_RDY),
211 RK_RNG_TIME_OUT);
212
213 /* clear RAND_RDY flag for first power on */
214 trng_write(pdata, TRNG_V1_ISTAT, status);
215
216 /* auto reseed after (auto_reseed_cnt * 16) byte rand generate */
217 trng_write(pdata, TRNG_V1_AUTO_RQSTS, auto_reseed_cnt);
218
219 return 0;
220}
221
222static int rk_trngv1_rng_read(struct udevice *dev, void *data, size_t len)
223{
224 struct rk_rng_plat *pdata = dev_get_priv(dev);
225 u32 reg = 0;
226 int retval;
227
228 if (len > RK_HW_RNG_MAX)
229 return -EINVAL;
230
231 trng_write(pdata, TRNG_V1_MODE, TRNG_V1_MODE_256_BIT);
232 trng_write(pdata, TRNG_V1_CTRL, TRNG_V1_CTRL_RAND);
233
234 retval = readl_poll_timeout(pdata->base + TRNG_V1_ISTAT, reg,
235 (reg & TRNG_V1_ISTAT_RAND_RDY),
236 RK_RNG_TIME_OUT);
237 /* clear ISTAT */
238 trng_write(pdata, TRNG_V1_ISTAT, reg);
239
240 if (retval)
241 goto exit;
242
243 rk_rng_read_regs(pdata->base + TRNG_V1_RAND0, data, len);
244
245exit:
246 /* close TRNG */
247 trng_write(pdata, TRNG_V1_CTRL, TRNG_V1_CTRL_NOP);
248
249 return retval;
250}
251
Lin Jinhan33a08de2025-04-07 22:46:58 +0000252static int rkrng_init(struct udevice *dev)
253{
254 struct rk_rng_plat *pdata = dev_get_priv(dev);
255 u32 reg = 0;
256
257 rk_clrreg(pdata->base + RKRNG_CTRL, 0xffff);
258
259 reg = trng_read(pdata, RKRNG_STATE);
260 trng_write(pdata, RKRNG_STATE, reg);
261
262 return 0;
263}
264
265static int rkrng_rng_read(struct udevice *dev, void *data, size_t len)
266{
267 struct rk_rng_plat *pdata = dev_get_priv(dev);
268 u32 reg = 0;
269 int retval;
270
271 if (len > RK_HW_RNG_MAX)
272 return -EINVAL;
273
274 reg = RKRNG_CTRL_SW_DRNG_REQ;
275
276 rk_clrsetreg(pdata->base + RKRNG_CTRL, 0xffff, reg);
277
278 retval = readl_poll_timeout(pdata->base + RKRNG_STATE, reg,
279 (reg & RKRNG_STATE_SW_DRNG_ACK),
280 RK_RNG_TIME_OUT);
281 if (retval)
282 goto exit;
283
284 trng_write(pdata, RKRNG_STATE, reg);
285
286 rk_rng_read_regs(pdata->base + RKRNG_DRNG_DATA_0, data, len);
287
288exit:
289 /* close TRNG */
290 rk_clrreg(pdata->base + RKRNG_CTRL, 0xffff);
291
292 return retval;
293}
294
Lin Jinhan20b78502020-03-31 17:39:59 +0800295static int rockchip_rng_read(struct udevice *dev, void *data, size_t len)
296{
297 unsigned char *buf = data;
298 unsigned int i;
299 int ret = -EIO;
300
Simon Glassb75b15b2020-12-03 16:55:23 -0700301 struct rk_rng_plat *pdata = dev_get_priv(dev);
Lin Jinhan20b78502020-03-31 17:39:59 +0800302
303 if (!len)
304 return 0;
305
306 if (!pdata->soc_data || !pdata->soc_data->rk_rng_read)
307 return -EINVAL;
308
309 for (i = 0; i < len / RK_HW_RNG_MAX; i++, buf += RK_HW_RNG_MAX) {
310 ret = pdata->soc_data->rk_rng_read(dev, buf, RK_HW_RNG_MAX);
311 if (ret)
312 goto exit;
313 }
314
315 if (len % RK_HW_RNG_MAX)
316 ret = pdata->soc_data->rk_rng_read(dev, buf,
317 len % RK_HW_RNG_MAX);
318
319exit:
320 return ret;
321}
322
Simon Glassaad29ae2020-12-03 16:55:21 -0700323static int rockchip_rng_of_to_plat(struct udevice *dev)
Lin Jinhan20b78502020-03-31 17:39:59 +0800324{
Simon Glassb75b15b2020-12-03 16:55:23 -0700325 struct rk_rng_plat *pdata = dev_get_priv(dev);
Lin Jinhan20b78502020-03-31 17:39:59 +0800326
327 memset(pdata, 0x00, sizeof(*pdata));
328
329 pdata->base = (fdt_addr_t)dev_read_addr_ptr(dev);
330 if (!pdata->base)
331 return -ENOMEM;
332
333 return 0;
334}
335
336static int rockchip_rng_probe(struct udevice *dev)
337{
Simon Glassb75b15b2020-12-03 16:55:23 -0700338 struct rk_rng_plat *pdata = dev_get_priv(dev);
Chris Morganeb1ca2e2023-04-13 09:13:02 -0500339 int ret = 0;
Lin Jinhan20b78502020-03-31 17:39:59 +0800340
341 pdata->soc_data = (struct rk_rng_soc_data *)dev_get_driver_data(dev);
342
Chris Morganeb1ca2e2023-04-13 09:13:02 -0500343 if (pdata->soc_data->rk_rng_init)
344 ret = pdata->soc_data->rk_rng_init(dev);
345
346 return ret;
Lin Jinhan20b78502020-03-31 17:39:59 +0800347}
348
Chris Morganeb1ca2e2023-04-13 09:13:02 -0500349static const struct rk_rng_soc_data rk_cryptov1_soc_data = {
350 .rk_rng_read = rk_cryptov1_rng_read,
351};
352
353static const struct rk_rng_soc_data rk_cryptov2_soc_data = {
354 .rk_rng_read = rk_cryptov2_rng_read,
Lin Jinhan20b78502020-03-31 17:39:59 +0800355};
356
Chris Morganeb1ca2e2023-04-13 09:13:02 -0500357static const struct rk_rng_soc_data rk_trngv1_soc_data = {
358 .rk_rng_init = rk_trngv1_init,
359 .rk_rng_read = rk_trngv1_rng_read,
Lin Jinhan20b78502020-03-31 17:39:59 +0800360};
361
Lin Jinhan33a08de2025-04-07 22:46:58 +0000362static const struct rk_rng_soc_data rkrng_soc_data = {
363 .rk_rng_init = rkrng_init,
364 .rk_rng_read = rkrng_rng_read,
365};
366
Lin Jinhan20b78502020-03-31 17:39:59 +0800367static const struct dm_rng_ops rockchip_rng_ops = {
368 .read = rockchip_rng_read,
369};
370
371static const struct udevice_id rockchip_rng_match[] = {
372 {
Jonas Karlman64ba61f2024-02-17 00:22:36 +0000373 .compatible = "rockchip,rk3288-crypto",
374 .data = (ulong)&rk_cryptov1_soc_data,
375 },
376 {
377 .compatible = "rockchip,rk3328-crypto",
378 .data = (ulong)&rk_cryptov1_soc_data,
379 },
380 {
381 .compatible = "rockchip,rk3399-crypto",
Chris Morganeb1ca2e2023-04-13 09:13:02 -0500382 .data = (ulong)&rk_cryptov1_soc_data,
Lin Jinhan20b78502020-03-31 17:39:59 +0800383 },
384 {
Jonas Karlmanb478f512025-04-08 22:11:42 +0000385 .compatible = "rockchip,rk3568-rng",
386 .data = (ulong)&rk_cryptov2_soc_data,
387 },
388 {
Lin Jinhan20b78502020-03-31 17:39:59 +0800389 .compatible = "rockchip,cryptov2-rng",
Chris Morganeb1ca2e2023-04-13 09:13:02 -0500390 .data = (ulong)&rk_cryptov2_soc_data,
391 },
392 {
Jonas Karlmand68e4502025-04-08 22:11:45 +0000393 .compatible = "rockchip,rk3588-rng",
Chris Morganeb1ca2e2023-04-13 09:13:02 -0500394 .data = (ulong)&rk_trngv1_soc_data,
Lin Jinhan20b78502020-03-31 17:39:59 +0800395 },
Lin Jinhan33a08de2025-04-07 22:46:58 +0000396 {
397 .compatible = "rockchip,rkrng",
398 .data = (ulong)&rkrng_soc_data,
399 },
Lin Jinhan20b78502020-03-31 17:39:59 +0800400 {},
401};
402
403U_BOOT_DRIVER(rockchip_rng) = {
404 .name = "rockchip-rng",
405 .id = UCLASS_RNG,
406 .of_match = rockchip_rng_match,
407 .ops = &rockchip_rng_ops,
408 .probe = rockchip_rng_probe,
Simon Glassaad29ae2020-12-03 16:55:21 -0700409 .of_to_plat = rockchip_rng_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700410 .priv_auto = sizeof(struct rk_rng_plat),
Lin Jinhan20b78502020-03-31 17:39:59 +0800411};