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