xref: /optee_os/core/drivers/xiphera_trng.c (revision ad0ae8003583f7270d62568c85a32a5f25a601c6)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2022, Vaisala Oyj
4  */
5 
6 #include <assert.h>
7 #include <io.h>
8 #include <kernel/boot.h>
9 #include <kernel/delay.h>
10 #include <kernel/dt.h>
11 #include <kernel/dt_driver.h>
12 #include <kernel/spinlock.h>
13 #include <libfdt.h>
14 #include <platform_config.h>
15 #include <rng_support.h>
16 #include <string.h>
17 #include <tee/tee_cryp_utl.h>
18 
19 #define CONTROL_REG                     0x00000000
20 #define STATUS_REG                      0x00000004
21 #define RAND_REG                        0x00000000
22 
23 #define HOST_TO_TRNG_RESET              0x00000001
24 #define HOST_TO_TRNG_RELEASE_RESET      0x00000002
25 #define HOST_TO_TRNG_ENABLE             0x80000000
26 #define HOST_TO_TRNG_ZEROIZE            0x80000004
27 #define HOST_TO_TRNG_ACK_ZEROIZE        0x80000008
28 #define HOST_TO_TRNG_READ               0x8000000F
29 
30 /* trng statuses */
31 #define TRNG_ACK_RESET                  0x000000AC
32 #define TRNG_SUCCESSFUL_STARTUP         0x00000057
33 #define TRNG_FAILED_STARTUP             0x000000FA
34 #define TRNG_NEW_RAND_AVAILABLE         0x000000ED
35 
36 static unsigned int trng_lock = SPINLOCK_UNLOCK;
37 
38 static vaddr_t xiphera_trng_base;
39 
40 static uint32_t xiphera_trng_read32(void)
41 {
42 	uint32_t value = 0;
43 	uint32_t exceptions = 0;
44 	uint32_t status = 0;
45 
46 	exceptions = cpu_spin_lock_xsave(&trng_lock);
47 
48 	while (true) {
49 		/* Wait until we have value available */
50 		status = io_read32(xiphera_trng_base + STATUS_REG);
51 		if (status != TRNG_NEW_RAND_AVAILABLE)
52 			continue;
53 
54 		value = io_read32(xiphera_trng_base + RAND_REG);
55 
56 		/*
57 		 * Ack that RNG value has been consumed and trigger new one to
58 		 * be generated
59 		 */
60 		io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_READ);
61 		io_write32(xiphera_trng_base + CONTROL_REG,
62 			   HOST_TO_TRNG_ENABLE);
63 
64 		break;
65 	}
66 
67 	cpu_spin_unlock_xrestore(&trng_lock, exceptions);
68 
69 	return value;
70 }
71 
72 /* This is a true RNG, no need for seeding */
73 void plat_rng_init(void)
74 {
75 }
76 
77 TEE_Result crypto_rng_read(void *buf, size_t len)
78 {
79 	uint8_t *rngbuf = buf;
80 	uint32_t val = 0;
81 	size_t len_to_copy = 0;
82 
83 	assert(buf);
84 	assert(xiphera_trng_base);
85 
86 	while (len) {
87 		val = xiphera_trng_read32();
88 		len_to_copy = MIN(len, sizeof(uint32_t));
89 		memcpy(rngbuf, &val, len_to_copy);
90 		rngbuf += len_to_copy;
91 		len -= len_to_copy;
92 	}
93 
94 	return TEE_SUCCESS;
95 }
96 
97 uint8_t hw_get_random_byte(void)
98 {
99 	uint8_t data = 0;
100 
101 	assert(xiphera_trng_base);
102 
103 	data = xiphera_trng_read32() & 0xFF;
104 
105 	return data;
106 }
107 
108 static TEE_Result xiphera_trng_probe(const void *fdt, int node,
109 				     const void *compat_data __unused)
110 {
111 	int dt_status = _fdt_get_status(fdt, node);
112 	uint32_t status = 0;
113 	size_t size = 0;
114 
115 	/* Skip non-secure instances */
116 	if (dt_status != DT_STATUS_OK_SEC)
117 		return TEE_ERROR_NODE_DISABLED;
118 
119 	if (xiphera_trng_base) {
120 		EMSG("Only one secure instance is supported");
121 		return TEE_ERROR_GENERIC;
122 	}
123 
124 	if (dt_map_dev(fdt, node, &xiphera_trng_base, &size) < 0)
125 		return TEE_ERROR_GENERIC;
126 
127 	/*
128 	 * The TRNG needs to be first reset in order to provide stable
129 	 * operation.
130 	 *
131 	 * Reset of the chip should complete within 200 us but in some cases it
132 	 * could take up to 400 us. If it is not ready within 400 us assume
133 	 * there is problem.
134 	 */
135 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_RESET);
136 	udelay(200);
137 
138 	status = io_read32(xiphera_trng_base + STATUS_REG);
139 	if (status != TRNG_ACK_RESET) {
140 		/*
141 		 * Give it additional 200 us to allow it to reset.
142 		 *
143 		 * If still not done -> error out.
144 		 */
145 		udelay(200);
146 		status = io_read32(xiphera_trng_base + STATUS_REG);
147 		if (status != TRNG_ACK_RESET) {
148 			EMSG("Failed to reset TRNG\n");
149 			return TEE_ERROR_GENERIC;
150 		}
151 	}
152 
153 	/*
154 	 * Now TRNG should be internally stable.
155 	 *
156 	 * Clear internal random number generation engine to start in stable
157 	 * state and give it 20 ms to enable good random number entropy and
158 	 * then check that random number engine is ready.
159 	 */
160 	io_write32(xiphera_trng_base + CONTROL_REG,
161 		   HOST_TO_TRNG_RELEASE_RESET);
162 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ENABLE);
163 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ZEROIZE);
164 	mdelay(20);
165 
166 	status = io_read32(xiphera_trng_base + STATUS_REG);
167 	if (status != TRNG_SUCCESSFUL_STARTUP) {
168 		/*
169 		 * Check specifically if there were startup test errors to aid
170 		 * in debugging TRNG implementation in FPGA
171 		 */
172 		if (status == TRNG_FAILED_STARTUP) {
173 			EMSG("Startup tests have failed\n");
174 			return TEE_ERROR_GENERIC;
175 		}
176 
177 		EMSG("Startup tests yielded no response -> TRNG stuck\n");
178 		return TEE_ERROR_GENERIC;
179 	}
180 
181 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ACK_ZEROIZE);
182 
183 	DMSG("TRNG initialized\n");
184 
185 	return TEE_SUCCESS;
186 }
187 
188 static const struct dt_device_match xiphera_trng_match_table[] = {
189 	{ .compatible = "xiphera,xip8001b-trng" },
190 	{ }
191 };
192 
193 DEFINE_DT_DRIVER(xiphera_trng_dt_driver) = {
194 	.name = "xiphera_trng",
195 	.type = DT_DRIVER_NOTYPE,
196 	.match_table = xiphera_trng_match_table,
197 	.probe = xiphera_trng_probe,
198 };
199