From 912a51957e534a372298b483b7393e639b474896 Mon Sep 17 00:00:00 2001 From: Thiago Silveira Date: Tue, 19 Sep 2017 05:01:27 -0300 Subject: [PATCH] drivers: entropy: Add nRF5 entropy generator driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Origin: Original Signed-off-by: Thiago Silveira Signed-off-by: Andrzej Głąbek --- drivers/entropy/CMakeLists.txt | 1 + drivers/entropy/Kconfig | 1 + drivers/entropy/Kconfig.nrf5 | 25 ++++++++ drivers/entropy/entropy_nrf5.c | 102 +++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 drivers/entropy/Kconfig.nrf5 create mode 100644 drivers/entropy/entropy_nrf5.c diff --git a/drivers/entropy/CMakeLists.txt b/drivers/entropy/CMakeLists.txt index 23e44fd7fb1..aff6939f76e 100644 --- a/drivers/entropy/CMakeLists.txt +++ b/drivers/entropy/CMakeLists.txt @@ -1,5 +1,6 @@ zephyr_sources_ifdef(CONFIG_ENTROPY_ESP32_RNG entropy_esp32.c) zephyr_sources_ifdef(CONFIG_ENTROPY_MCUX_RNGA entropy_mcux_rnga.c) zephyr_sources_ifdef(CONFIG_ENTROPY_MCUX_TRNG entropy_mcux_trng.c) +zephyr_sources_ifdef(CONFIG_ENTROPY_NRF5_RNG entropy_nrf5.c) zephyr_sources_ifdef(CONFIG_ENTROPY_STM32_RNG entropy_stm32_rng.c) zephyr_sources_ifdef(CONFIG_USERSPACE entropy_handlers.c) diff --git a/drivers/entropy/Kconfig b/drivers/entropy/Kconfig index d5e2fac1a82..dca59d6b3a8 100644 --- a/drivers/entropy/Kconfig +++ b/drivers/entropy/Kconfig @@ -18,6 +18,7 @@ if ENTROPY_GENERATOR source "drivers/entropy/Kconfig.mcux" source "drivers/entropy/Kconfig.stm32" source "drivers/entropy/Kconfig.esp32" +source "drivers/entropy/Kconfig.nrf5" config ENTROPY_HAS_DRIVER bool diff --git a/drivers/entropy/Kconfig.nrf5 b/drivers/entropy/Kconfig.nrf5 new file mode 100644 index 00000000000..5ad642841ed --- /dev/null +++ b/drivers/entropy/Kconfig.nrf5 @@ -0,0 +1,25 @@ +# Kconfig.nrf5 - nRF5 entropy generator driver configuration +# +# Copyright (c) 2017 Nordic Semiconductor ASA +# Copyright (c) 2017 Exati Tecnologia Ltda. +# +# SPDX-License-Identifier: Apache-2.0 + +menuconfig ENTROPY_NRF5_RNG + bool "nRF5 RNG driver" + # FIXME: nRF5 RNG driver can't co-exist with Bluetooth's HAL + # implementation yet + depends on ENTROPY_GENERATOR && !BT + select ENTROPY_HAS_DRIVER + help + This option enables the RNG peripheral, which is a random number + generator, based on internal thermal noise, that provides a + random 8-bit value to the host when read. + +config ENTROPY_NRF5_BIAS_CORRECTION + bool "Enable bias correction (uniform distribution)" + depends on ENTROPY_NRF5_RNG + help + This option enables the RNG bias correction, which guarantees a + uniform distribution of 0 and 1. When this option is enabled, the time + to generate a byte cannot be guaranteed. diff --git a/drivers/entropy/entropy_nrf5.c b/drivers/entropy/entropy_nrf5.c new file mode 100644 index 00000000000..0fc209607eb --- /dev/null +++ b/drivers/entropy/entropy_nrf5.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2017 Exati Tecnologia Ltda. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +struct entropy_nrf5_dev_data { + atomic_t user_count; +}; + +#define DEV_DATA(dev) \ + ((struct entropy_nrf5_dev_data *)(dev)->driver_data) + +static inline u8_t entropy_nrf5_get_u8(void) +{ + while (!nrf_rng_event_get(NRF_RNG_EVENT_VALRDY)) { + __WFE(); + __SEV(); + __WFE(); + } + nrf_rng_event_clear(NRF_RNG_EVENT_VALRDY); + + /* Clear the Pending status of the RNG interrupt so that it could + * wake up the core when the VALRDY event occurs again. */ + NVIC_ClearPendingIRQ(RNG_IRQn); + + return nrf_rng_random_value_get(); +} + +static int entropy_nrf5_get_entropy(struct device *device, u8_t *buf, u16_t len) +{ + /* Mark the peripheral as being used */ + atomic_inc(&DEV_DATA(device)->user_count); + + /* Disable the shortcut that stops the task after a byte is generated */ + nrf_rng_shorts_disable(NRF_RNG_SHORT_VALRDY_STOP_MASK); + + /* Start the RNG generator peripheral */ + nrf_rng_task_trigger(NRF_RNG_TASK_START); + + while (len) { + *buf = entropy_nrf5_get_u8(); + buf++; + len--; + } + + /* Only stop the RNG generator peripheral if we're the last user */ + if (atomic_dec(&DEV_DATA(device)->user_count) == 1) { + /* Disable the peripheral on the next VALRDY event */ + nrf_rng_shorts_enable(NRF_RNG_SHORT_VALRDY_STOP_MASK); + + if (atomic_get(&DEV_DATA(device)->user_count) != 0) { + /* Race condition: another thread started to use + * the peripheral while we were disabling it. + * Enable the peripheral again + */ + nrf_rng_shorts_disable(NRF_RNG_SHORT_VALRDY_STOP_MASK); + nrf_rng_task_trigger(NRF_RNG_TASK_START); + } + } + + return 0; +} + +static int entropy_nrf5_init(struct device *device) +{ + /* Enable the RNG interrupt to be generated on the VALRDY event, + * but do not enable this interrupt in NVIC to be serviced. + * When the interrupt enters the Pending state it will set internal + * event (SEVONPEND is activated by kernel) and wake up the core + * if it was suspended by WFE. And that's enough. */ + nrf_rng_int_enable(NRF_RNG_INT_VALRDY_MASK); + NVIC_ClearPendingIRQ(RNG_IRQn); + + /* Enable or disable bias correction */ + if (IS_ENABLED(CONFIG_ENTROPY_NRF5_BIAS_CORRECTION)) { + nrf_rng_error_correction_enable(); + } else { + nrf_rng_error_correction_disable(); + } + + /* Initialize the user count with zero */ + atomic_clear(&DEV_DATA(device)->user_count); + + return 0; +} + +static struct entropy_nrf5_dev_data entropy_nrf5_data; + +static const struct entropy_driver_api entropy_nrf5_api_funcs = { + .get_entropy = entropy_nrf5_get_entropy +}; + +DEVICE_AND_API_INIT(entropy_nrf5, CONFIG_ENTROPY_NAME, + entropy_nrf5_init, &entropy_nrf5_data, NULL, + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &entropy_nrf5_api_funcs);