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