xref: /optee_os/core/drivers/atmel_trng.c (revision f2da02b2d29cebf903eae58e3d2b6a9e814a60c5)
1*f2da02b2SClément Léger // SPDX-License-Identifier: BSD-2-Clause
2*f2da02b2SClément Léger /*
3*f2da02b2SClément Léger  * Copyright 2021 Microchip
4*f2da02b2SClément Léger  */
5*f2da02b2SClément Léger 
6*f2da02b2SClément Léger #include <assert.h>
7*f2da02b2SClément Léger #include <drivers/clk.h>
8*f2da02b2SClément Léger #include <drivers/clk_dt.h>
9*f2da02b2SClément Léger #include <io.h>
10*f2da02b2SClément Léger #include <kernel/boot.h>
11*f2da02b2SClément Léger #include <kernel/spinlock.h>
12*f2da02b2SClément Léger #include <libfdt.h>
13*f2da02b2SClément Léger #include <matrix.h>
14*f2da02b2SClément Léger #include <platform_config.h>
15*f2da02b2SClément Léger #include <rng_support.h>
16*f2da02b2SClément Léger #include <string.h>
17*f2da02b2SClément Léger #include <tee/tee_cryp_utl.h>
18*f2da02b2SClément Léger 
19*f2da02b2SClément Léger /* Registers */
20*f2da02b2SClément Léger #define TRNG_CTRL		0x0
21*f2da02b2SClément Léger #define TRNG_CTRL_WAKEY_OFFSET	8
22*f2da02b2SClément Léger #define TRNG_CTRL_WAKEY_VALUE	0x524E47
23*f2da02b2SClément Léger 
24*f2da02b2SClément Léger #define TRNG_IER		0x10
25*f2da02b2SClément Léger #define TRNG_ISR		0x1C
26*f2da02b2SClément Léger #define TRNG_ODATA		0x50
27*f2da02b2SClément Léger 
28*f2da02b2SClément Léger static unsigned int trng_lock = SPINLOCK_UNLOCK;
29*f2da02b2SClément Léger static unsigned int trng_random_val_lock = SPINLOCK_UNLOCK;
30*f2da02b2SClément Léger static vaddr_t trng_base;
31*f2da02b2SClément Léger static uint8_t random_byte_pos;
32*f2da02b2SClément Léger static union {
33*f2da02b2SClément Léger 	uint32_t val;
34*f2da02b2SClément Léger 	uint8_t byte[sizeof(uint32_t)];
35*f2da02b2SClément Léger } random_data;
36*f2da02b2SClément Léger 
37*f2da02b2SClément Léger static uint32_t atmel_trng_read32(void)
38*f2da02b2SClément Léger {
39*f2da02b2SClément Léger 	uint32_t exceptions = 0;
40*f2da02b2SClément Léger 	uint32_t value = 0;
41*f2da02b2SClément Léger 
42*f2da02b2SClément Léger 	exceptions = cpu_spin_lock_xsave(&trng_lock);
43*f2da02b2SClément Léger 
44*f2da02b2SClément Léger 	while (!io_read32(trng_base + TRNG_ISR))
45*f2da02b2SClément Léger 		;
46*f2da02b2SClément Léger 
47*f2da02b2SClément Léger 	value = io_read32(trng_base + TRNG_ODATA);
48*f2da02b2SClément Léger 
49*f2da02b2SClément Léger 	cpu_spin_unlock_xrestore(&trng_lock, exceptions);
50*f2da02b2SClément Léger 
51*f2da02b2SClément Léger 	return value;
52*f2da02b2SClément Léger }
53*f2da02b2SClément Léger 
54*f2da02b2SClément Léger TEE_Result crypto_rng_read(void *buf, size_t len)
55*f2da02b2SClément Léger {
56*f2da02b2SClément Léger 	uint8_t *rngbuf = buf;
57*f2da02b2SClément Léger 	uint32_t val = 0;
58*f2da02b2SClément Léger 	size_t len_to_copy = 0;
59*f2da02b2SClément Léger 
60*f2da02b2SClément Léger 	assert(buf);
61*f2da02b2SClément Léger 	assert(trng_base);
62*f2da02b2SClément Léger 
63*f2da02b2SClément Léger 	while (len) {
64*f2da02b2SClément Léger 		val = atmel_trng_read32();
65*f2da02b2SClément Léger 		len_to_copy = MIN(len, sizeof(uint32_t));
66*f2da02b2SClément Léger 		memcpy(rngbuf, &val, len_to_copy);
67*f2da02b2SClément Léger 		rngbuf += len_to_copy;
68*f2da02b2SClément Léger 		len -= len_to_copy;
69*f2da02b2SClément Léger 	}
70*f2da02b2SClément Léger 
71*f2da02b2SClément Léger 	return TEE_SUCCESS;
72*f2da02b2SClément Léger }
73*f2da02b2SClément Léger 
74*f2da02b2SClément Léger uint8_t hw_get_random_byte(void)
75*f2da02b2SClément Léger {
76*f2da02b2SClément Léger 	uint32_t exceptions = 0;
77*f2da02b2SClément Léger 	uint8_t data = 0;
78*f2da02b2SClément Léger 
79*f2da02b2SClément Léger 	assert(trng_base);
80*f2da02b2SClément Léger 
81*f2da02b2SClément Léger 	exceptions = cpu_spin_lock_xsave(&trng_random_val_lock);
82*f2da02b2SClément Léger 
83*f2da02b2SClément Léger 	/*
84*f2da02b2SClément Léger 	 * The TRNG generates a whole 32 bits word every 84 cycles. To avoid
85*f2da02b2SClément Léger 	 * discarding 3 bytes at each request, request 4 bytes of random data
86*f2da02b2SClément Léger 	 * and return only 1 at each request until there is no more bytes in the
87*f2da02b2SClément Léger 	 * random_data "cache".
88*f2da02b2SClément Léger 	 */
89*f2da02b2SClément Léger 	if (!random_byte_pos)
90*f2da02b2SClément Léger 		random_data.val = atmel_trng_read32();
91*f2da02b2SClément Léger 
92*f2da02b2SClément Léger 	data = random_data.byte[random_byte_pos++];
93*f2da02b2SClément Léger 	if (random_byte_pos == sizeof(uint32_t))
94*f2da02b2SClément Léger 		random_byte_pos = 0;
95*f2da02b2SClément Léger 
96*f2da02b2SClément Léger 	cpu_spin_unlock_xrestore(&trng_random_val_lock, exceptions);
97*f2da02b2SClément Léger 
98*f2da02b2SClément Léger 	return data;
99*f2da02b2SClément Léger }
100*f2da02b2SClément Léger 
101*f2da02b2SClément Léger /* This is a true RNG, no need for seeding */
102*f2da02b2SClément Léger void plat_rng_init(void)
103*f2da02b2SClément Léger {
104*f2da02b2SClément Léger 	assert(trng_base);
105*f2da02b2SClément Léger }
106*f2da02b2SClément Léger 
107*f2da02b2SClément Léger static void atmel_trng_reset(void)
108*f2da02b2SClément Léger {
109*f2da02b2SClément Léger 	uint32_t ctrl_val = TRNG_CTRL_WAKEY_VALUE << TRNG_CTRL_WAKEY_OFFSET;
110*f2da02b2SClément Léger 
111*f2da02b2SClément Léger 	/* Disable TRNG */
112*f2da02b2SClément Léger 	io_setbits32(trng_base + TRNG_CTRL, ctrl_val);
113*f2da02b2SClément Léger 	/* Enable interrupt */
114*f2da02b2SClément Léger 	io_setbits32(trng_base + TRNG_IER, 1);
115*f2da02b2SClément Léger 	/* Enable TRNG */
116*f2da02b2SClément Léger 	io_setbits32(trng_base + TRNG_CTRL, ctrl_val | 1);
117*f2da02b2SClément Léger }
118*f2da02b2SClément Léger 
119*f2da02b2SClément Léger static TEE_Result trng_node_probe(const void *fdt, int node,
120*f2da02b2SClément Léger 				  const void *compat_data __unused)
121*f2da02b2SClément Léger {
122*f2da02b2SClément Léger 	int status = _fdt_get_status(fdt, node);
123*f2da02b2SClément Léger 	size_t size = 0;
124*f2da02b2SClément Léger 	struct clk *clk = NULL;
125*f2da02b2SClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
126*f2da02b2SClément Léger 
127*f2da02b2SClément Léger 	if (status != DT_STATUS_OK_SEC)
128*f2da02b2SClément Léger 		return TEE_ERROR_GENERIC;
129*f2da02b2SClément Léger 
130*f2da02b2SClément Léger 	matrix_configure_periph_secure(AT91C_ID_TRNG);
131*f2da02b2SClément Léger 
132*f2da02b2SClément Léger 	clk = clk_dt_get_by_idx(fdt, node, 0, &res);
133*f2da02b2SClément Léger 	if (res)
134*f2da02b2SClément Léger 		return res;
135*f2da02b2SClément Léger 
136*f2da02b2SClément Léger 	if (dt_map_dev(fdt, node, &trng_base, &size) < 0)
137*f2da02b2SClément Léger 		return TEE_ERROR_GENERIC;
138*f2da02b2SClément Léger 
139*f2da02b2SClément Léger 	clk_enable(clk);
140*f2da02b2SClément Léger 
141*f2da02b2SClément Léger 	atmel_trng_reset();
142*f2da02b2SClément Léger 
143*f2da02b2SClément Léger 	return TEE_SUCCESS;
144*f2da02b2SClément Léger }
145*f2da02b2SClément Léger 
146*f2da02b2SClément Léger static const struct dt_device_match atmel_trng_match_table[] = {
147*f2da02b2SClément Léger 	{ .compatible = "atmel,at91sam9g45-trng" },
148*f2da02b2SClément Léger 	{ }
149*f2da02b2SClément Léger };
150*f2da02b2SClément Léger 
151*f2da02b2SClément Léger const struct dt_driver atmel_trng_dt_driver __dt_driver = {
152*f2da02b2SClément Léger 	.name = "atmel_trng",
153*f2da02b2SClément Léger 	.type = DT_DRIVER_NOTYPE,
154*f2da02b2SClément Léger 	.match_table = atmel_trng_match_table,
155*f2da02b2SClément Léger 	.probe = trng_node_probe,
156*f2da02b2SClément Léger };
157