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 assert(trng_base); 105 } 106 107 static void atmel_trng_reset(void) 108 { 109 uint32_t ctrl_val = TRNG_CTRL_WAKEY_VALUE << TRNG_CTRL_WAKEY_OFFSET; 110 111 /* Disable TRNG */ 112 io_setbits32(trng_base + TRNG_CTRL, ctrl_val); 113 /* Enable interrupt */ 114 io_setbits32(trng_base + TRNG_IER, 1); 115 /* Enable TRNG */ 116 io_setbits32(trng_base + TRNG_CTRL, ctrl_val | 1); 117 } 118 119 static TEE_Result trng_node_probe(const void *fdt, int node, 120 const void *compat_data __unused) 121 { 122 int status = _fdt_get_status(fdt, node); 123 size_t size = 0; 124 struct clk *clk = NULL; 125 TEE_Result res = TEE_ERROR_GENERIC; 126 127 if (status != DT_STATUS_OK_SEC) 128 return TEE_ERROR_GENERIC; 129 130 matrix_configure_periph_secure(AT91C_ID_TRNG); 131 132 clk = clk_dt_get_by_idx(fdt, node, 0, &res); 133 if (res) 134 return res; 135 136 if (dt_map_dev(fdt, node, &trng_base, &size) < 0) 137 return TEE_ERROR_GENERIC; 138 139 clk_enable(clk); 140 141 atmel_trng_reset(); 142 143 return TEE_SUCCESS; 144 } 145 146 static const struct dt_device_match atmel_trng_match_table[] = { 147 { .compatible = "atmel,at91sam9g45-trng" }, 148 { } 149 }; 150 151 const struct dt_driver atmel_trng_dt_driver __dt_driver = { 152 .name = "atmel_trng", 153 .type = DT_DRIVER_NOTYPE, 154 .match_table = atmel_trng_match_table, 155 .probe = trng_node_probe, 156 }; 157