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> 115959d83fSGatien 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> 255959d83fSGatien 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) 305959d83fSGatien Chevallier #define RNG_NSCR U(0x0C) 315959d83fSGatien 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) 365959d83fSGatien Chevallier #define RNG_CR_CONFIG1 GENMASK_32(11, 8) 375959d83fSGatien Chevallier #define RNG_CR_NISTC BIT(12) 385959d83fSGatien Chevallier #define RNG_CR_POWER_OPTIM BIT(13) 395959d83fSGatien 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) 425959d83fSGatien Chevallier #define RNG_CR_CONFIG3 GENMASK_32(25, 20) 43091ef005SGatien Chevallier #define RNG_CR_CONDRST BIT(30) 445959d83fSGatien Chevallier #define RNG_CR_ENTROPY_SRC_MASK (RNG_CR_CONFIG1 | RNG_CR_NISTC | \ 455959d83fSGatien 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 535959d83fSGatien Chevallier #define RNG_NSCR_MASK GENMASK_32(17, 0) 545959d83fSGatien 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 645959d83fSGatien Chevallier #define RNG_CONFIG_MASK (RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED | \ 655959d83fSGatien Chevallier RNG_CR_CLKDIV) 66091ef005SGatien Chevallier 67091ef005SGatien Chevallier struct stm32_rng_driver_data { 68*aa12f203SGatien Chevallier unsigned long max_noise_clk_freq; 6945da6509SGatien Chevallier unsigned long nb_clock; 705959d83fSGatien Chevallier uint32_t cr; 715959d83fSGatien Chevallier uint32_t nscr; 725959d83fSGatien Chevallier uint32_t htcr; 735959d83fSGatien Chevallier bool has_power_optim; 74091ef005SGatien Chevallier bool has_cond_reset; 75091ef005SGatien Chevallier }; 76091ef005SGatien Chevallier 77f3c22059SEtienne Carriere struct stm32_rng_instance { 78f3c22059SEtienne Carriere struct io_pa_va base; 79d7a1a7d2SEtienne Carriere struct clk *clock; 8045da6509SGatien Chevallier struct clk *bus_clock; 81ea8ba295SGatien Chevallier struct rstctrl *rstctrl; 82091ef005SGatien Chevallier const struct stm32_rng_driver_data *ddata; 83f3c22059SEtienne Carriere unsigned int lock; 845959d83fSGatien Chevallier uint64_t error_to_ref; 855959d83fSGatien Chevallier uint32_t pm_cr; 865959d83fSGatien Chevallier uint32_t pm_health; 875959d83fSGatien Chevallier uint32_t pm_noise_ctrl; 885959d83fSGatien Chevallier uint32_t health_test_conf; 895959d83fSGatien Chevallier uint32_t noise_ctrl_conf; 905959d83fSGatien Chevallier uint32_t rng_config; 91d8682c4cSEtienne Carriere bool release_post_boot; 923c752300SGatien Chevallier bool clock_error; 93091ef005SGatien Chevallier bool error_conceal; 94f3c22059SEtienne Carriere }; 95f3c22059SEtienne Carriere 96ea8ba295SGatien Chevallier /* Expect at most a single RNG instance */ 97f3c22059SEtienne Carriere static struct stm32_rng_instance *stm32_rng; 98f3c22059SEtienne Carriere 99f63f11bdSGatien Chevallier static vaddr_t get_base(void) 100f63f11bdSGatien Chevallier { 101f63f11bdSGatien Chevallier assert(stm32_rng); 102f63f11bdSGatien Chevallier 103f63f11bdSGatien Chevallier return io_pa_or_va(&stm32_rng->base, 1); 104f63f11bdSGatien Chevallier } 105f63f11bdSGatien Chevallier 106f3c22059SEtienne Carriere /* 107091ef005SGatien Chevallier * Extracts from the STM32 RNG specification when RNG supports CONDRST. 108f3c22059SEtienne Carriere * 109f3c22059SEtienne Carriere * When a noise source (or seed) error occurs, the RNG stops generating 110f3c22059SEtienne Carriere * random numbers and sets to “1” both SEIS and SECS bits to indicate 111f3c22059SEtienne Carriere * that a seed error occurred. (...) 112091ef005SGatien Chevallier * 113091ef005SGatien Chevallier * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield 114091ef005SGatien Chevallier * description for details). This step is needed only if SECS is set. 115091ef005SGatien Chevallier * Indeed, when SEIS is set and SECS is cleared it means RNG performed 116091ef005SGatien Chevallier * the reset automatically (auto-reset). 117091ef005SGatien Chevallier * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST 118091ef005SGatien Chevallier * to be cleared in the RNG_CR register, then confirm that SEIS is 119091ef005SGatien Chevallier * cleared in the RNG_SR register. Otherwise just clear SEIS bit in 120091ef005SGatien Chevallier * the RNG_SR register. 121091ef005SGatien Chevallier * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be 122091ef005SGatien Chevallier * cleared by RNG. The random number generation is now back to normal. 123091ef005SGatien Chevallier */ 124091ef005SGatien Chevallier static void conceal_seed_error_cond_reset(void) 125091ef005SGatien Chevallier { 126091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 127091ef005SGatien Chevallier vaddr_t rng_base = get_base(); 128f3c22059SEtienne Carriere 129091ef005SGatien Chevallier if (!dev->error_conceal) { 130091ef005SGatien Chevallier uint32_t sr = io_read32(rng_base + RNG_SR); 131091ef005SGatien Chevallier 132091ef005SGatien Chevallier if (sr & RNG_SR_SECS) { 133091ef005SGatien Chevallier /* Conceal by resetting the subsystem (step 1.) */ 134091ef005SGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 135091ef005SGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 136091ef005SGatien Chevallier 137091ef005SGatien Chevallier /* Arm timeout for error_conceal sequence */ 138091ef005SGatien Chevallier dev->error_to_ref = 139091ef005SGatien Chevallier timeout_init_us(RNG_READY_TIMEOUT_US); 140091ef005SGatien Chevallier dev->error_conceal = true; 141091ef005SGatien Chevallier } else { 142091ef005SGatien Chevallier /* RNG auto-reset (step 2.) */ 143091ef005SGatien Chevallier io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS); 144091ef005SGatien Chevallier } 145091ef005SGatien Chevallier } else { 146091ef005SGatien Chevallier /* Measure time before possible reschedule */ 147091ef005SGatien Chevallier bool timed_out = timeout_elapsed(dev->error_to_ref); 148091ef005SGatien Chevallier 149091ef005SGatien Chevallier /* Wait CONDRST is cleared (step 2.) */ 150091ef005SGatien Chevallier if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) { 151091ef005SGatien Chevallier if (timed_out) 152091ef005SGatien Chevallier panic(); 153091ef005SGatien Chevallier 154091ef005SGatien Chevallier /* Wait subsystem reset cycle completes */ 155091ef005SGatien Chevallier return; 156091ef005SGatien Chevallier } 157091ef005SGatien Chevallier 158091ef005SGatien Chevallier /* Check SEIS is cleared (step 2.) */ 159091ef005SGatien Chevallier if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 160091ef005SGatien Chevallier panic(); 161091ef005SGatien Chevallier 162091ef005SGatien Chevallier /* Wait SECS is cleared (step 3.) */ 163091ef005SGatien Chevallier if (io_read32(rng_base + RNG_SR) & RNG_SR_SECS) { 164091ef005SGatien Chevallier if (timed_out) 165091ef005SGatien Chevallier panic(); 166091ef005SGatien Chevallier 167091ef005SGatien Chevallier /* Wait subsystem reset cycle completes */ 168091ef005SGatien Chevallier return; 169091ef005SGatien Chevallier } 170091ef005SGatien Chevallier 171091ef005SGatien Chevallier dev->error_conceal = false; 172091ef005SGatien Chevallier } 173091ef005SGatien Chevallier } 174091ef005SGatien Chevallier 175091ef005SGatien Chevallier /* 176091ef005SGatien Chevallier * Extracts from the STM32 RNG specification, when CONDRST is not supported 177091ef005SGatien Chevallier * 178091ef005SGatien Chevallier * When a noise source (or seed) error occurs, the RNG stops generating 179091ef005SGatien Chevallier * random numbers and sets to “1” both SEIS and SECS bits to indicate 180091ef005SGatien Chevallier * that a seed error occurred. (...) 181091ef005SGatien Chevallier * 182f3c22059SEtienne Carriere * The following sequence shall be used to fully recover from a seed 183f3c22059SEtienne Carriere * error after the RNG initialization: 184f3c22059SEtienne Carriere * 1. Clear the SEIS bit by writing it to “0”. 185f3c22059SEtienne Carriere * 2. Read out 12 words from the RNG_DR register, and discard each of 186f3c22059SEtienne Carriere * them in order to clean the pipeline. 187f3c22059SEtienne Carriere * 3. Confirm that SEIS is still cleared. Random number generation is 188f3c22059SEtienne Carriere * back to normal. 189f3c22059SEtienne Carriere */ 190091ef005SGatien Chevallier static void conceal_seed_error_sw_reset(void) 191f3c22059SEtienne Carriere { 1926a6b6168SGatien Chevallier vaddr_t rng_base = get_base(); 193f3c22059SEtienne Carriere size_t i = 0; 194f3c22059SEtienne Carriere 1956a6b6168SGatien Chevallier io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS); 196f3c22059SEtienne Carriere 197f3c22059SEtienne Carriere for (i = 12; i != 0; i--) 198f3c22059SEtienne Carriere (void)io_read32(rng_base + RNG_DR); 199f3c22059SEtienne Carriere 200f3c22059SEtienne Carriere if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 201f3c22059SEtienne Carriere panic("RNG noise"); 202f3c22059SEtienne Carriere } 203f3c22059SEtienne Carriere 204091ef005SGatien Chevallier static void conceal_seed_error(void) 205091ef005SGatien Chevallier { 206091ef005SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) 207091ef005SGatien Chevallier conceal_seed_error_cond_reset(); 208091ef005SGatien Chevallier else 209091ef005SGatien Chevallier conceal_seed_error_sw_reset(); 210091ef005SGatien Chevallier } 211091ef005SGatien Chevallier 212c99311c8SEtienne Carriere static TEE_Result read_available(vaddr_t rng_base, uint8_t *out, size_t *size) 213f3c22059SEtienne Carriere { 214091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 215c99311c8SEtienne Carriere uint8_t *buf = NULL; 216c99311c8SEtienne Carriere size_t req_size = 0; 217c99311c8SEtienne Carriere size_t len = 0; 218f3c22059SEtienne Carriere 219091ef005SGatien Chevallier if (dev->error_conceal || io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 2206a6b6168SGatien Chevallier conceal_seed_error(); 221f3c22059SEtienne Carriere 22223123473SEtienne Carriere if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) { 22323123473SEtienne Carriere FMSG("RNG not ready"); 224c99311c8SEtienne Carriere return TEE_ERROR_NO_DATA; 22523123473SEtienne Carriere } 226f3c22059SEtienne Carriere 22723123473SEtienne Carriere if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) { 22823123473SEtienne Carriere FMSG("RNG noise error"); 229c99311c8SEtienne Carriere return TEE_ERROR_NO_DATA; 23023123473SEtienne Carriere } 231c99311c8SEtienne Carriere 232c99311c8SEtienne Carriere buf = out; 233c99311c8SEtienne Carriere req_size = MIN(RNG_FIFO_BYTE_DEPTH, *size); 234c99311c8SEtienne Carriere len = req_size; 235f3c22059SEtienne Carriere 236f3c22059SEtienne Carriere /* RNG is ready: read up to 4 32bit words */ 237f3c22059SEtienne Carriere while (len) { 23823bdf063SEtienne Carriere uint32_t data32 = 0; 239f3c22059SEtienne Carriere size_t sz = MIN(len, sizeof(uint32_t)); 240f3c22059SEtienne Carriere 24123bdf063SEtienne Carriere if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) 24223bdf063SEtienne Carriere break; 24323bdf063SEtienne Carriere data32 = io_read32(rng_base + RNG_DR); 24423bdf063SEtienne Carriere 2453e64c635SGatien Chevallier /* Late seed error case: DR being 0 is an error status */ 2463e64c635SGatien Chevallier if (!data32) { 2473e64c635SGatien Chevallier conceal_seed_error(); 2483e64c635SGatien Chevallier return TEE_ERROR_NO_DATA; 2493e64c635SGatien Chevallier } 2503e64c635SGatien Chevallier 251f3c22059SEtienne Carriere memcpy(buf, &data32, sz); 252f3c22059SEtienne Carriere buf += sz; 253f3c22059SEtienne Carriere len -= sz; 254f3c22059SEtienne Carriere } 255c99311c8SEtienne Carriere 25623bdf063SEtienne Carriere *size = req_size - len; 257f3c22059SEtienne Carriere 258c99311c8SEtienne Carriere return TEE_SUCCESS; 259f3c22059SEtienne Carriere } 260f3c22059SEtienne Carriere 261091ef005SGatien Chevallier static uint32_t stm32_rng_clock_freq_restrain(void) 262091ef005SGatien Chevallier { 263091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 264091ef005SGatien Chevallier unsigned long clock_rate = 0; 265091ef005SGatien Chevallier uint32_t clock_div = 0; 266091ef005SGatien Chevallier 267091ef005SGatien Chevallier clock_rate = clk_get_rate(dev->clock); 268091ef005SGatien Chevallier 269091ef005SGatien Chevallier /* 270091ef005SGatien Chevallier * Get the exponent to apply on the CLKDIV field in RNG_CR register 271091ef005SGatien Chevallier * No need to handle the case when clock-div > 0xF as it is physically 272091ef005SGatien Chevallier * impossible 273091ef005SGatien Chevallier */ 274*aa12f203SGatien Chevallier while ((clock_rate >> clock_div) > dev->ddata->max_noise_clk_freq) 275091ef005SGatien Chevallier clock_div++; 276091ef005SGatien Chevallier 277091ef005SGatien Chevallier DMSG("RNG clk rate : %lu", clk_get_rate(dev->clock) >> clock_div); 278091ef005SGatien Chevallier 279091ef005SGatien Chevallier return clock_div; 280091ef005SGatien Chevallier } 281091ef005SGatien Chevallier 282f63f11bdSGatien Chevallier static TEE_Result init_rng(void) 283f3c22059SEtienne Carriere { 284f63f11bdSGatien Chevallier vaddr_t rng_base = get_base(); 2853c752300SGatien Chevallier uint32_t cr_ced_mask = 0; 2865959d83fSGatien Chevallier uint32_t value = 0; 2873c752300SGatien Chevallier 2883c752300SGatien Chevallier if (!stm32_rng->clock_error) 2893c752300SGatien Chevallier cr_ced_mask = RNG_CR_CED; 290f3c22059SEtienne Carriere 291f63f11bdSGatien Chevallier /* Clean error indications */ 292f63f11bdSGatien Chevallier io_write32(rng_base + RNG_SR, 0); 293f3c22059SEtienne Carriere 294091ef005SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 295091ef005SGatien Chevallier uint32_t clock_div = stm32_rng_clock_freq_restrain(); 296091ef005SGatien Chevallier 2975959d83fSGatien Chevallier /* 2985959d83fSGatien Chevallier * Keep default RNG configuration if none was specified. 2995959d83fSGatien Chevallier * 0 is an invalid value as it disables all entropy sources. 3005959d83fSGatien Chevallier */ 3015959d83fSGatien Chevallier if (!stm32_rng->rng_config) 3025959d83fSGatien Chevallier stm32_rng->rng_config = io_read32(rng_base + RNG_CR) & 3035959d83fSGatien Chevallier RNG_CR_ENTROPY_SRC_MASK; 3045959d83fSGatien Chevallier 3055959d83fSGatien Chevallier /* 3065959d83fSGatien Chevallier * Configuration must be set in the same access that sets 3075959d83fSGatien Chevallier * RNG_CR_CONDRST bit. Otherwise, the configuration setting is 3085959d83fSGatien Chevallier * not taken into account. CONFIGLOCK bit is always cleared at 3095959d83fSGatien Chevallier * this stage. 3105959d83fSGatien Chevallier */ 3115959d83fSGatien Chevallier io_clrsetbits32(rng_base + RNG_CR, RNG_CONFIG_MASK, 3125959d83fSGatien Chevallier stm32_rng->rng_config | RNG_CR_CONDRST | 3135959d83fSGatien Chevallier cr_ced_mask | 3145959d83fSGatien Chevallier SHIFT_U32(clock_div, RNG_CR_CLKDIV_SHIFT)); 3155959d83fSGatien Chevallier 3165959d83fSGatien Chevallier /* 3175959d83fSGatien Chevallier * Write health test and noise source control configuration 3185959d83fSGatien Chevallier * according to current RNG entropy source configuration 3195959d83fSGatien Chevallier */ 3205959d83fSGatien Chevallier if (stm32_rng->noise_ctrl_conf) 3215959d83fSGatien Chevallier io_write32(rng_base + RNG_NSCR, 3225959d83fSGatien Chevallier stm32_rng->noise_ctrl_conf); 3235959d83fSGatien Chevallier 3245959d83fSGatien Chevallier if (stm32_rng->health_test_conf) 3255959d83fSGatien Chevallier io_write32(rng_base + RNG_HTCR, 3265959d83fSGatien Chevallier stm32_rng->health_test_conf); 327091ef005SGatien Chevallier 328091ef005SGatien Chevallier io_clrsetbits32(rng_base + RNG_CR, RNG_CR_CONDRST, 329091ef005SGatien Chevallier RNG_CR_RNGEN); 330eb5cf770SGatien Chevallier 3315959d83fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_CR, value, 3325959d83fSGatien Chevallier !(value & RNG_CR_CONDRST), 0, 3335959d83fSGatien Chevallier RNG_READY_TIMEOUT_US)) 334eb5cf770SGatien Chevallier panic(); 3355959d83fSGatien Chevallier 3365959d83fSGatien Chevallier DMSG("RNG control register %#"PRIx32, 3375959d83fSGatien Chevallier io_read32(rng_base + RNG_CR)); 3385959d83fSGatien Chevallier DMSG("RNG noise source control register %#"PRIx32, 3395959d83fSGatien Chevallier io_read32(rng_base + RNG_NSCR)); 3405959d83fSGatien Chevallier DMSG("RNG health test register %#"PRIx32, 3415959d83fSGatien Chevallier io_read32(rng_base + RNG_HTCR)); 342091ef005SGatien Chevallier } else { 3433c752300SGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_RNGEN | cr_ced_mask); 344091ef005SGatien Chevallier } 345f63f11bdSGatien Chevallier 3465959d83fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_SR, value, 3475959d83fSGatien Chevallier value & RNG_SR_DRDY, 0, 3485959d83fSGatien Chevallier RNG_READY_TIMEOUT_US)) 349f63f11bdSGatien Chevallier return TEE_ERROR_GENERIC; 350f63f11bdSGatien Chevallier 351f63f11bdSGatien Chevallier return TEE_SUCCESS; 352f3c22059SEtienne Carriere } 353f3c22059SEtienne Carriere 35498c36268SGatien Chevallier static TEE_Result stm32_rng_read(uint8_t *out, size_t size) 355f3c22059SEtienne Carriere { 356c99311c8SEtienne Carriere TEE_Result rc = TEE_ERROR_GENERIC; 357c99311c8SEtienne Carriere bool burst_timeout = false; 358c99311c8SEtienne Carriere uint64_t timeout_ref = 0; 359f3c22059SEtienne Carriere uint32_t exceptions = 0; 360f3c22059SEtienne Carriere uint8_t *out_ptr = out; 361c99311c8SEtienne Carriere vaddr_t rng_base = 0; 362f3c22059SEtienne Carriere size_t out_size = 0; 363f3c22059SEtienne Carriere 364f3c22059SEtienne Carriere if (!stm32_rng) { 365f3c22059SEtienne Carriere DMSG("No RNG"); 366f3c22059SEtienne Carriere return TEE_ERROR_NOT_SUPPORTED; 367f3c22059SEtienne Carriere } 368f3c22059SEtienne Carriere 369fb1681dfSGatien Chevallier rc = clk_enable(stm32_rng->clock); 370fb1681dfSGatien Chevallier if (rc) 371fb1681dfSGatien Chevallier return rc; 372fb1681dfSGatien Chevallier 37345da6509SGatien Chevallier if (stm32_rng->bus_clock) { 37445da6509SGatien Chevallier rc = clk_enable(stm32_rng->bus_clock); 37545da6509SGatien Chevallier if (rc) { 37645da6509SGatien Chevallier clk_disable(stm32_rng->clock); 37745da6509SGatien Chevallier return rc; 37845da6509SGatien Chevallier } 37945da6509SGatien Chevallier } 38045da6509SGatien Chevallier 381f63f11bdSGatien Chevallier rng_base = get_base(); 382c99311c8SEtienne Carriere 383c99311c8SEtienne Carriere /* Arm timeout */ 3840817aa6fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 385c99311c8SEtienne Carriere burst_timeout = false; 386f3c22059SEtienne Carriere 387f3c22059SEtienne Carriere while (out_size < size) { 388f3c22059SEtienne Carriere /* Read by chunks of the size the RNG FIFO depth */ 389f3c22059SEtienne Carriere size_t sz = size - out_size; 390f3c22059SEtienne Carriere 391f3c22059SEtienne Carriere exceptions = may_spin_lock(&stm32_rng->lock); 392f3c22059SEtienne Carriere 393c99311c8SEtienne Carriere rc = read_available(rng_base, out_ptr, &sz); 394c99311c8SEtienne Carriere 395c99311c8SEtienne Carriere /* Raise timeout only if we failed to get some samples */ 396c99311c8SEtienne Carriere assert(!rc || rc == TEE_ERROR_NO_DATA); 397c99311c8SEtienne Carriere if (rc) 398c99311c8SEtienne Carriere burst_timeout = timeout_elapsed(timeout_ref); 399f3c22059SEtienne Carriere 400f3c22059SEtienne Carriere may_spin_unlock(&stm32_rng->lock, exceptions); 401f3c22059SEtienne Carriere 402c99311c8SEtienne Carriere if (burst_timeout) { 403c99311c8SEtienne Carriere rc = TEE_ERROR_GENERIC; 404c99311c8SEtienne Carriere goto out; 405f3c22059SEtienne Carriere } 406f3c22059SEtienne Carriere 407c99311c8SEtienne Carriere if (!rc) { 408c99311c8SEtienne Carriere out_size += sz; 409c99311c8SEtienne Carriere out_ptr += sz; 410c99311c8SEtienne Carriere /* Re-arm timeout */ 4110817aa6fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 412c99311c8SEtienne Carriere burst_timeout = false; 413c99311c8SEtienne Carriere } 414c99311c8SEtienne Carriere } 415c99311c8SEtienne Carriere 416c99311c8SEtienne Carriere out: 417c99311c8SEtienne Carriere assert(!rc || rc == TEE_ERROR_GENERIC); 418f63f11bdSGatien Chevallier clk_disable(stm32_rng->clock); 41945da6509SGatien Chevallier if (stm32_rng->bus_clock) 42045da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 421f3c22059SEtienne Carriere 422f3c22059SEtienne Carriere return rc; 423f3c22059SEtienne Carriere } 424f3c22059SEtienne Carriere 425cd451498SEtienne Carriere #ifdef CFG_WITH_SOFTWARE_PRNG 426cd451498SEtienne Carriere /* Override weak plat_rng_init with platform handler to seed PRNG */ 427cd451498SEtienne Carriere void plat_rng_init(void) 428cd451498SEtienne Carriere { 429cd451498SEtienne Carriere uint8_t seed[RNG_FIFO_BYTE_DEPTH] = { }; 430cd451498SEtienne Carriere 431cd451498SEtienne Carriere if (stm32_rng_read(seed, sizeof(seed))) 432cd451498SEtienne Carriere panic(); 433cd451498SEtienne Carriere 434cd451498SEtienne Carriere if (crypto_rng_init(seed, sizeof(seed))) 435cd451498SEtienne Carriere panic(); 436cd451498SEtienne Carriere 437cd451498SEtienne Carriere DMSG("PRNG seeded with RNG"); 438cd451498SEtienne Carriere } 439cd451498SEtienne Carriere #else 440cb2478efSAndrew Davis TEE_Result hw_get_random_bytes(void *out, size_t size) 441097f329aSEtienne Carriere { 442097f329aSEtienne Carriere return stm32_rng_read(out, size); 443097f329aSEtienne Carriere } 44427f3087bSGatien Chevallier 44527f3087bSGatien Chevallier void plat_rng_init(void) 44627f3087bSGatien Chevallier { 44727f3087bSGatien Chevallier } 448097f329aSEtienne Carriere #endif 449097f329aSEtienne Carriere 4505959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_resume(void) 45129893549SGatien Chevallier { 45229893549SGatien Chevallier vaddr_t base = get_base(); 45329893549SGatien Chevallier 45429893549SGatien Chevallier /* Clean error indications */ 45529893549SGatien Chevallier io_write32(base + RNG_SR, 0); 45629893549SGatien Chevallier 45729893549SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 458eb5cf770SGatien Chevallier uint64_t timeout_ref = 0; 459eb5cf770SGatien Chevallier 46029893549SGatien Chevallier /* 461c2c5b4beSGatien Chevallier * Configuration must be set in the same access that sets 462c2c5b4beSGatien Chevallier * RNG_CR_CONDRST bit. Otherwise, the configuration setting is 463c2c5b4beSGatien Chevallier * not taken into account. CONFIGLOCK bit is always cleared in 464c2c5b4beSGatien Chevallier * this configuration. 46529893549SGatien Chevallier */ 4665959d83fSGatien Chevallier io_write32(base + RNG_CR, stm32_rng->pm_cr | RNG_CR_CONDRST); 4675959d83fSGatien Chevallier 4685959d83fSGatien Chevallier /* Restore health test and noise control configuration */ 4695959d83fSGatien Chevallier io_write32(base + RNG_NSCR, stm32_rng->pm_noise_ctrl); 4705959d83fSGatien Chevallier io_write32(base + RNG_HTCR, stm32_rng->pm_health); 47129893549SGatien Chevallier 47229893549SGatien Chevallier io_clrsetbits32(base + RNG_CR, RNG_CR_CONDRST, RNG_CR_RNGEN); 473eb5cf770SGatien Chevallier 474eb5cf770SGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 475eb5cf770SGatien Chevallier while (io_read32(base + RNG_CR) & RNG_CR_CONDRST) 476eb5cf770SGatien Chevallier if (timeout_elapsed(timeout_ref)) 477eb5cf770SGatien Chevallier break; 478eb5cf770SGatien Chevallier if (io_read32(base + RNG_CR) & RNG_CR_CONDRST) 479eb5cf770SGatien Chevallier panic(); 48029893549SGatien Chevallier } else { 4815959d83fSGatien Chevallier io_write32(base + RNG_CR, RNG_CR_RNGEN | stm32_rng->pm_cr); 4825959d83fSGatien Chevallier } 4835959d83fSGatien Chevallier 4845959d83fSGatien Chevallier return TEE_SUCCESS; 4855959d83fSGatien Chevallier } 4865959d83fSGatien Chevallier 4875959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_suspend(void) 4885959d83fSGatien Chevallier { 4895959d83fSGatien Chevallier vaddr_t rng_base = get_base(); 4905959d83fSGatien Chevallier 4915959d83fSGatien Chevallier stm32_rng->pm_cr = io_read32(rng_base + RNG_CR); 4925959d83fSGatien Chevallier 4935959d83fSGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 4945959d83fSGatien Chevallier stm32_rng->pm_health = io_read32(rng_base + RNG_HTCR); 4955959d83fSGatien Chevallier stm32_rng->pm_noise_ctrl = io_read32(rng_base + RNG_NSCR); 4965959d83fSGatien Chevallier } 4975959d83fSGatien Chevallier 4985959d83fSGatien Chevallier if (stm32_rng->ddata->has_power_optim) { 4995959d83fSGatien Chevallier uint64_t timeout_ref = 0; 5005959d83fSGatien Chevallier 5015959d83fSGatien Chevallier /* 5025959d83fSGatien Chevallier * As per reference manual, it is recommended to set 5035959d83fSGatien Chevallier * RNG_CONFIG2[bit0] when RNG power consumption is critical. 5045959d83fSGatien Chevallier */ 5055959d83fSGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_POWER_OPTIM | 5065959d83fSGatien Chevallier RNG_CR_CONDRST); 5075959d83fSGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 5085959d83fSGatien Chevallier 5095959d83fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 5105959d83fSGatien Chevallier while (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) 5115959d83fSGatien Chevallier if (timeout_elapsed(timeout_ref)) 5125959d83fSGatien Chevallier break; 5135959d83fSGatien Chevallier if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) 5145959d83fSGatien Chevallier panic(); 5155959d83fSGatien Chevallier } else { 5165959d83fSGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_RNGEN); 51729893549SGatien Chevallier } 51829893549SGatien Chevallier 51929893549SGatien Chevallier return TEE_SUCCESS; 52029893549SGatien Chevallier } 52129893549SGatien Chevallier 52229893549SGatien Chevallier static TEE_Result 52329893549SGatien Chevallier stm32_rng_pm(enum pm_op op, unsigned int pm_hint __unused, 52429893549SGatien Chevallier const struct pm_callback_handle *pm_handle __unused) 52529893549SGatien Chevallier { 52629893549SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 52729893549SGatien Chevallier 52829893549SGatien Chevallier assert(stm32_rng && (op == PM_OP_SUSPEND || op == PM_OP_RESUME)); 52929893549SGatien Chevallier 53029893549SGatien Chevallier res = clk_enable(stm32_rng->clock); 53129893549SGatien Chevallier if (res) 53229893549SGatien Chevallier return res; 53329893549SGatien Chevallier 53445da6509SGatien Chevallier if (stm32_rng->bus_clock) { 53545da6509SGatien Chevallier res = clk_enable(stm32_rng->bus_clock); 53645da6509SGatien Chevallier if (res) { 53745da6509SGatien Chevallier clk_disable(stm32_rng->clock); 53845da6509SGatien Chevallier return res; 53945da6509SGatien Chevallier } 54045da6509SGatien Chevallier } 54145da6509SGatien Chevallier 5425959d83fSGatien Chevallier if (op == PM_OP_RESUME) 5435959d83fSGatien Chevallier res = stm32_rng_pm_resume(); 54429893549SGatien Chevallier else 5455959d83fSGatien Chevallier res = stm32_rng_pm_suspend(); 54629893549SGatien Chevallier 54729893549SGatien Chevallier clk_disable(stm32_rng->clock); 54845da6509SGatien Chevallier if (stm32_rng->bus_clock) 54945da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 55029893549SGatien Chevallier 55129893549SGatien Chevallier return res; 55229893549SGatien Chevallier } 55329893549SGatien Chevallier DECLARE_KEEP_PAGER(stm32_rng_pm); 55429893549SGatien Chevallier 555ea8ba295SGatien Chevallier static TEE_Result stm32_rng_parse_fdt(const void *fdt, int node) 556f3c22059SEtienne Carriere { 557d7a1a7d2SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 558ea8ba295SGatien Chevallier struct dt_node_info dt_rng = { }; 559f3c22059SEtienne Carriere 560f354a5d8SGatien Chevallier fdt_fill_device_info(fdt, &dt_rng, node); 561ea8ba295SGatien Chevallier if (dt_rng.reg == DT_INFO_INVALID_REG) 562ea8ba295SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS; 563f3c22059SEtienne Carriere 564ea8ba295SGatien Chevallier stm32_rng->base.pa = dt_rng.reg; 565ea8ba295SGatien Chevallier stm32_rng->base.va = io_pa_or_va_secure(&stm32_rng->base, 566ea8ba295SGatien Chevallier dt_rng.reg_size); 567ea8ba295SGatien Chevallier assert(stm32_rng->base.va); 568f3c22059SEtienne Carriere 569ea8ba295SGatien Chevallier res = rstctrl_dt_get_by_index(fdt, node, 0, &stm32_rng->rstctrl); 570ea8ba295SGatien Chevallier if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND) 571ea8ba295SGatien Chevallier return res; 57268c4a16bSEtienne Carriere 57345da6509SGatien Chevallier if (stm32_rng->ddata->nb_clock > 1) { 57445da6509SGatien Chevallier res = clk_dt_get_by_name(fdt, node, "rng_clk", 57545da6509SGatien Chevallier &stm32_rng->clock); 57645da6509SGatien Chevallier if (res) 57745da6509SGatien Chevallier return res; 57845da6509SGatien Chevallier 57945da6509SGatien Chevallier res = clk_dt_get_by_name(fdt, node, "rng_hclk", 58045da6509SGatien Chevallier &stm32_rng->bus_clock); 58145da6509SGatien Chevallier if (res) 58245da6509SGatien Chevallier return res; 58345da6509SGatien Chevallier } else { 584d7a1a7d2SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &stm32_rng->clock); 585d7a1a7d2SEtienne Carriere if (res) 586d7a1a7d2SEtienne Carriere return res; 58745da6509SGatien Chevallier } 588d7a1a7d2SEtienne Carriere 5893c752300SGatien Chevallier if (fdt_getprop(fdt, node, "clock-error-detect", NULL)) 5903c752300SGatien Chevallier stm32_rng->clock_error = true; 5913c752300SGatien Chevallier 592ea8ba295SGatien Chevallier /* Release device if not used at runtime or for pm transitions */ 593ea8ba295SGatien Chevallier stm32_rng->release_post_boot = IS_ENABLED(CFG_WITH_SOFTWARE_PRNG) && 594ea8ba295SGatien Chevallier !IS_ENABLED(CFG_PM); 595f3c22059SEtienne Carriere 5965959d83fSGatien Chevallier stm32_rng->rng_config = stm32_rng->ddata->cr; 5975959d83fSGatien Chevallier if (stm32_rng->rng_config & ~RNG_CR_ENTROPY_SRC_MASK) 5985959d83fSGatien Chevallier panic("Incorrect entropy source configuration"); 5995959d83fSGatien Chevallier stm32_rng->health_test_conf = stm32_rng->ddata->htcr; 6005959d83fSGatien Chevallier stm32_rng->noise_ctrl_conf = stm32_rng->ddata->nscr; 6015959d83fSGatien Chevallier if (stm32_rng->noise_ctrl_conf & ~RNG_NSCR_MASK) 6025959d83fSGatien Chevallier panic("Incorrect noise source control configuration"); 6035959d83fSGatien Chevallier 604f3c22059SEtienne Carriere return TEE_SUCCESS; 605f3c22059SEtienne Carriere } 606f3c22059SEtienne Carriere 607ea8ba295SGatien Chevallier static TEE_Result stm32_rng_probe(const void *fdt, int offs, 608f9508605SGatien Chevallier const void *compat_data) 609ea8ba295SGatien Chevallier { 610ea8ba295SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 611ea8ba295SGatien Chevallier 612ea8ba295SGatien Chevallier /* Expect a single RNG instance */ 613ea8ba295SGatien Chevallier assert(!stm32_rng); 614ea8ba295SGatien Chevallier 615ea8ba295SGatien Chevallier stm32_rng = calloc(1, sizeof(*stm32_rng)); 616ea8ba295SGatien Chevallier if (!stm32_rng) 617ea8ba295SGatien Chevallier panic(); 618ea8ba295SGatien Chevallier 6195959d83fSGatien Chevallier stm32_rng->ddata = compat_data; 6205959d83fSGatien Chevallier assert(stm32_rng->ddata); 6215959d83fSGatien Chevallier 622ea8ba295SGatien Chevallier res = stm32_rng_parse_fdt(fdt, offs); 623ea8ba295SGatien Chevallier if (res) 624ea8ba295SGatien Chevallier goto err; 625ea8ba295SGatien Chevallier 626ea8ba295SGatien Chevallier res = clk_enable(stm32_rng->clock); 627ea8ba295SGatien Chevallier if (res) 628ea8ba295SGatien Chevallier goto err; 629ea8ba295SGatien Chevallier 63045da6509SGatien Chevallier if (stm32_rng->bus_clock) { 63145da6509SGatien Chevallier res = clk_enable(stm32_rng->bus_clock); 63245da6509SGatien Chevallier if (res) { 63345da6509SGatien Chevallier clk_disable(stm32_rng->clock); 63445da6509SGatien Chevallier goto err; 63545da6509SGatien Chevallier } 63645da6509SGatien Chevallier } 63745da6509SGatien Chevallier 638ea8ba295SGatien Chevallier if (stm32_rng->rstctrl && 639ea8ba295SGatien Chevallier rstctrl_assert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) { 640ea8ba295SGatien Chevallier res = TEE_ERROR_GENERIC; 641ea8ba295SGatien Chevallier goto err_clk; 642ea8ba295SGatien Chevallier } 643ea8ba295SGatien Chevallier 644ea8ba295SGatien Chevallier if (stm32_rng->rstctrl && 645ea8ba295SGatien Chevallier rstctrl_deassert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) { 646ea8ba295SGatien Chevallier res = TEE_ERROR_GENERIC; 647ea8ba295SGatien Chevallier goto err_clk; 648ea8ba295SGatien Chevallier } 649ea8ba295SGatien Chevallier 650f63f11bdSGatien Chevallier res = init_rng(); 651f63f11bdSGatien Chevallier if (res) 652f63f11bdSGatien Chevallier goto err_clk; 653f63f11bdSGatien Chevallier 654ea8ba295SGatien Chevallier clk_disable(stm32_rng->clock); 65545da6509SGatien Chevallier if (stm32_rng->bus_clock) 65645da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 657ea8ba295SGatien Chevallier 658ea8ba295SGatien Chevallier if (stm32_rng->release_post_boot) 659ea8ba295SGatien Chevallier stm32mp_register_non_secure_periph_iomem(stm32_rng->base.pa); 660ea8ba295SGatien Chevallier else 661ea8ba295SGatien Chevallier stm32mp_register_secure_periph_iomem(stm32_rng->base.pa); 662ea8ba295SGatien Chevallier 6635959d83fSGatien Chevallier /* Power management implementation expects both or none are set */ 6645959d83fSGatien Chevallier assert(stm32_rng->ddata->has_power_optim == 6655959d83fSGatien Chevallier stm32_rng->ddata->has_cond_reset); 6665959d83fSGatien Chevallier 66729893549SGatien Chevallier register_pm_core_service_cb(stm32_rng_pm, &stm32_rng, "rng-service"); 66829893549SGatien Chevallier 669ea8ba295SGatien Chevallier return TEE_SUCCESS; 670ea8ba295SGatien Chevallier 671ea8ba295SGatien Chevallier err_clk: 672ea8ba295SGatien Chevallier clk_disable(stm32_rng->clock); 67345da6509SGatien Chevallier if (stm32_rng->bus_clock) 67445da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 675ea8ba295SGatien Chevallier err: 676ea8ba295SGatien Chevallier free(stm32_rng); 677ea8ba295SGatien Chevallier stm32_rng = NULL; 678ea8ba295SGatien Chevallier 679ea8ba295SGatien Chevallier return res; 680ea8ba295SGatien Chevallier } 681ea8ba295SGatien Chevallier 682091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp13_data[] = { 68345da6509SGatien Chevallier { 684*aa12f203SGatien Chevallier .max_noise_clk_freq = U(48000000), 68545da6509SGatien Chevallier .nb_clock = 1, 68645da6509SGatien Chevallier .has_cond_reset = true, 6875959d83fSGatien Chevallier .has_power_optim = true, 6885959d83fSGatien Chevallier .cr = 0x00F00D00, 6895959d83fSGatien Chevallier .nscr = 0x2B5BB, 6905959d83fSGatien Chevallier .htcr = 0x969D, 69145da6509SGatien Chevallier }, 692091ef005SGatien Chevallier }; 693091ef005SGatien Chevallier 694091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp15_data[] = { 69545da6509SGatien Chevallier { 696*aa12f203SGatien Chevallier .max_noise_clk_freq = U(48000000), 69745da6509SGatien Chevallier .nb_clock = 1, 69845da6509SGatien Chevallier .has_cond_reset = false, 6995959d83fSGatien Chevallier .has_power_optim = false, 70045da6509SGatien Chevallier }, 701091ef005SGatien Chevallier }; 702091ef005SGatien Chevallier DECLARE_KEEP_PAGER(mp15_data); 703091ef005SGatien Chevallier 70445da6509SGatien Chevallier static const struct stm32_rng_driver_data mp25_data[] = { 70545da6509SGatien Chevallier { 706*aa12f203SGatien Chevallier .max_noise_clk_freq = U(48000000), 70745da6509SGatien Chevallier .nb_clock = 2, 70845da6509SGatien Chevallier .has_cond_reset = true, 7095959d83fSGatien Chevallier .has_power_optim = true, 7105959d83fSGatien Chevallier .cr = 0x00F00D00, 7115959d83fSGatien Chevallier .nscr = 0x2B5BB, 7125959d83fSGatien Chevallier .htcr = 0x969D, 71345da6509SGatien Chevallier }, 71445da6509SGatien Chevallier }; 71545da6509SGatien Chevallier 716ea8ba295SGatien Chevallier static const struct dt_device_match rng_match_table[] = { 717091ef005SGatien Chevallier { .compatible = "st,stm32-rng", .compat_data = &mp15_data }, 718091ef005SGatien Chevallier { .compatible = "st,stm32mp13-rng", .compat_data = &mp13_data }, 71945da6509SGatien Chevallier { .compatible = "st,stm32mp25-rng", .compat_data = &mp25_data }, 720ea8ba295SGatien Chevallier { } 721ea8ba295SGatien Chevallier }; 722ea8ba295SGatien Chevallier 723ea8ba295SGatien Chevallier DEFINE_DT_DRIVER(stm32_rng_dt_driver) = { 724ea8ba295SGatien Chevallier .name = "stm32_rng", 725ea8ba295SGatien Chevallier .match_table = rng_match_table, 726ea8ba295SGatien Chevallier .probe = stm32_rng_probe, 727ea8ba295SGatien Chevallier }; 728d8682c4cSEtienne Carriere 729d8682c4cSEtienne Carriere static TEE_Result stm32_rng_release(void) 730d8682c4cSEtienne Carriere { 731d8682c4cSEtienne Carriere if (stm32_rng && stm32_rng->release_post_boot) { 732d8682c4cSEtienne Carriere DMSG("Release RNG driver"); 733d8682c4cSEtienne Carriere free(stm32_rng); 734d8682c4cSEtienne Carriere stm32_rng = NULL; 735d8682c4cSEtienne Carriere } 736d8682c4cSEtienne Carriere 737d8682c4cSEtienne Carriere return TEE_SUCCESS; 738d8682c4cSEtienne Carriere } 739d8682c4cSEtienne Carriere 740d8682c4cSEtienne Carriere release_init_resource(stm32_rng_release); 741