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