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