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
67 /* This is a true RNG, no need for seeding */
plat_rng_init(void)68 void plat_rng_init(void)
69 {
70 }
71
atmel_trng_reset(void)72 static void atmel_trng_reset(void)
73 {
74 uint32_t ctrl_val = TRNG_CTRL_WAKEY_VALUE << TRNG_CTRL_WAKEY_OFFSET;
75
76 /* Disable TRNG */
77 io_setbits32(trng_base + TRNG_CTRL, ctrl_val);
78 /* Enable interrupt */
79 io_setbits32(trng_base + TRNG_IER, 1);
80 /* Enable TRNG */
81 io_setbits32(trng_base + TRNG_CTRL, ctrl_val | 1);
82 }
83
trng_node_probe(const void * fdt,int node,const void * compat_data __unused)84 static TEE_Result trng_node_probe(const void *fdt, int node,
85 const void *compat_data __unused)
86 {
87 int status = _fdt_get_status(fdt, node);
88 size_t size = 0;
89 struct clk *clk = NULL;
90 TEE_Result res = TEE_ERROR_GENERIC;
91
92 if (status != DT_STATUS_OK_SEC)
93 return TEE_ERROR_GENERIC;
94
95 matrix_configure_periph_secure(AT91C_ID_TRNG);
96
97 res = clk_dt_get_by_index(fdt, node, 0, &clk);
98 if (res)
99 return res;
100
101 if (dt_map_dev(fdt, node, &trng_base, &size, DT_MAP_AUTO) < 0)
102 return TEE_ERROR_GENERIC;
103
104 clk_enable(clk);
105
106 atmel_trng_reset();
107
108 return TEE_SUCCESS;
109 }
110
111 static const struct dt_device_match atmel_trng_match_table[] = {
112 { .compatible = "atmel,at91sam9g45-trng" },
113 { }
114 };
115
116 DEFINE_DT_DRIVER(atmel_trng_dt_driver) = {
117 .name = "atmel_trng",
118 .type = DT_DRIVER_NOTYPE,
119 .match_table = atmel_trng_match_table,
120 .probe = trng_node_probe,
121 };
122