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