1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2023 HiSilicon Limited. */ 3 4 #include <initcall.h> 5 #include <io.h> 6 #include <kernel/spinlock.h> 7 #include <malloc.h> 8 #include <mm/core_memprot.h> 9 #include <platform_config.h> 10 #include <rng_support.h> 11 #include <string.h> 12 13 #define HTRNG_RANDATA_REG 0xF0 14 #define HTRNG_BYTES 4U 15 16 #define POLL_PERIOD 10 17 #define POLL_TIMEOUT 1000 18 19 struct hisi_trng { 20 vaddr_t base; 21 }; 22 23 static unsigned int trng_lock = SPINLOCK_UNLOCK; 24 static struct hisi_trng *trng_dev; 25 26 static TEE_Result trng_read(uint32_t *val) 27 { 28 TEE_Result ret = TEE_SUCCESS; 29 uint32_t exceptions = 0; 30 31 exceptions = cpu_spin_lock_xsave(&trng_lock); 32 if (IO_READ32_POLL_TIMEOUT(trng_dev->base + HTRNG_RANDATA_REG, 33 *val, *val, POLL_PERIOD, POLL_TIMEOUT)) { 34 EMSG("Hardware busy"); 35 ret = TEE_ERROR_BUSY; 36 } 37 cpu_spin_unlock_xrestore(&trng_lock, exceptions); 38 39 return ret; 40 } 41 42 TEE_Result hw_get_random_bytes(void *buf, size_t len) 43 { 44 TEE_Result ret = TEE_ERROR_GENERIC; 45 size_t current_len = 0; 46 uint32_t val = 0; 47 size_t size = 0; 48 49 if (!trng_dev) { 50 EMSG("No valid TRNG device"); 51 return TEE_ERROR_NOT_SUPPORTED; 52 } 53 54 if (!buf || !len) { 55 EMSG("Invalid input parameter"); 56 return TEE_ERROR_BAD_PARAMETERS; 57 } 58 59 while (current_len < len) { 60 ret = trng_read(&val); 61 if (ret) 62 return TEE_ERROR_BUSY; 63 64 size = MIN(HTRNG_BYTES, len - current_len); 65 memcpy((uint8_t *)buf + current_len, &val, size); 66 current_len += size; 67 } 68 69 return TEE_SUCCESS; 70 } 71 72 static TEE_Result trng_init(void) 73 { 74 DMSG("TRNG driver init start"); 75 trng_dev = calloc(1, sizeof(struct hisi_trng)); 76 if (!trng_dev) { 77 EMSG("Fail to calloc trng device"); 78 return TEE_ERROR_OUT_OF_MEMORY; 79 } 80 81 trng_dev->base = (vaddr_t)phys_to_virt_io(HISI_TRNG_BASE, 82 HISI_TRNG_SIZE); 83 if (!trng_dev->base) { 84 EMSG("Fail to get trng io_base"); 85 free(trng_dev); 86 trng_dev = NULL; 87 return TEE_ERROR_ACCESS_DENIED; 88 } 89 90 DMSG("TRNG driver init done"); 91 92 return TEE_SUCCESS; 93 } 94 95 early_init(trng_init); 96