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