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