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
wait_for_irq(struct imx_rng * rng)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
irq_clear(struct imx_rng * rng)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
irq_unmask(struct imx_rng * rng)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
rng_seed(struct imx_rng * rng)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
map_controller_static(void)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)
map_controller(void)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
map_controller(void)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
160a5d5bbc8SVesa 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
hw_get_random_bytes(void * buf,size_t len)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
plat_rng_init(void)199de266e27SJorge Ramirez-Ortiz void plat_rng_init(void)
200de266e27SJorge Ramirez-Ortiz {
201de266e27SJorge Ramirez-Ortiz }
202de266e27SJorge Ramirez-Ortiz
rngb_init(void)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
220*38dd9649SJorge Ramirez-Ortiz early_init(rngb_init);
221