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