1*4d168941SAndrew F. Davis /* 2*4d168941SAndrew F. Davis * Copyright (c) 2016, Linaro Limited 3*4d168941SAndrew F. Davis * All rights reserved. 4*4d168941SAndrew F. Davis * 5*4d168941SAndrew F. Davis * Redistribution and use in source and binary forms, with or without 6*4d168941SAndrew F. Davis * modification, are permitted provided that the following conditions are met: 7*4d168941SAndrew F. Davis * 8*4d168941SAndrew F. Davis * 1. Redistributions of source code must retain the above copyright notice, 9*4d168941SAndrew F. Davis * this list of conditions and the following disclaimer. 10*4d168941SAndrew F. Davis * 11*4d168941SAndrew F. Davis * 2. Redistributions in binary form must reproduce the above copyright notice, 12*4d168941SAndrew F. Davis * this list of conditions and the following disclaimer in the documentation 13*4d168941SAndrew F. Davis * and/or other materials provided with the distribution. 14*4d168941SAndrew F. Davis * 15*4d168941SAndrew F. Davis * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16*4d168941SAndrew F. Davis * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*4d168941SAndrew F. Davis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*4d168941SAndrew F. Davis * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19*4d168941SAndrew F. Davis * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20*4d168941SAndrew F. Davis * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21*4d168941SAndrew F. Davis * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22*4d168941SAndrew F. Davis * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23*4d168941SAndrew F. Davis * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24*4d168941SAndrew F. Davis * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25*4d168941SAndrew F. Davis * POSSIBILITY OF SUCH DAMAGE. 26*4d168941SAndrew F. Davis */ 27*4d168941SAndrew F. Davis 28*4d168941SAndrew F. Davis #include <initcall.h> 29*4d168941SAndrew F. Davis #include <io.h> 30*4d168941SAndrew F. Davis #include <keep.h> 31*4d168941SAndrew F. Davis #include <kernel/interrupt.h> 32*4d168941SAndrew F. Davis #include <kernel/misc.h> 33*4d168941SAndrew F. Davis #include <kernel/spinlock.h> 34*4d168941SAndrew F. Davis #include <mm/core_memprot.h> 35*4d168941SAndrew F. Davis #include <mm/core_mmu.h> 36*4d168941SAndrew F. Davis #include <platform_config.h> 37*4d168941SAndrew F. Davis #include <rng_support.h> 38*4d168941SAndrew F. Davis 39*4d168941SAndrew F. Davis #define RNG_OUTPUT_L 0x0000 40*4d168941SAndrew F. Davis #define RNG_OUTPUT_H 0x0004 41*4d168941SAndrew F. Davis #define RNG_STATUS 0x0008 42*4d168941SAndrew F. Davis # define RNG_READY BIT(0) 43*4d168941SAndrew F. Davis # define SHUTDOWN_OFLO BIT(1) 44*4d168941SAndrew F. Davis #define RNG_INTMASK 0x000C 45*4d168941SAndrew F. Davis #define RNG_INTACK 0x0010 46*4d168941SAndrew F. Davis #define RNG_CONTROL 0x0014 47*4d168941SAndrew F. Davis # define ENABLE_TRNG BIT(10) 48*4d168941SAndrew F. Davis #define RNG_CONFIG 0x0018 49*4d168941SAndrew F. Davis #define RNG_ALARMCNT 0x001C 50*4d168941SAndrew F. Davis #define RNG_FROENABLE 0x0020 51*4d168941SAndrew F. Davis #define RNG_FRODETUNE 0x0024 52*4d168941SAndrew F. Davis #define RNG_ALARMMASK 0x0028 53*4d168941SAndrew F. Davis #define RNG_ALARMSTOP 0x002C 54*4d168941SAndrew F. Davis #define RNG_LFSR_L 0x0030 55*4d168941SAndrew F. Davis #define RNG_LFSR_M 0x0034 56*4d168941SAndrew F. Davis #define RNG_LFSR_H 0x0038 57*4d168941SAndrew F. Davis #define RNG_COUNT 0x003C 58*4d168941SAndrew F. Davis #define RNG_OPTIONS 0x0078 59*4d168941SAndrew F. Davis #define RNG_EIP_REV 0x007C 60*4d168941SAndrew F. Davis #define RNG_MMR_STATUS_EN 0x1FD8 61*4d168941SAndrew F. Davis #define RNG_REV 0x1FE0 62*4d168941SAndrew F. Davis #define RNG_SYS_CONFIG_REG 0x1FE4 63*4d168941SAndrew F. Davis # define RNG_AUTOIDLE BIT(0) 64*4d168941SAndrew F. Davis #define RNG_MMR_STATUS_SET 0x1FEC 65*4d168941SAndrew F. Davis #define RNG_SOFT_RESET_REG 0x1FF0 66*4d168941SAndrew F. Davis # define RNG_SOFT_RESET BIT(0) 67*4d168941SAndrew F. Davis #define RNG_IRQ_EOI_REG 0x1FF4 68*4d168941SAndrew F. Davis #define RNG_IRQSTATUS 0x1FF8 69*4d168941SAndrew F. Davis 70*4d168941SAndrew F. Davis #define RNG_CONTROL_STARTUP_CYCLES_SHIFT 16 71*4d168941SAndrew F. Davis #define RNG_CONTROL_STARTUP_CYCLES_MASK GENMASK_32(31, 16) 72*4d168941SAndrew F. Davis 73*4d168941SAndrew F. Davis #define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT 16 74*4d168941SAndrew F. Davis #define RNG_CONFIG_MAX_REFIL_CYCLES_MASK GENMASK_32(31, 16) 75*4d168941SAndrew F. Davis #define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT 0 76*4d168941SAndrew F. Davis #define RNG_CONFIG_MIN_REFIL_CYCLES_MASK GENMASK_32(7, 0) 77*4d168941SAndrew F. Davis 78*4d168941SAndrew F. Davis #define RNG_ALARMCNT_ALARM_TH_SHIFT 0 79*4d168941SAndrew F. Davis #define RNG_ALARMCNT_ALARM_TH_MASK GENMASK_32(7, 0) 80*4d168941SAndrew F. Davis #define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT 16 81*4d168941SAndrew F. Davis #define RNG_ALARMCNT_SHUTDOWN_TH_MASK GENMASK_32(20, 16) 82*4d168941SAndrew F. Davis 83*4d168941SAndrew F. Davis #define RNG_CONTROL_STARTUP_CYCLES 0xff 84*4d168941SAndrew F. Davis #define RNG_CONFIG_MIN_REFIL_CYCLES 0x21 85*4d168941SAndrew F. Davis #define RNG_CONFIG_MAX_REFIL_CYCLES 0x22 86*4d168941SAndrew F. Davis #define RNG_ALARM_THRESHOLD 0xff 87*4d168941SAndrew F. Davis #define RNG_SHUTDOWN_THRESHOLD 0x4 88*4d168941SAndrew F. Davis 89*4d168941SAndrew F. Davis #define RNG_FRO_MASK GENMASK_32(23, 0) 90*4d168941SAndrew F. Davis 91*4d168941SAndrew F. Davis #define RNG_REG_SIZE 0x2000 92*4d168941SAndrew F. Davis 93*4d168941SAndrew F. Davis register_phys_mem(MEM_AREA_IO_SEC, RNG_BASE, RNG_REG_SIZE); 94*4d168941SAndrew F. Davis 95*4d168941SAndrew F. Davis static unsigned int rng_lock = SPINLOCK_UNLOCK; 96*4d168941SAndrew F. Davis 97*4d168941SAndrew F. Davis uint8_t hw_get_random_byte(void) 98*4d168941SAndrew F. Davis { 99*4d168941SAndrew F. Davis static int pos; 100*4d168941SAndrew F. Davis static union { 101*4d168941SAndrew F. Davis uint32_t val[2]; 102*4d168941SAndrew F. Davis uint8_t byte[8]; 103*4d168941SAndrew F. Davis } random; 104*4d168941SAndrew F. Davis vaddr_t rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC); 105*4d168941SAndrew F. Davis uint8_t ret; 106*4d168941SAndrew F. Davis 107*4d168941SAndrew F. Davis uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL); 108*4d168941SAndrew F. Davis cpu_spin_lock(&rng_lock); 109*4d168941SAndrew F. Davis 110*4d168941SAndrew F. Davis if (!pos) { 111*4d168941SAndrew F. Davis /* Is the result ready (available)? */ 112*4d168941SAndrew F. Davis while (!(read32(rng + RNG_STATUS) & RNG_READY)) { 113*4d168941SAndrew F. Davis /* Is the shutdown threshold reached? */ 114*4d168941SAndrew F. Davis if (read32(rng + RNG_STATUS) & SHUTDOWN_OFLO) { 115*4d168941SAndrew F. Davis uint32_t alarm = read32(rng + RNG_ALARMSTOP); 116*4d168941SAndrew F. Davis uint32_t tuning = read32(rng + RNG_FRODETUNE); 117*4d168941SAndrew F. Davis /* Clear the alarm events */ 118*4d168941SAndrew F. Davis write32(0x0, rng + RNG_ALARMMASK); 119*4d168941SAndrew F. Davis write32(0x0, rng + RNG_ALARMSTOP); 120*4d168941SAndrew F. Davis /* De-tune offending FROs */ 121*4d168941SAndrew F. Davis write32(tuning ^ alarm, rng + RNG_FRODETUNE); 122*4d168941SAndrew F. Davis /* Re-enable the shut down FROs */ 123*4d168941SAndrew F. Davis write32(RNG_FRO_MASK, rng + RNG_FROENABLE); 124*4d168941SAndrew F. Davis /* Clear the shutdown overflow event */ 125*4d168941SAndrew F. Davis write32(SHUTDOWN_OFLO, rng + RNG_INTACK); 126*4d168941SAndrew F. Davis 127*4d168941SAndrew F. Davis DMSG("Fixed FRO shutdown\n"); 128*4d168941SAndrew F. Davis } 129*4d168941SAndrew F. Davis } 130*4d168941SAndrew F. Davis /* Read random value */ 131*4d168941SAndrew F. Davis random.val[0] = read32(rng + RNG_OUTPUT_L); 132*4d168941SAndrew F. Davis random.val[1] = read32(rng + RNG_OUTPUT_H); 133*4d168941SAndrew F. Davis /* Acknowledge read complete */ 134*4d168941SAndrew F. Davis write32(RNG_READY, rng + RNG_INTACK); 135*4d168941SAndrew F. Davis } 136*4d168941SAndrew F. Davis 137*4d168941SAndrew F. Davis ret = random.byte[pos]; 138*4d168941SAndrew F. Davis 139*4d168941SAndrew F. Davis pos = (pos + 1) % 8; 140*4d168941SAndrew F. Davis 141*4d168941SAndrew F. Davis cpu_spin_unlock(&rng_lock); 142*4d168941SAndrew F. Davis thread_set_exceptions(exceptions); 143*4d168941SAndrew F. Davis 144*4d168941SAndrew F. Davis return ret; 145*4d168941SAndrew F. Davis } 146*4d168941SAndrew F. Davis 147*4d168941SAndrew F. Davis static TEE_Result dra7_rng_init(void) 148*4d168941SAndrew F. Davis { 149*4d168941SAndrew F. Davis vaddr_t rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC); 150*4d168941SAndrew F. Davis uint32_t val; 151*4d168941SAndrew F. Davis 152*4d168941SAndrew F. Davis /* Execute a software reset */ 153*4d168941SAndrew F. Davis write32(RNG_SOFT_RESET, rng + RNG_SOFT_RESET_REG); 154*4d168941SAndrew F. Davis 155*4d168941SAndrew F. Davis /* Wait for the software reset completion by polling */ 156*4d168941SAndrew F. Davis while (read32(rng + RNG_SOFT_RESET_REG) & RNG_SOFT_RESET) 157*4d168941SAndrew F. Davis ; 158*4d168941SAndrew F. Davis 159*4d168941SAndrew F. Davis /* Switch to low-power operating mode */ 160*4d168941SAndrew F. Davis write32(RNG_AUTOIDLE, rng + RNG_SYS_CONFIG_REG); 161*4d168941SAndrew F. Davis 162*4d168941SAndrew F. Davis /* 163*4d168941SAndrew F. Davis * Select the number of clock input cycles to the 164*4d168941SAndrew F. Davis * FROs between two samples 165*4d168941SAndrew F. Davis */ 166*4d168941SAndrew F. Davis val = 0; 167*4d168941SAndrew F. Davis 168*4d168941SAndrew F. Davis /* Ensure initial latency */ 169*4d168941SAndrew F. Davis val |= RNG_CONFIG_MIN_REFIL_CYCLES << 170*4d168941SAndrew F. Davis RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT; 171*4d168941SAndrew F. Davis val |= RNG_CONFIG_MAX_REFIL_CYCLES << 172*4d168941SAndrew F. Davis RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT; 173*4d168941SAndrew F. Davis write32(val, rng + RNG_CONFIG); 174*4d168941SAndrew F. Davis 175*4d168941SAndrew F. Davis /* Configure the desired FROs */ 176*4d168941SAndrew F. Davis write32(0x0, rng + RNG_FRODETUNE); 177*4d168941SAndrew F. Davis 178*4d168941SAndrew F. Davis /* Enable all FROs */ 179*4d168941SAndrew F. Davis write32(0xffffff, rng + RNG_FROENABLE); 180*4d168941SAndrew F. Davis 181*4d168941SAndrew F. Davis /* 182*4d168941SAndrew F. Davis * Select the maximum number of samples after 183*4d168941SAndrew F. Davis * which if a repeating pattern is still detected, an 184*4d168941SAndrew F. Davis * alarm event is generated 185*4d168941SAndrew F. Davis */ 186*4d168941SAndrew F. Davis val = RNG_ALARM_THRESHOLD << RNG_ALARMCNT_ALARM_TH_SHIFT; 187*4d168941SAndrew F. Davis 188*4d168941SAndrew F. Davis /* 189*4d168941SAndrew F. Davis * Set the shutdown threshold to the number of FROs 190*4d168941SAndrew F. Davis * allowed to be shut downed 191*4d168941SAndrew F. Davis */ 192*4d168941SAndrew F. Davis val |= RNG_SHUTDOWN_THRESHOLD << RNG_ALARMCNT_SHUTDOWN_TH_SHIFT; 193*4d168941SAndrew F. Davis write32(val, rng + RNG_ALARMCNT); 194*4d168941SAndrew F. Davis 195*4d168941SAndrew F. Davis /* Enable the RNG module */ 196*4d168941SAndrew F. Davis val = RNG_CONTROL_STARTUP_CYCLES << RNG_CONTROL_STARTUP_CYCLES_SHIFT; 197*4d168941SAndrew F. Davis val |= ENABLE_TRNG; 198*4d168941SAndrew F. Davis write32(val, rng + RNG_CONTROL); 199*4d168941SAndrew F. Davis 200*4d168941SAndrew F. Davis IMSG("DRA7x TRNG initialized"); 201*4d168941SAndrew F. Davis 202*4d168941SAndrew F. Davis return TEE_SUCCESS; 203*4d168941SAndrew F. Davis } 204*4d168941SAndrew F. Davis driver_init(dra7_rng_init); 205