1*74c676beSVesa Jääskeläinen // SPDX-License-Identifier: BSD-2-Clause 2*74c676beSVesa Jääskeläinen /* 3*74c676beSVesa Jääskeläinen * Copyright (c) 2022, Vaisala Oyj 4*74c676beSVesa Jääskeläinen */ 5*74c676beSVesa Jääskeläinen 6*74c676beSVesa Jääskeläinen #include <assert.h> 7*74c676beSVesa Jääskeläinen #include <io.h> 8*74c676beSVesa Jääskeläinen #include <kernel/boot.h> 9*74c676beSVesa Jääskeläinen #include <kernel/delay.h> 10*74c676beSVesa Jääskeläinen #include <kernel/dt.h> 11*74c676beSVesa Jääskeläinen #include <kernel/dt_driver.h> 12*74c676beSVesa Jääskeläinen #include <kernel/spinlock.h> 13*74c676beSVesa Jääskeläinen #include <libfdt.h> 14*74c676beSVesa Jääskeläinen #include <platform_config.h> 15*74c676beSVesa Jääskeläinen #include <rng_support.h> 16*74c676beSVesa Jääskeläinen #include <string.h> 17*74c676beSVesa Jääskeläinen #include <tee/tee_cryp_utl.h> 18*74c676beSVesa Jääskeläinen 19*74c676beSVesa Jääskeläinen #define CONTROL_REG 0x00000000 20*74c676beSVesa Jääskeläinen #define STATUS_REG 0x00000004 21*74c676beSVesa Jääskeläinen #define RAND_REG 0x00000000 22*74c676beSVesa Jääskeläinen 23*74c676beSVesa Jääskeläinen #define HOST_TO_TRNG_RESET 0x00000001 24*74c676beSVesa Jääskeläinen #define HOST_TO_TRNG_RELEASE_RESET 0x00000002 25*74c676beSVesa Jääskeläinen #define HOST_TO_TRNG_ENABLE 0x80000000 26*74c676beSVesa Jääskeläinen #define HOST_TO_TRNG_ZEROIZE 0x80000004 27*74c676beSVesa Jääskeläinen #define HOST_TO_TRNG_ACK_ZEROIZE 0x80000008 28*74c676beSVesa Jääskeläinen #define HOST_TO_TRNG_READ 0x8000000F 29*74c676beSVesa Jääskeläinen 30*74c676beSVesa Jääskeläinen /* trng statuses */ 31*74c676beSVesa Jääskeläinen #define TRNG_ACK_RESET 0x000000AC 32*74c676beSVesa Jääskeläinen #define TRNG_SUCCESSFUL_STARTUP 0x00000057 33*74c676beSVesa Jääskeläinen #define TRNG_FAILED_STARTUP 0x000000FA 34*74c676beSVesa Jääskeläinen #define TRNG_NEW_RAND_AVAILABLE 0x000000ED 35*74c676beSVesa Jääskeläinen 36*74c676beSVesa Jääskeläinen static unsigned int trng_lock = SPINLOCK_UNLOCK; 37*74c676beSVesa Jääskeläinen 38*74c676beSVesa Jääskeläinen static vaddr_t xiphera_trng_base; 39*74c676beSVesa Jääskeläinen 40*74c676beSVesa Jääskeläinen static uint32_t xiphera_trng_read32(void) 41*74c676beSVesa Jääskeläinen { 42*74c676beSVesa Jääskeläinen uint32_t value = 0; 43*74c676beSVesa Jääskeläinen uint32_t exceptions = 0; 44*74c676beSVesa Jääskeläinen uint32_t status = 0; 45*74c676beSVesa Jääskeläinen 46*74c676beSVesa Jääskeläinen exceptions = cpu_spin_lock_xsave(&trng_lock); 47*74c676beSVesa Jääskeläinen 48*74c676beSVesa Jääskeläinen while (true) { 49*74c676beSVesa Jääskeläinen /* Wait until we have value available */ 50*74c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG); 51*74c676beSVesa Jääskeläinen if (status != TRNG_NEW_RAND_AVAILABLE) 52*74c676beSVesa Jääskeläinen continue; 53*74c676beSVesa Jääskeläinen 54*74c676beSVesa Jääskeläinen value = io_read32(xiphera_trng_base + RAND_REG); 55*74c676beSVesa Jääskeläinen 56*74c676beSVesa Jääskeläinen /* 57*74c676beSVesa Jääskeläinen * Ack that RNG value has been consumed and trigger new one to 58*74c676beSVesa Jääskeläinen * be generated 59*74c676beSVesa Jääskeläinen */ 60*74c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_READ); 61*74c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, 62*74c676beSVesa Jääskeläinen HOST_TO_TRNG_ENABLE); 63*74c676beSVesa Jääskeläinen 64*74c676beSVesa Jääskeläinen break; 65*74c676beSVesa Jääskeläinen } 66*74c676beSVesa Jääskeläinen 67*74c676beSVesa Jääskeläinen cpu_spin_unlock_xrestore(&trng_lock, exceptions); 68*74c676beSVesa Jääskeläinen 69*74c676beSVesa Jääskeläinen return value; 70*74c676beSVesa Jääskeläinen } 71*74c676beSVesa Jääskeläinen 72*74c676beSVesa Jääskeläinen /* This is a true RNG, no need for seeding */ 73*74c676beSVesa Jääskeläinen void plat_rng_init(void) 74*74c676beSVesa Jääskeläinen { 75*74c676beSVesa Jääskeläinen } 76*74c676beSVesa Jääskeläinen 77*74c676beSVesa Jääskeläinen TEE_Result crypto_rng_read(void *buf, size_t len) 78*74c676beSVesa Jääskeläinen { 79*74c676beSVesa Jääskeläinen uint8_t *rngbuf = buf; 80*74c676beSVesa Jääskeläinen uint32_t val = 0; 81*74c676beSVesa Jääskeläinen size_t len_to_copy = 0; 82*74c676beSVesa Jääskeläinen 83*74c676beSVesa Jääskeläinen assert(buf); 84*74c676beSVesa Jääskeläinen assert(xiphera_trng_base); 85*74c676beSVesa Jääskeläinen 86*74c676beSVesa Jääskeläinen while (len) { 87*74c676beSVesa Jääskeläinen val = xiphera_trng_read32(); 88*74c676beSVesa Jääskeläinen len_to_copy = MIN(len, sizeof(uint32_t)); 89*74c676beSVesa Jääskeläinen memcpy(rngbuf, &val, len_to_copy); 90*74c676beSVesa Jääskeläinen rngbuf += len_to_copy; 91*74c676beSVesa Jääskeläinen len -= len_to_copy; 92*74c676beSVesa Jääskeläinen } 93*74c676beSVesa Jääskeläinen 94*74c676beSVesa Jääskeläinen return TEE_SUCCESS; 95*74c676beSVesa Jääskeläinen } 96*74c676beSVesa Jääskeläinen 97*74c676beSVesa Jääskeläinen uint8_t hw_get_random_byte(void) 98*74c676beSVesa Jääskeläinen { 99*74c676beSVesa Jääskeläinen uint8_t data = 0; 100*74c676beSVesa Jääskeläinen 101*74c676beSVesa Jääskeläinen assert(xiphera_trng_base); 102*74c676beSVesa Jääskeläinen 103*74c676beSVesa Jääskeläinen data = xiphera_trng_read32() & 0xFF; 104*74c676beSVesa Jääskeläinen 105*74c676beSVesa Jääskeläinen return data; 106*74c676beSVesa Jääskeläinen } 107*74c676beSVesa Jääskeläinen 108*74c676beSVesa Jääskeläinen static TEE_Result xiphera_trng_probe(const void *fdt, int node, 109*74c676beSVesa Jääskeläinen const void *compat_data __unused) 110*74c676beSVesa Jääskeläinen { 111*74c676beSVesa Jääskeläinen int dt_status = _fdt_get_status(fdt, node); 112*74c676beSVesa Jääskeläinen uint32_t status = 0; 113*74c676beSVesa Jääskeläinen size_t size = 0; 114*74c676beSVesa Jääskeläinen 115*74c676beSVesa Jääskeläinen /* Skip non-secure instances */ 116*74c676beSVesa Jääskeläinen if (dt_status != DT_STATUS_OK_SEC) 117*74c676beSVesa Jääskeläinen return TEE_ERROR_NODE_DISABLED; 118*74c676beSVesa Jääskeläinen 119*74c676beSVesa Jääskeläinen if (xiphera_trng_base) { 120*74c676beSVesa Jääskeläinen EMSG("Only one secure instance is supported"); 121*74c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 122*74c676beSVesa Jääskeläinen } 123*74c676beSVesa Jääskeläinen 124*74c676beSVesa Jääskeläinen if (dt_map_dev(fdt, node, &xiphera_trng_base, &size) < 0) 125*74c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 126*74c676beSVesa Jääskeläinen 127*74c676beSVesa Jääskeläinen /* 128*74c676beSVesa Jääskeläinen * The TRNG needs to be first reset in order to provide stable 129*74c676beSVesa Jääskeläinen * operation. 130*74c676beSVesa Jääskeläinen * 131*74c676beSVesa Jääskeläinen * Reset of the chip should complete within 200 us but in some cases it 132*74c676beSVesa Jääskeläinen * could take up to 400 us. If it is not ready within 400 us assume 133*74c676beSVesa Jääskeläinen * there is problem. 134*74c676beSVesa Jääskeläinen */ 135*74c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_RESET); 136*74c676beSVesa Jääskeläinen udelay(200); 137*74c676beSVesa Jääskeläinen 138*74c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG); 139*74c676beSVesa Jääskeläinen if (status != TRNG_ACK_RESET) { 140*74c676beSVesa Jääskeläinen /* 141*74c676beSVesa Jääskeläinen * Give it additional 200 us to allow it to reset. 142*74c676beSVesa Jääskeläinen * 143*74c676beSVesa Jääskeläinen * If still not done -> error out. 144*74c676beSVesa Jääskeläinen */ 145*74c676beSVesa Jääskeläinen udelay(200); 146*74c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG); 147*74c676beSVesa Jääskeläinen if (status != TRNG_ACK_RESET) { 148*74c676beSVesa Jääskeläinen EMSG("Failed to reset TRNG\n"); 149*74c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 150*74c676beSVesa Jääskeläinen } 151*74c676beSVesa Jääskeläinen } 152*74c676beSVesa Jääskeläinen 153*74c676beSVesa Jääskeläinen /* 154*74c676beSVesa Jääskeläinen * Now TRNG should be internally stable. 155*74c676beSVesa Jääskeläinen * 156*74c676beSVesa Jääskeläinen * Clear internal random number generation engine to start in stable 157*74c676beSVesa Jääskeläinen * state and give it 20 ms to enable good random number entropy and 158*74c676beSVesa Jääskeläinen * then check that random number engine is ready. 159*74c676beSVesa Jääskeläinen */ 160*74c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, 161*74c676beSVesa Jääskeläinen HOST_TO_TRNG_RELEASE_RESET); 162*74c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ENABLE); 163*74c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ZEROIZE); 164*74c676beSVesa Jääskeläinen mdelay(20); 165*74c676beSVesa Jääskeläinen 166*74c676beSVesa Jääskeläinen status = io_read32(xiphera_trng_base + STATUS_REG); 167*74c676beSVesa Jääskeläinen if (status != TRNG_SUCCESSFUL_STARTUP) { 168*74c676beSVesa Jääskeläinen /* 169*74c676beSVesa Jääskeläinen * Check specifically if there were startup test errors to aid 170*74c676beSVesa Jääskeläinen * in debugging TRNG implementation in FPGA 171*74c676beSVesa Jääskeläinen */ 172*74c676beSVesa Jääskeläinen if (status == TRNG_FAILED_STARTUP) { 173*74c676beSVesa Jääskeläinen EMSG("Startup tests have failed\n"); 174*74c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 175*74c676beSVesa Jääskeläinen } 176*74c676beSVesa Jääskeläinen 177*74c676beSVesa Jääskeläinen EMSG("Startup tests yielded no response -> TRNG stuck\n"); 178*74c676beSVesa Jääskeläinen return TEE_ERROR_GENERIC; 179*74c676beSVesa Jääskeläinen } 180*74c676beSVesa Jääskeläinen 181*74c676beSVesa Jääskeläinen io_write32(xiphera_trng_base + CONTROL_REG, HOST_TO_TRNG_ACK_ZEROIZE); 182*74c676beSVesa Jääskeläinen 183*74c676beSVesa Jääskeläinen DMSG("TRNG initialized\n"); 184*74c676beSVesa Jääskeläinen 185*74c676beSVesa Jääskeläinen return TEE_SUCCESS; 186*74c676beSVesa Jääskeläinen } 187*74c676beSVesa Jääskeläinen 188*74c676beSVesa Jääskeläinen static const struct dt_device_match xiphera_trng_match_table[] = { 189*74c676beSVesa Jääskeläinen { .compatible = "xiphera,xip8001b-trng" }, 190*74c676beSVesa Jääskeläinen { } 191*74c676beSVesa Jääskeläinen }; 192*74c676beSVesa Jääskeläinen 193*74c676beSVesa Jääskeläinen DEFINE_DT_DRIVER(xiphera_trng_dt_driver) = { 194*74c676beSVesa Jääskeläinen .name = "xiphera_trng", 195*74c676beSVesa Jääskeläinen .type = DT_DRIVER_NOTYPE, 196*74c676beSVesa Jääskeläinen .match_table = xiphera_trng_match_table, 197*74c676beSVesa Jääskeläinen .probe = xiphera_trng_probe, 198*74c676beSVesa Jääskeläinen }; 199