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 4074c676beSVesa Jääskeläinen static uint32_t xiphera_trng_read32(void) 4174c676beSVesa Jääskeläinen { 4274c676beSVesa Jääskeläinen uint32_t value = 0; 4374c676beSVesa Jääskeläinen uint32_t exceptions = 0; 4474c676beSVesa Jääskeläinen uint32_t status = 0; 4574c676beSVesa Jääskeläinen 4674c676beSVesa Jääskeläinen while (true) { 4774c676beSVesa Jääskeläinen /* Wait until we have value available */ 4874c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG); 4974c676beSVesa Jääskeläinen if (status != TRNG_NEW_RAND_AVAILABLE) 5074c676beSVesa Jääskeläinen continue; 5174c676beSVesa Jääskeläinen 5274c676beSVesa Jääskeläinen value = io_read32(xiphera_trng_base + RAND_REG); 5374c676beSVesa Jääskeläinen 5474c676beSVesa Jääskeläinen /* 5574c676beSVesa Jääskeläinen * Ack that RNG value has been consumed and trigger new one to 5674c676beSVesa Jääskeläinen * be generated 5774c676beSVesa Jääskeläinen */ 5874c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_READ); 5974c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, 6074c676beSVesa Jääskeläinen HOST_TO_TRNG_ENABLE); 6174c676beSVesa Jääskeläinen 6274c676beSVesa Jääskeläinen break; 6374c676beSVesa Jääskeläinen } 6474c676beSVesa Jääskeläinen 6574c676beSVesa Jääskeläinen return value; 6674c676beSVesa Jääskeläinen } 6774c676beSVesa Jääskeläinen 6874c676beSVesa Jääskeläinen /* This is a true RNG, no need for seeding */ 6974c676beSVesa Jääskeläinen void plat_rng_init(void) 7074c676beSVesa Jääskeläinen { 7174c676beSVesa Jääskeläinen } 7274c676beSVesa Jääskeläinen 73*bc842791SAndrew Davis TEE_Result hw_get_random_bytes(void *buf, size_t len) 7474c676beSVesa Jääskeläinen { 75*bc842791SAndrew Davis static union { 76*bc842791SAndrew Davis uint32_t val; 77*bc842791SAndrew Davis uint8_t byte[4]; 78*bc842791SAndrew Davis } fifo; 79*bc842791SAndrew Davis static size_t fifo_pos; 80*bc842791SAndrew Davis uint8_t *buffer = buf; 81*bc842791SAndrew Davis size_t buffer_pos = 0; 8274c676beSVesa Jääskeläinen 8374c676beSVesa Jääskeläinen assert(xiphera_trng_base); 8474c676beSVesa Jääskeläinen 85*bc842791SAndrew Davis while (buffer_pos < len) { 86*bc842791SAndrew Davis uint32_t exceptions = cpu_spin_lock_xsave(&trng_lock); 87*bc842791SAndrew Davis 88*bc842791SAndrew Davis /* Refill our FIFO */ 89*bc842791SAndrew Davis if (fifo_pos == 0) 90*bc842791SAndrew Davis fifo.val = xiphera_trng_read32(); 91*bc842791SAndrew Davis 92*bc842791SAndrew Davis buffer[buffer_pos++] = fifo.byte[fifo_pos++]; 93*bc842791SAndrew Davis fifo_pos %= 4; 94*bc842791SAndrew Davis 95*bc842791SAndrew Davis cpu_spin_unlock_xrestore(&trng_lock, exceptions); 9674c676beSVesa Jääskeläinen } 9774c676beSVesa Jääskeläinen 9874c676beSVesa Jääskeläinen return TEE_SUCCESS; 9974c676beSVesa Jääskeläinen } 10074c676beSVesa Jääskeläinen 10174c676beSVesa Jääskeläinen static TEE_Result xiphera_trng_probe(const void *fdt, int node, 10274c676beSVesa Jääskeläinen const void *compat_data __unused) 10374c676beSVesa Jääskeläinen { 10474c676beSVesa Jääskeläinen int dt_status = _fdt_get_status(fdt, node); 10574c676beSVesa Jääskeläinen uint32_t status = 0; 10674c676beSVesa Jääskeläinen size_t size = 0; 10774c676beSVesa Jääskeläinen 10874c676beSVesa Jääskeläinen /* Skip non-secure instances */ 10974c676beSVesa Jääskeläinen if (dt_status != DT_STATUS_OK_SEC) 11074c676beSVesa Jääskeläinen return TEE_ERROR_NODE_DISABLED; 11174c676beSVesa Jääskeläinen 11274c676beSVesa Jääskeläinen if (xiphera_trng_base) { 11374c676beSVesa Jääskeläinen EMSG("Only one secure instance is supported"); 11474c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 11574c676beSVesa Jääskeläinen } 11674c676beSVesa Jääskeläinen 11774c676beSVesa Jääskeläinen if (dt_map_dev(fdt, node, &xiphera_trng_base, &size) < 0) 11874c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 11974c676beSVesa Jääskeläinen 12074c676beSVesa Jääskeläinen /* 12174c676beSVesa Jääskeläinen * The TRNG needs to be first reset in order to provide stable 12274c676beSVesa Jääskeläinen * operation. 12374c676beSVesa Jääskeläinen * 12474c676beSVesa Jääskeläinen * Reset of the chip should complete within 200 us but in some cases it 12574c676beSVesa Jääskeläinen * could take up to 400 us. If it is not ready within 400 us assume 12674c676beSVesa Jääskeläinen * there is problem. 12774c676beSVesa Jääskeläinen */ 12874c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_RESET); 12974c676beSVesa Jääskeläinen udelay(200); 13074c676beSVesa Jääskeläinen 13174c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG); 13274c676beSVesa Jääskeläinen if (status != TRNG_ACK_RESET) { 13374c676beSVesa Jääskeläinen /* 13474c676beSVesa Jääskeläinen * Give it additional 200 us to allow it to reset. 13574c676beSVesa Jääskeläinen * 13674c676beSVesa Jääskeläinen * If still not done -> error out. 13774c676beSVesa Jääskeläinen */ 13874c676beSVesa Jääskeläinen udelay(200); 13974c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG); 14074c676beSVesa Jääskeläinen if (status != TRNG_ACK_RESET) { 14174c676beSVesa Jääskeläinen EMSG("Failed to reset TRNG\n"); 14274c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 14374c676beSVesa Jääskeläinen } 14474c676beSVesa Jääskeläinen } 14574c676beSVesa Jääskeläinen 14674c676beSVesa Jääskeläinen /* 14774c676beSVesa Jääskeläinen * Now TRNG should be internally stable. 14874c676beSVesa Jääskeläinen * 14974c676beSVesa Jääskeläinen * Clear internal random number generation engine to start in stable 15074c676beSVesa Jääskeläinen * state and give it 20 ms to enable good random number entropy and 15174c676beSVesa Jääskeläinen * then check that random number engine is ready. 15274c676beSVesa Jääskeläinen */ 15374c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, 15474c676beSVesa Jääskeläinen HOST_TO_TRNG_RELEASE_RESET); 15574c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ENABLE); 15674c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ZEROIZE); 15774c676beSVesa Jääskeläinen mdelay(20); 15874c676beSVesa Jääskeläinen 15974c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG); 16074c676beSVesa Jääskeläinen if (status != TRNG_SUCCESSFUL_STARTUP) { 16174c676beSVesa Jääskeläinen /* 16274c676beSVesa Jääskeläinen * Check specifically if there were startup test errors to aid 16374c676beSVesa Jääskeläinen * in debugging TRNG implementation in FPGA 16474c676beSVesa Jääskeläinen */ 16574c676beSVesa Jääskeläinen if (status == TRNG_FAILED_STARTUP) { 16674c676beSVesa Jääskeläinen EMSG("Startup tests have failed\n"); 16774c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 16874c676beSVesa Jääskeläinen } 16974c676beSVesa Jääskeläinen 17074c676beSVesa Jääskeläinen EMSG("Startup tests yielded no response -> TRNG stuck\n"); 17174c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 17274c676beSVesa Jääskeläinen } 17374c676beSVesa Jääskeläinen 17474c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ACK_ZEROIZE); 17574c676beSVesa Jääskeläinen 17674c676beSVesa Jääskeläinen DMSG("TRNG initialized\n"); 17774c676beSVesa Jääskeläinen 17874c676beSVesa Jääskeläinen return TEE_SUCCESS; 17974c676beSVesa Jääskeläinen } 18074c676beSVesa Jääskeläinen 18174c676beSVesa Jääskeläinen static const struct dt_device_match xiphera_trng_match_table[] = { 18274c676beSVesa Jääskeläinen { .compatible = "xiphera,xip8001b-trng" }, 18374c676beSVesa Jääskeläinen { } 18474c676beSVesa Jääskeläinen }; 18574c676beSVesa Jääskeläinen 18674c676beSVesa Jääskeläinen DEFINE_DT_DRIVER(xiphera_trng_dt_driver) = { 18774c676beSVesa Jääskeläinen .name = "xiphera_trng", 18874c676beSVesa Jääskeläinen .type = DT_DRIVER_NOTYPE, 18974c676beSVesa Jääskeläinen .match_table = xiphera_trng_match_table, 19074c676beSVesa Jääskeläinen .probe = xiphera_trng_probe, 19174c676beSVesa Jääskeläinen }; 192