174c676beSVesa Jääskeläinen // SPDX-License-Identifier: BSD-2-Clause 274c676beSVesa Jääskeläinen /* 374c676beSVesa Jääskeläinen * Copyright (c) 2022, Vaisala Oyj 474c676beSVesa Jääskeläinen */ 574c676beSVesa Jääskeläinen 674c676beSVesa Jääskeläinen #include <assert.h> 774c676beSVesa Jääskeläinen #include <io.h> 874c676beSVesa Jääskeläinen #include <kernel/boot.h> 974c676beSVesa Jääskeläinen #include <kernel/delay.h> 1074c676beSVesa Jääskeläinen #include <kernel/dt.h> 1174c676beSVesa Jääskeläinen #include <kernel/dt_driver.h> 1274c676beSVesa Jääskeläinen #include <kernel/spinlock.h> 1374c676beSVesa Jääskeläinen #include <libfdt.h> 1474c676beSVesa Jääskeläinen #include <platform_config.h> 1574c676beSVesa Jääskeläinen #include <rng_support.h> 1674c676beSVesa Jääskeläinen #include <string.h> 1774c676beSVesa Jääskeläinen #include <tee/tee_cryp_utl.h> 1874c676beSVesa Jääskeläinen 1974c676beSVesa Jääskeläinen #define CONTROL_REG 0x00000000 2074c676beSVesa Jääskeläinen #define STATUS_REG 0x00000004 2174c676beSVesa Jääskeläinen #define RAND_REG 0x00000000 2274c676beSVesa Jääskeläinen 2374c676beSVesa Jääskeläinen #define HOST_TO_TRNG_RESET 0x00000001 2474c676beSVesa Jääskeläinen #define HOST_TO_TRNG_RELEASE_RESET 0x00000002 2574c676beSVesa Jääskeläinen #define HOST_TO_TRNG_ENABLE 0x80000000 2674c676beSVesa Jääskeläinen #define HOST_TO_TRNG_ZEROIZE 0x80000004 2774c676beSVesa Jääskeläinen #define HOST_TO_TRNG_ACK_ZEROIZE 0x80000008 2874c676beSVesa Jääskeläinen #define HOST_TO_TRNG_READ 0x8000000F 2974c676beSVesa Jääskeläinen 3074c676beSVesa Jääskeläinen /* trng statuses */ 3174c676beSVesa Jääskeläinen #define TRNG_ACK_RESET 0x000000AC 3274c676beSVesa Jääskeläinen #define TRNG_SUCCESSFUL_STARTUP 0x00000057 3374c676beSVesa Jääskeläinen #define TRNG_FAILED_STARTUP 0x000000FA 3474c676beSVesa Jääskeläinen #define TRNG_NEW_RAND_AVAILABLE 0x000000ED 3574c676beSVesa Jääskeläinen 3674c676beSVesa Jääskeläinen static unsigned int trng_lock = SPINLOCK_UNLOCK; 3774c676beSVesa Jääskeläinen 3874c676beSVesa Jääskeläinen static vaddr_t xiphera_trng_base; 3974c676beSVesa Jääskeläinen 40825dff97SVesa Jääskeläinen static bool xiphera_trng_random_available(void) 41825dff97SVesa Jääskeläinen { 42825dff97SVesa Jääskeläinen uint32_t status = 0; 43825dff97SVesa Jääskeläinen 44825dff97SVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG); 45825dff97SVesa Jääskeläinen 46825dff97SVesa Jääskeläinen return status == TRNG_NEW_RAND_AVAILABLE; 47825dff97SVesa Jääskeläinen } 48825dff97SVesa Jääskeläinen 4974c676beSVesa Jääskeläinen static uint32_t xiphera_trng_read32(void) 5074c676beSVesa Jääskeläinen { 5174c676beSVesa Jääskeläinen uint32_t value = 0; 5274c676beSVesa Jääskeläinen 5374c676beSVesa Jääskeläinen value = io_read32(xiphera_trng_base + RAND_REG); 5474c676beSVesa Jääskeläinen 5574c676beSVesa Jääskeläinen /* 56825dff97SVesa Jääskeläinen * Ack that RNG value has been consumed and trigger new one to be 57825dff97SVesa Jääskeläinen * generated 5874c676beSVesa Jääskeläinen */ 5974c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_READ); 60825dff97SVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ENABLE); 6174c676beSVesa Jääskeläinen 6274c676beSVesa Jääskeläinen return value; 6374c676beSVesa Jääskeläinen } 6474c676beSVesa Jääskeläinen 6574c676beSVesa Jääskeläinen /* This is a true RNG, no need for seeding */ 6674c676beSVesa Jääskeläinen void plat_rng_init(void) 6774c676beSVesa Jääskeläinen { 6874c676beSVesa Jääskeläinen } 6974c676beSVesa Jääskeläinen 70bc842791SAndrew Davis TEE_Result hw_get_random_bytes(void *buf, size_t len) 7174c676beSVesa Jääskeläinen { 72825dff97SVesa Jääskeläinen uint8_t *rngbuf = buf; 73825dff97SVesa Jääskeläinen uint32_t val = 0; 74825dff97SVesa Jääskeläinen size_t len_to_copy = 0; 7574c676beSVesa Jääskeläinen 76825dff97SVesa Jääskeläinen assert(buf); 7774c676beSVesa Jääskeläinen assert(xiphera_trng_base); 7874c676beSVesa Jääskeläinen 79825dff97SVesa Jääskeläinen while (len) { 80bc842791SAndrew Davis uint32_t exceptions = cpu_spin_lock_xsave(&trng_lock); 81bc842791SAndrew Davis 82825dff97SVesa Jääskeläinen if (xiphera_trng_random_available()) { 83825dff97SVesa Jääskeläinen val = xiphera_trng_read32(); 84bc842791SAndrew Davis 85825dff97SVesa Jääskeläinen len_to_copy = MIN(len, sizeof(uint32_t)); 86825dff97SVesa Jääskeläinen memcpy(rngbuf, &val, len_to_copy); 87825dff97SVesa Jääskeläinen rngbuf += len_to_copy; 88825dff97SVesa Jääskeläinen len -= len_to_copy; 89825dff97SVesa Jääskeläinen } 90bc842791SAndrew Davis 91bc842791SAndrew Davis cpu_spin_unlock_xrestore(&trng_lock, exceptions); 9274c676beSVesa Jääskeläinen } 9374c676beSVesa Jääskeläinen 9474c676beSVesa Jääskeläinen return TEE_SUCCESS; 9574c676beSVesa Jääskeläinen } 9674c676beSVesa Jääskeläinen 9774c676beSVesa Jääskeläinen static TEE_Result xiphera_trng_probe(const void *fdt, int node, 9874c676beSVesa Jääskeläinen const void *compat_data __unused) 9974c676beSVesa Jääskeläinen { 100*f354a5d8SGatien Chevallier int dt_status = fdt_get_status(fdt, node); 10174c676beSVesa Jääskeläinen uint32_t status = 0; 10274c676beSVesa Jääskeläinen size_t size = 0; 10374c676beSVesa Jääskeläinen 10474c676beSVesa Jääskeläinen /* Skip non-secure instances */ 10574c676beSVesa Jääskeläinen if (dt_status != DT_STATUS_OK_SEC) 10674c676beSVesa Jääskeläinen return TEE_ERROR_NODE_DISABLED; 10774c676beSVesa Jääskeläinen 10874c676beSVesa Jääskeläinen if (xiphera_trng_base) { 10974c676beSVesa Jääskeläinen EMSG("Only one secure instance is supported"); 11074c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 11174c676beSVesa Jääskeläinen } 11274c676beSVesa Jääskeläinen 113a5d5bbc8SVesa Jääskeläinen if (dt_map_dev(fdt, node, &xiphera_trng_base, &size, DT_MAP_AUTO) < 0) 11474c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 11574c676beSVesa Jääskeläinen 11674c676beSVesa Jääskeläinen /* 11774c676beSVesa Jääskeläinen * The TRNG needs to be first reset in order to provide stable 11874c676beSVesa Jääskeläinen * operation. 11974c676beSVesa Jääskeläinen * 12074c676beSVesa Jääskeläinen * Reset of the chip should complete within 200 us but in some cases it 12174c676beSVesa Jääskeläinen * could take up to 400 us. If it is not ready within 400 us assume 12274c676beSVesa Jääskeläinen * there is problem. 12374c676beSVesa Jääskeläinen */ 12474c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_RESET); 12574c676beSVesa Jääskeläinen udelay(200); 12674c676beSVesa Jääskeläinen 12774c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG); 12874c676beSVesa Jääskeläinen if (status != TRNG_ACK_RESET) { 12974c676beSVesa Jääskeläinen /* 13074c676beSVesa Jääskeläinen * Give it additional 200 us to allow it to reset. 13174c676beSVesa Jääskeläinen * 13274c676beSVesa Jääskeläinen * If still not done -> error out. 13374c676beSVesa Jääskeläinen */ 13474c676beSVesa Jääskeläinen udelay(200); 13574c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG); 13674c676beSVesa Jääskeläinen if (status != TRNG_ACK_RESET) { 13774c676beSVesa Jääskeläinen EMSG("Failed to reset TRNG\n"); 13874c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 13974c676beSVesa Jääskeläinen } 14074c676beSVesa Jääskeläinen } 14174c676beSVesa Jääskeläinen 14274c676beSVesa Jääskeläinen /* 14374c676beSVesa Jääskeläinen * Now TRNG should be internally stable. 14474c676beSVesa Jääskeläinen * 14574c676beSVesa Jääskeläinen * Clear internal random number generation engine to start in stable 14674c676beSVesa Jääskeläinen * state and give it 20 ms to enable good random number entropy and 14774c676beSVesa Jääskeläinen * then check that random number engine is ready. 14874c676beSVesa Jääskeläinen */ 14974c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, 15074c676beSVesa Jääskeläinen HOST_TO_TRNG_RELEASE_RESET); 15174c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ENABLE); 15274c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ZEROIZE); 15374c676beSVesa Jääskeläinen mdelay(20); 15474c676beSVesa Jääskeläinen 15574c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG); 15674c676beSVesa Jääskeläinen if (status != TRNG_SUCCESSFUL_STARTUP) { 15774c676beSVesa Jääskeläinen /* 15874c676beSVesa Jääskeläinen * Check specifically if there were startup test errors to aid 15974c676beSVesa Jääskeläinen * in debugging TRNG implementation in FPGA 16074c676beSVesa Jääskeläinen */ 16174c676beSVesa Jääskeläinen if (status == TRNG_FAILED_STARTUP) { 16274c676beSVesa Jääskeläinen EMSG("Startup tests have failed\n"); 16374c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 16474c676beSVesa Jääskeläinen } 16574c676beSVesa Jääskeläinen 16674c676beSVesa Jääskeläinen EMSG("Startup tests yielded no response -> TRNG stuck\n"); 16774c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 16874c676beSVesa Jääskeläinen } 16974c676beSVesa Jääskeläinen 17074c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ACK_ZEROIZE); 17174c676beSVesa Jääskeläinen 17274c676beSVesa Jääskeläinen DMSG("TRNG initialized\n"); 17374c676beSVesa Jääskeläinen 17474c676beSVesa Jääskeläinen return TEE_SUCCESS; 17574c676beSVesa Jääskeläinen } 17674c676beSVesa Jääskeläinen 17774c676beSVesa Jääskeläinen static const struct dt_device_match xiphera_trng_match_table[] = { 17874c676beSVesa Jääskeläinen { .compatible = "xiphera,xip8001b-trng" }, 17974c676beSVesa Jääskeläinen { } 18074c676beSVesa Jääskeläinen }; 18174c676beSVesa Jääskeläinen 18274c676beSVesa Jääskeläinen DEFINE_DT_DRIVER(xiphera_trng_dt_driver) = { 18374c676beSVesa Jääskeläinen .name = "xiphera_trng", 18474c676beSVesa Jääskeläinen .type = DT_DRIVER_NOTYPE, 18574c676beSVesa Jääskeläinen .match_table = xiphera_trng_match_table, 18674c676beSVesa Jääskeläinen .probe = xiphera_trng_probe, 18774c676beSVesa Jääskeläinen }; 188