xref: /optee_os/core/drivers/stm32_rng.c (revision 5959d83f6f5828c84992be4b693147f33b3d596e)
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 <io.h>
11*5959d83fSGatien Chevallier #include <kernel/boot.h>
12f3c22059SEtienne Carriere #include <kernel/delay.h>
13a2fc83d1SJerome Forissier #include <kernel/dt.h>
14ea8ba295SGatien Chevallier #include <kernel/dt_driver.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>
25*5959d83fSGatien Chevallier #include <util.h>
26f3c22059SEtienne Carriere 
270817aa6fSGatien Chevallier #define RNG_CR			U(0x00)
280817aa6fSGatien Chevallier #define RNG_SR			U(0x04)
290817aa6fSGatien Chevallier #define RNG_DR			U(0x08)
30*5959d83fSGatien Chevallier #define RNG_NSCR		U(0x0C)
31*5959d83fSGatien Chevallier #define RNG_HTCR		U(0x10)
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)
36*5959d83fSGatien Chevallier #define RNG_CR_CONFIG1		GENMASK_32(11, 8)
37*5959d83fSGatien Chevallier #define RNG_CR_NISTC		BIT(12)
38*5959d83fSGatien Chevallier #define RNG_CR_POWER_OPTIM	BIT(13)
39*5959d83fSGatien 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)
42*5959d83fSGatien Chevallier #define RNG_CR_CONFIG3		GENMASK_32(25, 20)
43091ef005SGatien Chevallier #define RNG_CR_CONDRST		BIT(30)
44*5959d83fSGatien Chevallier #define RNG_CR_ENTROPY_SRC_MASK	(RNG_CR_CONFIG1 | RNG_CR_NISTC | \
45*5959d83fSGatien 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 
53*5959d83fSGatien Chevallier #define RNG_NSCR_MASK		GENMASK_32(17, 0)
54*5959d83fSGatien Chevallier 
550817aa6fSGatien Chevallier #if TRACE_LEVEL > TRACE_DEBUG
560817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US	U(100000)
570817aa6fSGatien Chevallier #else
580817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US	U(10000)
590817aa6fSGatien Chevallier #endif
60ea8ba295SGatien Chevallier #define RNG_RESET_TIMEOUT_US	U(1000)
61f3c22059SEtienne Carriere 
620817aa6fSGatien Chevallier #define RNG_FIFO_BYTE_DEPTH	U(16)
630817aa6fSGatien Chevallier 
64*5959d83fSGatien Chevallier #define RNG_CONFIG_MASK		(RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED | \
65*5959d83fSGatien Chevallier 				 RNG_CR_CLKDIV)
66091ef005SGatien Chevallier 
67091ef005SGatien Chevallier #define RNG_MAX_NOISE_CLK_FREQ	U(3000000)
68091ef005SGatien Chevallier 
69091ef005SGatien Chevallier struct stm32_rng_driver_data {
7045da6509SGatien Chevallier 	unsigned long nb_clock;
71*5959d83fSGatien Chevallier 	uint32_t cr;
72*5959d83fSGatien Chevallier 	uint32_t nscr;
73*5959d83fSGatien Chevallier 	uint32_t htcr;
74*5959d83fSGatien Chevallier 	bool has_power_optim;
75091ef005SGatien Chevallier 	bool has_cond_reset;
76091ef005SGatien Chevallier };
77091ef005SGatien Chevallier 
78f3c22059SEtienne Carriere struct stm32_rng_instance {
79f3c22059SEtienne Carriere 	struct io_pa_va base;
80d7a1a7d2SEtienne Carriere 	struct clk *clock;
8145da6509SGatien Chevallier 	struct clk *bus_clock;
82ea8ba295SGatien Chevallier 	struct rstctrl *rstctrl;
83091ef005SGatien Chevallier 	const struct stm32_rng_driver_data *ddata;
84f3c22059SEtienne Carriere 	unsigned int lock;
85*5959d83fSGatien Chevallier 	uint64_t error_to_ref;
86*5959d83fSGatien Chevallier 	uint32_t pm_cr;
87*5959d83fSGatien Chevallier 	uint32_t pm_health;
88*5959d83fSGatien Chevallier 	uint32_t pm_noise_ctrl;
89*5959d83fSGatien Chevallier 	uint32_t health_test_conf;
90*5959d83fSGatien Chevallier 	uint32_t noise_ctrl_conf;
91*5959d83fSGatien Chevallier 	uint32_t rng_config;
92d8682c4cSEtienne Carriere 	bool release_post_boot;
933c752300SGatien Chevallier 	bool clock_error;
94091ef005SGatien Chevallier 	bool error_conceal;
95f3c22059SEtienne Carriere };
96f3c22059SEtienne Carriere 
97ea8ba295SGatien Chevallier /* Expect at most a single RNG instance */
98f3c22059SEtienne Carriere static struct stm32_rng_instance *stm32_rng;
99f3c22059SEtienne Carriere 
100f63f11bdSGatien Chevallier static vaddr_t get_base(void)
101f63f11bdSGatien Chevallier {
102f63f11bdSGatien Chevallier 	assert(stm32_rng);
103f63f11bdSGatien Chevallier 
104f63f11bdSGatien Chevallier 	return io_pa_or_va(&stm32_rng->base, 1);
105f63f11bdSGatien Chevallier }
106f63f11bdSGatien Chevallier 
107f3c22059SEtienne Carriere /*
108091ef005SGatien Chevallier  * Extracts from the STM32 RNG specification when RNG supports CONDRST.
109f3c22059SEtienne Carriere  *
110f3c22059SEtienne Carriere  * When a noise source (or seed) error occurs, the RNG stops generating
111f3c22059SEtienne Carriere  * random numbers and sets to “1” both SEIS and SECS bits to indicate
112f3c22059SEtienne Carriere  * that a seed error occurred. (...)
113091ef005SGatien Chevallier  *
114091ef005SGatien Chevallier  * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield
115091ef005SGatien Chevallier  * description for details). This step is needed only if SECS is set.
116091ef005SGatien Chevallier  * Indeed, when SEIS is set and SECS is cleared it means RNG performed
117091ef005SGatien Chevallier  * the reset automatically (auto-reset).
118091ef005SGatien Chevallier  * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST
119091ef005SGatien Chevallier  * to be cleared in the RNG_CR register, then confirm that SEIS is
120091ef005SGatien Chevallier  * cleared in the RNG_SR register. Otherwise just clear SEIS bit in
121091ef005SGatien Chevallier  * the RNG_SR register.
122091ef005SGatien Chevallier  * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be
123091ef005SGatien Chevallier  * cleared by RNG. The random number generation is now back to normal.
124091ef005SGatien Chevallier  */
125091ef005SGatien Chevallier static void conceal_seed_error_cond_reset(void)
126091ef005SGatien Chevallier {
127091ef005SGatien Chevallier 	struct stm32_rng_instance *dev = stm32_rng;
128091ef005SGatien Chevallier 	vaddr_t rng_base = get_base();
129f3c22059SEtienne Carriere 
130091ef005SGatien Chevallier 	if (!dev->error_conceal) {
131091ef005SGatien Chevallier 		uint32_t sr = io_read32(rng_base + RNG_SR);
132091ef005SGatien Chevallier 
133091ef005SGatien Chevallier 		if (sr & RNG_SR_SECS) {
134091ef005SGatien Chevallier 			/* Conceal by resetting the subsystem (step 1.) */
135091ef005SGatien Chevallier 			io_setbits32(rng_base + RNG_CR, RNG_CR_CONDRST);
136091ef005SGatien Chevallier 			io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST);
137091ef005SGatien Chevallier 
138091ef005SGatien Chevallier 			/* Arm timeout for error_conceal sequence */
139091ef005SGatien Chevallier 			dev->error_to_ref =
140091ef005SGatien Chevallier 				timeout_init_us(RNG_READY_TIMEOUT_US);
141091ef005SGatien Chevallier 			dev->error_conceal = true;
142091ef005SGatien Chevallier 		} else {
143091ef005SGatien Chevallier 			/* RNG auto-reset (step 2.) */
144091ef005SGatien Chevallier 			io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS);
145091ef005SGatien Chevallier 		}
146091ef005SGatien Chevallier 	} else {
147091ef005SGatien Chevallier 		/* Measure time before possible reschedule */
148091ef005SGatien Chevallier 		bool timed_out = timeout_elapsed(dev->error_to_ref);
149091ef005SGatien Chevallier 
150091ef005SGatien Chevallier 		/* Wait CONDRST is cleared (step 2.) */
151091ef005SGatien Chevallier 		if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) {
152091ef005SGatien Chevallier 			if (timed_out)
153091ef005SGatien Chevallier 				panic();
154091ef005SGatien Chevallier 
155091ef005SGatien Chevallier 			/* Wait subsystem reset cycle completes */
156091ef005SGatien Chevallier 			return;
157091ef005SGatien Chevallier 		}
158091ef005SGatien Chevallier 
159091ef005SGatien Chevallier 		/* Check SEIS is cleared (step 2.) */
160091ef005SGatien Chevallier 		if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS)
161091ef005SGatien Chevallier 			panic();
162091ef005SGatien Chevallier 
163091ef005SGatien Chevallier 		/* Wait SECS is cleared (step 3.) */
164091ef005SGatien Chevallier 		if (io_read32(rng_base + RNG_SR) & RNG_SR_SECS) {
165091ef005SGatien Chevallier 			if (timed_out)
166091ef005SGatien Chevallier 				panic();
167091ef005SGatien Chevallier 
168091ef005SGatien Chevallier 			/* Wait subsystem reset cycle completes */
169091ef005SGatien Chevallier 			return;
170091ef005SGatien Chevallier 		}
171091ef005SGatien Chevallier 
172091ef005SGatien Chevallier 		dev->error_conceal = false;
173091ef005SGatien Chevallier 	}
174091ef005SGatien Chevallier }
175091ef005SGatien Chevallier 
176091ef005SGatien Chevallier /*
177091ef005SGatien Chevallier  * Extracts from the STM32 RNG specification, when CONDRST is not supported
178091ef005SGatien Chevallier  *
179091ef005SGatien Chevallier  * When a noise source (or seed) error occurs, the RNG stops generating
180091ef005SGatien Chevallier  * random numbers and sets to “1” both SEIS and SECS bits to indicate
181091ef005SGatien Chevallier  * that a seed error occurred. (...)
182091ef005SGatien Chevallier  *
183f3c22059SEtienne Carriere  * The following sequence shall be used to fully recover from a seed
184f3c22059SEtienne Carriere  * error after the RNG initialization:
185f3c22059SEtienne Carriere  * 1. Clear the SEIS bit by writing it to “0”.
186f3c22059SEtienne Carriere  * 2. Read out 12 words from the RNG_DR register, and discard each of
187f3c22059SEtienne Carriere  * them in order to clean the pipeline.
188f3c22059SEtienne Carriere  * 3. Confirm that SEIS is still cleared. Random number generation is
189f3c22059SEtienne Carriere  * back to normal.
190f3c22059SEtienne Carriere  */
191091ef005SGatien Chevallier static void conceal_seed_error_sw_reset(void)
192f3c22059SEtienne Carriere {
1936a6b6168SGatien Chevallier 	vaddr_t rng_base = get_base();
194f3c22059SEtienne Carriere 	size_t i = 0;
195f3c22059SEtienne Carriere 
1966a6b6168SGatien Chevallier 	io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS);
197f3c22059SEtienne Carriere 
198f3c22059SEtienne Carriere 	for (i = 12; i != 0; i--)
199f3c22059SEtienne Carriere 		(void)io_read32(rng_base + RNG_DR);
200f3c22059SEtienne Carriere 
201f3c22059SEtienne Carriere 	if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS)
202f3c22059SEtienne Carriere 		panic("RNG noise");
203f3c22059SEtienne Carriere }
204f3c22059SEtienne Carriere 
205091ef005SGatien Chevallier static void conceal_seed_error(void)
206091ef005SGatien Chevallier {
207091ef005SGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset)
208091ef005SGatien Chevallier 		conceal_seed_error_cond_reset();
209091ef005SGatien Chevallier 	else
210091ef005SGatien Chevallier 		conceal_seed_error_sw_reset();
211091ef005SGatien Chevallier }
212091ef005SGatien Chevallier 
213c99311c8SEtienne Carriere static TEE_Result read_available(vaddr_t rng_base, uint8_t *out, size_t *size)
214f3c22059SEtienne Carriere {
215091ef005SGatien Chevallier 	struct stm32_rng_instance *dev = stm32_rng;
216c99311c8SEtienne Carriere 	uint8_t *buf = NULL;
217c99311c8SEtienne Carriere 	size_t req_size = 0;
218c99311c8SEtienne Carriere 	size_t len = 0;
219f3c22059SEtienne Carriere 
220091ef005SGatien Chevallier 	if (dev->error_conceal || io_read32(rng_base + RNG_SR) & RNG_SR_SEIS)
2216a6b6168SGatien Chevallier 		conceal_seed_error();
222f3c22059SEtienne Carriere 
22323123473SEtienne Carriere 	if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) {
22423123473SEtienne Carriere 		FMSG("RNG not ready");
225c99311c8SEtienne Carriere 		return TEE_ERROR_NO_DATA;
22623123473SEtienne Carriere 	}
227f3c22059SEtienne Carriere 
22823123473SEtienne Carriere 	if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) {
22923123473SEtienne Carriere 		FMSG("RNG noise error");
230c99311c8SEtienne Carriere 		return TEE_ERROR_NO_DATA;
23123123473SEtienne Carriere 	}
232c99311c8SEtienne Carriere 
233c99311c8SEtienne Carriere 	buf = out;
234c99311c8SEtienne Carriere 	req_size = MIN(RNG_FIFO_BYTE_DEPTH, *size);
235c99311c8SEtienne Carriere 	len = req_size;
236f3c22059SEtienne Carriere 
237f3c22059SEtienne Carriere 	/* RNG is ready: read up to 4 32bit words */
238f3c22059SEtienne Carriere 	while (len) {
23923bdf063SEtienne Carriere 		uint32_t data32 = 0;
240f3c22059SEtienne Carriere 		size_t sz = MIN(len, sizeof(uint32_t));
241f3c22059SEtienne Carriere 
24223bdf063SEtienne Carriere 		if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY))
24323bdf063SEtienne Carriere 			break;
24423bdf063SEtienne Carriere 		data32 = io_read32(rng_base + RNG_DR);
24523bdf063SEtienne Carriere 
2463e64c635SGatien Chevallier 		/* Late seed error case: DR being 0 is an error status */
2473e64c635SGatien Chevallier 		if (!data32) {
2483e64c635SGatien Chevallier 			conceal_seed_error();
2493e64c635SGatien Chevallier 			return TEE_ERROR_NO_DATA;
2503e64c635SGatien Chevallier 		}
2513e64c635SGatien Chevallier 
252f3c22059SEtienne Carriere 		memcpy(buf, &data32, sz);
253f3c22059SEtienne Carriere 		buf += sz;
254f3c22059SEtienne Carriere 		len -= sz;
255f3c22059SEtienne Carriere 	}
256c99311c8SEtienne Carriere 
25723bdf063SEtienne Carriere 	*size = req_size - len;
258f3c22059SEtienne Carriere 
259c99311c8SEtienne Carriere 	return TEE_SUCCESS;
260f3c22059SEtienne Carriere }
261f3c22059SEtienne Carriere 
262091ef005SGatien Chevallier static uint32_t stm32_rng_clock_freq_restrain(void)
263091ef005SGatien Chevallier {
264091ef005SGatien Chevallier 	struct stm32_rng_instance *dev = stm32_rng;
265091ef005SGatien Chevallier 	unsigned long clock_rate = 0;
266091ef005SGatien Chevallier 	uint32_t clock_div = 0;
267091ef005SGatien Chevallier 
268091ef005SGatien Chevallier 	clock_rate = clk_get_rate(dev->clock);
269091ef005SGatien Chevallier 
270091ef005SGatien Chevallier 	/*
271091ef005SGatien Chevallier 	 * Get the exponent to apply on the CLKDIV field in RNG_CR register
272091ef005SGatien Chevallier 	 * No need to handle the case when clock-div > 0xF as it is physically
273091ef005SGatien Chevallier 	 * impossible
274091ef005SGatien Chevallier 	 */
275091ef005SGatien Chevallier 	while ((clock_rate >> clock_div) > RNG_MAX_NOISE_CLK_FREQ)
276091ef005SGatien Chevallier 		clock_div++;
277091ef005SGatien Chevallier 
278091ef005SGatien Chevallier 	DMSG("RNG clk rate : %lu", clk_get_rate(dev->clock) >> clock_div);
279091ef005SGatien Chevallier 
280091ef005SGatien Chevallier 	return clock_div;
281091ef005SGatien Chevallier }
282091ef005SGatien Chevallier 
283f63f11bdSGatien Chevallier static TEE_Result init_rng(void)
284f3c22059SEtienne Carriere {
285f63f11bdSGatien Chevallier 	vaddr_t rng_base = get_base();
2863c752300SGatien Chevallier 	uint32_t cr_ced_mask = 0;
287*5959d83fSGatien Chevallier 	uint32_t value = 0;
2883c752300SGatien Chevallier 
2893c752300SGatien Chevallier 	if (!stm32_rng->clock_error)
2903c752300SGatien Chevallier 		cr_ced_mask = RNG_CR_CED;
291f3c22059SEtienne Carriere 
292f63f11bdSGatien Chevallier 	/* Clean error indications */
293f63f11bdSGatien Chevallier 	io_write32(rng_base + RNG_SR, 0);
294f3c22059SEtienne Carriere 
295091ef005SGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset) {
296091ef005SGatien Chevallier 		uint32_t clock_div = stm32_rng_clock_freq_restrain();
297091ef005SGatien Chevallier 
298*5959d83fSGatien Chevallier 		/*
299*5959d83fSGatien Chevallier 		 * Keep default RNG configuration if none was specified.
300*5959d83fSGatien Chevallier 		 * 0 is an invalid value as it disables all entropy sources.
301*5959d83fSGatien Chevallier 		 */
302*5959d83fSGatien Chevallier 		if (!stm32_rng->rng_config)
303*5959d83fSGatien Chevallier 			stm32_rng->rng_config = io_read32(rng_base + RNG_CR) &
304*5959d83fSGatien Chevallier 						RNG_CR_ENTROPY_SRC_MASK;
305*5959d83fSGatien Chevallier 
306*5959d83fSGatien Chevallier 		/*
307*5959d83fSGatien Chevallier 		 * Configuration must be set in the same access that sets
308*5959d83fSGatien Chevallier 		 * RNG_CR_CONDRST bit. Otherwise, the configuration setting is
309*5959d83fSGatien Chevallier 		 * not taken into account. CONFIGLOCK bit is always cleared at
310*5959d83fSGatien Chevallier 		 * this stage.
311*5959d83fSGatien Chevallier 		 */
312*5959d83fSGatien Chevallier 		io_clrsetbits32(rng_base + RNG_CR, RNG_CONFIG_MASK,
313*5959d83fSGatien Chevallier 				stm32_rng->rng_config | RNG_CR_CONDRST |
314*5959d83fSGatien Chevallier 				cr_ced_mask |
315*5959d83fSGatien Chevallier 				SHIFT_U32(clock_div, RNG_CR_CLKDIV_SHIFT));
316*5959d83fSGatien Chevallier 
317*5959d83fSGatien Chevallier 		/*
318*5959d83fSGatien Chevallier 		 * Write health test and noise source control configuration
319*5959d83fSGatien Chevallier 		 * according to current RNG entropy source configuration
320*5959d83fSGatien Chevallier 		 */
321*5959d83fSGatien Chevallier 		if (stm32_rng->noise_ctrl_conf)
322*5959d83fSGatien Chevallier 			io_write32(rng_base + RNG_NSCR,
323*5959d83fSGatien Chevallier 				   stm32_rng->noise_ctrl_conf);
324*5959d83fSGatien Chevallier 
325*5959d83fSGatien Chevallier 		if (stm32_rng->health_test_conf)
326*5959d83fSGatien Chevallier 			io_write32(rng_base + RNG_HTCR,
327*5959d83fSGatien Chevallier 				   stm32_rng->health_test_conf);
328091ef005SGatien Chevallier 
329091ef005SGatien Chevallier 		io_clrsetbits32(rng_base + RNG_CR, RNG_CR_CONDRST,
330091ef005SGatien Chevallier 				RNG_CR_RNGEN);
331eb5cf770SGatien Chevallier 
332*5959d83fSGatien Chevallier 		if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_CR, value,
333*5959d83fSGatien Chevallier 					   !(value & RNG_CR_CONDRST), 0,
334*5959d83fSGatien Chevallier 					   RNG_READY_TIMEOUT_US))
335eb5cf770SGatien Chevallier 			panic();
336*5959d83fSGatien Chevallier 
337*5959d83fSGatien Chevallier 		DMSG("RNG control register %#"PRIx32,
338*5959d83fSGatien Chevallier 		     io_read32(rng_base + RNG_CR));
339*5959d83fSGatien Chevallier 		DMSG("RNG noise source control register %#"PRIx32,
340*5959d83fSGatien Chevallier 		     io_read32(rng_base + RNG_NSCR));
341*5959d83fSGatien Chevallier 		DMSG("RNG health test register %#"PRIx32,
342*5959d83fSGatien Chevallier 		     io_read32(rng_base + RNG_HTCR));
343091ef005SGatien Chevallier 	} else {
3443c752300SGatien Chevallier 		io_setbits32(rng_base + RNG_CR, RNG_CR_RNGEN | cr_ced_mask);
345091ef005SGatien Chevallier 	}
346f63f11bdSGatien Chevallier 
347*5959d83fSGatien Chevallier 	if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_SR, value,
348*5959d83fSGatien Chevallier 				   value & RNG_SR_DRDY, 0,
349*5959d83fSGatien Chevallier 				   RNG_READY_TIMEOUT_US))
350f63f11bdSGatien Chevallier 		return TEE_ERROR_GENERIC;
351f63f11bdSGatien Chevallier 
352f63f11bdSGatien Chevallier 	return TEE_SUCCESS;
353f3c22059SEtienne Carriere }
354f3c22059SEtienne Carriere 
35598c36268SGatien Chevallier static TEE_Result stm32_rng_read(uint8_t *out, size_t size)
356f3c22059SEtienne Carriere {
357c99311c8SEtienne Carriere 	TEE_Result rc = TEE_ERROR_GENERIC;
358c99311c8SEtienne Carriere 	bool burst_timeout = false;
359c99311c8SEtienne Carriere 	uint64_t timeout_ref = 0;
360f3c22059SEtienne Carriere 	uint32_t exceptions = 0;
361f3c22059SEtienne Carriere 	uint8_t *out_ptr = out;
362c99311c8SEtienne Carriere 	vaddr_t rng_base = 0;
363f3c22059SEtienne Carriere 	size_t out_size = 0;
364f3c22059SEtienne Carriere 
365f3c22059SEtienne Carriere 	if (!stm32_rng) {
366f3c22059SEtienne Carriere 		DMSG("No RNG");
367f3c22059SEtienne Carriere 		return TEE_ERROR_NOT_SUPPORTED;
368f3c22059SEtienne Carriere 	}
369f3c22059SEtienne Carriere 
370fb1681dfSGatien Chevallier 	rc = clk_enable(stm32_rng->clock);
371fb1681dfSGatien Chevallier 	if (rc)
372fb1681dfSGatien Chevallier 		return rc;
373fb1681dfSGatien Chevallier 
37445da6509SGatien Chevallier 	if (stm32_rng->bus_clock) {
37545da6509SGatien Chevallier 		rc = clk_enable(stm32_rng->bus_clock);
37645da6509SGatien Chevallier 		if (rc) {
37745da6509SGatien Chevallier 			clk_disable(stm32_rng->clock);
37845da6509SGatien Chevallier 			return rc;
37945da6509SGatien Chevallier 		}
38045da6509SGatien Chevallier 	}
38145da6509SGatien Chevallier 
382f63f11bdSGatien Chevallier 	rng_base = get_base();
383c99311c8SEtienne Carriere 
384c99311c8SEtienne Carriere 	/* Arm timeout */
3850817aa6fSGatien Chevallier 	timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
386c99311c8SEtienne Carriere 	burst_timeout = false;
387f3c22059SEtienne Carriere 
388f3c22059SEtienne Carriere 	while (out_size < size) {
389f3c22059SEtienne Carriere 		/* Read by chunks of the size the RNG FIFO depth */
390f3c22059SEtienne Carriere 		size_t sz = size - out_size;
391f3c22059SEtienne Carriere 
392f3c22059SEtienne Carriere 		exceptions = may_spin_lock(&stm32_rng->lock);
393f3c22059SEtienne Carriere 
394c99311c8SEtienne Carriere 		rc = read_available(rng_base, out_ptr, &sz);
395c99311c8SEtienne Carriere 
396c99311c8SEtienne Carriere 		/* Raise timeout only if we failed to get some samples */
397c99311c8SEtienne Carriere 		assert(!rc || rc == TEE_ERROR_NO_DATA);
398c99311c8SEtienne Carriere 		if (rc)
399c99311c8SEtienne Carriere 			burst_timeout = timeout_elapsed(timeout_ref);
400f3c22059SEtienne Carriere 
401f3c22059SEtienne Carriere 		may_spin_unlock(&stm32_rng->lock, exceptions);
402f3c22059SEtienne Carriere 
403c99311c8SEtienne Carriere 		if (burst_timeout) {
404c99311c8SEtienne Carriere 			rc = TEE_ERROR_GENERIC;
405c99311c8SEtienne Carriere 			goto out;
406f3c22059SEtienne Carriere 		}
407f3c22059SEtienne Carriere 
408c99311c8SEtienne Carriere 		if (!rc) {
409c99311c8SEtienne Carriere 			out_size += sz;
410c99311c8SEtienne Carriere 			out_ptr += sz;
411c99311c8SEtienne Carriere 			/* Re-arm timeout */
4120817aa6fSGatien Chevallier 			timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
413c99311c8SEtienne Carriere 			burst_timeout = false;
414c99311c8SEtienne Carriere 		}
415c99311c8SEtienne Carriere 	}
416c99311c8SEtienne Carriere 
417c99311c8SEtienne Carriere out:
418c99311c8SEtienne Carriere 	assert(!rc || rc == TEE_ERROR_GENERIC);
419f63f11bdSGatien Chevallier 	clk_disable(stm32_rng->clock);
42045da6509SGatien Chevallier 	if (stm32_rng->bus_clock)
42145da6509SGatien Chevallier 		clk_disable(stm32_rng->bus_clock);
422f3c22059SEtienne Carriere 
423f3c22059SEtienne Carriere 	return rc;
424f3c22059SEtienne Carriere }
425f3c22059SEtienne Carriere 
426cd451498SEtienne Carriere #ifdef CFG_WITH_SOFTWARE_PRNG
427cd451498SEtienne Carriere /* Override weak plat_rng_init with platform handler to seed PRNG */
428cd451498SEtienne Carriere void plat_rng_init(void)
429cd451498SEtienne Carriere {
430cd451498SEtienne Carriere 	uint8_t seed[RNG_FIFO_BYTE_DEPTH] = { };
431cd451498SEtienne Carriere 
432cd451498SEtienne Carriere 	if (stm32_rng_read(seed, sizeof(seed)))
433cd451498SEtienne Carriere 		panic();
434cd451498SEtienne Carriere 
435cd451498SEtienne Carriere 	if (crypto_rng_init(seed, sizeof(seed)))
436cd451498SEtienne Carriere 		panic();
437cd451498SEtienne Carriere 
438cd451498SEtienne Carriere 	DMSG("PRNG seeded with RNG");
439cd451498SEtienne Carriere }
440cd451498SEtienne Carriere #else
441cb2478efSAndrew Davis TEE_Result hw_get_random_bytes(void *out, size_t size)
442097f329aSEtienne Carriere {
443097f329aSEtienne Carriere 	return stm32_rng_read(out, size);
444097f329aSEtienne Carriere }
44527f3087bSGatien Chevallier 
44627f3087bSGatien Chevallier void plat_rng_init(void)
44727f3087bSGatien Chevallier {
44827f3087bSGatien Chevallier }
449097f329aSEtienne Carriere #endif
450097f329aSEtienne Carriere 
451*5959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_resume(void)
45229893549SGatien Chevallier {
45329893549SGatien Chevallier 	vaddr_t base = get_base();
45429893549SGatien Chevallier 
45529893549SGatien Chevallier 	/* Clean error indications */
45629893549SGatien Chevallier 	io_write32(base + RNG_SR, 0);
45729893549SGatien Chevallier 
45829893549SGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset) {
459eb5cf770SGatien Chevallier 		uint64_t timeout_ref = 0;
460eb5cf770SGatien Chevallier 
46129893549SGatien Chevallier 		/*
462c2c5b4beSGatien Chevallier 		 * Configuration must be set in the same access that sets
463c2c5b4beSGatien Chevallier 		 * RNG_CR_CONDRST bit. Otherwise, the configuration setting is
464c2c5b4beSGatien Chevallier 		 * not taken into account. CONFIGLOCK bit is always cleared in
465c2c5b4beSGatien Chevallier 		 * this configuration.
46629893549SGatien Chevallier 		 */
467*5959d83fSGatien Chevallier 		io_write32(base + RNG_CR, stm32_rng->pm_cr | RNG_CR_CONDRST);
468*5959d83fSGatien Chevallier 
469*5959d83fSGatien Chevallier 		/* Restore health test and noise control configuration */
470*5959d83fSGatien Chevallier 		io_write32(base + RNG_NSCR, stm32_rng->pm_noise_ctrl);
471*5959d83fSGatien Chevallier 		io_write32(base + RNG_HTCR, stm32_rng->pm_health);
47229893549SGatien Chevallier 
47329893549SGatien Chevallier 		io_clrsetbits32(base + RNG_CR, RNG_CR_CONDRST, RNG_CR_RNGEN);
474eb5cf770SGatien Chevallier 
475eb5cf770SGatien Chevallier 		timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
476eb5cf770SGatien Chevallier 		while (io_read32(base + RNG_CR) & RNG_CR_CONDRST)
477eb5cf770SGatien Chevallier 			if (timeout_elapsed(timeout_ref))
478eb5cf770SGatien Chevallier 				break;
479eb5cf770SGatien Chevallier 		if (io_read32(base + RNG_CR) & RNG_CR_CONDRST)
480eb5cf770SGatien Chevallier 			panic();
48129893549SGatien Chevallier 	} else {
482*5959d83fSGatien Chevallier 		io_write32(base + RNG_CR, RNG_CR_RNGEN | stm32_rng->pm_cr);
483*5959d83fSGatien Chevallier 	}
484*5959d83fSGatien Chevallier 
485*5959d83fSGatien Chevallier 	return TEE_SUCCESS;
486*5959d83fSGatien Chevallier }
487*5959d83fSGatien Chevallier 
488*5959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_suspend(void)
489*5959d83fSGatien Chevallier {
490*5959d83fSGatien Chevallier 	vaddr_t rng_base = get_base();
491*5959d83fSGatien Chevallier 
492*5959d83fSGatien Chevallier 	stm32_rng->pm_cr = io_read32(rng_base + RNG_CR);
493*5959d83fSGatien Chevallier 
494*5959d83fSGatien Chevallier 	if (stm32_rng->ddata->has_cond_reset) {
495*5959d83fSGatien Chevallier 		stm32_rng->pm_health = io_read32(rng_base + RNG_HTCR);
496*5959d83fSGatien Chevallier 		stm32_rng->pm_noise_ctrl = io_read32(rng_base + RNG_NSCR);
497*5959d83fSGatien Chevallier 	}
498*5959d83fSGatien Chevallier 
499*5959d83fSGatien Chevallier 	if (stm32_rng->ddata->has_power_optim) {
500*5959d83fSGatien Chevallier 		uint64_t timeout_ref = 0;
501*5959d83fSGatien Chevallier 
502*5959d83fSGatien Chevallier 		/*
503*5959d83fSGatien Chevallier 		 * As per reference manual, it is recommended to set
504*5959d83fSGatien Chevallier 		 * RNG_CONFIG2[bit0] when RNG power consumption is critical.
505*5959d83fSGatien Chevallier 		 */
506*5959d83fSGatien Chevallier 		io_setbits32(rng_base + RNG_CR, RNG_CR_POWER_OPTIM |
507*5959d83fSGatien Chevallier 				RNG_CR_CONDRST);
508*5959d83fSGatien Chevallier 		io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST);
509*5959d83fSGatien Chevallier 
510*5959d83fSGatien Chevallier 		timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US);
511*5959d83fSGatien Chevallier 		while (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST)
512*5959d83fSGatien Chevallier 			if (timeout_elapsed(timeout_ref))
513*5959d83fSGatien Chevallier 				break;
514*5959d83fSGatien Chevallier 		if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST)
515*5959d83fSGatien Chevallier 			panic();
516*5959d83fSGatien Chevallier 	} else {
517*5959d83fSGatien Chevallier 		io_clrbits32(rng_base + RNG_CR, RNG_CR_RNGEN);
51829893549SGatien Chevallier 	}
51929893549SGatien Chevallier 
52029893549SGatien Chevallier 	return TEE_SUCCESS;
52129893549SGatien Chevallier }
52229893549SGatien Chevallier 
52329893549SGatien Chevallier static TEE_Result
52429893549SGatien Chevallier stm32_rng_pm(enum pm_op op, unsigned int pm_hint __unused,
52529893549SGatien Chevallier 	     const struct pm_callback_handle *pm_handle __unused)
52629893549SGatien Chevallier {
52729893549SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
52829893549SGatien Chevallier 
52929893549SGatien Chevallier 	assert(stm32_rng && (op == PM_OP_SUSPEND || op == PM_OP_RESUME));
53029893549SGatien Chevallier 
53129893549SGatien Chevallier 	res = clk_enable(stm32_rng->clock);
53229893549SGatien Chevallier 	if (res)
53329893549SGatien Chevallier 		return res;
53429893549SGatien Chevallier 
53545da6509SGatien Chevallier 	if (stm32_rng->bus_clock) {
53645da6509SGatien Chevallier 		res = clk_enable(stm32_rng->bus_clock);
53745da6509SGatien Chevallier 		if (res) {
53845da6509SGatien Chevallier 			clk_disable(stm32_rng->clock);
53945da6509SGatien Chevallier 			return res;
54045da6509SGatien Chevallier 		}
54145da6509SGatien Chevallier 	}
54245da6509SGatien Chevallier 
543*5959d83fSGatien Chevallier 	if (op == PM_OP_RESUME)
544*5959d83fSGatien Chevallier 		res = stm32_rng_pm_resume();
54529893549SGatien Chevallier 	else
546*5959d83fSGatien Chevallier 		res = stm32_rng_pm_suspend();
54729893549SGatien Chevallier 
54829893549SGatien Chevallier 	clk_disable(stm32_rng->clock);
54945da6509SGatien Chevallier 	if (stm32_rng->bus_clock)
55045da6509SGatien Chevallier 		clk_disable(stm32_rng->bus_clock);
55129893549SGatien Chevallier 
55229893549SGatien Chevallier 	return res;
55329893549SGatien Chevallier }
55429893549SGatien Chevallier DECLARE_KEEP_PAGER(stm32_rng_pm);
55529893549SGatien Chevallier 
556ea8ba295SGatien Chevallier static TEE_Result stm32_rng_parse_fdt(const void *fdt, int node)
557f3c22059SEtienne Carriere {
558d7a1a7d2SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
559ea8ba295SGatien Chevallier 	struct dt_node_info dt_rng = { };
560f3c22059SEtienne Carriere 
561f354a5d8SGatien Chevallier 	fdt_fill_device_info(fdt, &dt_rng, node);
562ea8ba295SGatien Chevallier 	if (dt_rng.reg == DT_INFO_INVALID_REG)
563ea8ba295SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
564f3c22059SEtienne Carriere 
565ea8ba295SGatien Chevallier 	stm32_rng->base.pa = dt_rng.reg;
566ea8ba295SGatien Chevallier 	stm32_rng->base.va = io_pa_or_va_secure(&stm32_rng->base,
567ea8ba295SGatien Chevallier 						dt_rng.reg_size);
568ea8ba295SGatien Chevallier 	assert(stm32_rng->base.va);
569f3c22059SEtienne Carriere 
570ea8ba295SGatien Chevallier 	res = rstctrl_dt_get_by_index(fdt, node, 0, &stm32_rng->rstctrl);
571ea8ba295SGatien Chevallier 	if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND)
572ea8ba295SGatien Chevallier 		return res;
57368c4a16bSEtienne Carriere 
57445da6509SGatien Chevallier 	if (stm32_rng->ddata->nb_clock > 1) {
57545da6509SGatien Chevallier 		res = clk_dt_get_by_name(fdt, node, "rng_clk",
57645da6509SGatien Chevallier 					 &stm32_rng->clock);
57745da6509SGatien Chevallier 		if (res)
57845da6509SGatien Chevallier 			return res;
57945da6509SGatien Chevallier 
58045da6509SGatien Chevallier 		res = clk_dt_get_by_name(fdt, node, "rng_hclk",
58145da6509SGatien Chevallier 					 &stm32_rng->bus_clock);
58245da6509SGatien Chevallier 		if (res)
58345da6509SGatien Chevallier 			return res;
58445da6509SGatien Chevallier 	} else {
585d7a1a7d2SEtienne Carriere 		res = clk_dt_get_by_index(fdt, node, 0, &stm32_rng->clock);
586d7a1a7d2SEtienne Carriere 		if (res)
587d7a1a7d2SEtienne Carriere 			return res;
58845da6509SGatien Chevallier 	}
589d7a1a7d2SEtienne Carriere 
5903c752300SGatien Chevallier 	if (fdt_getprop(fdt, node, "clock-error-detect", NULL))
5913c752300SGatien Chevallier 		stm32_rng->clock_error = true;
5923c752300SGatien Chevallier 
593ea8ba295SGatien Chevallier 	/* Release device if not used at runtime or for pm transitions */
594ea8ba295SGatien Chevallier 	stm32_rng->release_post_boot = IS_ENABLED(CFG_WITH_SOFTWARE_PRNG) &&
595ea8ba295SGatien Chevallier 				       !IS_ENABLED(CFG_PM);
596f3c22059SEtienne Carriere 
597*5959d83fSGatien Chevallier 	stm32_rng->rng_config = stm32_rng->ddata->cr;
598*5959d83fSGatien Chevallier 	if (stm32_rng->rng_config & ~RNG_CR_ENTROPY_SRC_MASK)
599*5959d83fSGatien Chevallier 		panic("Incorrect entropy source configuration");
600*5959d83fSGatien Chevallier 	stm32_rng->health_test_conf = stm32_rng->ddata->htcr;
601*5959d83fSGatien Chevallier 	stm32_rng->noise_ctrl_conf = stm32_rng->ddata->nscr;
602*5959d83fSGatien Chevallier 	if (stm32_rng->noise_ctrl_conf & ~RNG_NSCR_MASK)
603*5959d83fSGatien Chevallier 		panic("Incorrect noise source control configuration");
604*5959d83fSGatien Chevallier 
605f3c22059SEtienne Carriere 	return TEE_SUCCESS;
606f3c22059SEtienne Carriere }
607f3c22059SEtienne Carriere 
608ea8ba295SGatien Chevallier static TEE_Result stm32_rng_probe(const void *fdt, int offs,
609f9508605SGatien Chevallier 				  const void *compat_data)
610ea8ba295SGatien Chevallier {
611ea8ba295SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
612ea8ba295SGatien Chevallier 
613ea8ba295SGatien Chevallier 	/* Expect a single RNG instance */
614ea8ba295SGatien Chevallier 	assert(!stm32_rng);
615ea8ba295SGatien Chevallier 
616ea8ba295SGatien Chevallier 	stm32_rng = calloc(1, sizeof(*stm32_rng));
617ea8ba295SGatien Chevallier 	if (!stm32_rng)
618ea8ba295SGatien Chevallier 		panic();
619ea8ba295SGatien Chevallier 
620*5959d83fSGatien Chevallier 	stm32_rng->ddata = compat_data;
621*5959d83fSGatien Chevallier 	assert(stm32_rng->ddata);
622*5959d83fSGatien Chevallier 
623ea8ba295SGatien Chevallier 	res = stm32_rng_parse_fdt(fdt, offs);
624ea8ba295SGatien Chevallier 	if (res)
625ea8ba295SGatien Chevallier 		goto err;
626ea8ba295SGatien Chevallier 
627ea8ba295SGatien Chevallier 	res = clk_enable(stm32_rng->clock);
628ea8ba295SGatien Chevallier 	if (res)
629ea8ba295SGatien Chevallier 		goto err;
630ea8ba295SGatien Chevallier 
63145da6509SGatien Chevallier 	if (stm32_rng->bus_clock) {
63245da6509SGatien Chevallier 		res = clk_enable(stm32_rng->bus_clock);
63345da6509SGatien Chevallier 		if (res) {
63445da6509SGatien Chevallier 			clk_disable(stm32_rng->clock);
63545da6509SGatien Chevallier 			goto err;
63645da6509SGatien Chevallier 		}
63745da6509SGatien Chevallier 	}
63845da6509SGatien Chevallier 
639ea8ba295SGatien Chevallier 	if (stm32_rng->rstctrl &&
640ea8ba295SGatien Chevallier 	    rstctrl_assert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) {
641ea8ba295SGatien Chevallier 		res = TEE_ERROR_GENERIC;
642ea8ba295SGatien Chevallier 		goto err_clk;
643ea8ba295SGatien Chevallier 	}
644ea8ba295SGatien Chevallier 
645ea8ba295SGatien Chevallier 	if (stm32_rng->rstctrl &&
646ea8ba295SGatien Chevallier 	    rstctrl_deassert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) {
647ea8ba295SGatien Chevallier 		res = TEE_ERROR_GENERIC;
648ea8ba295SGatien Chevallier 		goto err_clk;
649ea8ba295SGatien Chevallier 	}
650ea8ba295SGatien Chevallier 
651f63f11bdSGatien Chevallier 	res = init_rng();
652f63f11bdSGatien Chevallier 	if (res)
653f63f11bdSGatien Chevallier 		goto err_clk;
654f63f11bdSGatien Chevallier 
655ea8ba295SGatien Chevallier 	clk_disable(stm32_rng->clock);
65645da6509SGatien Chevallier 	if (stm32_rng->bus_clock)
65745da6509SGatien Chevallier 		clk_disable(stm32_rng->bus_clock);
658ea8ba295SGatien Chevallier 
659ea8ba295SGatien Chevallier 	if (stm32_rng->release_post_boot)
660ea8ba295SGatien Chevallier 		stm32mp_register_non_secure_periph_iomem(stm32_rng->base.pa);
661ea8ba295SGatien Chevallier 	else
662ea8ba295SGatien Chevallier 		stm32mp_register_secure_periph_iomem(stm32_rng->base.pa);
663ea8ba295SGatien Chevallier 
664*5959d83fSGatien Chevallier 	/* Power management implementation expects both or none are set */
665*5959d83fSGatien Chevallier 	assert(stm32_rng->ddata->has_power_optim ==
666*5959d83fSGatien Chevallier 	       stm32_rng->ddata->has_cond_reset);
667*5959d83fSGatien Chevallier 
66829893549SGatien Chevallier 	register_pm_core_service_cb(stm32_rng_pm, &stm32_rng, "rng-service");
66929893549SGatien Chevallier 
670ea8ba295SGatien Chevallier 	return TEE_SUCCESS;
671ea8ba295SGatien Chevallier 
672ea8ba295SGatien Chevallier err_clk:
673ea8ba295SGatien Chevallier 	clk_disable(stm32_rng->clock);
67445da6509SGatien Chevallier 	if (stm32_rng->bus_clock)
67545da6509SGatien Chevallier 		clk_disable(stm32_rng->bus_clock);
676ea8ba295SGatien Chevallier err:
677ea8ba295SGatien Chevallier 	free(stm32_rng);
678ea8ba295SGatien Chevallier 	stm32_rng = NULL;
679ea8ba295SGatien Chevallier 
680ea8ba295SGatien Chevallier 	return res;
681ea8ba295SGatien Chevallier }
682ea8ba295SGatien Chevallier 
683091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp13_data[] = {
68445da6509SGatien Chevallier 	{
68545da6509SGatien Chevallier 		.nb_clock = 1,
68645da6509SGatien Chevallier 		.has_cond_reset = true,
687*5959d83fSGatien Chevallier 		.has_power_optim = true,
688*5959d83fSGatien Chevallier 		.cr = 0x00F00D00,
689*5959d83fSGatien Chevallier 		.nscr = 0x2B5BB,
690*5959d83fSGatien Chevallier 		.htcr = 0x969D,
69145da6509SGatien Chevallier 	},
692091ef005SGatien Chevallier };
693091ef005SGatien Chevallier 
694091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp15_data[] = {
69545da6509SGatien Chevallier 	{
69645da6509SGatien Chevallier 		.nb_clock = 1,
69745da6509SGatien Chevallier 		.has_cond_reset = false,
698*5959d83fSGatien Chevallier 		.has_power_optim = false,
69945da6509SGatien Chevallier 	},
700091ef005SGatien Chevallier };
701091ef005SGatien Chevallier DECLARE_KEEP_PAGER(mp15_data);
702091ef005SGatien Chevallier 
70345da6509SGatien Chevallier static const struct stm32_rng_driver_data mp25_data[] = {
70445da6509SGatien Chevallier 	{
70545da6509SGatien Chevallier 		.nb_clock = 2,
70645da6509SGatien Chevallier 		.has_cond_reset = true,
707*5959d83fSGatien Chevallier 		.has_power_optim = true,
708*5959d83fSGatien Chevallier 		.cr = 0x00F00D00,
709*5959d83fSGatien Chevallier 		.nscr = 0x2B5BB,
710*5959d83fSGatien Chevallier 		.htcr = 0x969D,
71145da6509SGatien Chevallier 	},
71245da6509SGatien Chevallier };
71345da6509SGatien Chevallier 
714ea8ba295SGatien Chevallier static const struct dt_device_match rng_match_table[] = {
715091ef005SGatien Chevallier 	{ .compatible = "st,stm32-rng", .compat_data = &mp15_data },
716091ef005SGatien Chevallier 	{ .compatible = "st,stm32mp13-rng", .compat_data = &mp13_data },
71745da6509SGatien Chevallier 	{ .compatible = "st,stm32mp25-rng", .compat_data = &mp25_data },
718ea8ba295SGatien Chevallier 	{ }
719ea8ba295SGatien Chevallier };
720ea8ba295SGatien Chevallier 
721ea8ba295SGatien Chevallier DEFINE_DT_DRIVER(stm32_rng_dt_driver) = {
722ea8ba295SGatien Chevallier 	.name = "stm32_rng",
723ea8ba295SGatien Chevallier 	.match_table = rng_match_table,
724ea8ba295SGatien Chevallier 	.probe = stm32_rng_probe,
725ea8ba295SGatien Chevallier };
726d8682c4cSEtienne Carriere 
727d8682c4cSEtienne Carriere static TEE_Result stm32_rng_release(void)
728d8682c4cSEtienne Carriere {
729d8682c4cSEtienne Carriere 	if (stm32_rng && stm32_rng->release_post_boot) {
730d8682c4cSEtienne Carriere 		DMSG("Release RNG driver");
731d8682c4cSEtienne Carriere 		free(stm32_rng);
732d8682c4cSEtienne Carriere 		stm32_rng = NULL;
733d8682c4cSEtienne Carriere 	}
734d8682c4cSEtienne Carriere 
735d8682c4cSEtienne Carriere 	return TEE_SUCCESS;
736d8682c4cSEtienne Carriere }
737d8682c4cSEtienne Carriere 
738d8682c4cSEtienne Carriere release_init_resource(stm32_rng_release);
739