xref: /optee_os/core/drivers/stm32_rng.c (revision 7d9d593df977e5e18e1cc70e929ac6f1e341e405)
1f3c22059SEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause
2f3c22059SEtienne Carriere /*
3*d773ec0bSGatien Chevallier  * Copyright (c) 2018-2024, 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 <io.h>
11f3c22059SEtienne Carriere #include <kernel/delay.h>
12a2fc83d1SJerome Forissier #include <kernel/dt.h>
13ea8ba295SGatien Chevallier #include <kernel/dt_driver.h>
14*d773ec0bSGatien Chevallier #include <kernel/boot.h>
15f3c22059SEtienne Carriere #include <kernel/panic.h>
1629893549SGatien Chevallier #include <kernel/pm.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)
295959d83fSGatien Chevallier #define RNG_NSCR		U(0x0C)
305959d83fSGatien Chevallier #define RNG_HTCR		U(0x10)
31b82b7e73SGatien Chevallier #define RNG_VERR		U(0x3F4)
32f3c22059SEtienne Carriere 
33f3c22059SEtienne Carriere #define RNG_CR_RNGEN		BIT(2)
34f3c22059SEtienne Carriere #define RNG_CR_IE		BIT(3)
35f3c22059SEtienne Carriere #define RNG_CR_CED		BIT(5)
365959d83fSGatien Chevallier #define RNG_CR_CONFIG1		GENMASK_32(11, 8)
375959d83fSGatien Chevallier #define RNG_CR_NISTC		BIT(12)
385959d83fSGatien Chevallier #define RNG_CR_POWER_OPTIM	BIT(13)
395959d83fSGatien Chevallier #define RNG_CR_CONFIG2		GENMASK_32(15, 13)
40091ef005SGatien Chevallier #define RNG_CR_CLKDIV		GENMASK_32(19, 16)
41091ef005SGatien Chevallier #define RNG_CR_CLKDIV_SHIFT	U(16)
425959d83fSGatien Chevallier #define RNG_CR_CONFIG3		GENMASK_32(25, 20)
43091ef005SGatien Chevallier #define RNG_CR_CONDRST		BIT(30)
445959d83fSGatien Chevallier #define RNG_CR_ENTROPY_SRC_MASK	(RNG_CR_CONFIG1 | RNG_CR_NISTC | \
455959d83fSGatien Chevallier 				 RNG_CR_CONFIG2 | RNG_CR_CONFIG3)
46f3c22059SEtienne Carriere 
47f3c22059SEtienne Carriere #define RNG_SR_DRDY		BIT(0)
48f3c22059SEtienne Carriere #define RNG_SR_CECS		BIT(1)
49f3c22059SEtienne Carriere #define RNG_SR_SECS		BIT(2)
50f3c22059SEtienne Carriere #define RNG_SR_CEIS		BIT(5)
51f3c22059SEtienne Carriere #define RNG_SR_SEIS		BIT(6)
52f3c22059SEtienne Carriere 
535959d83fSGatien Chevallier #define RNG_NSCR_MASK		GENMASK_32(17, 0)
545959d83fSGatien Chevallier 
55b82b7e73SGatien Chevallier #define RNG_VERR_MINOR_MASK	GENMASK_32(3, 0)
56b82b7e73SGatien Chevallier #define RNG_VERR_MAJOR_MASK	GENMASK_32(7, 4)
57b82b7e73SGatien Chevallier #define RNG_VERR_MAJOR_SHIFT	U(4)
58b82b7e73SGatien Chevallier 
590817aa6fSGatien Chevallier #if TRACE_LEVEL > TRACE_DEBUG
600817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US	U(100000)
610817aa6fSGatien Chevallier #else
620817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US	U(10000)
630817aa6fSGatien Chevallier #endif
64ea8ba295SGatien Chevallier #define RNG_RESET_TIMEOUT_US	U(1000)
65f3c22059SEtienne Carriere 
660817aa6fSGatien Chevallier #define RNG_FIFO_BYTE_DEPTH	U(16)
670817aa6fSGatien Chevallier 
685959d83fSGatien Chevallier #define RNG_CONFIG_MASK		(RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED | \
695959d83fSGatien Chevallier 				 RNG_CR_CLKDIV)
70091ef005SGatien Chevallier 
71091ef005SGatien Chevallier struct stm32_rng_driver_data {
72aa12f203SGatien Chevallier 	unsigned long max_noise_clk_freq;
7345da6509SGatien Chevallier 	unsigned long nb_clock;
745959d83fSGatien Chevallier 	uint32_t cr;
755959d83fSGatien Chevallier 	uint32_t nscr;
765959d83fSGatien Chevallier 	uint32_t htcr;
775959d83fSGatien Chevallier 	bool has_power_optim;
78091ef005SGatien Chevallier 	bool has_cond_reset;
79091ef005SGatien Chevallier };
80091ef005SGatien Chevallier 
81f3c22059SEtienne Carriere struct stm32_rng_instance {
82f3c22059SEtienne Carriere 	struct io_pa_va base;
83d7a1a7d2SEtienne Carriere 	struct clk *clock;
8445da6509SGatien Chevallier 	struct clk *bus_clock;
85ea8ba295SGatien Chevallier 	struct rstctrl *rstctrl;
86091ef005SGatien Chevallier 	const struct stm32_rng_driver_data *ddata;
87f3c22059SEtienne Carriere 	unsigned int lock;
885959d83fSGatien Chevallier 	uint64_t error_to_ref;
895959d83fSGatien Chevallier 	uint32_t pm_cr;
905959d83fSGatien Chevallier 	uint32_t pm_health;
915959d83fSGatien Chevallier 	uint32_t pm_noise_ctrl;
925959d83fSGatien Chevallier 	uint32_t health_test_conf;
935959d83fSGatien Chevallier 	uint32_t noise_ctrl_conf;
945959d83fSGatien Chevallier 	uint32_t rng_config;
953c752300SGatien Chevallier 	bool clock_error;
96091ef005SGatien Chevallier 	bool error_conceal;
97f3c22059SEtienne Carriere };
98f3c22059SEtienne Carriere 
99ea8ba295SGatien Chevallier /* Expect at most a single RNG instance */
100f3c22059SEtienne Carriere static struct stm32_rng_instance *stm32_rng;
101f3c22059SEtienne Carriere 
get_base(void)102f63f11bdSGatien Chevallier static vaddr_t get_base(void)
103f63f11bdSGatien Chevallier {
104f63f11bdSGatien Chevallier 	assert(stm32_rng);
105f63f11bdSGatien Chevallier 
106f63f11bdSGatien Chevallier 	return io_pa_or_va(&stm32_rng->base, 1);
107f63f11bdSGatien Chevallier }
108f63f11bdSGatien Chevallier 
109f3c22059SEtienne Carriere /*
110091ef005SGatien Chevallier  * Extracts from the STM32 RNG specification when RNG supports CONDRST.
111f3c22059SEtienne Carriere  *
112f3c22059SEtienne Carriere  * When a noise source (or seed) error occurs, the RNG stops generating
113f3c22059SEtienne Carriere  * random numbers and sets to “1” both SEIS and SECS bits to indicate
114f3c22059SEtienne Carriere  * that a seed error occurred. (...)
115091ef005SGatien Chevallier  *
116091ef005SGatien Chevallier  * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield
117091ef005SGatien Chevallier  * description for details). This step is needed only if SECS is set.
118091ef005SGatien Chevallier  * Indeed, when SEIS is set and SECS is cleared it means RNG performed
119091ef005SGatien Chevallier  * the reset automatically (auto-reset).
120091ef005SGatien Chevallier  * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST
121091ef005SGatien Chevallier  * to be cleared in the RNG_CR register, then confirm that SEIS is
122091ef005SGatien Chevallier  * cleared in the RNG_SR register. Otherwise just clear SEIS bit in
123091ef005SGatien Chevallier  * the RNG_SR register.
124091ef005SGatien Chevallier  * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be
125091ef005SGatien Chevallier  * cleared by RNG. The random number generation is now back to normal.
126091ef005SGatien Chevallier  */
conceal_seed_error_cond_reset(void)127091ef005SGatien Chevallier static void conceal_seed_error_cond_reset(void)
128091ef005SGatien Chevallier {
129091ef005SGatien Chevallier 	struct stm32_rng_instance *dev = stm32_rng;
130091ef005SGatien Chevallier 	vaddr_t rng_base = get_base();
131f3c22059SEtienne Carriere 
132091ef005SGatien Chevallier 	if (!dev->error_conceal) {
133091ef005SGatien Chevallier 		uint32_t sr = io_read32(rng_base + RNG_SR);
134091ef005SGatien Chevallier 
135091ef005SGatien Chevallier 		if (sr & RNG_SR_SECS) {
136091ef005SGatien Chevallier 			/* Conceal by resetting the subsystem (step 1.) */
137091ef005SGatien Chevallier 			io_setbits32(rng_base + RNG_CR, RNG_CR_CONDRST);
138091ef005SGatien Chevallier 			io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST);
139091ef005SGatien Chevallier 
140091ef005SGatien Chevallier 			/* Arm timeout for error_conceal sequence */
141091ef005SGatien Chevallier 			dev->error_to_ref =
142091ef005SGatien Chevallier 				timeout_init_us(RNG_READY_TIMEOUT_US);
143091ef005SGatien Chevallier 			dev->error_conceal = true;
144091ef005SGatien Chevallier 		} else {
145091ef005SGatien Chevallier 			/* RNG auto-reset (step 2.) */
146091ef005SGatien Chevallier 			io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS);
147091ef005SGatien Chevallier 		}
148091ef005SGatien Chevallier 	} else {
149091ef005SGatien Chevallier 		/* Measure time before possible reschedule */
150091ef005SGatien Chevallier 		bool timed_out = timeout_elapsed(dev->error_to_ref);
151091ef005SGatien Chevallier 
152091ef005SGatien Chevallier 		/* Wait CONDRST is cleared (step 2.) */
153091ef005SGatien Chevallier 		if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) {
154091ef005SGatien Chevallier 			if (timed_out)
155091ef005SGatien Chevallier 				panic();
156091ef005SGatien Chevallier 
157091ef005SGatien Chevallier 			/* Wait subsystem reset cycle completes */
158091ef005SGatien Chevallier 			return;
159091ef005SGatien Chevallier 		}
160091ef005SGatien Chevallier 
161091ef005SGatien Chevallier 		/* Check SEIS is cleared (step 2.) */
162091ef005SGatien Chevallier 		if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS)
163091ef005SGatien Chevallier 			panic();
164091ef005SGatien Chevallier 
165091ef005SGatien Chevallier 		/* Wait SECS is cleared (step 3.) */
166091ef005SGatien Chevallier 		if (io_read32(rng_base + RNG_SR) & RNG_SR_SECS) {
167091ef005SGatien Chevallier 			if (timed_out)
168091ef005SGatien Chevallier 				panic();
169091ef005SGatien Chevallier 
170091ef005SGatien Chevallier 			/* Wait subsystem reset cycle completes */
171091ef005SGatien Chevallier 			return;
172091ef005SGatien Chevallier 		}
173091ef005SGatien Chevallier 
174091ef005SGatien Chevallier 		dev->error_conceal = false;
175091ef005SGatien Chevallier 	}
176091ef005SGatien Chevallier }
177091ef005SGatien Chevallier 
178091ef005SGatien Chevallier /*
179091ef005SGatien Chevallier  * Extracts from the STM32 RNG specification, when CONDRST is not supported
180091ef005SGatien Chevallier  *
181091ef005SGatien Chevallier  * When a noise source (or seed) error occurs, the RNG stops generating
182091ef005SGatien Chevallier  * random numbers and sets to “1” both SEIS and SECS bits to indicate
183091ef005SGatien Chevallier  * that a seed error occurred. (...)
184091ef005SGatien Chevallier  *
185f3c22059SEtienne Carriere  * The following sequence shall be used to fully recover from a seed
186f3c22059SEtienne Carriere  * error after the RNG initialization:
187f3c22059SEtienne Carriere  * 1. Clear the SEIS bit by writing it to “0”.
188f3c22059SEtienne Carriere  * 2. Read out 12 words from the RNG_DR register, and discard each of
189f3c22059SEtienne Carriere  * them in order to clean the pipeline.
190f3c22059SEtienne Carriere  * 3. Confirm that SEIS is still cleared. Random number generation is
191f3c22059SEtienne Carriere  * back to normal.
192f3c22059SEtienne Carriere  */
conceal_seed_error_sw_reset(void)193091ef005SGatien Chevallier static void conceal_seed_error_sw_reset(void)
194f3c22059SEtienne Carriere {
1956a6b6168SGatien Chevallier 	vaddr_t rng_base = get_base();
196f3c22059SEtienne Carriere 	size_t i = 0;
197f3c22059SEtienne Carriere 
1986a6b6168SGatien Chevallier 	io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS);
199f3c22059SEtienne Carriere 
200f3c22059SEtienne Carriere 	for (i = 12; i != 0; i--)
201f3c22059SEtienne Carriere 		(void)io_read32(rng_base + RNG_DR);
202f3c22059SEtienne Carriere 
203f3c22059SEtienne Carriere 	if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS)
204f3c22059SEtienne Carriere 		panic("RNG noise");
205f3c22059SEtienne Carriere }
206f3c22059SEtienne Carriere 
conceal_seed_error(void)207091ef005SGatien Chevallier static void conceal_seed_error(void)
208091ef005SGatien Chevallier {
209091ef005SGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset)
210091ef005SGatien Chevallier 		conceal_seed_error_cond_reset();
211091ef005SGatien Chevallier 	else
212091ef005SGatien Chevallier 		conceal_seed_error_sw_reset();
213091ef005SGatien Chevallier }
214091ef005SGatien Chevallier 
read_available(vaddr_t rng_base,uint8_t * out,size_t * size)215c99311c8SEtienne Carriere static TEE_Result read_available(vaddr_t rng_base, uint8_t *out, size_t *size)
216f3c22059SEtienne Carriere {
217091ef005SGatien Chevallier 	struct stm32_rng_instance *dev = stm32_rng;
218c99311c8SEtienne Carriere 	uint8_t *buf = NULL;
219c99311c8SEtienne Carriere 	size_t req_size = 0;
220c99311c8SEtienne Carriere 	size_t len = 0;
221f3c22059SEtienne Carriere 
222091ef005SGatien Chevallier 	if (dev->error_conceal || io_read32(rng_base + RNG_SR) & RNG_SR_SEIS)
2236a6b6168SGatien Chevallier 		conceal_seed_error();
224f3c22059SEtienne Carriere 
22523123473SEtienne Carriere 	if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) {
22623123473SEtienne Carriere 		FMSG("RNG not ready");
227c99311c8SEtienne Carriere 		return TEE_ERROR_NO_DATA;
22823123473SEtienne Carriere 	}
229f3c22059SEtienne Carriere 
23023123473SEtienne Carriere 	if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) {
23123123473SEtienne Carriere 		FMSG("RNG noise error");
232c99311c8SEtienne Carriere 		return TEE_ERROR_NO_DATA;
23323123473SEtienne Carriere 	}
234c99311c8SEtienne Carriere 
235c99311c8SEtienne Carriere 	buf = out;
236c99311c8SEtienne Carriere 	req_size = MIN(RNG_FIFO_BYTE_DEPTH, *size);
237c99311c8SEtienne Carriere 	len = req_size;
238f3c22059SEtienne Carriere 
239f3c22059SEtienne Carriere 	/* RNG is ready: read up to 4 32bit words */
240f3c22059SEtienne Carriere 	while (len) {
24123bdf063SEtienne Carriere 		uint32_t data32 = 0;
242f3c22059SEtienne Carriere 		size_t sz = MIN(len, sizeof(uint32_t));
243f3c22059SEtienne Carriere 
24423bdf063SEtienne Carriere 		if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY))
24523bdf063SEtienne Carriere 			break;
24623bdf063SEtienne Carriere 		data32 = io_read32(rng_base + RNG_DR);
24723bdf063SEtienne Carriere 
2483e64c635SGatien Chevallier 		/* Late seed error case: DR being 0 is an error status */
2493e64c635SGatien Chevallier 		if (!data32) {
2503e64c635SGatien Chevallier 			conceal_seed_error();
2513e64c635SGatien Chevallier 			return TEE_ERROR_NO_DATA;
2523e64c635SGatien Chevallier 		}
2533e64c635SGatien Chevallier 
254f3c22059SEtienne Carriere 		memcpy(buf, &data32, sz);
255f3c22059SEtienne Carriere 		buf += sz;
256f3c22059SEtienne Carriere 		len -= sz;
257f3c22059SEtienne Carriere 	}
258c99311c8SEtienne Carriere 
25923bdf063SEtienne Carriere 	*size = req_size - len;
260f3c22059SEtienne Carriere 
261c99311c8SEtienne Carriere 	return TEE_SUCCESS;
262f3c22059SEtienne Carriere }
263f3c22059SEtienne Carriere 
stm32_rng_clock_freq_restrain(void)264091ef005SGatien Chevallier static uint32_t stm32_rng_clock_freq_restrain(void)
265091ef005SGatien Chevallier {
266091ef005SGatien Chevallier 	struct stm32_rng_instance *dev = stm32_rng;
267091ef005SGatien Chevallier 	unsigned long clock_rate = 0;
268091ef005SGatien Chevallier 	uint32_t clock_div = 0;
269091ef005SGatien Chevallier 
270091ef005SGatien Chevallier 	clock_rate = clk_get_rate(dev->clock);
271091ef005SGatien Chevallier 
272091ef005SGatien Chevallier 	/*
273091ef005SGatien Chevallier 	 * Get the exponent to apply on the CLKDIV field in RNG_CR register
274091ef005SGatien Chevallier 	 * No need to handle the case when clock-div > 0xF as it is physically
275091ef005SGatien Chevallier 	 * impossible
276091ef005SGatien Chevallier 	 */
277aa12f203SGatien Chevallier 	while ((clock_rate >> clock_div) > dev->ddata->max_noise_clk_freq)
278091ef005SGatien Chevallier 		clock_div++;
279091ef005SGatien Chevallier 
280091ef005SGatien Chevallier 	DMSG("RNG clk rate : %lu", clk_get_rate(dev->clock) >> clock_div);
281091ef005SGatien Chevallier 
282091ef005SGatien Chevallier 	return clock_div;
283091ef005SGatien Chevallier }
284091ef005SGatien Chevallier 
enable_rng_clock(void)285*d773ec0bSGatien Chevallier static TEE_Result enable_rng_clock(void)
286f3c22059SEtienne Carriere {
287*d773ec0bSGatien Chevallier 	TEE_Result res = clk_enable(stm32_rng->clock);
288*d773ec0bSGatien Chevallier 
289*d773ec0bSGatien Chevallier 	if (!res && stm32_rng->bus_clock) {
290*d773ec0bSGatien Chevallier 		res = clk_enable(stm32_rng->bus_clock);
291*d773ec0bSGatien Chevallier 		if (res)
292*d773ec0bSGatien Chevallier 			clk_disable(stm32_rng->clock);
293*d773ec0bSGatien Chevallier 	}
294*d773ec0bSGatien Chevallier 
295*d773ec0bSGatien Chevallier 	return res;
296*d773ec0bSGatien Chevallier }
297*d773ec0bSGatien Chevallier 
disable_rng_clock(void)298*d773ec0bSGatien Chevallier static void disable_rng_clock(void)
299*d773ec0bSGatien Chevallier {
300*d773ec0bSGatien Chevallier 	clk_disable(stm32_rng->clock);
301*d773ec0bSGatien Chevallier 	if (stm32_rng->bus_clock)
302*d773ec0bSGatien Chevallier 		clk_disable(stm32_rng->bus_clock);
303*d773ec0bSGatien Chevallier }
304*d773ec0bSGatien Chevallier 
stm32_rng_init(void)305*d773ec0bSGatien Chevallier static TEE_Result stm32_rng_init(void)
306*d773ec0bSGatien Chevallier {
307*d773ec0bSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
308f63f11bdSGatien Chevallier 	vaddr_t rng_base = get_base();
3093c752300SGatien Chevallier 	uint32_t cr_ced_mask = 0;
3105959d83fSGatien Chevallier 	uint32_t value = 0;
3113c752300SGatien Chevallier 
312*d773ec0bSGatien Chevallier 	res = enable_rng_clock();
313*d773ec0bSGatien Chevallier 	if (res)
314*d773ec0bSGatien Chevallier 		return res;
315*d773ec0bSGatien Chevallier 
316*d773ec0bSGatien Chevallier 	if (stm32_rng->rstctrl &&
317*d773ec0bSGatien Chevallier 	    rstctrl_assert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) {
318*d773ec0bSGatien Chevallier 		res = TEE_ERROR_GENERIC;
319*d773ec0bSGatien Chevallier 		goto out;
320*d773ec0bSGatien Chevallier 	}
321*d773ec0bSGatien Chevallier 
322*d773ec0bSGatien Chevallier 	if (stm32_rng->rstctrl &&
323*d773ec0bSGatien Chevallier 	    rstctrl_deassert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) {
324*d773ec0bSGatien Chevallier 		res = TEE_ERROR_GENERIC;
325*d773ec0bSGatien Chevallier 		goto out;
326*d773ec0bSGatien Chevallier 	}
327*d773ec0bSGatien Chevallier 
3283c752300SGatien Chevallier 	if (!stm32_rng->clock_error)
3293c752300SGatien Chevallier 		cr_ced_mask = RNG_CR_CED;
330f3c22059SEtienne Carriere 
331f63f11bdSGatien Chevallier 	/* Clean error indications */
332f63f11bdSGatien Chevallier 	io_write32(rng_base + RNG_SR, 0);
333f3c22059SEtienne Carriere 
334091ef005SGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset) {
335091ef005SGatien Chevallier 		uint32_t clock_div = stm32_rng_clock_freq_restrain();
336091ef005SGatien Chevallier 
3375959d83fSGatien Chevallier 		/*
3385959d83fSGatien Chevallier 		 * Keep default RNG configuration if none was specified.
3395959d83fSGatien Chevallier 		 * 0 is an invalid value as it disables all entropy sources.
3405959d83fSGatien Chevallier 		 */
3415959d83fSGatien Chevallier 		if (!stm32_rng->rng_config)
3425959d83fSGatien Chevallier 			stm32_rng->rng_config = io_read32(rng_base + RNG_CR) &
3435959d83fSGatien Chevallier 						RNG_CR_ENTROPY_SRC_MASK;
3445959d83fSGatien Chevallier 
3455959d83fSGatien Chevallier 		/*
3465959d83fSGatien Chevallier 		 * Configuration must be set in the same access that sets
3475959d83fSGatien Chevallier 		 * RNG_CR_CONDRST bit. Otherwise, the configuration setting is
3485959d83fSGatien Chevallier 		 * not taken into account. CONFIGLOCK bit is always cleared at
3495959d83fSGatien Chevallier 		 * this stage.
3505959d83fSGatien Chevallier 		 */
3515959d83fSGatien Chevallier 		io_clrsetbits32(rng_base + RNG_CR, RNG_CONFIG_MASK,
3525959d83fSGatien Chevallier 				stm32_rng->rng_config | RNG_CR_CONDRST |
3535959d83fSGatien Chevallier 				cr_ced_mask |
3545959d83fSGatien Chevallier 				SHIFT_U32(clock_div, RNG_CR_CLKDIV_SHIFT));
3555959d83fSGatien Chevallier 
3565959d83fSGatien Chevallier 		/*
3575959d83fSGatien Chevallier 		 * Write health test and noise source control configuration
3585959d83fSGatien Chevallier 		 * according to current RNG entropy source configuration
3595959d83fSGatien Chevallier 		 */
3605959d83fSGatien Chevallier 		if (stm32_rng->noise_ctrl_conf)
3615959d83fSGatien Chevallier 			io_write32(rng_base + RNG_NSCR,
3625959d83fSGatien Chevallier 				   stm32_rng->noise_ctrl_conf);
3635959d83fSGatien Chevallier 
3645959d83fSGatien Chevallier 		if (stm32_rng->health_test_conf)
3655959d83fSGatien Chevallier 			io_write32(rng_base + RNG_HTCR,
3665959d83fSGatien Chevallier 				   stm32_rng->health_test_conf);
367091ef005SGatien Chevallier 
368091ef005SGatien Chevallier 		io_clrsetbits32(rng_base + RNG_CR, RNG_CR_CONDRST,
369091ef005SGatien Chevallier 				RNG_CR_RNGEN);
370eb5cf770SGatien Chevallier 
3715959d83fSGatien Chevallier 		if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_CR, value,
3725959d83fSGatien Chevallier 					   !(value & RNG_CR_CONDRST), 0,
3735959d83fSGatien Chevallier 					   RNG_READY_TIMEOUT_US))
374eb5cf770SGatien Chevallier 			panic();
3755959d83fSGatien Chevallier 
3765959d83fSGatien Chevallier 		DMSG("RNG control register %#"PRIx32,
3775959d83fSGatien Chevallier 		     io_read32(rng_base + RNG_CR));
3785959d83fSGatien Chevallier 		DMSG("RNG noise source control register %#"PRIx32,
3795959d83fSGatien Chevallier 		     io_read32(rng_base + RNG_NSCR));
3805959d83fSGatien Chevallier 		DMSG("RNG health test register %#"PRIx32,
3815959d83fSGatien Chevallier 		     io_read32(rng_base + RNG_HTCR));
382091ef005SGatien Chevallier 	} else {
3833c752300SGatien Chevallier 		io_setbits32(rng_base + RNG_CR, RNG_CR_RNGEN | cr_ced_mask);
384091ef005SGatien Chevallier 	}
385f63f11bdSGatien Chevallier 
3865959d83fSGatien Chevallier 	if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_SR, value,
3875959d83fSGatien Chevallier 				   value & RNG_SR_DRDY, 0,
3885959d83fSGatien Chevallier 				   RNG_READY_TIMEOUT_US))
389f63f11bdSGatien Chevallier 		return TEE_ERROR_GENERIC;
390f63f11bdSGatien Chevallier 
391*d773ec0bSGatien Chevallier 	res =  TEE_SUCCESS;
392*d773ec0bSGatien Chevallier 
393*d773ec0bSGatien Chevallier out:
394*d773ec0bSGatien Chevallier 	disable_rng_clock();
395*d773ec0bSGatien Chevallier 
396*d773ec0bSGatien Chevallier 	return res;
397f3c22059SEtienne Carriere }
398f3c22059SEtienne Carriere 
stm32_rng_read(uint8_t * out,size_t size)39998c36268SGatien Chevallier static TEE_Result stm32_rng_read(uint8_t *out, size_t size)
400f3c22059SEtienne Carriere {
401c99311c8SEtienne Carriere 	TEE_Result rc = TEE_ERROR_GENERIC;
402c99311c8SEtienne Carriere 	bool burst_timeout = false;
403c99311c8SEtienne Carriere 	uint64_t timeout_ref = 0;
404f3c22059SEtienne Carriere 	uint32_t exceptions = 0;
405f3c22059SEtienne Carriere 	uint8_t *out_ptr = out;
406c99311c8SEtienne Carriere 	vaddr_t rng_base = 0;
407f3c22059SEtienne Carriere 	size_t out_size = 0;
408f3c22059SEtienne Carriere 
409f3c22059SEtienne Carriere 	if (!stm32_rng) {
410f3c22059SEtienne Carriere 		DMSG("No RNG");
411f3c22059SEtienne Carriere 		return TEE_ERROR_NOT_SUPPORTED;
412f3c22059SEtienne Carriere 	}
413f3c22059SEtienne Carriere 
414*d773ec0bSGatien Chevallier 	rc = enable_rng_clock();
415fb1681dfSGatien Chevallier 	if (rc)
416fb1681dfSGatien Chevallier 		return rc;
417fb1681dfSGatien Chevallier 
418f63f11bdSGatien Chevallier 	rng_base = get_base();
419c99311c8SEtienne Carriere 
420c99311c8SEtienne Carriere 	/* Arm timeout */
4210817aa6fSGatien Chevallier 	timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
422c99311c8SEtienne Carriere 	burst_timeout = false;
423f3c22059SEtienne Carriere 
424f3c22059SEtienne Carriere 	while (out_size < size) {
425f3c22059SEtienne Carriere 		/* Read by chunks of the size the RNG FIFO depth */
426f3c22059SEtienne Carriere 		size_t sz = size - out_size;
427f3c22059SEtienne Carriere 
428f3c22059SEtienne Carriere 		exceptions = may_spin_lock(&stm32_rng->lock);
429f3c22059SEtienne Carriere 
430c99311c8SEtienne Carriere 		rc = read_available(rng_base, out_ptr, &sz);
431c99311c8SEtienne Carriere 
432c99311c8SEtienne Carriere 		/* Raise timeout only if we failed to get some samples */
433c99311c8SEtienne Carriere 		assert(!rc || rc == TEE_ERROR_NO_DATA);
434c99311c8SEtienne Carriere 		if (rc)
435c99311c8SEtienne Carriere 			burst_timeout = timeout_elapsed(timeout_ref);
436f3c22059SEtienne Carriere 
437f3c22059SEtienne Carriere 		may_spin_unlock(&stm32_rng->lock, exceptions);
438f3c22059SEtienne Carriere 
439c99311c8SEtienne Carriere 		if (burst_timeout) {
440c99311c8SEtienne Carriere 			rc = TEE_ERROR_GENERIC;
441c99311c8SEtienne Carriere 			goto out;
442f3c22059SEtienne Carriere 		}
443f3c22059SEtienne Carriere 
444c99311c8SEtienne Carriere 		if (!rc) {
445c99311c8SEtienne Carriere 			out_size += sz;
446c99311c8SEtienne Carriere 			out_ptr += sz;
447c99311c8SEtienne Carriere 			/* Re-arm timeout */
4480817aa6fSGatien Chevallier 			timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
449c99311c8SEtienne Carriere 			burst_timeout = false;
450c99311c8SEtienne Carriere 		}
451c99311c8SEtienne Carriere 	}
452c99311c8SEtienne Carriere 
453c99311c8SEtienne Carriere out:
454c99311c8SEtienne Carriere 	assert(!rc || rc == TEE_ERROR_GENERIC);
455*d773ec0bSGatien Chevallier 	disable_rng_clock();
456f3c22059SEtienne Carriere 
457f3c22059SEtienne Carriere 	return rc;
458f3c22059SEtienne Carriere }
459f3c22059SEtienne Carriere 
460cd451498SEtienne Carriere #ifdef CFG_WITH_SOFTWARE_PRNG
461f2fe4f00SThomas Bourgoin /* Override weak plat_rng_init with platform handler to attempt to seed PRNG */
plat_rng_init(void)462cd451498SEtienne Carriere void plat_rng_init(void)
463cd451498SEtienne Carriere {
464cd451498SEtienne Carriere 	uint8_t seed[RNG_FIFO_BYTE_DEPTH] = { };
465cd451498SEtienne Carriere 
466f2fe4f00SThomas Bourgoin 	if (!stm32_rng) {
467f2fe4f00SThomas Bourgoin 		__plat_rng_init();
468f2fe4f00SThomas Bourgoin 		DMSG("PRNG seeded without RNG");
469f2fe4f00SThomas Bourgoin 		return;
470f2fe4f00SThomas Bourgoin 	}
471f2fe4f00SThomas Bourgoin 
472cd451498SEtienne Carriere 	if (stm32_rng_read(seed, sizeof(seed)))
473cd451498SEtienne Carriere 		panic();
474cd451498SEtienne Carriere 
475cd451498SEtienne Carriere 	if (crypto_rng_init(seed, sizeof(seed)))
476cd451498SEtienne Carriere 		panic();
477cd451498SEtienne Carriere 
478cd451498SEtienne Carriere 	DMSG("PRNG seeded with RNG");
479cd451498SEtienne Carriere }
480cd451498SEtienne Carriere #else
hw_get_random_bytes(void * out,size_t size)481cb2478efSAndrew Davis TEE_Result hw_get_random_bytes(void *out, size_t size)
482097f329aSEtienne Carriere {
483097f329aSEtienne Carriere 	return stm32_rng_read(out, size);
484097f329aSEtienne Carriere }
48527f3087bSGatien Chevallier 
plat_rng_init(void)48627f3087bSGatien Chevallier void plat_rng_init(void)
48727f3087bSGatien Chevallier {
48827f3087bSGatien Chevallier }
489097f329aSEtienne Carriere #endif
490097f329aSEtienne Carriere 
stm32_rng_pm_resume(void)4915959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_resume(void)
49229893549SGatien Chevallier {
49329893549SGatien Chevallier 	vaddr_t base = get_base();
49429893549SGatien Chevallier 
49529893549SGatien Chevallier 	/* Clean error indications */
49629893549SGatien Chevallier 	io_write32(base + RNG_SR, 0);
49729893549SGatien Chevallier 
49829893549SGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset) {
499eb5cf770SGatien Chevallier 		uint64_t timeout_ref = 0;
500eb5cf770SGatien Chevallier 
50129893549SGatien Chevallier 		/*
502c2c5b4beSGatien Chevallier 		 * Configuration must be set in the same access that sets
503c2c5b4beSGatien Chevallier 		 * RNG_CR_CONDRST bit. Otherwise, the configuration setting is
504c2c5b4beSGatien Chevallier 		 * not taken into account. CONFIGLOCK bit is always cleared in
505c2c5b4beSGatien Chevallier 		 * this configuration.
50629893549SGatien Chevallier 		 */
5075959d83fSGatien Chevallier 		io_write32(base + RNG_CR, stm32_rng->pm_cr | RNG_CR_CONDRST);
5085959d83fSGatien Chevallier 
5095959d83fSGatien Chevallier 		/* Restore health test and noise control configuration */
5105959d83fSGatien Chevallier 		io_write32(base + RNG_NSCR, stm32_rng->pm_noise_ctrl);
5115959d83fSGatien Chevallier 		io_write32(base + RNG_HTCR, stm32_rng->pm_health);
51229893549SGatien Chevallier 
51329893549SGatien Chevallier 		io_clrsetbits32(base + RNG_CR, RNG_CR_CONDRST, RNG_CR_RNGEN);
514eb5cf770SGatien Chevallier 
515eb5cf770SGatien Chevallier 		timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
516eb5cf770SGatien Chevallier 		while (io_read32(base + RNG_CR) & RNG_CR_CONDRST)
517eb5cf770SGatien Chevallier 			if (timeout_elapsed(timeout_ref))
518eb5cf770SGatien Chevallier 				break;
519eb5cf770SGatien Chevallier 		if (io_read32(base + RNG_CR) & RNG_CR_CONDRST)
520eb5cf770SGatien Chevallier 			panic();
52129893549SGatien Chevallier 	} else {
5225959d83fSGatien Chevallier 		io_write32(base + RNG_CR, RNG_CR_RNGEN | stm32_rng->pm_cr);
5235959d83fSGatien Chevallier 	}
5245959d83fSGatien Chevallier 
5255959d83fSGatien Chevallier 	return TEE_SUCCESS;
5265959d83fSGatien Chevallier }
5275959d83fSGatien Chevallier 
stm32_rng_pm_suspend(void)5285959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_suspend(void)
5295959d83fSGatien Chevallier {
5305959d83fSGatien Chevallier 	vaddr_t rng_base = get_base();
5315959d83fSGatien Chevallier 
5325959d83fSGatien Chevallier 	stm32_rng->pm_cr = io_read32(rng_base + RNG_CR);
5335959d83fSGatien Chevallier 
5345959d83fSGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset) {
5355959d83fSGatien Chevallier 		stm32_rng->pm_health = io_read32(rng_base + RNG_HTCR);
5365959d83fSGatien Chevallier 		stm32_rng->pm_noise_ctrl = io_read32(rng_base + RNG_NSCR);
5375959d83fSGatien Chevallier 	}
5385959d83fSGatien Chevallier 
5395959d83fSGatien Chevallier 	if (stm32_rng->ddata->has_power_optim) {
5405959d83fSGatien Chevallier 		uint64_t timeout_ref = 0;
5415959d83fSGatien Chevallier 
5425959d83fSGatien Chevallier 		/*
5435959d83fSGatien Chevallier 		 * As per reference manual, it is recommended to set
5445959d83fSGatien Chevallier 		 * RNG_CONFIG2[bit0] when RNG power consumption is critical.
5455959d83fSGatien Chevallier 		 */
5465959d83fSGatien Chevallier 		io_setbits32(rng_base + RNG_CR, RNG_CR_POWER_OPTIM |
5475959d83fSGatien Chevallier 				RNG_CR_CONDRST);
5485959d83fSGatien Chevallier 		io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST);
5495959d83fSGatien Chevallier 
5505959d83fSGatien Chevallier 		timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
5515959d83fSGatien Chevallier 		while (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST)
5525959d83fSGatien Chevallier 			if (timeout_elapsed(timeout_ref))
5535959d83fSGatien Chevallier 				break;
5545959d83fSGatien Chevallier 		if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST)
5555959d83fSGatien Chevallier 			panic();
5565959d83fSGatien Chevallier 	} else {
5575959d83fSGatien Chevallier 		io_clrbits32(rng_base + RNG_CR, RNG_CR_RNGEN);
55829893549SGatien Chevallier 	}
55929893549SGatien Chevallier 
56029893549SGatien Chevallier 	return TEE_SUCCESS;
56129893549SGatien Chevallier }
56229893549SGatien Chevallier 
56329893549SGatien Chevallier static TEE_Result
stm32_rng_pm(enum pm_op op,unsigned int pm_hint __unused,const struct pm_callback_handle * pm_handle __unused)56429893549SGatien Chevallier stm32_rng_pm(enum pm_op op, unsigned int pm_hint __unused,
56529893549SGatien Chevallier 	     const struct pm_callback_handle *pm_handle __unused)
56629893549SGatien Chevallier {
56729893549SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
56829893549SGatien Chevallier 
56929893549SGatien Chevallier 	assert(stm32_rng && (op == PM_OP_SUSPEND || op == PM_OP_RESUME));
57029893549SGatien Chevallier 
571*d773ec0bSGatien Chevallier 	res = enable_rng_clock();
57229893549SGatien Chevallier 	if (res)
57329893549SGatien Chevallier 		return res;
57429893549SGatien Chevallier 
5755959d83fSGatien Chevallier 	if (op == PM_OP_RESUME)
5765959d83fSGatien Chevallier 		res = stm32_rng_pm_resume();
57729893549SGatien Chevallier 	else
5785959d83fSGatien Chevallier 		res = stm32_rng_pm_suspend();
57929893549SGatien Chevallier 
580*d773ec0bSGatien Chevallier 	disable_rng_clock();
58129893549SGatien Chevallier 
58229893549SGatien Chevallier 	return res;
58329893549SGatien Chevallier }
58429893549SGatien Chevallier DECLARE_KEEP_PAGER(stm32_rng_pm);
58529893549SGatien Chevallier 
stm32_rng_parse_fdt(const void * fdt,int node)586ea8ba295SGatien Chevallier static TEE_Result stm32_rng_parse_fdt(const void *fdt, int node)
587f3c22059SEtienne Carriere {
588d7a1a7d2SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
589ea8ba295SGatien Chevallier 	struct dt_node_info dt_rng = { };
590f3c22059SEtienne Carriere 
591f354a5d8SGatien Chevallier 	fdt_fill_device_info(fdt, &dt_rng, node);
592ea8ba295SGatien Chevallier 	if (dt_rng.reg == DT_INFO_INVALID_REG)
593ea8ba295SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
594f3c22059SEtienne Carriere 
595ea8ba295SGatien Chevallier 	stm32_rng->base.pa = dt_rng.reg;
596ea8ba295SGatien Chevallier 	stm32_rng->base.va = io_pa_or_va_secure(&stm32_rng->base,
597ea8ba295SGatien Chevallier 						dt_rng.reg_size);
598ea8ba295SGatien Chevallier 	assert(stm32_rng->base.va);
599f3c22059SEtienne Carriere 
600ea8ba295SGatien Chevallier 	res = rstctrl_dt_get_by_index(fdt, node, 0, &stm32_rng->rstctrl);
601ea8ba295SGatien Chevallier 	if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND)
602ea8ba295SGatien Chevallier 		return res;
60368c4a16bSEtienne Carriere 
60445da6509SGatien Chevallier 	if (stm32_rng->ddata->nb_clock > 1) {
60545da6509SGatien Chevallier 		res = clk_dt_get_by_name(fdt, node, "rng_clk",
60645da6509SGatien Chevallier 					 &stm32_rng->clock);
60745da6509SGatien Chevallier 		if (res)
60845da6509SGatien Chevallier 			return res;
60945da6509SGatien Chevallier 
61045da6509SGatien Chevallier 		res = clk_dt_get_by_name(fdt, node, "rng_hclk",
61145da6509SGatien Chevallier 					 &stm32_rng->bus_clock);
61245da6509SGatien Chevallier 		if (res)
61345da6509SGatien Chevallier 			return res;
61445da6509SGatien Chevallier 	} else {
615d7a1a7d2SEtienne Carriere 		res = clk_dt_get_by_index(fdt, node, 0, &stm32_rng->clock);
616d7a1a7d2SEtienne Carriere 		if (res)
617d7a1a7d2SEtienne Carriere 			return res;
61845da6509SGatien Chevallier 	}
619d7a1a7d2SEtienne Carriere 
6203c752300SGatien Chevallier 	if (fdt_getprop(fdt, node, "clock-error-detect", NULL))
6213c752300SGatien Chevallier 		stm32_rng->clock_error = true;
6223c752300SGatien Chevallier 
6235959d83fSGatien Chevallier 	stm32_rng->rng_config = stm32_rng->ddata->cr;
6245959d83fSGatien Chevallier 	if (stm32_rng->rng_config & ~RNG_CR_ENTROPY_SRC_MASK)
6255959d83fSGatien Chevallier 		panic("Incorrect entropy source configuration");
6265959d83fSGatien Chevallier 	stm32_rng->health_test_conf = stm32_rng->ddata->htcr;
6275959d83fSGatien Chevallier 	stm32_rng->noise_ctrl_conf = stm32_rng->ddata->nscr;
6285959d83fSGatien Chevallier 	if (stm32_rng->noise_ctrl_conf & ~RNG_NSCR_MASK)
6295959d83fSGatien Chevallier 		panic("Incorrect noise source control configuration");
6305959d83fSGatien Chevallier 
631f3c22059SEtienne Carriere 	return TEE_SUCCESS;
632f3c22059SEtienne Carriere }
633f3c22059SEtienne Carriere 
stm32_rng_probe(const void * fdt,int offs,const void * compat_data)634ea8ba295SGatien Chevallier static TEE_Result stm32_rng_probe(const void *fdt, int offs,
635f9508605SGatien Chevallier 				  const void *compat_data)
636ea8ba295SGatien Chevallier {
637b82b7e73SGatien Chevallier 	unsigned int __maybe_unused version = 0;
638*d773ec0bSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
639ea8ba295SGatien Chevallier 
640ea8ba295SGatien Chevallier 	/* Expect a single RNG instance */
641ea8ba295SGatien Chevallier 	assert(!stm32_rng);
642ea8ba295SGatien Chevallier 
643ea8ba295SGatien Chevallier 	stm32_rng = calloc(1, sizeof(*stm32_rng));
644ea8ba295SGatien Chevallier 	if (!stm32_rng)
645ea8ba295SGatien Chevallier 		panic();
646ea8ba295SGatien Chevallier 
6475959d83fSGatien Chevallier 	stm32_rng->ddata = compat_data;
6485959d83fSGatien Chevallier 	assert(stm32_rng->ddata);
6495959d83fSGatien Chevallier 
650ea8ba295SGatien Chevallier 	res = stm32_rng_parse_fdt(fdt, offs);
651ea8ba295SGatien Chevallier 	if (res)
652ea8ba295SGatien Chevallier 		goto err;
653ea8ba295SGatien Chevallier 
654*d773ec0bSGatien Chevallier 	res = enable_rng_clock();
655ea8ba295SGatien Chevallier 	if (res)
656ea8ba295SGatien Chevallier 		goto err;
657ea8ba295SGatien Chevallier 
658b82b7e73SGatien Chevallier 	version = io_read32(get_base() + RNG_VERR);
659b82b7e73SGatien Chevallier 	DMSG("RNG version Major %u, Minor %u",
660b82b7e73SGatien Chevallier 	     (version & RNG_VERR_MAJOR_MASK) >> RNG_VERR_MAJOR_SHIFT,
661b82b7e73SGatien Chevallier 	     version & RNG_VERR_MINOR_MASK);
662b82b7e73SGatien Chevallier 
663*d773ec0bSGatien Chevallier 	disable_rng_clock();
664ea8ba295SGatien Chevallier 
665*d773ec0bSGatien Chevallier 	res = stm32_rng_init();
666f63f11bdSGatien Chevallier 	if (res)
667*d773ec0bSGatien Chevallier 		goto err;
668f63f11bdSGatien Chevallier 
6695959d83fSGatien Chevallier 	/* Power management implementation expects both or none are set */
6705959d83fSGatien Chevallier 	assert(stm32_rng->ddata->has_power_optim ==
6715959d83fSGatien Chevallier 	       stm32_rng->ddata->has_cond_reset);
6725959d83fSGatien Chevallier 
673*d773ec0bSGatien Chevallier 	if (!IS_ENABLED(CFG_WITH_SOFTWARE_PRNG))
674*d773ec0bSGatien Chevallier 		register_pm_core_service_cb(stm32_rng_pm, &stm32_rng,
675*d773ec0bSGatien Chevallier 					    "rng-service");
67629893549SGatien Chevallier 
677ea8ba295SGatien Chevallier 	return TEE_SUCCESS;
678ea8ba295SGatien Chevallier 
679ea8ba295SGatien Chevallier err:
680ea8ba295SGatien Chevallier 	free(stm32_rng);
681ea8ba295SGatien Chevallier 	stm32_rng = NULL;
682ea8ba295SGatien Chevallier 
683ea8ba295SGatien Chevallier 	return res;
684ea8ba295SGatien Chevallier }
685ea8ba295SGatien Chevallier 
686091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp13_data[] = {
68745da6509SGatien Chevallier 	{
688aa12f203SGatien Chevallier 		.max_noise_clk_freq = U(48000000),
68945da6509SGatien Chevallier 		.nb_clock = 1,
69045da6509SGatien Chevallier 		.has_cond_reset = true,
6915959d83fSGatien Chevallier 		.has_power_optim = true,
6925959d83fSGatien Chevallier 		.cr = 0x00F00D00,
6935959d83fSGatien Chevallier 		.nscr = 0x2B5BB,
6945959d83fSGatien Chevallier 		.htcr = 0x969D,
69545da6509SGatien Chevallier 	},
696091ef005SGatien Chevallier };
697091ef005SGatien Chevallier 
698091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp15_data[] = {
69945da6509SGatien Chevallier 	{
700aa12f203SGatien Chevallier 		.max_noise_clk_freq = U(48000000),
70145da6509SGatien Chevallier 		.nb_clock = 1,
70245da6509SGatien Chevallier 		.has_cond_reset = false,
7035959d83fSGatien Chevallier 		.has_power_optim = false,
70445da6509SGatien Chevallier 	},
705091ef005SGatien Chevallier };
706091ef005SGatien Chevallier DECLARE_KEEP_PAGER(mp15_data);
707091ef005SGatien Chevallier 
70845da6509SGatien Chevallier static const struct stm32_rng_driver_data mp25_data[] = {
70945da6509SGatien Chevallier 	{
710aa12f203SGatien Chevallier 		.max_noise_clk_freq = U(48000000),
71145da6509SGatien Chevallier 		.nb_clock = 2,
71245da6509SGatien Chevallier 		.has_cond_reset = true,
7135959d83fSGatien Chevallier 		.has_power_optim = true,
7145959d83fSGatien Chevallier 		.cr = 0x00F00D00,
7155959d83fSGatien Chevallier 		.nscr = 0x2B5BB,
7165959d83fSGatien Chevallier 		.htcr = 0x969D,
71745da6509SGatien Chevallier 	},
71845da6509SGatien Chevallier };
71945da6509SGatien Chevallier 
720ea8ba295SGatien Chevallier static const struct dt_device_match rng_match_table[] = {
721091ef005SGatien Chevallier 	{ .compatible = "st,stm32-rng", .compat_data = &mp15_data },
722091ef005SGatien Chevallier 	{ .compatible = "st,stm32mp13-rng", .compat_data = &mp13_data },
72345da6509SGatien Chevallier 	{ .compatible = "st,stm32mp25-rng", .compat_data = &mp25_data },
724ea8ba295SGatien Chevallier 	{ }
725ea8ba295SGatien Chevallier };
726ea8ba295SGatien Chevallier 
727ea8ba295SGatien Chevallier DEFINE_DT_DRIVER(stm32_rng_dt_driver) = {
728ea8ba295SGatien Chevallier 	.name = "stm32_rng",
729ea8ba295SGatien Chevallier 	.match_table = rng_match_table,
730ea8ba295SGatien Chevallier 	.probe = stm32_rng_probe,
731ea8ba295SGatien Chevallier };
732d8682c4cSEtienne Carriere 
stm32_rng_release(void)733d8682c4cSEtienne Carriere static TEE_Result stm32_rng_release(void)
734d8682c4cSEtienne Carriere {
735*d773ec0bSGatien Chevallier 	if (stm32_rng && IS_ENABLED(CFG_WITH_SOFTWARE_PRNG)) {
736d8682c4cSEtienne Carriere 		DMSG("Release RNG driver");
737d8682c4cSEtienne Carriere 		free(stm32_rng);
738d8682c4cSEtienne Carriere 		stm32_rng = NULL;
739d8682c4cSEtienne Carriere 	}
740d8682c4cSEtienne Carriere 
741d8682c4cSEtienne Carriere 	return TEE_SUCCESS;
742d8682c4cSEtienne Carriere }
743d8682c4cSEtienne Carriere 
744d8682c4cSEtienne Carriere release_init_resource(stm32_rng_release);
745