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 12 #define HTRNG_RANDATA_REG 0xF0 13 #define HTRNG_BYTES 4 14 15 #define POLL_PERIOD 10 16 #define POLL_TIMEOUT 1000 17 18 struct hisi_trng { 19 vaddr_t base; 20 }; 21 22 static unsigned int trng_lock = SPINLOCK_UNLOCK; 23 static struct hisi_trng *trng_dev; 24 25 static TEE_Result trng_read(uint32_t *val) 26 { 27 TEE_Result ret = TEE_SUCCESS; 28 uint32_t exceptions = 0; 29 30 exceptions = cpu_spin_lock_xsave(&trng_lock); 31 if (IO_READ32_POLL_TIMEOUT(trng_dev->base + HTRNG_RANDATA_REG, 32 val, val, POLL_PERIOD, POLL_TIMEOUT)) { 33 EMSG("Hardware busy."); 34 ret = TEE_ERROR_BUSY; 35 } 36 cpu_spin_unlock_xrestore(&trng_lock, exceptions); 37 38 return ret; 39 } 40 41 TEE_Result hw_get_random_bytes(void *buf, size_t len) 42 { 43 TEE_Result ret = TEE_ERROR_GENERIC; 44 size_t current_len = 0; 45 uint32_t val = 0; 46 47 if (!trng_dev) { 48 EMSG("No valid TRNG device."); 49 return TEE_ERROR_NOT_SUPPORTED; 50 } 51 52 if (!buf || !len) { 53 EMSG("Invalid input parameter."); 54 return TEE_ERROR_BAD_PARAMETERS; 55 } 56 57 while (current_len < len) { 58 ret = trng_read(&val); 59 if (ret) 60 return TEE_ERROR_BUSY; 61 62 size = MIN(HTRNG_BYTES, len - current_len); 63 memcpy((uint8_t *)buf + current_len, &val, size); 64 current_len += size; 65 } 66 67 return TEE_SUCCESS; 68 } 69 70 static TEE_Result trng_init(void) 71 { 72 TEE_Result ret = TEE_ERROR_GENERIC; 73 74 IMSG("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->base = (vaddr_t)phys_to_virt_io(HISI_TRNG_BASE, HISI_TRNG_SIZE); 82 if (!trng_dev->base) { 83 EMSG("Fail to get trng io_base."); 84 free(trng_dev); 85 trng_dev = NULL; 86 return TEE_ERROR_ACCESS_DENIED; 87 } 88 89 DMSG("TRNG driver init done."); 90 91 return TEE_SUCCESS; 92 } 93 94 early_init(trng_init); 95