mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-08-03 14:14:33 +00:00
Even though the STM32 TRNG hardware produces 2- or 4-byte sized words of random data before triggering an interrupt, the driver currently discards all but the bottom byte: 50/75% of the produced entropy goes to waste! Make sure we consume all the random data from each word we read to improve the entropy generation rate seen by users of the driver. Signed-off-by: Mathieu Choplain <mathieu.choplain@st.com>
122 lines
3.4 KiB
C
122 lines
3.4 KiB
C
/*
|
|
* Copyright (c) 2025 STMicroelectronics
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/device.h>
|
|
#include <stm32_ll_rng.h>
|
|
|
|
/**
|
|
* This driver supports two compatibles:
|
|
* - "st,stm32-rng" for TRNG with IRQ lines
|
|
* - "st,stm32-rng-noirq" for TRNG without IRQ lines
|
|
*/
|
|
#define IRQLESS_TRNG DT_HAS_COMPAT_STATUS_OKAY(st_stm32_rng_noirq)
|
|
|
|
#if IRQLESS_TRNG
|
|
#define DT_DRV_COMPAT st_stm32_rng_noirq
|
|
#define TRNG_GENERATION_DELAY K_NSEC(DT_INST_PROP_OR(0, generation_delay_ns, 0))
|
|
#else /* !IRQLESS_TRNG */
|
|
#define DT_DRV_COMPAT st_stm32_rng
|
|
#define IRQN DT_INST_IRQN(0)
|
|
#define IRQ_PRIO DT_INST_IRQ(0, priority)
|
|
#endif /* IRQLESS_TRNG */
|
|
|
|
/* Cross-series LL compatibility wrappers */
|
|
static inline void ll_rng_enable_it(RNG_TypeDef *RNGx)
|
|
{
|
|
/* Silence "unused" warning on IRQ-less hardware*/
|
|
ARG_UNUSED(RNGx);
|
|
#if !IRQLESS_TRNG
|
|
# if defined(CONFIG_SOC_STM32WB09XX)
|
|
LL_RNG_EnableEnErrorIrq(RNGx);
|
|
LL_RNG_EnableEnFfFullIrq(RNGx);
|
|
# else
|
|
LL_RNG_EnableIT(RNGx);
|
|
# endif
|
|
#endif /* !IRQLESS_TRNG */
|
|
}
|
|
|
|
static inline uint32_t ll_rng_is_active_seis(RNG_TypeDef *RNGx)
|
|
{
|
|
#if defined(CONFIG_SOC_STM32WB09XX)
|
|
return LL_RNG_IsActiveFlag_ENTROPY_ERR(RNGx);
|
|
#elif defined(CONFIG_SOC_SERIES_STM32WB0X)
|
|
/* STM32WB05 / STM32WB06 / STM32WB07 */
|
|
return LL_RNG_IsActiveFlag_FAULT(RNGx);
|
|
#else
|
|
return LL_RNG_IsActiveFlag_SEIS(RNGx);
|
|
#endif /* CONFIG_SOC_SERIES_STM32WB0X */
|
|
}
|
|
|
|
static inline void ll_rng_clear_seis(RNG_TypeDef *RNGx)
|
|
{
|
|
#if defined(CONFIG_SOC_STM32WB09XX)
|
|
LL_RNG_SetResetHealthErrorFlags(RNGx, 1);
|
|
#elif defined(CONFIG_SOC_SERIES_STM32WB0X)
|
|
/* STM32WB05 / STM32WB06 / STM32WB07 */
|
|
LL_RNG_ClearFlag_FAULT(RNGx);
|
|
#else
|
|
LL_RNG_ClearFlag_SEIS(RNGx);
|
|
#endif /* CONFIG_SOC_SERIES_STM32WB0X */
|
|
}
|
|
|
|
static inline uint32_t ll_rng_is_active_secs(RNG_TypeDef *RNGx)
|
|
{
|
|
#if !defined(CONFIG_SOC_SERIES_STM32WB0X)
|
|
return LL_RNG_IsActiveFlag_SECS(RNGx);
|
|
#else
|
|
/**
|
|
* STM32WB0x RNG has no equivalent of SECS.
|
|
* Since this flag is always checked in conjunction
|
|
* with FAULT (the SEIS equivalent), returning 0 is OK.
|
|
*/
|
|
return 0;
|
|
#endif /* !CONFIG_SOC_SERIES_STM32WB0X */
|
|
}
|
|
|
|
static inline uint32_t ll_rng_is_active_drdy(RNG_TypeDef *RNGx)
|
|
{
|
|
#if defined(CONFIG_SOC_STM32WB09XX)
|
|
return LL_RNG_IsActiveFlag_VAL_READY(RNGx);
|
|
#elif defined(CONFIG_SOC_SERIES_STM32WB0X)
|
|
/* STM32WB05 / STM32WB06 / STM32WB07 */
|
|
return LL_RNG_IsActiveFlag_RNGRDY(RNGx);
|
|
#else
|
|
return LL_RNG_IsActiveFlag_DRDY(RNGx);
|
|
#endif /* CONFIG_SOC_SERIES_STM32WB0X */
|
|
}
|
|
|
|
#if defined(CONFIG_SOC_SERIES_STM32WB0X) && !defined(CONFIG_SOC_STM32WB09XX)
|
|
/* STM32WB05, STM32WB06 and STM32WB07 have 16-bit data register */
|
|
typedef uint16_t rng_sample_t;
|
|
#else
|
|
/* All other TRNG IPs have 32-bit data register */
|
|
typedef uint32_t rng_sample_t;
|
|
#endif
|
|
|
|
static inline rng_sample_t ll_rng_read_rand_data(RNG_TypeDef *RNGx)
|
|
{
|
|
#if defined(CONFIG_SOC_STM32WB09XX)
|
|
rng_sample_t rnd = LL_RNG_GetRndVal(RNGx);
|
|
|
|
/**
|
|
* STM32WB09 TRNG does not clear IRQ flags in hardware.
|
|
* We must clear the "FIFO full" flag now that we consumed data
|
|
* from it to ensure the TRNG's IRQ line goes back to low state.
|
|
*
|
|
* Raw register access is performed because STM32CubeWB0 v1.0.0
|
|
* package is lacking the LL function to clear IRQ flags.
|
|
*/
|
|
WRITE_REG(RNG->IRQ_SR, RNG_IRQ_SR_FF_FULL_IRQ);
|
|
|
|
return rnd;
|
|
#elif defined(CONFIG_SOC_SERIES_STM32WB0X)
|
|
/* STM32WB05 / STM32WB06 / STM32WB07 */
|
|
return LL_RNG_ReadRandData16(RNGx);
|
|
#else
|
|
return LL_RNG_ReadRandData32(RNGx);
|
|
#endif /* CONFIG_SOC_SERIES_STM32WB0X */
|
|
}
|