Commit 2bee500f authored by Brett Witherspoon's avatar Brett Witherspoon Committed by Kumar Gala
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: default avatarBrett Witherspoon <spoonb@cdspooner.com>
parent 3bcd1880
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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)
+1 −0
Original line number Diff line number Diff line
@@ -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"
+51 −0
Original line number Diff line number Diff line
# 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
+170 −0
Original line number Diff line number Diff line
/*
 * 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);
+8 −0
Original line number Diff line number Diff line
@@ -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>;
Loading