blob: c397b4d95cdb55381b4adc61c063f320c826b289 [file] [log] [blame]
Sughosh Ganucd9a2f92019-12-28 23:58:29 +05301// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2019, Linaro Limited
4 */
5
Heinrich Schuchardtd909bab2020-09-17 16:49:02 +02006#define LOG_CATEGORY UCLASS_RNG
7
Sughosh Ganucd9a2f92019-12-28 23:58:29 +05308#include <common.h>
9#include <clk.h>
10#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053012#include <reset.h>
13#include <rng.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060014#include <linux/bitops.h>
Simon Glassdbd79542020-05-10 11:40:11 -060015#include <linux/delay.h>
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053016
17#include <asm/io.h>
18#include <linux/iopoll.h>
19#include <linux/kernel.h>
20
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +020021#define RNG_CR 0x00
22#define RNG_CR_RNGEN BIT(2)
23#define RNG_CR_CED BIT(5)
Gatien Chevallier5e65d462023-09-19 17:27:58 +020024#define RNG_CR_CONFIG1 GENMASK(11, 8)
25#define RNG_CR_NISTC BIT(12)
26#define RNG_CR_CONFIG2 GENMASK(15, 13)
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +020027#define RNG_CR_CLKDIV_SHIFT 16
Gatien Chevallier5e65d462023-09-19 17:27:58 +020028#define RNG_CR_CLKDIV GENMASK(19, 16)
29#define RNG_CR_CONFIG3 GENMASK(25, 20)
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +020030#define RNG_CR_CONDRST BIT(30)
Gatien Chevallier5e65d462023-09-19 17:27:58 +020031#define RNG_CR_ENTROPY_SRC_MASK (RNG_CR_CONFIG1 | RNG_CR_NISTC | RNG_CR_CONFIG2 | RNG_CR_CONFIG3)
32#define RNG_CR_CONFIG_MASK (RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED | RNG_CR_CLKDIV)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053033
Lionel Debieve71f44212022-06-30 10:20:15 +020034#define RNG_SR 0x04
35#define RNG_SR_SEIS BIT(6)
36#define RNG_SR_CEIS BIT(5)
37#define RNG_SR_SECS BIT(2)
38#define RNG_SR_DRDY BIT(0)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053039
Lionel Debieve71f44212022-06-30 10:20:15 +020040#define RNG_DR 0x08
41
Gatien Chevallier5e65d462023-09-19 17:27:58 +020042#define RNG_NSCR 0x0C
43#define RNG_NSCR_MASK GENMASK(17, 0)
44
45#define RNG_HTCR 0x10
46
Gatien Chevallier278ed192023-09-19 17:27:57 +020047#define RNG_NB_RECOVER_TRIES 3
48
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +020049/*
50 * struct stm32_rng_data - RNG compat data
51 *
52 * @max_clock_rate: Max RNG clock frequency, in Hertz
Gatien Chevallier5e65d462023-09-19 17:27:58 +020053 * @cr: Entropy source configuration
54 * @nscr: Noice sources control configuration
55 * @htcr: Health tests configuration
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +020056 * @has_cond_reset: True if conditionnal reset is supported
57 *
58 */
Lionel Debieve71f44212022-06-30 10:20:15 +020059struct stm32_rng_data {
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +020060 uint max_clock_rate;
Gatien Chevallier5e65d462023-09-19 17:27:58 +020061 u32 cr;
62 u32 nscr;
63 u32 htcr;
Lionel Debieve71f44212022-06-30 10:20:15 +020064 bool has_cond_reset;
65};
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053066
Simon Glassb75b15b2020-12-03 16:55:23 -070067struct stm32_rng_plat {
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053068 fdt_addr_t base;
69 struct clk clk;
70 struct reset_ctl rst;
Lionel Debieve71f44212022-06-30 10:20:15 +020071 const struct stm32_rng_data *data;
Gatien Chevalliere2acc952023-09-19 17:27:55 +020072 bool ced;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053073};
74
Gatien Chevallier278ed192023-09-19 17:27:57 +020075/*
76 * Extracts from the STM32 RNG specification when RNG supports CONDRST.
77 *
78 * When a noise source (or seed) error occurs, the RNG stops generating
79 * random numbers and sets to “1” both SEIS and SECS bits to indicate
80 * that a seed error occurred. (...)
81 *
82 * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield
83 * description for details). This step is needed only if SECS is set.
84 * Indeed, when SEIS is set and SECS is cleared it means RNG performed
85 * the reset automatically (auto-reset).
86 * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST
87 * to be cleared in the RNG_CR register, then confirm that SEIS is
88 * cleared in the RNG_SR register. Otherwise just clear SEIS bit in
89 * the RNG_SR register.
90 * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be
91 * cleared by RNG. The random number generation is now back to normal.
92 */
93static int stm32_rng_conceal_seed_error_cond_reset(struct stm32_rng_plat *pdata)
94{
95 u32 sr = readl_relaxed(pdata->base + RNG_SR);
96 u32 cr = readl_relaxed(pdata->base + RNG_CR);
97 int err;
98
99 if (sr & RNG_SR_SECS) {
100 /* Conceal by resetting the subsystem (step 1.) */
101 writel_relaxed(cr | RNG_CR_CONDRST, pdata->base + RNG_CR);
102 writel_relaxed(cr & ~RNG_CR_CONDRST, pdata->base + RNG_CR);
103 } else {
104 /* RNG auto-reset (step 2.) */
105 writel_relaxed(sr & ~RNG_SR_SEIS, pdata->base + RNG_SR);
106 return 0;
107 }
108
109 err = readl_relaxed_poll_timeout(pdata->base + RNG_SR, sr, !(sr & RNG_CR_CONDRST), 100000);
110 if (err) {
111 log_err("%s: timeout %x\n", __func__, sr);
112 return err;
113 }
114
115 /* Check SEIS is cleared (step 2.) */
116 if (readl_relaxed(pdata->base + RNG_SR) & RNG_SR_SEIS)
117 return -EINVAL;
118
119 err = readl_relaxed_poll_timeout(pdata->base + RNG_SR, sr, !(sr & RNG_SR_SECS), 100000);
120 if (err) {
121 log_err("%s: timeout %x\n", __func__, sr);
122 return err;
123 }
124
125 return 0;
126}
127
128/*
129 * Extracts from the STM32 RNG specification, when CONDRST is not supported
130 *
131 * When a noise source (or seed) error occurs, the RNG stops generating
132 * random numbers and sets to “1” both SEIS and SECS bits to indicate
133 * that a seed error occurred. (...)
134 *
135 * The following sequence shall be used to fully recover from a seed
136 * error after the RNG initialization:
137 * 1. Clear the SEIS bit by writing it to “0”.
138 * 2. Read out 12 words from the RNG_DR register, and discard each of
139 * them in order to clean the pipeline.
140 * 3. Confirm that SEIS is still cleared. Random number generation is
141 * back to normal.
142 */
143static int stm32_rng_conceal_seed_error_sw_reset(struct stm32_rng_plat *pdata)
144{
145 uint i = 0;
146 u32 sr = readl_relaxed(pdata->base + RNG_SR);
147
148 writel_relaxed(sr & ~RNG_SR_SEIS, pdata->base + RNG_SR);
149
150 for (i = 12; i != 0; i--)
151 (void)readl_relaxed(pdata->base + RNG_DR);
152
153 if (readl_relaxed(pdata->base + RNG_SR) & RNG_SR_SEIS)
154 return -EINVAL;
155
156 return 0;
157}
158
159static int stm32_rng_conceal_seed_error(struct stm32_rng_plat *pdata)
160{
161 log_debug("Concealing RNG seed error\n");
162
163 if (pdata->data->has_cond_reset)
164 return stm32_rng_conceal_seed_error_cond_reset(pdata);
165 else
166 return stm32_rng_conceal_seed_error_sw_reset(pdata);
167};
168
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530169static int stm32_rng_read(struct udevice *dev, void *data, size_t len)
170{
Gatien Chevallier278ed192023-09-19 17:27:57 +0200171 int retval;
172 u32 sr, reg;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530173 size_t increment;
Simon Glassb75b15b2020-12-03 16:55:23 -0700174 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Gatien Chevallier278ed192023-09-19 17:27:57 +0200175 uint tries = 0;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530176
177 while (len > 0) {
178 retval = readl_poll_timeout(pdata->base + RNG_SR, sr,
Gatien Chevallier278ed192023-09-19 17:27:57 +0200179 sr, 10000);
180 if (retval) {
181 log_err("%s: Timeout RNG no data", __func__);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530182 return retval;
Gatien Chevallier278ed192023-09-19 17:27:57 +0200183 }
184
185 if (sr != RNG_SR_DRDY) {
186 if (sr & RNG_SR_SEIS) {
187 retval = stm32_rng_conceal_seed_error(pdata);
188 tries++;
189 if (retval || tries > RNG_NB_RECOVER_TRIES) {
190 log_err("%s: Couldn't recover from seed error", __func__);
191 return -ENOTRECOVERABLE;
192 }
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530193
Gatien Chevallier278ed192023-09-19 17:27:57 +0200194 /* Start again */
195 continue;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530196 }
Gatien Chevallier278ed192023-09-19 17:27:57 +0200197
198 if (sr & RNG_SR_CEIS) {
199 log_info("RNG clock too slow");
200 writel_relaxed(0, pdata->base + RNG_SR);
201 }
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530202 }
203
204 /*
205 * Once the DRDY bit is set, the RNG_DR register can
Gatien Chevallier278ed192023-09-19 17:27:57 +0200206 * be read up to four consecutive times.
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530207 */
Gatien Chevallier278ed192023-09-19 17:27:57 +0200208 reg = readl(pdata->base + RNG_DR);
209 /* Late seed error case: DR being 0 is an error status */
210 if (!reg) {
211 retval = stm32_rng_conceal_seed_error(pdata);
212 tries++;
213
214 if (retval || tries > RNG_NB_RECOVER_TRIES) {
215 log_err("%s: Couldn't recover from seed error", __func__);
216 return -ENOTRECOVERABLE;
217 }
218
219 /* Start again */
220 continue;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530221 }
Gatien Chevallier278ed192023-09-19 17:27:57 +0200222
223 increment = min(len, sizeof(u32));
224 memcpy(data, &reg, increment);
225 data += increment;
226 len -= increment;
227
228 tries = 0;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530229 }
230
231 return 0;
232}
233
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +0200234static uint stm32_rng_clock_freq_restrain(struct stm32_rng_plat *pdata)
235{
236 ulong clock_rate = 0;
237 uint clock_div = 0;
238
239 clock_rate = clk_get_rate(&pdata->clk);
240
241 /*
242 * Get the exponent to apply on the CLKDIV field in RNG_CR register.
243 * No need to handle the case when clock-div > 0xF as it is physically
244 * impossible.
245 */
246 while ((clock_rate >> clock_div) > pdata->data->max_clock_rate)
247 clock_div++;
248
249 log_debug("RNG clk rate : %lu\n", clk_get_rate(&pdata->clk) >> clock_div);
250
251 return clock_div;
252}
253
Simon Glassb75b15b2020-12-03 16:55:23 -0700254static int stm32_rng_init(struct stm32_rng_plat *pdata)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530255{
256 int err;
Lionel Debieve71f44212022-06-30 10:20:15 +0200257 u32 cr, sr;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530258
259 err = clk_enable(&pdata->clk);
260 if (err)
261 return err;
262
Lionel Debieve71f44212022-06-30 10:20:15 +0200263 cr = readl(pdata->base + RNG_CR);
264
Gatien Chevallier5e65d462023-09-19 17:27:58 +0200265 /*
266 * Keep default RNG configuration if none was specified, that is when conf.cr is set to 0.
267 */
268 if (pdata->data->has_cond_reset && pdata->data->cr) {
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +0200269 uint clock_div = stm32_rng_clock_freq_restrain(pdata);
270
Gatien Chevallier5e65d462023-09-19 17:27:58 +0200271 cr &= ~RNG_CR_CONFIG_MASK;
272 cr |= RNG_CR_CONDRST | (pdata->data->cr & RNG_CR_ENTROPY_SRC_MASK) |
273 (clock_div << RNG_CR_CLKDIV_SHIFT);
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200274 if (pdata->ced)
275 cr &= ~RNG_CR_CED;
276 else
277 cr |= RNG_CR_CED;
Lionel Debieve71f44212022-06-30 10:20:15 +0200278 writel(cr, pdata->base + RNG_CR);
Gatien Chevallier5e65d462023-09-19 17:27:58 +0200279
280 /* Health tests and noise control registers */
281 writel_relaxed(pdata->data->htcr, pdata->base + RNG_HTCR);
282 writel_relaxed(pdata->data->nscr & RNG_NSCR_MASK, pdata->base + RNG_NSCR);
283
Lionel Debieve71f44212022-06-30 10:20:15 +0200284 cr &= ~RNG_CR_CONDRST;
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200285 cr |= RNG_CR_RNGEN;
Lionel Debieve71f44212022-06-30 10:20:15 +0200286 writel(cr, pdata->base + RNG_CR);
287 err = readl_poll_timeout(pdata->base + RNG_CR, cr,
288 (!(cr & RNG_CR_CONDRST)), 10000);
Gatien Chevallier5e65d462023-09-19 17:27:58 +0200289 if (err) {
290 log_err("%s: Timeout!", __func__);
Lionel Debieve71f44212022-06-30 10:20:15 +0200291 return err;
Gatien Chevallier5e65d462023-09-19 17:27:58 +0200292 }
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200293 } else {
Gatien Chevallier5e65d462023-09-19 17:27:58 +0200294 if (pdata->data->has_cond_reset)
295 cr |= RNG_CR_CONDRST;
296
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200297 if (pdata->ced)
298 cr &= ~RNG_CR_CED;
299 else
300 cr |= RNG_CR_CED;
301
Gatien Chevallier5e65d462023-09-19 17:27:58 +0200302 writel(cr, pdata->base + RNG_CR);
303
304 if (pdata->data->has_cond_reset)
305 cr &= ~RNG_CR_CONDRST;
306
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200307 cr |= RNG_CR_RNGEN;
308
309 writel(cr, pdata->base + RNG_CR);
Lionel Debieve71f44212022-06-30 10:20:15 +0200310 }
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530311
312 /* clear error indicators */
313 writel(0, pdata->base + RNG_SR);
314
Lionel Debieve71f44212022-06-30 10:20:15 +0200315 err = readl_poll_timeout(pdata->base + RNG_SR, sr,
316 sr & RNG_SR_DRDY, 10000);
Gatien Chevallier5e65d462023-09-19 17:27:58 +0200317 if (err)
318 log_err("%s: Timeout!", __func__);
319
Lionel Debieve71f44212022-06-30 10:20:15 +0200320 return err;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530321}
322
Simon Glassb75b15b2020-12-03 16:55:23 -0700323static int stm32_rng_cleanup(struct stm32_rng_plat *pdata)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530324{
325 writel(0, pdata->base + RNG_CR);
326
327 return clk_disable(&pdata->clk);
328}
329
330static int stm32_rng_probe(struct udevice *dev)
331{
Simon Glassb75b15b2020-12-03 16:55:23 -0700332 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530333
Lionel Debieve71f44212022-06-30 10:20:15 +0200334 pdata->data = (struct stm32_rng_data *)dev_get_driver_data(dev);
335
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530336 reset_assert(&pdata->rst);
337 udelay(20);
338 reset_deassert(&pdata->rst);
339
340 return stm32_rng_init(pdata);
341}
342
343static int stm32_rng_remove(struct udevice *dev)
344{
Simon Glassb75b15b2020-12-03 16:55:23 -0700345 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530346
347 return stm32_rng_cleanup(pdata);
348}
349
Simon Glassaad29ae2020-12-03 16:55:21 -0700350static int stm32_rng_of_to_plat(struct udevice *dev)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530351{
Simon Glassb75b15b2020-12-03 16:55:23 -0700352 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530353 int err;
354
355 pdata->base = dev_read_addr(dev);
356 if (!pdata->base)
357 return -ENOMEM;
358
359 err = clk_get_by_index(dev, 0, &pdata->clk);
360 if (err)
361 return err;
362
363 err = reset_get_by_index(dev, 0, &pdata->rst);
364 if (err)
365 return err;
366
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200367 pdata->ced = dev_read_bool(dev, "clock-error-detect");
368
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530369 return 0;
370}
371
372static const struct dm_rng_ops stm32_rng_ops = {
373 .read = stm32_rng_read,
374};
375
Lionel Debieve71f44212022-06-30 10:20:15 +0200376static const struct stm32_rng_data stm32mp13_rng_data = {
377 .has_cond_reset = true,
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +0200378 .max_clock_rate = 48000000,
Gatien Chevallier5e65d462023-09-19 17:27:58 +0200379 .htcr = 0x969D,
380 .nscr = 0x2B5BB,
381 .cr = 0xF00D00,
Lionel Debieve71f44212022-06-30 10:20:15 +0200382};
383
384static const struct stm32_rng_data stm32_rng_data = {
385 .has_cond_reset = false,
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +0200386 .max_clock_rate = 3000000,
Gatien Chevallier5e65d462023-09-19 17:27:58 +0200387 /* Not supported */
388 .htcr = 0,
389 .nscr = 0,
390 .cr = 0,
Lionel Debieve71f44212022-06-30 10:20:15 +0200391};
392
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530393static const struct udevice_id stm32_rng_match[] = {
Lionel Debieve71f44212022-06-30 10:20:15 +0200394 {.compatible = "st,stm32mp13-rng", .data = (ulong)&stm32mp13_rng_data},
395 {.compatible = "st,stm32-rng", .data = (ulong)&stm32_rng_data},
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530396 {},
397};
398
399U_BOOT_DRIVER(stm32_rng) = {
400 .name = "stm32-rng",
401 .id = UCLASS_RNG,
402 .of_match = stm32_rng_match,
403 .ops = &stm32_rng_ops,
404 .probe = stm32_rng_probe,
405 .remove = stm32_rng_remove,
Simon Glassb75b15b2020-12-03 16:55:23 -0700406 .plat_auto = sizeof(struct stm32_rng_plat),
Simon Glassaad29ae2020-12-03 16:55:21 -0700407 .of_to_plat = stm32_rng_of_to_plat,
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530408};