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