xref: /optee_os/core/drivers/imx_rngb.c (revision ac59b32ba611b6685830f5949ec32bd6a73fd4f7)
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