xref: /rk3399_ARM-atf/plat/mediatek/drivers/rng/mt8186/rng_plat.c (revision 52e486f6a6192bd18d36cdcbc35c59092eefc810)
1 /*
2  * Copyright (c) 2024, MediaTek Inc. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <errno.h>
9 #include <stdint.h>
10 
11 #include <common/debug.h>
12 #include <drivers/delay_timer.h>
13 #include <lib/mmio.h>
14 #include <lib/smccc.h>
15 #include <lib/spinlock.h>
16 #include <plat/common/platform.h>
17 #include <platform_def.h>
18 #include <services/trng_svc.h>
19 #include <smccc_helpers.h>
20 
21 #include <mtk_mmap_pool.h>
22 #include <mtk_sip_svc.h>
23 #include "rng_plat.h"
24 
25 static spinlock_t rng_lock;
26 
27 static int trng_wait(uint32_t reg, uint32_t expected_value)
28 {
29 	uint64_t timeout = timeout_init_us(TRNG_TIME_OUT);
30 	uint32_t value = 0;
31 
32 	do {
33 		value = mmio_read_32(reg);
34 		if ((value & expected_value) == expected_value)
35 			return 0;
36 
37 		udelay(10);
38 	} while (!timeout_elapsed(timeout));
39 
40 	return -ETIMEDOUT;
41 }
42 
43 static int trng_write(uint32_t reg, uint32_t value,
44 			   uint32_t read_reg, uint32_t expected_value)
45 {
46 	int retry = MTK_TRNG_MAX_ROUND;
47 	uint32_t read_value = 0;
48 
49 	do {
50 		mmio_write_32(reg, value);
51 
52 		read_value = mmio_read_32(read_reg);
53 		if ((read_value & value) == expected_value)
54 			return 0;
55 
56 		udelay(10);
57 	} while (--retry > 0);
58 
59 	return -ETIMEDOUT;
60 }
61 
62 static uint32_t trng_prng(uint32_t *rand)
63 {
64 	int32_t ret = 0;
65 	uint32_t seed[4] = {0};
66 
67 	if (rand == NULL)
68 		return MTK_SIP_E_INVALID_PARAM;
69 
70 	/* ungate */
71 	ret = trng_write(TRNG_PDN_CLR, TRNG_PDN_VALUE, TRNG_PDN_STATUS, 0);
72 	if (ret) {
73 		ERROR("%s: ungate fail\n", __func__);
74 		return MTK_SIP_E_NOT_SUPPORTED;
75 	}
76 
77 	/* read random data once and drop it */
78 	seed[0] = mmio_read_32(TRNG_DATA);
79 
80 	/* enable von-neumann extractor */
81 	mmio_setbits_32(TRNG_CONF, TRNG_CONF_VON_EN);
82 
83 	/* start */
84 	mmio_setbits_32(TRNG_CTRL, TRNG_CTRL_START);
85 
86 	/* get seeds from trng */
87 	for (int i = 0; i < ARRAY_SIZE(seed); i++) {
88 		ret = trng_wait(TRNG_CTRL, TRNG_CTRL_RDY);
89 		if (ret) {
90 			ERROR("%s: trng NOT ready\n", __func__);
91 			return MTK_SIP_E_NOT_SUPPORTED;
92 		}
93 
94 		seed[i] = mmio_read_32(TRNG_DATA);
95 	}
96 
97 	/* stop */
98 	mmio_clrbits_32(TRNG_CTRL, TRNG_CTRL_START);
99 
100 	/* gate */
101 	ret = trng_write(TRNG_PDN_SET, TRNG_PDN_VALUE, TRNG_PDN_STATUS, TRNG_PDN_VALUE);
102 	if (ret) {
103 		ERROR("%s: gate fail\n", __func__);
104 		return MTK_SIP_E_NOT_SUPPORTED;
105 	}
106 
107 	for (int i = 0; i < ARRAY_SIZE(seed); i++)
108 		rand[i] = seed[i];
109 
110 	return 0;
111 }
112 
113 static uint32_t get_true_rnd(uint32_t *val, uint32_t num)
114 {
115 	uint32_t rand[4] = {0};
116 	uint32_t ret;
117 
118 	if (val == NULL || num > ARRAY_SIZE(rand))
119 		return MTK_SIP_E_INVALID_PARAM;
120 
121 	spin_lock(&rng_lock);
122 	ret = trng_prng(rand);
123 	spin_unlock(&rng_lock);
124 
125 	for (int i = 0; i < num; i++)
126 		val[i] = rand[i];
127 
128 	return ret;
129 }
130 
131 /*
132  * plat_get_entropy - get 64-bit random number data which is used form
133  * atf early stage
134  * output - out: output 64-bit entropy combine with 2 32-bit random number
135  */
136 bool plat_get_entropy(uint64_t *out)
137 {
138 	uint32_t entropy_pool[2] = {0};
139 	uint32_t ret;
140 
141 	assert(out);
142 	assert(!check_uptr_overflow((uintptr_t)out, sizeof(*out)));
143 
144 	/* Get 2 32-bits entropy */
145 	ret = get_true_rnd(entropy_pool, ARRAY_SIZE(entropy_pool));
146 	if (ret)
147 		return false;
148 
149 	/* Output 8 bytes entropy combine with 2 32-bit random number. */
150 	*out = ((uint64_t)entropy_pool[0] << 32) | entropy_pool[1];
151 
152 	return true;
153 }
154