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