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