Skip to content
Permalink
Browse files

drivers: add CC13xx / CC26xx entropy driver

Add driver for the TRNG entropy source on the TI CC13xx / CC26xx
series SoCs.

Signed-off-by: Brett Witherspoon <spoonb@cdspooner.com>
  • Loading branch information...
bwitherspoon authored and galak committed Apr 25, 2019
1 parent 3bcd188 commit 2bee500f062e7adaf58aaf61b38eb0c3f1efd86c
@@ -2,6 +2,7 @@

zephyr_library()

zephyr_library_sources_ifdef(CONFIG_ENTROPY_CC13XX_CC26XX_RNG entropy_cc13xx_cc26xx.c)
zephyr_library_sources_ifdef(CONFIG_ENTROPY_ESP32_RNG entropy_esp32.c)
zephyr_library_sources_ifdef(CONFIG_ENTROPY_MCUX_RNGA entropy_mcux_rnga.c)
zephyr_library_sources_ifdef(CONFIG_ENTROPY_MCUX_TRNG entropy_mcux_trng.c)
@@ -13,6 +13,7 @@ menuconfig ENTROPY_GENERATOR

if ENTROPY_GENERATOR

source "drivers/entropy/Kconfig.cc13xx_cc26xx"
source "drivers/entropy/Kconfig.mcux"
source "drivers/entropy/Kconfig.stm32"
source "drivers/entropy/Kconfig.esp32"
@@ -0,0 +1,51 @@
# Kconfig.cc13xx_cc26xx - TI CC13xx / CC26xx entropy driver configuration
#
# Copyright (c) 2019 Brett Witherspoon
#
# SPDX-License-Identifier: Apache-2.0

config ENTROPY_CC13XX_CC26XX_RNG
bool "TI SimpleLink CC13xx / CC26xx True Random Number Generator (TRNG)"
depends on SOC_SERIES_CC13X2_CC26X2
select ENTROPY_HAS_DRIVER
select HAS_DTS_ENTROPY
select RING_BUFFER
help
This option enables the driver for the True Random Number Generator (TRNG)
for TI SimpleLink CC13xx / CC26xx SoCs.

if ENTROPY_CC13XX_CC26XX_RNG

config ENTROPY_CC13XX_CC26XX_POOL_SIZE
int "Number of bytes in the entropy pool"
default 512
help
The size in bytes of the buffer used to store entropy generated by the
hardware. Should be a power of two for high performance.

config ENTROPY_CC13XX_CC26XX_SAMPLES_PER_CYCLE
int "Number of samples to generate entropy"
range 256 16777216
default 240000
help
The number of samples used to generate entropy. The time required to
generate 64 bits of entropy is determined by the number of FROs enabled,
the sampling (system) clock frequency, and this value.

config ENTROPY_CC13XX_CC26XX_ALARM_THRESHOLD
int "Threshold for detected repeated patterns"
range 0 255
default 255
help
The number of samples detected with repeating patterns before an alarm
event is triggered. The associated FRO is automatically shut down.

config ENTROPY_CC13XX_CC26XX_SHUTDOWN_THRESHOLD
int "Threshold for the number of FROs automatically shut down"
range 0 24
default 0
help
The number of FROs allowed to be shutdown before the driver attempts to
take corrective action.

endif # ENTROPY_CC13XX_CC26XX_RNG
@@ -0,0 +1,170 @@
/*
* Copyright (c) 2019 Brett Witherspoon
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <kernel.h>
#include <device.h>
#include <entropy.h>
#include <irq.h>
#include <ring_buffer.h>
#include <sys_io.h>

#include <driverlib/prcm.h>
#include <driverlib/trng.h>

struct entropy_cc13xx_cc26xx_data {
struct k_sem lock;
struct k_sem sync;
struct ring_buf pool;
u8_t data[CONFIG_ENTROPY_CC13XX_CC26XX_POOL_SIZE];
};

DEVICE_DECLARE(entropy_cc13xx_cc26xx);

static inline struct entropy_cc13xx_cc26xx_data *
get_dev_data(struct device *dev)
{
return dev->driver_data;
}

static int entropy_cc13xx_cc26xx_get_entropy(struct device *dev, u8_t *buf,
u16_t len)
{
struct entropy_cc13xx_cc26xx_data *data = get_dev_data(dev);
u32_t cnt;

TRNGIntEnable(TRNG_NUMBER_READY);

while (len) {
k_sem_take(&data->lock, K_FOREVER);
cnt = ring_buf_get(&data->pool, buf, len);
k_sem_give(&data->lock);

if (cnt) {
buf += cnt;
len -= cnt;
} else {
k_sem_take(&data->sync, K_FOREVER);
}
}

return 0;
}

static void entropy_cc13xx_cc26xx_isr(void *arg)
{
struct entropy_cc13xx_cc26xx_data *data = get_dev_data(arg);
u32_t src, cnt, off;
u32_t num[2];

/* Interrupt service routine as described in TRM section 18.6.1.3.2 */
src = TRNGStatusGet();

if (src & TRNG_NUMBER_READY) {
/* This function acknowledges the ready status */
num[1] = TRNGNumberGet(TRNG_HI_WORD);
num[0] = TRNGNumberGet(TRNG_LOW_WORD);

cnt = ring_buf_put(&data->pool, (u8_t *)num, sizeof(num));

/* When pool is full disable interrupt and stop reading numbers */
if (cnt != sizeof(num)) {
TRNGIntDisable(TRNG_NUMBER_READY);
}

k_sem_give(&data->sync);
}

/* Change the shutdown FROs' oscillating frequncy in an attempt to
* prevent further locking on to the sampling clock frequncy.
*/
if (src & TRNG_FRO_SHUTDOWN) {
/* Clear shutdown */
TRNGIntClear(TRNG_FRO_SHUTDOWN);
/* Disabled FROs */
off = sys_read32(TRNG_BASE + TRNG_O_ALARMSTOP);
/* Clear alarms */
sys_write32(0, TRNG_BASE + TRNG_O_ALARMMASK);
sys_write32(0, TRNG_BASE + TRNG_O_ALARMSTOP);
/* De-tune FROs */
sys_write32(off, TRNG_BASE + TRNG_O_FRODETUNE);
/* Re-enable FROs */
sys_write32(off, TRNG_BASE + TRNG_O_FROEN);
}
}

static int entropy_cc13xx_cc26xx_init(struct device *dev)
{
struct entropy_cc13xx_cc26xx_data *data = get_dev_data(dev);

/* Power TRNG domain */
PRCMPowerDomainOn(PRCM_DOMAIN_PERIPH);

/* Enable TRNG peripheral clocks */
PRCMPeripheralRunEnable(PRCM_PERIPH_TRNG);
/* Enabled the TRNG while in sleep mode to keep the entropy pool full. After
* the pool is full the TRNG will enter idle mode when random numbers are no
* longer being read. */
PRCMPeripheralSleepEnable(PRCM_PERIPH_TRNG);
PRCMPeripheralDeepSleepEnable(PRCM_PERIPH_TRNG);


/* Load PRCM settings */
PRCMLoadSet();
while (!PRCMLoadGet()) {
continue;
}

/* Peripherals should not be accessed until power domain is on. */
while (PRCMPowerDomainStatus(PRCM_DOMAIN_PERIPH) !=
PRCM_DOMAIN_POWER_ON) {
continue;
}

/* Initialize driver data */
ring_buf_init(&data->pool, sizeof(data->data), data->data);

/* Initialization as described in TRM section 18.6.1.2 */
TRNGReset();
while (sys_read32(TRNG_BASE + TRNG_O_SWRESET)) {
continue;
}

/* Set samples per cycle */
TRNGConfigure(0, CONFIG_ENTROPY_CC13XX_CC26XX_SAMPLES_PER_CYCLE, 0);
/* De-tune FROs */
sys_write32(TRNG_FRODETUNE_FRO_MASK_M, TRNG_BASE + TRNG_O_FRODETUNE);
/* Enable FROs */
sys_write32(TRNG_FROEN_FRO_MASK_M, TRNG_BASE + TRNG_O_FROEN);
/* Set shutdown and alarm thresholds */
sys_write32((CONFIG_ENTROPY_CC13XX_CC26XX_SHUTDOWN_THRESHOLD << 16) |
CONFIG_ENTROPY_CC13XX_CC26XX_ALARM_THRESHOLD,
TRNG_BASE + TRNG_O_ALARMCNT);

TRNGEnable();
TRNGIntEnable(TRNG_NUMBER_READY | TRNG_FRO_SHUTDOWN);

IRQ_CONNECT(DT_TI_CC13XX_CC26XX_TRNG_0_IRQ_0,
DT_TI_CC13XX_CC26XX_TRNG_0_IRQ_0_PRIORITY,
entropy_cc13xx_cc26xx_isr,
DEVICE_GET(entropy_cc13xx_cc26xx), 0);
irq_enable(DT_TI_CC13XX_CC26XX_TRNG_0_IRQ_0);

return 0;
}

static const struct entropy_driver_api entropy_cc13xx_cc26xx_driver_api = {
.get_entropy = entropy_cc13xx_cc26xx_get_entropy,
};

static struct entropy_cc13xx_cc26xx_data entropy_cc13xx_cc26xx_data = {
.lock = Z_SEM_INITIALIZER(entropy_cc13xx_cc26xx_data.lock, 1, 1),
.sync = Z_SEM_INITIALIZER(entropy_cc13xx_cc26xx_data.sync, 0, 1),
};

DEVICE_AND_API_INIT(entropy_cc13xx_cc26xx, DT_TI_CC13XX_CC26XX_TRNG_0_LABEL,
entropy_cc13xx_cc26xx_init, &entropy_cc13xx_cc26xx_data,
NULL, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&entropy_cc13xx_cc26xx_driver_api);
@@ -52,6 +52,14 @@
#gpio-cells = <2>;
};

trng: random@40028000 {
compatible = "ti,cc13xx-cc26xx-trng";
reg = <0x40028000 0x2000>;
interrupts = <33 0>;
status = "disabled";
label = "TRNG";
};

uart0: uart@40001000 {
compatible = "ti,cc13xx-cc26xx-uart";
reg = <0x40001000 0x1000>;
@@ -0,0 +1,39 @@
#
# Copyright (c) 2019 Brett Witherspoon
#
# SPDX-License-Identifier: Apache-2.0
#
---
title: TI SimpleLink CC13xx / CC26xx True Random Number Generator (TRNG)
version: 0.1

description: >
This is a representation of the TI SimpleLink CC13xx / CC26xx TRNG node
properties:
compatible:
type: string
category: required
description: compatible strings
constraint: "ti,cc13xx-cc26xx-trng"
generation: define

reg:
type: int
description: mmio register space
generation: define
category: required

interrupts:
type: compound
category: required
description: required interrupts
generation: define

label:
type: string
category: required
description: Human readable string describing the device (used by Zephyr for API name)
generation: define

...
@@ -39,6 +39,13 @@ config GPIO_CC13XX_CC26XX

endif # GPIO

if ENTROPY_GENERATOR

config ENTROPY_CC13XX_CC26XX_RNG
default y

endif # ENTROPY_GENERATOR

if SERIAL

config UART_CC13XX_CC26XX
@@ -7,5 +7,6 @@
/* SoC level DTS fixup file */

#define DT_NUM_IRQ_PRIO_BITS DT_ARM_V7M_NVIC_E000E100_ARM_NUM_IRQ_PRIORITY_BITS
#define CONFIG_ENTROPY_NAME DT_TI_CC13XX_CC26XX_TRNG_0_LABEL

/* End of SoC Level DTS fixup file */

0 comments on commit 2bee500

Please sign in to comment.
You can’t perform that action at this time.