1*1bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 24d168941SAndrew F. Davis /* 34d168941SAndrew F. Davis * Copyright (c) 2016, Linaro Limited 44d168941SAndrew F. Davis * All rights reserved. 54d168941SAndrew F. Davis * 64d168941SAndrew F. Davis * Redistribution and use in source and binary forms, with or without 74d168941SAndrew F. Davis * modification, are permitted provided that the following conditions are met: 84d168941SAndrew F. Davis * 94d168941SAndrew F. Davis * 1. Redistributions of source code must retain the above copyright notice, 104d168941SAndrew F. Davis * this list of conditions and the following disclaimer. 114d168941SAndrew F. Davis * 124d168941SAndrew F. Davis * 2. Redistributions in binary form must reproduce the above copyright notice, 134d168941SAndrew F. Davis * this list of conditions and the following disclaimer in the documentation 144d168941SAndrew F. Davis * and/or other materials provided with the distribution. 154d168941SAndrew F. Davis * 164d168941SAndrew F. Davis * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 174d168941SAndrew F. Davis * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 184d168941SAndrew F. Davis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 194d168941SAndrew F. Davis * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 204d168941SAndrew F. Davis * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 214d168941SAndrew F. Davis * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 224d168941SAndrew F. Davis * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 234d168941SAndrew F. Davis * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 244d168941SAndrew F. Davis * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 254d168941SAndrew F. Davis * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 264d168941SAndrew F. Davis * POSSIBILITY OF SUCH DAMAGE. 274d168941SAndrew F. Davis */ 284d168941SAndrew F. Davis 294d168941SAndrew F. Davis #include <initcall.h> 304d168941SAndrew F. Davis #include <io.h> 314d168941SAndrew F. Davis #include <keep.h> 324d168941SAndrew F. Davis #include <kernel/interrupt.h> 334d168941SAndrew F. Davis #include <kernel/misc.h> 344d168941SAndrew F. Davis #include <kernel/spinlock.h> 354d168941SAndrew F. Davis #include <mm/core_memprot.h> 364d168941SAndrew F. Davis #include <mm/core_mmu.h> 374d168941SAndrew F. Davis #include <platform_config.h> 384d168941SAndrew F. Davis #include <rng_support.h> 394d168941SAndrew F. Davis 404d168941SAndrew F. Davis #define RNG_OUTPUT_L 0x0000 414d168941SAndrew F. Davis #define RNG_OUTPUT_H 0x0004 424d168941SAndrew F. Davis #define RNG_STATUS 0x0008 434d168941SAndrew F. Davis # define RNG_READY BIT(0) 444d168941SAndrew F. Davis # define SHUTDOWN_OFLO BIT(1) 454d168941SAndrew F. Davis #define RNG_INTMASK 0x000C 464d168941SAndrew F. Davis #define RNG_INTACK 0x0010 474d168941SAndrew F. Davis #define RNG_CONTROL 0x0014 484d168941SAndrew F. Davis # define ENABLE_TRNG BIT(10) 494d168941SAndrew F. Davis #define RNG_CONFIG 0x0018 504d168941SAndrew F. Davis #define RNG_ALARMCNT 0x001C 514d168941SAndrew F. Davis #define RNG_FROENABLE 0x0020 524d168941SAndrew F. Davis #define RNG_FRODETUNE 0x0024 534d168941SAndrew F. Davis #define RNG_ALARMMASK 0x0028 544d168941SAndrew F. Davis #define RNG_ALARMSTOP 0x002C 554d168941SAndrew F. Davis #define RNG_LFSR_L 0x0030 564d168941SAndrew F. Davis #define RNG_LFSR_M 0x0034 574d168941SAndrew F. Davis #define RNG_LFSR_H 0x0038 584d168941SAndrew F. Davis #define RNG_COUNT 0x003C 594d168941SAndrew F. Davis #define RNG_OPTIONS 0x0078 604d168941SAndrew F. Davis #define RNG_EIP_REV 0x007C 614d168941SAndrew F. Davis #define RNG_MMR_STATUS_EN 0x1FD8 624d168941SAndrew F. Davis #define RNG_REV 0x1FE0 634d168941SAndrew F. Davis #define RNG_SYS_CONFIG_REG 0x1FE4 644d168941SAndrew F. Davis # define RNG_AUTOIDLE BIT(0) 654d168941SAndrew F. Davis #define RNG_MMR_STATUS_SET 0x1FEC 664d168941SAndrew F. Davis #define RNG_SOFT_RESET_REG 0x1FF0 674d168941SAndrew F. Davis # define RNG_SOFT_RESET BIT(0) 684d168941SAndrew F. Davis #define RNG_IRQ_EOI_REG 0x1FF4 694d168941SAndrew F. Davis #define RNG_IRQSTATUS 0x1FF8 704d168941SAndrew F. Davis 714d168941SAndrew F. Davis #define RNG_CONTROL_STARTUP_CYCLES_SHIFT 16 724d168941SAndrew F. Davis #define RNG_CONTROL_STARTUP_CYCLES_MASK GENMASK_32(31, 16) 734d168941SAndrew F. Davis 744d168941SAndrew F. Davis #define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT 16 754d168941SAndrew F. Davis #define RNG_CONFIG_MAX_REFIL_CYCLES_MASK GENMASK_32(31, 16) 764d168941SAndrew F. Davis #define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT 0 774d168941SAndrew F. Davis #define RNG_CONFIG_MIN_REFIL_CYCLES_MASK GENMASK_32(7, 0) 784d168941SAndrew F. Davis 794d168941SAndrew F. Davis #define RNG_ALARMCNT_ALARM_TH_SHIFT 0 804d168941SAndrew F. Davis #define RNG_ALARMCNT_ALARM_TH_MASK GENMASK_32(7, 0) 814d168941SAndrew F. Davis #define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT 16 824d168941SAndrew F. Davis #define RNG_ALARMCNT_SHUTDOWN_TH_MASK GENMASK_32(20, 16) 834d168941SAndrew F. Davis 844d168941SAndrew F. Davis #define RNG_CONTROL_STARTUP_CYCLES 0xff 854d168941SAndrew F. Davis #define RNG_CONFIG_MIN_REFIL_CYCLES 0x21 864d168941SAndrew F. Davis #define RNG_CONFIG_MAX_REFIL_CYCLES 0x22 874d168941SAndrew F. Davis #define RNG_ALARM_THRESHOLD 0xff 884d168941SAndrew F. Davis #define RNG_SHUTDOWN_THRESHOLD 0x4 894d168941SAndrew F. Davis 904d168941SAndrew F. Davis #define RNG_FRO_MASK GENMASK_32(23, 0) 914d168941SAndrew F. Davis 924d168941SAndrew F. Davis #define RNG_REG_SIZE 0x2000 934d168941SAndrew F. Davis 944d168941SAndrew F. Davis register_phys_mem(MEM_AREA_IO_SEC, RNG_BASE, RNG_REG_SIZE); 954d168941SAndrew F. Davis 964d168941SAndrew F. Davis static unsigned int rng_lock = SPINLOCK_UNLOCK; 974d168941SAndrew F. Davis 984d168941SAndrew F. Davis uint8_t hw_get_random_byte(void) 994d168941SAndrew F. Davis { 1004d168941SAndrew F. Davis static int pos; 1014d168941SAndrew F. Davis static union { 1024d168941SAndrew F. Davis uint32_t val[2]; 1034d168941SAndrew F. Davis uint8_t byte[8]; 1044d168941SAndrew F. Davis } random; 1054d168941SAndrew F. Davis vaddr_t rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC); 1064d168941SAndrew F. Davis uint8_t ret; 1074d168941SAndrew F. Davis 1084d168941SAndrew F. Davis uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL); 1094d168941SAndrew F. Davis cpu_spin_lock(&rng_lock); 1104d168941SAndrew F. Davis 1114d168941SAndrew F. Davis if (!pos) { 1124d168941SAndrew F. Davis /* Is the result ready (available)? */ 1134d168941SAndrew F. Davis while (!(read32(rng + RNG_STATUS) & RNG_READY)) { 1144d168941SAndrew F. Davis /* Is the shutdown threshold reached? */ 1154d168941SAndrew F. Davis if (read32(rng + RNG_STATUS) & SHUTDOWN_OFLO) { 1164d168941SAndrew F. Davis uint32_t alarm = read32(rng + RNG_ALARMSTOP); 1174d168941SAndrew F. Davis uint32_t tuning = read32(rng + RNG_FRODETUNE); 1184d168941SAndrew F. Davis /* Clear the alarm events */ 1194d168941SAndrew F. Davis write32(0x0, rng + RNG_ALARMMASK); 1204d168941SAndrew F. Davis write32(0x0, rng + RNG_ALARMSTOP); 1214d168941SAndrew F. Davis /* De-tune offending FROs */ 1224d168941SAndrew F. Davis write32(tuning ^ alarm, rng + RNG_FRODETUNE); 1234d168941SAndrew F. Davis /* Re-enable the shut down FROs */ 1244d168941SAndrew F. Davis write32(RNG_FRO_MASK, rng + RNG_FROENABLE); 1254d168941SAndrew F. Davis /* Clear the shutdown overflow event */ 1264d168941SAndrew F. Davis write32(SHUTDOWN_OFLO, rng + RNG_INTACK); 1274d168941SAndrew F. Davis 1284d168941SAndrew F. Davis DMSG("Fixed FRO shutdown\n"); 1294d168941SAndrew F. Davis } 1304d168941SAndrew F. Davis } 1314d168941SAndrew F. Davis /* Read random value */ 1324d168941SAndrew F. Davis random.val[0] = read32(rng + RNG_OUTPUT_L); 1334d168941SAndrew F. Davis random.val[1] = read32(rng + RNG_OUTPUT_H); 1344d168941SAndrew F. Davis /* Acknowledge read complete */ 1354d168941SAndrew F. Davis write32(RNG_READY, rng + RNG_INTACK); 1364d168941SAndrew F. Davis } 1374d168941SAndrew F. Davis 1384d168941SAndrew F. Davis ret = random.byte[pos]; 1394d168941SAndrew F. Davis 1404d168941SAndrew F. Davis pos = (pos + 1) % 8; 1414d168941SAndrew F. Davis 1424d168941SAndrew F. Davis cpu_spin_unlock(&rng_lock); 1434d168941SAndrew F. Davis thread_set_exceptions(exceptions); 1444d168941SAndrew F. Davis 1454d168941SAndrew F. Davis return ret; 1464d168941SAndrew F. Davis } 1474d168941SAndrew F. Davis 1484d168941SAndrew F. Davis static TEE_Result dra7_rng_init(void) 1494d168941SAndrew F. Davis { 1504d168941SAndrew F. Davis vaddr_t rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC); 1514d168941SAndrew F. Davis uint32_t val; 1524d168941SAndrew F. Davis 1534d168941SAndrew F. Davis /* Execute a software reset */ 1544d168941SAndrew F. Davis write32(RNG_SOFT_RESET, rng + RNG_SOFT_RESET_REG); 1554d168941SAndrew F. Davis 1564d168941SAndrew F. Davis /* Wait for the software reset completion by polling */ 1574d168941SAndrew F. Davis while (read32(rng + RNG_SOFT_RESET_REG) & RNG_SOFT_RESET) 1584d168941SAndrew F. Davis ; 1594d168941SAndrew F. Davis 1604d168941SAndrew F. Davis /* Switch to low-power operating mode */ 1614d168941SAndrew F. Davis write32(RNG_AUTOIDLE, rng + RNG_SYS_CONFIG_REG); 1624d168941SAndrew F. Davis 1634d168941SAndrew F. Davis /* 1644d168941SAndrew F. Davis * Select the number of clock input cycles to the 1654d168941SAndrew F. Davis * FROs between two samples 1664d168941SAndrew F. Davis */ 1674d168941SAndrew F. Davis val = 0; 1684d168941SAndrew F. Davis 1694d168941SAndrew F. Davis /* Ensure initial latency */ 1704d168941SAndrew F. Davis val |= RNG_CONFIG_MIN_REFIL_CYCLES << 1714d168941SAndrew F. Davis RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT; 1724d168941SAndrew F. Davis val |= RNG_CONFIG_MAX_REFIL_CYCLES << 1734d168941SAndrew F. Davis RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT; 1744d168941SAndrew F. Davis write32(val, rng + RNG_CONFIG); 1754d168941SAndrew F. Davis 1764d168941SAndrew F. Davis /* Configure the desired FROs */ 1774d168941SAndrew F. Davis write32(0x0, rng + RNG_FRODETUNE); 1784d168941SAndrew F. Davis 1794d168941SAndrew F. Davis /* Enable all FROs */ 1804d168941SAndrew F. Davis write32(0xffffff, rng + RNG_FROENABLE); 1814d168941SAndrew F. Davis 1824d168941SAndrew F. Davis /* 1834d168941SAndrew F. Davis * Select the maximum number of samples after 1844d168941SAndrew F. Davis * which if a repeating pattern is still detected, an 1854d168941SAndrew F. Davis * alarm event is generated 1864d168941SAndrew F. Davis */ 1874d168941SAndrew F. Davis val = RNG_ALARM_THRESHOLD << RNG_ALARMCNT_ALARM_TH_SHIFT; 1884d168941SAndrew F. Davis 1894d168941SAndrew F. Davis /* 1904d168941SAndrew F. Davis * Set the shutdown threshold to the number of FROs 1914d168941SAndrew F. Davis * allowed to be shut downed 1924d168941SAndrew F. Davis */ 1934d168941SAndrew F. Davis val |= RNG_SHUTDOWN_THRESHOLD << RNG_ALARMCNT_SHUTDOWN_TH_SHIFT; 1944d168941SAndrew F. Davis write32(val, rng + RNG_ALARMCNT); 1954d168941SAndrew F. Davis 1964d168941SAndrew F. Davis /* Enable the RNG module */ 1974d168941SAndrew F. Davis val = RNG_CONTROL_STARTUP_CYCLES << RNG_CONTROL_STARTUP_CYCLES_SHIFT; 1984d168941SAndrew F. Davis val |= ENABLE_TRNG; 1994d168941SAndrew F. Davis write32(val, rng + RNG_CONTROL); 2004d168941SAndrew F. Davis 2014d168941SAndrew F. Davis IMSG("DRA7x TRNG initialized"); 2024d168941SAndrew F. Davis 2034d168941SAndrew F. Davis return TEE_SUCCESS; 2044d168941SAndrew F. Davis } 2054d168941SAndrew F. Davis driver_init(dra7_rng_init); 206