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