From 51930d9710ef8a639147cda001b783d2da7bb200 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 27 Mar 2019 16:00:01 +0100 Subject: [PATCH] drivers: entropy: Add SAM0 entropy driver This adds a driver for the True Random Number Generator found in some Atmel SAM0 SoCs. The Code is based on the driver for the SAM TRNG, but uses different register and clock definitions. Signed-off-by: Benjamin Valentin --- CODEOWNERS | 1 + drivers/entropy/CMakeLists.txt | 1 + drivers/entropy/Kconfig | 1 + drivers/entropy/Kconfig.sam0 | 13 +++ drivers/entropy/entropy_sam0.c | 159 ++++++++++++++++++++++++++ dts/bindings/rng/atmel,sam0-trng.yaml | 21 ++++ 6 files changed, 196 insertions(+) create mode 100644 drivers/entropy/Kconfig.sam0 create mode 100644 drivers/entropy/entropy_sam0.c create mode 100644 dts/bindings/rng/atmel,sam0-trng.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 99a3411d6c43a..ca5e9d272babd 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -129,6 +129,7 @@ /drivers/ps2/ @albertofloyd @franciscomunoz @scottwcpg /drivers/kscan/ @albertofloyd @franciscomunoz @scottwcpg /drivers/ethernet/ @jukkar @tbursztyka @pfalcon +/drivers/entropy/*sam0* @benpicco /drivers/flash/ @nashif @nvlsianpu /drivers/flash/*native_posix* @vanwinkeljan @aescolar /drivers/flash/*nrf* @nvlsianpu diff --git a/drivers/entropy/CMakeLists.txt b/drivers/entropy/CMakeLists.txt index 2b26f08977877..d28c1db6d1907 100644 --- a/drivers/entropy/CMakeLists.txt +++ b/drivers/entropy/CMakeLists.txt @@ -8,6 +8,7 @@ zephyr_library_sources_ifdef(CONFIG_ENTROPY_MCUX_RNGA entropy_mcux_rnga zephyr_library_sources_ifdef(CONFIG_ENTROPY_MCUX_TRNG entropy_mcux_trng.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_NRF5_RNG entropy_nrf5.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_SAM_RNG entropy_sam.c) +zephyr_library_sources_ifdef(CONFIG_ENTROPY_SAM0_RNG entropy_sam0.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_STM32_RNG entropy_stm32.c) zephyr_library_sources_ifdef(CONFIG_FAKE_ENTROPY_NATIVE_POSIX fake_entropy_native_posix.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE entropy_handlers.c) diff --git a/drivers/entropy/Kconfig b/drivers/entropy/Kconfig index 24ec9b13aab82..aa1de918c8cd9 100644 --- a/drivers/entropy/Kconfig +++ b/drivers/entropy/Kconfig @@ -19,6 +19,7 @@ source "drivers/entropy/Kconfig.stm32" source "drivers/entropy/Kconfig.esp32" source "drivers/entropy/Kconfig.nrf5" source "drivers/entropy/Kconfig.sam" +source "drivers/entropy/Kconfig.sam0" source "drivers/entropy/Kconfig.native_posix" config ENTROPY_HAS_DRIVER diff --git a/drivers/entropy/Kconfig.sam0 b/drivers/entropy/Kconfig.sam0 new file mode 100644 index 0000000000000..eb8ecc240be37 --- /dev/null +++ b/drivers/entropy/Kconfig.sam0 @@ -0,0 +1,13 @@ +# Kconfig.sam - Atmel SAM0 TRNG configuration +# +# Copyright (c) 2019 Benjamin Valentin +# +# SPDX-License-Identifier: Apache-2.0 + +config ENTROPY_SAM0_RNG + bool "Atmel SAM0 MCU Family True Random Number Generator (TRNG) Driver" + depends on SOC_FAMILY_SAM0 + select ENTROPY_HAS_DRIVER + select HAS_DTS_ENTROPY + help + Enable True Random Number Generator (TRNG) driver for Atmel SAM0 MCUs. diff --git a/drivers/entropy/entropy_sam0.c b/drivers/entropy/entropy_sam0.c new file mode 100644 index 0000000000000..dd964bfdf1a46 --- /dev/null +++ b/drivers/entropy/entropy_sam0.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2019 ML!PA Consulting GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +struct trng_sam0_dev_cfg { + Trng *regs; +}; + +#define DEV_CFG(dev) \ + ((const struct trng_sam0_dev_cfg *const)(dev)->config->config_info) + +static int entropy_sam0_wait_ready(Trng *const trng, u32_t flags) +{ + /* According to the reference manual, the generator provides + * one 32-bit random value every 84 peripheral clock cycles. + * MCK may not be smaller than HCLK/4, so it should not take + * more than 336 HCLK ticks. Assuming the CPU can do 1 + * instruction per HCLK the number of times to loop before + * the TRNG is ready is less than 1000. And that is when + * assuming the loop only takes 1 instruction. So looping a + * million times should be more than enough. + */ + int timeout = 1000000; + + while (!trng->INTFLAG.bit.DATARDY) { + if (timeout-- == 0) { + return -ETIMEDOUT; + } + + if ((flags & ENTROPY_BUSYWAIT) == 0U) { + /* This internal function is used by both get_entropy, + * and get_entropy_isr APIs. The later may call this + * function with the ENTROPY_BUSYWAIT flag set. In + * that case make no assumption that the kernel is + * initialized when the function is called; so, just + * do busy-wait for the random data to be ready. + */ + k_yield(); + } + } + + return 0; +} + +static int entropy_sam0_get_entropy_internal(struct device *dev, u8_t *buffer, + u16_t length, u32_t flags) +{ + Trng *const trng = DEV_CFG(dev)->regs; + + while (length > 0) { + size_t to_copy; + u32_t value; + int res; + + res = entropy_sam0_wait_ready(trng, flags); + if (res < 0) { + return res; + } + + value = TRNG->DATA.reg; + to_copy = MIN(length, sizeof(value)); + + memcpy(buffer, &value, to_copy); + buffer += to_copy; + length -= to_copy; + } + + return 0; +} + +static int entropy_sam0_get_entropy(struct device *dev, u8_t *buffer, + u16_t length) +{ + return entropy_sam0_get_entropy_internal(dev, buffer, length, 0); +} + +static int entropy_sam0_get_entropy_isr(struct device *dev, u8_t *buffer, + u16_t length, u32_t flags) +{ + u16_t cnt = length; + + + if ((flags & ENTROPY_BUSYWAIT) == 0U) { + + /* No busy wait; return whatever data is available. */ + + Trng *const trng = DEV_CFG(dev)->regs; + + do { + size_t to_copy; + u32_t value; + + if (!(trng->INTFLAG.bit.DATARDY)) { + + /* Data not ready */ + break; + } + + value = TRNG->DATA.reg; + to_copy = MIN(length, sizeof(value)); + + memcpy(buffer, &value, to_copy); + buffer += to_copy; + length -= to_copy; + + } while (length > 0); + + return cnt - length; + + } else { + /* Allowed to busy-wait */ + int ret = + entropy_sam0_get_entropy_internal(dev, + buffer, length, flags); + + if (ret == 0) { + /* Data retrieved successfully. */ + return cnt; + } + + return ret; + } +} + +static int entropy_sam0_init(struct device *dev) +{ + Trng *const trng = DEV_CFG(dev)->regs; + + /* Enable the MCLK */ + MCLK->APBCMASK.bit.TRNG_ = 1; + + /* Enable the TRNG */ + trng->CTRLA.bit.ENABLE = 1; + + return 0; +} + +static const struct entropy_driver_api entropy_sam0_api = { + .get_entropy = entropy_sam0_get_entropy, + .get_entropy_isr = entropy_sam0_get_entropy_isr +}; + +static const struct trng_sam0_dev_cfg trng_sam0_cfg = { + .regs = (Trng *)DT_ATMEL_SAM0_TRNG_0_BASE_ADDRESS, +}; + +DEVICE_AND_API_INIT(entropy_sam0, CONFIG_ENTROPY_NAME, + entropy_sam0_init, NULL, &trng_sam0_cfg, + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &entropy_sam0_api); diff --git a/dts/bindings/rng/atmel,sam0-trng.yaml b/dts/bindings/rng/atmel,sam0-trng.yaml new file mode 100644 index 0000000000000..98abd92faae40 --- /dev/null +++ b/dts/bindings/rng/atmel,sam0-trng.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2019 ML!PA Consulting GmbH +# SPDX-License-Identifier: Apache-2.0 + +title: Atmel SAM0 TRNG (True Random Number Generator) + +description: > + This binding gives a base representation of the Atmel SAM0 RNG + +compatible: "atmel,sam0-trng" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + label: + required: true