1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014-2016, STMicroelectronics International N.V.
4  */
5 
6 #include <io.h>
7 #include <kernel/panic.h>
8 #include <mm/core_mmu.h>
9 #include <mm/core_memprot.h>
10 #include <platform_config.h>
11 #include <trace.h>
12 
13 #include "rng_support.h"
14 
15 /* Address of the register to read in the RNG IP */
16 #define RNG_VAL_OFFSET             0x24
17 #define RNG_STATUS_OFFSET          0x20
18 
19 #define RNG_STATUS_ERR0		BIT32(0)
20 #define RNG_STATUS_ERR1		BIT32(1)
21 #define RNG_STATUS_FULL		BIT32(5)
22 
rng_base(void)23 static vaddr_t rng_base(void)
24 {
25 	static void *va;
26 
27 	if (cpu_mmu_enabled()) {
28 		if (!va)
29 			va = phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC, RNG_SIZE);
30 		return (vaddr_t)va;
31 	}
32 	return RNG_BASE;
33 }
34 
hwrng_waithost_fifo_full(void)35 static inline int hwrng_waithost_fifo_full(void)
36 {
37 	uint32_t status;
38 
39 	do {
40 		status = io_read32(rng_base() + RNG_STATUS_OFFSET);
41 	} while (!(status & RNG_STATUS_FULL));
42 
43 	if (status & (RNG_STATUS_ERR0 | RNG_STATUS_ERR1))
44 		return 1;
45 
46 	return 0;
47 }
48 
hw_get_random_byte(void)49 uint8_t hw_get_random_byte(void)
50 {
51 	/*
52 	 * Only the HW RNG IP is used to generate the value through the
53 	 * HOST interface.
54 	 *
55 	 * @see the document rng_fspec_revG_120720.pdf for details
56 	 *
57 	 * - HOST FIFO size = 8x8b (64b)
58 	 * - LSB (16b) of the RNG_VAL register allows to read 16b
59 	 * - bit5 of the RNG_STATUS register allows to known if the HOST
60 	 *   FIFO is full or not.
61 	 * - bit1,0 of the RNG_STATUS register allows to known if the
62 	 *   data are valid.
63 	 *
64 	 * Main principle:
65 	 *  For performance reason, a local SW fifo is used to store the
66 	 *  content of the HOST FIFO (max size = 8bytes). When a random
67 	 *  value is expected, this SW fifo is used to return a stored value.
68 	 *  When the local SW fifo is empty, it is filled with the HOST FIFO
69 	 *  according the following sequence:
70 	 *
71 	 *  - wait HOST FIFO full
72 	 *      o Indicates that max 8-bytes (64b) are available
73 	 *      o This is mandatory to guarantee that a valid data is
74 	 *      available. No STATUS bit to indicate that the HOST FIFO
75 	 *      is empty is provided.
76 	 *  - check STATUS bits
77 	 *  - update the local SW fifo with the HOST FIFO
78 	 *
79 	 *  This avoid to wait at each iteration that a valid random value is
80 	 *  available. _LOCAL_FIFO_SIZE indicates the size of the local SW fifo.
81 	 *
82 	 */
83 
84 
85 #define _LOCAL_FIFO_SIZE 8     /* min 2, 4, 6, max 8 */
86 
87 	static uint8_t lfifo[_LOCAL_FIFO_SIZE];     /* local fifo */
88 	static int pos = -1;
89 
90 	static int nbcall;  /* debug purpose - 0 is the initial value*/
91 
92 	volatile uint32_t tmpval[_LOCAL_FIFO_SIZE/2];
93 	uint8_t value;
94 	int i;
95 
96 	nbcall++;
97 
98 	/* Retrieve data from local fifo */
99 	if (pos >= 0) {
100 		pos++;
101 		value = lfifo[pos];
102 		if (pos == (_LOCAL_FIFO_SIZE - 1))
103 			pos = -1;
104 		return value;
105 	}
106 
107 	if (hwrng_waithost_fifo_full())
108 		return 0;
109 
110 	/* Read the FIFO according the number of expected element */
111 	for (i = 0; i < _LOCAL_FIFO_SIZE / 2; i++)
112 		tmpval[i] = io_read32(rng_base() + RNG_VAL_OFFSET) & 0xFFFF;
113 
114 	/* Update the local SW fifo for next request */
115 	pos = 0;
116 	for (i = 0; i < _LOCAL_FIFO_SIZE / 2; i++) {
117 		lfifo[pos] = tmpval[i] & 0xFF;
118 		pos++;
119 		lfifo[pos] = (tmpval[i] >> 8) & 0xFF;
120 		pos++;
121 	};
122 
123 	pos = 0;
124 	return lfifo[pos];
125 }
126