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