1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * (c) 2021 Jorge Ramirez <jorge@foundries.io>, Foundries Ltd.
4 */
5
6 #include <arm.h>
7 #include <crypto/crypto.h>
8 #include <initcall.h>
9 #include <io.h>
10 #include <kernel/boot.h>
11 #include <kernel/delay.h>
12 #include <kernel/dt.h>
13 #include <kernel/panic.h>
14 #include <libfdt.h>
15 #include <mm/core_memprot.h>
16 #include <mm/core_mmu.h>
17 #include <platform_config.h>
18 #include <rng_support.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <tee/tee_cryp_utl.h>
22 #include <trace.h>
23 #include <util.h>
24
25 #define RNG_VER 0x00
26 #define RNG_CMD 0x04
27 #define RNG_CR 0x08
28 #define RNG_SR 0x0C
29 #define RNG_ESR 0x10
30 #define RNG_OUT 0x14
31
32 #define RNG_CMD_SEED BIT(1)
33 #define RNG_CMD_CLR_INT BIT(4)
34 #define RNG_CMD_CLR_ERR BIT(5)
35 #define RNG_CMD_SOFT_RESET BIT(6)
36
37 #define RNG_CR_AR BIT(4)
38 #define RNG_CR_MASK_DONE BIT(5)
39 #define RNG_CR_MASK_ERROR BIT(6)
40
41 #define RNG_SR_ST_DONE BIT(4)
42 #define RNG_SR_SEED_DONE BIT(5)
43 #define RNG_SR_ERROR BIT(16)
44 #define RNG_SR_FIFO_LEVEL_SHIFT 8
45 #define RNG_SR_FIFO_LEVEL_MASK GENMASK_32(11, RNG_SR_FIFO_LEVEL_SHIFT)
46
47 #define RNG_VER_TYPE_SHIFT 28
48 #define RNG_VER_TYPE_MASK GENMASK_32(31, RNG_VER_TYPE_SHIFT)
49
50 #define RNG_ESR_STATUS_STAT_ERR BIT(3)
51
52 #define RNG_TYPE_RNGA 0
53 #define RNG_TYPE_RNGB 1
54 #define RNG_TYPE_RNGC 2
55
56 #define SEED_TIMEOUT 2000000
57 #define IRQ_TIMEOUT 1000000
58
59 #define WORDS_IN_FIFO(__rng_sr) \
60 (((__rng_sr) & RNG_SR_FIFO_LEVEL_MASK) >> RNG_SR_FIFO_LEVEL_SHIFT)
61
62 #define RNG_TYPE(__rng_vr) \
63 (((__rng_vr) & RNG_VER_TYPE_MASK) >> RNG_VER_TYPE_SHIFT)
64
65 static struct imx_rng {
66 struct io_pa_va base;
67 size_t size;
68 bool ready;
69 uint32_t error;
70 } rngb = {
71 .base.pa = RNGB_BASE,
72 .size = 0x4000,
73 };
74
wait_for_irq(struct imx_rng * rng)75 static void wait_for_irq(struct imx_rng *rng)
76 {
77 uint64_t tref = timeout_init_us(IRQ_TIMEOUT);
78 uint32_t status = 0;
79
80 do {
81 rng->error = io_read32(rng->base.va + RNG_ESR);
82 status = io_read32(rng->base.va + RNG_SR);
83
84 if (timeout_elapsed(tref))
85 panic();
86
87 } while ((status & (RNG_SR_SEED_DONE | RNG_SR_ST_DONE)) == 0);
88 }
89
soft_reset(struct imx_rng * rng)90 static void soft_reset(struct imx_rng *rng)
91 {
92 io_setbits32(rng->base.va + RNG_CMD, RNG_CMD_SOFT_RESET);
93 }
94
irq_clear(struct imx_rng * rng)95 static void irq_clear(struct imx_rng *rng)
96 {
97 io_setbits32(rng->base.va + RNG_CMD,
98 RNG_CMD_CLR_ERR | RNG_CMD_CLR_INT);
99 }
100
irq_mask(struct imx_rng * rng)101 static void irq_mask(struct imx_rng *rng)
102 {
103 io_setbits32(rng->base.va + RNG_CR,
104 RNG_CR_MASK_DONE | RNG_CR_MASK_ERROR);
105 }
106
irq_unmask(struct imx_rng * rng)107 static void irq_unmask(struct imx_rng *rng)
108 {
109 io_clrbits32(rng->base.va + RNG_CR,
110 RNG_CR_MASK_DONE | RNG_CR_MASK_ERROR);
111 }
112
rng_seed(struct imx_rng * rng)113 static void rng_seed(struct imx_rng *rng)
114 {
115 uint64_t tref = timeout_init_us(SEED_TIMEOUT);
116
117 irq_clear(rng);
118 irq_mask(rng);
119 do {
120 irq_unmask(rng);
121 /* seed creation */
122 io_setbits32(rng->base.va + RNG_CMD, RNG_CMD_SEED);
123 wait_for_irq(rng);
124 if (rng->error)
125 soft_reset(rng);
126 else
127 irq_clear(rng);
128 irq_mask(rng);
129
130 if (timeout_elapsed(tref))
131 panic();
132 } while (rng->error);
133
134 /* configure continuous auto-reseed */
135 io_setbits32(rng->base.va + RNG_CR, RNG_CR_AR);
136 }
137
map_controller_static(void)138 static TEE_Result map_controller_static(void)
139 {
140 rngb.base.va = (vaddr_t)core_mmu_add_mapping(MEM_AREA_IO_SEC,
141 rngb.base.pa, rngb.size);
142 if (!rngb.base.va)
143 return TEE_ERROR_GENERIC;
144
145 return TEE_SUCCESS;
146 }
147
148 #if !defined(CFG_DT)
map_controller(void)149 static TEE_Result map_controller(void)
150 {
151 return map_controller_static();
152 }
153 #else
154 static const char *const rng_match_table[] = {
155 "fsl,imx25-rngb",
156 };
157
map_controller(void)158 static TEE_Result map_controller(void)
159 {
160 void *fdt = get_dt();
161 unsigned int i = 0;
162 int off = -1;
163
164 if (!fdt)
165 return map_controller_static();
166
167 for (i = 0; i < ARRAY_SIZE(rng_match_table); i++) {
168 off = fdt_node_offset_by_compatible(fdt, 0, rng_match_table[i]);
169 if (off >= 0)
170 break;
171 }
172
173 if (off < 0)
174 return map_controller_static();
175
176 if (dt_enable_secure_status(fdt, off))
177 return TEE_ERROR_NOT_SUPPORTED;
178
179 if (dt_map_dev(fdt, off, &rngb.base.va, &rngb.size, DT_MAP_AUTO) < 0)
180 return TEE_ERROR_NOT_SUPPORTED;
181
182 rngb.base.pa = virt_to_phys((void *)rngb.base.va);
183
184 return TEE_SUCCESS;
185 }
186 #endif
187
hw_get_random_bytes(void * buf,size_t len)188 TEE_Result hw_get_random_bytes(void *buf, size_t len)
189 {
190 uint32_t *rngbuf = buf;
191 uint32_t status = 0;
192 uint32_t val = 0;
193
194 if (!rngb.ready)
195 return TEE_ERROR_BAD_STATE;
196
197 while (len) {
198 status = io_read32(rngb.base.va + RNG_SR);
199 if (status & RNG_SR_ERROR)
200 return TEE_ERROR_BAD_STATE;
201
202 if (WORDS_IN_FIFO(status)) {
203 val = io_read32(rngb.base.va + RNG_OUT);
204 if (len > sizeof(uint32_t)) {
205 len = len - sizeof(uint32_t);
206 memcpy(rngbuf, &val, sizeof(uint32_t));
207 rngbuf++;
208 } else {
209 memcpy(rngbuf, &val, len);
210 len = 0;
211 }
212 }
213 }
214
215 return TEE_SUCCESS;
216 }
217
plat_rng_init(void)218 void plat_rng_init(void)
219 {
220 }
221
rngb_init(void)222 static TEE_Result rngb_init(void)
223 {
224 uint32_t type = 0;
225
226 if (map_controller())
227 panic();
228
229 type = RNG_TYPE(io_read32(rngb.base.va + RNG_VER));
230 if (type != RNG_TYPE_RNGB && type != RNG_TYPE_RNGC)
231 panic();
232
233 rng_seed(&rngb);
234 rngb.ready = true;
235
236 return TEE_SUCCESS;
237 }
238
239 early_init(rngb_init);
240