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 unsigned int trng_random_val_lock = SPINLOCK_UNLOCK;
30 static vaddr_t trng_base;
31 static uint8_t random_byte_pos;
32 static union {
33 	uint32_t val;
34 	uint8_t byte[sizeof(uint32_t)];
35 } random_data;
36 
atmel_trng_read32(void)37 static uint32_t atmel_trng_read32(void)
38 {
39 	uint32_t exceptions = 0;
40 	uint32_t value = 0;
41 
42 	exceptions = cpu_spin_lock_xsave(&trng_lock);
43 
44 	while (!io_read32(trng_base + TRNG_ISR))
45 		;
46 
47 	value = io_read32(trng_base + TRNG_ODATA);
48 
49 	cpu_spin_unlock_xrestore(&trng_lock, exceptions);
50 
51 	return value;
52 }
53 
crypto_rng_read(void * buf,size_t len)54 TEE_Result crypto_rng_read(void *buf, size_t len)
55 {
56 	uint8_t *rngbuf = buf;
57 	uint32_t val = 0;
58 	size_t len_to_copy = 0;
59 
60 	assert(buf);
61 	assert(trng_base);
62 
63 	while (len) {
64 		val = atmel_trng_read32();
65 		len_to_copy = MIN(len, sizeof(uint32_t));
66 		memcpy(rngbuf, &val, len_to_copy);
67 		rngbuf += len_to_copy;
68 		len -= len_to_copy;
69 	}
70 
71 	return TEE_SUCCESS;
72 }
73 
hw_get_random_byte(void)74 uint8_t hw_get_random_byte(void)
75 {
76 	uint32_t exceptions = 0;
77 	uint8_t data = 0;
78 
79 	assert(trng_base);
80 
81 	exceptions = cpu_spin_lock_xsave(&trng_random_val_lock);
82 
83 	/*
84 	 * The TRNG generates a whole 32 bits word every 84 cycles. To avoid
85 	 * discarding 3 bytes at each request, request 4 bytes of random data
86 	 * and return only 1 at each request until there is no more bytes in the
87 	 * random_data "cache".
88 	 */
89 	if (!random_byte_pos)
90 		random_data.val = atmel_trng_read32();
91 
92 	data = random_data.byte[random_byte_pos++];
93 	if (random_byte_pos == sizeof(uint32_t))
94 		random_byte_pos = 0;
95 
96 	cpu_spin_unlock_xrestore(&trng_random_val_lock, exceptions);
97 
98 	return data;
99 }
100 
101 /* This is a true RNG, no need for seeding */
plat_rng_init(void)102 void plat_rng_init(void)
103 {
104 }
105 
atmel_trng_reset(void)106 static void atmel_trng_reset(void)
107 {
108 	uint32_t ctrl_val = TRNG_CTRL_WAKEY_VALUE << TRNG_CTRL_WAKEY_OFFSET;
109 
110 	/* Disable TRNG */
111 	io_setbits32(trng_base + TRNG_CTRL, ctrl_val);
112 	/* Enable interrupt */
113 	io_setbits32(trng_base + TRNG_IER, 1);
114 	/* Enable TRNG */
115 	io_setbits32(trng_base + TRNG_CTRL, ctrl_val | 1);
116 }
117 
trng_node_probe(const void * fdt,int node,const void * compat_data __unused)118 static TEE_Result trng_node_probe(const void *fdt, int node,
119 				  const void *compat_data __unused)
120 {
121 	int status = _fdt_get_status(fdt, node);
122 	size_t size = 0;
123 	struct clk *clk = NULL;
124 	TEE_Result res = TEE_ERROR_GENERIC;
125 
126 	if (status != DT_STATUS_OK_SEC)
127 		return TEE_ERROR_GENERIC;
128 
129 	matrix_configure_periph_secure(AT91C_ID_TRNG);
130 
131 	res = clk_dt_get_by_index(fdt, node, 0, &clk);
132 	if (res)
133 		return res;
134 
135 	if (dt_map_dev(fdt, node, &trng_base, &size) < 0)
136 		return TEE_ERROR_GENERIC;
137 
138 	clk_enable(clk);
139 
140 	atmel_trng_reset();
141 
142 	return TEE_SUCCESS;
143 }
144 
145 static const struct dt_device_match atmel_trng_match_table[] = {
146 	{ .compatible = "atmel,at91sam9g45-trng" },
147 	{ }
148 };
149 
150 DEFINE_DT_DRIVER(atmel_trng_dt_driver) = {
151 	.name = "atmel_trng",
152 	.type = DT_DRIVER_NOTYPE,
153 	.match_table = atmel_trng_match_table,
154 	.probe = trng_node_probe,
155 };
156