1 /*
2 * Copyright (c) 2022, 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 <drivers/clk.h>
13 #include <drivers/delay_timer.h>
14 #include <drivers/st/stm32_rng.h>
15 #include <drivers/st/stm32mp_reset.h>
16 #include <lib/mmio.h>
17 #include <libfdt.h>
18
19 #include <platform_def.h>
20
21 #if STM32_RNG_VER == 2
22 #define DT_RNG_COMPAT "st,stm32-rng"
23 #endif
24 #if STM32_RNG_VER == 4
25 #define DT_RNG_COMPAT "st,stm32mp13-rng"
26 #endif
27 #define RNG_CR 0x00U
28 #define RNG_SR 0x04U
29 #define RNG_DR 0x08U
30
31 #define RNG_CR_RNGEN BIT(2)
32 #define RNG_CR_IE BIT(3)
33 #define RNG_CR_CED BIT(5)
34 #define RNG_CR_CLKDIV GENMASK(19, 16)
35 #define RNG_CR_CLKDIV_SHIFT 16U
36 #define RNG_CR_CONDRST BIT(30)
37
38 #define RNG_SR_DRDY BIT(0)
39 #define RNG_SR_CECS BIT(1)
40 #define RNG_SR_SECS BIT(2)
41 #define RNG_SR_CEIS BIT(5)
42 #define RNG_SR_SEIS BIT(6)
43
44 #define RNG_TIMEOUT_US 100000U
45 #define RNG_TIMEOUT_STEP_US 10U
46
47 #define TIMEOUT_US_1MS 1000U
48
49 #define RNG_NIST_CONFIG_A 0x00F40F00U
50 #define RNG_NIST_CONFIG_B 0x01801000U
51 #define RNG_NIST_CONFIG_C 0x00F00D00U
52 #define RNG_NIST_CONFIG_MASK GENMASK(25, 8)
53
54 #define RNG_MAX_NOISE_CLK_FREQ 48000000U
55
56 struct stm32_rng_instance {
57 uintptr_t base;
58 unsigned long clock;
59 };
60
61 static struct stm32_rng_instance stm32_rng;
62
seed_error_recovery(void)63 static void seed_error_recovery(void)
64 {
65 uint8_t i __maybe_unused;
66
67 /* Recommended by the SoC reference manual */
68 mmio_clrbits_32(stm32_rng.base + RNG_SR, RNG_SR_SEIS);
69 dmbsy();
70
71 #if STM32_RNG_VER == 2
72 /* No Auto-reset on version 2, need to clean FIFO */
73 for (i = 12U; i != 0U; i--) {
74 (void)mmio_read_32(stm32_rng.base + RNG_DR);
75 }
76
77 dmbsy();
78 #endif
79
80 if ((mmio_read_32(stm32_rng.base + RNG_SR) & RNG_SR_SEIS) != 0U) {
81 ERROR("RNG noise\n");
82 panic();
83 }
84 }
85
stm32_rng_clock_freq_restrain(void)86 static uint32_t stm32_rng_clock_freq_restrain(void)
87 {
88 unsigned long clock_rate;
89 uint32_t clock_div = 0U;
90
91 clock_rate = clk_get_rate(stm32_rng.clock);
92
93 /*
94 * Get the exponent to apply on the CLKDIV field in RNG_CR register
95 * No need to handle the case when clock-div > 0xF as it is physically
96 * impossible
97 */
98 while ((clock_rate >> clock_div) > RNG_MAX_NOISE_CLK_FREQ) {
99 clock_div++;
100 }
101
102 VERBOSE("RNG clk rate : %lu\n", clk_get_rate(stm32_rng.clock) >> clock_div);
103
104 return clock_div;
105 }
106
stm32_rng_enable(void)107 static int stm32_rng_enable(void)
108 {
109 uint32_t sr;
110 uint64_t timeout;
111 uint32_t clock_div __maybe_unused;
112
113 #if STM32_RNG_VER == 2
114 mmio_write_32(stm32_rng.base + RNG_CR, RNG_CR_RNGEN | RNG_CR_CED);
115 #endif
116 #if STM32_RNG_VER == 4
117 /* Reset internal block and disable CED bit */
118 clock_div = stm32_rng_clock_freq_restrain();
119
120 /* Update configuration fields */
121 mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_NIST_CONFIG_MASK,
122 RNG_NIST_CONFIG_A | RNG_CR_CONDRST | RNG_CR_CED);
123
124 mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_CR_CLKDIV,
125 (clock_div << RNG_CR_CLKDIV_SHIFT));
126
127 mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_CR_CONDRST, RNG_CR_RNGEN);
128 #endif
129 timeout = timeout_init_us(RNG_TIMEOUT_US);
130 sr = mmio_read_32(stm32_rng.base + RNG_SR);
131 while ((sr & RNG_SR_DRDY) == 0U) {
132 if (timeout_elapsed(timeout)) {
133 WARN("Timeout waiting\n");
134 return -ETIMEDOUT;
135 }
136
137 if ((sr & (RNG_SR_SECS | RNG_SR_SEIS)) != 0U) {
138 seed_error_recovery();
139 timeout = timeout_init_us(RNG_TIMEOUT_US);
140 }
141
142 udelay(RNG_TIMEOUT_STEP_US);
143 sr = mmio_read_32(stm32_rng.base + RNG_SR);
144 }
145
146 VERBOSE("Init RNG done\n");
147
148 return 0;
149 }
150
151 /*
152 * stm32_rng_read - Read a number of random bytes from RNG
153 * out: pointer to the output buffer
154 * size: number of bytes to be read
155 * Return 0 on success, non-0 on failure
156 */
stm32_rng_read(uint8_t * out,uint32_t size)157 int stm32_rng_read(uint8_t *out, uint32_t size)
158 {
159 uint8_t *buf = out;
160 size_t len = size;
161 int nb_tries;
162 uint32_t data32;
163 int rc = 0;
164 unsigned int count;
165
166 if (stm32_rng.base == 0U) {
167 return -EPERM;
168 }
169
170 while (len != 0U) {
171 nb_tries = RNG_TIMEOUT_US / RNG_TIMEOUT_STEP_US;
172 do {
173 uint32_t status = mmio_read_32(stm32_rng.base + RNG_SR);
174
175 if ((status & (RNG_SR_SECS | RNG_SR_SEIS)) != 0U) {
176 seed_error_recovery();
177 }
178
179 udelay(RNG_TIMEOUT_STEP_US);
180 nb_tries--;
181 if (nb_tries == 0) {
182 rc = -ETIMEDOUT;
183 goto bail;
184 }
185 } while ((mmio_read_32(stm32_rng.base + RNG_SR) &
186 RNG_SR_DRDY) == 0U);
187
188 count = 4U;
189 while (len != 0U) {
190 data32 = mmio_read_32(stm32_rng.base + RNG_DR);
191 count--;
192
193 memcpy(buf, &data32, MIN(len, sizeof(uint32_t)));
194 buf += MIN(len, sizeof(uint32_t));
195 len -= MIN(len, sizeof(uint32_t));
196
197 if (count == 0U) {
198 break;
199 }
200 }
201 }
202
203 bail:
204 if (rc != 0) {
205 memset(out, 0, buf - out);
206 }
207
208 return rc;
209 }
210
211 /*
212 * stm32_rng_init: Initialize rng from DT
213 * return 0 on success, negative value on failure
214 */
stm32_rng_init(void)215 int stm32_rng_init(void)
216 {
217 void *fdt;
218 struct dt_node_info dt_rng;
219 int node;
220
221 if (stm32_rng.base != 0U) {
222 /* Driver is already initialized */
223 return 0;
224 }
225
226 if (fdt_get_address(&fdt) == 0) {
227 panic();
228 }
229
230 node = dt_get_node(&dt_rng, -1, DT_RNG_COMPAT);
231 if (node < 0) {
232 return 0;
233 }
234
235 if (dt_rng.status == DT_DISABLED) {
236 return 0;
237 }
238
239 assert(dt_rng.base != 0U);
240
241 stm32_rng.base = dt_rng.base;
242
243 if (dt_rng.clock < 0) {
244 panic();
245 }
246
247 stm32_rng.clock = (unsigned long)dt_rng.clock;
248 clk_enable(stm32_rng.clock);
249
250 if (dt_rng.reset >= 0) {
251 int ret;
252
253 ret = stm32mp_reset_assert((unsigned long)dt_rng.reset,
254 TIMEOUT_US_1MS);
255 if (ret != 0) {
256 panic();
257 }
258
259 udelay(20);
260
261 ret = stm32mp_reset_deassert((unsigned long)dt_rng.reset,
262 TIMEOUT_US_1MS);
263 if (ret != 0) {
264 panic();
265 }
266 }
267
268 return stm32_rng_enable();
269 }
270