11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 24d168941SAndrew F. Davis /* 34d168941SAndrew F. Davis * Copyright (c) 2016, Linaro Limited 44d168941SAndrew F. Davis */ 54d168941SAndrew F. Davis 64d168941SAndrew F. Davis #include <initcall.h> 74d168941SAndrew F. Davis #include <io.h> 84d168941SAndrew F. Davis #include <keep.h> 94d168941SAndrew F. Davis #include <kernel/interrupt.h> 104d168941SAndrew F. Davis #include <kernel/misc.h> 114d168941SAndrew F. Davis #include <kernel/spinlock.h> 124d168941SAndrew F. Davis #include <mm/core_memprot.h> 134d168941SAndrew F. Davis #include <mm/core_mmu.h> 144d168941SAndrew F. Davis #include <platform_config.h> 154d168941SAndrew F. Davis #include <rng_support.h> 164d168941SAndrew F. Davis 174d168941SAndrew F. Davis #define RNG_OUTPUT_L 0x0000 184d168941SAndrew F. Davis #define RNG_OUTPUT_H 0x0004 194d168941SAndrew F. Davis #define RNG_STATUS 0x0008 204d168941SAndrew F. Davis # define RNG_READY BIT(0) 214d168941SAndrew F. Davis # define SHUTDOWN_OFLO BIT(1) 224d168941SAndrew F. Davis #define RNG_INTMASK 0x000C 234d168941SAndrew F. Davis #define RNG_INTACK 0x0010 244d168941SAndrew F. Davis #define RNG_CONTROL 0x0014 254d168941SAndrew F. Davis # define ENABLE_TRNG BIT(10) 264d168941SAndrew F. Davis #define RNG_CONFIG 0x0018 274d168941SAndrew F. Davis #define RNG_ALARMCNT 0x001C 284d168941SAndrew F. Davis #define RNG_FROENABLE 0x0020 294d168941SAndrew F. Davis #define RNG_FRODETUNE 0x0024 304d168941SAndrew F. Davis #define RNG_ALARMMASK 0x0028 314d168941SAndrew F. Davis #define RNG_ALARMSTOP 0x002C 324d168941SAndrew F. Davis #define RNG_LFSR_L 0x0030 334d168941SAndrew F. Davis #define RNG_LFSR_M 0x0034 344d168941SAndrew F. Davis #define RNG_LFSR_H 0x0038 354d168941SAndrew F. Davis #define RNG_COUNT 0x003C 364d168941SAndrew F. Davis #define RNG_OPTIONS 0x0078 374d168941SAndrew F. Davis #define RNG_EIP_REV 0x007C 384d168941SAndrew F. Davis #define RNG_MMR_STATUS_EN 0x1FD8 394d168941SAndrew F. Davis #define RNG_REV 0x1FE0 404d168941SAndrew F. Davis #define RNG_SYS_CONFIG_REG 0x1FE4 414d168941SAndrew F. Davis # define RNG_AUTOIDLE BIT(0) 424d168941SAndrew F. Davis #define RNG_MMR_STATUS_SET 0x1FEC 434d168941SAndrew F. Davis #define RNG_SOFT_RESET_REG 0x1FF0 444d168941SAndrew F. Davis # define RNG_SOFT_RESET BIT(0) 454d168941SAndrew F. Davis #define RNG_IRQ_EOI_REG 0x1FF4 464d168941SAndrew F. Davis #define RNG_IRQSTATUS 0x1FF8 474d168941SAndrew F. Davis 484d168941SAndrew F. Davis #define RNG_CONTROL_STARTUP_CYCLES_SHIFT 16 494d168941SAndrew F. Davis #define RNG_CONTROL_STARTUP_CYCLES_MASK GENMASK_32(31, 16) 504d168941SAndrew F. Davis 514d168941SAndrew F. Davis #define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT 16 524d168941SAndrew F. Davis #define RNG_CONFIG_MAX_REFIL_CYCLES_MASK GENMASK_32(31, 16) 534d168941SAndrew F. Davis #define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT 0 544d168941SAndrew F. Davis #define RNG_CONFIG_MIN_REFIL_CYCLES_MASK GENMASK_32(7, 0) 554d168941SAndrew F. Davis 564d168941SAndrew F. Davis #define RNG_ALARMCNT_ALARM_TH_SHIFT 0 574d168941SAndrew F. Davis #define RNG_ALARMCNT_ALARM_TH_MASK GENMASK_32(7, 0) 584d168941SAndrew F. Davis #define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT 16 594d168941SAndrew F. Davis #define RNG_ALARMCNT_SHUTDOWN_TH_MASK GENMASK_32(20, 16) 604d168941SAndrew F. Davis 614d168941SAndrew F. Davis #define RNG_CONTROL_STARTUP_CYCLES 0xff 624d168941SAndrew F. Davis #define RNG_CONFIG_MIN_REFIL_CYCLES 0x21 634d168941SAndrew F. Davis #define RNG_CONFIG_MAX_REFIL_CYCLES 0x22 644d168941SAndrew F. Davis #define RNG_ALARM_THRESHOLD 0xff 654d168941SAndrew F. Davis #define RNG_SHUTDOWN_THRESHOLD 0x4 664d168941SAndrew F. Davis 674d168941SAndrew F. Davis #define RNG_FRO_MASK GENMASK_32(23, 0) 684d168941SAndrew F. Davis 694d168941SAndrew F. Davis #define RNG_REG_SIZE 0x2000 704d168941SAndrew F. Davis 71a5e82dc7SJerome Forissier register_phys_mem_pgdir(MEM_AREA_IO_SEC, RNG_BASE, RNG_REG_SIZE); 724d168941SAndrew F. Davis 734d168941SAndrew F. Davis static unsigned int rng_lock = SPINLOCK_UNLOCK; 74d11c29c3SAndrew Davis static vaddr_t rng; 754d168941SAndrew F. Davis 766594a67eSAndrew Davis static void dra7_rng_read64(uint32_t *low_word, uint32_t *high_word) 774d168941SAndrew F. Davis { 784d168941SAndrew F. Davis /* Is the result ready (available)? */ 79918bb3a5SEtienne Carriere while (!(io_read32(rng + RNG_STATUS) & RNG_READY)) { 804d168941SAndrew F. Davis /* Is the shutdown threshold reached? */ 81918bb3a5SEtienne Carriere if (io_read32(rng + RNG_STATUS) & SHUTDOWN_OFLO) { 82918bb3a5SEtienne Carriere uint32_t alarm = io_read32(rng + RNG_ALARMSTOP); 83918bb3a5SEtienne Carriere uint32_t tune = io_read32(rng + RNG_FRODETUNE); 84918bb3a5SEtienne Carriere 854d168941SAndrew F. Davis /* Clear the alarm events */ 86918bb3a5SEtienne Carriere io_write32(rng + RNG_ALARMMASK, 0x0); 87918bb3a5SEtienne Carriere io_write32(rng + RNG_ALARMSTOP, 0x0); 884d168941SAndrew F. Davis /* De-tune offending FROs */ 89918bb3a5SEtienne Carriere io_write32(rng + RNG_FRODETUNE, tune ^ alarm); 904d168941SAndrew F. Davis /* Re-enable the shut down FROs */ 91918bb3a5SEtienne Carriere io_write32(rng + RNG_FROENABLE, RNG_FRO_MASK); 924d168941SAndrew F. Davis /* Clear the shutdown overflow event */ 93918bb3a5SEtienne Carriere io_write32(rng + RNG_INTACK, SHUTDOWN_OFLO); 944d168941SAndrew F. Davis 954d168941SAndrew F. Davis DMSG("Fixed FRO shutdown\n"); 964d168941SAndrew F. Davis } 974d168941SAndrew F. Davis } 984d168941SAndrew F. Davis /* Read random value */ 996594a67eSAndrew Davis *low_word = io_read32(rng + RNG_OUTPUT_L); 1006594a67eSAndrew Davis *high_word = io_read32(rng + RNG_OUTPUT_H); 1014d168941SAndrew F. Davis /* Acknowledge read complete */ 102918bb3a5SEtienne Carriere io_write32(rng + RNG_INTACK, RNG_READY); 1034d168941SAndrew F. Davis } 1044d168941SAndrew F. Davis 105*671dbd1eSAndrew Davis TEE_Result hw_get_random_bytes(void *buf, size_t len) 1066594a67eSAndrew Davis { 1076594a67eSAndrew Davis static union { 1086594a67eSAndrew Davis uint32_t val[2]; 1096594a67eSAndrew Davis uint8_t byte[8]; 110*671dbd1eSAndrew Davis } fifo; 111*671dbd1eSAndrew Davis static size_t fifo_pos; 112*671dbd1eSAndrew Davis uint8_t *buffer = buf; 113*671dbd1eSAndrew Davis size_t buffer_pos = 0; 1146594a67eSAndrew Davis 115*671dbd1eSAndrew Davis while (buffer_pos < len) { 1166594a67eSAndrew Davis uint32_t exceptions = cpu_spin_lock_xsave(&rng_lock); 1176594a67eSAndrew Davis 118*671dbd1eSAndrew Davis /* Refill our FIFO */ 119*671dbd1eSAndrew Davis if (fifo_pos == 0) 120*671dbd1eSAndrew Davis dra7_rng_read64(&fifo.val[0], &fifo.val[1]); 1214d168941SAndrew F. Davis 122*671dbd1eSAndrew Davis buffer[buffer_pos++] = fifo.byte[fifo_pos++]; 123*671dbd1eSAndrew Davis fifo_pos %= 8; 1244d168941SAndrew F. Davis 125c6712bd0SAndrew Davis cpu_spin_unlock_xrestore(&rng_lock, exceptions); 126*671dbd1eSAndrew Davis } 1274d168941SAndrew F. Davis 128*671dbd1eSAndrew Davis return TEE_SUCCESS; 1294d168941SAndrew F. Davis } 1304d168941SAndrew F. Davis 1314d168941SAndrew F. Davis static TEE_Result dra7_rng_init(void) 1324d168941SAndrew F. Davis { 1334d168941SAndrew F. Davis uint32_t val; 1344d168941SAndrew F. Davis 135d11c29c3SAndrew Davis rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC, RNG_REG_SIZE); 136d11c29c3SAndrew Davis 1374d168941SAndrew F. Davis /* Execute a software reset */ 138918bb3a5SEtienne Carriere io_write32(rng + RNG_SOFT_RESET_REG, RNG_SOFT_RESET); 1394d168941SAndrew F. Davis 1404d168941SAndrew F. Davis /* Wait for the software reset completion by polling */ 141918bb3a5SEtienne Carriere while (io_read32(rng + RNG_SOFT_RESET_REG) & RNG_SOFT_RESET) 1424d168941SAndrew F. Davis ; 1434d168941SAndrew F. Davis 1444d168941SAndrew F. Davis /* Switch to low-power operating mode */ 145918bb3a5SEtienne Carriere io_write32(rng + RNG_SYS_CONFIG_REG, RNG_AUTOIDLE); 1464d168941SAndrew F. Davis 1474d168941SAndrew F. Davis /* 1484d168941SAndrew F. Davis * Select the number of clock input cycles to the 1494d168941SAndrew F. Davis * FROs between two samples 1504d168941SAndrew F. Davis */ 1514d168941SAndrew F. Davis val = 0; 1524d168941SAndrew F. Davis 1534d168941SAndrew F. Davis /* Ensure initial latency */ 1544d168941SAndrew F. Davis val |= RNG_CONFIG_MIN_REFIL_CYCLES << 1554d168941SAndrew F. Davis RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT; 1564d168941SAndrew F. Davis val |= RNG_CONFIG_MAX_REFIL_CYCLES << 1574d168941SAndrew F. Davis RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT; 158918bb3a5SEtienne Carriere io_write32(rng + RNG_CONFIG, val); 1594d168941SAndrew F. Davis 1604d168941SAndrew F. Davis /* Configure the desired FROs */ 161918bb3a5SEtienne Carriere io_write32(rng + RNG_FRODETUNE, 0x0); 1624d168941SAndrew F. Davis 1634d168941SAndrew F. Davis /* Enable all FROs */ 164918bb3a5SEtienne Carriere io_write32(rng + RNG_FROENABLE, 0xffffff); 1654d168941SAndrew F. Davis 1664d168941SAndrew F. Davis /* 1674d168941SAndrew F. Davis * Select the maximum number of samples after 1684d168941SAndrew F. Davis * which if a repeating pattern is still detected, an 1694d168941SAndrew F. Davis * alarm event is generated 1704d168941SAndrew F. Davis */ 1714d168941SAndrew F. Davis val = RNG_ALARM_THRESHOLD << RNG_ALARMCNT_ALARM_TH_SHIFT; 1724d168941SAndrew F. Davis 1734d168941SAndrew F. Davis /* 1744d168941SAndrew F. Davis * Set the shutdown threshold to the number of FROs 1754d168941SAndrew F. Davis * allowed to be shut downed 1764d168941SAndrew F. Davis */ 1774d168941SAndrew F. Davis val |= RNG_SHUTDOWN_THRESHOLD << RNG_ALARMCNT_SHUTDOWN_TH_SHIFT; 178918bb3a5SEtienne Carriere io_write32(rng + RNG_ALARMCNT, val); 1794d168941SAndrew F. Davis 1804d168941SAndrew F. Davis /* Enable the RNG module */ 1814d168941SAndrew F. Davis val = RNG_CONTROL_STARTUP_CYCLES << RNG_CONTROL_STARTUP_CYCLES_SHIFT; 1824d168941SAndrew F. Davis val |= ENABLE_TRNG; 183918bb3a5SEtienne Carriere io_write32(rng + RNG_CONTROL, val); 1844d168941SAndrew F. Davis 1854d168941SAndrew F. Davis IMSG("DRA7x TRNG initialized"); 1864d168941SAndrew F. Davis 1874d168941SAndrew F. Davis return TEE_SUCCESS; 1884d168941SAndrew F. Davis } 1894d168941SAndrew F. Davis driver_init(dra7_rng_init); 190