xref: /optee_os/core/drivers/stm32_rng.c (revision d773ec0baf4ced1d5b29b86af1ceff16ac63a6a2)
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>
10*d773ec0bSGatien Chevallier #include <drivers/stm32_etzpc.h>
11*d773ec0bSGatien Chevallier #if defined(CFG_STM32MP15)
12*d773ec0bSGatien Chevallier #include <drivers/stm32mp1_etzpc.h>
13*d773ec0bSGatien Chevallier #endif /* defined(CFG_STM32MP15) */
14f3c22059SEtienne Carriere #include <io.h>
15f3c22059SEtienne Carriere #include <kernel/delay.h>
16a2fc83d1SJerome Forissier #include <kernel/dt.h>
17ea8ba295SGatien Chevallier #include <kernel/dt_driver.h>
18*d773ec0bSGatien Chevallier #include <kernel/boot.h>
19f3c22059SEtienne Carriere #include <kernel/panic.h>
2029893549SGatien Chevallier #include <kernel/pm.h>
2165b5ada4SMarouene Boubakri #include <kernel/thread.h>
22a2fc83d1SJerome Forissier #include <libfdt.h>
23f3c22059SEtienne Carriere #include <mm/core_memprot.h>
24097f329aSEtienne Carriere #include <rng_support.h>
25f3c22059SEtienne Carriere #include <stdbool.h>
26f3c22059SEtienne Carriere #include <stm32_util.h>
27f3c22059SEtienne Carriere #include <string.h>
28cd451498SEtienne Carriere #include <tee/tee_cryp_utl.h>
29f3c22059SEtienne Carriere 
300817aa6fSGatien Chevallier #define RNG_CR			U(0x00)
310817aa6fSGatien Chevallier #define RNG_SR			U(0x04)
320817aa6fSGatien Chevallier #define RNG_DR			U(0x08)
335959d83fSGatien Chevallier #define RNG_NSCR		U(0x0C)
345959d83fSGatien Chevallier #define RNG_HTCR		U(0x10)
35b82b7e73SGatien Chevallier #define RNG_VERR		U(0x3F4)
36f3c22059SEtienne Carriere 
37f3c22059SEtienne Carriere #define RNG_CR_RNGEN		BIT(2)
38f3c22059SEtienne Carriere #define RNG_CR_IE		BIT(3)
39f3c22059SEtienne Carriere #define RNG_CR_CED		BIT(5)
405959d83fSGatien Chevallier #define RNG_CR_CONFIG1		GENMASK_32(11, 8)
415959d83fSGatien Chevallier #define RNG_CR_NISTC		BIT(12)
425959d83fSGatien Chevallier #define RNG_CR_POWER_OPTIM	BIT(13)
435959d83fSGatien Chevallier #define RNG_CR_CONFIG2		GENMASK_32(15, 13)
44091ef005SGatien Chevallier #define RNG_CR_CLKDIV		GENMASK_32(19, 16)
45091ef005SGatien Chevallier #define RNG_CR_CLKDIV_SHIFT	U(16)
465959d83fSGatien Chevallier #define RNG_CR_CONFIG3		GENMASK_32(25, 20)
47091ef005SGatien Chevallier #define RNG_CR_CONDRST		BIT(30)
485959d83fSGatien Chevallier #define RNG_CR_ENTROPY_SRC_MASK	(RNG_CR_CONFIG1 | RNG_CR_NISTC | \
495959d83fSGatien Chevallier 				 RNG_CR_CONFIG2 | RNG_CR_CONFIG3)
50f3c22059SEtienne Carriere 
51f3c22059SEtienne Carriere #define RNG_SR_DRDY		BIT(0)
52f3c22059SEtienne Carriere #define RNG_SR_CECS		BIT(1)
53f3c22059SEtienne Carriere #define RNG_SR_SECS		BIT(2)
54f3c22059SEtienne Carriere #define RNG_SR_CEIS		BIT(5)
55f3c22059SEtienne Carriere #define RNG_SR_SEIS		BIT(6)
56f3c22059SEtienne Carriere 
575959d83fSGatien Chevallier #define RNG_NSCR_MASK		GENMASK_32(17, 0)
585959d83fSGatien Chevallier 
59b82b7e73SGatien Chevallier #define RNG_VERR_MINOR_MASK	GENMASK_32(3, 0)
60b82b7e73SGatien Chevallier #define RNG_VERR_MAJOR_MASK	GENMASK_32(7, 4)
61b82b7e73SGatien Chevallier #define RNG_VERR_MAJOR_SHIFT	U(4)
62b82b7e73SGatien Chevallier 
630817aa6fSGatien Chevallier #if TRACE_LEVEL > TRACE_DEBUG
640817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US	U(100000)
650817aa6fSGatien Chevallier #else
660817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US	U(10000)
670817aa6fSGatien Chevallier #endif
68ea8ba295SGatien Chevallier #define RNG_RESET_TIMEOUT_US	U(1000)
69f3c22059SEtienne Carriere 
700817aa6fSGatien Chevallier #define RNG_FIFO_BYTE_DEPTH	U(16)
710817aa6fSGatien Chevallier 
725959d83fSGatien Chevallier #define RNG_CONFIG_MASK		(RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED | \
735959d83fSGatien Chevallier 				 RNG_CR_CLKDIV)
74091ef005SGatien Chevallier 
75091ef005SGatien Chevallier struct stm32_rng_driver_data {
76aa12f203SGatien Chevallier 	unsigned long max_noise_clk_freq;
7745da6509SGatien Chevallier 	unsigned long nb_clock;
785959d83fSGatien Chevallier 	uint32_t cr;
795959d83fSGatien Chevallier 	uint32_t nscr;
805959d83fSGatien Chevallier 	uint32_t htcr;
815959d83fSGatien Chevallier 	bool has_power_optim;
82091ef005SGatien Chevallier 	bool has_cond_reset;
83091ef005SGatien Chevallier };
84091ef005SGatien Chevallier 
85f3c22059SEtienne Carriere struct stm32_rng_instance {
86f3c22059SEtienne Carriere 	struct io_pa_va base;
87d7a1a7d2SEtienne Carriere 	struct clk *clock;
8845da6509SGatien Chevallier 	struct clk *bus_clock;
89ea8ba295SGatien Chevallier 	struct rstctrl *rstctrl;
90091ef005SGatien Chevallier 	const struct stm32_rng_driver_data *ddata;
91f3c22059SEtienne Carriere 	unsigned int lock;
925959d83fSGatien Chevallier 	uint64_t error_to_ref;
935959d83fSGatien Chevallier 	uint32_t pm_cr;
945959d83fSGatien Chevallier 	uint32_t pm_health;
955959d83fSGatien Chevallier 	uint32_t pm_noise_ctrl;
965959d83fSGatien Chevallier 	uint32_t health_test_conf;
975959d83fSGatien Chevallier 	uint32_t noise_ctrl_conf;
985959d83fSGatien Chevallier 	uint32_t rng_config;
993c752300SGatien Chevallier 	bool clock_error;
100091ef005SGatien Chevallier 	bool error_conceal;
101f3c22059SEtienne Carriere };
102f3c22059SEtienne Carriere 
103ea8ba295SGatien Chevallier /* Expect at most a single RNG instance */
104f3c22059SEtienne Carriere static struct stm32_rng_instance *stm32_rng;
105f3c22059SEtienne Carriere 
106f63f11bdSGatien Chevallier static vaddr_t get_base(void)
107f63f11bdSGatien Chevallier {
108f63f11bdSGatien Chevallier 	assert(stm32_rng);
109f63f11bdSGatien Chevallier 
110f63f11bdSGatien Chevallier 	return io_pa_or_va(&stm32_rng->base, 1);
111f63f11bdSGatien Chevallier }
112f63f11bdSGatien Chevallier 
113f3c22059SEtienne Carriere /*
114091ef005SGatien Chevallier  * Extracts from the STM32 RNG specification when RNG supports CONDRST.
115f3c22059SEtienne Carriere  *
116f3c22059SEtienne Carriere  * When a noise source (or seed) error occurs, the RNG stops generating
117f3c22059SEtienne Carriere  * random numbers and sets to “1” both SEIS and SECS bits to indicate
118f3c22059SEtienne Carriere  * that a seed error occurred. (...)
119091ef005SGatien Chevallier  *
120091ef005SGatien Chevallier  * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield
121091ef005SGatien Chevallier  * description for details). This step is needed only if SECS is set.
122091ef005SGatien Chevallier  * Indeed, when SEIS is set and SECS is cleared it means RNG performed
123091ef005SGatien Chevallier  * the reset automatically (auto-reset).
124091ef005SGatien Chevallier  * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST
125091ef005SGatien Chevallier  * to be cleared in the RNG_CR register, then confirm that SEIS is
126091ef005SGatien Chevallier  * cleared in the RNG_SR register. Otherwise just clear SEIS bit in
127091ef005SGatien Chevallier  * the RNG_SR register.
128091ef005SGatien Chevallier  * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be
129091ef005SGatien Chevallier  * cleared by RNG. The random number generation is now back to normal.
130091ef005SGatien Chevallier  */
131091ef005SGatien Chevallier static void conceal_seed_error_cond_reset(void)
132091ef005SGatien Chevallier {
133091ef005SGatien Chevallier 	struct stm32_rng_instance *dev = stm32_rng;
134091ef005SGatien Chevallier 	vaddr_t rng_base = get_base();
135f3c22059SEtienne Carriere 
136091ef005SGatien Chevallier 	if (!dev->error_conceal) {
137091ef005SGatien Chevallier 		uint32_t sr = io_read32(rng_base + RNG_SR);
138091ef005SGatien Chevallier 
139091ef005SGatien Chevallier 		if (sr & RNG_SR_SECS) {
140091ef005SGatien Chevallier 			/* Conceal by resetting the subsystem (step 1.) */
141091ef005SGatien Chevallier 			io_setbits32(rng_base + RNG_CR, RNG_CR_CONDRST);
142091ef005SGatien Chevallier 			io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST);
143091ef005SGatien Chevallier 
144091ef005SGatien Chevallier 			/* Arm timeout for error_conceal sequence */
145091ef005SGatien Chevallier 			dev->error_to_ref =
146091ef005SGatien Chevallier 				timeout_init_us(RNG_READY_TIMEOUT_US);
147091ef005SGatien Chevallier 			dev->error_conceal = true;
148091ef005SGatien Chevallier 		} else {
149091ef005SGatien Chevallier 			/* RNG auto-reset (step 2.) */
150091ef005SGatien Chevallier 			io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS);
151091ef005SGatien Chevallier 		}
152091ef005SGatien Chevallier 	} else {
153091ef005SGatien Chevallier 		/* Measure time before possible reschedule */
154091ef005SGatien Chevallier 		bool timed_out = timeout_elapsed(dev->error_to_ref);
155091ef005SGatien Chevallier 
156091ef005SGatien Chevallier 		/* Wait CONDRST is cleared (step 2.) */
157091ef005SGatien Chevallier 		if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) {
158091ef005SGatien Chevallier 			if (timed_out)
159091ef005SGatien Chevallier 				panic();
160091ef005SGatien Chevallier 
161091ef005SGatien Chevallier 			/* Wait subsystem reset cycle completes */
162091ef005SGatien Chevallier 			return;
163091ef005SGatien Chevallier 		}
164091ef005SGatien Chevallier 
165091ef005SGatien Chevallier 		/* Check SEIS is cleared (step 2.) */
166091ef005SGatien Chevallier 		if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS)
167091ef005SGatien Chevallier 			panic();
168091ef005SGatien Chevallier 
169091ef005SGatien Chevallier 		/* Wait SECS is cleared (step 3.) */
170091ef005SGatien Chevallier 		if (io_read32(rng_base + RNG_SR) & RNG_SR_SECS) {
171091ef005SGatien Chevallier 			if (timed_out)
172091ef005SGatien Chevallier 				panic();
173091ef005SGatien Chevallier 
174091ef005SGatien Chevallier 			/* Wait subsystem reset cycle completes */
175091ef005SGatien Chevallier 			return;
176091ef005SGatien Chevallier 		}
177091ef005SGatien Chevallier 
178091ef005SGatien Chevallier 		dev->error_conceal = false;
179091ef005SGatien Chevallier 	}
180091ef005SGatien Chevallier }
181091ef005SGatien Chevallier 
182091ef005SGatien Chevallier /*
183091ef005SGatien Chevallier  * Extracts from the STM32 RNG specification, when CONDRST is not supported
184091ef005SGatien Chevallier  *
185091ef005SGatien Chevallier  * When a noise source (or seed) error occurs, the RNG stops generating
186091ef005SGatien Chevallier  * random numbers and sets to “1” both SEIS and SECS bits to indicate
187091ef005SGatien Chevallier  * that a seed error occurred. (...)
188091ef005SGatien Chevallier  *
189f3c22059SEtienne Carriere  * The following sequence shall be used to fully recover from a seed
190f3c22059SEtienne Carriere  * error after the RNG initialization:
191f3c22059SEtienne Carriere  * 1. Clear the SEIS bit by writing it to “0”.
192f3c22059SEtienne Carriere  * 2. Read out 12 words from the RNG_DR register, and discard each of
193f3c22059SEtienne Carriere  * them in order to clean the pipeline.
194f3c22059SEtienne Carriere  * 3. Confirm that SEIS is still cleared. Random number generation is
195f3c22059SEtienne Carriere  * back to normal.
196f3c22059SEtienne Carriere  */
197091ef005SGatien Chevallier static void conceal_seed_error_sw_reset(void)
198f3c22059SEtienne Carriere {
1996a6b6168SGatien Chevallier 	vaddr_t rng_base = get_base();
200f3c22059SEtienne Carriere 	size_t i = 0;
201f3c22059SEtienne Carriere 
2026a6b6168SGatien Chevallier 	io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS);
203f3c22059SEtienne Carriere 
204f3c22059SEtienne Carriere 	for (i = 12; i != 0; i--)
205f3c22059SEtienne Carriere 		(void)io_read32(rng_base + RNG_DR);
206f3c22059SEtienne Carriere 
207f3c22059SEtienne Carriere 	if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS)
208f3c22059SEtienne Carriere 		panic("RNG noise");
209f3c22059SEtienne Carriere }
210f3c22059SEtienne Carriere 
211091ef005SGatien Chevallier static void conceal_seed_error(void)
212091ef005SGatien Chevallier {
213091ef005SGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset)
214091ef005SGatien Chevallier 		conceal_seed_error_cond_reset();
215091ef005SGatien Chevallier 	else
216091ef005SGatien Chevallier 		conceal_seed_error_sw_reset();
217091ef005SGatien Chevallier }
218091ef005SGatien Chevallier 
219c99311c8SEtienne Carriere static TEE_Result read_available(vaddr_t rng_base, uint8_t *out, size_t *size)
220f3c22059SEtienne Carriere {
221091ef005SGatien Chevallier 	struct stm32_rng_instance *dev = stm32_rng;
222c99311c8SEtienne Carriere 	uint8_t *buf = NULL;
223c99311c8SEtienne Carriere 	size_t req_size = 0;
224c99311c8SEtienne Carriere 	size_t len = 0;
225f3c22059SEtienne Carriere 
226091ef005SGatien Chevallier 	if (dev->error_conceal || io_read32(rng_base + RNG_SR) & RNG_SR_SEIS)
2276a6b6168SGatien Chevallier 		conceal_seed_error();
228f3c22059SEtienne Carriere 
22923123473SEtienne Carriere 	if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) {
23023123473SEtienne Carriere 		FMSG("RNG not ready");
231c99311c8SEtienne Carriere 		return TEE_ERROR_NO_DATA;
23223123473SEtienne Carriere 	}
233f3c22059SEtienne Carriere 
23423123473SEtienne Carriere 	if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) {
23523123473SEtienne Carriere 		FMSG("RNG noise error");
236c99311c8SEtienne Carriere 		return TEE_ERROR_NO_DATA;
23723123473SEtienne Carriere 	}
238c99311c8SEtienne Carriere 
239c99311c8SEtienne Carriere 	buf = out;
240c99311c8SEtienne Carriere 	req_size = MIN(RNG_FIFO_BYTE_DEPTH, *size);
241c99311c8SEtienne Carriere 	len = req_size;
242f3c22059SEtienne Carriere 
243f3c22059SEtienne Carriere 	/* RNG is ready: read up to 4 32bit words */
244f3c22059SEtienne Carriere 	while (len) {
24523bdf063SEtienne Carriere 		uint32_t data32 = 0;
246f3c22059SEtienne Carriere 		size_t sz = MIN(len, sizeof(uint32_t));
247f3c22059SEtienne Carriere 
24823bdf063SEtienne Carriere 		if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY))
24923bdf063SEtienne Carriere 			break;
25023bdf063SEtienne Carriere 		data32 = io_read32(rng_base + RNG_DR);
25123bdf063SEtienne Carriere 
2523e64c635SGatien Chevallier 		/* Late seed error case: DR being 0 is an error status */
2533e64c635SGatien Chevallier 		if (!data32) {
2543e64c635SGatien Chevallier 			conceal_seed_error();
2553e64c635SGatien Chevallier 			return TEE_ERROR_NO_DATA;
2563e64c635SGatien Chevallier 		}
2573e64c635SGatien Chevallier 
258f3c22059SEtienne Carriere 		memcpy(buf, &data32, sz);
259f3c22059SEtienne Carriere 		buf += sz;
260f3c22059SEtienne Carriere 		len -= sz;
261f3c22059SEtienne Carriere 	}
262c99311c8SEtienne Carriere 
26323bdf063SEtienne Carriere 	*size = req_size - len;
264f3c22059SEtienne Carriere 
265c99311c8SEtienne Carriere 	return TEE_SUCCESS;
266f3c22059SEtienne Carriere }
267f3c22059SEtienne Carriere 
268091ef005SGatien Chevallier static uint32_t stm32_rng_clock_freq_restrain(void)
269091ef005SGatien Chevallier {
270091ef005SGatien Chevallier 	struct stm32_rng_instance *dev = stm32_rng;
271091ef005SGatien Chevallier 	unsigned long clock_rate = 0;
272091ef005SGatien Chevallier 	uint32_t clock_div = 0;
273091ef005SGatien Chevallier 
274091ef005SGatien Chevallier 	clock_rate = clk_get_rate(dev->clock);
275091ef005SGatien Chevallier 
276091ef005SGatien Chevallier 	/*
277091ef005SGatien Chevallier 	 * Get the exponent to apply on the CLKDIV field in RNG_CR register
278091ef005SGatien Chevallier 	 * No need to handle the case when clock-div > 0xF as it is physically
279091ef005SGatien Chevallier 	 * impossible
280091ef005SGatien Chevallier 	 */
281aa12f203SGatien Chevallier 	while ((clock_rate >> clock_div) > dev->ddata->max_noise_clk_freq)
282091ef005SGatien Chevallier 		clock_div++;
283091ef005SGatien Chevallier 
284091ef005SGatien Chevallier 	DMSG("RNG clk rate : %lu", clk_get_rate(dev->clock) >> clock_div);
285091ef005SGatien Chevallier 
286091ef005SGatien Chevallier 	return clock_div;
287091ef005SGatien Chevallier }
288091ef005SGatien Chevallier 
289*d773ec0bSGatien Chevallier static TEE_Result enable_rng_clock(void)
290f3c22059SEtienne Carriere {
291*d773ec0bSGatien Chevallier 	TEE_Result res = clk_enable(stm32_rng->clock);
292*d773ec0bSGatien Chevallier 
293*d773ec0bSGatien Chevallier 	if (!res && stm32_rng->bus_clock) {
294*d773ec0bSGatien Chevallier 		res = clk_enable(stm32_rng->bus_clock);
295*d773ec0bSGatien Chevallier 		if (res)
296*d773ec0bSGatien Chevallier 			clk_disable(stm32_rng->clock);
297*d773ec0bSGatien Chevallier 	}
298*d773ec0bSGatien Chevallier 
299*d773ec0bSGatien Chevallier 	return res;
300*d773ec0bSGatien Chevallier }
301*d773ec0bSGatien Chevallier 
302*d773ec0bSGatien Chevallier static void disable_rng_clock(void)
303*d773ec0bSGatien Chevallier {
304*d773ec0bSGatien Chevallier 	clk_disable(stm32_rng->clock);
305*d773ec0bSGatien Chevallier 	if (stm32_rng->bus_clock)
306*d773ec0bSGatien Chevallier 		clk_disable(stm32_rng->bus_clock);
307*d773ec0bSGatien Chevallier }
308*d773ec0bSGatien Chevallier 
309*d773ec0bSGatien Chevallier static TEE_Result stm32_rng_init(void)
310*d773ec0bSGatien Chevallier {
311*d773ec0bSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
312f63f11bdSGatien Chevallier 	vaddr_t rng_base = get_base();
3133c752300SGatien Chevallier 	uint32_t cr_ced_mask = 0;
3145959d83fSGatien Chevallier 	uint32_t value = 0;
3153c752300SGatien Chevallier 
316*d773ec0bSGatien Chevallier 	res = enable_rng_clock();
317*d773ec0bSGatien Chevallier 	if (res)
318*d773ec0bSGatien Chevallier 		return res;
319*d773ec0bSGatien Chevallier 
320*d773ec0bSGatien Chevallier 	if (stm32_rng->rstctrl &&
321*d773ec0bSGatien Chevallier 	    rstctrl_assert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) {
322*d773ec0bSGatien Chevallier 		res = TEE_ERROR_GENERIC;
323*d773ec0bSGatien Chevallier 		goto out;
324*d773ec0bSGatien Chevallier 	}
325*d773ec0bSGatien Chevallier 
326*d773ec0bSGatien Chevallier 	if (stm32_rng->rstctrl &&
327*d773ec0bSGatien Chevallier 	    rstctrl_deassert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) {
328*d773ec0bSGatien Chevallier 		res = TEE_ERROR_GENERIC;
329*d773ec0bSGatien Chevallier 		goto out;
330*d773ec0bSGatien Chevallier 	}
331*d773ec0bSGatien Chevallier 
3323c752300SGatien Chevallier 	if (!stm32_rng->clock_error)
3333c752300SGatien Chevallier 		cr_ced_mask = RNG_CR_CED;
334f3c22059SEtienne Carriere 
335f63f11bdSGatien Chevallier 	/* Clean error indications */
336f63f11bdSGatien Chevallier 	io_write32(rng_base + RNG_SR, 0);
337f3c22059SEtienne Carriere 
338091ef005SGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset) {
339091ef005SGatien Chevallier 		uint32_t clock_div = stm32_rng_clock_freq_restrain();
340091ef005SGatien Chevallier 
3415959d83fSGatien Chevallier 		/*
3425959d83fSGatien Chevallier 		 * Keep default RNG configuration if none was specified.
3435959d83fSGatien Chevallier 		 * 0 is an invalid value as it disables all entropy sources.
3445959d83fSGatien Chevallier 		 */
3455959d83fSGatien Chevallier 		if (!stm32_rng->rng_config)
3465959d83fSGatien Chevallier 			stm32_rng->rng_config = io_read32(rng_base + RNG_CR) &
3475959d83fSGatien Chevallier 						RNG_CR_ENTROPY_SRC_MASK;
3485959d83fSGatien Chevallier 
3495959d83fSGatien Chevallier 		/*
3505959d83fSGatien Chevallier 		 * Configuration must be set in the same access that sets
3515959d83fSGatien Chevallier 		 * RNG_CR_CONDRST bit. Otherwise, the configuration setting is
3525959d83fSGatien Chevallier 		 * not taken into account. CONFIGLOCK bit is always cleared at
3535959d83fSGatien Chevallier 		 * this stage.
3545959d83fSGatien Chevallier 		 */
3555959d83fSGatien Chevallier 		io_clrsetbits32(rng_base + RNG_CR, RNG_CONFIG_MASK,
3565959d83fSGatien Chevallier 				stm32_rng->rng_config | RNG_CR_CONDRST |
3575959d83fSGatien Chevallier 				cr_ced_mask |
3585959d83fSGatien Chevallier 				SHIFT_U32(clock_div, RNG_CR_CLKDIV_SHIFT));
3595959d83fSGatien Chevallier 
3605959d83fSGatien Chevallier 		/*
3615959d83fSGatien Chevallier 		 * Write health test and noise source control configuration
3625959d83fSGatien Chevallier 		 * according to current RNG entropy source configuration
3635959d83fSGatien Chevallier 		 */
3645959d83fSGatien Chevallier 		if (stm32_rng->noise_ctrl_conf)
3655959d83fSGatien Chevallier 			io_write32(rng_base + RNG_NSCR,
3665959d83fSGatien Chevallier 				   stm32_rng->noise_ctrl_conf);
3675959d83fSGatien Chevallier 
3685959d83fSGatien Chevallier 		if (stm32_rng->health_test_conf)
3695959d83fSGatien Chevallier 			io_write32(rng_base + RNG_HTCR,
3705959d83fSGatien Chevallier 				   stm32_rng->health_test_conf);
371091ef005SGatien Chevallier 
372091ef005SGatien Chevallier 		io_clrsetbits32(rng_base + RNG_CR, RNG_CR_CONDRST,
373091ef005SGatien Chevallier 				RNG_CR_RNGEN);
374eb5cf770SGatien Chevallier 
3755959d83fSGatien Chevallier 		if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_CR, value,
3765959d83fSGatien Chevallier 					   !(value & RNG_CR_CONDRST), 0,
3775959d83fSGatien Chevallier 					   RNG_READY_TIMEOUT_US))
378eb5cf770SGatien Chevallier 			panic();
3795959d83fSGatien Chevallier 
3805959d83fSGatien Chevallier 		DMSG("RNG control register %#"PRIx32,
3815959d83fSGatien Chevallier 		     io_read32(rng_base + RNG_CR));
3825959d83fSGatien Chevallier 		DMSG("RNG noise source control register %#"PRIx32,
3835959d83fSGatien Chevallier 		     io_read32(rng_base + RNG_NSCR));
3845959d83fSGatien Chevallier 		DMSG("RNG health test register %#"PRIx32,
3855959d83fSGatien Chevallier 		     io_read32(rng_base + RNG_HTCR));
386091ef005SGatien Chevallier 	} else {
3873c752300SGatien Chevallier 		io_setbits32(rng_base + RNG_CR, RNG_CR_RNGEN | cr_ced_mask);
388091ef005SGatien Chevallier 	}
389f63f11bdSGatien Chevallier 
3905959d83fSGatien Chevallier 	if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_SR, value,
3915959d83fSGatien Chevallier 				   value & RNG_SR_DRDY, 0,
3925959d83fSGatien Chevallier 				   RNG_READY_TIMEOUT_US))
393f63f11bdSGatien Chevallier 		return TEE_ERROR_GENERIC;
394f63f11bdSGatien Chevallier 
395*d773ec0bSGatien Chevallier 	res =  TEE_SUCCESS;
396*d773ec0bSGatien Chevallier 
397*d773ec0bSGatien Chevallier out:
398*d773ec0bSGatien Chevallier 	disable_rng_clock();
399*d773ec0bSGatien Chevallier 
400*d773ec0bSGatien Chevallier 	return res;
401f3c22059SEtienne Carriere }
402f3c22059SEtienne Carriere 
40398c36268SGatien Chevallier static TEE_Result stm32_rng_read(uint8_t *out, size_t size)
404f3c22059SEtienne Carriere {
405c99311c8SEtienne Carriere 	TEE_Result rc = TEE_ERROR_GENERIC;
406c99311c8SEtienne Carriere 	bool burst_timeout = false;
407c99311c8SEtienne Carriere 	uint64_t timeout_ref = 0;
408f3c22059SEtienne Carriere 	uint32_t exceptions = 0;
409f3c22059SEtienne Carriere 	uint8_t *out_ptr = out;
410c99311c8SEtienne Carriere 	vaddr_t rng_base = 0;
411f3c22059SEtienne Carriere 	size_t out_size = 0;
412f3c22059SEtienne Carriere 
413f3c22059SEtienne Carriere 	if (!stm32_rng) {
414f3c22059SEtienne Carriere 		DMSG("No RNG");
415f3c22059SEtienne Carriere 		return TEE_ERROR_NOT_SUPPORTED;
416f3c22059SEtienne Carriere 	}
417f3c22059SEtienne Carriere 
418*d773ec0bSGatien Chevallier 	rc = enable_rng_clock();
419fb1681dfSGatien Chevallier 	if (rc)
420fb1681dfSGatien Chevallier 		return rc;
421fb1681dfSGatien Chevallier 
422f63f11bdSGatien Chevallier 	rng_base = get_base();
423c99311c8SEtienne Carriere 
424c99311c8SEtienne Carriere 	/* Arm timeout */
4250817aa6fSGatien Chevallier 	timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
426c99311c8SEtienne Carriere 	burst_timeout = false;
427f3c22059SEtienne Carriere 
428f3c22059SEtienne Carriere 	while (out_size < size) {
429f3c22059SEtienne Carriere 		/* Read by chunks of the size the RNG FIFO depth */
430f3c22059SEtienne Carriere 		size_t sz = size - out_size;
431f3c22059SEtienne Carriere 
432f3c22059SEtienne Carriere 		exceptions = may_spin_lock(&stm32_rng->lock);
433f3c22059SEtienne Carriere 
434c99311c8SEtienne Carriere 		rc = read_available(rng_base, out_ptr, &sz);
435c99311c8SEtienne Carriere 
436c99311c8SEtienne Carriere 		/* Raise timeout only if we failed to get some samples */
437c99311c8SEtienne Carriere 		assert(!rc || rc == TEE_ERROR_NO_DATA);
438c99311c8SEtienne Carriere 		if (rc)
439c99311c8SEtienne Carriere 			burst_timeout = timeout_elapsed(timeout_ref);
440f3c22059SEtienne Carriere 
441f3c22059SEtienne Carriere 		may_spin_unlock(&stm32_rng->lock, exceptions);
442f3c22059SEtienne Carriere 
443c99311c8SEtienne Carriere 		if (burst_timeout) {
444c99311c8SEtienne Carriere 			rc = TEE_ERROR_GENERIC;
445c99311c8SEtienne Carriere 			goto out;
446f3c22059SEtienne Carriere 		}
447f3c22059SEtienne Carriere 
448c99311c8SEtienne Carriere 		if (!rc) {
449c99311c8SEtienne Carriere 			out_size += sz;
450c99311c8SEtienne Carriere 			out_ptr += sz;
451c99311c8SEtienne Carriere 			/* Re-arm timeout */
4520817aa6fSGatien Chevallier 			timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
453c99311c8SEtienne Carriere 			burst_timeout = false;
454c99311c8SEtienne Carriere 		}
455c99311c8SEtienne Carriere 	}
456c99311c8SEtienne Carriere 
457c99311c8SEtienne Carriere out:
458c99311c8SEtienne Carriere 	assert(!rc || rc == TEE_ERROR_GENERIC);
459*d773ec0bSGatien Chevallier 	disable_rng_clock();
460f3c22059SEtienne Carriere 
461f3c22059SEtienne Carriere 	return rc;
462f3c22059SEtienne Carriere }
463f3c22059SEtienne Carriere 
464cd451498SEtienne Carriere #ifdef CFG_WITH_SOFTWARE_PRNG
465f2fe4f00SThomas Bourgoin /* Override weak plat_rng_init with platform handler to attempt to seed PRNG */
466cd451498SEtienne Carriere void plat_rng_init(void)
467cd451498SEtienne Carriere {
468cd451498SEtienne Carriere 	uint8_t seed[RNG_FIFO_BYTE_DEPTH] = { };
469cd451498SEtienne Carriere 
470f2fe4f00SThomas Bourgoin 	if (!stm32_rng) {
471f2fe4f00SThomas Bourgoin 		__plat_rng_init();
472f2fe4f00SThomas Bourgoin 		DMSG("PRNG seeded without RNG");
473f2fe4f00SThomas Bourgoin 		return;
474f2fe4f00SThomas Bourgoin 	}
475f2fe4f00SThomas Bourgoin 
476cd451498SEtienne Carriere 	if (stm32_rng_read(seed, sizeof(seed)))
477cd451498SEtienne Carriere 		panic();
478cd451498SEtienne Carriere 
479cd451498SEtienne Carriere 	if (crypto_rng_init(seed, sizeof(seed)))
480cd451498SEtienne Carriere 		panic();
481cd451498SEtienne Carriere 
482cd451498SEtienne Carriere 	DMSG("PRNG seeded with RNG");
483cd451498SEtienne Carriere }
484cd451498SEtienne Carriere #else
485cb2478efSAndrew Davis TEE_Result hw_get_random_bytes(void *out, size_t size)
486097f329aSEtienne Carriere {
487097f329aSEtienne Carriere 	return stm32_rng_read(out, size);
488097f329aSEtienne Carriere }
48927f3087bSGatien Chevallier 
49027f3087bSGatien Chevallier void plat_rng_init(void)
49127f3087bSGatien Chevallier {
49227f3087bSGatien Chevallier }
493097f329aSEtienne Carriere #endif
494097f329aSEtienne Carriere 
4955959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_resume(void)
49629893549SGatien Chevallier {
49729893549SGatien Chevallier 	vaddr_t base = get_base();
49829893549SGatien Chevallier 
49929893549SGatien Chevallier 	/* Clean error indications */
50029893549SGatien Chevallier 	io_write32(base + RNG_SR, 0);
50129893549SGatien Chevallier 
50229893549SGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset) {
503eb5cf770SGatien Chevallier 		uint64_t timeout_ref = 0;
504eb5cf770SGatien Chevallier 
50529893549SGatien Chevallier 		/*
506c2c5b4beSGatien Chevallier 		 * Configuration must be set in the same access that sets
507c2c5b4beSGatien Chevallier 		 * RNG_CR_CONDRST bit. Otherwise, the configuration setting is
508c2c5b4beSGatien Chevallier 		 * not taken into account. CONFIGLOCK bit is always cleared in
509c2c5b4beSGatien Chevallier 		 * this configuration.
51029893549SGatien Chevallier 		 */
5115959d83fSGatien Chevallier 		io_write32(base + RNG_CR, stm32_rng->pm_cr | RNG_CR_CONDRST);
5125959d83fSGatien Chevallier 
5135959d83fSGatien Chevallier 		/* Restore health test and noise control configuration */
5145959d83fSGatien Chevallier 		io_write32(base + RNG_NSCR, stm32_rng->pm_noise_ctrl);
5155959d83fSGatien Chevallier 		io_write32(base + RNG_HTCR, stm32_rng->pm_health);
51629893549SGatien Chevallier 
51729893549SGatien Chevallier 		io_clrsetbits32(base + RNG_CR, RNG_CR_CONDRST, RNG_CR_RNGEN);
518eb5cf770SGatien Chevallier 
519eb5cf770SGatien Chevallier 		timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
520eb5cf770SGatien Chevallier 		while (io_read32(base + RNG_CR) & RNG_CR_CONDRST)
521eb5cf770SGatien Chevallier 			if (timeout_elapsed(timeout_ref))
522eb5cf770SGatien Chevallier 				break;
523eb5cf770SGatien Chevallier 		if (io_read32(base + RNG_CR) & RNG_CR_CONDRST)
524eb5cf770SGatien Chevallier 			panic();
52529893549SGatien Chevallier 	} else {
5265959d83fSGatien Chevallier 		io_write32(base + RNG_CR, RNG_CR_RNGEN | stm32_rng->pm_cr);
5275959d83fSGatien Chevallier 	}
5285959d83fSGatien Chevallier 
5295959d83fSGatien Chevallier 	return TEE_SUCCESS;
5305959d83fSGatien Chevallier }
5315959d83fSGatien Chevallier 
5325959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_suspend(void)
5335959d83fSGatien Chevallier {
5345959d83fSGatien Chevallier 	vaddr_t rng_base = get_base();
5355959d83fSGatien Chevallier 
5365959d83fSGatien Chevallier 	stm32_rng->pm_cr = io_read32(rng_base + RNG_CR);
5375959d83fSGatien Chevallier 
5385959d83fSGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset) {
5395959d83fSGatien Chevallier 		stm32_rng->pm_health = io_read32(rng_base + RNG_HTCR);
5405959d83fSGatien Chevallier 		stm32_rng->pm_noise_ctrl = io_read32(rng_base + RNG_NSCR);
5415959d83fSGatien Chevallier 	}
5425959d83fSGatien Chevallier 
5435959d83fSGatien Chevallier 	if (stm32_rng->ddata->has_power_optim) {
5445959d83fSGatien Chevallier 		uint64_t timeout_ref = 0;
5455959d83fSGatien Chevallier 
5465959d83fSGatien Chevallier 		/*
5475959d83fSGatien Chevallier 		 * As per reference manual, it is recommended to set
5485959d83fSGatien Chevallier 		 * RNG_CONFIG2[bit0] when RNG power consumption is critical.
5495959d83fSGatien Chevallier 		 */
5505959d83fSGatien Chevallier 		io_setbits32(rng_base + RNG_CR, RNG_CR_POWER_OPTIM |
5515959d83fSGatien Chevallier 				RNG_CR_CONDRST);
5525959d83fSGatien Chevallier 		io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST);
5535959d83fSGatien Chevallier 
5545959d83fSGatien Chevallier 		timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
5555959d83fSGatien Chevallier 		while (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST)
5565959d83fSGatien Chevallier 			if (timeout_elapsed(timeout_ref))
5575959d83fSGatien Chevallier 				break;
5585959d83fSGatien Chevallier 		if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST)
5595959d83fSGatien Chevallier 			panic();
5605959d83fSGatien Chevallier 	} else {
5615959d83fSGatien Chevallier 		io_clrbits32(rng_base + RNG_CR, RNG_CR_RNGEN);
56229893549SGatien Chevallier 	}
56329893549SGatien Chevallier 
56429893549SGatien Chevallier 	return TEE_SUCCESS;
56529893549SGatien Chevallier }
56629893549SGatien Chevallier 
56729893549SGatien Chevallier static TEE_Result
56829893549SGatien Chevallier stm32_rng_pm(enum pm_op op, unsigned int pm_hint __unused,
56929893549SGatien Chevallier 	     const struct pm_callback_handle *pm_handle __unused)
57029893549SGatien Chevallier {
57129893549SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
57229893549SGatien Chevallier 
57329893549SGatien Chevallier 	assert(stm32_rng && (op == PM_OP_SUSPEND || op == PM_OP_RESUME));
57429893549SGatien Chevallier 
575*d773ec0bSGatien Chevallier 	res = enable_rng_clock();
57629893549SGatien Chevallier 	if (res)
57729893549SGatien Chevallier 		return res;
57829893549SGatien Chevallier 
5795959d83fSGatien Chevallier 	if (op == PM_OP_RESUME)
5805959d83fSGatien Chevallier 		res = stm32_rng_pm_resume();
58129893549SGatien Chevallier 	else
5825959d83fSGatien Chevallier 		res = stm32_rng_pm_suspend();
58329893549SGatien Chevallier 
584*d773ec0bSGatien Chevallier 	disable_rng_clock();
58529893549SGatien Chevallier 
58629893549SGatien Chevallier 	return res;
58729893549SGatien Chevallier }
58829893549SGatien Chevallier DECLARE_KEEP_PAGER(stm32_rng_pm);
58929893549SGatien Chevallier 
590ea8ba295SGatien Chevallier static TEE_Result stm32_rng_parse_fdt(const void *fdt, int node)
591f3c22059SEtienne Carriere {
592d7a1a7d2SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
593ea8ba295SGatien Chevallier 	struct dt_node_info dt_rng = { };
594f3c22059SEtienne Carriere 
595f354a5d8SGatien Chevallier 	fdt_fill_device_info(fdt, &dt_rng, node);
596ea8ba295SGatien Chevallier 	if (dt_rng.reg == DT_INFO_INVALID_REG)
597ea8ba295SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
598f3c22059SEtienne Carriere 
599ea8ba295SGatien Chevallier 	stm32_rng->base.pa = dt_rng.reg;
600ea8ba295SGatien Chevallier 	stm32_rng->base.va = io_pa_or_va_secure(&stm32_rng->base,
601ea8ba295SGatien Chevallier 						dt_rng.reg_size);
602ea8ba295SGatien Chevallier 	assert(stm32_rng->base.va);
603f3c22059SEtienne Carriere 
604ea8ba295SGatien Chevallier 	res = rstctrl_dt_get_by_index(fdt, node, 0, &stm32_rng->rstctrl);
605ea8ba295SGatien Chevallier 	if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND)
606ea8ba295SGatien Chevallier 		return res;
60768c4a16bSEtienne Carriere 
60845da6509SGatien Chevallier 	if (stm32_rng->ddata->nb_clock > 1) {
60945da6509SGatien Chevallier 		res = clk_dt_get_by_name(fdt, node, "rng_clk",
61045da6509SGatien Chevallier 					 &stm32_rng->clock);
61145da6509SGatien Chevallier 		if (res)
61245da6509SGatien Chevallier 			return res;
61345da6509SGatien Chevallier 
61445da6509SGatien Chevallier 		res = clk_dt_get_by_name(fdt, node, "rng_hclk",
61545da6509SGatien Chevallier 					 &stm32_rng->bus_clock);
61645da6509SGatien Chevallier 		if (res)
61745da6509SGatien Chevallier 			return res;
61845da6509SGatien Chevallier 	} else {
619d7a1a7d2SEtienne Carriere 		res = clk_dt_get_by_index(fdt, node, 0, &stm32_rng->clock);
620d7a1a7d2SEtienne Carriere 		if (res)
621d7a1a7d2SEtienne Carriere 			return res;
62245da6509SGatien Chevallier 	}
623d7a1a7d2SEtienne Carriere 
6243c752300SGatien Chevallier 	if (fdt_getprop(fdt, node, "clock-error-detect", NULL))
6253c752300SGatien Chevallier 		stm32_rng->clock_error = true;
6263c752300SGatien Chevallier 
6275959d83fSGatien Chevallier 	stm32_rng->rng_config = stm32_rng->ddata->cr;
6285959d83fSGatien Chevallier 	if (stm32_rng->rng_config & ~RNG_CR_ENTROPY_SRC_MASK)
6295959d83fSGatien Chevallier 		panic("Incorrect entropy source configuration");
6305959d83fSGatien Chevallier 	stm32_rng->health_test_conf = stm32_rng->ddata->htcr;
6315959d83fSGatien Chevallier 	stm32_rng->noise_ctrl_conf = stm32_rng->ddata->nscr;
6325959d83fSGatien Chevallier 	if (stm32_rng->noise_ctrl_conf & ~RNG_NSCR_MASK)
6335959d83fSGatien Chevallier 		panic("Incorrect noise source control configuration");
6345959d83fSGatien Chevallier 
635f3c22059SEtienne Carriere 	return TEE_SUCCESS;
636f3c22059SEtienne Carriere }
637f3c22059SEtienne Carriere 
638ea8ba295SGatien Chevallier static TEE_Result stm32_rng_probe(const void *fdt, int offs,
639f9508605SGatien Chevallier 				  const void *compat_data)
640ea8ba295SGatien Chevallier {
641b82b7e73SGatien Chevallier 	unsigned int __maybe_unused version = 0;
642*d773ec0bSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
643ea8ba295SGatien Chevallier 
644ea8ba295SGatien Chevallier 	/* Expect a single RNG instance */
645ea8ba295SGatien Chevallier 	assert(!stm32_rng);
646ea8ba295SGatien Chevallier 
647ea8ba295SGatien Chevallier 	stm32_rng = calloc(1, sizeof(*stm32_rng));
648ea8ba295SGatien Chevallier 	if (!stm32_rng)
649ea8ba295SGatien Chevallier 		panic();
650ea8ba295SGatien Chevallier 
6515959d83fSGatien Chevallier 	stm32_rng->ddata = compat_data;
6525959d83fSGatien Chevallier 	assert(stm32_rng->ddata);
6535959d83fSGatien Chevallier 
654ea8ba295SGatien Chevallier 	res = stm32_rng_parse_fdt(fdt, offs);
655ea8ba295SGatien Chevallier 	if (res)
656ea8ba295SGatien Chevallier 		goto err;
657ea8ba295SGatien Chevallier 
658*d773ec0bSGatien Chevallier 	res = enable_rng_clock();
659ea8ba295SGatien Chevallier 	if (res)
660ea8ba295SGatien Chevallier 		goto err;
661ea8ba295SGatien Chevallier 
662b82b7e73SGatien Chevallier 	version = io_read32(get_base() + RNG_VERR);
663b82b7e73SGatien Chevallier 	DMSG("RNG version Major %u, Minor %u",
664b82b7e73SGatien Chevallier 	     (version & RNG_VERR_MAJOR_MASK) >> RNG_VERR_MAJOR_SHIFT,
665b82b7e73SGatien Chevallier 	     version & RNG_VERR_MINOR_MASK);
666b82b7e73SGatien Chevallier 
667*d773ec0bSGatien Chevallier 	disable_rng_clock();
668ea8ba295SGatien Chevallier 
669*d773ec0bSGatien Chevallier 	res = stm32_rng_init();
670f63f11bdSGatien Chevallier 	if (res)
671*d773ec0bSGatien Chevallier 		goto err;
672f63f11bdSGatien Chevallier 
673*d773ec0bSGatien Chevallier #if defined(CFG_STM32MP15)
674*d773ec0bSGatien Chevallier 	/* Only STM32MP15 requires a software registering of RNG secure state */
675*d773ec0bSGatien Chevallier 	if (etzpc_get_decprot(STM32MP1_ETZPC_RNG1_ID) == ETZPC_DECPROT_NS_RW)
676ea8ba295SGatien Chevallier 		stm32mp_register_non_secure_periph_iomem(stm32_rng->base.pa);
677ea8ba295SGatien Chevallier 	else
678ea8ba295SGatien Chevallier 		stm32mp_register_secure_periph_iomem(stm32_rng->base.pa);
679*d773ec0bSGatien Chevallier #endif /* defined(CFG_STM32MP15) */
680ea8ba295SGatien Chevallier 
6815959d83fSGatien Chevallier 	/* Power management implementation expects both or none are set */
6825959d83fSGatien Chevallier 	assert(stm32_rng->ddata->has_power_optim ==
6835959d83fSGatien Chevallier 	       stm32_rng->ddata->has_cond_reset);
6845959d83fSGatien Chevallier 
685*d773ec0bSGatien Chevallier 	if (!IS_ENABLED(CFG_WITH_SOFTWARE_PRNG))
686*d773ec0bSGatien Chevallier 		register_pm_core_service_cb(stm32_rng_pm, &stm32_rng,
687*d773ec0bSGatien Chevallier 					    "rng-service");
68829893549SGatien Chevallier 
689ea8ba295SGatien Chevallier 	return TEE_SUCCESS;
690ea8ba295SGatien Chevallier 
691ea8ba295SGatien Chevallier err:
692ea8ba295SGatien Chevallier 	free(stm32_rng);
693ea8ba295SGatien Chevallier 	stm32_rng = NULL;
694ea8ba295SGatien Chevallier 
695ea8ba295SGatien Chevallier 	return res;
696ea8ba295SGatien Chevallier }
697ea8ba295SGatien Chevallier 
698091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp13_data[] = {
69945da6509SGatien Chevallier 	{
700aa12f203SGatien Chevallier 		.max_noise_clk_freq = U(48000000),
70145da6509SGatien Chevallier 		.nb_clock = 1,
70245da6509SGatien Chevallier 		.has_cond_reset = true,
7035959d83fSGatien Chevallier 		.has_power_optim = true,
7045959d83fSGatien Chevallier 		.cr = 0x00F00D00,
7055959d83fSGatien Chevallier 		.nscr = 0x2B5BB,
7065959d83fSGatien Chevallier 		.htcr = 0x969D,
70745da6509SGatien Chevallier 	},
708091ef005SGatien Chevallier };
709091ef005SGatien Chevallier 
710091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp15_data[] = {
71145da6509SGatien Chevallier 	{
712aa12f203SGatien Chevallier 		.max_noise_clk_freq = U(48000000),
71345da6509SGatien Chevallier 		.nb_clock = 1,
71445da6509SGatien Chevallier 		.has_cond_reset = false,
7155959d83fSGatien Chevallier 		.has_power_optim = false,
71645da6509SGatien Chevallier 	},
717091ef005SGatien Chevallier };
718091ef005SGatien Chevallier DECLARE_KEEP_PAGER(mp15_data);
719091ef005SGatien Chevallier 
72045da6509SGatien Chevallier static const struct stm32_rng_driver_data mp25_data[] = {
72145da6509SGatien Chevallier 	{
722aa12f203SGatien Chevallier 		.max_noise_clk_freq = U(48000000),
72345da6509SGatien Chevallier 		.nb_clock = 2,
72445da6509SGatien Chevallier 		.has_cond_reset = true,
7255959d83fSGatien Chevallier 		.has_power_optim = true,
7265959d83fSGatien Chevallier 		.cr = 0x00F00D00,
7275959d83fSGatien Chevallier 		.nscr = 0x2B5BB,
7285959d83fSGatien Chevallier 		.htcr = 0x969D,
72945da6509SGatien Chevallier 	},
73045da6509SGatien Chevallier };
73145da6509SGatien Chevallier 
732ea8ba295SGatien Chevallier static const struct dt_device_match rng_match_table[] = {
733091ef005SGatien Chevallier 	{ .compatible = "st,stm32-rng", .compat_data = &mp15_data },
734091ef005SGatien Chevallier 	{ .compatible = "st,stm32mp13-rng", .compat_data = &mp13_data },
73545da6509SGatien Chevallier 	{ .compatible = "st,stm32mp25-rng", .compat_data = &mp25_data },
736ea8ba295SGatien Chevallier 	{ }
737ea8ba295SGatien Chevallier };
738ea8ba295SGatien Chevallier 
739ea8ba295SGatien Chevallier DEFINE_DT_DRIVER(stm32_rng_dt_driver) = {
740ea8ba295SGatien Chevallier 	.name = "stm32_rng",
741ea8ba295SGatien Chevallier 	.match_table = rng_match_table,
742ea8ba295SGatien Chevallier 	.probe = stm32_rng_probe,
743ea8ba295SGatien Chevallier };
744d8682c4cSEtienne Carriere 
745d8682c4cSEtienne Carriere static TEE_Result stm32_rng_release(void)
746d8682c4cSEtienne Carriere {
747*d773ec0bSGatien Chevallier 	if (stm32_rng && IS_ENABLED(CFG_WITH_SOFTWARE_PRNG)) {
748d8682c4cSEtienne Carriere 		DMSG("Release RNG driver");
749d8682c4cSEtienne Carriere 		free(stm32_rng);
750d8682c4cSEtienne Carriere 		stm32_rng = NULL;
751d8682c4cSEtienne Carriere 	}
752d8682c4cSEtienne Carriere 
753d8682c4cSEtienne Carriere 	return TEE_SUCCESS;
754d8682c4cSEtienne Carriere }
755d8682c4cSEtienne Carriere 
756d8682c4cSEtienne Carriere release_init_resource(stm32_rng_release);
757