xref: /arm-trusted-firmware/drivers/nxp/crypto/caam/src/rng.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright 2021 NXP
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  *
6*91f16700Schasinglulu  */
7*91f16700Schasinglulu 
8*91f16700Schasinglulu #include <stdbool.h>
9*91f16700Schasinglulu #include <stdint.h>
10*91f16700Schasinglulu #include <stdio.h>
11*91f16700Schasinglulu #include <stdlib.h>
12*91f16700Schasinglulu 
13*91f16700Schasinglulu #include <arch_helpers.h>
14*91f16700Schasinglulu #include "caam.h"
15*91f16700Schasinglulu #include <common/debug.h>
16*91f16700Schasinglulu #include "jobdesc.h"
17*91f16700Schasinglulu #include "sec_hw_specific.h"
18*91f16700Schasinglulu 
19*91f16700Schasinglulu 
20*91f16700Schasinglulu /* Callback function after Instantiation descriptor is submitted to SEC */
21*91f16700Schasinglulu static void rng_done(uint32_t *desc, uint32_t status, void *arg,
22*91f16700Schasinglulu 		     void *job_ring)
23*91f16700Schasinglulu {
24*91f16700Schasinglulu 	INFO("RNG Desc SUCCESS with status %x\n", status);
25*91f16700Schasinglulu }
26*91f16700Schasinglulu 
27*91f16700Schasinglulu /* Is the HW RNG instantiated?
28*91f16700Schasinglulu  * Return code:
29*91f16700Schasinglulu  * 0 - Not in the instantiated state
30*91f16700Schasinglulu  * 1 - In the instantiated state
31*91f16700Schasinglulu  * state_handle - 0 for SH0, 1 for SH1
32*91f16700Schasinglulu  */
33*91f16700Schasinglulu static int is_hw_rng_instantiated(uint32_t *state_handle)
34*91f16700Schasinglulu {
35*91f16700Schasinglulu 	int ret_code = 0;
36*91f16700Schasinglulu 	uint32_t rdsta;
37*91f16700Schasinglulu 
38*91f16700Schasinglulu 	rdsta = sec_in32(get_caam_addr() + RNG_REG_RDSTA_OFFSET);
39*91f16700Schasinglulu 
40*91f16700Schasinglulu 	 /*Check if either of the two state handles has been instantiated */
41*91f16700Schasinglulu 	if (rdsta & RNG_STATE0_HANDLE_INSTANTIATED) {
42*91f16700Schasinglulu 		*state_handle = 0;
43*91f16700Schasinglulu 		ret_code = 1;
44*91f16700Schasinglulu 	} else if (rdsta & RNG_STATE0_HANDLE_INSTANTIATED) {
45*91f16700Schasinglulu 		*state_handle = 1;
46*91f16700Schasinglulu 		ret_code = 1;
47*91f16700Schasinglulu 	}
48*91f16700Schasinglulu 
49*91f16700Schasinglulu 	return ret_code;
50*91f16700Schasinglulu }
51*91f16700Schasinglulu 
52*91f16700Schasinglulu /* @brief Kick the TRNG block of the RNG HW Engine
53*91f16700Schasinglulu  * @param [in] ent_delay       Entropy delay to be used
54*91f16700Schasinglulu  *        By default, the TRNG runs for 200 clocks per sample;
55*91f16700Schasinglulu  *        1200 clocks per sample generates better entropy.
56*91f16700Schasinglulu  * @retval 0 on success
57*91f16700Schasinglulu  * @retval -1 on error
58*91f16700Schasinglulu  */
59*91f16700Schasinglulu static void kick_trng(int ent_delay)
60*91f16700Schasinglulu {
61*91f16700Schasinglulu 	uint32_t val;
62*91f16700Schasinglulu 
63*91f16700Schasinglulu 	/* put RNG4 into program mode */
64*91f16700Schasinglulu 	val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET);
65*91f16700Schasinglulu 	val = val | RTMCTL_PRGM;
66*91f16700Schasinglulu 	sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val);
67*91f16700Schasinglulu 
68*91f16700Schasinglulu 	/* rtsdctl bits 0-15 contain "Entropy Delay, which defines the
69*91f16700Schasinglulu 	 *  length (in system clocks) of each Entropy sample taken
70*91f16700Schasinglulu 	 */
71*91f16700Schasinglulu 	val = sec_in32(get_caam_addr() + RNG_REG_RTSDCTL_OFFSET);
72*91f16700Schasinglulu 	val = (val & ~RTSDCTL_ENT_DLY_MASK) |
73*91f16700Schasinglulu 	    (ent_delay << RTSDCTL_ENT_DLY_SHIFT);
74*91f16700Schasinglulu 	sec_out32(get_caam_addr() + RNG_REG_RTSDCTL_OFFSET, val);
75*91f16700Schasinglulu 	/* min. freq. count, equal to 1/4 of the entropy sample length */
76*91f16700Schasinglulu 	sec_out32(get_caam_addr() + RNG_REG_RTFRQMIN_OFFSET, ent_delay >> 2);
77*91f16700Schasinglulu 	/* disable maximum frequency count */
78*91f16700Schasinglulu 	sec_out32(get_caam_addr() + RNG_REG_RTFRQMAX_OFFSET, RTFRQMAX_DISABLE);
79*91f16700Schasinglulu 
80*91f16700Schasinglulu 	/* select raw sampling in both entropy shifter
81*91f16700Schasinglulu 	 *  and statistical checker
82*91f16700Schasinglulu 	 */
83*91f16700Schasinglulu 	val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET);
84*91f16700Schasinglulu 	val = val | RTMCTL_SAMP_MODE_RAW_ES_SC;
85*91f16700Schasinglulu 	sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val);
86*91f16700Schasinglulu 
87*91f16700Schasinglulu 	/* put RNG4 into run mode */
88*91f16700Schasinglulu 	val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET);
89*91f16700Schasinglulu 	val = val & ~RTMCTL_PRGM;
90*91f16700Schasinglulu 	sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val);
91*91f16700Schasinglulu }
92*91f16700Schasinglulu 
93*91f16700Schasinglulu /* @brief Submit descriptor to instantiate the RNG
94*91f16700Schasinglulu  * @retval 0 on success
95*91f16700Schasinglulu  * @retval -1 on error
96*91f16700Schasinglulu  */
97*91f16700Schasinglulu static int instantiate_rng(void)
98*91f16700Schasinglulu {
99*91f16700Schasinglulu 	int ret = 0;
100*91f16700Schasinglulu 	struct job_descriptor desc __aligned(CACHE_WRITEBACK_GRANULE);
101*91f16700Schasinglulu 	struct job_descriptor *jobdesc = &desc;
102*91f16700Schasinglulu 
103*91f16700Schasinglulu 	jobdesc->arg = NULL;
104*91f16700Schasinglulu 	jobdesc->callback = rng_done;
105*91f16700Schasinglulu 
106*91f16700Schasinglulu 	/* create the hw_rng descriptor */
107*91f16700Schasinglulu 	cnstr_rng_instantiate_jobdesc(jobdesc->desc);
108*91f16700Schasinglulu 
109*91f16700Schasinglulu 	/* Finally, generate the requested random data bytes */
110*91f16700Schasinglulu 	ret = run_descriptor_jr(jobdesc);
111*91f16700Schasinglulu 	if (ret != 0) {
112*91f16700Schasinglulu 		ERROR("Error in running descriptor\n");
113*91f16700Schasinglulu 		ret = -1;
114*91f16700Schasinglulu 	}
115*91f16700Schasinglulu 	return ret;
116*91f16700Schasinglulu }
117*91f16700Schasinglulu 
118*91f16700Schasinglulu /* Generate Random Data using HW RNG
119*91f16700Schasinglulu  * Parameters:
120*91f16700Schasinglulu  * uint8_t* add_input   - user specified optional input byte array
121*91f16700Schasinglulu  * uint32_t add_input_len - number of bytes of additional input
122*91f16700Schasinglulu  * uint8_t* out                   - user specified output byte array
123*91f16700Schasinglulu  * uint32_t out_len       - number of bytes to store in output byte array
124*91f16700Schasinglulu  * Return code:
125*91f16700Schasinglulu  * 0 - SUCCESS
126*91f16700Schasinglulu  * -1 - ERROR
127*91f16700Schasinglulu  */
128*91f16700Schasinglulu static int
129*91f16700Schasinglulu hw_rng_generate(uint32_t *add_input, uint32_t add_input_len,
130*91f16700Schasinglulu 		uint8_t *out, uint32_t out_len, uint32_t state_handle)
131*91f16700Schasinglulu {
132*91f16700Schasinglulu 	int ret = 0;
133*91f16700Schasinglulu 	struct job_descriptor desc __aligned(CACHE_WRITEBACK_GRANULE);
134*91f16700Schasinglulu 	struct job_descriptor *jobdesc = &desc;
135*91f16700Schasinglulu 
136*91f16700Schasinglulu 	jobdesc->arg = NULL;
137*91f16700Schasinglulu 	jobdesc->callback = rng_done;
138*91f16700Schasinglulu 
139*91f16700Schasinglulu #if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
140*91f16700Schasinglulu 	inv_dcache_range((uintptr_t)out, out_len);
141*91f16700Schasinglulu 	dmbsy();
142*91f16700Schasinglulu #endif
143*91f16700Schasinglulu 
144*91f16700Schasinglulu 	/* create the hw_rng descriptor */
145*91f16700Schasinglulu 	ret = cnstr_rng_jobdesc(jobdesc->desc, state_handle,
146*91f16700Schasinglulu 				add_input, add_input_len, out, out_len);
147*91f16700Schasinglulu 	if (ret != 0) {
148*91f16700Schasinglulu 		ERROR("Descriptor construction failed\n");
149*91f16700Schasinglulu 		ret = -1;
150*91f16700Schasinglulu 		goto out;
151*91f16700Schasinglulu 	}
152*91f16700Schasinglulu 	/* Finally, generate the requested random data bytes */
153*91f16700Schasinglulu 	ret = run_descriptor_jr(jobdesc);
154*91f16700Schasinglulu 	if (ret != 0) {
155*91f16700Schasinglulu 		ERROR("Error in running descriptor\n");
156*91f16700Schasinglulu 		ret = -1;
157*91f16700Schasinglulu 	}
158*91f16700Schasinglulu 
159*91f16700Schasinglulu out:
160*91f16700Schasinglulu 	return ret;
161*91f16700Schasinglulu }
162*91f16700Schasinglulu 
163*91f16700Schasinglulu /* this function instantiates the rng
164*91f16700Schasinglulu  *
165*91f16700Schasinglulu  * Return code:
166*91f16700Schasinglulu  *  0 - All is well
167*91f16700Schasinglulu  * <0 - Error occurred somewhere
168*91f16700Schasinglulu  */
169*91f16700Schasinglulu int hw_rng_instantiate(void)
170*91f16700Schasinglulu {
171*91f16700Schasinglulu 	int ret = 0;
172*91f16700Schasinglulu 	int ent_delay = RTSDCTL_ENT_DLY_MIN;
173*91f16700Schasinglulu 	uint32_t state_handle;
174*91f16700Schasinglulu 
175*91f16700Schasinglulu 	ret = is_hw_rng_instantiated(&state_handle);
176*91f16700Schasinglulu 	if (ret != 0) {
177*91f16700Schasinglulu 		NOTICE("RNG already instantiated\n");
178*91f16700Schasinglulu 		return 0;
179*91f16700Schasinglulu 	}
180*91f16700Schasinglulu 	do {
181*91f16700Schasinglulu 		kick_trng(ent_delay);
182*91f16700Schasinglulu 		ent_delay += 400;
183*91f16700Schasinglulu 		/*if instantiate_rng(...) fails, the loop will rerun
184*91f16700Schasinglulu 		 *and the kick_trng(...) function will modify the
185*91f16700Schasinglulu 		 *upper and lower limits of the entropy sampling
186*91f16700Schasinglulu 		 *interval, leading to a successful initialization of
187*91f16700Schasinglulu 		 */
188*91f16700Schasinglulu 		ret = instantiate_rng();
189*91f16700Schasinglulu 	} while ((ret == -1) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
190*91f16700Schasinglulu 	if (ret != 0) {
191*91f16700Schasinglulu 		ERROR("RNG: Failed to instantiate RNG\n");
192*91f16700Schasinglulu 		return ret;
193*91f16700Schasinglulu 	}
194*91f16700Schasinglulu 
195*91f16700Schasinglulu 	NOTICE("RNG: INSTANTIATED\n");
196*91f16700Schasinglulu 
197*91f16700Schasinglulu 	/* Enable RDB bit so that RNG works faster */
198*91f16700Schasinglulu 	// sec_setbits32(&sec->scfgr, SEC_SCFGR_RDBENABLE);
199*91f16700Schasinglulu 
200*91f16700Schasinglulu 	return ret;
201*91f16700Schasinglulu }
202*91f16700Schasinglulu 
203*91f16700Schasinglulu /* Generate random bytes, and stuff them into the bytes buffer
204*91f16700Schasinglulu  *
205*91f16700Schasinglulu  * If the HW RNG has not already been instantiated,
206*91f16700Schasinglulu  *  it will be instantiated before data is generated.
207*91f16700Schasinglulu  *
208*91f16700Schasinglulu  * Parameters:
209*91f16700Schasinglulu  * uint8_t* bytes  - byte buffer large enough to hold the requested random date
210*91f16700Schasinglulu  * int byte_len - number of random bytes to generate
211*91f16700Schasinglulu  *
212*91f16700Schasinglulu  * Return code:
213*91f16700Schasinglulu  *  0 - All is well
214*91f16700Schasinglulu  *  ~0 - Error occurred somewhere
215*91f16700Schasinglulu  */
216*91f16700Schasinglulu int get_rand_bytes_hw(uint8_t *bytes, int byte_len)
217*91f16700Schasinglulu {
218*91f16700Schasinglulu 	int ret_code = 0;
219*91f16700Schasinglulu 	uint32_t state_handle;
220*91f16700Schasinglulu 
221*91f16700Schasinglulu 	/* If this is the first time this routine is called,
222*91f16700Schasinglulu 	 *  then the hash_drbg will not already be instantiated.
223*91f16700Schasinglulu 	 * Therefore, before generating data, instantiate the hash_drbg
224*91f16700Schasinglulu 	 */
225*91f16700Schasinglulu 	ret_code = is_hw_rng_instantiated(&state_handle);
226*91f16700Schasinglulu 	if (ret_code == 0) {
227*91f16700Schasinglulu 		INFO("Instantiating the HW RNG\n");
228*91f16700Schasinglulu 
229*91f16700Schasinglulu 		/* Instantiate the hw RNG */
230*91f16700Schasinglulu 		ret_code = hw_rng_instantiate();
231*91f16700Schasinglulu 		if (ret_code != 0) {
232*91f16700Schasinglulu 			ERROR("HW RNG Instantiate failed\n");
233*91f16700Schasinglulu 			return ret_code;
234*91f16700Schasinglulu 		}
235*91f16700Schasinglulu 	}
236*91f16700Schasinglulu 	/* If  HW RNG is still not instantiated, something must have gone wrong,
237*91f16700Schasinglulu 	 * it must be in the error state, we will not generate any random data
238*91f16700Schasinglulu 	 */
239*91f16700Schasinglulu 	if (is_hw_rng_instantiated(&state_handle) == 0) {
240*91f16700Schasinglulu 		ERROR("HW RNG is in an Error state, and cannot be used\n");
241*91f16700Schasinglulu 		return -1;
242*91f16700Schasinglulu 	}
243*91f16700Schasinglulu 	/* Generate a random 256-bit value, as 32 bytes */
244*91f16700Schasinglulu 	ret_code = hw_rng_generate(0, 0, bytes, byte_len, state_handle);
245*91f16700Schasinglulu 	if (ret_code != 0) {
246*91f16700Schasinglulu 		ERROR("HW RNG Generate failed\n");
247*91f16700Schasinglulu 		return ret_code;
248*91f16700Schasinglulu 	}
249*91f16700Schasinglulu 
250*91f16700Schasinglulu 	return ret_code;
251*91f16700Schasinglulu }
252