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