[PATCH v2 0/7] rng: stm32: support STM32MP13x platforms

This is the cover letter for patchset [1]. First, do not restrain the STM32 RNG driver to the MPU series.
The STM32MP13x platforms have a RNG hardware block that supports customization, a conditional reset sequences that allows to recover from certain situations and a configuration locking mechanism.
This series adds support for the mentionned features. Note that the hardware RNG can and should be managed in the secure world for this platform, hence the rng not being default enabled on the STM32MP135F-DK board.
[1] http://patchwork.ozlabs.org/project/uboot/list/?series=372119&state=*
Changes in V2: - Added this cover letter - Added ARCH_STM32 as a dependency for RNG_STM32 - Added review tags
Gatien Chevallier (7): rng: stm32: rename STM32 RNG driver configs: default activate CONFIG_RNG_STM32 for STM32MP13x platforms rng: stm32: Implement configurable RNG clock error detection rng: stm32: add RNG clock frequency restraint rng: stm32: add error concealment sequence rng: stm32: Implement custom RNG configuration support ARM: dts: stm32: add RNG node for STM32MP13x platforms
MAINTAINERS | 2 +- arch/arm/dts/stm32mp131.dtsi | 8 + configs/stm32mp13_defconfig | 1 + configs/stm32mp15_basic_defconfig | 2 +- configs/stm32mp15_defconfig | 2 +- configs/stm32mp15_trusted_defconfig | 2 +- drivers/rng/Kconfig | 8 +- drivers/rng/Makefile | 2 +- drivers/rng/stm32_rng.c | 408 ++++++++++++++++++++++++++++ drivers/rng/stm32mp1_rng.c | 198 -------------- 10 files changed, 426 insertions(+), 207 deletions(-) create mode 100644 drivers/rng/stm32_rng.c delete mode 100644 drivers/rng/stm32mp1_rng.c

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 Reviewed-by: Grzegorz Szymaszek gszymaszek@short.pl ---
Changes in V2: - Added ARCH_STM32 in the "depends on" section of the RNG_STM32 configuration field. - Added Grzegorz's tag and discarded Patrick's and Heinrich's as there's a modification
MAINTAINERS | 2 +- configs/stm32mp15_basic_defconfig | 2 +- configs/stm32mp15_defconfig | 2 +- configs/stm32mp15_trusted_defconfig | 2 +- drivers/rng/Kconfig | 8 ++++---- drivers/rng/Makefile | 2 +- drivers/rng/{stm32mp1_rng.c => stm32_rng.c} | 0 7 files changed, 9 insertions(+), 9 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..24666bff98 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" - depends on ARCH_STM32MP +config RNG_STM32 + bool "Enable random number generator for STM32" + depends on ARCH_STM32 || 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

Hi,
On 9/11/23 17:37, 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 Reviewed-by: Grzegorz Szymaszek gszymaszek@short.pl
Changes in V2:
- Added ARCH_STM32 in the "depends on" section of the RNG_STM32 configuration field.
- Added Grzegorz's tag and discarded Patrick's and Heinrich's as there's a modification
MAINTAINERS | 2 +- configs/stm32mp15_basic_defconfig | 2 +- configs/stm32mp15_defconfig | 2 +- configs/stm32mp15_trusted_defconfig | 2 +- drivers/rng/Kconfig | 8 ++++---- drivers/rng/Makefile | 2 +- drivers/rng/{stm32mp1_rng.c => stm32_rng.c} | 0 7 files changed, 9 insertions(+), 9 deletions(-) rename drivers/rng/{stm32mp1_rng.c => stm32_rng.c} (100%)
Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com
Thanks Patrick

Default embed this configuration. If OP-TEE PTA RNG is exposed, it means that the RNG is managed by the secure world. Therefore, the RNG node should be disabled in the device tree as an access would be denied by the hardware firewall.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com --- Changes in V2: - Added Patrick's tag
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

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 Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com --- Changes in V2: - Added Patrick's tag
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; }

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 Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com --- Changes in V2: - Added Patrick's tag
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[] = {

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 Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com --- Changes in V2: - Added Patrick's tag
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;

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 Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com --- Changes in V2: - Added Patrick's tag
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[] = {

Add RNG node for STM32MP13x platforms.
Signed-off-by: Gatien Chevallier gatien.chevallier@foss.st.com Reviewed-by: Patrick Delaunay patrick.delaunay@foss.st.com --- Changes in V2: - Added Patrick's tag
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>;
participants (2)
-
Gatien Chevallier
-
Patrick DELAUNAY