1 /*
2 * Copyright 2017, 2019, 2021 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "fsl_rng.h"
9
10 /* Component ID definition, used by tools. */
11 #ifndef FSL_COMPONENT_ID
12 #define FSL_COMPONENT_ID "platform.drivers.rng_1"
13 #endif
14
15 /*******************************************************************************
16 * Definitions
17 *******************************************************************************/
18
19 /*******************************************************************************
20 * Prototypes
21 *******************************************************************************/
22
23 /*******************************************************************************
24 * Code
25 ******************************************************************************/
rng_accumulateEntropy(RNG_Type * base)26 static void rng_accumulateEntropy(RNG_Type *base)
27 {
28 uint32_t minChiSq;
29 uint32_t maxChiSq;
30
31 /* Steps to accumulate entropy, more info can be found in LPC55SXX UM*/
32
33 /* Select fourth clock on which to compute CHI SQUARE statistics*/
34 base->COUNTER_CFG = (base->COUNTER_CFG & ~RNG_COUNTER_CFG_CLOCK_SEL_MASK) | RNG_COUNTER_CFG_CLOCK_SEL(4U);
35
36 /* Activate CHI computing */
37 base->ONLINE_TEST_CFG = RNG_ONLINE_TEST_CFG_ACTIVATE(1U);
38
39 /* Read min chi squared value, on power on should be higher than max chi squared value */
40 minChiSq = ((base->ONLINE_TEST_VAL & RNG_ONLINE_TEST_VAL_MIN_CHI_SQUARED_MASK) >>
41 RNG_ONLINE_TEST_VAL_MIN_CHI_SQUARED_SHIFT);
42
43 /* Read max chi squared value */
44 maxChiSq = ((base->ONLINE_TEST_VAL & RNG_ONLINE_TEST_VAL_MAX_CHI_SQUARED_MASK) >>
45 RNG_ONLINE_TEST_VAL_MAX_CHI_SQUARED_SHIFT);
46
47 /* Wait until minChiSq decreases and become smaller than maxChiSq*/
48 while (minChiSq > (maxChiSq - 1U))
49 {
50 maxChiSq = ((base->ONLINE_TEST_VAL & RNG_ONLINE_TEST_VAL_MAX_CHI_SQUARED_MASK) >>
51 RNG_ONLINE_TEST_VAL_MAX_CHI_SQUARED_SHIFT);
52 minChiSq = ((base->ONLINE_TEST_VAL & RNG_ONLINE_TEST_VAL_MIN_CHI_SQUARED_MASK) >>
53 RNG_ONLINE_TEST_VAL_MIN_CHI_SQUARED_SHIFT);
54 }
55 }
56
57 /*!
58 * @brief Gets a entry data from the RNG.
59 *
60 * This function gets an entropy data from RNG.
61 */
rng_readEntropy(RNG_Type * base)62 static uint32_t rng_readEntropy(RNG_Type *base)
63 {
64 uint32_t data;
65 uint32_t refreshCnt, maxChiSq, tmpShift4x;
66
67 /* Activate CHI computing */
68 base->ONLINE_TEST_CFG = RNG_ONLINE_TEST_CFG_ACTIVATE(1);
69
70 /* Wait for refresh count become 31 to refill fresh entropy since last read of random number*/
71 do
72 {
73 refreshCnt = ((base->COUNTER_VAL & RNG_COUNTER_VAL_REFRESH_CNT_MASK) >> RNG_COUNTER_VAL_REFRESH_CNT_SHIFT);
74 } while (refreshCnt < 31U);
75
76 /* reading RANDOM_NUMBER register will reset refCnt to 0 */
77 data = base->RANDOM_NUMBER;
78
79 /* Perform CHI computing by checking max chi squared value */
80 /* Wait until maxChiSq become smaller or equal than 4, then next random number can be read*/
81 maxChiSq = ((base->ONLINE_TEST_VAL & RNG_ONLINE_TEST_VAL_MAX_CHI_SQUARED_MASK) >>
82 RNG_ONLINE_TEST_VAL_MAX_CHI_SQUARED_SHIFT);
83
84 while (maxChiSq > 4U)
85 {
86 /* Deactivate CHI computing to reset*/
87 base->ONLINE_TEST_CFG = RNG_ONLINE_TEST_CFG_ACTIVATE(0);
88
89 /* read Shift4x register, if is less than 7 increment it and then start accumulating entropy again */
90 tmpShift4x = ((base->COUNTER_CFG & RNG_COUNTER_CFG_SHIFT4X_MASK) >> RNG_COUNTER_CFG_SHIFT4X_SHIFT);
91 if (tmpShift4x < 7U)
92 {
93 tmpShift4x++;
94 base->COUNTER_CFG =
95 (base->COUNTER_CFG & ~RNG_COUNTER_CFG_SHIFT4X_MASK) | RNG_COUNTER_CFG_SHIFT4X(tmpShift4x);
96 }
97 rng_accumulateEntropy(base);
98
99 maxChiSq = ((base->ONLINE_TEST_VAL & RNG_ONLINE_TEST_VAL_MAX_CHI_SQUARED_MASK) >>
100 RNG_ONLINE_TEST_VAL_MAX_CHI_SQUARED_SHIFT);
101 }
102
103 return data;
104 }
105
RNG_Init(RNG_Type * base)106 void RNG_Init(RNG_Type *base)
107 {
108 uint32_t maxChiSq, tmpShift4x;
109
110 /* Clear ring oscilator disable bit*/
111 PMC->PDRUNCFGCLR0 = PMC_PDRUNCFG0_PDEN_RNG_MASK;
112 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
113 CLOCK_EnableClock(kCLOCK_Rng);
114 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
115
116 #if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
117 /* Reset the module. */
118 RESET_PeripheralReset(kRNG_RST_SHIFT_RSTn);
119 #endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
120
121 /* Turn on CHI Squared test */
122 /* Activate CHI computing and wait until min chi squared become smaller than max chi squared */
123 rng_accumulateEntropy(base);
124
125 maxChiSq = ((base->ONLINE_TEST_VAL & RNG_ONLINE_TEST_VAL_MAX_CHI_SQUARED_MASK) >>
126 RNG_ONLINE_TEST_VAL_MAX_CHI_SQUARED_SHIFT);
127
128 /* When maxChiSq is bigger than 4 its assumed there is not enough entropy and previous steps are repeated */
129 /* When maxChiSq is 4 or less initialization is complete and random number can be read*/
130 while (maxChiSq > 4U)
131 {
132 /* Deactivate CHI coputing to reset*/
133 base->ONLINE_TEST_CFG = RNG_ONLINE_TEST_CFG_ACTIVATE(0);
134
135 /* read Shift4x register, if is less than 7 increment it and then start accumulating entropy again */
136 tmpShift4x = ((base->COUNTER_CFG & RNG_COUNTER_CFG_SHIFT4X_MASK) >> RNG_COUNTER_CFG_SHIFT4X_SHIFT);
137 if (tmpShift4x < 7U)
138 {
139 tmpShift4x++;
140 base->COUNTER_CFG =
141 (base->COUNTER_CFG & ~RNG_COUNTER_CFG_SHIFT4X_MASK) | RNG_COUNTER_CFG_SHIFT4X(tmpShift4x);
142 }
143 rng_accumulateEntropy(base);
144
145 maxChiSq = ((base->ONLINE_TEST_VAL & RNG_ONLINE_TEST_VAL_MAX_CHI_SQUARED_MASK) >>
146 RNG_ONLINE_TEST_VAL_MAX_CHI_SQUARED_SHIFT);
147 }
148 }
149
RNG_Deinit(RNG_Type * base)150 void RNG_Deinit(RNG_Type *base)
151 {
152 /* Set ring oscilator disable bit*/
153 PMC->PDRUNCFGSET0 = PMC_PDRUNCFG0_PDEN_RNG_MASK;
154
155 #if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
156 /* Reset the module. */
157 RESET_PeripheralReset(kRNG_RST_SHIFT_RSTn);
158 #endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
159
160 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
161 CLOCK_DisableClock(kCLOCK_Rng);
162 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
163 }
164
RNG_GetRandomData(RNG_Type * base,void * data,size_t dataSize)165 status_t RNG_GetRandomData(RNG_Type *base, void *data, size_t dataSize)
166 {
167 status_t result = kStatus_Fail;
168 uint32_t random32;
169 uint32_t randomSize;
170 uint8_t *pRandom;
171 uint8_t *pData = (uint8_t *)data;
172 uint32_t i;
173
174 /* Check input parameters.*/
175 if (!((base != NULL) && (data != NULL) && (dataSize != 0U)))
176 {
177 result = kStatus_InvalidArgument;
178 }
179 else
180 {
181 /* Check that ring oscilator is enabled */
182 if (0U == (PMC->PDRUNCFG0 & PMC_PDRUNCFG0_PDEN_RNG_MASK))
183 {
184 do
185 {
186 /* Read Entropy.*/
187 random32 = rng_readEntropy(base);
188 pRandom = (uint8_t *)&random32;
189
190 if (dataSize < sizeof(random32))
191 {
192 randomSize = dataSize;
193 }
194 else
195 {
196 randomSize = sizeof(random32);
197 }
198
199 for (i = 0; i < randomSize; i++)
200 {
201 *pData++ = *pRandom++;
202 }
203
204 dataSize -= randomSize;
205 } while (dataSize > 0U);
206
207 result = kStatus_Success;
208 }
209 }
210
211 return result;
212 }
213