Contiki-NG
Loading...
Searching...
No Matches
soc-trng.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016, University of Bristol - http://www.bristol.ac.uk
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30/*---------------------------------------------------------------------------*/
31/**
32 * \addtogroup cc26xx-trng
33 * @{
34 *
35 * \file
36 *
37 * Implementation of the CC13xx/CC26xx RNG driver
38 */
39/*---------------------------------------------------------------------------*/
40#include "contiki.h"
41#include "lpm.h"
42#include "sys/process.h"
43#include "dev/soc-trng.h"
44#include "ti-lib.h"
45
46#include <stdbool.h>
47#include <stdint.h>
48#include <stddef.h>
49/*---------------------------------------------------------------------------*/
50#ifdef SOC_TRNG_CONF_CACHE_LEN
51#define SOC_TRNG_CACHE_LEN SOC_TRNG_CONF_CACHE_LEN
52#else
53/** Size of the random number cache. Each slot holds 4 16-bit numbers */
54#define SOC_TRNG_CACHE_LEN 4
55#endif
56/*---------------------------------------------------------------------------*/
57#define MIN_REFILL_CYCLES_MAX 0x00000000
58/*---------------------------------------------------------------------------*/
59PROCESS(soc_trng_process, "CC13xx/CC26xx TRNG process");
60/*---------------------------------------------------------------------------*/
61static soc_trng_callback_t notify_cb = NULL;
62/*---------------------------------------------------------------------------*/
63#define soc_trng_isr TRNGIntHandler
64/*---------------------------------------------------------------------------*/
65static uint64_t rands_cache[SOC_TRNG_CACHE_LEN];
66static bool rands_mask[SOC_TRNG_CACHE_LEN];
67/*---------------------------------------------------------------------------*/
68static void
69disable_number_ready_interrupt(void)
70{
71 ti_lib_trng_int_disable(TRNG_NUMBER_READY);
72 ti_lib_int_disable(INT_TRNG_IRQ);
73}
74/*---------------------------------------------------------------------------*/
75static void
76enable_number_ready_interrupt(void)
77{
78 ti_lib_trng_int_clear(TRNG_NUMBER_READY);
79 ti_lib_trng_int_enable(TRNG_NUMBER_READY);
80 ti_lib_int_enable(INT_TRNG_IRQ);
81}
82/*---------------------------------------------------------------------------*/
83static bool
84accessible(void)
85{
86 /* First, check the PD */
87 if(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH)
88 != PRCM_DOMAIN_POWER_ON) {
89 return false;
90 }
91
92 /* Then check the 'run mode' clock gate */
93 if(!(HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) &
94 PRCM_SECDMACLKGDS_TRNG_CLK_EN_M)) {
95 return false;
96 }
97
98 return true;
99}
100/*---------------------------------------------------------------------------*/
101static void
102power_up(void)
103{
104 /* First, make sure the PERIPH PD is on */
105 ti_lib_prcm_power_domain_on(PRCM_DOMAIN_PERIPH);
106 while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH)
107 != PRCM_DOMAIN_POWER_ON));
108
109 /* Enable clock in active mode */
110 ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_TRNG);
111 ti_lib_prcm_load_set();
112 while(!ti_lib_prcm_load_get());
113}
114/*---------------------------------------------------------------------------*/
115static void
116reset_synchronous(void)
117{
118 ti_lib_trng_reset();
119 while(HWREG(TRNG_BASE + TRNG_O_SWRESET));
120}
121/*---------------------------------------------------------------------------*/
122static uint8_t
123request(void)
124{
125 if(notify_cb) {
126 return LPM_MODE_SLEEP;
127 }
128 return LPM_MODE_MAX_SUPPORTED;
129}
130/*---------------------------------------------------------------------------*/
131LPM_MODULE(rng_module, request, NULL, NULL, LPM_DOMAIN_NONE);
132/*---------------------------------------------------------------------------*/
133static uint64_t
134read_number(void)
135{
136 uint64_t ran = (uint64_t)HWREG(TRNG_BASE + TRNG_O_OUT1) << 32;
137 ran += ti_lib_trng_number_get(TRNG_LOW_WORD);
138
139 return ran;
140}
141/*---------------------------------------------------------------------------*/
142uint64_t
144{
145 uint64_t ran;
146 bool interrupts_disabled;
147 int i;
148
149 /* If the TRNG is gathering entropy, return a cached value */
150 if(notify_cb) {
151 for(i = 0; i < SOC_TRNG_CACHE_LEN; i++) {
152 if(rands_mask[i]) {
153 rands_mask[i] = false;
154 return rands_cache[i];
155 }
156 }
157 return 0;
158 }
159
160 if(!accessible()) {
161 power_up();
162 }
163
164 /*
165 * If we were previously enabled, we either have a number already available,
166 * or we need clock, which means we are calculating. If neither is true then
167 * we need setup from scratch.
168 */
169 if((ti_lib_trng_status_get() & (TRNG_NEED_CLOCK | TRNG_NUMBER_READY)) == 0) {
170 reset_synchronous();
171 ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, SOC_TRNG_REFILL_CYCLES_MIN, 0);
172 ti_lib_trng_enable();
173 }
174
175 interrupts_disabled = ti_lib_int_master_disable();
176
177 while((ti_lib_trng_status_get() & TRNG_NUMBER_READY) == 0);
178
179 ran = read_number();
180
181 if(!interrupts_disabled) {
182 ti_lib_int_master_enable();
183 }
184
185 return ran;
186}
187/*---------------------------------------------------------------------------*/
188uint8_t
190{
191 int i;
192 bool interrupts_disabled;
193
194 if(notify_cb != NULL) {
196 }
197
198 if(!accessible()) {
199 power_up();
200 }
201
202 /*
203 * First we need to cache some random numbers for general use in case the
204 * application requests them while we are calculating.
205 *
206 * If we were previously enabled, we either have a number already available,
207 * or we need clock, which means we are calculating. If neither is true then
208 * we need setup from scratch.
209 */
210 if((ti_lib_trng_status_get() & (TRNG_NEED_CLOCK | TRNG_NUMBER_READY)) == 0) {
211 reset_synchronous();
212 }
213
214 interrupts_disabled = ti_lib_int_master_disable();
215
216 ti_lib_trng_disable();
217 ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, SOC_TRNG_REFILL_CYCLES_MIN, 0);
218 ti_lib_trng_enable();
219
220 /* Cache SOC_TRNG_CACHE_LEN min-entropy rands */
221 for(i = 0; i < SOC_TRNG_CACHE_LEN; i++) {
222 while((ti_lib_trng_status_get() & TRNG_NUMBER_READY) == 0);
223 rands_mask[i] = true;
224 rands_cache[i] = read_number();
225 }
226
227 /* Configure the RNG to the required entropy */
228 ti_lib_trng_disable();
229 ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, samples, 0);
230
231 /*
232 * Clear the TRNG_NUMBER_READY flag. This will trigger a new calculation
233 * as soon as the module gets enabled.
234 */
235 ti_lib_trng_int_clear(TRNG_NUMBER_READY);
236
237 /* Enable clock in sleep mode and register with LPM */
238 ti_lib_prcm_peripheral_sleep_enable(PRCM_PERIPH_TRNG);
239 ti_lib_prcm_load_set();
240 while(!ti_lib_prcm_load_get());
241
242 lpm_register_module(&rng_module);
243
244 notify_cb = cb;
245
246 /* Enable the number ready interrupt and fire-up the module */
247 enable_number_ready_interrupt();
248 ti_lib_trng_enable();
249
250 if(!interrupts_disabled) {
251 ti_lib_int_master_enable();
252 }
253
255}
256/*---------------------------------------------------------------------------*/
257PROCESS_THREAD(soc_trng_process, ev, data)
258{
260
261 while(1) {
262 PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
263
264 if(notify_cb) {
265 uint64_t ran = read_number();
266
267 notify_cb(ran);
268 notify_cb = NULL;
269 }
270
271 /* Disable clock in sleep mode */
272 ti_lib_prcm_peripheral_sleep_disable(PRCM_PERIPH_TRNG);
273 ti_lib_prcm_load_set();
274 while(!ti_lib_prcm_load_get());
275
276 lpm_unregister_module(&rng_module);
277 }
278
279 PROCESS_END();
280}
281/*---------------------------------------------------------------------------*/
282void
283soc_trng_isr(void)
284{
285 ti_lib_trng_disable();
286
287 disable_number_ready_interrupt();
288
289 ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, SOC_TRNG_REFILL_CYCLES_MIN, 0);
290 ti_lib_trng_enable();
291
292 process_poll(&soc_trng_process);
293}
294/*---------------------------------------------------------------------------*/
295void
297{
298 process_start(&soc_trng_process, NULL);
299}
300/*---------------------------------------------------------------------------*/
301/**
302 * @}
303 */
#define LPM_MODULE(n, m, s, w, l)
Declare a variable to be used in order to get notifications from LPM.
Definition lpm.h:96
void lpm_unregister_module(lpm_registered_module_t *module)
Unregister a module from LPM notifications.
Definition lpm.c:551
void lpm_register_module(lpm_registered_module_t *module)
Register a module for LPM notifications.
Definition lpm.c:545
void(* soc_trng_callback_t)(uint64_t rand)
Pointer to a callback to be provided as an argument to soc_trng_rand_asynchronous()
Definition soc-trng.h:61
#define SOC_TRNG_RAND_ASYNC_REQUEST_OK
Async request accepted.
Definition soc-trng.h:52
void soc_trng_init()
Initialise the CC13xx/CC26xx TRNG driver.
Definition soc-trng.c:296
#define SOC_TRNG_CACHE_LEN
Size of the random number cache.
Definition soc-trng.c:54
uint8_t soc_trng_rand_asynchronous(uint32_t samples, soc_trng_callback_t cb)
Request a 64-bit, configurable-entropy random number.
Definition soc-trng.c:189
uint64_t soc_trng_rand_synchronous()
Returns a minimum entropy random number.
Definition soc-trng.c:143
#define SOC_TRNG_RAND_ASYNC_REQUEST_ERROR
Async request rejected.
Definition soc-trng.h:51
#define PROCESS(name, strname)
Declare a process.
Definition process.h:307
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition process.h:120
#define PROCESS_END()
Define the end of a process.
Definition process.h:131
void process_start(struct process *p, process_data_t data)
Start a process.
Definition process.c:107
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition process.h:273
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition process.h:178
void process_poll(struct process *p)
Request a process to be polled.
Definition process.c:375
Header file for the Contiki process interface.
Header file for the CC13xx/CC26xx TRNG driver.
Header file with macros which rename TI CC26xxware functions.