xref: /optee_os/core/drivers/hisi_trng.c (revision 7e679511f069539eb18cd0689765f84963e754f5)
1*7e679511SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2fb5592f9Sloubaihui /* Copyright (c) 2023 HiSilicon Limited. */
3fb5592f9Sloubaihui 
4fb5592f9Sloubaihui #include <initcall.h>
5fb5592f9Sloubaihui #include <io.h>
6fb5592f9Sloubaihui #include <kernel/spinlock.h>
7fb5592f9Sloubaihui #include <malloc.h>
8fb5592f9Sloubaihui #include <mm/core_memprot.h>
9fb5592f9Sloubaihui #include <platform_config.h>
10fb5592f9Sloubaihui #include <rng_support.h>
119b72ef09Sloubaihui #include <string.h>
12fb5592f9Sloubaihui 
13fb5592f9Sloubaihui #define HTRNG_RANDATA_REG 0xF0
149b72ef09Sloubaihui #define HTRNG_BYTES 4U
15fb5592f9Sloubaihui 
16fb5592f9Sloubaihui #define POLL_PERIOD 10
17fb5592f9Sloubaihui #define POLL_TIMEOUT 1000
18fb5592f9Sloubaihui 
19fb5592f9Sloubaihui struct hisi_trng {
20fb5592f9Sloubaihui 	vaddr_t base;
21fb5592f9Sloubaihui };
22fb5592f9Sloubaihui 
23fb5592f9Sloubaihui static unsigned int trng_lock = SPINLOCK_UNLOCK;
24fb5592f9Sloubaihui static struct hisi_trng *trng_dev;
25fb5592f9Sloubaihui 
trng_read(uint32_t * val)26fb5592f9Sloubaihui static TEE_Result trng_read(uint32_t *val)
27fb5592f9Sloubaihui {
28fb5592f9Sloubaihui 	TEE_Result ret = TEE_SUCCESS;
29fb5592f9Sloubaihui 	uint32_t exceptions = 0;
30fb5592f9Sloubaihui 
31fb5592f9Sloubaihui 	exceptions = cpu_spin_lock_xsave(&trng_lock);
32fb5592f9Sloubaihui 	if (IO_READ32_POLL_TIMEOUT(trng_dev->base + HTRNG_RANDATA_REG,
339b72ef09Sloubaihui 				   *val, *val, POLL_PERIOD, POLL_TIMEOUT)) {
347d41fd4cSloubaihui 		EMSG("Hardware busy");
35fb5592f9Sloubaihui 		ret = TEE_ERROR_BUSY;
36fb5592f9Sloubaihui 	}
37fb5592f9Sloubaihui 	cpu_spin_unlock_xrestore(&trng_lock, exceptions);
38fb5592f9Sloubaihui 
39fb5592f9Sloubaihui 	return ret;
40fb5592f9Sloubaihui }
41fb5592f9Sloubaihui 
hw_get_random_bytes(void * buf,size_t len)42fb5592f9Sloubaihui TEE_Result hw_get_random_bytes(void *buf, size_t len)
43fb5592f9Sloubaihui {
44fb5592f9Sloubaihui 	TEE_Result ret = TEE_ERROR_GENERIC;
45fb5592f9Sloubaihui 	size_t current_len = 0;
46fb5592f9Sloubaihui 	uint32_t val = 0;
479b72ef09Sloubaihui 	size_t size = 0;
48fb5592f9Sloubaihui 
49fb5592f9Sloubaihui 	if (!trng_dev) {
507d41fd4cSloubaihui 		EMSG("No valid TRNG device");
51fb5592f9Sloubaihui 		return TEE_ERROR_NOT_SUPPORTED;
52fb5592f9Sloubaihui 	}
53fb5592f9Sloubaihui 
54fb5592f9Sloubaihui 	if (!buf || !len) {
557d41fd4cSloubaihui 		EMSG("Invalid input parameter");
56fb5592f9Sloubaihui 		return TEE_ERROR_BAD_PARAMETERS;
57fb5592f9Sloubaihui 	}
58fb5592f9Sloubaihui 
59fb5592f9Sloubaihui 	while (current_len < len) {
60fb5592f9Sloubaihui 		ret = trng_read(&val);
61fb5592f9Sloubaihui 		if (ret)
62fb5592f9Sloubaihui 			return TEE_ERROR_BUSY;
63fb5592f9Sloubaihui 
64fb5592f9Sloubaihui 		size = MIN(HTRNG_BYTES, len - current_len);
65fb5592f9Sloubaihui 		memcpy((uint8_t *)buf + current_len, &val, size);
66fb5592f9Sloubaihui 		current_len += size;
67fb5592f9Sloubaihui 	}
68fb5592f9Sloubaihui 
69fb5592f9Sloubaihui 	return TEE_SUCCESS;
70fb5592f9Sloubaihui }
71fb5592f9Sloubaihui 
trng_init(void)72fb5592f9Sloubaihui static TEE_Result trng_init(void)
73fb5592f9Sloubaihui {
747d41fd4cSloubaihui 	DMSG("TRNG driver init start");
75fb5592f9Sloubaihui 	trng_dev = calloc(1, sizeof(struct hisi_trng));
76fb5592f9Sloubaihui 	if (!trng_dev) {
777d41fd4cSloubaihui 		EMSG("Fail to calloc trng device");
78fb5592f9Sloubaihui 		return TEE_ERROR_OUT_OF_MEMORY;
79fb5592f9Sloubaihui 	}
80fb5592f9Sloubaihui 
819b72ef09Sloubaihui 	trng_dev->base = (vaddr_t)phys_to_virt_io(HISI_TRNG_BASE,
829b72ef09Sloubaihui 						  HISI_TRNG_SIZE);
83fb5592f9Sloubaihui 	if (!trng_dev->base) {
847d41fd4cSloubaihui 		EMSG("Fail to get trng io_base");
85fb5592f9Sloubaihui 		free(trng_dev);
86fb5592f9Sloubaihui 		trng_dev = NULL;
87fb5592f9Sloubaihui 		return TEE_ERROR_ACCESS_DENIED;
88fb5592f9Sloubaihui 	}
89fb5592f9Sloubaihui 
907d41fd4cSloubaihui 	DMSG("TRNG driver init done");
91fb5592f9Sloubaihui 
92fb5592f9Sloubaihui 	return TEE_SUCCESS;
93fb5592f9Sloubaihui }
94fb5592f9Sloubaihui 
95fb5592f9Sloubaihui early_init(trng_init);
96