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
seed_error_recovery(void)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
stm32_rng_clock_freq_restrain(void)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
stm32_rng_enable(void)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
check_data_validity(void)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 */
stm32_rng_read(uint8_t * out,uint32_t size)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 */
stm32_rng_select(uintptr_t rng_base)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 */
stm32_rng_init(void)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