blob: b1a790b217f761934ee8af28903872f117cad408 [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)
24#define RNG_CR_CLKDIV_SHIFT 16
25#define RNG_CR_CONDRST BIT(30)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053026
Lionel Debieve71f44212022-06-30 10:20:15 +020027#define RNG_SR 0x04
28#define RNG_SR_SEIS BIT(6)
29#define RNG_SR_CEIS BIT(5)
30#define RNG_SR_SECS BIT(2)
31#define RNG_SR_DRDY BIT(0)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053032
Lionel Debieve71f44212022-06-30 10:20:15 +020033#define RNG_DR 0x08
34
Gatien Chevallier278ed192023-09-19 17:27:57 +020035#define RNG_NB_RECOVER_TRIES 3
36
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +020037/*
38 * struct stm32_rng_data - RNG compat data
39 *
40 * @max_clock_rate: Max RNG clock frequency, in Hertz
41 * @has_cond_reset: True if conditionnal reset is supported
42 *
43 */
Lionel Debieve71f44212022-06-30 10:20:15 +020044struct stm32_rng_data {
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +020045 uint max_clock_rate;
Lionel Debieve71f44212022-06-30 10:20:15 +020046 bool has_cond_reset;
47};
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053048
Simon Glassb75b15b2020-12-03 16:55:23 -070049struct stm32_rng_plat {
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053050 fdt_addr_t base;
51 struct clk clk;
52 struct reset_ctl rst;
Lionel Debieve71f44212022-06-30 10:20:15 +020053 const struct stm32_rng_data *data;
Gatien Chevalliere2acc952023-09-19 17:27:55 +020054 bool ced;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053055};
56
Gatien Chevallier278ed192023-09-19 17:27:57 +020057/*
58 * Extracts from the STM32 RNG specification when RNG supports CONDRST.
59 *
60 * When a noise source (or seed) error occurs, the RNG stops generating
61 * random numbers and sets to “1” both SEIS and SECS bits to indicate
62 * that a seed error occurred. (...)
63 *
64 * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield
65 * description for details). This step is needed only if SECS is set.
66 * Indeed, when SEIS is set and SECS is cleared it means RNG performed
67 * the reset automatically (auto-reset).
68 * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST
69 * to be cleared in the RNG_CR register, then confirm that SEIS is
70 * cleared in the RNG_SR register. Otherwise just clear SEIS bit in
71 * the RNG_SR register.
72 * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be
73 * cleared by RNG. The random number generation is now back to normal.
74 */
75static int stm32_rng_conceal_seed_error_cond_reset(struct stm32_rng_plat *pdata)
76{
77 u32 sr = readl_relaxed(pdata->base + RNG_SR);
78 u32 cr = readl_relaxed(pdata->base + RNG_CR);
79 int err;
80
81 if (sr & RNG_SR_SECS) {
82 /* Conceal by resetting the subsystem (step 1.) */
83 writel_relaxed(cr | RNG_CR_CONDRST, pdata->base + RNG_CR);
84 writel_relaxed(cr & ~RNG_CR_CONDRST, pdata->base + RNG_CR);
85 } else {
86 /* RNG auto-reset (step 2.) */
87 writel_relaxed(sr & ~RNG_SR_SEIS, pdata->base + RNG_SR);
88 return 0;
89 }
90
91 err = readl_relaxed_poll_timeout(pdata->base + RNG_SR, sr, !(sr & RNG_CR_CONDRST), 100000);
92 if (err) {
93 log_err("%s: timeout %x\n", __func__, sr);
94 return err;
95 }
96
97 /* Check SEIS is cleared (step 2.) */
98 if (readl_relaxed(pdata->base + RNG_SR) & RNG_SR_SEIS)
99 return -EINVAL;
100
101 err = readl_relaxed_poll_timeout(pdata->base + RNG_SR, sr, !(sr & RNG_SR_SECS), 100000);
102 if (err) {
103 log_err("%s: timeout %x\n", __func__, sr);
104 return err;
105 }
106
107 return 0;
108}
109
110/*
111 * Extracts from the STM32 RNG specification, when CONDRST is not supported
112 *
113 * When a noise source (or seed) error occurs, the RNG stops generating
114 * random numbers and sets to “1” both SEIS and SECS bits to indicate
115 * that a seed error occurred. (...)
116 *
117 * The following sequence shall be used to fully recover from a seed
118 * error after the RNG initialization:
119 * 1. Clear the SEIS bit by writing it to “0”.
120 * 2. Read out 12 words from the RNG_DR register, and discard each of
121 * them in order to clean the pipeline.
122 * 3. Confirm that SEIS is still cleared. Random number generation is
123 * back to normal.
124 */
125static int stm32_rng_conceal_seed_error_sw_reset(struct stm32_rng_plat *pdata)
126{
127 uint i = 0;
128 u32 sr = readl_relaxed(pdata->base + RNG_SR);
129
130 writel_relaxed(sr & ~RNG_SR_SEIS, pdata->base + RNG_SR);
131
132 for (i = 12; i != 0; i--)
133 (void)readl_relaxed(pdata->base + RNG_DR);
134
135 if (readl_relaxed(pdata->base + RNG_SR) & RNG_SR_SEIS)
136 return -EINVAL;
137
138 return 0;
139}
140
141static int stm32_rng_conceal_seed_error(struct stm32_rng_plat *pdata)
142{
143 log_debug("Concealing RNG seed error\n");
144
145 if (pdata->data->has_cond_reset)
146 return stm32_rng_conceal_seed_error_cond_reset(pdata);
147 else
148 return stm32_rng_conceal_seed_error_sw_reset(pdata);
149};
150
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530151static int stm32_rng_read(struct udevice *dev, void *data, size_t len)
152{
Gatien Chevallier278ed192023-09-19 17:27:57 +0200153 int retval;
154 u32 sr, reg;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530155 size_t increment;
Simon Glassb75b15b2020-12-03 16:55:23 -0700156 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Gatien Chevallier278ed192023-09-19 17:27:57 +0200157 uint tries = 0;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530158
159 while (len > 0) {
160 retval = readl_poll_timeout(pdata->base + RNG_SR, sr,
Gatien Chevallier278ed192023-09-19 17:27:57 +0200161 sr, 10000);
162 if (retval) {
163 log_err("%s: Timeout RNG no data", __func__);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530164 return retval;
Gatien Chevallier278ed192023-09-19 17:27:57 +0200165 }
166
167 if (sr != RNG_SR_DRDY) {
168 if (sr & RNG_SR_SEIS) {
169 retval = stm32_rng_conceal_seed_error(pdata);
170 tries++;
171 if (retval || tries > RNG_NB_RECOVER_TRIES) {
172 log_err("%s: Couldn't recover from seed error", __func__);
173 return -ENOTRECOVERABLE;
174 }
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530175
Gatien Chevallier278ed192023-09-19 17:27:57 +0200176 /* Start again */
177 continue;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530178 }
Gatien Chevallier278ed192023-09-19 17:27:57 +0200179
180 if (sr & RNG_SR_CEIS) {
181 log_info("RNG clock too slow");
182 writel_relaxed(0, pdata->base + RNG_SR);
183 }
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530184 }
185
186 /*
187 * Once the DRDY bit is set, the RNG_DR register can
Gatien Chevallier278ed192023-09-19 17:27:57 +0200188 * be read up to four consecutive times.
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530189 */
Gatien Chevallier278ed192023-09-19 17:27:57 +0200190 reg = readl(pdata->base + RNG_DR);
191 /* Late seed error case: DR being 0 is an error status */
192 if (!reg) {
193 retval = stm32_rng_conceal_seed_error(pdata);
194 tries++;
195
196 if (retval || tries > RNG_NB_RECOVER_TRIES) {
197 log_err("%s: Couldn't recover from seed error", __func__);
198 return -ENOTRECOVERABLE;
199 }
200
201 /* Start again */
202 continue;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530203 }
Gatien Chevallier278ed192023-09-19 17:27:57 +0200204
205 increment = min(len, sizeof(u32));
206 memcpy(data, &reg, increment);
207 data += increment;
208 len -= increment;
209
210 tries = 0;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530211 }
212
213 return 0;
214}
215
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +0200216static uint stm32_rng_clock_freq_restrain(struct stm32_rng_plat *pdata)
217{
218 ulong clock_rate = 0;
219 uint clock_div = 0;
220
221 clock_rate = clk_get_rate(&pdata->clk);
222
223 /*
224 * Get the exponent to apply on the CLKDIV field in RNG_CR register.
225 * No need to handle the case when clock-div > 0xF as it is physically
226 * impossible.
227 */
228 while ((clock_rate >> clock_div) > pdata->data->max_clock_rate)
229 clock_div++;
230
231 log_debug("RNG clk rate : %lu\n", clk_get_rate(&pdata->clk) >> clock_div);
232
233 return clock_div;
234}
235
Simon Glassb75b15b2020-12-03 16:55:23 -0700236static int stm32_rng_init(struct stm32_rng_plat *pdata)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530237{
238 int err;
Lionel Debieve71f44212022-06-30 10:20:15 +0200239 u32 cr, sr;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530240
241 err = clk_enable(&pdata->clk);
242 if (err)
243 return err;
244
Lionel Debieve71f44212022-06-30 10:20:15 +0200245 cr = readl(pdata->base + RNG_CR);
246
Lionel Debieve71f44212022-06-30 10:20:15 +0200247 if (pdata->data->has_cond_reset) {
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +0200248 uint clock_div = stm32_rng_clock_freq_restrain(pdata);
249
250 cr |= RNG_CR_CONDRST | (clock_div << RNG_CR_CLKDIV_SHIFT);
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200251 if (pdata->ced)
252 cr &= ~RNG_CR_CED;
253 else
254 cr |= RNG_CR_CED;
Lionel Debieve71f44212022-06-30 10:20:15 +0200255 writel(cr, pdata->base + RNG_CR);
256 cr &= ~RNG_CR_CONDRST;
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200257 cr |= RNG_CR_RNGEN;
Lionel Debieve71f44212022-06-30 10:20:15 +0200258 writel(cr, pdata->base + RNG_CR);
259 err = readl_poll_timeout(pdata->base + RNG_CR, cr,
260 (!(cr & RNG_CR_CONDRST)), 10000);
261 if (err)
262 return err;
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200263 } else {
264 if (pdata->ced)
265 cr &= ~RNG_CR_CED;
266 else
267 cr |= RNG_CR_CED;
268
269 cr |= RNG_CR_RNGEN;
270
271 writel(cr, pdata->base + RNG_CR);
Lionel Debieve71f44212022-06-30 10:20:15 +0200272 }
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530273
274 /* clear error indicators */
275 writel(0, pdata->base + RNG_SR);
276
Lionel Debieve71f44212022-06-30 10:20:15 +0200277 err = readl_poll_timeout(pdata->base + RNG_SR, sr,
278 sr & RNG_SR_DRDY, 10000);
279 return err;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530280}
281
Simon Glassb75b15b2020-12-03 16:55:23 -0700282static int stm32_rng_cleanup(struct stm32_rng_plat *pdata)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530283{
284 writel(0, pdata->base + RNG_CR);
285
286 return clk_disable(&pdata->clk);
287}
288
289static int stm32_rng_probe(struct udevice *dev)
290{
Simon Glassb75b15b2020-12-03 16:55:23 -0700291 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530292
Lionel Debieve71f44212022-06-30 10:20:15 +0200293 pdata->data = (struct stm32_rng_data *)dev_get_driver_data(dev);
294
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530295 reset_assert(&pdata->rst);
296 udelay(20);
297 reset_deassert(&pdata->rst);
298
299 return stm32_rng_init(pdata);
300}
301
302static int stm32_rng_remove(struct udevice *dev)
303{
Simon Glassb75b15b2020-12-03 16:55:23 -0700304 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530305
306 return stm32_rng_cleanup(pdata);
307}
308
Simon Glassaad29ae2020-12-03 16:55:21 -0700309static int stm32_rng_of_to_plat(struct udevice *dev)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530310{
Simon Glassb75b15b2020-12-03 16:55:23 -0700311 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530312 int err;
313
314 pdata->base = dev_read_addr(dev);
315 if (!pdata->base)
316 return -ENOMEM;
317
318 err = clk_get_by_index(dev, 0, &pdata->clk);
319 if (err)
320 return err;
321
322 err = reset_get_by_index(dev, 0, &pdata->rst);
323 if (err)
324 return err;
325
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200326 pdata->ced = dev_read_bool(dev, "clock-error-detect");
327
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530328 return 0;
329}
330
331static const struct dm_rng_ops stm32_rng_ops = {
332 .read = stm32_rng_read,
333};
334
Lionel Debieve71f44212022-06-30 10:20:15 +0200335static const struct stm32_rng_data stm32mp13_rng_data = {
336 .has_cond_reset = true,
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +0200337 .max_clock_rate = 48000000,
Lionel Debieve71f44212022-06-30 10:20:15 +0200338};
339
340static const struct stm32_rng_data stm32_rng_data = {
341 .has_cond_reset = false,
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +0200342 .max_clock_rate = 3000000,
Lionel Debieve71f44212022-06-30 10:20:15 +0200343};
344
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530345static const struct udevice_id stm32_rng_match[] = {
Lionel Debieve71f44212022-06-30 10:20:15 +0200346 {.compatible = "st,stm32mp13-rng", .data = (ulong)&stm32mp13_rng_data},
347 {.compatible = "st,stm32-rng", .data = (ulong)&stm32_rng_data},
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530348 {},
349};
350
351U_BOOT_DRIVER(stm32_rng) = {
352 .name = "stm32-rng",
353 .id = UCLASS_RNG,
354 .of_match = stm32_rng_match,
355 .ops = &stm32_rng_ops,
356 .probe = stm32_rng_probe,
357 .remove = stm32_rng_remove,
Simon Glassb75b15b2020-12-03 16:55:23 -0700358 .plat_auto = sizeof(struct stm32_rng_plat),
Simon Glassaad29ae2020-12-03 16:55:21 -0700359 .of_to_plat = stm32_rng_of_to_plat,
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530360};