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