Contiki-NG
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 process_event_t rng_ready_event = PROCESS_EVENT_NONE;
62/*---------------------------------------------------------------------------*/
63static soc_trng_callback_t notify_cb = NULL;
64/*---------------------------------------------------------------------------*/
65#define soc_trng_isr TRNGIntHandler
66/*---------------------------------------------------------------------------*/
67static uint64_t rands_cache[SOC_TRNG_CACHE_LEN];
68static bool rands_mask[SOC_TRNG_CACHE_LEN];
69/*---------------------------------------------------------------------------*/
70static void
71disable_number_ready_interrupt(void)
72{
73 ti_lib_trng_int_disable(TRNG_NUMBER_READY);
74 ti_lib_int_disable(INT_TRNG_IRQ);
75}
76/*---------------------------------------------------------------------------*/
77static void
78enable_number_ready_interrupt(void)
79{
80 ti_lib_trng_int_clear(TRNG_NUMBER_READY);
81 ti_lib_trng_int_enable(TRNG_NUMBER_READY);
82 ti_lib_int_enable(INT_TRNG_IRQ);
83}
84/*---------------------------------------------------------------------------*/
85static bool
86accessible(void)
87{
88 /* First, check the PD */
89 if(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH)
90 != PRCM_DOMAIN_POWER_ON) {
91 return false;
92 }
93
94 /* Then check the 'run mode' clock gate */
95 if(!(HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) &
96 PRCM_SECDMACLKGDS_TRNG_CLK_EN_M)) {
97 return false;
98 }
99
100 return true;
101}
102/*---------------------------------------------------------------------------*/
103static void
104power_up(void)
105{
106 /* First, make sure the PERIPH PD is on */
107 ti_lib_prcm_power_domain_on(PRCM_DOMAIN_PERIPH);
108 while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH)
109 != PRCM_DOMAIN_POWER_ON));
110
111 /* Enable clock in active mode */
112 ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_TRNG);
113 ti_lib_prcm_load_set();
114 while(!ti_lib_prcm_load_get());
115}
116/*---------------------------------------------------------------------------*/
117static void
118reset_synchronous(void)
119{
120 ti_lib_trng_reset();
121 while(HWREG(TRNG_BASE + TRNG_O_SWRESET));
122}
123/*---------------------------------------------------------------------------*/
124static uint8_t
125request(void)
126{
127 if(notify_cb) {
128 return LPM_MODE_SLEEP;
129 }
130 return LPM_MODE_MAX_SUPPORTED;
131}
132/*---------------------------------------------------------------------------*/
133LPM_MODULE(rng_module, request, NULL, NULL, LPM_DOMAIN_NONE);
134/*---------------------------------------------------------------------------*/
135static uint64_t
136read_number(void)
137{
138 uint64_t ran = (uint64_t)HWREG(TRNG_BASE + TRNG_O_OUT1) << 32;
139 ran += ti_lib_trng_number_get(TRNG_LOW_WORD);
140
141 return ran;
142}
143/*---------------------------------------------------------------------------*/
144uint64_t
146{
147 uint64_t ran;
148 bool interrupts_disabled;
149 int i;
150
151 /* If the TRNG is gathering entropy, return a cached value */
152 if(notify_cb) {
153 for(i = 0; i < SOC_TRNG_CACHE_LEN; i++) {
154 if(rands_mask[i]) {
155 rands_mask[i] = false;
156 return rands_cache[i];
157 }
158 }
159 return 0;
160 }
161
162 if(!accessible()) {
163 power_up();
164 }
165
166 /*
167 * If we were previously enabled, we either have a number already available,
168 * or we need clock, which means we are calculating. If neither is true then
169 * we need setup from scratch.
170 */
171 if((ti_lib_trng_status_get() & (TRNG_NEED_CLOCK | TRNG_NUMBER_READY)) == 0) {
172 reset_synchronous();
173 ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, SOC_TRNG_REFILL_CYCLES_MIN, 0);
174 ti_lib_trng_enable();
175 }
176
177 interrupts_disabled = ti_lib_int_master_disable();
178
179 while((ti_lib_trng_status_get() & TRNG_NUMBER_READY) == 0);
180
181 ran = read_number();
182
183 if(!interrupts_disabled) {
184 ti_lib_int_master_enable();
185 }
186
187 return ran;
188}
189/*---------------------------------------------------------------------------*/
190uint8_t
192{
193 int i;
194 bool interrupts_disabled;
195
196 if(notify_cb != NULL) {
198 }
199
200 if(!accessible()) {
201 power_up();
202 }
203
204 /*
205 * First we need to cache some random numbers for general use in case the
206 * application requests them while we are calculating.
207 *
208 * If we were previously enabled, we either have a number already available,
209 * or we need clock, which means we are calculating. If neither is true then
210 * we need setup from scratch.
211 */
212 if((ti_lib_trng_status_get() & (TRNG_NEED_CLOCK | TRNG_NUMBER_READY)) == 0) {
213 reset_synchronous();
214 }
215
216 interrupts_disabled = ti_lib_int_master_disable();
217
218 ti_lib_trng_disable();
219 ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, SOC_TRNG_REFILL_CYCLES_MIN, 0);
220 ti_lib_trng_enable();
221
222 /* Cache SOC_TRNG_CACHE_LEN min-entropy rands */
223 for(i = 0; i < SOC_TRNG_CACHE_LEN; i++) {
224 while((ti_lib_trng_status_get() & TRNG_NUMBER_READY) == 0);
225 rands_mask[i] = true;
226 rands_cache[i] = read_number();
227 }
228
229 /* Configure the RNG to the required entropy */
230 ti_lib_trng_disable();
231 ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, samples, 0);
232
233 /*
234 * Clear the TRNG_NUMBER_READY flag. This will trigger a new calculation
235 * as soon as the module gets enabled.
236 */
237 ti_lib_trng_int_clear(TRNG_NUMBER_READY);
238
239 /* Enable clock in sleep mode and register with LPM */
240 ti_lib_prcm_peripheral_sleep_enable(PRCM_PERIPH_TRNG);
241 ti_lib_prcm_load_set();
242 while(!ti_lib_prcm_load_get());
243
244 lpm_register_module(&rng_module);
245
246 notify_cb = cb;
247
248 /* Enable the number ready interrupt and fire-up the module */
249 enable_number_ready_interrupt();
250 ti_lib_trng_enable();
251
252 if(!interrupts_disabled) {
253 ti_lib_int_master_enable();
254 }
255
257}
258/*---------------------------------------------------------------------------*/
259PROCESS_THREAD(soc_trng_process, ev, data)
260{
262
263 while(1) {
264 PROCESS_YIELD_UNTIL(ev == rng_ready_event);
265
266 if(notify_cb) {
267 uint64_t ran = read_number();
268
269 notify_cb(ran);
270 notify_cb = NULL;
271 }
272
273 /* Disable clock in sleep mode */
274 ti_lib_prcm_peripheral_sleep_disable(PRCM_PERIPH_TRNG);
275 ti_lib_prcm_load_set();
276 while(!ti_lib_prcm_load_get());
277
278 lpm_unregister_module(&rng_module);
279 }
280
281 PROCESS_END();
282}
283/*---------------------------------------------------------------------------*/
284void
285soc_trng_isr(void)
286{
287 ti_lib_trng_disable();
288
289 disable_number_ready_interrupt();
290
291 ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, SOC_TRNG_REFILL_CYCLES_MIN, 0);
292 ti_lib_trng_enable();
293
294 process_post(&soc_trng_process, rng_ready_event, NULL);
295}
296/*---------------------------------------------------------------------------*/
297void
299{
300 if(rng_ready_event != PROCESS_EVENT_NONE) {
301 return;
302 }
303
304 /* Register the RNG ready event */
305 rng_ready_event = process_alloc_event();
306 process_start(&soc_trng_process, NULL);
307}
308/*---------------------------------------------------------------------------*/
309/**
310 * @}
311 */
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1110
#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:298
#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:191
uint64_t soc_trng_rand_synchronous()
Returns a minimum entropy random number.
Definition: soc-trng.c:145
#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
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition: process.c:93
#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:99
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
Header file for the Contiki process interface.
Header file for the CC13xx/CC26xx TRNG driver.
Header file with macros which rename TI CC26xxware functions.