xref: /optee_os/core/arch/arm/plat-k3/drivers/eip76d_trng.c (revision 5b6c7df764e5e20f9c3dc2dcb97588e562893115)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Texas Instruments K3 EIP76D TRNG Driver
4  *
5  * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
6  *	Andrew Davis <afd@ti.com>
7  */
8 
9 #include <initcall.h>
10 #include <io.h>
11 #include <keep.h>
12 #include <kernel/interrupt.h>
13 #include <kernel/misc.h>
14 #include <kernel/spinlock.h>
15 #include <mm/core_memprot.h>
16 #include <mm/core_mmu.h>
17 #include <platform_config.h>
18 #include <rng_support.h>
19 
20 #include "eip76d_trng.h"
21 
22 #define	RNG_OUTPUT_0            0x00
23 #define	RNG_OUTPUT_1            0x04
24 #define	RNG_OUTPUT_2            0x08
25 #define	RNG_OUTPUT_3            0x0C
26 #define	RNG_STATUS              0x10
27 #define RNG_READY               BIT(0)
28 #define SHUTDOWN_OFLO           BIT(1)
29 #define	RNG_INTACK              0x10
30 #define	RNG_CONTROL             0x14
31 #define ENABLE_TRNG             BIT(10)
32 #define	RNG_CONFIG              0x18
33 #define	RNG_ALARMCNT            0x1C
34 #define	RNG_FROENABLE           0x20
35 #define	RNG_FRODETUNE           0x24
36 #define	RNG_ALARMMASK           0x28
37 #define	RNG_ALARMSTOP           0x2C
38 #define	RNG_OPTIONS             0x78
39 #define	RNG_EIP_REV             0x7C
40 
41 #define RNG_CONTROL_STARTUP_CYCLES_SHIFT        16
42 #define RNG_CONTROL_STARTUP_CYCLES_MASK         GENMASK_32(31, 16)
43 
44 #define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT       16
45 #define RNG_CONFIG_MAX_REFIL_CYCLES_MASK        GENMASK_32(31, 16)
46 #define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT       0
47 #define RNG_CONFIG_MIN_REFIL_CYCLES_MASK        GENMASK_32(7, 0)
48 
49 #define RNG_ALARMCNT_ALARM_TH_SHIFT             0
50 #define RNG_ALARMCNT_ALARM_TH_MASK              GENMASK_32(7, 0)
51 #define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT          16
52 #define RNG_ALARMCNT_SHUTDOWN_TH_MASK           GENMASK_32(20, 16)
53 
54 #define RNG_CONTROL_STARTUP_CYCLES              0xff
55 #define RNG_CONFIG_MIN_REFIL_CYCLES             0x5
56 #define RNG_CONFIG_MAX_REFIL_CYCLES             0x22
57 #define RNG_ALARM_THRESHOLD                     0xff
58 #define RNG_SHUTDOWN_THRESHOLD                  0x4
59 
60 #define RNG_FRO_MASK    GENMASK_32(23, 0)
61 
62 register_phys_mem_pgdir(MEM_AREA_IO_SEC, RNG_BASE, RNG_REG_SIZE);
63 
64 static struct mutex fifo_lock = MUTEX_INITIALIZER;
65 static vaddr_t rng;
66 
eip76d_rng_is_enabled(void)67 static bool eip76d_rng_is_enabled(void)
68 {
69 	return io_read32(rng + RNG_CONTROL) & ENABLE_TRNG;
70 }
71 
eip76d_rng_init_seq(void)72 static void eip76d_rng_init_seq(void)
73 {
74 	uint32_t val = 0;
75 
76 	/* Ensure initial latency */
77 	val |= RNG_CONFIG_MIN_REFIL_CYCLES << RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT;
78 	val |= RNG_CONFIG_MAX_REFIL_CYCLES << RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT;
79 	io_write32(rng + RNG_CONFIG, val);
80 
81 	/* Configure the desired FROs */
82 	io_write32(rng + RNG_FRODETUNE, 0x0);
83 
84 	/* Enable all FROs */
85 	io_write32(rng + RNG_FROENABLE, 0xffffff);
86 
87 	io_write32(rng + RNG_CONTROL, ENABLE_TRNG);
88 }
89 
eip76d_rng_read128(uint32_t * word0,uint32_t * word1,uint32_t * word2,uint32_t * word3)90 static void eip76d_rng_read128(uint32_t *word0, uint32_t *word1,
91 			       uint32_t *word2, uint32_t *word3)
92 {
93 	if (!eip76d_rng_is_enabled())
94 		eip76d_rng_init_seq();
95 
96 	/* Is the result ready (available)? */
97 	while (!(io_read32(rng + RNG_STATUS) & RNG_READY)) {
98 		/* Is the shutdown threshold reached? */
99 		if (io_read32(rng + RNG_STATUS) & SHUTDOWN_OFLO) {
100 			uint32_t alarm = io_read32(rng + RNG_ALARMSTOP);
101 			uint32_t tune = io_read32(rng + RNG_FRODETUNE);
102 
103 			/* Clear the alarm events */
104 			io_write32(rng + RNG_ALARMMASK, 0x0);
105 			io_write32(rng + RNG_ALARMSTOP, 0x0);
106 			/* De-tune offending FROs */
107 			io_write32(rng + RNG_FRODETUNE, tune ^ alarm);
108 			/* Re-enable the shut down FROs */
109 			io_write32(rng + RNG_FROENABLE, RNG_FRO_MASK);
110 			/* Clear the shutdown overflow event */
111 			io_write32(rng + RNG_INTACK, SHUTDOWN_OFLO);
112 
113 			DMSG("Fixed FRO shutdown");
114 		}
115 	}
116 	/* Read random value */
117 	*word0 = io_read32(rng + RNG_OUTPUT_0);
118 	*word1 = io_read32(rng + RNG_OUTPUT_1);
119 	*word2 = io_read32(rng + RNG_OUTPUT_2);
120 	*word3 = io_read32(rng + RNG_OUTPUT_3);
121 	/* Acknowledge read complete */
122 	io_write32(rng + RNG_INTACK, RNG_READY);
123 }
124 
hw_get_random_bytes(void * buf,size_t len)125 TEE_Result hw_get_random_bytes(void *buf, size_t len)
126 {
127 	static union {
128 		uint32_t val[4];
129 		uint8_t byte[16];
130 	} fifo;
131 	static size_t fifo_pos;
132 	uint8_t *buffer = buf;
133 	size_t buffer_pos = 0;
134 
135 	while (buffer_pos < len) {
136 		mutex_lock(&fifo_lock);
137 
138 		/* Refill our FIFO */
139 		if (fifo_pos == 0)
140 			eip76d_rng_read128(&fifo.val[0], &fifo.val[1],
141 					   &fifo.val[2], &fifo.val[3]);
142 
143 		buffer[buffer_pos++] = fifo.byte[fifo_pos++];
144 		fifo_pos %= 16;
145 
146 		mutex_unlock(&fifo_lock);
147 	}
148 
149 	return TEE_SUCCESS;
150 }
151 
eip76d_rng_init(void)152 TEE_Result eip76d_rng_init(void)
153 {
154 	rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC, RNG_REG_SIZE);
155 
156 	eip76d_rng_init_seq();
157 
158 	IMSG("EIP76D TRNG initialized");
159 
160 	return TEE_SUCCESS;
161 }
162