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