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