xref: /optee_os/core/drivers/atmel_trng.c (revision 9194d279f018f1905a562d026cb2a7d7cd79b9a6)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2021 Microchip
4  */
5 
6 #include <assert.h>
7 #include <drivers/clk.h>
8 #include <drivers/clk_dt.h>
9 #include <io.h>
10 #include <kernel/boot.h>
11 #include <kernel/spinlock.h>
12 #include <libfdt.h>
13 #include <matrix.h>
14 #include <platform_config.h>
15 #include <rng_support.h>
16 #include <string.h>
17 #include <tee/tee_cryp_utl.h>
18 
19 /* Registers */
20 #define TRNG_CTRL		0x0
21 #define TRNG_CTRL_WAKEY_OFFSET	8
22 #define TRNG_CTRL_WAKEY_VALUE	0x524E47
23 
24 #define TRNG_IER		0x10
25 #define TRNG_ISR		0x1C
26 #define TRNG_ODATA		0x50
27 
28 static unsigned int trng_lock = SPINLOCK_UNLOCK;
29 static vaddr_t trng_base;
30 
atmel_trng_read32(void)31 static uint32_t atmel_trng_read32(void)
32 {
33 	uint32_t exceptions = 0;
34 	uint32_t value = 0;
35 
36 	exceptions = cpu_spin_lock_xsave(&trng_lock);
37 
38 	while (!io_read32(trng_base + TRNG_ISR))
39 		;
40 
41 	value = io_read32(trng_base + TRNG_ODATA);
42 
43 	cpu_spin_unlock_xrestore(&trng_lock, exceptions);
44 
45 	return value;
46 }
47 
hw_get_random_bytes(void * buf,size_t len)48 TEE_Result hw_get_random_bytes(void *buf, size_t len)
49 {
50 	uint8_t *rngbuf = buf;
51 	uint32_t val = 0;
52 	size_t len_to_copy = 0;
53 
54 	assert(trng_base);
55 
56 	while (len) {
57 		val = atmel_trng_read32();
58 		len_to_copy = MIN(len, sizeof(uint32_t));
59 		memcpy(rngbuf, &val, len_to_copy);
60 		rngbuf += len_to_copy;
61 		len -= len_to_copy;
62 	}
63 
64 	return TEE_SUCCESS;
65 }
66 
atmel_trng_reset(void)67 static void atmel_trng_reset(void)
68 {
69 	uint32_t ctrl_val = TRNG_CTRL_WAKEY_VALUE << TRNG_CTRL_WAKEY_OFFSET;
70 
71 	/* Disable TRNG */
72 	io_setbits32(trng_base + TRNG_CTRL, ctrl_val);
73 	/* Enable interrupt */
74 	io_setbits32(trng_base + TRNG_IER, 1);
75 	/* Enable TRNG */
76 	io_setbits32(trng_base + TRNG_CTRL, ctrl_val | 1);
77 }
78 
trng_node_probe(const void * fdt,int node,const void * compat_data __unused)79 static TEE_Result trng_node_probe(const void *fdt, int node,
80 				  const void *compat_data __unused)
81 {
82 	int status = fdt_get_status(fdt, node);
83 	size_t size = 0;
84 	struct clk *clk = NULL;
85 	TEE_Result res = TEE_ERROR_GENERIC;
86 
87 	if (status != DT_STATUS_OK_SEC)
88 		return TEE_ERROR_GENERIC;
89 
90 	matrix_configure_periph_secure(AT91C_ID_TRNG);
91 
92 	res = clk_dt_get_by_index(fdt, node, 0, &clk);
93 	if (res)
94 		return res;
95 
96 	if (dt_map_dev(fdt, node, &trng_base, &size, DT_MAP_AUTO) < 0)
97 		return TEE_ERROR_GENERIC;
98 
99 	clk_enable(clk);
100 
101 	atmel_trng_reset();
102 
103 	return TEE_SUCCESS;
104 }
105 
106 static const struct dt_device_match atmel_trng_match_table[] = {
107 	{ .compatible = "atmel,at91sam9g45-trng" },
108 	{ .compatible = "microchip,sama7g5-trng" },
109 	{ }
110 };
111 
112 DEFINE_DT_DRIVER(atmel_trng_dt_driver) = {
113 	.name = "atmel_trng",
114 	.type = DT_DRIVER_NOTYPE,
115 	.match_table = atmel_trng_match_table,
116 	.probe = trng_node_probe,
117 };
118