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