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