xref: /optee_os/core/drivers/atmel_trng.c (revision cc105e35cbdcc864e5d4ad12d74f7709672e911f)
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 vaddr_t trng_base;
30f2da02b2SClément Léger 
atmel_trng_read32(void)31f2da02b2SClément Léger static uint32_t atmel_trng_read32(void)
32f2da02b2SClément Léger {
33f2da02b2SClément Léger 	uint32_t exceptions = 0;
34f2da02b2SClément Léger 	uint32_t value = 0;
35f2da02b2SClément Léger 
36f2da02b2SClément Léger 	exceptions = cpu_spin_lock_xsave(&trng_lock);
37f2da02b2SClément Léger 
38f2da02b2SClément Léger 	while (!io_read32(trng_base + TRNG_ISR))
39f2da02b2SClément Léger 		;
40f2da02b2SClément Léger 
41f2da02b2SClément Léger 	value = io_read32(trng_base + TRNG_ODATA);
42f2da02b2SClément Léger 
43f2da02b2SClément Léger 	cpu_spin_unlock_xrestore(&trng_lock, exceptions);
44f2da02b2SClément Léger 
45f2da02b2SClément Léger 	return value;
46f2da02b2SClément Léger }
47f2da02b2SClément Léger 
hw_get_random_bytes(void * buf,size_t len)488af02d37SAndrew Davis TEE_Result hw_get_random_bytes(void *buf, size_t len)
49f2da02b2SClément Léger {
50f2da02b2SClément Léger 	uint8_t *rngbuf = buf;
51f2da02b2SClément Léger 	uint32_t val = 0;
52f2da02b2SClément Léger 	size_t len_to_copy = 0;
53f2da02b2SClément Léger 
54f2da02b2SClément Léger 	assert(trng_base);
55f2da02b2SClément Léger 
56f2da02b2SClément Léger 	while (len) {
57f2da02b2SClément Léger 		val = atmel_trng_read32();
58f2da02b2SClément Léger 		len_to_copy = MIN(len, sizeof(uint32_t));
59f2da02b2SClément Léger 		memcpy(rngbuf, &val, len_to_copy);
60f2da02b2SClément Léger 		rngbuf += len_to_copy;
61f2da02b2SClément Léger 		len -= len_to_copy;
62f2da02b2SClément Léger 	}
63f2da02b2SClément Léger 
64f2da02b2SClément Léger 	return TEE_SUCCESS;
65f2da02b2SClément Léger }
66f2da02b2SClément Léger 
67f2da02b2SClément Léger /* This is a true RNG, no need for seeding */
plat_rng_init(void)68f2da02b2SClément Léger void plat_rng_init(void)
69f2da02b2SClément Léger {
70f2da02b2SClément Léger }
71f2da02b2SClément Léger 
atmel_trng_reset(void)72f2da02b2SClément Léger static void atmel_trng_reset(void)
73f2da02b2SClément Léger {
74f2da02b2SClément Léger 	uint32_t ctrl_val = TRNG_CTRL_WAKEY_VALUE << TRNG_CTRL_WAKEY_OFFSET;
75f2da02b2SClément Léger 
76f2da02b2SClément Léger 	/* Disable TRNG */
77f2da02b2SClément Léger 	io_setbits32(trng_base + TRNG_CTRL, ctrl_val);
78f2da02b2SClément Léger 	/* Enable interrupt */
79f2da02b2SClément Léger 	io_setbits32(trng_base + TRNG_IER, 1);
80f2da02b2SClément Léger 	/* Enable TRNG */
81f2da02b2SClément Léger 	io_setbits32(trng_base + TRNG_CTRL, ctrl_val | 1);
82f2da02b2SClément Léger }
83f2da02b2SClément Léger 
trng_node_probe(const void * fdt,int node,const void * compat_data __unused)84f2da02b2SClément Léger static TEE_Result trng_node_probe(const void *fdt, int node,
85f2da02b2SClément Léger 				  const void *compat_data __unused)
86f2da02b2SClément Léger {
87f354a5d8SGatien Chevallier 	int status = fdt_get_status(fdt, node);
88f2da02b2SClément Léger 	size_t size = 0;
89f2da02b2SClément Léger 	struct clk *clk = NULL;
90f2da02b2SClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
91f2da02b2SClément Léger 
92f2da02b2SClément Léger 	if (status != DT_STATUS_OK_SEC)
93f2da02b2SClément Léger 		return TEE_ERROR_GENERIC;
94f2da02b2SClément Léger 
95f2da02b2SClément Léger 	matrix_configure_periph_secure(AT91C_ID_TRNG);
96f2da02b2SClément Léger 
97056e7438SEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 0, &clk);
98f2da02b2SClément Léger 	if (res)
99f2da02b2SClément Léger 		return res;
100f2da02b2SClément Léger 
101a5d5bbc8SVesa Jääskeläinen 	if (dt_map_dev(fdt, node, &trng_base, &size, DT_MAP_AUTO) < 0)
102f2da02b2SClément Léger 		return TEE_ERROR_GENERIC;
103f2da02b2SClément Léger 
104f2da02b2SClément Léger 	clk_enable(clk);
105f2da02b2SClément Léger 
106f2da02b2SClément Léger 	atmel_trng_reset();
107f2da02b2SClément Léger 
108f2da02b2SClément Léger 	return TEE_SUCCESS;
109f2da02b2SClément Léger }
110f2da02b2SClément Léger 
111f2da02b2SClément Léger static const struct dt_device_match atmel_trng_match_table[] = {
112f2da02b2SClément Léger 	{ .compatible = "atmel,at91sam9g45-trng" },
113*cc105e35STony Han 	{ .compatible = "microchip,sama7g5-trng" },
114f2da02b2SClément Léger 	{ }
115f2da02b2SClément Léger };
116f2da02b2SClément Léger 
11761bdedeaSJerome Forissier DEFINE_DT_DRIVER(atmel_trng_dt_driver) = {
118f2da02b2SClément Léger 	.name = "atmel_trng",
119f2da02b2SClément Léger 	.type = DT_DRIVER_NOTYPE,
120f2da02b2SClément Léger 	.match_table = atmel_trng_match_table,
121f2da02b2SClément Léger 	.probe = trng_node_probe,
122f2da02b2SClément Léger };
123