xref: /rk3399_ARM-atf/drivers/st/crypto/stm32_rng.c (revision 982ee634e7c4decd941b2fe97d85181b5615797a)
1 /*
2  * Copyright (c) 2022-2025, STMicroelectronics - All Rights Reserved
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <errno.h>
9 #include <stdbool.h>
10 
11 #include <arch_helpers.h>
12 #include <common/fdt_wrappers.h>
13 #include <drivers/clk.h>
14 #include <drivers/delay_timer.h>
15 #include <drivers/st/stm32_rng.h>
16 #include <drivers/st/stm32mp_reset.h>
17 #include <lib/mmio.h>
18 #include <libfdt.h>
19 
20 #include <platform_def.h>
21 
22 #if STM32_RNG_VER == 2
23 #define DT_RNG_COMPAT		"st,stm32-rng"
24 #endif
25 #if STM32_RNG_VER == 4
26 #define DT_RNG_COMPAT		"st,stm32mp13-rng"
27 #endif
28 #define RNG_CR			0x00U
29 #define RNG_SR			0x04U
30 #define RNG_DR			0x08U
31 #if STM32_RNG_VER == 4
32 #define RNG_HTCR		0x10U
33 #endif
34 
35 #define RNG_CR_RNGEN		BIT(2)
36 #define RNG_CR_IE		BIT(3)
37 #define RNG_CR_CED		BIT(5)
38 #define RNG_CR_CLKDIV		GENMASK(19, 16)
39 #define RNG_CR_CLKDIV_SHIFT	16U
40 #define RNG_CR_CONDRST		BIT(30)
41 
42 #define RNG_SR_DRDY		BIT(0)
43 #define RNG_SR_CECS		BIT(1)
44 #define RNG_SR_SECS		BIT(2)
45 #define RNG_SR_CEIS		BIT(5)
46 #define RNG_SR_SEIS		BIT(6)
47 
48 #define RNG_TIMEOUT_US		100000U
49 #define RNG_TIMEOUT_STEP_US	10U
50 
51 #define TIMEOUT_US_1MS		1000U
52 
53 #define RNG_NIST_CONFIG_A	0x00F40F00U
54 #define RNG_NIST_CONFIG_B	0x01801000U
55 #define RNG_NIST_CONFIG_C	0x00F00D00U
56 #define RNG_NIST_CONFIG_MASK	GENMASK(25, 8)
57 
58 #if STM32_RNG_VER == 4
59 #if STM32_RNG_VER_MINOR == 2
60 #define RNG_HTCFG_CONFIG	0x000072ACU /* Reset value */
61 #else
62 #define RNG_HTCFG_CONFIG	0x0000AAC7U
63 #endif
64 #endif
65 
66 #define RNG_MAX_NOISE_CLK_FREQ	48000000U
67 
68 struct stm32_rng_instance {
69 	uintptr_t base;
70 	unsigned long clock;
71 };
72 
73 static struct stm32_rng_instance stm32_rng;
74 
75 static void seed_error_recovery(void)
76 {
77 	uint8_t i __maybe_unused;
78 
79 	/* Recommended by the SoC reference manual */
80 	mmio_clrbits_32(stm32_rng.base + RNG_SR, RNG_SR_SEIS);
81 	dmbsy();
82 
83 #if STM32_RNG_VER == 2
84 	/* No Auto-reset on version 2, need to clean FIFO */
85 	for (i = 12U; i != 0U; i--) {
86 		(void)mmio_read_32(stm32_rng.base + RNG_DR);
87 	}
88 
89 	dmbsy();
90 #endif
91 
92 	if ((mmio_read_32(stm32_rng.base + RNG_SR) & RNG_SR_SEIS) != 0U) {
93 		ERROR("RNG noise\n");
94 		panic();
95 	}
96 }
97 
98 static uint32_t stm32_rng_clock_freq_restrain(void)
99 {
100 	unsigned long clock_rate;
101 	uint32_t clock_div = 0U;
102 
103 	clock_rate = clk_get_rate(stm32_rng.clock);
104 
105 	/*
106 	 * Get the exponent to apply on the CLKDIV field in RNG_CR register
107 	 * No need to handle the case when clock-div > 0xF as it is physically
108 	 * impossible
109 	 */
110 	while ((clock_rate >> clock_div) > RNG_MAX_NOISE_CLK_FREQ) {
111 		clock_div++;
112 	}
113 
114 	VERBOSE("RNG clk rate : %lu\n", clk_get_rate(stm32_rng.clock) >> clock_div);
115 
116 	return clock_div;
117 }
118 
119 static int stm32_rng_enable(void)
120 {
121 	uint32_t sr;
122 	uint64_t timeout;
123 	uint32_t clock_div __maybe_unused;
124 
125 #if STM32_RNG_VER == 2
126 	mmio_write_32(stm32_rng.base + RNG_CR, RNG_CR_RNGEN | RNG_CR_CED);
127 #endif
128 #if STM32_RNG_VER == 4
129 	/* Reset internal block and disable CED bit */
130 	clock_div = stm32_rng_clock_freq_restrain();
131 
132 	/* Update configuration fields */
133 	mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_NIST_CONFIG_MASK,
134 			   RNG_NIST_CONFIG_A | RNG_CR_CONDRST | RNG_CR_CED);
135 
136 	mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_CR_CLKDIV,
137 			   (clock_div << RNG_CR_CLKDIV_SHIFT));
138 
139 	mmio_write_32(stm32_rng.base + RNG_HTCR, RNG_HTCFG_CONFIG);
140 
141 	mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_CR_CONDRST, RNG_CR_RNGEN);
142 #endif
143 	timeout = timeout_init_us(RNG_TIMEOUT_US);
144 	sr = mmio_read_32(stm32_rng.base + RNG_SR);
145 	while ((sr & RNG_SR_DRDY) == 0U) {
146 		if (timeout_elapsed(timeout)) {
147 			WARN("Timeout waiting\n");
148 			return -ETIMEDOUT;
149 		}
150 
151 		if ((sr & (RNG_SR_SECS | RNG_SR_SEIS)) != 0U) {
152 			seed_error_recovery();
153 			timeout = timeout_init_us(RNG_TIMEOUT_US);
154 		}
155 
156 		udelay(RNG_TIMEOUT_STEP_US);
157 		sr = mmio_read_32(stm32_rng.base + RNG_SR);
158 	}
159 
160 	VERBOSE("Init RNG done\n");
161 
162 	return 0;
163 }
164 
165 static int check_data_validity(void)
166 {
167 	int nb_tries = RNG_TIMEOUT_US / RNG_TIMEOUT_STEP_US;
168 	uint32_t status = mmio_read_32(stm32_rng.base + RNG_SR);
169 
170 	/* Exit if data is ready without any seed error */
171 	if ((status & (RNG_SR_SECS | RNG_SR_SEIS | RNG_SR_DRDY)) != RNG_SR_DRDY) {
172 		do {
173 
174 			if ((status & (RNG_SR_SECS | RNG_SR_SEIS)) != 0U) {
175 				seed_error_recovery();
176 			}
177 
178 			udelay(RNG_TIMEOUT_STEP_US);
179 			nb_tries--;
180 			if (nb_tries == 0) {
181 				return -ETIMEDOUT;
182 			}
183 
184 			status = mmio_read_32(stm32_rng.base + RNG_SR);
185 		} while ((status & RNG_SR_DRDY) == 0U);
186 	}
187 
188 	return 0;
189 }
190 
191 /*
192  * stm32_rng_read - Read a number of random bytes from RNG
193  * out: pointer to the output buffer
194  * size: number of bytes to be read
195  * Return 0 on success, non-0 on failure
196  */
197 int stm32_rng_read(uint8_t *out, uint32_t size)
198 {
199 	uint8_t *buf = out;
200 	size_t len = size;
201 	uint32_t data32;
202 	int rc = 0;
203 	unsigned int count;
204 
205 	if (stm32_rng.base == 0U) {
206 		return -EPERM;
207 	}
208 
209 	while (len != 0U) {
210 		rc = check_data_validity();
211 		if (rc != 0) {
212 			goto bail;
213 		}
214 
215 		count = 4U;
216 		while (len != 0U) {
217 			if ((mmio_read_32(stm32_rng.base + RNG_SR) & RNG_SR_DRDY) == 0U) {
218 				break;
219 			}
220 
221 			data32 = mmio_read_32(stm32_rng.base + RNG_DR);
222 
223 			while (data32 == 0U) {
224 				rc = check_data_validity();
225 				if (rc != 0) {
226 					goto bail;
227 				}
228 
229 				data32 = mmio_read_32(stm32_rng.base + RNG_DR);
230 			}
231 
232 			count--;
233 
234 			(void)memcpy(buf, (uint8_t *)&data32, MIN(len, sizeof(uint32_t)));
235 			buf += MIN(len, sizeof(uint32_t));
236 			len -= MIN(len, sizeof(uint32_t));
237 
238 			if (count == 0U) {
239 				break;
240 			}
241 		}
242 	}
243 
244 bail:
245 	if (rc != 0) {
246 		(void)memset(out, 0, buf - out);
247 	}
248 
249 	return rc;
250 }
251 
252 /*
253  * stm32_rng_select: Select a specified RNG instance from its base address.
254  * This function only works if the driver is uninitialized.
255  */
256 void stm32_rng_select(uintptr_t rng_base)
257 {
258 	if ((stm32_rng.base == 0U) || (stm32_rng.clock == 0U)) {
259 		/* RNG instance is selected once */
260 		stm32_rng.base = rng_base;
261 	}
262 }
263 
264 /*
265  * stm32_rng_init: Initialize rng from DT
266  * return 0 on success, negative value on failure
267  */
268 int stm32_rng_init(void)
269 {
270 	struct stm32_rng_instance rng = {0, 0};
271 	void *fdt;
272 	int node;
273 	int success = 0;
274 	int disabled = 0;
275 
276 	if (stm32_rng.base != 0U) {
277 		if (stm32_rng.clock != 0U) {
278 			/* Driver is already initialized */
279 			return 0;
280 		}
281 
282 		rng.base = stm32_rng.base;
283 	}
284 
285 	if (fdt_get_address(&fdt) == 0) {
286 		panic();
287 	}
288 
289 	fdt_for_each_compatible_node(fdt, node, DT_RNG_COMPAT) {
290 		struct dt_node_info dt_rng;
291 		int ret;
292 
293 		dt_fill_device_info(&dt_rng, node);
294 
295 		VERBOSE("Setting up rng@%x, status: %x\n", dt_rng.base, dt_rng.status);
296 
297 		/*
298 		 * All the valid RNG peripherals available in device tree are
299 		 * activated but only the last RNG found is assigned to the RNG
300 		 * instance of the driver.
301 		 */
302 		if ((dt_rng.status == DT_DISABLED) || (dt_rng.base == 0U)) {
303 			disabled++;
304 			continue;
305 		}
306 
307 		stm32_rng.base = dt_rng.base;
308 
309 		if (dt_rng.clock < 0) {
310 			panic();
311 		}
312 
313 		stm32_rng.clock = (unsigned long)dt_rng.clock;
314 		clk_enable(stm32_rng.clock);
315 
316 		if (stm32_rng.base == rng.base) {
317 			/* Set the rng instance as the rng to use by TF-A */
318 			rng.clock = stm32_rng.clock;
319 		}
320 
321 		if (dt_rng.reset >= 0) {
322 
323 			ret = stm32mp_reset_assert((unsigned long)dt_rng.reset, TIMEOUT_US_1MS);
324 			if (ret != 0) {
325 				panic();
326 			}
327 
328 			udelay(20);
329 
330 			ret = stm32mp_reset_deassert((unsigned long)dt_rng.reset, TIMEOUT_US_1MS);
331 			if (ret != 0) {
332 				panic();
333 			}
334 		}
335 
336 		ret = stm32_rng_enable();
337 		if (ret != 0) {
338 			ERROR("Failed to enable rng@%x\n", dt_rng.base);
339 		} else {
340 			success++;
341 		}
342 	}
343 
344 	if ((success == 0) && (disabled > 0)) {
345 		WARN("%s: No RNG found in device tree.\n", __func__);
346 		return 0;
347 	} else if (success > 0) {
348 		if ((rng.clock != 0U) && (rng.base != 0U)) {
349 			stm32_rng = rng;
350 		}
351 		return 0;
352 	} else {
353 		return -ENODEV;
354 	}
355 }
356