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