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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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