1*f2da02b2SClément Léger // SPDX-License-Identifier: BSD-2-Clause 2*f2da02b2SClément Léger /* 3*f2da02b2SClément Léger * Copyright 2021 Microchip 4*f2da02b2SClément Léger */ 5*f2da02b2SClément Léger 6*f2da02b2SClément Léger #include <assert.h> 7*f2da02b2SClément Léger #include <drivers/clk.h> 8*f2da02b2SClément Léger #include <drivers/clk_dt.h> 9*f2da02b2SClément Léger #include <io.h> 10*f2da02b2SClément Léger #include <kernel/boot.h> 11*f2da02b2SClément Léger #include <kernel/spinlock.h> 12*f2da02b2SClément Léger #include <libfdt.h> 13*f2da02b2SClément Léger #include <matrix.h> 14*f2da02b2SClément Léger #include <platform_config.h> 15*f2da02b2SClément Léger #include <rng_support.h> 16*f2da02b2SClément Léger #include <string.h> 17*f2da02b2SClément Léger #include <tee/tee_cryp_utl.h> 18*f2da02b2SClément Léger 19*f2da02b2SClément Léger /* Registers */ 20*f2da02b2SClément Léger #define TRNG_CTRL 0x0 21*f2da02b2SClément Léger #define TRNG_CTRL_WAKEY_OFFSET 8 22*f2da02b2SClément Léger #define TRNG_CTRL_WAKEY_VALUE 0x524E47 23*f2da02b2SClément Léger 24*f2da02b2SClément Léger #define TRNG_IER 0x10 25*f2da02b2SClément Léger #define TRNG_ISR 0x1C 26*f2da02b2SClément Léger #define TRNG_ODATA 0x50 27*f2da02b2SClément Léger 28*f2da02b2SClément Léger static unsigned int trng_lock = SPINLOCK_UNLOCK; 29*f2da02b2SClément Léger static unsigned int trng_random_val_lock = SPINLOCK_UNLOCK; 30*f2da02b2SClément Léger static vaddr_t trng_base; 31*f2da02b2SClément Léger static uint8_t random_byte_pos; 32*f2da02b2SClément Léger static union { 33*f2da02b2SClément Léger uint32_t val; 34*f2da02b2SClément Léger uint8_t byte[sizeof(uint32_t)]; 35*f2da02b2SClément Léger } random_data; 36*f2da02b2SClément Léger 37*f2da02b2SClément Léger static uint32_t atmel_trng_read32(void) 38*f2da02b2SClément Léger { 39*f2da02b2SClément Léger uint32_t exceptions = 0; 40*f2da02b2SClément Léger uint32_t value = 0; 41*f2da02b2SClément Léger 42*f2da02b2SClément Léger exceptions = cpu_spin_lock_xsave(&trng_lock); 43*f2da02b2SClément Léger 44*f2da02b2SClément Léger while (!io_read32(trng_base + TRNG_ISR)) 45*f2da02b2SClément Léger ; 46*f2da02b2SClément Léger 47*f2da02b2SClément Léger value = io_read32(trng_base + TRNG_ODATA); 48*f2da02b2SClément Léger 49*f2da02b2SClément Léger cpu_spin_unlock_xrestore(&trng_lock, exceptions); 50*f2da02b2SClément Léger 51*f2da02b2SClément Léger return value; 52*f2da02b2SClément Léger } 53*f2da02b2SClément Léger 54*f2da02b2SClément Léger TEE_Result crypto_rng_read(void *buf, size_t len) 55*f2da02b2SClément Léger { 56*f2da02b2SClément Léger uint8_t *rngbuf = buf; 57*f2da02b2SClément Léger uint32_t val = 0; 58*f2da02b2SClément Léger size_t len_to_copy = 0; 59*f2da02b2SClément Léger 60*f2da02b2SClément Léger assert(buf); 61*f2da02b2SClément Léger assert(trng_base); 62*f2da02b2SClément Léger 63*f2da02b2SClément Léger while (len) { 64*f2da02b2SClément Léger val = atmel_trng_read32(); 65*f2da02b2SClément Léger len_to_copy = MIN(len, sizeof(uint32_t)); 66*f2da02b2SClément Léger memcpy(rngbuf, &val, len_to_copy); 67*f2da02b2SClément Léger rngbuf += len_to_copy; 68*f2da02b2SClément Léger len -= len_to_copy; 69*f2da02b2SClément Léger } 70*f2da02b2SClément Léger 71*f2da02b2SClément Léger return TEE_SUCCESS; 72*f2da02b2SClément Léger } 73*f2da02b2SClément Léger 74*f2da02b2SClément Léger uint8_t hw_get_random_byte(void) 75*f2da02b2SClément Léger { 76*f2da02b2SClément Léger uint32_t exceptions = 0; 77*f2da02b2SClément Léger uint8_t data = 0; 78*f2da02b2SClément Léger 79*f2da02b2SClément Léger assert(trng_base); 80*f2da02b2SClément Léger 81*f2da02b2SClément Léger exceptions = cpu_spin_lock_xsave(&trng_random_val_lock); 82*f2da02b2SClément Léger 83*f2da02b2SClément Léger /* 84*f2da02b2SClément Léger * The TRNG generates a whole 32 bits word every 84 cycles. To avoid 85*f2da02b2SClément Léger * discarding 3 bytes at each request, request 4 bytes of random data 86*f2da02b2SClément Léger * and return only 1 at each request until there is no more bytes in the 87*f2da02b2SClément Léger * random_data "cache". 88*f2da02b2SClément Léger */ 89*f2da02b2SClément Léger if (!random_byte_pos) 90*f2da02b2SClément Léger random_data.val = atmel_trng_read32(); 91*f2da02b2SClément Léger 92*f2da02b2SClément Léger data = random_data.byte[random_byte_pos++]; 93*f2da02b2SClément Léger if (random_byte_pos == sizeof(uint32_t)) 94*f2da02b2SClément Léger random_byte_pos = 0; 95*f2da02b2SClément Léger 96*f2da02b2SClément Léger cpu_spin_unlock_xrestore(&trng_random_val_lock, exceptions); 97*f2da02b2SClément Léger 98*f2da02b2SClément Léger return data; 99*f2da02b2SClément Léger } 100*f2da02b2SClément Léger 101*f2da02b2SClément Léger /* This is a true RNG, no need for seeding */ 102*f2da02b2SClément Léger void plat_rng_init(void) 103*f2da02b2SClément Léger { 104*f2da02b2SClément Léger assert(trng_base); 105*f2da02b2SClément Léger } 106*f2da02b2SClément Léger 107*f2da02b2SClément Léger static void atmel_trng_reset(void) 108*f2da02b2SClément Léger { 109*f2da02b2SClément Léger uint32_t ctrl_val = TRNG_CTRL_WAKEY_VALUE << TRNG_CTRL_WAKEY_OFFSET; 110*f2da02b2SClément Léger 111*f2da02b2SClément Léger /* Disable TRNG */ 112*f2da02b2SClément Léger io_setbits32(trng_base + TRNG_CTRL, ctrl_val); 113*f2da02b2SClément Léger /* Enable interrupt */ 114*f2da02b2SClément Léger io_setbits32(trng_base + TRNG_IER, 1); 115*f2da02b2SClément Léger /* Enable TRNG */ 116*f2da02b2SClément Léger io_setbits32(trng_base + TRNG_CTRL, ctrl_val | 1); 117*f2da02b2SClément Léger } 118*f2da02b2SClément Léger 119*f2da02b2SClément Léger static TEE_Result trng_node_probe(const void *fdt, int node, 120*f2da02b2SClément Léger const void *compat_data __unused) 121*f2da02b2SClément Léger { 122*f2da02b2SClément Léger int status = _fdt_get_status(fdt, node); 123*f2da02b2SClément Léger size_t size = 0; 124*f2da02b2SClément Léger struct clk *clk = NULL; 125*f2da02b2SClément Léger TEE_Result res = TEE_ERROR_GENERIC; 126*f2da02b2SClément Léger 127*f2da02b2SClément Léger if (status != DT_STATUS_OK_SEC) 128*f2da02b2SClément Léger return TEE_ERROR_GENERIC; 129*f2da02b2SClément Léger 130*f2da02b2SClément Léger matrix_configure_periph_secure(AT91C_ID_TRNG); 131*f2da02b2SClément Léger 132*f2da02b2SClément Léger clk = clk_dt_get_by_idx(fdt, node, 0, &res); 133*f2da02b2SClément Léger if (res) 134*f2da02b2SClément Léger return res; 135*f2da02b2SClément Léger 136*f2da02b2SClément Léger if (dt_map_dev(fdt, node, &trng_base, &size) < 0) 137*f2da02b2SClément Léger return TEE_ERROR_GENERIC; 138*f2da02b2SClément Léger 139*f2da02b2SClément Léger clk_enable(clk); 140*f2da02b2SClément Léger 141*f2da02b2SClément Léger atmel_trng_reset(); 142*f2da02b2SClément Léger 143*f2da02b2SClément Léger return TEE_SUCCESS; 144*f2da02b2SClément Léger } 145*f2da02b2SClément Léger 146*f2da02b2SClément Léger static const struct dt_device_match atmel_trng_match_table[] = { 147*f2da02b2SClément Léger { .compatible = "atmel,at91sam9g45-trng" }, 148*f2da02b2SClément Léger { } 149*f2da02b2SClément Léger }; 150*f2da02b2SClément Léger 151*f2da02b2SClément Léger const struct dt_driver atmel_trng_dt_driver __dt_driver = { 152*f2da02b2SClément Léger .name = "atmel_trng", 153*f2da02b2SClément Léger .type = DT_DRIVER_NOTYPE, 154*f2da02b2SClément Léger .match_table = atmel_trng_match_table, 155*f2da02b2SClément Léger .probe = trng_node_probe, 156*f2da02b2SClément Léger }; 157