xref: /optee_os/core/drivers/dra7_rng.c (revision 78b7c7c7653f8bff42fe44d31a79d7f6bbfd4d47)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2016, Linaro Limited
4  * All rights reserved.
5  */
6 
7 #include <initcall.h>
8 #include <io.h>
9 #include <keep.h>
10 #include <kernel/interrupt.h>
11 #include <kernel/misc.h>
12 #include <kernel/spinlock.h>
13 #include <mm/core_memprot.h>
14 #include <mm/core_mmu.h>
15 #include <platform_config.h>
16 #include <rng_support.h>
17 
18 #define	RNG_OUTPUT_L            0x0000
19 #define	RNG_OUTPUT_H            0x0004
20 #define	RNG_STATUS              0x0008
21 #  define RNG_READY             BIT(0)
22 #  define SHUTDOWN_OFLO         BIT(1)
23 #define	RNG_INTMASK             0x000C
24 #define	RNG_INTACK              0x0010
25 #define	RNG_CONTROL             0x0014
26 #  define ENABLE_TRNG           BIT(10)
27 #define	RNG_CONFIG              0x0018
28 #define	RNG_ALARMCNT            0x001C
29 #define	RNG_FROENABLE           0x0020
30 #define	RNG_FRODETUNE           0x0024
31 #define	RNG_ALARMMASK           0x0028
32 #define	RNG_ALARMSTOP           0x002C
33 #define	RNG_LFSR_L              0x0030
34 #define	RNG_LFSR_M              0x0034
35 #define	RNG_LFSR_H              0x0038
36 #define	RNG_COUNT               0x003C
37 #define	RNG_OPTIONS             0x0078
38 #define	RNG_EIP_REV             0x007C
39 #define	RNG_MMR_STATUS_EN       0x1FD8
40 #define	RNG_REV                 0x1FE0
41 #define	RNG_SYS_CONFIG_REG      0x1FE4
42 #  define RNG_AUTOIDLE          BIT(0)
43 #define	RNG_MMR_STATUS_SET      0x1FEC
44 #define	RNG_SOFT_RESET_REG      0x1FF0
45 #  define RNG_SOFT_RESET        BIT(0)
46 #define	RNG_IRQ_EOI_REG         0x1FF4
47 #define	RNG_IRQSTATUS           0x1FF8
48 
49 #define RNG_CONTROL_STARTUP_CYCLES_SHIFT        16
50 #define RNG_CONTROL_STARTUP_CYCLES_MASK         GENMASK_32(31, 16)
51 
52 #define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT       16
53 #define RNG_CONFIG_MAX_REFIL_CYCLES_MASK        GENMASK_32(31, 16)
54 #define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT       0
55 #define RNG_CONFIG_MIN_REFIL_CYCLES_MASK        GENMASK_32(7, 0)
56 
57 #define RNG_ALARMCNT_ALARM_TH_SHIFT             0
58 #define RNG_ALARMCNT_ALARM_TH_MASK              GENMASK_32(7, 0)
59 #define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT          16
60 #define RNG_ALARMCNT_SHUTDOWN_TH_MASK           GENMASK_32(20, 16)
61 
62 #define RNG_CONTROL_STARTUP_CYCLES              0xff
63 #define RNG_CONFIG_MIN_REFIL_CYCLES             0x21
64 #define RNG_CONFIG_MAX_REFIL_CYCLES             0x22
65 #define RNG_ALARM_THRESHOLD                     0xff
66 #define RNG_SHUTDOWN_THRESHOLD                  0x4
67 
68 #define RNG_FRO_MASK    GENMASK_32(23, 0)
69 
70 #define RNG_REG_SIZE    0x2000
71 
72 register_phys_mem(MEM_AREA_IO_SEC, RNG_BASE, RNG_REG_SIZE);
73 
74 static unsigned int rng_lock = SPINLOCK_UNLOCK;
75 
76 uint8_t hw_get_random_byte(void)
77 {
78 	static int pos;
79 	static union {
80 		uint32_t val[2];
81 		uint8_t byte[8];
82 	} random;
83 	vaddr_t rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC);
84 	uint8_t ret;
85 
86 	uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL);
87 	cpu_spin_lock(&rng_lock);
88 
89 	if (!pos) {
90 		/* Is the result ready (available)? */
91 		while (!(read32(rng + RNG_STATUS) & RNG_READY)) {
92 			/* Is the shutdown threshold reached? */
93 			if (read32(rng + RNG_STATUS) & SHUTDOWN_OFLO) {
94 				uint32_t alarm = read32(rng + RNG_ALARMSTOP);
95 				uint32_t tuning = read32(rng + RNG_FRODETUNE);
96 				/* Clear the alarm events */
97 				write32(0x0, rng + RNG_ALARMMASK);
98 				write32(0x0, rng + RNG_ALARMSTOP);
99 				/* De-tune offending FROs */
100 				write32(tuning ^ alarm, rng + RNG_FRODETUNE);
101 				/* Re-enable the shut down FROs */
102 				write32(RNG_FRO_MASK, rng + RNG_FROENABLE);
103 				/* Clear the shutdown overflow event */
104 				write32(SHUTDOWN_OFLO, rng + RNG_INTACK);
105 
106 				DMSG("Fixed FRO shutdown\n");
107 			}
108 		}
109 		/* Read random value */
110 		random.val[0] = read32(rng + RNG_OUTPUT_L);
111 		random.val[1] = read32(rng + RNG_OUTPUT_H);
112 		/* Acknowledge read complete */
113 		write32(RNG_READY, rng + RNG_INTACK);
114 	}
115 
116 	ret = random.byte[pos];
117 
118 	pos = (pos + 1) % 8;
119 
120 	cpu_spin_unlock(&rng_lock);
121 	thread_set_exceptions(exceptions);
122 
123 	return ret;
124 }
125 
126 static TEE_Result dra7_rng_init(void)
127 {
128 	vaddr_t rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC);
129 	uint32_t val;
130 
131 	/* Execute a software reset */
132 	write32(RNG_SOFT_RESET, rng + RNG_SOFT_RESET_REG);
133 
134 	/* Wait for the software reset completion by polling */
135 	while (read32(rng + RNG_SOFT_RESET_REG) & RNG_SOFT_RESET)
136 		;
137 
138 	/* Switch to low-power operating mode */
139 	write32(RNG_AUTOIDLE, rng + RNG_SYS_CONFIG_REG);
140 
141 	/*
142 	 * Select the number of clock input cycles to the
143 	 * FROs between two samples
144 	 */
145 	val = 0;
146 
147 	/* Ensure initial latency */
148 	val |= RNG_CONFIG_MIN_REFIL_CYCLES <<
149 			RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT;
150 	val |= RNG_CONFIG_MAX_REFIL_CYCLES <<
151 			RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT;
152 	write32(val, rng + RNG_CONFIG);
153 
154 	/* Configure the desired FROs */
155 	write32(0x0, rng + RNG_FRODETUNE);
156 
157 	/* Enable all FROs */
158 	write32(0xffffff, rng + RNG_FROENABLE);
159 
160 	/*
161 	 * Select the maximum number of samples after
162 	 * which if a repeating pattern is still detected, an
163 	 * alarm event is generated
164 	 */
165 	val = RNG_ALARM_THRESHOLD << RNG_ALARMCNT_ALARM_TH_SHIFT;
166 
167 	/*
168 	 * Set the shutdown threshold to the number of FROs
169 	 * allowed to be shut downed
170 	 */
171 	val |= RNG_SHUTDOWN_THRESHOLD << RNG_ALARMCNT_SHUTDOWN_TH_SHIFT;
172 	write32(val, rng + RNG_ALARMCNT);
173 
174 	/* Enable the RNG module */
175 	val = RNG_CONTROL_STARTUP_CYCLES << RNG_CONTROL_STARTUP_CYCLES_SHIFT;
176 	val |= ENABLE_TRNG;
177 	write32(val, rng + RNG_CONTROL);
178 
179 	IMSG("DRA7x TRNG initialized");
180 
181 	return TEE_SUCCESS;
182 }
183 driver_init(dra7_rng_init);
184