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