xref: /optee_os/core/drivers/dra7_rng.c (revision 1bb929836182ecb96d2d9d268daa807c67596396)
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