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