xref: /optee_os/core/drivers/xiphera_trng.c (revision 9194d279f018f1905a562d026cb2a7d7cd79b9a6)
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 
xiphera_trng_random_available(void)40 static bool xiphera_trng_random_available(void)
41 {
42 	uint32_t status = 0;
43 
44 	status = io_read32(xiphera_trng_base + STATUS_REG);
45 
46 	return status == TRNG_NEW_RAND_AVAILABLE;
47 }
48 
xiphera_trng_read32(void)49 static uint32_t xiphera_trng_read32(void)
50 {
51 	uint32_t value = 0;
52 
53 	value = io_read32(xiphera_trng_base + RAND_REG);
54 
55 	/*
56 	 * Ack that RNG value has been consumed and trigger new one to be
57 	 * generated
58 	 */
59 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_READ);
60 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ENABLE);
61 
62 	return value;
63 }
64 
hw_get_random_bytes(void * buf,size_t len)65 TEE_Result hw_get_random_bytes(void *buf, size_t len)
66 {
67 	uint8_t *rngbuf = buf;
68 	uint32_t val = 0;
69 	size_t len_to_copy = 0;
70 
71 	assert(buf);
72 	assert(xiphera_trng_base);
73 
74 	while (len) {
75 		uint32_t exceptions = cpu_spin_lock_xsave(&trng_lock);
76 
77 		if (xiphera_trng_random_available()) {
78 			val = xiphera_trng_read32();
79 
80 			len_to_copy = MIN(len, sizeof(uint32_t));
81 			memcpy(rngbuf, &val, len_to_copy);
82 			rngbuf += len_to_copy;
83 			len -= len_to_copy;
84 		}
85 
86 		cpu_spin_unlock_xrestore(&trng_lock, exceptions);
87 	}
88 
89 	return TEE_SUCCESS;
90 }
91 
xiphera_trng_probe(const void * fdt,int node,const void * compat_data __unused)92 static TEE_Result xiphera_trng_probe(const void *fdt, int node,
93 				     const void *compat_data __unused)
94 {
95 	int dt_status = fdt_get_status(fdt, node);
96 	uint32_t status = 0;
97 	size_t size = 0;
98 
99 	/* Skip non-secure instances */
100 	if (dt_status != DT_STATUS_OK_SEC)
101 		return TEE_ERROR_NODE_DISABLED;
102 
103 	if (xiphera_trng_base) {
104 		EMSG("Only one secure instance is supported");
105 		return TEE_ERROR_GENERIC;
106 	}
107 
108 	if (dt_map_dev(fdt, node, &xiphera_trng_base, &size, DT_MAP_AUTO) < 0)
109 		return TEE_ERROR_GENERIC;
110 
111 	/*
112 	 * The TRNG needs to be first reset in order to provide stable
113 	 * operation.
114 	 *
115 	 * Reset of the chip should complete within 200 us but in some cases it
116 	 * could take up to 400 us. If it is not ready within 400 us assume
117 	 * there is problem.
118 	 */
119 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_RESET);
120 	udelay(200);
121 
122 	status = io_read32(xiphera_trng_base + STATUS_REG);
123 	if (status != TRNG_ACK_RESET) {
124 		/*
125 		 * Give it additional 200 us to allow it to reset.
126 		 *
127 		 * If still not done -> error out.
128 		 */
129 		udelay(200);
130 		status = io_read32(xiphera_trng_base + STATUS_REG);
131 		if (status != TRNG_ACK_RESET) {
132 			EMSG("Failed to reset TRNG");
133 			return TEE_ERROR_GENERIC;
134 		}
135 	}
136 
137 	/*
138 	 * Now TRNG should be internally stable.
139 	 *
140 	 * Clear internal random number generation engine to start in stable
141 	 * state and give it 20 ms to enable good random number entropy and
142 	 * then check that random number engine is ready.
143 	 */
144 	io_write32(xiphera_trng_base + CONTROL_REG,
145 		   HOST_TO_TRNG_RELEASE_RESET);
146 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ENABLE);
147 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ZEROIZE);
148 	mdelay(20);
149 
150 	status = io_read32(xiphera_trng_base + STATUS_REG);
151 	if (status != TRNG_SUCCESSFUL_STARTUP) {
152 		/*
153 		 * Check specifically if there were startup test errors to aid
154 		 * in debugging TRNG implementation in FPGA
155 		 */
156 		if (status == TRNG_FAILED_STARTUP) {
157 			EMSG("Startup tests have failed");
158 			return TEE_ERROR_GENERIC;
159 		}
160 
161 		EMSG("Startup tests yielded no response -> TRNG stuck");
162 		return TEE_ERROR_GENERIC;
163 	}
164 
165 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ACK_ZEROIZE);
166 
167 	DMSG("TRNG initialized");
168 
169 	return TEE_SUCCESS;
170 }
171 
172 static const struct dt_device_match xiphera_trng_match_table[] = {
173 	{ .compatible = "xiphera,xip8001b-trng" },
174 	{ }
175 };
176 
177 DEFINE_DT_DRIVER(xiphera_trng_dt_driver) = {
178 	.name = "xiphera_trng",
179 	.type = DT_DRIVER_NOTYPE,
180 	.match_table = xiphera_trng_match_table,
181 	.probe = xiphera_trng_probe,
182 };
183