xref: /optee_os/core/drivers/stm32_rng.c (revision 091ef005ee68fc6aace41f5666448c1343e43314)
1f3c22059SEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause
2f3c22059SEtienne Carriere /*
3ea8ba295SGatien Chevallier  * Copyright (c) 2018-2023, STMicroelectronics
4f3c22059SEtienne Carriere  */
5f3c22059SEtienne Carriere 
6f3c22059SEtienne Carriere #include <assert.h>
7d7a1a7d2SEtienne Carriere #include <drivers/clk.h>
8d7a1a7d2SEtienne Carriere #include <drivers/clk_dt.h>
9ea8ba295SGatien Chevallier #include <drivers/rstctrl.h>
10f3c22059SEtienne Carriere #include <drivers/stm32_rng.h>
11f3c22059SEtienne Carriere #include <io.h>
12f3c22059SEtienne Carriere #include <kernel/delay.h>
13a2fc83d1SJerome Forissier #include <kernel/dt.h>
14ea8ba295SGatien Chevallier #include <kernel/dt_driver.h>
1565401337SJens Wiklander #include <kernel/boot.h>
16f3c22059SEtienne Carriere #include <kernel/panic.h>
1765b5ada4SMarouene Boubakri #include <kernel/thread.h>
18a2fc83d1SJerome Forissier #include <libfdt.h>
19f3c22059SEtienne Carriere #include <mm/core_memprot.h>
20097f329aSEtienne Carriere #include <rng_support.h>
21f3c22059SEtienne Carriere #include <stdbool.h>
22f3c22059SEtienne Carriere #include <stm32_util.h>
23f3c22059SEtienne Carriere #include <string.h>
24cd451498SEtienne Carriere #include <tee/tee_cryp_utl.h>
25f3c22059SEtienne Carriere 
260817aa6fSGatien Chevallier #define RNG_CR			U(0x00)
270817aa6fSGatien Chevallier #define RNG_SR			U(0x04)
280817aa6fSGatien Chevallier #define RNG_DR			U(0x08)
29f3c22059SEtienne Carriere 
30f3c22059SEtienne Carriere #define RNG_CR_RNGEN		BIT(2)
31f3c22059SEtienne Carriere #define RNG_CR_IE		BIT(3)
32f3c22059SEtienne Carriere #define RNG_CR_CED		BIT(5)
33*091ef005SGatien Chevallier #define RNG_CR_CLKDIV		GENMASK_32(19, 16)
34*091ef005SGatien Chevallier #define RNG_CR_CLKDIV_SHIFT	U(16)
35*091ef005SGatien Chevallier #define RNG_CR_CONDRST		BIT(30)
36f3c22059SEtienne Carriere 
37f3c22059SEtienne Carriere #define RNG_SR_DRDY		BIT(0)
38f3c22059SEtienne Carriere #define RNG_SR_CECS		BIT(1)
39f3c22059SEtienne Carriere #define RNG_SR_SECS		BIT(2)
40f3c22059SEtienne Carriere #define RNG_SR_CEIS		BIT(5)
41f3c22059SEtienne Carriere #define RNG_SR_SEIS		BIT(6)
42f3c22059SEtienne Carriere 
430817aa6fSGatien Chevallier #if TRACE_LEVEL > TRACE_DEBUG
440817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US	U(100000)
450817aa6fSGatien Chevallier #else
460817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US	U(10000)
470817aa6fSGatien Chevallier #endif
48ea8ba295SGatien Chevallier #define RNG_RESET_TIMEOUT_US	U(1000)
49f3c22059SEtienne Carriere 
500817aa6fSGatien Chevallier #define RNG_FIFO_BYTE_DEPTH	U(16)
510817aa6fSGatien Chevallier 
52*091ef005SGatien Chevallier #define RNG_NIST_CONFIG_A	U(0x0F00D00)
53*091ef005SGatien Chevallier #define RNG_NIST_CONFIG_B	U(0x1801000)
54*091ef005SGatien Chevallier #define RNG_NIST_CONFIG_MASK	GENMASK_32(25, 8)
55*091ef005SGatien Chevallier 
56*091ef005SGatien Chevallier #define RNG_MAX_NOISE_CLK_FREQ	U(3000000)
57*091ef005SGatien Chevallier 
58*091ef005SGatien Chevallier struct stm32_rng_driver_data {
59*091ef005SGatien Chevallier 	bool has_cond_reset;
60*091ef005SGatien Chevallier };
61*091ef005SGatien Chevallier 
62f3c22059SEtienne Carriere struct stm32_rng_instance {
63f3c22059SEtienne Carriere 	struct io_pa_va base;
64d7a1a7d2SEtienne Carriere 	struct clk *clock;
65ea8ba295SGatien Chevallier 	struct rstctrl *rstctrl;
66*091ef005SGatien Chevallier 	const struct stm32_rng_driver_data *ddata;
67f3c22059SEtienne Carriere 	unsigned int lock;
68d8682c4cSEtienne Carriere 	bool release_post_boot;
69*091ef005SGatien Chevallier 	bool error_conceal;
70*091ef005SGatien Chevallier 	uint64_t error_to_ref;
71f3c22059SEtienne Carriere };
72f3c22059SEtienne Carriere 
73ea8ba295SGatien Chevallier /* Expect at most a single RNG instance */
74f3c22059SEtienne Carriere static struct stm32_rng_instance *stm32_rng;
75f3c22059SEtienne Carriere 
76f63f11bdSGatien Chevallier static vaddr_t get_base(void)
77f63f11bdSGatien Chevallier {
78f63f11bdSGatien Chevallier 	assert(stm32_rng);
79f63f11bdSGatien Chevallier 
80f63f11bdSGatien Chevallier 	return io_pa_or_va(&stm32_rng->base, 1);
81f63f11bdSGatien Chevallier }
82f63f11bdSGatien Chevallier 
83f3c22059SEtienne Carriere /*
84*091ef005SGatien Chevallier  * Extracts from the STM32 RNG specification when RNG supports CONDRST.
85f3c22059SEtienne Carriere  *
86f3c22059SEtienne Carriere  * When a noise source (or seed) error occurs, the RNG stops generating
87f3c22059SEtienne Carriere  * random numbers and sets to “1” both SEIS and SECS bits to indicate
88f3c22059SEtienne Carriere  * that a seed error occurred. (...)
89*091ef005SGatien Chevallier  *
90*091ef005SGatien Chevallier  * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield
91*091ef005SGatien Chevallier  * description for details). This step is needed only if SECS is set.
92*091ef005SGatien Chevallier  * Indeed, when SEIS is set and SECS is cleared it means RNG performed
93*091ef005SGatien Chevallier  * the reset automatically (auto-reset).
94*091ef005SGatien Chevallier  * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST
95*091ef005SGatien Chevallier  * to be cleared in the RNG_CR register, then confirm that SEIS is
96*091ef005SGatien Chevallier  * cleared in the RNG_SR register. Otherwise just clear SEIS bit in
97*091ef005SGatien Chevallier  * the RNG_SR register.
98*091ef005SGatien Chevallier  * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be
99*091ef005SGatien Chevallier  * cleared by RNG. The random number generation is now back to normal.
100*091ef005SGatien Chevallier  */
101*091ef005SGatien Chevallier static void conceal_seed_error_cond_reset(void)
102*091ef005SGatien Chevallier {
103*091ef005SGatien Chevallier 	struct stm32_rng_instance *dev = stm32_rng;
104*091ef005SGatien Chevallier 	vaddr_t rng_base = get_base();
105f3c22059SEtienne Carriere 
106*091ef005SGatien Chevallier 	if (!dev->error_conceal) {
107*091ef005SGatien Chevallier 		uint32_t sr = io_read32(rng_base + RNG_SR);
108*091ef005SGatien Chevallier 
109*091ef005SGatien Chevallier 		if (sr & RNG_SR_SECS) {
110*091ef005SGatien Chevallier 			/* Conceal by resetting the subsystem (step 1.) */
111*091ef005SGatien Chevallier 			io_setbits32(rng_base + RNG_CR, RNG_CR_CONDRST);
112*091ef005SGatien Chevallier 			io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST);
113*091ef005SGatien Chevallier 
114*091ef005SGatien Chevallier 			/* Arm timeout for error_conceal sequence */
115*091ef005SGatien Chevallier 			dev->error_to_ref =
116*091ef005SGatien Chevallier 				timeout_init_us(RNG_READY_TIMEOUT_US);
117*091ef005SGatien Chevallier 			dev->error_conceal = true;
118*091ef005SGatien Chevallier 		} else {
119*091ef005SGatien Chevallier 			/* RNG auto-reset (step 2.) */
120*091ef005SGatien Chevallier 			io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS);
121*091ef005SGatien Chevallier 		}
122*091ef005SGatien Chevallier 	} else {
123*091ef005SGatien Chevallier 		/* Measure time before possible reschedule */
124*091ef005SGatien Chevallier 		bool timed_out = timeout_elapsed(dev->error_to_ref);
125*091ef005SGatien Chevallier 
126*091ef005SGatien Chevallier 		/* Wait CONDRST is cleared (step 2.) */
127*091ef005SGatien Chevallier 		if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) {
128*091ef005SGatien Chevallier 			if (timed_out)
129*091ef005SGatien Chevallier 				panic();
130*091ef005SGatien Chevallier 
131*091ef005SGatien Chevallier 			/* Wait subsystem reset cycle completes */
132*091ef005SGatien Chevallier 			return;
133*091ef005SGatien Chevallier 		}
134*091ef005SGatien Chevallier 
135*091ef005SGatien Chevallier 		/* Check SEIS is cleared (step 2.) */
136*091ef005SGatien Chevallier 		if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS)
137*091ef005SGatien Chevallier 			panic();
138*091ef005SGatien Chevallier 
139*091ef005SGatien Chevallier 		/* Wait SECS is cleared (step 3.) */
140*091ef005SGatien Chevallier 		if (io_read32(rng_base + RNG_SR) & RNG_SR_SECS) {
141*091ef005SGatien Chevallier 			if (timed_out)
142*091ef005SGatien Chevallier 				panic();
143*091ef005SGatien Chevallier 
144*091ef005SGatien Chevallier 			/* Wait subsystem reset cycle completes */
145*091ef005SGatien Chevallier 			return;
146*091ef005SGatien Chevallier 		}
147*091ef005SGatien Chevallier 
148*091ef005SGatien Chevallier 		dev->error_conceal = false;
149*091ef005SGatien Chevallier 	}
150*091ef005SGatien Chevallier }
151*091ef005SGatien Chevallier 
152*091ef005SGatien Chevallier /*
153*091ef005SGatien Chevallier  * Extracts from the STM32 RNG specification, when CONDRST is not supported
154*091ef005SGatien Chevallier  *
155*091ef005SGatien Chevallier  * When a noise source (or seed) error occurs, the RNG stops generating
156*091ef005SGatien Chevallier  * random numbers and sets to “1” both SEIS and SECS bits to indicate
157*091ef005SGatien Chevallier  * that a seed error occurred. (...)
158*091ef005SGatien Chevallier  *
159f3c22059SEtienne Carriere  * The following sequence shall be used to fully recover from a seed
160f3c22059SEtienne Carriere  * error after the RNG initialization:
161f3c22059SEtienne Carriere  * 1. Clear the SEIS bit by writing it to “0”.
162f3c22059SEtienne Carriere  * 2. Read out 12 words from the RNG_DR register, and discard each of
163f3c22059SEtienne Carriere  * them in order to clean the pipeline.
164f3c22059SEtienne Carriere  * 3. Confirm that SEIS is still cleared. Random number generation is
165f3c22059SEtienne Carriere  * back to normal.
166f3c22059SEtienne Carriere  */
167*091ef005SGatien Chevallier static void conceal_seed_error_sw_reset(void)
168f3c22059SEtienne Carriere {
1696a6b6168SGatien Chevallier 	vaddr_t rng_base = get_base();
170f3c22059SEtienne Carriere 	size_t i = 0;
171f3c22059SEtienne Carriere 
1726a6b6168SGatien Chevallier 	io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS);
173f3c22059SEtienne Carriere 
174f3c22059SEtienne Carriere 	for (i = 12; i != 0; i--)
175f3c22059SEtienne Carriere 		(void)io_read32(rng_base + RNG_DR);
176f3c22059SEtienne Carriere 
177f3c22059SEtienne Carriere 	if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS)
178f3c22059SEtienne Carriere 		panic("RNG noise");
179f3c22059SEtienne Carriere }
180f3c22059SEtienne Carriere 
181*091ef005SGatien Chevallier static void conceal_seed_error(void)
182*091ef005SGatien Chevallier {
183*091ef005SGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset)
184*091ef005SGatien Chevallier 		conceal_seed_error_cond_reset();
185*091ef005SGatien Chevallier 	else
186*091ef005SGatien Chevallier 		conceal_seed_error_sw_reset();
187*091ef005SGatien Chevallier }
188*091ef005SGatien Chevallier 
189c99311c8SEtienne Carriere static TEE_Result read_available(vaddr_t rng_base, uint8_t *out, size_t *size)
190f3c22059SEtienne Carriere {
191*091ef005SGatien Chevallier 	struct stm32_rng_instance *dev = stm32_rng;
192c99311c8SEtienne Carriere 	uint8_t *buf = NULL;
193c99311c8SEtienne Carriere 	size_t req_size = 0;
194c99311c8SEtienne Carriere 	size_t len = 0;
195f3c22059SEtienne Carriere 
196*091ef005SGatien Chevallier 	if (dev->error_conceal || io_read32(rng_base + RNG_SR) & RNG_SR_SEIS)
1976a6b6168SGatien Chevallier 		conceal_seed_error();
198f3c22059SEtienne Carriere 
19923123473SEtienne Carriere 	if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) {
20023123473SEtienne Carriere 		FMSG("RNG not ready");
201c99311c8SEtienne Carriere 		return TEE_ERROR_NO_DATA;
20223123473SEtienne Carriere 	}
203f3c22059SEtienne Carriere 
20423123473SEtienne Carriere 	if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) {
20523123473SEtienne Carriere 		FMSG("RNG noise error");
206c99311c8SEtienne Carriere 		return TEE_ERROR_NO_DATA;
20723123473SEtienne Carriere 	}
208c99311c8SEtienne Carriere 
209c99311c8SEtienne Carriere 	buf = out;
210c99311c8SEtienne Carriere 	req_size = MIN(RNG_FIFO_BYTE_DEPTH, *size);
211c99311c8SEtienne Carriere 	len = req_size;
212f3c22059SEtienne Carriere 
213f3c22059SEtienne Carriere 	/* RNG is ready: read up to 4 32bit words */
214f3c22059SEtienne Carriere 	while (len) {
215f3c22059SEtienne Carriere 		uint32_t data32 = io_read32(rng_base + RNG_DR);
216f3c22059SEtienne Carriere 		size_t sz = MIN(len, sizeof(uint32_t));
217f3c22059SEtienne Carriere 
218f3c22059SEtienne Carriere 		memcpy(buf, &data32, sz);
219f3c22059SEtienne Carriere 		buf += sz;
220f3c22059SEtienne Carriere 		len -= sz;
221f3c22059SEtienne Carriere 	}
222c99311c8SEtienne Carriere 
223f3c22059SEtienne Carriere 	*size = req_size;
224f3c22059SEtienne Carriere 
225c99311c8SEtienne Carriere 	return TEE_SUCCESS;
226f3c22059SEtienne Carriere }
227f3c22059SEtienne Carriere 
228*091ef005SGatien Chevallier static uint32_t stm32_rng_clock_freq_restrain(void)
229*091ef005SGatien Chevallier {
230*091ef005SGatien Chevallier 	struct stm32_rng_instance *dev = stm32_rng;
231*091ef005SGatien Chevallier 	unsigned long clock_rate = 0;
232*091ef005SGatien Chevallier 	uint32_t clock_div = 0;
233*091ef005SGatien Chevallier 
234*091ef005SGatien Chevallier 	clock_rate = clk_get_rate(dev->clock);
235*091ef005SGatien Chevallier 
236*091ef005SGatien Chevallier 	/*
237*091ef005SGatien Chevallier 	 * Get the exponent to apply on the CLKDIV field in RNG_CR register
238*091ef005SGatien Chevallier 	 * No need to handle the case when clock-div > 0xF as it is physically
239*091ef005SGatien Chevallier 	 * impossible
240*091ef005SGatien Chevallier 	 */
241*091ef005SGatien Chevallier 	while ((clock_rate >> clock_div) > RNG_MAX_NOISE_CLK_FREQ)
242*091ef005SGatien Chevallier 		clock_div++;
243*091ef005SGatien Chevallier 
244*091ef005SGatien Chevallier 	DMSG("RNG clk rate : %lu", clk_get_rate(dev->clock) >> clock_div);
245*091ef005SGatien Chevallier 
246*091ef005SGatien Chevallier 	return clock_div;
247*091ef005SGatien Chevallier }
248*091ef005SGatien Chevallier 
249f63f11bdSGatien Chevallier static TEE_Result init_rng(void)
250f3c22059SEtienne Carriere {
251f63f11bdSGatien Chevallier 	vaddr_t rng_base = get_base();
252f63f11bdSGatien Chevallier 	uint64_t timeout_ref = 0;
253f3c22059SEtienne Carriere 
254f63f11bdSGatien Chevallier 	/* Clean error indications */
255f63f11bdSGatien Chevallier 	io_write32(rng_base + RNG_SR, 0);
256f3c22059SEtienne Carriere 
257*091ef005SGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset) {
258*091ef005SGatien Chevallier 		uint32_t clock_div = stm32_rng_clock_freq_restrain();
259*091ef005SGatien Chevallier 
260*091ef005SGatien Chevallier 		/* Update configuration fields */
261*091ef005SGatien Chevallier 		io_clrsetbits32(rng_base + RNG_CR, RNG_NIST_CONFIG_MASK,
262*091ef005SGatien Chevallier 				RNG_NIST_CONFIG_B | RNG_CR_CONDRST |
263*091ef005SGatien Chevallier 				RNG_CR_CED);
264*091ef005SGatien Chevallier 		io_clrsetbits32(rng_base + RNG_CR, RNG_CR_CLKDIV,
265*091ef005SGatien Chevallier 				clock_div << RNG_CR_CLKDIV_SHIFT);
266*091ef005SGatien Chevallier 
267*091ef005SGatien Chevallier 		/* No need to wait for RNG_CR_CONDRST toggle as we enable clk */
268*091ef005SGatien Chevallier 		io_clrsetbits32(rng_base + RNG_CR, RNG_CR_CONDRST,
269*091ef005SGatien Chevallier 				RNG_CR_RNGEN);
270*091ef005SGatien Chevallier 	} else {
271f63f11bdSGatien Chevallier 		io_setbits32(rng_base + RNG_CR, RNG_CR_RNGEN | RNG_CR_CED);
272*091ef005SGatien Chevallier 	}
273f63f11bdSGatien Chevallier 
2740817aa6fSGatien Chevallier 	timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
275f63f11bdSGatien Chevallier 	while (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY))
276f63f11bdSGatien Chevallier 		if (timeout_elapsed(timeout_ref))
277f63f11bdSGatien Chevallier 			break;
278f63f11bdSGatien Chevallier 
279f63f11bdSGatien Chevallier 	if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY))
280f63f11bdSGatien Chevallier 		return TEE_ERROR_GENERIC;
281f63f11bdSGatien Chevallier 
282f63f11bdSGatien Chevallier 	return TEE_SUCCESS;
283f3c22059SEtienne Carriere }
284f3c22059SEtienne Carriere 
285f3c22059SEtienne Carriere TEE_Result stm32_rng_read(uint8_t *out, size_t size)
286f3c22059SEtienne Carriere {
287c99311c8SEtienne Carriere 	TEE_Result rc = TEE_ERROR_GENERIC;
288c99311c8SEtienne Carriere 	bool burst_timeout = false;
289c99311c8SEtienne Carriere 	uint64_t timeout_ref = 0;
290f3c22059SEtienne Carriere 	uint32_t exceptions = 0;
291f3c22059SEtienne Carriere 	uint8_t *out_ptr = out;
292c99311c8SEtienne Carriere 	vaddr_t rng_base = 0;
293f3c22059SEtienne Carriere 	size_t out_size = 0;
294f3c22059SEtienne Carriere 
295f3c22059SEtienne Carriere 	if (!stm32_rng) {
296f3c22059SEtienne Carriere 		DMSG("No RNG");
297f3c22059SEtienne Carriere 		return TEE_ERROR_NOT_SUPPORTED;
298f3c22059SEtienne Carriere 	}
299f3c22059SEtienne Carriere 
300f63f11bdSGatien Chevallier 	clk_enable(stm32_rng->clock);
301f63f11bdSGatien Chevallier 	rng_base = get_base();
302c99311c8SEtienne Carriere 
303c99311c8SEtienne Carriere 	/* Arm timeout */
3040817aa6fSGatien Chevallier 	timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
305c99311c8SEtienne Carriere 	burst_timeout = false;
306f3c22059SEtienne Carriere 
307f3c22059SEtienne Carriere 	while (out_size < size) {
308f3c22059SEtienne Carriere 		/* Read by chunks of the size the RNG FIFO depth */
309f3c22059SEtienne Carriere 		size_t sz = size - out_size;
310f3c22059SEtienne Carriere 
311f3c22059SEtienne Carriere 		exceptions = may_spin_lock(&stm32_rng->lock);
312f3c22059SEtienne Carriere 
313c99311c8SEtienne Carriere 		rc = read_available(rng_base, out_ptr, &sz);
314c99311c8SEtienne Carriere 
315c99311c8SEtienne Carriere 		/* Raise timeout only if we failed to get some samples */
316c99311c8SEtienne Carriere 		assert(!rc || rc == TEE_ERROR_NO_DATA);
317c99311c8SEtienne Carriere 		if (rc)
318c99311c8SEtienne Carriere 			burst_timeout = timeout_elapsed(timeout_ref);
319f3c22059SEtienne Carriere 
320f3c22059SEtienne Carriere 		may_spin_unlock(&stm32_rng->lock, exceptions);
321f3c22059SEtienne Carriere 
322c99311c8SEtienne Carriere 		if (burst_timeout) {
323c99311c8SEtienne Carriere 			rc = TEE_ERROR_GENERIC;
324c99311c8SEtienne Carriere 			goto out;
325f3c22059SEtienne Carriere 		}
326f3c22059SEtienne Carriere 
327c99311c8SEtienne Carriere 		if (!rc) {
328c99311c8SEtienne Carriere 			out_size += sz;
329c99311c8SEtienne Carriere 			out_ptr += sz;
330c99311c8SEtienne Carriere 			/* Re-arm timeout */
3310817aa6fSGatien Chevallier 			timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
332c99311c8SEtienne Carriere 			burst_timeout = false;
333c99311c8SEtienne Carriere 		}
334c99311c8SEtienne Carriere 	}
335c99311c8SEtienne Carriere 
336c99311c8SEtienne Carriere out:
337c99311c8SEtienne Carriere 	assert(!rc || rc == TEE_ERROR_GENERIC);
338f63f11bdSGatien Chevallier 	clk_disable(stm32_rng->clock);
339f3c22059SEtienne Carriere 
340f3c22059SEtienne Carriere 	return rc;
341f3c22059SEtienne Carriere }
342f3c22059SEtienne Carriere 
343cd451498SEtienne Carriere #ifdef CFG_WITH_SOFTWARE_PRNG
344cd451498SEtienne Carriere /* Override weak plat_rng_init with platform handler to seed PRNG */
345cd451498SEtienne Carriere void plat_rng_init(void)
346cd451498SEtienne Carriere {
347cd451498SEtienne Carriere 	uint8_t seed[RNG_FIFO_BYTE_DEPTH] = { };
348cd451498SEtienne Carriere 
349cd451498SEtienne Carriere 	if (stm32_rng_read(seed, sizeof(seed)))
350cd451498SEtienne Carriere 		panic();
351cd451498SEtienne Carriere 
352cd451498SEtienne Carriere 	if (crypto_rng_init(seed, sizeof(seed)))
353cd451498SEtienne Carriere 		panic();
354cd451498SEtienne Carriere 
355cd451498SEtienne Carriere 	DMSG("PRNG seeded with RNG");
356cd451498SEtienne Carriere }
357cd451498SEtienne Carriere #else
358cb2478efSAndrew Davis TEE_Result hw_get_random_bytes(void *out, size_t size)
359097f329aSEtienne Carriere {
360097f329aSEtienne Carriere 	return stm32_rng_read(out, size);
361097f329aSEtienne Carriere }
362097f329aSEtienne Carriere #endif
363097f329aSEtienne Carriere 
364f3c22059SEtienne Carriere #ifdef CFG_EMBED_DTB
365ea8ba295SGatien Chevallier static TEE_Result stm32_rng_parse_fdt(const void *fdt, int node)
366f3c22059SEtienne Carriere {
367d7a1a7d2SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
368ea8ba295SGatien Chevallier 	struct dt_node_info dt_rng = { };
369f3c22059SEtienne Carriere 
370ea8ba295SGatien Chevallier 	_fdt_fill_device_info(fdt, &dt_rng, node);
371ea8ba295SGatien Chevallier 	if (dt_rng.reg == DT_INFO_INVALID_REG)
372ea8ba295SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
373f3c22059SEtienne Carriere 
374ea8ba295SGatien Chevallier 	stm32_rng->base.pa = dt_rng.reg;
375ea8ba295SGatien Chevallier 	stm32_rng->base.va = io_pa_or_va_secure(&stm32_rng->base,
376ea8ba295SGatien Chevallier 						dt_rng.reg_size);
377ea8ba295SGatien Chevallier 	assert(stm32_rng->base.va);
378f3c22059SEtienne Carriere 
379ea8ba295SGatien Chevallier 	res = rstctrl_dt_get_by_index(fdt, node, 0, &stm32_rng->rstctrl);
380ea8ba295SGatien Chevallier 	if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND)
381ea8ba295SGatien Chevallier 		return res;
38268c4a16bSEtienne Carriere 
383d7a1a7d2SEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 0, &stm32_rng->clock);
384d7a1a7d2SEtienne Carriere 	if (res)
385d7a1a7d2SEtienne Carriere 		return res;
386d7a1a7d2SEtienne Carriere 
387ea8ba295SGatien Chevallier 	/* Release device if not used at runtime or for pm transitions */
388ea8ba295SGatien Chevallier 	stm32_rng->release_post_boot = IS_ENABLED(CFG_WITH_SOFTWARE_PRNG) &&
389ea8ba295SGatien Chevallier 				       !IS_ENABLED(CFG_PM);
390f3c22059SEtienne Carriere 
391f3c22059SEtienne Carriere 	return TEE_SUCCESS;
392f3c22059SEtienne Carriere }
393f3c22059SEtienne Carriere 
394ea8ba295SGatien Chevallier static TEE_Result stm32_rng_probe(const void *fdt, int offs,
395ea8ba295SGatien Chevallier 				  const void *compat_data __unused)
396ea8ba295SGatien Chevallier {
397ea8ba295SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
398ea8ba295SGatien Chevallier 
399ea8ba295SGatien Chevallier 	/* Expect a single RNG instance */
400ea8ba295SGatien Chevallier 	assert(!stm32_rng);
401ea8ba295SGatien Chevallier 
402ea8ba295SGatien Chevallier 	stm32_rng = calloc(1, sizeof(*stm32_rng));
403ea8ba295SGatien Chevallier 	if (!stm32_rng)
404ea8ba295SGatien Chevallier 		panic();
405ea8ba295SGatien Chevallier 
406ea8ba295SGatien Chevallier 	res = stm32_rng_parse_fdt(fdt, offs);
407ea8ba295SGatien Chevallier 	if (res)
408ea8ba295SGatien Chevallier 		goto err;
409ea8ba295SGatien Chevallier 
410*091ef005SGatien Chevallier 	stm32_rng->ddata = compat_data;
411*091ef005SGatien Chevallier 	assert(stm32_rng->ddata);
412*091ef005SGatien Chevallier 
413ea8ba295SGatien Chevallier 	res = clk_enable(stm32_rng->clock);
414ea8ba295SGatien Chevallier 	if (res)
415ea8ba295SGatien Chevallier 		goto err;
416ea8ba295SGatien Chevallier 
417ea8ba295SGatien Chevallier 	if (stm32_rng->rstctrl &&
418ea8ba295SGatien Chevallier 	    rstctrl_assert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) {
419ea8ba295SGatien Chevallier 		res = TEE_ERROR_GENERIC;
420ea8ba295SGatien Chevallier 		goto err_clk;
421ea8ba295SGatien Chevallier 	}
422ea8ba295SGatien Chevallier 
423ea8ba295SGatien Chevallier 	if (stm32_rng->rstctrl &&
424ea8ba295SGatien Chevallier 	    rstctrl_deassert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) {
425ea8ba295SGatien Chevallier 		res = TEE_ERROR_GENERIC;
426ea8ba295SGatien Chevallier 		goto err_clk;
427ea8ba295SGatien Chevallier 	}
428ea8ba295SGatien Chevallier 
429f63f11bdSGatien Chevallier 	res = init_rng();
430f63f11bdSGatien Chevallier 	if (res)
431f63f11bdSGatien Chevallier 		goto err_clk;
432f63f11bdSGatien Chevallier 
433ea8ba295SGatien Chevallier 	clk_disable(stm32_rng->clock);
434ea8ba295SGatien Chevallier 
435ea8ba295SGatien Chevallier 	if (stm32_rng->release_post_boot)
436ea8ba295SGatien Chevallier 		stm32mp_register_non_secure_periph_iomem(stm32_rng->base.pa);
437ea8ba295SGatien Chevallier 	else
438ea8ba295SGatien Chevallier 		stm32mp_register_secure_periph_iomem(stm32_rng->base.pa);
439ea8ba295SGatien Chevallier 
440ea8ba295SGatien Chevallier 	return TEE_SUCCESS;
441ea8ba295SGatien Chevallier 
442ea8ba295SGatien Chevallier err_clk:
443ea8ba295SGatien Chevallier 	clk_disable(stm32_rng->clock);
444ea8ba295SGatien Chevallier err:
445ea8ba295SGatien Chevallier 	free(stm32_rng);
446ea8ba295SGatien Chevallier 	stm32_rng = NULL;
447ea8ba295SGatien Chevallier 
448ea8ba295SGatien Chevallier 	return res;
449ea8ba295SGatien Chevallier }
450ea8ba295SGatien Chevallier 
451*091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp13_data[] = {
452*091ef005SGatien Chevallier 	{ .has_cond_reset = true },
453*091ef005SGatien Chevallier };
454*091ef005SGatien Chevallier 
455*091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp15_data[] = {
456*091ef005SGatien Chevallier 	{ .has_cond_reset = false },
457*091ef005SGatien Chevallier };
458*091ef005SGatien Chevallier DECLARE_KEEP_PAGER(mp15_data);
459*091ef005SGatien Chevallier 
460ea8ba295SGatien Chevallier static const struct dt_device_match rng_match_table[] = {
461*091ef005SGatien Chevallier 	{ .compatible = "st,stm32-rng", .compat_data = &mp15_data },
462*091ef005SGatien Chevallier 	{ .compatible = "st,stm32mp13-rng", .compat_data = &mp13_data },
463ea8ba295SGatien Chevallier 	{ }
464ea8ba295SGatien Chevallier };
465ea8ba295SGatien Chevallier 
466ea8ba295SGatien Chevallier DEFINE_DT_DRIVER(stm32_rng_dt_driver) = {
467ea8ba295SGatien Chevallier 	.name = "stm32_rng",
468ea8ba295SGatien Chevallier 	.match_table = rng_match_table,
469ea8ba295SGatien Chevallier 	.probe = stm32_rng_probe,
470ea8ba295SGatien Chevallier };
471d8682c4cSEtienne Carriere 
472d8682c4cSEtienne Carriere static TEE_Result stm32_rng_release(void)
473d8682c4cSEtienne Carriere {
474d8682c4cSEtienne Carriere 	if (stm32_rng && stm32_rng->release_post_boot) {
475d8682c4cSEtienne Carriere 		DMSG("Release RNG driver");
476d8682c4cSEtienne Carriere 		free(stm32_rng);
477d8682c4cSEtienne Carriere 		stm32_rng = NULL;
478d8682c4cSEtienne Carriere 	}
479d8682c4cSEtienne Carriere 
480d8682c4cSEtienne Carriere 	return TEE_SUCCESS;
481d8682c4cSEtienne Carriere }
482d8682c4cSEtienne Carriere 
483d8682c4cSEtienne Carriere release_init_resource(stm32_rng_release);
484f3c22059SEtienne Carriere #endif /*CFG_EMBED_DTB*/
485