xref: /optee_os/core/drivers/xiphera_trng.c (revision bc8427916ab0fb8bb4ba1cf49e857edbce4b2487)
174c676beSVesa Jääskeläinen // SPDX-License-Identifier: BSD-2-Clause
274c676beSVesa Jääskeläinen /*
374c676beSVesa Jääskeläinen  * Copyright (c) 2022, Vaisala Oyj
474c676beSVesa Jääskeläinen  */
574c676beSVesa Jääskeläinen 
674c676beSVesa Jääskeläinen #include <assert.h>
774c676beSVesa Jääskeläinen #include <io.h>
874c676beSVesa Jääskeläinen #include <kernel/boot.h>
974c676beSVesa Jääskeläinen #include <kernel/delay.h>
1074c676beSVesa Jääskeläinen #include <kernel/dt.h>
1174c676beSVesa Jääskeläinen #include <kernel/dt_driver.h>
1274c676beSVesa Jääskeläinen #include <kernel/spinlock.h>
1374c676beSVesa Jääskeläinen #include <libfdt.h>
1474c676beSVesa Jääskeläinen #include <platform_config.h>
1574c676beSVesa Jääskeläinen #include <rng_support.h>
1674c676beSVesa Jääskeläinen #include <string.h>
1774c676beSVesa Jääskeläinen #include <tee/tee_cryp_utl.h>
1874c676beSVesa Jääskeläinen 
1974c676beSVesa Jääskeläinen #define CONTROL_REG                     0x00000000
2074c676beSVesa Jääskeläinen #define STATUS_REG                      0x00000004
2174c676beSVesa Jääskeläinen #define RAND_REG                        0x00000000
2274c676beSVesa Jääskeläinen 
2374c676beSVesa Jääskeläinen #define HOST_TO_TRNG_RESET              0x00000001
2474c676beSVesa Jääskeläinen #define HOST_TO_TRNG_RELEASE_RESET      0x00000002
2574c676beSVesa Jääskeläinen #define HOST_TO_TRNG_ENABLE             0x80000000
2674c676beSVesa Jääskeläinen #define HOST_TO_TRNG_ZEROIZE            0x80000004
2774c676beSVesa Jääskeläinen #define HOST_TO_TRNG_ACK_ZEROIZE        0x80000008
2874c676beSVesa Jääskeläinen #define HOST_TO_TRNG_READ               0x8000000F
2974c676beSVesa Jääskeläinen 
3074c676beSVesa Jääskeläinen /* trng statuses */
3174c676beSVesa Jääskeläinen #define TRNG_ACK_RESET                  0x000000AC
3274c676beSVesa Jääskeläinen #define TRNG_SUCCESSFUL_STARTUP         0x00000057
3374c676beSVesa Jääskeläinen #define TRNG_FAILED_STARTUP             0x000000FA
3474c676beSVesa Jääskeläinen #define TRNG_NEW_RAND_AVAILABLE         0x000000ED
3574c676beSVesa Jääskeläinen 
3674c676beSVesa Jääskeläinen static unsigned int trng_lock = SPINLOCK_UNLOCK;
3774c676beSVesa Jääskeläinen 
3874c676beSVesa Jääskeläinen static vaddr_t xiphera_trng_base;
3974c676beSVesa Jääskeläinen 
4074c676beSVesa Jääskeläinen static uint32_t xiphera_trng_read32(void)
4174c676beSVesa Jääskeläinen {
4274c676beSVesa Jääskeläinen 	uint32_t value = 0;
4374c676beSVesa Jääskeläinen 	uint32_t exceptions = 0;
4474c676beSVesa Jääskeläinen 	uint32_t status = 0;
4574c676beSVesa Jääskeläinen 
4674c676beSVesa Jääskeläinen 	while (true) {
4774c676beSVesa Jääskeläinen 		/* Wait until we have value available */
4874c676beSVesa Jääskeläinen 		status = io_read32(xiphera_trng_base + STATUS_REG);
4974c676beSVesa Jääskeläinen 		if (status != TRNG_NEW_RAND_AVAILABLE)
5074c676beSVesa Jääskeläinen 			continue;
5174c676beSVesa Jääskeläinen 
5274c676beSVesa Jääskeläinen 		value = io_read32(xiphera_trng_base + RAND_REG);
5374c676beSVesa Jääskeläinen 
5474c676beSVesa Jääskeläinen 		/*
5574c676beSVesa Jääskeläinen 		 * Ack that RNG value has been consumed and trigger new one to
5674c676beSVesa Jääskeläinen 		 * be generated
5774c676beSVesa Jääskeläinen 		 */
5874c676beSVesa Jääskeläinen 		io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_READ);
5974c676beSVesa Jääskeläinen 		io_write32(xiphera_trng_base + CONTROL_REG,
6074c676beSVesa Jääskeläinen 			   HOST_TO_TRNG_ENABLE);
6174c676beSVesa Jääskeläinen 
6274c676beSVesa Jääskeläinen 		break;
6374c676beSVesa Jääskeläinen 	}
6474c676beSVesa Jääskeläinen 
6574c676beSVesa Jääskeläinen 	return value;
6674c676beSVesa Jääskeläinen }
6774c676beSVesa Jääskeläinen 
6874c676beSVesa Jääskeläinen /* This is a true RNG, no need for seeding */
6974c676beSVesa Jääskeläinen void plat_rng_init(void)
7074c676beSVesa Jääskeläinen {
7174c676beSVesa Jääskeläinen }
7274c676beSVesa Jääskeläinen 
73*bc842791SAndrew Davis TEE_Result hw_get_random_bytes(void *buf, size_t len)
7474c676beSVesa Jääskeläinen {
75*bc842791SAndrew Davis 	static union {
76*bc842791SAndrew Davis 		uint32_t val;
77*bc842791SAndrew Davis 		uint8_t byte[4];
78*bc842791SAndrew Davis 	} fifo;
79*bc842791SAndrew Davis 	static size_t fifo_pos;
80*bc842791SAndrew Davis 	uint8_t *buffer = buf;
81*bc842791SAndrew Davis 	size_t buffer_pos = 0;
8274c676beSVesa Jääskeläinen 
8374c676beSVesa Jääskeläinen 	assert(xiphera_trng_base);
8474c676beSVesa Jääskeläinen 
85*bc842791SAndrew Davis 	while (buffer_pos < len) {
86*bc842791SAndrew Davis 		uint32_t exceptions = cpu_spin_lock_xsave(&trng_lock);
87*bc842791SAndrew Davis 
88*bc842791SAndrew Davis 		/* Refill our FIFO */
89*bc842791SAndrew Davis 		if (fifo_pos == 0)
90*bc842791SAndrew Davis 			fifo.val = xiphera_trng_read32();
91*bc842791SAndrew Davis 
92*bc842791SAndrew Davis 		buffer[buffer_pos++] = fifo.byte[fifo_pos++];
93*bc842791SAndrew Davis 		fifo_pos %= 4;
94*bc842791SAndrew Davis 
95*bc842791SAndrew Davis 		cpu_spin_unlock_xrestore(&trng_lock, exceptions);
9674c676beSVesa Jääskeläinen 	}
9774c676beSVesa Jääskeläinen 
9874c676beSVesa Jääskeläinen 	return TEE_SUCCESS;
9974c676beSVesa Jääskeläinen }
10074c676beSVesa Jääskeläinen 
10174c676beSVesa Jääskeläinen static TEE_Result xiphera_trng_probe(const void *fdt, int node,
10274c676beSVesa Jääskeläinen 				     const void *compat_data __unused)
10374c676beSVesa Jääskeläinen {
10474c676beSVesa Jääskeläinen 	int dt_status = _fdt_get_status(fdt, node);
10574c676beSVesa Jääskeläinen 	uint32_t status = 0;
10674c676beSVesa Jääskeläinen 	size_t size = 0;
10774c676beSVesa Jääskeläinen 
10874c676beSVesa Jääskeläinen 	/* Skip non-secure instances */
10974c676beSVesa Jääskeläinen 	if (dt_status != DT_STATUS_OK_SEC)
11074c676beSVesa Jääskeläinen 		return TEE_ERROR_NODE_DISABLED;
11174c676beSVesa Jääskeläinen 
11274c676beSVesa Jääskeläinen 	if (xiphera_trng_base) {
11374c676beSVesa Jääskeläinen 		EMSG("Only one secure instance is supported");
11474c676beSVesa Jääskeläinen 		return TEE_ERROR_GENERIC;
11574c676beSVesa Jääskeläinen 	}
11674c676beSVesa Jääskeläinen 
11774c676beSVesa Jääskeläinen 	if (dt_map_dev(fdt, node, &xiphera_trng_base, &size) < 0)
11874c676beSVesa Jääskeläinen 		return TEE_ERROR_GENERIC;
11974c676beSVesa Jääskeläinen 
12074c676beSVesa Jääskeläinen 	/*
12174c676beSVesa Jääskeläinen 	 * The TRNG needs to be first reset in order to provide stable
12274c676beSVesa Jääskeläinen 	 * operation.
12374c676beSVesa Jääskeläinen 	 *
12474c676beSVesa Jääskeläinen 	 * Reset of the chip should complete within 200 us but in some cases it
12574c676beSVesa Jääskeläinen 	 * could take up to 400 us. If it is not ready within 400 us assume
12674c676beSVesa Jääskeläinen 	 * there is problem.
12774c676beSVesa Jääskeläinen 	 */
12874c676beSVesa Jääskeläinen 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_RESET);
12974c676beSVesa Jääskeläinen 	udelay(200);
13074c676beSVesa Jääskeläinen 
13174c676beSVesa Jääskeläinen 	status = io_read32(xiphera_trng_base + STATUS_REG);
13274c676beSVesa Jääskeläinen 	if (status != TRNG_ACK_RESET) {
13374c676beSVesa Jääskeläinen 		/*
13474c676beSVesa Jääskeläinen 		 * Give it additional 200 us to allow it to reset.
13574c676beSVesa Jääskeläinen 		 *
13674c676beSVesa Jääskeläinen 		 * If still not done -> error out.
13774c676beSVesa Jääskeläinen 		 */
13874c676beSVesa Jääskeläinen 		udelay(200);
13974c676beSVesa Jääskeläinen 		status = io_read32(xiphera_trng_base + STATUS_REG);
14074c676beSVesa Jääskeläinen 		if (status != TRNG_ACK_RESET) {
14174c676beSVesa Jääskeläinen 			EMSG("Failed to reset TRNG\n");
14274c676beSVesa Jääskeläinen 			return TEE_ERROR_GENERIC;
14374c676beSVesa Jääskeläinen 		}
14474c676beSVesa Jääskeläinen 	}
14574c676beSVesa Jääskeläinen 
14674c676beSVesa Jääskeläinen 	/*
14774c676beSVesa Jääskeläinen 	 * Now TRNG should be internally stable.
14874c676beSVesa Jääskeläinen 	 *
14974c676beSVesa Jääskeläinen 	 * Clear internal random number generation engine to start in stable
15074c676beSVesa Jääskeläinen 	 * state and give it 20 ms to enable good random number entropy and
15174c676beSVesa Jääskeläinen 	 * then check that random number engine is ready.
15274c676beSVesa Jääskeläinen 	 */
15374c676beSVesa Jääskeläinen 	io_write32(xiphera_trng_base + CONTROL_REG,
15474c676beSVesa Jääskeläinen 		   HOST_TO_TRNG_RELEASE_RESET);
15574c676beSVesa Jääskeläinen 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ENABLE);
15674c676beSVesa Jääskeläinen 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ZEROIZE);
15774c676beSVesa Jääskeläinen 	mdelay(20);
15874c676beSVesa Jääskeläinen 
15974c676beSVesa Jääskeläinen 	status = io_read32(xiphera_trng_base + STATUS_REG);
16074c676beSVesa Jääskeläinen 	if (status != TRNG_SUCCESSFUL_STARTUP) {
16174c676beSVesa Jääskeläinen 		/*
16274c676beSVesa Jääskeläinen 		 * Check specifically if there were startup test errors to aid
16374c676beSVesa Jääskeläinen 		 * in debugging TRNG implementation in FPGA
16474c676beSVesa Jääskeläinen 		 */
16574c676beSVesa Jääskeläinen 		if (status == TRNG_FAILED_STARTUP) {
16674c676beSVesa Jääskeläinen 			EMSG("Startup tests have failed\n");
16774c676beSVesa Jääskeläinen 			return TEE_ERROR_GENERIC;
16874c676beSVesa Jääskeläinen 		}
16974c676beSVesa Jääskeläinen 
17074c676beSVesa Jääskeläinen 		EMSG("Startup tests yielded no response -> TRNG stuck\n");
17174c676beSVesa Jääskeläinen 		return TEE_ERROR_GENERIC;
17274c676beSVesa Jääskeläinen 	}
17374c676beSVesa Jääskeläinen 
17474c676beSVesa Jääskeläinen 	io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ACK_ZEROIZE);
17574c676beSVesa Jääskeläinen 
17674c676beSVesa Jääskeläinen 	DMSG("TRNG initialized\n");
17774c676beSVesa Jääskeläinen 
17874c676beSVesa Jääskeläinen 	return TEE_SUCCESS;
17974c676beSVesa Jääskeläinen }
18074c676beSVesa Jääskeläinen 
18174c676beSVesa Jääskeläinen static const struct dt_device_match xiphera_trng_match_table[] = {
18274c676beSVesa Jääskeläinen 	{ .compatible = "xiphera,xip8001b-trng" },
18374c676beSVesa Jääskeläinen 	{ }
18474c676beSVesa Jääskeläinen };
18574c676beSVesa Jääskeläinen 
18674c676beSVesa Jääskeläinen DEFINE_DT_DRIVER(xiphera_trng_dt_driver) = {
18774c676beSVesa Jääskeläinen 	.name = "xiphera_trng",
18874c676beSVesa Jääskeläinen 	.type = DT_DRIVER_NOTYPE,
18974c676beSVesa Jääskeläinen 	.match_table = xiphera_trng_match_table,
19074c676beSVesa Jääskeläinen 	.probe = xiphera_trng_probe,
19174c676beSVesa Jääskeläinen };
192