1f3c22059SEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause 2f3c22059SEtienne Carriere /* 3ea8ba295SGatien Chevallier * Copyright (c) 2018-2023, STMicroelectronics 4f3c22059SEtienne Carriere */ 5f3c22059SEtienne Carriere 6f3c22059SEtienne Carriere #include <assert.h> 7d7a1a7d2SEtienne Carriere #include <drivers/clk.h> 8d7a1a7d2SEtienne Carriere #include <drivers/clk_dt.h> 9ea8ba295SGatien Chevallier #include <drivers/rstctrl.h> 10f3c22059SEtienne Carriere #include <io.h> 11*5959d83fSGatien Chevallier #include <kernel/boot.h> 12f3c22059SEtienne Carriere #include <kernel/delay.h> 13a2fc83d1SJerome Forissier #include <kernel/dt.h> 14ea8ba295SGatien Chevallier #include <kernel/dt_driver.h> 15f3c22059SEtienne Carriere #include <kernel/panic.h> 1629893549SGatien Chevallier #include <kernel/pm.h> 1765b5ada4SMarouene Boubakri #include <kernel/thread.h> 18a2fc83d1SJerome Forissier #include <libfdt.h> 19f3c22059SEtienne Carriere #include <mm/core_memprot.h> 20097f329aSEtienne Carriere #include <rng_support.h> 21f3c22059SEtienne Carriere #include <stdbool.h> 22f3c22059SEtienne Carriere #include <stm32_util.h> 23f3c22059SEtienne Carriere #include <string.h> 24cd451498SEtienne Carriere #include <tee/tee_cryp_utl.h> 25*5959d83fSGatien Chevallier #include <util.h> 26f3c22059SEtienne Carriere 270817aa6fSGatien Chevallier #define RNG_CR U(0x00) 280817aa6fSGatien Chevallier #define RNG_SR U(0x04) 290817aa6fSGatien Chevallier #define RNG_DR U(0x08) 30*5959d83fSGatien Chevallier #define RNG_NSCR U(0x0C) 31*5959d83fSGatien Chevallier #define RNG_HTCR U(0x10) 32f3c22059SEtienne Carriere 33f3c22059SEtienne Carriere #define RNG_CR_RNGEN BIT(2) 34f3c22059SEtienne Carriere #define RNG_CR_IE BIT(3) 35f3c22059SEtienne Carriere #define RNG_CR_CED BIT(5) 36*5959d83fSGatien Chevallier #define RNG_CR_CONFIG1 GENMASK_32(11, 8) 37*5959d83fSGatien Chevallier #define RNG_CR_NISTC BIT(12) 38*5959d83fSGatien Chevallier #define RNG_CR_POWER_OPTIM BIT(13) 39*5959d83fSGatien Chevallier #define RNG_CR_CONFIG2 GENMASK_32(15, 13) 40091ef005SGatien Chevallier #define RNG_CR_CLKDIV GENMASK_32(19, 16) 41091ef005SGatien Chevallier #define RNG_CR_CLKDIV_SHIFT U(16) 42*5959d83fSGatien Chevallier #define RNG_CR_CONFIG3 GENMASK_32(25, 20) 43091ef005SGatien Chevallier #define RNG_CR_CONDRST BIT(30) 44*5959d83fSGatien Chevallier #define RNG_CR_ENTROPY_SRC_MASK (RNG_CR_CONFIG1 | RNG_CR_NISTC | \ 45*5959d83fSGatien Chevallier RNG_CR_CONFIG2 | RNG_CR_CONFIG3) 46f3c22059SEtienne Carriere 47f3c22059SEtienne Carriere #define RNG_SR_DRDY BIT(0) 48f3c22059SEtienne Carriere #define RNG_SR_CECS BIT(1) 49f3c22059SEtienne Carriere #define RNG_SR_SECS BIT(2) 50f3c22059SEtienne Carriere #define RNG_SR_CEIS BIT(5) 51f3c22059SEtienne Carriere #define RNG_SR_SEIS BIT(6) 52f3c22059SEtienne Carriere 53*5959d83fSGatien Chevallier #define RNG_NSCR_MASK GENMASK_32(17, 0) 54*5959d83fSGatien Chevallier 550817aa6fSGatien Chevallier #if TRACE_LEVEL > TRACE_DEBUG 560817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US U(100000) 570817aa6fSGatien Chevallier #else 580817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US U(10000) 590817aa6fSGatien Chevallier #endif 60ea8ba295SGatien Chevallier #define RNG_RESET_TIMEOUT_US U(1000) 61f3c22059SEtienne Carriere 620817aa6fSGatien Chevallier #define RNG_FIFO_BYTE_DEPTH U(16) 630817aa6fSGatien Chevallier 64*5959d83fSGatien Chevallier #define RNG_CONFIG_MASK (RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED | \ 65*5959d83fSGatien Chevallier RNG_CR_CLKDIV) 66091ef005SGatien Chevallier 67091ef005SGatien Chevallier #define RNG_MAX_NOISE_CLK_FREQ U(3000000) 68091ef005SGatien Chevallier 69091ef005SGatien Chevallier struct stm32_rng_driver_data { 7045da6509SGatien Chevallier unsigned long nb_clock; 71*5959d83fSGatien Chevallier uint32_t cr; 72*5959d83fSGatien Chevallier uint32_t nscr; 73*5959d83fSGatien Chevallier uint32_t htcr; 74*5959d83fSGatien Chevallier bool has_power_optim; 75091ef005SGatien Chevallier bool has_cond_reset; 76091ef005SGatien Chevallier }; 77091ef005SGatien Chevallier 78f3c22059SEtienne Carriere struct stm32_rng_instance { 79f3c22059SEtienne Carriere struct io_pa_va base; 80d7a1a7d2SEtienne Carriere struct clk *clock; 8145da6509SGatien Chevallier struct clk *bus_clock; 82ea8ba295SGatien Chevallier struct rstctrl *rstctrl; 83091ef005SGatien Chevallier const struct stm32_rng_driver_data *ddata; 84f3c22059SEtienne Carriere unsigned int lock; 85*5959d83fSGatien Chevallier uint64_t error_to_ref; 86*5959d83fSGatien Chevallier uint32_t pm_cr; 87*5959d83fSGatien Chevallier uint32_t pm_health; 88*5959d83fSGatien Chevallier uint32_t pm_noise_ctrl; 89*5959d83fSGatien Chevallier uint32_t health_test_conf; 90*5959d83fSGatien Chevallier uint32_t noise_ctrl_conf; 91*5959d83fSGatien Chevallier uint32_t rng_config; 92d8682c4cSEtienne Carriere bool release_post_boot; 933c752300SGatien Chevallier bool clock_error; 94091ef005SGatien Chevallier bool error_conceal; 95f3c22059SEtienne Carriere }; 96f3c22059SEtienne Carriere 97ea8ba295SGatien Chevallier /* Expect at most a single RNG instance */ 98f3c22059SEtienne Carriere static struct stm32_rng_instance *stm32_rng; 99f3c22059SEtienne Carriere 100f63f11bdSGatien Chevallier static vaddr_t get_base(void) 101f63f11bdSGatien Chevallier { 102f63f11bdSGatien Chevallier assert(stm32_rng); 103f63f11bdSGatien Chevallier 104f63f11bdSGatien Chevallier return io_pa_or_va(&stm32_rng->base, 1); 105f63f11bdSGatien Chevallier } 106f63f11bdSGatien Chevallier 107f3c22059SEtienne Carriere /* 108091ef005SGatien Chevallier * Extracts from the STM32 RNG specification when RNG supports CONDRST. 109f3c22059SEtienne Carriere * 110f3c22059SEtienne Carriere * When a noise source (or seed) error occurs, the RNG stops generating 111f3c22059SEtienne Carriere * random numbers and sets to “1” both SEIS and SECS bits to indicate 112f3c22059SEtienne Carriere * that a seed error occurred. (...) 113091ef005SGatien Chevallier * 114091ef005SGatien Chevallier * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield 115091ef005SGatien Chevallier * description for details). This step is needed only if SECS is set. 116091ef005SGatien Chevallier * Indeed, when SEIS is set and SECS is cleared it means RNG performed 117091ef005SGatien Chevallier * the reset automatically (auto-reset). 118091ef005SGatien Chevallier * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST 119091ef005SGatien Chevallier * to be cleared in the RNG_CR register, then confirm that SEIS is 120091ef005SGatien Chevallier * cleared in the RNG_SR register. Otherwise just clear SEIS bit in 121091ef005SGatien Chevallier * the RNG_SR register. 122091ef005SGatien Chevallier * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be 123091ef005SGatien Chevallier * cleared by RNG. The random number generation is now back to normal. 124091ef005SGatien Chevallier */ 125091ef005SGatien Chevallier static void conceal_seed_error_cond_reset(void) 126091ef005SGatien Chevallier { 127091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 128091ef005SGatien Chevallier vaddr_t rng_base = get_base(); 129f3c22059SEtienne Carriere 130091ef005SGatien Chevallier if (!dev->error_conceal) { 131091ef005SGatien Chevallier uint32_t sr = io_read32(rng_base + RNG_SR); 132091ef005SGatien Chevallier 133091ef005SGatien Chevallier if (sr & RNG_SR_SECS) { 134091ef005SGatien Chevallier /* Conceal by resetting the subsystem (step 1.) */ 135091ef005SGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 136091ef005SGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 137091ef005SGatien Chevallier 138091ef005SGatien Chevallier /* Arm timeout for error_conceal sequence */ 139091ef005SGatien Chevallier dev->error_to_ref = 140091ef005SGatien Chevallier timeout_init_us(RNG_READY_TIMEOUT_US); 141091ef005SGatien Chevallier dev->error_conceal = true; 142091ef005SGatien Chevallier } else { 143091ef005SGatien Chevallier /* RNG auto-reset (step 2.) */ 144091ef005SGatien Chevallier io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS); 145091ef005SGatien Chevallier } 146091ef005SGatien Chevallier } else { 147091ef005SGatien Chevallier /* Measure time before possible reschedule */ 148091ef005SGatien Chevallier bool timed_out = timeout_elapsed(dev->error_to_ref); 149091ef005SGatien Chevallier 150091ef005SGatien Chevallier /* Wait CONDRST is cleared (step 2.) */ 151091ef005SGatien Chevallier if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) { 152091ef005SGatien Chevallier if (timed_out) 153091ef005SGatien Chevallier panic(); 154091ef005SGatien Chevallier 155091ef005SGatien Chevallier /* Wait subsystem reset cycle completes */ 156091ef005SGatien Chevallier return; 157091ef005SGatien Chevallier } 158091ef005SGatien Chevallier 159091ef005SGatien Chevallier /* Check SEIS is cleared (step 2.) */ 160091ef005SGatien Chevallier if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 161091ef005SGatien Chevallier panic(); 162091ef005SGatien Chevallier 163091ef005SGatien Chevallier /* Wait SECS is cleared (step 3.) */ 164091ef005SGatien Chevallier if (io_read32(rng_base + RNG_SR) & RNG_SR_SECS) { 165091ef005SGatien Chevallier if (timed_out) 166091ef005SGatien Chevallier panic(); 167091ef005SGatien Chevallier 168091ef005SGatien Chevallier /* Wait subsystem reset cycle completes */ 169091ef005SGatien Chevallier return; 170091ef005SGatien Chevallier } 171091ef005SGatien Chevallier 172091ef005SGatien Chevallier dev->error_conceal = false; 173091ef005SGatien Chevallier } 174091ef005SGatien Chevallier } 175091ef005SGatien Chevallier 176091ef005SGatien Chevallier /* 177091ef005SGatien Chevallier * Extracts from the STM32 RNG specification, when CONDRST is not supported 178091ef005SGatien Chevallier * 179091ef005SGatien Chevallier * When a noise source (or seed) error occurs, the RNG stops generating 180091ef005SGatien Chevallier * random numbers and sets to “1” both SEIS and SECS bits to indicate 181091ef005SGatien Chevallier * that a seed error occurred. (...) 182091ef005SGatien Chevallier * 183f3c22059SEtienne Carriere * The following sequence shall be used to fully recover from a seed 184f3c22059SEtienne Carriere * error after the RNG initialization: 185f3c22059SEtienne Carriere * 1. Clear the SEIS bit by writing it to “0”. 186f3c22059SEtienne Carriere * 2. Read out 12 words from the RNG_DR register, and discard each of 187f3c22059SEtienne Carriere * them in order to clean the pipeline. 188f3c22059SEtienne Carriere * 3. Confirm that SEIS is still cleared. Random number generation is 189f3c22059SEtienne Carriere * back to normal. 190f3c22059SEtienne Carriere */ 191091ef005SGatien Chevallier static void conceal_seed_error_sw_reset(void) 192f3c22059SEtienne Carriere { 1936a6b6168SGatien Chevallier vaddr_t rng_base = get_base(); 194f3c22059SEtienne Carriere size_t i = 0; 195f3c22059SEtienne Carriere 1966a6b6168SGatien Chevallier io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS); 197f3c22059SEtienne Carriere 198f3c22059SEtienne Carriere for (i = 12; i != 0; i--) 199f3c22059SEtienne Carriere (void)io_read32(rng_base + RNG_DR); 200f3c22059SEtienne Carriere 201f3c22059SEtienne Carriere if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 202f3c22059SEtienne Carriere panic("RNG noise"); 203f3c22059SEtienne Carriere } 204f3c22059SEtienne Carriere 205091ef005SGatien Chevallier static void conceal_seed_error(void) 206091ef005SGatien Chevallier { 207091ef005SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) 208091ef005SGatien Chevallier conceal_seed_error_cond_reset(); 209091ef005SGatien Chevallier else 210091ef005SGatien Chevallier conceal_seed_error_sw_reset(); 211091ef005SGatien Chevallier } 212091ef005SGatien Chevallier 213c99311c8SEtienne Carriere static TEE_Result read_available(vaddr_t rng_base, uint8_t *out, size_t *size) 214f3c22059SEtienne Carriere { 215091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 216c99311c8SEtienne Carriere uint8_t *buf = NULL; 217c99311c8SEtienne Carriere size_t req_size = 0; 218c99311c8SEtienne Carriere size_t len = 0; 219f3c22059SEtienne Carriere 220091ef005SGatien Chevallier if (dev->error_conceal || io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 2216a6b6168SGatien Chevallier conceal_seed_error(); 222f3c22059SEtienne Carriere 22323123473SEtienne Carriere if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) { 22423123473SEtienne Carriere FMSG("RNG not ready"); 225c99311c8SEtienne Carriere return TEE_ERROR_NO_DATA; 22623123473SEtienne Carriere } 227f3c22059SEtienne Carriere 22823123473SEtienne Carriere if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) { 22923123473SEtienne Carriere FMSG("RNG noise error"); 230c99311c8SEtienne Carriere return TEE_ERROR_NO_DATA; 23123123473SEtienne Carriere } 232c99311c8SEtienne Carriere 233c99311c8SEtienne Carriere buf = out; 234c99311c8SEtienne Carriere req_size = MIN(RNG_FIFO_BYTE_DEPTH, *size); 235c99311c8SEtienne Carriere len = req_size; 236f3c22059SEtienne Carriere 237f3c22059SEtienne Carriere /* RNG is ready: read up to 4 32bit words */ 238f3c22059SEtienne Carriere while (len) { 23923bdf063SEtienne Carriere uint32_t data32 = 0; 240f3c22059SEtienne Carriere size_t sz = MIN(len, sizeof(uint32_t)); 241f3c22059SEtienne Carriere 24223bdf063SEtienne Carriere if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) 24323bdf063SEtienne Carriere break; 24423bdf063SEtienne Carriere data32 = io_read32(rng_base + RNG_DR); 24523bdf063SEtienne Carriere 2463e64c635SGatien Chevallier /* Late seed error case: DR being 0 is an error status */ 2473e64c635SGatien Chevallier if (!data32) { 2483e64c635SGatien Chevallier conceal_seed_error(); 2493e64c635SGatien Chevallier return TEE_ERROR_NO_DATA; 2503e64c635SGatien Chevallier } 2513e64c635SGatien Chevallier 252f3c22059SEtienne Carriere memcpy(buf, &data32, sz); 253f3c22059SEtienne Carriere buf += sz; 254f3c22059SEtienne Carriere len -= sz; 255f3c22059SEtienne Carriere } 256c99311c8SEtienne Carriere 25723bdf063SEtienne Carriere *size = req_size - len; 258f3c22059SEtienne Carriere 259c99311c8SEtienne Carriere return TEE_SUCCESS; 260f3c22059SEtienne Carriere } 261f3c22059SEtienne Carriere 262091ef005SGatien Chevallier static uint32_t stm32_rng_clock_freq_restrain(void) 263091ef005SGatien Chevallier { 264091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 265091ef005SGatien Chevallier unsigned long clock_rate = 0; 266091ef005SGatien Chevallier uint32_t clock_div = 0; 267091ef005SGatien Chevallier 268091ef005SGatien Chevallier clock_rate = clk_get_rate(dev->clock); 269091ef005SGatien Chevallier 270091ef005SGatien Chevallier /* 271091ef005SGatien Chevallier * Get the exponent to apply on the CLKDIV field in RNG_CR register 272091ef005SGatien Chevallier * No need to handle the case when clock-div > 0xF as it is physically 273091ef005SGatien Chevallier * impossible 274091ef005SGatien Chevallier */ 275091ef005SGatien Chevallier while ((clock_rate >> clock_div) > RNG_MAX_NOISE_CLK_FREQ) 276091ef005SGatien Chevallier clock_div++; 277091ef005SGatien Chevallier 278091ef005SGatien Chevallier DMSG("RNG clk rate : %lu", clk_get_rate(dev->clock) >> clock_div); 279091ef005SGatien Chevallier 280091ef005SGatien Chevallier return clock_div; 281091ef005SGatien Chevallier } 282091ef005SGatien Chevallier 283f63f11bdSGatien Chevallier static TEE_Result init_rng(void) 284f3c22059SEtienne Carriere { 285f63f11bdSGatien Chevallier vaddr_t rng_base = get_base(); 2863c752300SGatien Chevallier uint32_t cr_ced_mask = 0; 287*5959d83fSGatien Chevallier uint32_t value = 0; 2883c752300SGatien Chevallier 2893c752300SGatien Chevallier if (!stm32_rng->clock_error) 2903c752300SGatien Chevallier cr_ced_mask = RNG_CR_CED; 291f3c22059SEtienne Carriere 292f63f11bdSGatien Chevallier /* Clean error indications */ 293f63f11bdSGatien Chevallier io_write32(rng_base + RNG_SR, 0); 294f3c22059SEtienne Carriere 295091ef005SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 296091ef005SGatien Chevallier uint32_t clock_div = stm32_rng_clock_freq_restrain(); 297091ef005SGatien Chevallier 298*5959d83fSGatien Chevallier /* 299*5959d83fSGatien Chevallier * Keep default RNG configuration if none was specified. 300*5959d83fSGatien Chevallier * 0 is an invalid value as it disables all entropy sources. 301*5959d83fSGatien Chevallier */ 302*5959d83fSGatien Chevallier if (!stm32_rng->rng_config) 303*5959d83fSGatien Chevallier stm32_rng->rng_config = io_read32(rng_base + RNG_CR) & 304*5959d83fSGatien Chevallier RNG_CR_ENTROPY_SRC_MASK; 305*5959d83fSGatien Chevallier 306*5959d83fSGatien Chevallier /* 307*5959d83fSGatien Chevallier * Configuration must be set in the same access that sets 308*5959d83fSGatien Chevallier * RNG_CR_CONDRST bit. Otherwise, the configuration setting is 309*5959d83fSGatien Chevallier * not taken into account. CONFIGLOCK bit is always cleared at 310*5959d83fSGatien Chevallier * this stage. 311*5959d83fSGatien Chevallier */ 312*5959d83fSGatien Chevallier io_clrsetbits32(rng_base + RNG_CR, RNG_CONFIG_MASK, 313*5959d83fSGatien Chevallier stm32_rng->rng_config | RNG_CR_CONDRST | 314*5959d83fSGatien Chevallier cr_ced_mask | 315*5959d83fSGatien Chevallier SHIFT_U32(clock_div, RNG_CR_CLKDIV_SHIFT)); 316*5959d83fSGatien Chevallier 317*5959d83fSGatien Chevallier /* 318*5959d83fSGatien Chevallier * Write health test and noise source control configuration 319*5959d83fSGatien Chevallier * according to current RNG entropy source configuration 320*5959d83fSGatien Chevallier */ 321*5959d83fSGatien Chevallier if (stm32_rng->noise_ctrl_conf) 322*5959d83fSGatien Chevallier io_write32(rng_base + RNG_NSCR, 323*5959d83fSGatien Chevallier stm32_rng->noise_ctrl_conf); 324*5959d83fSGatien Chevallier 325*5959d83fSGatien Chevallier if (stm32_rng->health_test_conf) 326*5959d83fSGatien Chevallier io_write32(rng_base + RNG_HTCR, 327*5959d83fSGatien Chevallier stm32_rng->health_test_conf); 328091ef005SGatien Chevallier 329091ef005SGatien Chevallier io_clrsetbits32(rng_base + RNG_CR, RNG_CR_CONDRST, 330091ef005SGatien Chevallier RNG_CR_RNGEN); 331eb5cf770SGatien Chevallier 332*5959d83fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_CR, value, 333*5959d83fSGatien Chevallier !(value & RNG_CR_CONDRST), 0, 334*5959d83fSGatien Chevallier RNG_READY_TIMEOUT_US)) 335eb5cf770SGatien Chevallier panic(); 336*5959d83fSGatien Chevallier 337*5959d83fSGatien Chevallier DMSG("RNG control register %#"PRIx32, 338*5959d83fSGatien Chevallier io_read32(rng_base + RNG_CR)); 339*5959d83fSGatien Chevallier DMSG("RNG noise source control register %#"PRIx32, 340*5959d83fSGatien Chevallier io_read32(rng_base + RNG_NSCR)); 341*5959d83fSGatien Chevallier DMSG("RNG health test register %#"PRIx32, 342*5959d83fSGatien Chevallier io_read32(rng_base + RNG_HTCR)); 343091ef005SGatien Chevallier } else { 3443c752300SGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_RNGEN | cr_ced_mask); 345091ef005SGatien Chevallier } 346f63f11bdSGatien Chevallier 347*5959d83fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_SR, value, 348*5959d83fSGatien Chevallier value & RNG_SR_DRDY, 0, 349*5959d83fSGatien Chevallier RNG_READY_TIMEOUT_US)) 350f63f11bdSGatien Chevallier return TEE_ERROR_GENERIC; 351f63f11bdSGatien Chevallier 352f63f11bdSGatien Chevallier return TEE_SUCCESS; 353f3c22059SEtienne Carriere } 354f3c22059SEtienne Carriere 35598c36268SGatien Chevallier static TEE_Result stm32_rng_read(uint8_t *out, size_t size) 356f3c22059SEtienne Carriere { 357c99311c8SEtienne Carriere TEE_Result rc = TEE_ERROR_GENERIC; 358c99311c8SEtienne Carriere bool burst_timeout = false; 359c99311c8SEtienne Carriere uint64_t timeout_ref = 0; 360f3c22059SEtienne Carriere uint32_t exceptions = 0; 361f3c22059SEtienne Carriere uint8_t *out_ptr = out; 362c99311c8SEtienne Carriere vaddr_t rng_base = 0; 363f3c22059SEtienne Carriere size_t out_size = 0; 364f3c22059SEtienne Carriere 365f3c22059SEtienne Carriere if (!stm32_rng) { 366f3c22059SEtienne Carriere DMSG("No RNG"); 367f3c22059SEtienne Carriere return TEE_ERROR_NOT_SUPPORTED; 368f3c22059SEtienne Carriere } 369f3c22059SEtienne Carriere 370fb1681dfSGatien Chevallier rc = clk_enable(stm32_rng->clock); 371fb1681dfSGatien Chevallier if (rc) 372fb1681dfSGatien Chevallier return rc; 373fb1681dfSGatien Chevallier 37445da6509SGatien Chevallier if (stm32_rng->bus_clock) { 37545da6509SGatien Chevallier rc = clk_enable(stm32_rng->bus_clock); 37645da6509SGatien Chevallier if (rc) { 37745da6509SGatien Chevallier clk_disable(stm32_rng->clock); 37845da6509SGatien Chevallier return rc; 37945da6509SGatien Chevallier } 38045da6509SGatien Chevallier } 38145da6509SGatien Chevallier 382f63f11bdSGatien Chevallier rng_base = get_base(); 383c99311c8SEtienne Carriere 384c99311c8SEtienne Carriere /* Arm timeout */ 3850817aa6fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 386c99311c8SEtienne Carriere burst_timeout = false; 387f3c22059SEtienne Carriere 388f3c22059SEtienne Carriere while (out_size < size) { 389f3c22059SEtienne Carriere /* Read by chunks of the size the RNG FIFO depth */ 390f3c22059SEtienne Carriere size_t sz = size - out_size; 391f3c22059SEtienne Carriere 392f3c22059SEtienne Carriere exceptions = may_spin_lock(&stm32_rng->lock); 393f3c22059SEtienne Carriere 394c99311c8SEtienne Carriere rc = read_available(rng_base, out_ptr, &sz); 395c99311c8SEtienne Carriere 396c99311c8SEtienne Carriere /* Raise timeout only if we failed to get some samples */ 397c99311c8SEtienne Carriere assert(!rc || rc == TEE_ERROR_NO_DATA); 398c99311c8SEtienne Carriere if (rc) 399c99311c8SEtienne Carriere burst_timeout = timeout_elapsed(timeout_ref); 400f3c22059SEtienne Carriere 401f3c22059SEtienne Carriere may_spin_unlock(&stm32_rng->lock, exceptions); 402f3c22059SEtienne Carriere 403c99311c8SEtienne Carriere if (burst_timeout) { 404c99311c8SEtienne Carriere rc = TEE_ERROR_GENERIC; 405c99311c8SEtienne Carriere goto out; 406f3c22059SEtienne Carriere } 407f3c22059SEtienne Carriere 408c99311c8SEtienne Carriere if (!rc) { 409c99311c8SEtienne Carriere out_size += sz; 410c99311c8SEtienne Carriere out_ptr += sz; 411c99311c8SEtienne Carriere /* Re-arm timeout */ 4120817aa6fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 413c99311c8SEtienne Carriere burst_timeout = false; 414c99311c8SEtienne Carriere } 415c99311c8SEtienne Carriere } 416c99311c8SEtienne Carriere 417c99311c8SEtienne Carriere out: 418c99311c8SEtienne Carriere assert(!rc || rc == TEE_ERROR_GENERIC); 419f63f11bdSGatien Chevallier clk_disable(stm32_rng->clock); 42045da6509SGatien Chevallier if (stm32_rng->bus_clock) 42145da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 422f3c22059SEtienne Carriere 423f3c22059SEtienne Carriere return rc; 424f3c22059SEtienne Carriere } 425f3c22059SEtienne Carriere 426cd451498SEtienne Carriere #ifdef CFG_WITH_SOFTWARE_PRNG 427cd451498SEtienne Carriere /* Override weak plat_rng_init with platform handler to seed PRNG */ 428cd451498SEtienne Carriere void plat_rng_init(void) 429cd451498SEtienne Carriere { 430cd451498SEtienne Carriere uint8_t seed[RNG_FIFO_BYTE_DEPTH] = { }; 431cd451498SEtienne Carriere 432cd451498SEtienne Carriere if (stm32_rng_read(seed, sizeof(seed))) 433cd451498SEtienne Carriere panic(); 434cd451498SEtienne Carriere 435cd451498SEtienne Carriere if (crypto_rng_init(seed, sizeof(seed))) 436cd451498SEtienne Carriere panic(); 437cd451498SEtienne Carriere 438cd451498SEtienne Carriere DMSG("PRNG seeded with RNG"); 439cd451498SEtienne Carriere } 440cd451498SEtienne Carriere #else 441cb2478efSAndrew Davis TEE_Result hw_get_random_bytes(void *out, size_t size) 442097f329aSEtienne Carriere { 443097f329aSEtienne Carriere return stm32_rng_read(out, size); 444097f329aSEtienne Carriere } 44527f3087bSGatien Chevallier 44627f3087bSGatien Chevallier void plat_rng_init(void) 44727f3087bSGatien Chevallier { 44827f3087bSGatien Chevallier } 449097f329aSEtienne Carriere #endif 450097f329aSEtienne Carriere 451*5959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_resume(void) 45229893549SGatien Chevallier { 45329893549SGatien Chevallier vaddr_t base = get_base(); 45429893549SGatien Chevallier 45529893549SGatien Chevallier /* Clean error indications */ 45629893549SGatien Chevallier io_write32(base + RNG_SR, 0); 45729893549SGatien Chevallier 45829893549SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 459eb5cf770SGatien Chevallier uint64_t timeout_ref = 0; 460eb5cf770SGatien Chevallier 46129893549SGatien Chevallier /* 462c2c5b4beSGatien Chevallier * Configuration must be set in the same access that sets 463c2c5b4beSGatien Chevallier * RNG_CR_CONDRST bit. Otherwise, the configuration setting is 464c2c5b4beSGatien Chevallier * not taken into account. CONFIGLOCK bit is always cleared in 465c2c5b4beSGatien Chevallier * this configuration. 46629893549SGatien Chevallier */ 467*5959d83fSGatien Chevallier io_write32(base + RNG_CR, stm32_rng->pm_cr | RNG_CR_CONDRST); 468*5959d83fSGatien Chevallier 469*5959d83fSGatien Chevallier /* Restore health test and noise control configuration */ 470*5959d83fSGatien Chevallier io_write32(base + RNG_NSCR, stm32_rng->pm_noise_ctrl); 471*5959d83fSGatien Chevallier io_write32(base + RNG_HTCR, stm32_rng->pm_health); 47229893549SGatien Chevallier 47329893549SGatien Chevallier io_clrsetbits32(base + RNG_CR, RNG_CR_CONDRST, RNG_CR_RNGEN); 474eb5cf770SGatien Chevallier 475eb5cf770SGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 476eb5cf770SGatien Chevallier while (io_read32(base + RNG_CR) & RNG_CR_CONDRST) 477eb5cf770SGatien Chevallier if (timeout_elapsed(timeout_ref)) 478eb5cf770SGatien Chevallier break; 479eb5cf770SGatien Chevallier if (io_read32(base + RNG_CR) & RNG_CR_CONDRST) 480eb5cf770SGatien Chevallier panic(); 48129893549SGatien Chevallier } else { 482*5959d83fSGatien Chevallier io_write32(base + RNG_CR, RNG_CR_RNGEN | stm32_rng->pm_cr); 483*5959d83fSGatien Chevallier } 484*5959d83fSGatien Chevallier 485*5959d83fSGatien Chevallier return TEE_SUCCESS; 486*5959d83fSGatien Chevallier } 487*5959d83fSGatien Chevallier 488*5959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_suspend(void) 489*5959d83fSGatien Chevallier { 490*5959d83fSGatien Chevallier vaddr_t rng_base = get_base(); 491*5959d83fSGatien Chevallier 492*5959d83fSGatien Chevallier stm32_rng->pm_cr = io_read32(rng_base + RNG_CR); 493*5959d83fSGatien Chevallier 494*5959d83fSGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 495*5959d83fSGatien Chevallier stm32_rng->pm_health = io_read32(rng_base + RNG_HTCR); 496*5959d83fSGatien Chevallier stm32_rng->pm_noise_ctrl = io_read32(rng_base + RNG_NSCR); 497*5959d83fSGatien Chevallier } 498*5959d83fSGatien Chevallier 499*5959d83fSGatien Chevallier if (stm32_rng->ddata->has_power_optim) { 500*5959d83fSGatien Chevallier uint64_t timeout_ref = 0; 501*5959d83fSGatien Chevallier 502*5959d83fSGatien Chevallier /* 503*5959d83fSGatien Chevallier * As per reference manual, it is recommended to set 504*5959d83fSGatien Chevallier * RNG_CONFIG2[bit0] when RNG power consumption is critical. 505*5959d83fSGatien Chevallier */ 506*5959d83fSGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_POWER_OPTIM | 507*5959d83fSGatien Chevallier RNG_CR_CONDRST); 508*5959d83fSGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 509*5959d83fSGatien Chevallier 510*5959d83fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 511*5959d83fSGatien Chevallier while (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) 512*5959d83fSGatien Chevallier if (timeout_elapsed(timeout_ref)) 513*5959d83fSGatien Chevallier break; 514*5959d83fSGatien Chevallier if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) 515*5959d83fSGatien Chevallier panic(); 516*5959d83fSGatien Chevallier } else { 517*5959d83fSGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_RNGEN); 51829893549SGatien Chevallier } 51929893549SGatien Chevallier 52029893549SGatien Chevallier return TEE_SUCCESS; 52129893549SGatien Chevallier } 52229893549SGatien Chevallier 52329893549SGatien Chevallier static TEE_Result 52429893549SGatien Chevallier stm32_rng_pm(enum pm_op op, unsigned int pm_hint __unused, 52529893549SGatien Chevallier const struct pm_callback_handle *pm_handle __unused) 52629893549SGatien Chevallier { 52729893549SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 52829893549SGatien Chevallier 52929893549SGatien Chevallier assert(stm32_rng && (op == PM_OP_SUSPEND || op == PM_OP_RESUME)); 53029893549SGatien Chevallier 53129893549SGatien Chevallier res = clk_enable(stm32_rng->clock); 53229893549SGatien Chevallier if (res) 53329893549SGatien Chevallier return res; 53429893549SGatien Chevallier 53545da6509SGatien Chevallier if (stm32_rng->bus_clock) { 53645da6509SGatien Chevallier res = clk_enable(stm32_rng->bus_clock); 53745da6509SGatien Chevallier if (res) { 53845da6509SGatien Chevallier clk_disable(stm32_rng->clock); 53945da6509SGatien Chevallier return res; 54045da6509SGatien Chevallier } 54145da6509SGatien Chevallier } 54245da6509SGatien Chevallier 543*5959d83fSGatien Chevallier if (op == PM_OP_RESUME) 544*5959d83fSGatien Chevallier res = stm32_rng_pm_resume(); 54529893549SGatien Chevallier else 546*5959d83fSGatien Chevallier res = stm32_rng_pm_suspend(); 54729893549SGatien Chevallier 54829893549SGatien Chevallier clk_disable(stm32_rng->clock); 54945da6509SGatien Chevallier if (stm32_rng->bus_clock) 55045da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 55129893549SGatien Chevallier 55229893549SGatien Chevallier return res; 55329893549SGatien Chevallier } 55429893549SGatien Chevallier DECLARE_KEEP_PAGER(stm32_rng_pm); 55529893549SGatien Chevallier 556ea8ba295SGatien Chevallier static TEE_Result stm32_rng_parse_fdt(const void *fdt, int node) 557f3c22059SEtienne Carriere { 558d7a1a7d2SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 559ea8ba295SGatien Chevallier struct dt_node_info dt_rng = { }; 560f3c22059SEtienne Carriere 561f354a5d8SGatien Chevallier fdt_fill_device_info(fdt, &dt_rng, node); 562ea8ba295SGatien Chevallier if (dt_rng.reg == DT_INFO_INVALID_REG) 563ea8ba295SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS; 564f3c22059SEtienne Carriere 565ea8ba295SGatien Chevallier stm32_rng->base.pa = dt_rng.reg; 566ea8ba295SGatien Chevallier stm32_rng->base.va = io_pa_or_va_secure(&stm32_rng->base, 567ea8ba295SGatien Chevallier dt_rng.reg_size); 568ea8ba295SGatien Chevallier assert(stm32_rng->base.va); 569f3c22059SEtienne Carriere 570ea8ba295SGatien Chevallier res = rstctrl_dt_get_by_index(fdt, node, 0, &stm32_rng->rstctrl); 571ea8ba295SGatien Chevallier if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND) 572ea8ba295SGatien Chevallier return res; 57368c4a16bSEtienne Carriere 57445da6509SGatien Chevallier if (stm32_rng->ddata->nb_clock > 1) { 57545da6509SGatien Chevallier res = clk_dt_get_by_name(fdt, node, "rng_clk", 57645da6509SGatien Chevallier &stm32_rng->clock); 57745da6509SGatien Chevallier if (res) 57845da6509SGatien Chevallier return res; 57945da6509SGatien Chevallier 58045da6509SGatien Chevallier res = clk_dt_get_by_name(fdt, node, "rng_hclk", 58145da6509SGatien Chevallier &stm32_rng->bus_clock); 58245da6509SGatien Chevallier if (res) 58345da6509SGatien Chevallier return res; 58445da6509SGatien Chevallier } else { 585d7a1a7d2SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &stm32_rng->clock); 586d7a1a7d2SEtienne Carriere if (res) 587d7a1a7d2SEtienne Carriere return res; 58845da6509SGatien Chevallier } 589d7a1a7d2SEtienne Carriere 5903c752300SGatien Chevallier if (fdt_getprop(fdt, node, "clock-error-detect", NULL)) 5913c752300SGatien Chevallier stm32_rng->clock_error = true; 5923c752300SGatien Chevallier 593ea8ba295SGatien Chevallier /* Release device if not used at runtime or for pm transitions */ 594ea8ba295SGatien Chevallier stm32_rng->release_post_boot = IS_ENABLED(CFG_WITH_SOFTWARE_PRNG) && 595ea8ba295SGatien Chevallier !IS_ENABLED(CFG_PM); 596f3c22059SEtienne Carriere 597*5959d83fSGatien Chevallier stm32_rng->rng_config = stm32_rng->ddata->cr; 598*5959d83fSGatien Chevallier if (stm32_rng->rng_config & ~RNG_CR_ENTROPY_SRC_MASK) 599*5959d83fSGatien Chevallier panic("Incorrect entropy source configuration"); 600*5959d83fSGatien Chevallier stm32_rng->health_test_conf = stm32_rng->ddata->htcr; 601*5959d83fSGatien Chevallier stm32_rng->noise_ctrl_conf = stm32_rng->ddata->nscr; 602*5959d83fSGatien Chevallier if (stm32_rng->noise_ctrl_conf & ~RNG_NSCR_MASK) 603*5959d83fSGatien Chevallier panic("Incorrect noise source control configuration"); 604*5959d83fSGatien Chevallier 605f3c22059SEtienne Carriere return TEE_SUCCESS; 606f3c22059SEtienne Carriere } 607f3c22059SEtienne Carriere 608ea8ba295SGatien Chevallier static TEE_Result stm32_rng_probe(const void *fdt, int offs, 609f9508605SGatien Chevallier const void *compat_data) 610ea8ba295SGatien Chevallier { 611ea8ba295SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 612ea8ba295SGatien Chevallier 613ea8ba295SGatien Chevallier /* Expect a single RNG instance */ 614ea8ba295SGatien Chevallier assert(!stm32_rng); 615ea8ba295SGatien Chevallier 616ea8ba295SGatien Chevallier stm32_rng = calloc(1, sizeof(*stm32_rng)); 617ea8ba295SGatien Chevallier if (!stm32_rng) 618ea8ba295SGatien Chevallier panic(); 619ea8ba295SGatien Chevallier 620*5959d83fSGatien Chevallier stm32_rng->ddata = compat_data; 621*5959d83fSGatien Chevallier assert(stm32_rng->ddata); 622*5959d83fSGatien Chevallier 623ea8ba295SGatien Chevallier res = stm32_rng_parse_fdt(fdt, offs); 624ea8ba295SGatien Chevallier if (res) 625ea8ba295SGatien Chevallier goto err; 626ea8ba295SGatien Chevallier 627ea8ba295SGatien Chevallier res = clk_enable(stm32_rng->clock); 628ea8ba295SGatien Chevallier if (res) 629ea8ba295SGatien Chevallier goto err; 630ea8ba295SGatien Chevallier 63145da6509SGatien Chevallier if (stm32_rng->bus_clock) { 63245da6509SGatien Chevallier res = clk_enable(stm32_rng->bus_clock); 63345da6509SGatien Chevallier if (res) { 63445da6509SGatien Chevallier clk_disable(stm32_rng->clock); 63545da6509SGatien Chevallier goto err; 63645da6509SGatien Chevallier } 63745da6509SGatien Chevallier } 63845da6509SGatien Chevallier 639ea8ba295SGatien Chevallier if (stm32_rng->rstctrl && 640ea8ba295SGatien Chevallier rstctrl_assert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) { 641ea8ba295SGatien Chevallier res = TEE_ERROR_GENERIC; 642ea8ba295SGatien Chevallier goto err_clk; 643ea8ba295SGatien Chevallier } 644ea8ba295SGatien Chevallier 645ea8ba295SGatien Chevallier if (stm32_rng->rstctrl && 646ea8ba295SGatien Chevallier rstctrl_deassert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) { 647ea8ba295SGatien Chevallier res = TEE_ERROR_GENERIC; 648ea8ba295SGatien Chevallier goto err_clk; 649ea8ba295SGatien Chevallier } 650ea8ba295SGatien Chevallier 651f63f11bdSGatien Chevallier res = init_rng(); 652f63f11bdSGatien Chevallier if (res) 653f63f11bdSGatien Chevallier goto err_clk; 654f63f11bdSGatien Chevallier 655ea8ba295SGatien Chevallier clk_disable(stm32_rng->clock); 65645da6509SGatien Chevallier if (stm32_rng->bus_clock) 65745da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 658ea8ba295SGatien Chevallier 659ea8ba295SGatien Chevallier if (stm32_rng->release_post_boot) 660ea8ba295SGatien Chevallier stm32mp_register_non_secure_periph_iomem(stm32_rng->base.pa); 661ea8ba295SGatien Chevallier else 662ea8ba295SGatien Chevallier stm32mp_register_secure_periph_iomem(stm32_rng->base.pa); 663ea8ba295SGatien Chevallier 664*5959d83fSGatien Chevallier /* Power management implementation expects both or none are set */ 665*5959d83fSGatien Chevallier assert(stm32_rng->ddata->has_power_optim == 666*5959d83fSGatien Chevallier stm32_rng->ddata->has_cond_reset); 667*5959d83fSGatien Chevallier 66829893549SGatien Chevallier register_pm_core_service_cb(stm32_rng_pm, &stm32_rng, "rng-service"); 66929893549SGatien Chevallier 670ea8ba295SGatien Chevallier return TEE_SUCCESS; 671ea8ba295SGatien Chevallier 672ea8ba295SGatien Chevallier err_clk: 673ea8ba295SGatien Chevallier clk_disable(stm32_rng->clock); 67445da6509SGatien Chevallier if (stm32_rng->bus_clock) 67545da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 676ea8ba295SGatien Chevallier err: 677ea8ba295SGatien Chevallier free(stm32_rng); 678ea8ba295SGatien Chevallier stm32_rng = NULL; 679ea8ba295SGatien Chevallier 680ea8ba295SGatien Chevallier return res; 681ea8ba295SGatien Chevallier } 682ea8ba295SGatien Chevallier 683091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp13_data[] = { 68445da6509SGatien Chevallier { 68545da6509SGatien Chevallier .nb_clock = 1, 68645da6509SGatien Chevallier .has_cond_reset = true, 687*5959d83fSGatien Chevallier .has_power_optim = true, 688*5959d83fSGatien Chevallier .cr = 0x00F00D00, 689*5959d83fSGatien Chevallier .nscr = 0x2B5BB, 690*5959d83fSGatien Chevallier .htcr = 0x969D, 69145da6509SGatien Chevallier }, 692091ef005SGatien Chevallier }; 693091ef005SGatien Chevallier 694091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp15_data[] = { 69545da6509SGatien Chevallier { 69645da6509SGatien Chevallier .nb_clock = 1, 69745da6509SGatien Chevallier .has_cond_reset = false, 698*5959d83fSGatien Chevallier .has_power_optim = false, 69945da6509SGatien Chevallier }, 700091ef005SGatien Chevallier }; 701091ef005SGatien Chevallier DECLARE_KEEP_PAGER(mp15_data); 702091ef005SGatien Chevallier 70345da6509SGatien Chevallier static const struct stm32_rng_driver_data mp25_data[] = { 70445da6509SGatien Chevallier { 70545da6509SGatien Chevallier .nb_clock = 2, 70645da6509SGatien Chevallier .has_cond_reset = true, 707*5959d83fSGatien Chevallier .has_power_optim = true, 708*5959d83fSGatien Chevallier .cr = 0x00F00D00, 709*5959d83fSGatien Chevallier .nscr = 0x2B5BB, 710*5959d83fSGatien Chevallier .htcr = 0x969D, 71145da6509SGatien Chevallier }, 71245da6509SGatien Chevallier }; 71345da6509SGatien Chevallier 714ea8ba295SGatien Chevallier static const struct dt_device_match rng_match_table[] = { 715091ef005SGatien Chevallier { .compatible = "st,stm32-rng", .compat_data = &mp15_data }, 716091ef005SGatien Chevallier { .compatible = "st,stm32mp13-rng", .compat_data = &mp13_data }, 71745da6509SGatien Chevallier { .compatible = "st,stm32mp25-rng", .compat_data = &mp25_data }, 718ea8ba295SGatien Chevallier { } 719ea8ba295SGatien Chevallier }; 720ea8ba295SGatien Chevallier 721ea8ba295SGatien Chevallier DEFINE_DT_DRIVER(stm32_rng_dt_driver) = { 722ea8ba295SGatien Chevallier .name = "stm32_rng", 723ea8ba295SGatien Chevallier .match_table = rng_match_table, 724ea8ba295SGatien Chevallier .probe = stm32_rng_probe, 725ea8ba295SGatien Chevallier }; 726d8682c4cSEtienne Carriere 727d8682c4cSEtienne Carriere static TEE_Result stm32_rng_release(void) 728d8682c4cSEtienne Carriere { 729d8682c4cSEtienne Carriere if (stm32_rng && stm32_rng->release_post_boot) { 730d8682c4cSEtienne Carriere DMSG("Release RNG driver"); 731d8682c4cSEtienne Carriere free(stm32_rng); 732d8682c4cSEtienne Carriere stm32_rng = NULL; 733d8682c4cSEtienne Carriere } 734d8682c4cSEtienne Carriere 735d8682c4cSEtienne Carriere return TEE_SUCCESS; 736d8682c4cSEtienne Carriere } 737d8682c4cSEtienne Carriere 738d8682c4cSEtienne Carriere release_init_resource(stm32_rng_release); 739