xref: /optee_os/core/drivers/hisi_trng.c (revision 17a66904a791447da1356331f01e7c1ca25329be)
1 // SPDX-License-Identifier: GPL-2.0
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 
12 #define HTRNG_RANDATA_REG 0xF0
13 #define HTRNG_BYTES 4
14 
15 #define POLL_PERIOD 10
16 #define POLL_TIMEOUT 1000
17 
18 struct hisi_trng {
19 	vaddr_t base;
20 };
21 
22 static unsigned int trng_lock = SPINLOCK_UNLOCK;
23 static struct hisi_trng *trng_dev;
24 
25 static TEE_Result trng_read(uint32_t *val)
26 {
27 	TEE_Result ret = TEE_SUCCESS;
28 	uint32_t exceptions = 0;
29 
30 	exceptions = cpu_spin_lock_xsave(&trng_lock);
31 	if (IO_READ32_POLL_TIMEOUT(trng_dev->base + HTRNG_RANDATA_REG,
32 				   val, val, POLL_PERIOD, POLL_TIMEOUT)) {
33 		EMSG("Hardware busy.");
34 		ret = TEE_ERROR_BUSY;
35 	}
36 	cpu_spin_unlock_xrestore(&trng_lock, exceptions);
37 
38 	return ret;
39 }
40 
41 TEE_Result hw_get_random_bytes(void *buf, size_t len)
42 {
43 	TEE_Result ret = TEE_ERROR_GENERIC;
44 	size_t current_len = 0;
45 	uint32_t val = 0;
46 
47 	if (!trng_dev) {
48 		EMSG("No valid TRNG device.");
49 		return TEE_ERROR_NOT_SUPPORTED;
50 	}
51 
52 	if (!buf || !len) {
53 		EMSG("Invalid input parameter.");
54 		return TEE_ERROR_BAD_PARAMETERS;
55 	}
56 
57 	while (current_len < len) {
58 		ret = trng_read(&val);
59 		if (ret)
60 			return TEE_ERROR_BUSY;
61 
62 		size = MIN(HTRNG_BYTES, len - current_len);
63 		memcpy((uint8_t *)buf + current_len, &val, size);
64 		current_len += size;
65 	}
66 
67 	return TEE_SUCCESS;
68 }
69 
70 static TEE_Result trng_init(void)
71 {
72 	TEE_Result ret = TEE_ERROR_GENERIC;
73 
74 	IMSG("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->base = (vaddr_t)phys_to_virt_io(HISI_TRNG_BASE, HISI_TRNG_SIZE);
82 	if (!trng_dev->base) {
83 		EMSG("Fail to get trng io_base.");
84 		free(trng_dev);
85 		trng_dev = NULL;
86 		return TEE_ERROR_ACCESS_DENIED;
87 	}
88 
89 	DMSG("TRNG driver init done.");
90 
91 	return TEE_SUCCESS;
92 }
93 
94 early_init(trng_init);
95