]> git.ipfire.org Git - thirdparty/u-boot.git/blob - drivers/rng/stm32_rng.c
rng: eliminate common.h include from RNG drivers
[thirdparty/u-boot.git] / drivers / rng / stm32_rng.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2019, Linaro Limited
4 */
5
6 #define LOG_CATEGORY UCLASS_RNG
7
8 #include <clk.h>
9 #include <dm.h>
10 #include <log.h>
11 #include <reset.h>
12 #include <rng.h>
13 #include <asm/io.h>
14 #include <linux/bitops.h>
15 #include <linux/delay.h>
16 #include <linux/iopoll.h>
17 #include <linux/kernel.h>
18
19 #define RNG_CR 0x00
20 #define RNG_CR_RNGEN BIT(2)
21 #define RNG_CR_CED BIT(5)
22 #define RNG_CR_CONFIG1 GENMASK(11, 8)
23 #define RNG_CR_NISTC BIT(12)
24 #define RNG_CR_CONFIG2 GENMASK(15, 13)
25 #define RNG_CR_CLKDIV_SHIFT 16
26 #define RNG_CR_CLKDIV GENMASK(19, 16)
27 #define RNG_CR_CONFIG3 GENMASK(25, 20)
28 #define RNG_CR_CONDRST BIT(30)
29 #define RNG_CR_ENTROPY_SRC_MASK (RNG_CR_CONFIG1 | RNG_CR_NISTC | RNG_CR_CONFIG2 | RNG_CR_CONFIG3)
30 #define RNG_CR_CONFIG_MASK (RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED | RNG_CR_CLKDIV)
31
32 #define RNG_SR 0x04
33 #define RNG_SR_SEIS BIT(6)
34 #define RNG_SR_CEIS BIT(5)
35 #define RNG_SR_SECS BIT(2)
36 #define RNG_SR_DRDY BIT(0)
37
38 #define RNG_DR 0x08
39
40 #define RNG_NSCR 0x0C
41 #define RNG_NSCR_MASK GENMASK(17, 0)
42
43 #define RNG_HTCR 0x10
44
45 #define RNG_NB_RECOVER_TRIES 3
46
47 /*
48 * struct stm32_rng_data - RNG compat data
49 *
50 * @max_clock_rate: Max RNG clock frequency, in Hertz
51 * @cr: Entropy source configuration
52 * @nscr: Noice sources control configuration
53 * @htcr: Health tests configuration
54 * @has_cond_reset: True if conditionnal reset is supported
55 *
56 */
57 struct stm32_rng_data {
58 uint max_clock_rate;
59 u32 cr;
60 u32 nscr;
61 u32 htcr;
62 bool has_cond_reset;
63 };
64
65 struct stm32_rng_plat {
66 fdt_addr_t base;
67 struct clk clk;
68 struct reset_ctl rst;
69 const struct stm32_rng_data *data;
70 bool ced;
71 };
72
73 /*
74 * Extracts from the STM32 RNG specification when RNG supports CONDRST.
75 *
76 * When a noise source (or seed) error occurs, the RNG stops generating
77 * random numbers and sets to “1” both SEIS and SECS bits to indicate
78 * that a seed error occurred. (...)
79 *
80 * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield
81 * description for details). This step is needed only if SECS is set.
82 * Indeed, when SEIS is set and SECS is cleared it means RNG performed
83 * the reset automatically (auto-reset).
84 * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST
85 * to be cleared in the RNG_CR register, then confirm that SEIS is
86 * cleared in the RNG_SR register. Otherwise just clear SEIS bit in
87 * the RNG_SR register.
88 * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be
89 * cleared by RNG. The random number generation is now back to normal.
90 */
91 static int stm32_rng_conceal_seed_error_cond_reset(struct stm32_rng_plat *pdata)
92 {
93 u32 sr = readl_relaxed(pdata->base + RNG_SR);
94 u32 cr = readl_relaxed(pdata->base + RNG_CR);
95 int err;
96
97 if (sr & RNG_SR_SECS) {
98 /* Conceal by resetting the subsystem (step 1.) */
99 writel_relaxed(cr | RNG_CR_CONDRST, pdata->base + RNG_CR);
100 writel_relaxed(cr & ~RNG_CR_CONDRST, pdata->base + RNG_CR);
101 } else {
102 /* RNG auto-reset (step 2.) */
103 writel_relaxed(sr & ~RNG_SR_SEIS, pdata->base + RNG_SR);
104 return 0;
105 }
106
107 err = readl_relaxed_poll_timeout(pdata->base + RNG_SR, sr, !(sr & RNG_CR_CONDRST), 100000);
108 if (err) {
109 log_err("%s: timeout %x\n", __func__, sr);
110 return err;
111 }
112
113 /* Check SEIS is cleared (step 2.) */
114 if (readl_relaxed(pdata->base + RNG_SR) & RNG_SR_SEIS)
115 return -EINVAL;
116
117 err = readl_relaxed_poll_timeout(pdata->base + RNG_SR, sr, !(sr & RNG_SR_SECS), 100000);
118 if (err) {
119 log_err("%s: timeout %x\n", __func__, sr);
120 return err;
121 }
122
123 return 0;
124 }
125
126 /*
127 * Extracts from the STM32 RNG specification, when CONDRST is not supported
128 *
129 * When a noise source (or seed) error occurs, the RNG stops generating
130 * random numbers and sets to “1” both SEIS and SECS bits to indicate
131 * that a seed error occurred. (...)
132 *
133 * The following sequence shall be used to fully recover from a seed
134 * error after the RNG initialization:
135 * 1. Clear the SEIS bit by writing it to “0”.
136 * 2. Read out 12 words from the RNG_DR register, and discard each of
137 * them in order to clean the pipeline.
138 * 3. Confirm that SEIS is still cleared. Random number generation is
139 * back to normal.
140 */
141 static int stm32_rng_conceal_seed_error_sw_reset(struct stm32_rng_plat *pdata)
142 {
143 uint i = 0;
144 u32 sr = readl_relaxed(pdata->base + RNG_SR);
145
146 writel_relaxed(sr & ~RNG_SR_SEIS, pdata->base + RNG_SR);
147
148 for (i = 12; i != 0; i--)
149 (void)readl_relaxed(pdata->base + RNG_DR);
150
151 if (readl_relaxed(pdata->base + RNG_SR) & RNG_SR_SEIS)
152 return -EINVAL;
153
154 return 0;
155 }
156
157 static int stm32_rng_conceal_seed_error(struct stm32_rng_plat *pdata)
158 {
159 log_debug("Concealing RNG seed error\n");
160
161 if (pdata->data->has_cond_reset)
162 return stm32_rng_conceal_seed_error_cond_reset(pdata);
163 else
164 return stm32_rng_conceal_seed_error_sw_reset(pdata);
165 };
166
167 static int stm32_rng_read(struct udevice *dev, void *data, size_t len)
168 {
169 int retval;
170 u32 sr, reg;
171 size_t increment;
172 struct stm32_rng_plat *pdata = dev_get_plat(dev);
173 uint tries = 0;
174
175 while (len > 0) {
176 retval = readl_poll_timeout(pdata->base + RNG_SR, sr,
177 sr, 10000);
178 if (retval) {
179 log_err("%s: Timeout RNG no data", __func__);
180 return retval;
181 }
182
183 if (sr != RNG_SR_DRDY) {
184 if (sr & RNG_SR_SEIS) {
185 retval = stm32_rng_conceal_seed_error(pdata);
186 tries++;
187 if (retval || tries > RNG_NB_RECOVER_TRIES) {
188 log_err("%s: Couldn't recover from seed error", __func__);
189 return -ENOTRECOVERABLE;
190 }
191
192 /* Start again */
193 continue;
194 }
195
196 if (sr & RNG_SR_CEIS) {
197 log_info("RNG clock too slow");
198 writel_relaxed(0, pdata->base + RNG_SR);
199 }
200 }
201
202 /*
203 * Once the DRDY bit is set, the RNG_DR register can
204 * be read up to four consecutive times.
205 */
206 reg = readl(pdata->base + RNG_DR);
207 /* Late seed error case: DR being 0 is an error status */
208 if (!reg) {
209 retval = stm32_rng_conceal_seed_error(pdata);
210 tries++;
211
212 if (retval || tries > RNG_NB_RECOVER_TRIES) {
213 log_err("%s: Couldn't recover from seed error", __func__);
214 return -ENOTRECOVERABLE;
215 }
216
217 /* Start again */
218 continue;
219 }
220
221 increment = min(len, sizeof(u32));
222 memcpy(data, &reg, increment);
223 data += increment;
224 len -= increment;
225
226 tries = 0;
227 }
228
229 return 0;
230 }
231
232 static uint stm32_rng_clock_freq_restrain(struct stm32_rng_plat *pdata)
233 {
234 ulong clock_rate = 0;
235 uint clock_div = 0;
236
237 clock_rate = clk_get_rate(&pdata->clk);
238
239 /*
240 * Get the exponent to apply on the CLKDIV field in RNG_CR register.
241 * No need to handle the case when clock-div > 0xF as it is physically
242 * impossible.
243 */
244 while ((clock_rate >> clock_div) > pdata->data->max_clock_rate)
245 clock_div++;
246
247 log_debug("RNG clk rate : %lu\n", clk_get_rate(&pdata->clk) >> clock_div);
248
249 return clock_div;
250 }
251
252 static int stm32_rng_init(struct stm32_rng_plat *pdata)
253 {
254 int err;
255 u32 cr, sr;
256
257 err = clk_enable(&pdata->clk);
258 if (err)
259 return err;
260
261 cr = readl(pdata->base + RNG_CR);
262
263 /*
264 * Keep default RNG configuration if none was specified, that is when conf.cr is set to 0.
265 */
266 if (pdata->data->has_cond_reset && pdata->data->cr) {
267 uint clock_div = stm32_rng_clock_freq_restrain(pdata);
268
269 cr &= ~RNG_CR_CONFIG_MASK;
270 cr |= RNG_CR_CONDRST | (pdata->data->cr & RNG_CR_ENTROPY_SRC_MASK) |
271 (clock_div << RNG_CR_CLKDIV_SHIFT);
272 if (pdata->ced)
273 cr &= ~RNG_CR_CED;
274 else
275 cr |= RNG_CR_CED;
276 writel(cr, pdata->base + RNG_CR);
277
278 /* Health tests and noise control registers */
279 writel_relaxed(pdata->data->htcr, pdata->base + RNG_HTCR);
280 writel_relaxed(pdata->data->nscr & RNG_NSCR_MASK, pdata->base + RNG_NSCR);
281
282 cr &= ~RNG_CR_CONDRST;
283 cr |= RNG_CR_RNGEN;
284 writel(cr, pdata->base + RNG_CR);
285 err = readl_poll_timeout(pdata->base + RNG_CR, cr,
286 (!(cr & RNG_CR_CONDRST)), 10000);
287 if (err) {
288 log_err("%s: Timeout!", __func__);
289 return err;
290 }
291 } else {
292 if (pdata->data->has_cond_reset)
293 cr |= RNG_CR_CONDRST;
294
295 if (pdata->ced)
296 cr &= ~RNG_CR_CED;
297 else
298 cr |= RNG_CR_CED;
299
300 writel(cr, pdata->base + RNG_CR);
301
302 if (pdata->data->has_cond_reset)
303 cr &= ~RNG_CR_CONDRST;
304
305 cr |= RNG_CR_RNGEN;
306
307 writel(cr, pdata->base + RNG_CR);
308 }
309
310 /* clear error indicators */
311 writel(0, pdata->base + RNG_SR);
312
313 err = readl_poll_timeout(pdata->base + RNG_SR, sr,
314 sr & RNG_SR_DRDY, 10000);
315 if (err)
316 log_err("%s: Timeout!", __func__);
317
318 return err;
319 }
320
321 static int stm32_rng_cleanup(struct stm32_rng_plat *pdata)
322 {
323 writel(0, pdata->base + RNG_CR);
324
325 return clk_disable(&pdata->clk);
326 }
327
328 static int stm32_rng_probe(struct udevice *dev)
329 {
330 struct stm32_rng_plat *pdata = dev_get_plat(dev);
331
332 pdata->data = (struct stm32_rng_data *)dev_get_driver_data(dev);
333
334 reset_assert(&pdata->rst);
335 udelay(20);
336 reset_deassert(&pdata->rst);
337
338 return stm32_rng_init(pdata);
339 }
340
341 static int stm32_rng_remove(struct udevice *dev)
342 {
343 struct stm32_rng_plat *pdata = dev_get_plat(dev);
344
345 return stm32_rng_cleanup(pdata);
346 }
347
348 static int stm32_rng_of_to_plat(struct udevice *dev)
349 {
350 struct stm32_rng_plat *pdata = dev_get_plat(dev);
351 int err;
352
353 pdata->base = dev_read_addr(dev);
354 if (!pdata->base)
355 return -ENOMEM;
356
357 err = clk_get_by_index(dev, 0, &pdata->clk);
358 if (err)
359 return err;
360
361 err = reset_get_by_index(dev, 0, &pdata->rst);
362 if (err)
363 return err;
364
365 pdata->ced = dev_read_bool(dev, "clock-error-detect");
366
367 return 0;
368 }
369
370 static const struct dm_rng_ops stm32_rng_ops = {
371 .read = stm32_rng_read,
372 };
373
374 static const struct stm32_rng_data stm32mp13_rng_data = {
375 .has_cond_reset = true,
376 .max_clock_rate = 48000000,
377 .htcr = 0x969D,
378 .nscr = 0x2B5BB,
379 .cr = 0xF00D00,
380 };
381
382 static const struct stm32_rng_data stm32_rng_data = {
383 .has_cond_reset = false,
384 .max_clock_rate = 3000000,
385 /* Not supported */
386 .htcr = 0,
387 .nscr = 0,
388 .cr = 0,
389 };
390
391 static const struct udevice_id stm32_rng_match[] = {
392 {.compatible = "st,stm32mp13-rng", .data = (ulong)&stm32mp13_rng_data},
393 {.compatible = "st,stm32-rng", .data = (ulong)&stm32_rng_data},
394 {},
395 };
396
397 U_BOOT_DRIVER(stm32_rng) = {
398 .name = "stm32-rng",
399 .id = UCLASS_RNG,
400 .of_match = stm32_rng_match,
401 .ops = &stm32_rng_ops,
402 .probe = stm32_rng_probe,
403 .remove = stm32_rng_remove,
404 .plat_auto = sizeof(struct stm32_rng_plat),
405 .of_to_plat = stm32_rng_of_to_plat,
406 };