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 vaddr_t trng_base; 30 31 static uint32_t atmel_trng_read32(void) 32 { 33 uint32_t exceptions = 0; 34 uint32_t value = 0; 35 36 exceptions = cpu_spin_lock_xsave(&trng_lock); 37 38 while (!io_read32(trng_base + TRNG_ISR)) 39 ; 40 41 value = io_read32(trng_base + TRNG_ODATA); 42 43 cpu_spin_unlock_xrestore(&trng_lock, exceptions); 44 45 return value; 46 } 47 48 TEE_Result hw_get_random_bytes(void *buf, size_t len) 49 { 50 uint8_t *rngbuf = buf; 51 uint32_t val = 0; 52 size_t len_to_copy = 0; 53 54 assert(trng_base); 55 56 while (len) { 57 val = atmel_trng_read32(); 58 len_to_copy = MIN(len, sizeof(uint32_t)); 59 memcpy(rngbuf, &val, len_to_copy); 60 rngbuf += len_to_copy; 61 len -= len_to_copy; 62 } 63 64 return TEE_SUCCESS; 65 } 66 67 /* This is a true RNG, no need for seeding */ 68 void plat_rng_init(void) 69 { 70 } 71 72 static void atmel_trng_reset(void) 73 { 74 uint32_t ctrl_val = TRNG_CTRL_WAKEY_VALUE << TRNG_CTRL_WAKEY_OFFSET; 75 76 /* Disable TRNG */ 77 io_setbits32(trng_base + TRNG_CTRL, ctrl_val); 78 /* Enable interrupt */ 79 io_setbits32(trng_base + TRNG_IER, 1); 80 /* Enable TRNG */ 81 io_setbits32(trng_base + TRNG_CTRL, ctrl_val | 1); 82 } 83 84 static TEE_Result trng_node_probe(const void *fdt, int node, 85 const void *compat_data __unused) 86 { 87 int status = _fdt_get_status(fdt, node); 88 size_t size = 0; 89 struct clk *clk = NULL; 90 TEE_Result res = TEE_ERROR_GENERIC; 91 92 if (status != DT_STATUS_OK_SEC) 93 return TEE_ERROR_GENERIC; 94 95 matrix_configure_periph_secure(AT91C_ID_TRNG); 96 97 res = clk_dt_get_by_index(fdt, node, 0, &clk); 98 if (res) 99 return res; 100 101 if (dt_map_dev(fdt, node, &trng_base, &size) < 0) 102 return TEE_ERROR_GENERIC; 103 104 clk_enable(clk); 105 106 atmel_trng_reset(); 107 108 return TEE_SUCCESS; 109 } 110 111 static const struct dt_device_match atmel_trng_match_table[] = { 112 { .compatible = "atmel,at91sam9g45-trng" }, 113 { } 114 }; 115 116 DEFINE_DT_DRIVER(atmel_trng_dt_driver) = { 117 .name = "atmel_trng", 118 .type = DT_DRIVER_NOTYPE, 119 .match_table = atmel_trng_match_table, 120 .probe = trng_node_probe, 121 }; 122