blob: 8de12e9806448c8d330430c27dd37eaaff44f94f [file] [log] [blame]
Konstantin Porotchkin298841e2020-07-26 17:47:20 +03001/*
2 * Copyright (c) 2020, Marvell Technology Group Ltd. All rights reserved.
3 *
4 * Based on Linux kernel omap-rng.c - RNG driver for TI OMAP CPU family
5 *
6 * Author: Deepak Saxena <dsaxena@plexity.net>
7 *
8 * Copyright 2005 (c) MontaVista Software, Inc.
9 *
10 * Mostly based on original driver:
11 *
12 * Copyright (C) 2005 Nokia Corporation
13 * Author: Juha Yrjölä <juha.yrjola@nokia.com>
14 *
15 * SPDX-License-Identifier: BSD-3-Clause
16 */
17
18#include <assert.h>
19#include <errno.h>
20#include <string.h>
21
22#include <common/debug.h>
23#include <drivers/delay_timer.h>
24#include <drivers/rambus/trng_ip_76.h>
25#include <lib/mmio.h>
26#include <lib/spinlock.h>
27#include <lib/utils.h>
28
29#define RNG_REG_STATUS_RDY (1 << 0)
30
31#define RNG_REG_INTACK_RDY_MASK (1 << 0)
32
33#define RNG_CONTROL_ENABLE_TRNG_MASK (1 << 10)
34
35#define RNG_CONFIG_NOISE_BLOCKS(val) ((0xff & (val)) << 0)
36#define RNG_CONFIG_NOISE_BLK_VAL 0x5
37
38#define RNG_CONFIG_SAMPLE_CYCLES(val) ((0xff & (val)) << 16)
39#define RNG_CONFIG_SAMPLE_CYCLES_VAL 0x22
40
41#define RNG_REG_FRO_ENABLE_MASK 0xffffff
42#define RNG_REG_FRO_DETUNE_MASK 0x0
43
44#define EIP76_RNG_OUTPUT_SIZE 0x10
45#define EIP76_RNG_WAIT_ROUNDS 10
46
47#define RNG_HW_IS_EIP76(ver) ((ver) & (0xff == 0x4C))
48#define RNG_HW_VER_MAJOR(ver) (((ver) & (0xf << 24)) >> 24)
49#define RNG_HW_VER_MINOR(ver) (((ver) & (0xf << 20)) >> 20)
50#define RNG_HW_VER_PATCH(ver) (((ver) & (0xf << 16)) >> 16)
51
52
53enum {
54 RNG_OUTPUT_0_REG = 0,
55 RNG_OUTPUT_1_REG,
56 RNG_OUTPUT_2_REG,
57 RNG_OUTPUT_3_REG,
58 RNG_STATUS_REG,
59 RNG_INTMASK_REG,
60 RNG_INTACK_REG,
61 RNG_CONTROL_REG,
62 RNG_CONFIG_REG,
63 RNG_ALARMCNT_REG,
64 RNG_FROENABLE_REG,
65 RNG_FRODETUNE_REG,
66 RNG_ALARMMASK_REG,
67 RNG_ALARMSTOP_REG,
68 RNG_REV_REG
69};
70
71static uint16_t reg_map_eip76[] = {
72 [RNG_OUTPUT_0_REG] = 0x0,
73 [RNG_OUTPUT_1_REG] = 0x4,
74 [RNG_OUTPUT_2_REG] = 0x8,
75 [RNG_OUTPUT_3_REG] = 0xc,
76 [RNG_STATUS_REG] = 0x10,
77 [RNG_INTACK_REG] = 0x10,
78 [RNG_CONTROL_REG] = 0x14,
79 [RNG_CONFIG_REG] = 0x18,
80 [RNG_ALARMCNT_REG] = 0x1c,
81 [RNG_FROENABLE_REG] = 0x20,
82 [RNG_FRODETUNE_REG] = 0x24,
83 [RNG_ALARMMASK_REG] = 0x28,
84 [RNG_ALARMSTOP_REG] = 0x2c,
85 [RNG_REV_REG] = 0x7c,
86};
87
88struct eip76_rng_dev {
89 uintptr_t base;
90 uint16_t *regs;
91};
92
93/* Locals */
94static struct eip76_rng_dev eip76_dev;
95static spinlock_t rng_lock;
96
97static inline uint32_t eip76_rng_read(struct eip76_rng_dev *dev, uint16_t reg)
98{
99 return mmio_read_32(dev->base + dev->regs[reg]);
100}
101
102static inline void eip76_rng_write(struct eip76_rng_dev *dev,
103 uint16_t reg, uint32_t val)
104{
105 mmio_write_32(dev->base + dev->regs[reg], val);
106}
107
108static void eip76_rng_init(struct eip76_rng_dev *dev)
109{
110 uint32_t val;
111
112 /* Return if RNG is already running. */
113 if (eip76_rng_read(dev, RNG_CONTROL_REG) &
114 RNG_CONTROL_ENABLE_TRNG_MASK) {
115 return;
116 }
117
118 /* This field sets the number of 512-bit blocks of raw Noise Source
119 * output data that must be processed by either the Conditioning
120 * Function or the SP 800-90 DRBG ‘BC_DF’ functionality to yield
121 * a ‘full entropy’ output value. As according to [SP 800-90B draft]
122 * the amount of entropy input to this functionality must be twice
123 * the amount that is output and the 8-bit samples output by the Noise
124 * Source are supposed to have one bit of entropy each, the settings
125 * for this field are as follows:
126 * - SHA-1 Conditioning Function:
127 * generates 160 bits output, requiring 2560 sample bits,
128 * equivalent to 5 blocks of raw Noise Source input.
129 * - SHA-256 Conditioning Function:
130 * generates 256 bits output, requiring 4096 sample bits, equivalent
131 * to 8 blocks of raw Noise Source input. Note that two blocks of 256
132 * bits are needed to start or re-seed the SP 800-90 DRBG
133 * (in the EIP-76d-*-SHA2 configurations)
134 * - SP 800-90 DRBG ‘BC_DF’ functionality:
135 * generates 384 bits output, requiring 6144 sample bits, equivalent
136 * to 12 blocks of raw Noise Source input.
137 * This field can only be modified when ‘enable_trng’ in TRNG_CONTROL
138 * is ‘0’ or when either of the ‘test_known_noise’ or ‘test_cond_func’
139 * bits in TRNG_TEST is ‘1’. Value 0 in this field selects 256 blocks
140 * of 512 bits to be processed.
141 */
142 val = RNG_CONFIG_NOISE_BLOCKS(RNG_CONFIG_NOISE_BLK_VAL);
143
144 /* This field sets the number of FRO samples that are XOR-ed together
145 * into one bit to be shifted into the main shift register.
146 * This value must be such that there is at least one bit of entropy
147 * (in total) in each 8 bits that are shifted.
148 * This field can only be modified when ‘enable_trng’ in TRNG_CONTROL
149 * is ‘0’ or when either of the ‘test_known_noise’ or ‘test_cond_func’
150 * bits in TRNG_TEST is ‘1’. Value 0 in this field selects 65536 FRO
151 * samples to be XOR-ed together
152 */
153 val |= RNG_CONFIG_SAMPLE_CYCLES(RNG_CONFIG_SAMPLE_CYCLES_VAL);
154 eip76_rng_write(dev, RNG_CONFIG_REG, val);
155
156 /* Enable all available FROs */
157 eip76_rng_write(dev, RNG_FRODETUNE_REG, RNG_REG_FRO_DETUNE_MASK);
158 eip76_rng_write(dev, RNG_FROENABLE_REG, RNG_REG_FRO_ENABLE_MASK);
159
160 /* Enable TRNG */
161 eip76_rng_write(dev, RNG_CONTROL_REG, RNG_CONTROL_ENABLE_TRNG_MASK);
162}
163
164int32_t eip76_rng_read_rand_buf(void *data, bool wait)
165{
166 uint32_t i, present;
167
168 if (!eip76_dev.base) /* not initialized */
169 return -1;
170
171 for (i = 0; i < EIP76_RNG_WAIT_ROUNDS; i++) {
172 present = eip76_rng_read(&eip76_dev, RNG_STATUS_REG) &
173 RNG_REG_STATUS_RDY;
174 if (present || !wait) {
175 break;
176 }
177
178 udelay(10);
179 }
180
181 if (present != 0U) {
182 return 0;
183 }
184
185 memcpy(data,
186 (void *)(eip76_dev.base + eip76_dev.regs[RNG_OUTPUT_0_REG]),
187 EIP76_RNG_OUTPUT_SIZE);
188
189 eip76_rng_write(&eip76_dev, RNG_INTACK_REG, RNG_REG_INTACK_RDY_MASK);
190
191 return EIP76_RNG_OUTPUT_SIZE;
192}
193
194int32_t eip76_rng_probe(uintptr_t base_addr)
195{
196 uint32_t ver;
197
198 eip76_dev.base = base_addr;
199 eip76_dev.regs = reg_map_eip76;
200
201 eip76_rng_init(&eip76_dev);
202
203 ver = eip76_rng_read(&eip76_dev, RNG_REV_REG);
204
205 INFO("%s Random Number Generator HW ver. %01x.%01x.%01x\n",
206 RNG_HW_IS_EIP76(ver) ? "TRNG-IP-76" : "Unknown",
207 RNG_HW_VER_MAJOR(ver), RNG_HW_VER_MINOR(ver),
208 RNG_HW_VER_PATCH(ver));
209
210 return 0;
211}
212
213int32_t eip76_rng_get_random(uint8_t *data, uint32_t len)
214{
215 static uint8_t rand[EIP76_RNG_OUTPUT_SIZE];
216 static uint8_t pos;
217 uint32_t i;
218 int32_t ret = 0;
219
220 if (!data)
221 return -1;
222
223 spin_lock(&rng_lock);
224
225 for (i = 0; i < len; i++) {
226 if (pos >= EIP76_RNG_OUTPUT_SIZE) {
227 pos = 0;
228 }
229
230 if (pos != 0U) {
231 ret = eip76_rng_read_rand_buf(rand, true);
232 }
233
234 /* Only advance FIFO index if it is non zero or
235 * the update from TRNG HW was successful
236 */
237 if (pos || ret > 0) {
238 data[i] = rand[pos++];
239 ret = 0;
240 } else {
241 ret = -1;
242 break;
243 }
244 }
245
246 spin_unlock(&rng_lock);
247
248 return ret;
249}