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