[PATCH 1/7] rng: stm32: rename STM32 RNG driver

Rename the RNG driver as it is usable by other STM32 platforms than the STM32MP1x ones. Rename CONFIG_RNG_STM32MP1 to CONFIG_RNG_STM32
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com --- MAINTAINERS | 2 +- configs/stm32mp15_basic_defconfig | 2 +- configs/stm32mp15_defconfig | 2 +- configs/stm32mp15_trusted_defconfig | 2 +- drivers/rng/Kconfig | 6 +++--- drivers/rng/Makefile | 2 +- drivers/rng/{stm32mp1_rng.c => stm32_rng.c} | 0 7 files changed, 8 insertions(+), 8 deletions(-) rename drivers/rng/{stm32mp1_rng.c => stm32_rng.c} (100%)
diff --git a/MAINTAINERS b/MAINTAINERS index 0a10a436bc..a3bffa63d5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -621,7 +621,7 @@ F: drivers/ram/stm32mp1/ F: drivers/remoteproc/stm32_copro.c F: drivers/reset/stm32-reset.c F: drivers/rng/optee_rng.c -F: drivers/rng/stm32mp1_rng.c +F: drivers/rng/stm32_rng.c F: drivers/rtc/stm32_rtc.c F: drivers/serial/serial_stm32.* F: drivers/spi/stm32_qspi.c diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 9ea5aaa714..29b869cf34 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -150,7 +150,7 @@ CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_REMOTEPROC_STM32_COPRO=y CONFIG_DM_RNG=y -CONFIG_RNG_STM32MP1=y +CONFIG_RNG_STM32=y CONFIG_DM_RTC=y CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y diff --git a/configs/stm32mp15_defconfig b/configs/stm32mp15_defconfig index 4d0a81f8a8..b061a83f9d 100644 --- a/configs/stm32mp15_defconfig +++ b/configs/stm32mp15_defconfig @@ -123,7 +123,7 @@ CONFIG_DM_REGULATOR_SCMI=y CONFIG_REMOTEPROC_STM32_COPRO=y CONFIG_RESET_SCMI=y CONFIG_DM_RNG=y -CONFIG_RNG_STM32MP1=y +CONFIG_RNG_STM32=y CONFIG_DM_RTC=y CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 0a7d862485..b51eefe652 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -123,7 +123,7 @@ CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_REMOTEPROC_STM32_COPRO=y CONFIG_RESET_SCMI=y CONFIG_DM_RNG=y -CONFIG_RNG_STM32MP1=y +CONFIG_RNG_STM32=y CONFIG_DM_RTC=y CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig index 5deb5db5b7..1563ff3ab8 100644 --- a/drivers/rng/Kconfig +++ b/drivers/rng/Kconfig @@ -48,11 +48,11 @@ config RNG_OPTEE accessible to normal world but reserved and used by the OP-TEE to avoid the weakness of a software PRNG.
-config RNG_STM32MP1 - bool "Enable random number generator for STM32MP1" +config RNG_STM32 + bool "Enable random number generator for STM32" depends on ARCH_STM32MP help - Enable STM32MP1 rng driver. + Enable STM32 rng driver.
config RNG_ROCKCHIP bool "Enable random number generator for rockchip crypto rng" diff --git a/drivers/rng/Makefile b/drivers/rng/Makefile index 78f61051ac..192f911e15 100644 --- a/drivers/rng/Makefile +++ b/drivers/rng/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_RNG_SANDBOX) += sandbox_rng.o obj-$(CONFIG_RNG_MSM) += msm_rng.o obj-$(CONFIG_RNG_NPCM) += npcm_rng.o obj-$(CONFIG_RNG_OPTEE) += optee_rng.o -obj-$(CONFIG_RNG_STM32MP1) += stm32mp1_rng.o +obj-$(CONFIG_RNG_STM32) += stm32_rng.o obj-$(CONFIG_RNG_ROCKCHIP) += rockchip_rng.o obj-$(CONFIG_RNG_IPROC200) += iproc_rng200.o obj-$(CONFIG_RNG_SMCCC_TRNG) += smccc_trng.o diff --git a/drivers/rng/stm32mp1_rng.c b/drivers/rng/stm32_rng.c similarity index 100% rename from drivers/rng/stm32mp1_rng.c rename to drivers/rng/stm32_rng.c

Default embed this configuration. If OP-TEE PTA RNG is present as well, the priority will be given to it instead of the U-Boot driver.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com --- configs/stm32mp13_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/stm32mp13_defconfig b/configs/stm32mp13_defconfig index 82b62744f6..4a899c85de 100644 --- a/configs/stm32mp13_defconfig +++ b/configs/stm32mp13_defconfig @@ -65,6 +65,7 @@ CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_SCMI=y CONFIG_RESET_SCMI=y CONFIG_DM_RNG=y +CONFIG_RNG_STM32=y CONFIG_DM_RTC=y CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y

On 9/7/23 18:21, Gatien Chevallier wrote:
Default embed this configuration. If OP-TEE PTA RNG is present as well, the priority will be given to it instead of the U-Boot driver.
Are you relying here on drivers being probed in alphabetical sequence?
Best regards
Heinrich
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com
configs/stm32mp13_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/stm32mp13_defconfig b/configs/stm32mp13_defconfig index 82b62744f6..4a899c85de 100644 --- a/configs/stm32mp13_defconfig +++ b/configs/stm32mp13_defconfig @@ -65,6 +65,7 @@ CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_SCMI=y CONFIG_RESET_SCMI=y CONFIG_DM_RNG=y +CONFIG_RNG_STM32=y CONFIG_DM_RTC=y CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y

On 9/8/23 20:58, Heinrich Schuchardt wrote:
On 9/7/23 18:21, Gatien Chevallier wrote:
Default embed this configuration. If OP-TEE PTA RNG is present as well, the priority will be given to it instead of the U-Boot driver.
Are you relying here on drivers being probed in alphabetical sequence?
Best regards
Heinrich
Hello Heinrich,
I've made a strange wording here.
OP-TEE RNG PTA shouldn't be exposed if the RNG is non-secure as it shouldn't be handled by the secure world. If it is, it is a bad OP-TEE configuration.
On the contrary, if the RNG OPTEE PTA is exposed, then the OP-TEE RNG PTA should be used. Therefore, the RNG node status shouldn't be set to "okay" in U-boot's device tree.
Hope this solves the confusion, I'll reword the sentence.
Best regards, Gatien
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com
configs/stm32mp13_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/stm32mp13_defconfig b/configs/stm32mp13_defconfig index 82b62744f6..4a899c85de 100644 --- a/configs/stm32mp13_defconfig +++ b/configs/stm32mp13_defconfig @@ -65,6 +65,7 @@ CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_SCMI=y CONFIG_RESET_SCMI=y CONFIG_DM_RNG=y +CONFIG_RNG_STM32=y CONFIG_DM_RTC=y CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y

Hi,
On 9/7/23 18:21, Gatien Chevallier wrote:
Default embed this configuration. If OP-TEE PTA RNG is present as well, the priority will be given to it instead of the U-Boot driver.
The STM32 RNG driver will be probed when the is activated in U-Boot device tree,
it is avaiable for non secure world.
OP-TEE RNG PTA will be registered when the RNG access is liited to
secure world by firewall.
For me not priority here but secure/non secure configuration, managed by device tree.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com
configs/stm32mp13_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/stm32mp13_defconfig b/configs/stm32mp13_defconfig index 82b62744f6..4a899c85de 100644 --- a/configs/stm32mp13_defconfig +++ b/configs/stm32mp13_defconfig @@ -65,6 +65,7 @@ CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_SCMI=y CONFIG_RESET_SCMI=y CONFIG_DM_RNG=y +CONFIG_RNG_STM32=y CONFIG_DM_RTC=y CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y
with commit message update
Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com
Thanks Patrick

RNG clock error detection is now enabled if the "clock-error-detect" property is set in the device tree.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com --- drivers/rng/stm32_rng.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/drivers/rng/stm32_rng.c b/drivers/rng/stm32_rng.c index 89da78c6c8..ada5d92214 100644 --- a/drivers/rng/stm32_rng.c +++ b/drivers/rng/stm32_rng.c @@ -40,6 +40,7 @@ struct stm32_rng_plat { struct clk clk; struct reset_ctl rst; const struct stm32_rng_data *data; + bool ced; };
static int stm32_rng_read(struct udevice *dev, void *data, size_t len) @@ -97,25 +98,34 @@ static int stm32_rng_init(struct stm32_rng_plat *pdata)
cr = readl(pdata->base + RNG_CR);
- /* Disable CED */ - cr |= RNG_CR_CED; if (pdata->data->has_cond_reset) { cr |= RNG_CR_CONDRST; + if (pdata->ced) + cr &= ~RNG_CR_CED; + else + cr |= RNG_CR_CED; writel(cr, pdata->base + RNG_CR); cr &= ~RNG_CR_CONDRST; + cr |= RNG_CR_RNGEN; writel(cr, pdata->base + RNG_CR); err = readl_poll_timeout(pdata->base + RNG_CR, cr, (!(cr & RNG_CR_CONDRST)), 10000); if (err) return err; + } else { + if (pdata->ced) + cr &= ~RNG_CR_CED; + else + cr |= RNG_CR_CED; + + cr |= RNG_CR_RNGEN; + + writel(cr, pdata->base + RNG_CR); }
/* clear error indicators */ writel(0, pdata->base + RNG_SR);
- cr |= RNG_CR_RNGEN; - writel(cr, pdata->base + RNG_CR); - err = readl_poll_timeout(pdata->base + RNG_SR, sr, sr & RNG_SR_DRDY, 10000); return err; @@ -165,6 +175,8 @@ static int stm32_rng_of_to_plat(struct udevice *dev) if (err) return err;
+ pdata->ced = dev_read_bool(dev, "clock-error-detect"); + return 0; }

On 9/7/23 18:21, Gatien Chevallier wrote:
RNG clock error detection is now enabled if the "clock-error-detect" property is set in the device tree.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com
drivers/rng/stm32_rng.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/drivers/rng/stm32_rng.c b/drivers/rng/stm32_rng.c index 89da78c6c8..ada5d92214 100644 --- a/drivers/rng/stm32_rng.c +++ b/drivers/rng/stm32_rng.c @@ -40,6 +40,7 @@ struct stm32_rng_plat { struct clk clk; struct reset_ctl rst; const struct stm32_rng_data *data;
bool ced; };
static int stm32_rng_read(struct udevice *dev, void *data, size_t len)
@@ -97,25 +98,34 @@ static int stm32_rng_init(struct stm32_rng_plat *pdata)
cr = readl(pdata->base + RNG_CR);
- /* Disable CED */
- cr |= RNG_CR_CED; if (pdata->data->has_cond_reset) { cr |= RNG_CR_CONDRST;
if (pdata->ced)
cr &= ~RNG_CR_CED;
else
cr |= RNG_CR_CED;
writel(cr, pdata->base + RNG_CR); cr &= ~RNG_CR_CONDRST;
cr |= RNG_CR_RNGEN;
writel(cr, pdata->base + RNG_CR); err = readl_poll_timeout(pdata->base + RNG_CR, cr, (!(cr & RNG_CR_CONDRST)), 10000); if (err) return err;
} else {
if (pdata->ced)
cr &= ~RNG_CR_CED;
else
cr |= RNG_CR_CED;
cr |= RNG_CR_RNGEN;
writel(cr, pdata->base + RNG_CR);
}
/* clear error indicators */ writel(0, pdata->base + RNG_SR);
- cr |= RNG_CR_RNGEN;
- writel(cr, pdata->base + RNG_CR);
- err = readl_poll_timeout(pdata->base + RNG_SR, sr, sr & RNG_SR_DRDY, 10000); return err;
@@ -165,6 +175,8 @@ static int stm32_rng_of_to_plat(struct udevice *dev) if (err) return err;
- pdata->ced = dev_read_bool(dev, "clock-error-detect");
The kernel describes this property in Documentation/devicetree/bindings/rng/st,stm32-rng.yaml
Which patch is adding it to the U-Boot device-trees? I can't find it in this patch series.
It would have been helpful to send a cover-letter with the patch series to get an overview of the changed files in the patch set.
Best regards
Heinrich
- return 0; }

Hi,
On 9/8/23 21:07, Heinrich Schuchardt wrote:
On 9/7/23 18:21, Gatien Chevallier wrote:
RNG clock error detection is now enabled if the "clock-error-detect" property is set in the device tree.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com
drivers/rng/stm32_rng.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/drivers/rng/stm32_rng.c b/drivers/rng/stm32_rng.c index 89da78c6c8..ada5d92214 100644 --- a/drivers/rng/stm32_rng.c +++ b/drivers/rng/stm32_rng.c @@ -40,6 +40,7 @@ struct stm32_rng_plat { struct clk clk; struct reset_ctl rst; const struct stm32_rng_data *data; + bool ced; };
static int stm32_rng_read(struct udevice *dev, void *data, size_t len) @@ -97,25 +98,34 @@ static int stm32_rng_init(struct stm32_rng_plat *pdata)
cr = readl(pdata->base + RNG_CR);
- /* Disable CED */ - cr |= RNG_CR_CED; if (pdata->data->has_cond_reset) { cr |= RNG_CR_CONDRST; + if (pdata->ced) + cr &= ~RNG_CR_CED; + else + cr |= RNG_CR_CED; writel(cr, pdata->base + RNG_CR); cr &= ~RNG_CR_CONDRST; + cr |= RNG_CR_RNGEN; writel(cr, pdata->base + RNG_CR); err = readl_poll_timeout(pdata->base + RNG_CR, cr, (!(cr & RNG_CR_CONDRST)), 10000); if (err) return err; + } else { + if (pdata->ced) + cr &= ~RNG_CR_CED; + else + cr |= RNG_CR_CED;
+ cr |= RNG_CR_RNGEN;
+ writel(cr, pdata->base + RNG_CR); }
/* clear error indicators */ writel(0, pdata->base + RNG_SR);
- cr |= RNG_CR_RNGEN; - writel(cr, pdata->base + RNG_CR);
err = readl_poll_timeout(pdata->base + RNG_SR, sr, sr & RNG_SR_DRDY, 10000); return err; @@ -165,6 +175,8 @@ static int stm32_rng_of_to_plat(struct udevice *dev) if (err) return err;
+ pdata->ced = dev_read_bool(dev, "clock-error-detect");
The kernel describes this property in Documentation/devicetree/bindings/rng/st,stm32-rng.yaml
Which patch is adding it to the U-Boot device-trees? I can't find it in this patch series.
For STM32 platform we rely on the bindin files of kernel to avoid to duplicate the binding after yaml migration
and we add the U-Boot specificity only when it is needed (for clock and ram)
See Documentation: https://u-boot.readthedocs.io/en/stable/board/st/st-dt.html
doc/board/st/st-dt.rst
* rng - rng/st,stm32-rng.yaml
So for me no need of binding patch in U-Boot since [1] as this property is already supported by kernel binding.
[1] 551a959a8c11 ("doc: stm32mp1: add page for device tree bindings")
http://patchwork.ozlabs.org/project/uboot/patch/20210802180823.1.I3aa79d907e...
Patrick
It would have been helpful to send a cover-letter with the patch series to get an overview of the changed files in the patch set.
Best regards
Heinrich
return 0; }

Hi,
On 9/7/23 18:21, Gatien Chevallier wrote:
RNG clock error detection is now enabled if the "clock-error-detect" property is set in the device tree.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com
drivers/rng/stm32_rng.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com
Thanks Patrick

In order to ensure a good RNG quality and compatibility with certified RNG configuration, add RNG clock frequency restraint.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com --- drivers/rng/stm32_rng.c | 43 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-)
diff --git a/drivers/rng/stm32_rng.c b/drivers/rng/stm32_rng.c index ada5d92214..f943acd7d2 100644 --- a/drivers/rng/stm32_rng.c +++ b/drivers/rng/stm32_rng.c @@ -18,10 +18,11 @@ #include <linux/iopoll.h> #include <linux/kernel.h>
-#define RNG_CR 0x00 -#define RNG_CR_RNGEN BIT(2) -#define RNG_CR_CED BIT(5) -#define RNG_CR_CONDRST BIT(30) +#define RNG_CR 0x00 +#define RNG_CR_RNGEN BIT(2) +#define RNG_CR_CED BIT(5) +#define RNG_CR_CLKDIV_SHIFT 16 +#define RNG_CR_CONDRST BIT(30)
#define RNG_SR 0x04 #define RNG_SR_SEIS BIT(6) @@ -31,7 +32,15 @@
#define RNG_DR 0x08
+/* + * struct stm32_rng_data - RNG compat data + * + * @max_clock_rate: Max RNG clock frequency, in Hertz + * @has_cond_reset: True if conditionnal reset is supported + * + */ struct stm32_rng_data { + uint max_clock_rate; bool has_cond_reset; };
@@ -87,6 +96,26 @@ static int stm32_rng_read(struct udevice *dev, void *data, size_t len) return 0; }
+static uint stm32_rng_clock_freq_restrain(struct stm32_rng_plat *pdata) +{ + ulong clock_rate = 0; + uint clock_div = 0; + + clock_rate = clk_get_rate(&pdata->clk); + + /* + * Get the exponent to apply on the CLKDIV field in RNG_CR register. + * No need to handle the case when clock-div > 0xF as it is physically + * impossible. + */ + while ((clock_rate >> clock_div) > pdata->data->max_clock_rate) + clock_div++; + + log_debug("RNG clk rate : %lu\n", clk_get_rate(&pdata->clk) >> clock_div); + + return clock_div; +} + static int stm32_rng_init(struct stm32_rng_plat *pdata) { int err; @@ -99,7 +128,9 @@ static int stm32_rng_init(struct stm32_rng_plat *pdata) cr = readl(pdata->base + RNG_CR);
if (pdata->data->has_cond_reset) { - cr |= RNG_CR_CONDRST; + uint clock_div = stm32_rng_clock_freq_restrain(pdata); + + cr |= RNG_CR_CONDRST | (clock_div << RNG_CR_CLKDIV_SHIFT); if (pdata->ced) cr &= ~RNG_CR_CED; else @@ -186,10 +217,12 @@ static const struct dm_rng_ops stm32_rng_ops = {
static const struct stm32_rng_data stm32mp13_rng_data = { .has_cond_reset = true, + .max_clock_rate = 48000000, };
static const struct stm32_rng_data stm32_rng_data = { .has_cond_reset = false, + .max_clock_rate = 3000000, };
static const struct udevice_id stm32_rng_match[] = {

Hi,
On 9/7/23 18:21, Gatien Chevallier wrote:
In order to ensure a good RNG quality and compatibility with certified RNG configuration, add RNG clock frequency restraint.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com
drivers/rng/stm32_rng.c | 43 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-)
Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com
Thanks Patrick

Seed errors can occur when using the hardware RNG. Implement the sequences to handle them. This avoids irrecoverable RNG state.
Try to conceal seed errors when possible. If, despite the error concealing tries, a seed error is still present, then return an error.
A clock error does not compromise the hardware block and data can still be read from RNG_DR. Just warn that the RNG clock is too slow and clear RNG_SR.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com --- drivers/rng/stm32_rng.c | 163 ++++++++++++++++++++++++++++++++++------ 1 file changed, 140 insertions(+), 23 deletions(-)
diff --git a/drivers/rng/stm32_rng.c b/drivers/rng/stm32_rng.c index f943acd7d2..b1a790b217 100644 --- a/drivers/rng/stm32_rng.c +++ b/drivers/rng/stm32_rng.c @@ -32,6 +32,8 @@
#define RNG_DR 0x08
+#define RNG_NB_RECOVER_TRIES 3 + /* * struct stm32_rng_data - RNG compat data * @@ -52,45 +54,160 @@ struct stm32_rng_plat { bool ced; };
+/* + * Extracts from the STM32 RNG specification when RNG supports CONDRST. + * + * When a noise source (or seed) error occurs, the RNG stops generating + * random numbers and sets to “1” both SEIS and SECS bits to indicate + * that a seed error occurred. (...) + * + * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield + * description for details). This step is needed only if SECS is set. + * Indeed, when SEIS is set and SECS is cleared it means RNG performed + * the reset automatically (auto-reset). + * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST + * to be cleared in the RNG_CR register, then confirm that SEIS is + * cleared in the RNG_SR register. Otherwise just clear SEIS bit in + * the RNG_SR register. + * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be + * cleared by RNG. The random number generation is now back to normal. + */ +static int stm32_rng_conceal_seed_error_cond_reset(struct stm32_rng_plat *pdata) +{ + u32 sr = readl_relaxed(pdata->base + RNG_SR); + u32 cr = readl_relaxed(pdata->base + RNG_CR); + int err; + + if (sr & RNG_SR_SECS) { + /* Conceal by resetting the subsystem (step 1.) */ + writel_relaxed(cr | RNG_CR_CONDRST, pdata->base + RNG_CR); + writel_relaxed(cr & ~RNG_CR_CONDRST, pdata->base + RNG_CR); + } else { + /* RNG auto-reset (step 2.) */ + writel_relaxed(sr & ~RNG_SR_SEIS, pdata->base + RNG_SR); + return 0; + } + + err = readl_relaxed_poll_timeout(pdata->base + RNG_SR, sr, !(sr & RNG_CR_CONDRST), 100000); + if (err) { + log_err("%s: timeout %x\n", __func__, sr); + return err; + } + + /* Check SEIS is cleared (step 2.) */ + if (readl_relaxed(pdata->base + RNG_SR) & RNG_SR_SEIS) + return -EINVAL; + + err = readl_relaxed_poll_timeout(pdata->base + RNG_SR, sr, !(sr & RNG_SR_SECS), 100000); + if (err) { + log_err("%s: timeout %x\n", __func__, sr); + return err; + } + + return 0; +} + +/* + * Extracts from the STM32 RNG specification, when CONDRST is not supported + * + * When a noise source (or seed) error occurs, the RNG stops generating + * random numbers and sets to “1” both SEIS and SECS bits to indicate + * that a seed error occurred. (...) + * + * The following sequence shall be used to fully recover from a seed + * error after the RNG initialization: + * 1. Clear the SEIS bit by writing it to “0”. + * 2. Read out 12 words from the RNG_DR register, and discard each of + * them in order to clean the pipeline. + * 3. Confirm that SEIS is still cleared. Random number generation is + * back to normal. + */ +static int stm32_rng_conceal_seed_error_sw_reset(struct stm32_rng_plat *pdata) +{ + uint i = 0; + u32 sr = readl_relaxed(pdata->base + RNG_SR); + + writel_relaxed(sr & ~RNG_SR_SEIS, pdata->base + RNG_SR); + + for (i = 12; i != 0; i--) + (void)readl_relaxed(pdata->base + RNG_DR); + + if (readl_relaxed(pdata->base + RNG_SR) & RNG_SR_SEIS) + return -EINVAL; + + return 0; +} + +static int stm32_rng_conceal_seed_error(struct stm32_rng_plat *pdata) +{ + log_debug("Concealing RNG seed error\n"); + + if (pdata->data->has_cond_reset) + return stm32_rng_conceal_seed_error_cond_reset(pdata); + else + return stm32_rng_conceal_seed_error_sw_reset(pdata); +}; + static int stm32_rng_read(struct udevice *dev, void *data, size_t len) { - int retval, i; - u32 sr, count, reg; + int retval; + u32 sr, reg; size_t increment; struct stm32_rng_plat *pdata = dev_get_plat(dev); + uint tries = 0;
while (len > 0) { retval = readl_poll_timeout(pdata->base + RNG_SR, sr, - sr & RNG_SR_DRDY, 10000); - if (retval) + sr, 10000); + if (retval) { + log_err("%s: Timeout RNG no data", __func__); return retval; + }
- if (sr & (RNG_SR_SEIS | RNG_SR_SECS)) { - /* As per SoC TRM */ - clrbits_le32(pdata->base + RNG_SR, RNG_SR_SEIS); - for (i = 0; i < 12; i++) - readl(pdata->base + RNG_DR); - if (readl(pdata->base + RNG_SR) & RNG_SR_SEIS) { - log_err("RNG Noise"); - return -EIO; + if (sr != RNG_SR_DRDY) { + if (sr & RNG_SR_SEIS) { + retval = stm32_rng_conceal_seed_error(pdata); + tries++; + if (retval || tries > RNG_NB_RECOVER_TRIES) { + log_err("%s: Couldn't recover from seed error", __func__); + return -ENOTRECOVERABLE; + } + + /* Start again */ + continue; + } + + if (sr & RNG_SR_CEIS) { + log_info("RNG clock too slow"); + writel_relaxed(0, pdata->base + RNG_SR); } - /* start again */ - continue; }
/* * Once the DRDY bit is set, the RNG_DR register can - * be read four consecutive times. + * be read up to four consecutive times. */ - count = 4; - while (len && count) { - reg = readl(pdata->base + RNG_DR); - memcpy(data, ®, min(len, sizeof(u32))); - increment = min(len, sizeof(u32)); - data += increment; - len -= increment; - count--; + reg = readl(pdata->base + RNG_DR); + /* Late seed error case: DR being 0 is an error status */ + if (!reg) { + retval = stm32_rng_conceal_seed_error(pdata); + tries++; + + if (retval || tries > RNG_NB_RECOVER_TRIES) { + log_err("%s: Couldn't recover from seed error", __func__); + return -ENOTRECOVERABLE; + } + + /* Start again */ + continue; } + + increment = min(len, sizeof(u32)); + memcpy(data, ®, increment); + data += increment; + len -= increment; + + tries = 0; }
return 0;

Hi,
On 9/7/23 18:21, Gatien Chevallier wrote:
Seed errors can occur when using the hardware RNG. Implement the sequences to handle them. This avoids irrecoverable RNG state.
Try to conceal seed errors when possible. If, despite the error concealing tries, a seed error is still present, then return an error.
A clock error does not compromise the hardware block and data can still be read from RNG_DR. Just warn that the RNG clock is too slow and clear RNG_SR.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com
drivers/rng/stm32_rng.c | 163 ++++++++++++++++++++++++++++++++++------ 1 file changed, 140 insertions(+), 23 deletions(-)
Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com
Thanks Patrick

STM32 RNG configuration should best fit the requirements of the platform. Therefore, put a platform-specific RNG configuration field in the platform data. Default RNG configuration for STM32MP13 is the NIST certified configuration [1].
While there, fix and the RNG init sequence to support all RNG versions.
[1] https://csrc.nist.gov/projects/cryptographic-module-validation-program/entro...
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com --- drivers/rng/stm32_rng.c | 54 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-)
diff --git a/drivers/rng/stm32_rng.c b/drivers/rng/stm32_rng.c index b1a790b217..c397b4d95c 100644 --- a/drivers/rng/stm32_rng.c +++ b/drivers/rng/stm32_rng.c @@ -21,8 +21,15 @@ #define RNG_CR 0x00 #define RNG_CR_RNGEN BIT(2) #define RNG_CR_CED BIT(5) +#define RNG_CR_CONFIG1 GENMASK(11, 8) +#define RNG_CR_NISTC BIT(12) +#define RNG_CR_CONFIG2 GENMASK(15, 13) #define RNG_CR_CLKDIV_SHIFT 16 +#define RNG_CR_CLKDIV GENMASK(19, 16) +#define RNG_CR_CONFIG3 GENMASK(25, 20) #define RNG_CR_CONDRST BIT(30) +#define RNG_CR_ENTROPY_SRC_MASK (RNG_CR_CONFIG1 | RNG_CR_NISTC | RNG_CR_CONFIG2 | RNG_CR_CONFIG3) +#define RNG_CR_CONFIG_MASK (RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED | RNG_CR_CLKDIV)
#define RNG_SR 0x04 #define RNG_SR_SEIS BIT(6) @@ -32,17 +39,28 @@
#define RNG_DR 0x08
+#define RNG_NSCR 0x0C +#define RNG_NSCR_MASK GENMASK(17, 0) + +#define RNG_HTCR 0x10 + #define RNG_NB_RECOVER_TRIES 3
/* * struct stm32_rng_data - RNG compat data * * @max_clock_rate: Max RNG clock frequency, in Hertz + * @cr: Entropy source configuration + * @nscr: Noice sources control configuration + * @htcr: Health tests configuration * @has_cond_reset: True if conditionnal reset is supported * */ struct stm32_rng_data { uint max_clock_rate; + u32 cr; + u32 nscr; + u32 htcr; bool has_cond_reset; };
@@ -244,28 +262,48 @@ static int stm32_rng_init(struct stm32_rng_plat *pdata)
cr = readl(pdata->base + RNG_CR);
- if (pdata->data->has_cond_reset) { + /* + * Keep default RNG configuration if none was specified, that is when conf.cr is set to 0. + */ + if (pdata->data->has_cond_reset && pdata->data->cr) { uint clock_div = stm32_rng_clock_freq_restrain(pdata);
- cr |= RNG_CR_CONDRST | (clock_div << RNG_CR_CLKDIV_SHIFT); + cr &= ~RNG_CR_CONFIG_MASK; + cr |= RNG_CR_CONDRST | (pdata->data->cr & RNG_CR_ENTROPY_SRC_MASK) | + (clock_div << RNG_CR_CLKDIV_SHIFT); if (pdata->ced) cr &= ~RNG_CR_CED; else cr |= RNG_CR_CED; writel(cr, pdata->base + RNG_CR); + + /* Health tests and noise control registers */ + writel_relaxed(pdata->data->htcr, pdata->base + RNG_HTCR); + writel_relaxed(pdata->data->nscr & RNG_NSCR_MASK, pdata->base + RNG_NSCR); + cr &= ~RNG_CR_CONDRST; cr |= RNG_CR_RNGEN; writel(cr, pdata->base + RNG_CR); err = readl_poll_timeout(pdata->base + RNG_CR, cr, (!(cr & RNG_CR_CONDRST)), 10000); - if (err) + if (err) { + log_err("%s: Timeout!", __func__); return err; + } } else { + if (pdata->data->has_cond_reset) + cr |= RNG_CR_CONDRST; + if (pdata->ced) cr &= ~RNG_CR_CED; else cr |= RNG_CR_CED;
+ writel(cr, pdata->base + RNG_CR); + + if (pdata->data->has_cond_reset) + cr &= ~RNG_CR_CONDRST; + cr |= RNG_CR_RNGEN;
writel(cr, pdata->base + RNG_CR); @@ -276,6 +314,9 @@ static int stm32_rng_init(struct stm32_rng_plat *pdata)
err = readl_poll_timeout(pdata->base + RNG_SR, sr, sr & RNG_SR_DRDY, 10000); + if (err) + log_err("%s: Timeout!", __func__); + return err; }
@@ -335,11 +376,18 @@ static const struct dm_rng_ops stm32_rng_ops = { static const struct stm32_rng_data stm32mp13_rng_data = { .has_cond_reset = true, .max_clock_rate = 48000000, + .htcr = 0x969D, + .nscr = 0x2B5BB, + .cr = 0xF00D00, };
static const struct stm32_rng_data stm32_rng_data = { .has_cond_reset = false, .max_clock_rate = 3000000, + /* Not supported */ + .htcr = 0, + .nscr = 0, + .cr = 0, };
static const struct udevice_id stm32_rng_match[] = {

Hi,
On 9/7/23 18:21, Gatien Chevallier wrote:
STM32 RNG configuration should best fit the requirements of the platform. Therefore, put a platform-specific RNG configuration field in the platform data. Default RNG configuration for STM32MP13 is the NIST certified configuration [1].
While there, fix and the RNG init sequence to support all RNG versions.
[1] https://csrc.nist.gov/projects/cryptographic-module-validation-program/entro...
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com
drivers/rng/stm32_rng.c | 54 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-)
Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com
Thanks Patrick

Add RNG node for STM32MP13x platforms.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com --- arch/arm/dts/stm32mp131.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm/dts/stm32mp131.dtsi b/arch/arm/dts/stm32mp131.dtsi index d23bbc3639..bd7285053d 100644 --- a/arch/arm/dts/stm32mp131.dtsi +++ b/arch/arm/dts/stm32mp131.dtsi @@ -1208,6 +1208,14 @@ }; };
+ rng: rng@54004000 { + compatible = "st,stm32mp13-rng"; + reg = <0x54004000 0x400>; + clocks = <&rcc RNG1_K>; + resets = <&rcc RNG1_R>; + status = "disabled"; + }; + mdma: dma-controller@58000000 { compatible = "st,stm32h7-mdma"; reg = <0x58000000 0x1000>;

Hi,
On 9/7/23 18:22, Gatien Chevallier wrote:
Add RNG node for STM32MP13x platforms.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com
arch/arm/dts/stm32mp131.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm/dts/stm32mp131.dtsi b/arch/arm/dts/stm32mp131.dtsi index d23bbc3639..bd7285053d 100644 --- a/arch/arm/dts/stm32mp131.dtsi +++ b/arch/arm/dts/stm32mp131.dtsi @@ -1208,6 +1208,14 @@ }; };
rng: rng@54004000 {
compatible = "st,stm32mp13-rng";
reg = <0x54004000 0x400>;
clocks = <&rcc RNG1_K>;
resets = <&rcc RNG1_R>;
status = "disabled";
};
- mdma: dma-controller@58000000 { compatible = "st,stm32h7-mdma"; reg = <0x58000000 0x1000>;
Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com
Thanks Patrick

On 9/7/23 18:21, Gatien Chevallier wrote:
Rename the RNG driver as it is usable by other STM32 platforms than the STM32MP1x ones. Rename CONFIG_RNG_STM32MP1 to CONFIG_RNG_STM32
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com
LGTM
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de

Hi,
On Thu, Sep 07, 2023 at 06:21:54PM +0200, Gatien Chevallier wrote:
diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig -%<- -config RNG_STM32MP1
- bool "Enable random number generator for STM32MP1"
+config RNG_STM32
- bool "Enable random number generator for STM32" depends on ARCH_STM32MP
Shouldn't the "depends on" be updated as well? ("depends on ARCH_STM32 || ARCH_STM32MP", like in STM32_RESET.)
All the best

On 9/11/23 10:27, Grzegorz Szymaszek wrote:
Hi,
On Thu, Sep 07, 2023 at 06:21:54PM +0200, Gatien Chevallier wrote:
diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig -%<- -config RNG_STM32MP1
- bool "Enable random number generator for STM32MP1"
+config RNG_STM32
- bool "Enable random number generator for STM32" depends on ARCH_STM32MP
Shouldn't the "depends on" be updated as well? ("depends on ARCH_STM32 || ARCH_STM32MP", like in STM32_RESET.)
Hi Grzegorz,
I agree, this could be used for MCUs so I'll add ARCH_STM32.
Heinrich, Patrick, can I keep your tag while adding this?
Best regards, Gatien
All the best

On Mon, Sep 11, 2023 at 10:27:38AM +0200, Grzegorz Szymaszek wrote:
[...] Shouldn't the "depends on" be updated as well? ("depends on ARCH_STM32 || ARCH_STM32MP", like in STM32_RESET.)
Forgot to add:
Reviewed-by: Grzegorz Szymaszek gszymaszek@short.pl

Hi,
On 9/7/23 18:21, Gatien Chevallier wrote:
Rename the RNG driver as it is usable by other STM32 platforms than the STM32MP1x ones. Rename CONFIG_RNG_STM32MP1 to CONFIG_RNG_STM32
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com
MAINTAINERS | 2 +- configs/stm32mp15_basic_defconfig | 2 +- configs/stm32mp15_defconfig | 2 +- configs/stm32mp15_trusted_defconfig | 2 +- drivers/rng/Kconfig | 6 +++--- drivers/rng/Makefile | 2 +- drivers/rng/{stm32mp1_rng.c => stm32_rng.c} | 0 7 files changed, 8 insertions(+), 8 deletions(-) rename drivers/rng/{stm32mp1_rng.c => stm32_rng.c} (100%)
Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com
Thanks Patrick
participants (5)
-
Gatien CHEVALLIER
-
Gatien Chevallier
-
Grzegorz Szymaszek
-
Heinrich Schuchardt
-
Patrick DELAUNAY