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