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