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