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) 32b82b7e73SGatien Chevallier #define RNG_VERR U(0x3F4) 33f3c22059SEtienne Carriere 34f3c22059SEtienne Carriere #define RNG_CR_RNGEN BIT(2) 35f3c22059SEtienne Carriere #define RNG_CR_IE BIT(3) 36f3c22059SEtienne Carriere #define RNG_CR_CED BIT(5) 375959d83fSGatien Chevallier #define RNG_CR_CONFIG1 GENMASK_32(11, 8) 385959d83fSGatien Chevallier #define RNG_CR_NISTC BIT(12) 395959d83fSGatien Chevallier #define RNG_CR_POWER_OPTIM BIT(13) 405959d83fSGatien Chevallier #define RNG_CR_CONFIG2 GENMASK_32(15, 13) 41091ef005SGatien Chevallier #define RNG_CR_CLKDIV GENMASK_32(19, 16) 42091ef005SGatien Chevallier #define RNG_CR_CLKDIV_SHIFT U(16) 435959d83fSGatien Chevallier #define RNG_CR_CONFIG3 GENMASK_32(25, 20) 44091ef005SGatien Chevallier #define RNG_CR_CONDRST BIT(30) 455959d83fSGatien Chevallier #define RNG_CR_ENTROPY_SRC_MASK (RNG_CR_CONFIG1 | RNG_CR_NISTC | \ 465959d83fSGatien Chevallier RNG_CR_CONFIG2 | RNG_CR_CONFIG3) 47f3c22059SEtienne Carriere 48f3c22059SEtienne Carriere #define RNG_SR_DRDY BIT(0) 49f3c22059SEtienne Carriere #define RNG_SR_CECS BIT(1) 50f3c22059SEtienne Carriere #define RNG_SR_SECS BIT(2) 51f3c22059SEtienne Carriere #define RNG_SR_CEIS BIT(5) 52f3c22059SEtienne Carriere #define RNG_SR_SEIS BIT(6) 53f3c22059SEtienne Carriere 545959d83fSGatien Chevallier #define RNG_NSCR_MASK GENMASK_32(17, 0) 555959d83fSGatien Chevallier 56b82b7e73SGatien Chevallier #define RNG_VERR_MINOR_MASK GENMASK_32(3, 0) 57b82b7e73SGatien Chevallier #define RNG_VERR_MAJOR_MASK GENMASK_32(7, 4) 58b82b7e73SGatien Chevallier #define RNG_VERR_MAJOR_SHIFT U(4) 59b82b7e73SGatien Chevallier 600817aa6fSGatien Chevallier #if TRACE_LEVEL > TRACE_DEBUG 610817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US U(100000) 620817aa6fSGatien Chevallier #else 630817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US U(10000) 640817aa6fSGatien Chevallier #endif 65ea8ba295SGatien Chevallier #define RNG_RESET_TIMEOUT_US U(1000) 66f3c22059SEtienne Carriere 670817aa6fSGatien Chevallier #define RNG_FIFO_BYTE_DEPTH U(16) 680817aa6fSGatien Chevallier 695959d83fSGatien Chevallier #define RNG_CONFIG_MASK (RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED | \ 705959d83fSGatien Chevallier RNG_CR_CLKDIV) 71091ef005SGatien Chevallier 72091ef005SGatien Chevallier struct stm32_rng_driver_data { 73aa12f203SGatien Chevallier unsigned long max_noise_clk_freq; 7445da6509SGatien Chevallier unsigned long nb_clock; 755959d83fSGatien Chevallier uint32_t cr; 765959d83fSGatien Chevallier uint32_t nscr; 775959d83fSGatien Chevallier uint32_t htcr; 785959d83fSGatien Chevallier bool has_power_optim; 79091ef005SGatien Chevallier bool has_cond_reset; 80091ef005SGatien Chevallier }; 81091ef005SGatien Chevallier 82f3c22059SEtienne Carriere struct stm32_rng_instance { 83f3c22059SEtienne Carriere struct io_pa_va base; 84d7a1a7d2SEtienne Carriere struct clk *clock; 8545da6509SGatien Chevallier struct clk *bus_clock; 86ea8ba295SGatien Chevallier struct rstctrl *rstctrl; 87091ef005SGatien Chevallier const struct stm32_rng_driver_data *ddata; 88f3c22059SEtienne Carriere unsigned int lock; 895959d83fSGatien Chevallier uint64_t error_to_ref; 905959d83fSGatien Chevallier uint32_t pm_cr; 915959d83fSGatien Chevallier uint32_t pm_health; 925959d83fSGatien Chevallier uint32_t pm_noise_ctrl; 935959d83fSGatien Chevallier uint32_t health_test_conf; 945959d83fSGatien Chevallier uint32_t noise_ctrl_conf; 955959d83fSGatien Chevallier uint32_t rng_config; 96d8682c4cSEtienne Carriere bool release_post_boot; 973c752300SGatien Chevallier bool clock_error; 98091ef005SGatien Chevallier bool error_conceal; 99f3c22059SEtienne Carriere }; 100f3c22059SEtienne Carriere 101ea8ba295SGatien Chevallier /* Expect at most a single RNG instance */ 102f3c22059SEtienne Carriere static struct stm32_rng_instance *stm32_rng; 103f3c22059SEtienne Carriere 104f63f11bdSGatien Chevallier static vaddr_t get_base(void) 105f63f11bdSGatien Chevallier { 106f63f11bdSGatien Chevallier assert(stm32_rng); 107f63f11bdSGatien Chevallier 108f63f11bdSGatien Chevallier return io_pa_or_va(&stm32_rng->base, 1); 109f63f11bdSGatien Chevallier } 110f63f11bdSGatien Chevallier 111f3c22059SEtienne Carriere /* 112091ef005SGatien Chevallier * Extracts from the STM32 RNG specification when RNG supports CONDRST. 113f3c22059SEtienne Carriere * 114f3c22059SEtienne Carriere * When a noise source (or seed) error occurs, the RNG stops generating 115f3c22059SEtienne Carriere * random numbers and sets to “1” both SEIS and SECS bits to indicate 116f3c22059SEtienne Carriere * that a seed error occurred. (...) 117091ef005SGatien Chevallier * 118091ef005SGatien Chevallier * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield 119091ef005SGatien Chevallier * description for details). This step is needed only if SECS is set. 120091ef005SGatien Chevallier * Indeed, when SEIS is set and SECS is cleared it means RNG performed 121091ef005SGatien Chevallier * the reset automatically (auto-reset). 122091ef005SGatien Chevallier * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST 123091ef005SGatien Chevallier * to be cleared in the RNG_CR register, then confirm that SEIS is 124091ef005SGatien Chevallier * cleared in the RNG_SR register. Otherwise just clear SEIS bit in 125091ef005SGatien Chevallier * the RNG_SR register. 126091ef005SGatien Chevallier * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be 127091ef005SGatien Chevallier * cleared by RNG. The random number generation is now back to normal. 128091ef005SGatien Chevallier */ 129091ef005SGatien Chevallier static void conceal_seed_error_cond_reset(void) 130091ef005SGatien Chevallier { 131091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 132091ef005SGatien Chevallier vaddr_t rng_base = get_base(); 133f3c22059SEtienne Carriere 134091ef005SGatien Chevallier if (!dev->error_conceal) { 135091ef005SGatien Chevallier uint32_t sr = io_read32(rng_base + RNG_SR); 136091ef005SGatien Chevallier 137091ef005SGatien Chevallier if (sr & RNG_SR_SECS) { 138091ef005SGatien Chevallier /* Conceal by resetting the subsystem (step 1.) */ 139091ef005SGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 140091ef005SGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 141091ef005SGatien Chevallier 142091ef005SGatien Chevallier /* Arm timeout for error_conceal sequence */ 143091ef005SGatien Chevallier dev->error_to_ref = 144091ef005SGatien Chevallier timeout_init_us(RNG_READY_TIMEOUT_US); 145091ef005SGatien Chevallier dev->error_conceal = true; 146091ef005SGatien Chevallier } else { 147091ef005SGatien Chevallier /* RNG auto-reset (step 2.) */ 148091ef005SGatien Chevallier io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS); 149091ef005SGatien Chevallier } 150091ef005SGatien Chevallier } else { 151091ef005SGatien Chevallier /* Measure time before possible reschedule */ 152091ef005SGatien Chevallier bool timed_out = timeout_elapsed(dev->error_to_ref); 153091ef005SGatien Chevallier 154091ef005SGatien Chevallier /* Wait CONDRST is cleared (step 2.) */ 155091ef005SGatien Chevallier if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) { 156091ef005SGatien Chevallier if (timed_out) 157091ef005SGatien Chevallier panic(); 158091ef005SGatien Chevallier 159091ef005SGatien Chevallier /* Wait subsystem reset cycle completes */ 160091ef005SGatien Chevallier return; 161091ef005SGatien Chevallier } 162091ef005SGatien Chevallier 163091ef005SGatien Chevallier /* Check SEIS is cleared (step 2.) */ 164091ef005SGatien Chevallier if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 165091ef005SGatien Chevallier panic(); 166091ef005SGatien Chevallier 167091ef005SGatien Chevallier /* Wait SECS is cleared (step 3.) */ 168091ef005SGatien Chevallier if (io_read32(rng_base + RNG_SR) & RNG_SR_SECS) { 169091ef005SGatien Chevallier if (timed_out) 170091ef005SGatien Chevallier panic(); 171091ef005SGatien Chevallier 172091ef005SGatien Chevallier /* Wait subsystem reset cycle completes */ 173091ef005SGatien Chevallier return; 174091ef005SGatien Chevallier } 175091ef005SGatien Chevallier 176091ef005SGatien Chevallier dev->error_conceal = false; 177091ef005SGatien Chevallier } 178091ef005SGatien Chevallier } 179091ef005SGatien Chevallier 180091ef005SGatien Chevallier /* 181091ef005SGatien Chevallier * Extracts from the STM32 RNG specification, when CONDRST is not supported 182091ef005SGatien Chevallier * 183091ef005SGatien Chevallier * When a noise source (or seed) error occurs, the RNG stops generating 184091ef005SGatien Chevallier * random numbers and sets to “1” both SEIS and SECS bits to indicate 185091ef005SGatien Chevallier * that a seed error occurred. (...) 186091ef005SGatien Chevallier * 187f3c22059SEtienne Carriere * The following sequence shall be used to fully recover from a seed 188f3c22059SEtienne Carriere * error after the RNG initialization: 189f3c22059SEtienne Carriere * 1. Clear the SEIS bit by writing it to “0”. 190f3c22059SEtienne Carriere * 2. Read out 12 words from the RNG_DR register, and discard each of 191f3c22059SEtienne Carriere * them in order to clean the pipeline. 192f3c22059SEtienne Carriere * 3. Confirm that SEIS is still cleared. Random number generation is 193f3c22059SEtienne Carriere * back to normal. 194f3c22059SEtienne Carriere */ 195091ef005SGatien Chevallier static void conceal_seed_error_sw_reset(void) 196f3c22059SEtienne Carriere { 1976a6b6168SGatien Chevallier vaddr_t rng_base = get_base(); 198f3c22059SEtienne Carriere size_t i = 0; 199f3c22059SEtienne Carriere 2006a6b6168SGatien Chevallier io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS); 201f3c22059SEtienne Carriere 202f3c22059SEtienne Carriere for (i = 12; i != 0; i--) 203f3c22059SEtienne Carriere (void)io_read32(rng_base + RNG_DR); 204f3c22059SEtienne Carriere 205f3c22059SEtienne Carriere if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 206f3c22059SEtienne Carriere panic("RNG noise"); 207f3c22059SEtienne Carriere } 208f3c22059SEtienne Carriere 209091ef005SGatien Chevallier static void conceal_seed_error(void) 210091ef005SGatien Chevallier { 211091ef005SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) 212091ef005SGatien Chevallier conceal_seed_error_cond_reset(); 213091ef005SGatien Chevallier else 214091ef005SGatien Chevallier conceal_seed_error_sw_reset(); 215091ef005SGatien Chevallier } 216091ef005SGatien Chevallier 217c99311c8SEtienne Carriere static TEE_Result read_available(vaddr_t rng_base, uint8_t *out, size_t *size) 218f3c22059SEtienne Carriere { 219091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 220c99311c8SEtienne Carriere uint8_t *buf = NULL; 221c99311c8SEtienne Carriere size_t req_size = 0; 222c99311c8SEtienne Carriere size_t len = 0; 223f3c22059SEtienne Carriere 224091ef005SGatien Chevallier if (dev->error_conceal || io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 2256a6b6168SGatien Chevallier conceal_seed_error(); 226f3c22059SEtienne Carriere 22723123473SEtienne Carriere if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) { 22823123473SEtienne Carriere FMSG("RNG not ready"); 229c99311c8SEtienne Carriere return TEE_ERROR_NO_DATA; 23023123473SEtienne Carriere } 231f3c22059SEtienne Carriere 23223123473SEtienne Carriere if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) { 23323123473SEtienne Carriere FMSG("RNG noise error"); 234c99311c8SEtienne Carriere return TEE_ERROR_NO_DATA; 23523123473SEtienne Carriere } 236c99311c8SEtienne Carriere 237c99311c8SEtienne Carriere buf = out; 238c99311c8SEtienne Carriere req_size = MIN(RNG_FIFO_BYTE_DEPTH, *size); 239c99311c8SEtienne Carriere len = req_size; 240f3c22059SEtienne Carriere 241f3c22059SEtienne Carriere /* RNG is ready: read up to 4 32bit words */ 242f3c22059SEtienne Carriere while (len) { 24323bdf063SEtienne Carriere uint32_t data32 = 0; 244f3c22059SEtienne Carriere size_t sz = MIN(len, sizeof(uint32_t)); 245f3c22059SEtienne Carriere 24623bdf063SEtienne Carriere if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) 24723bdf063SEtienne Carriere break; 24823bdf063SEtienne Carriere data32 = io_read32(rng_base + RNG_DR); 24923bdf063SEtienne Carriere 2503e64c635SGatien Chevallier /* Late seed error case: DR being 0 is an error status */ 2513e64c635SGatien Chevallier if (!data32) { 2523e64c635SGatien Chevallier conceal_seed_error(); 2533e64c635SGatien Chevallier return TEE_ERROR_NO_DATA; 2543e64c635SGatien Chevallier } 2553e64c635SGatien Chevallier 256f3c22059SEtienne Carriere memcpy(buf, &data32, sz); 257f3c22059SEtienne Carriere buf += sz; 258f3c22059SEtienne Carriere len -= sz; 259f3c22059SEtienne Carriere } 260c99311c8SEtienne Carriere 26123bdf063SEtienne Carriere *size = req_size - len; 262f3c22059SEtienne Carriere 263c99311c8SEtienne Carriere return TEE_SUCCESS; 264f3c22059SEtienne Carriere } 265f3c22059SEtienne Carriere 266091ef005SGatien Chevallier static uint32_t stm32_rng_clock_freq_restrain(void) 267091ef005SGatien Chevallier { 268091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 269091ef005SGatien Chevallier unsigned long clock_rate = 0; 270091ef005SGatien Chevallier uint32_t clock_div = 0; 271091ef005SGatien Chevallier 272091ef005SGatien Chevallier clock_rate = clk_get_rate(dev->clock); 273091ef005SGatien Chevallier 274091ef005SGatien Chevallier /* 275091ef005SGatien Chevallier * Get the exponent to apply on the CLKDIV field in RNG_CR register 276091ef005SGatien Chevallier * No need to handle the case when clock-div > 0xF as it is physically 277091ef005SGatien Chevallier * impossible 278091ef005SGatien Chevallier */ 279aa12f203SGatien Chevallier while ((clock_rate >> clock_div) > dev->ddata->max_noise_clk_freq) 280091ef005SGatien Chevallier clock_div++; 281091ef005SGatien Chevallier 282091ef005SGatien Chevallier DMSG("RNG clk rate : %lu", clk_get_rate(dev->clock) >> clock_div); 283091ef005SGatien Chevallier 284091ef005SGatien Chevallier return clock_div; 285091ef005SGatien Chevallier } 286091ef005SGatien Chevallier 287f63f11bdSGatien Chevallier static TEE_Result init_rng(void) 288f3c22059SEtienne Carriere { 289f63f11bdSGatien Chevallier vaddr_t rng_base = get_base(); 2903c752300SGatien Chevallier uint32_t cr_ced_mask = 0; 2915959d83fSGatien Chevallier uint32_t value = 0; 2923c752300SGatien Chevallier 2933c752300SGatien Chevallier if (!stm32_rng->clock_error) 2943c752300SGatien Chevallier cr_ced_mask = RNG_CR_CED; 295f3c22059SEtienne Carriere 296f63f11bdSGatien Chevallier /* Clean error indications */ 297f63f11bdSGatien Chevallier io_write32(rng_base + RNG_SR, 0); 298f3c22059SEtienne Carriere 299091ef005SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 300091ef005SGatien Chevallier uint32_t clock_div = stm32_rng_clock_freq_restrain(); 301091ef005SGatien Chevallier 3025959d83fSGatien Chevallier /* 3035959d83fSGatien Chevallier * Keep default RNG configuration if none was specified. 3045959d83fSGatien Chevallier * 0 is an invalid value as it disables all entropy sources. 3055959d83fSGatien Chevallier */ 3065959d83fSGatien Chevallier if (!stm32_rng->rng_config) 3075959d83fSGatien Chevallier stm32_rng->rng_config = io_read32(rng_base + RNG_CR) & 3085959d83fSGatien Chevallier RNG_CR_ENTROPY_SRC_MASK; 3095959d83fSGatien Chevallier 3105959d83fSGatien Chevallier /* 3115959d83fSGatien Chevallier * Configuration must be set in the same access that sets 3125959d83fSGatien Chevallier * RNG_CR_CONDRST bit. Otherwise, the configuration setting is 3135959d83fSGatien Chevallier * not taken into account. CONFIGLOCK bit is always cleared at 3145959d83fSGatien Chevallier * this stage. 3155959d83fSGatien Chevallier */ 3165959d83fSGatien Chevallier io_clrsetbits32(rng_base + RNG_CR, RNG_CONFIG_MASK, 3175959d83fSGatien Chevallier stm32_rng->rng_config | RNG_CR_CONDRST | 3185959d83fSGatien Chevallier cr_ced_mask | 3195959d83fSGatien Chevallier SHIFT_U32(clock_div, RNG_CR_CLKDIV_SHIFT)); 3205959d83fSGatien Chevallier 3215959d83fSGatien Chevallier /* 3225959d83fSGatien Chevallier * Write health test and noise source control configuration 3235959d83fSGatien Chevallier * according to current RNG entropy source configuration 3245959d83fSGatien Chevallier */ 3255959d83fSGatien Chevallier if (stm32_rng->noise_ctrl_conf) 3265959d83fSGatien Chevallier io_write32(rng_base + RNG_NSCR, 3275959d83fSGatien Chevallier stm32_rng->noise_ctrl_conf); 3285959d83fSGatien Chevallier 3295959d83fSGatien Chevallier if (stm32_rng->health_test_conf) 3305959d83fSGatien Chevallier io_write32(rng_base + RNG_HTCR, 3315959d83fSGatien Chevallier stm32_rng->health_test_conf); 332091ef005SGatien Chevallier 333091ef005SGatien Chevallier io_clrsetbits32(rng_base + RNG_CR, RNG_CR_CONDRST, 334091ef005SGatien Chevallier RNG_CR_RNGEN); 335eb5cf770SGatien Chevallier 3365959d83fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_CR, value, 3375959d83fSGatien Chevallier !(value & RNG_CR_CONDRST), 0, 3385959d83fSGatien Chevallier RNG_READY_TIMEOUT_US)) 339eb5cf770SGatien Chevallier panic(); 3405959d83fSGatien Chevallier 3415959d83fSGatien Chevallier DMSG("RNG control register %#"PRIx32, 3425959d83fSGatien Chevallier io_read32(rng_base + RNG_CR)); 3435959d83fSGatien Chevallier DMSG("RNG noise source control register %#"PRIx32, 3445959d83fSGatien Chevallier io_read32(rng_base + RNG_NSCR)); 3455959d83fSGatien Chevallier DMSG("RNG health test register %#"PRIx32, 3465959d83fSGatien Chevallier io_read32(rng_base + RNG_HTCR)); 347091ef005SGatien Chevallier } else { 3483c752300SGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_RNGEN | cr_ced_mask); 349091ef005SGatien Chevallier } 350f63f11bdSGatien Chevallier 3515959d83fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_SR, value, 3525959d83fSGatien Chevallier value & RNG_SR_DRDY, 0, 3535959d83fSGatien Chevallier RNG_READY_TIMEOUT_US)) 354f63f11bdSGatien Chevallier return TEE_ERROR_GENERIC; 355f63f11bdSGatien Chevallier 356f63f11bdSGatien Chevallier return TEE_SUCCESS; 357f3c22059SEtienne Carriere } 358f3c22059SEtienne Carriere 35998c36268SGatien Chevallier static TEE_Result stm32_rng_read(uint8_t *out, size_t size) 360f3c22059SEtienne Carriere { 361c99311c8SEtienne Carriere TEE_Result rc = TEE_ERROR_GENERIC; 362c99311c8SEtienne Carriere bool burst_timeout = false; 363c99311c8SEtienne Carriere uint64_t timeout_ref = 0; 364f3c22059SEtienne Carriere uint32_t exceptions = 0; 365f3c22059SEtienne Carriere uint8_t *out_ptr = out; 366c99311c8SEtienne Carriere vaddr_t rng_base = 0; 367f3c22059SEtienne Carriere size_t out_size = 0; 368f3c22059SEtienne Carriere 369f3c22059SEtienne Carriere if (!stm32_rng) { 370f3c22059SEtienne Carriere DMSG("No RNG"); 371f3c22059SEtienne Carriere return TEE_ERROR_NOT_SUPPORTED; 372f3c22059SEtienne Carriere } 373f3c22059SEtienne Carriere 374fb1681dfSGatien Chevallier rc = clk_enable(stm32_rng->clock); 375fb1681dfSGatien Chevallier if (rc) 376fb1681dfSGatien Chevallier return rc; 377fb1681dfSGatien Chevallier 37845da6509SGatien Chevallier if (stm32_rng->bus_clock) { 37945da6509SGatien Chevallier rc = clk_enable(stm32_rng->bus_clock); 38045da6509SGatien Chevallier if (rc) { 38145da6509SGatien Chevallier clk_disable(stm32_rng->clock); 38245da6509SGatien Chevallier return rc; 38345da6509SGatien Chevallier } 38445da6509SGatien Chevallier } 38545da6509SGatien Chevallier 386f63f11bdSGatien Chevallier rng_base = get_base(); 387c99311c8SEtienne Carriere 388c99311c8SEtienne Carriere /* Arm timeout */ 3890817aa6fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 390c99311c8SEtienne Carriere burst_timeout = false; 391f3c22059SEtienne Carriere 392f3c22059SEtienne Carriere while (out_size < size) { 393f3c22059SEtienne Carriere /* Read by chunks of the size the RNG FIFO depth */ 394f3c22059SEtienne Carriere size_t sz = size - out_size; 395f3c22059SEtienne Carriere 396f3c22059SEtienne Carriere exceptions = may_spin_lock(&stm32_rng->lock); 397f3c22059SEtienne Carriere 398c99311c8SEtienne Carriere rc = read_available(rng_base, out_ptr, &sz); 399c99311c8SEtienne Carriere 400c99311c8SEtienne Carriere /* Raise timeout only if we failed to get some samples */ 401c99311c8SEtienne Carriere assert(!rc || rc == TEE_ERROR_NO_DATA); 402c99311c8SEtienne Carriere if (rc) 403c99311c8SEtienne Carriere burst_timeout = timeout_elapsed(timeout_ref); 404f3c22059SEtienne Carriere 405f3c22059SEtienne Carriere may_spin_unlock(&stm32_rng->lock, exceptions); 406f3c22059SEtienne Carriere 407c99311c8SEtienne Carriere if (burst_timeout) { 408c99311c8SEtienne Carriere rc = TEE_ERROR_GENERIC; 409c99311c8SEtienne Carriere goto out; 410f3c22059SEtienne Carriere } 411f3c22059SEtienne Carriere 412c99311c8SEtienne Carriere if (!rc) { 413c99311c8SEtienne Carriere out_size += sz; 414c99311c8SEtienne Carriere out_ptr += sz; 415c99311c8SEtienne Carriere /* Re-arm timeout */ 4160817aa6fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 417c99311c8SEtienne Carriere burst_timeout = false; 418c99311c8SEtienne Carriere } 419c99311c8SEtienne Carriere } 420c99311c8SEtienne Carriere 421c99311c8SEtienne Carriere out: 422c99311c8SEtienne Carriere assert(!rc || rc == TEE_ERROR_GENERIC); 423f63f11bdSGatien Chevallier clk_disable(stm32_rng->clock); 42445da6509SGatien Chevallier if (stm32_rng->bus_clock) 42545da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 426f3c22059SEtienne Carriere 427f3c22059SEtienne Carriere return rc; 428f3c22059SEtienne Carriere } 429f3c22059SEtienne Carriere 430cd451498SEtienne Carriere #ifdef CFG_WITH_SOFTWARE_PRNG 431cd451498SEtienne Carriere /* Override weak plat_rng_init with platform handler to seed PRNG */ 432cd451498SEtienne Carriere void plat_rng_init(void) 433cd451498SEtienne Carriere { 434cd451498SEtienne Carriere uint8_t seed[RNG_FIFO_BYTE_DEPTH] = { }; 435cd451498SEtienne Carriere 436cd451498SEtienne Carriere if (stm32_rng_read(seed, sizeof(seed))) 437cd451498SEtienne Carriere panic(); 438cd451498SEtienne Carriere 439cd451498SEtienne Carriere if (crypto_rng_init(seed, sizeof(seed))) 440cd451498SEtienne Carriere panic(); 441cd451498SEtienne Carriere 442cd451498SEtienne Carriere DMSG("PRNG seeded with RNG"); 443cd451498SEtienne Carriere } 444cd451498SEtienne Carriere #else 445cb2478efSAndrew Davis TEE_Result hw_get_random_bytes(void *out, size_t size) 446097f329aSEtienne Carriere { 447097f329aSEtienne Carriere return stm32_rng_read(out, size); 448097f329aSEtienne Carriere } 44927f3087bSGatien Chevallier 45027f3087bSGatien Chevallier void plat_rng_init(void) 45127f3087bSGatien Chevallier { 45227f3087bSGatien Chevallier } 453097f329aSEtienne Carriere #endif 454097f329aSEtienne Carriere 4555959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_resume(void) 45629893549SGatien Chevallier { 45729893549SGatien Chevallier vaddr_t base = get_base(); 45829893549SGatien Chevallier 45929893549SGatien Chevallier /* Clean error indications */ 46029893549SGatien Chevallier io_write32(base + RNG_SR, 0); 46129893549SGatien Chevallier 46229893549SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 463eb5cf770SGatien Chevallier uint64_t timeout_ref = 0; 464eb5cf770SGatien Chevallier 46529893549SGatien Chevallier /* 466c2c5b4beSGatien Chevallier * Configuration must be set in the same access that sets 467c2c5b4beSGatien Chevallier * RNG_CR_CONDRST bit. Otherwise, the configuration setting is 468c2c5b4beSGatien Chevallier * not taken into account. CONFIGLOCK bit is always cleared in 469c2c5b4beSGatien Chevallier * this configuration. 47029893549SGatien Chevallier */ 4715959d83fSGatien Chevallier io_write32(base + RNG_CR, stm32_rng->pm_cr | RNG_CR_CONDRST); 4725959d83fSGatien Chevallier 4735959d83fSGatien Chevallier /* Restore health test and noise control configuration */ 4745959d83fSGatien Chevallier io_write32(base + RNG_NSCR, stm32_rng->pm_noise_ctrl); 4755959d83fSGatien Chevallier io_write32(base + RNG_HTCR, stm32_rng->pm_health); 47629893549SGatien Chevallier 47729893549SGatien Chevallier io_clrsetbits32(base + RNG_CR, RNG_CR_CONDRST, RNG_CR_RNGEN); 478eb5cf770SGatien Chevallier 479eb5cf770SGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 480eb5cf770SGatien Chevallier while (io_read32(base + RNG_CR) & RNG_CR_CONDRST) 481eb5cf770SGatien Chevallier if (timeout_elapsed(timeout_ref)) 482eb5cf770SGatien Chevallier break; 483eb5cf770SGatien Chevallier if (io_read32(base + RNG_CR) & RNG_CR_CONDRST) 484eb5cf770SGatien Chevallier panic(); 48529893549SGatien Chevallier } else { 4865959d83fSGatien Chevallier io_write32(base + RNG_CR, RNG_CR_RNGEN | stm32_rng->pm_cr); 4875959d83fSGatien Chevallier } 4885959d83fSGatien Chevallier 4895959d83fSGatien Chevallier return TEE_SUCCESS; 4905959d83fSGatien Chevallier } 4915959d83fSGatien Chevallier 4925959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_suspend(void) 4935959d83fSGatien Chevallier { 4945959d83fSGatien Chevallier vaddr_t rng_base = get_base(); 4955959d83fSGatien Chevallier 4965959d83fSGatien Chevallier stm32_rng->pm_cr = io_read32(rng_base + RNG_CR); 4975959d83fSGatien Chevallier 4985959d83fSGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 4995959d83fSGatien Chevallier stm32_rng->pm_health = io_read32(rng_base + RNG_HTCR); 5005959d83fSGatien Chevallier stm32_rng->pm_noise_ctrl = io_read32(rng_base + RNG_NSCR); 5015959d83fSGatien Chevallier } 5025959d83fSGatien Chevallier 5035959d83fSGatien Chevallier if (stm32_rng->ddata->has_power_optim) { 5045959d83fSGatien Chevallier uint64_t timeout_ref = 0; 5055959d83fSGatien Chevallier 5065959d83fSGatien Chevallier /* 5075959d83fSGatien Chevallier * As per reference manual, it is recommended to set 5085959d83fSGatien Chevallier * RNG_CONFIG2[bit0] when RNG power consumption is critical. 5095959d83fSGatien Chevallier */ 5105959d83fSGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_POWER_OPTIM | 5115959d83fSGatien Chevallier RNG_CR_CONDRST); 5125959d83fSGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 5135959d83fSGatien Chevallier 5145959d83fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 5155959d83fSGatien Chevallier while (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) 5165959d83fSGatien Chevallier if (timeout_elapsed(timeout_ref)) 5175959d83fSGatien Chevallier break; 5185959d83fSGatien Chevallier if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) 5195959d83fSGatien Chevallier panic(); 5205959d83fSGatien Chevallier } else { 5215959d83fSGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_RNGEN); 52229893549SGatien Chevallier } 52329893549SGatien Chevallier 52429893549SGatien Chevallier return TEE_SUCCESS; 52529893549SGatien Chevallier } 52629893549SGatien Chevallier 52729893549SGatien Chevallier static TEE_Result 52829893549SGatien Chevallier stm32_rng_pm(enum pm_op op, unsigned int pm_hint __unused, 52929893549SGatien Chevallier const struct pm_callback_handle *pm_handle __unused) 53029893549SGatien Chevallier { 53129893549SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 53229893549SGatien Chevallier 53329893549SGatien Chevallier assert(stm32_rng && (op == PM_OP_SUSPEND || op == PM_OP_RESUME)); 53429893549SGatien Chevallier 53529893549SGatien Chevallier res = clk_enable(stm32_rng->clock); 53629893549SGatien Chevallier if (res) 53729893549SGatien Chevallier return res; 53829893549SGatien Chevallier 53945da6509SGatien Chevallier if (stm32_rng->bus_clock) { 54045da6509SGatien Chevallier res = clk_enable(stm32_rng->bus_clock); 54145da6509SGatien Chevallier if (res) { 54245da6509SGatien Chevallier clk_disable(stm32_rng->clock); 54345da6509SGatien Chevallier return res; 54445da6509SGatien Chevallier } 54545da6509SGatien Chevallier } 54645da6509SGatien Chevallier 5475959d83fSGatien Chevallier if (op == PM_OP_RESUME) 5485959d83fSGatien Chevallier res = stm32_rng_pm_resume(); 54929893549SGatien Chevallier else 5505959d83fSGatien Chevallier res = stm32_rng_pm_suspend(); 55129893549SGatien Chevallier 55229893549SGatien Chevallier clk_disable(stm32_rng->clock); 55345da6509SGatien Chevallier if (stm32_rng->bus_clock) 55445da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 55529893549SGatien Chevallier 55629893549SGatien Chevallier return res; 55729893549SGatien Chevallier } 55829893549SGatien Chevallier DECLARE_KEEP_PAGER(stm32_rng_pm); 55929893549SGatien Chevallier 560ea8ba295SGatien Chevallier static TEE_Result stm32_rng_parse_fdt(const void *fdt, int node) 561f3c22059SEtienne Carriere { 562d7a1a7d2SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 563ea8ba295SGatien Chevallier struct dt_node_info dt_rng = { }; 564f3c22059SEtienne Carriere 565f354a5d8SGatien Chevallier fdt_fill_device_info(fdt, &dt_rng, node); 566ea8ba295SGatien Chevallier if (dt_rng.reg == DT_INFO_INVALID_REG) 567ea8ba295SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS; 568f3c22059SEtienne Carriere 569ea8ba295SGatien Chevallier stm32_rng->base.pa = dt_rng.reg; 570ea8ba295SGatien Chevallier stm32_rng->base.va = io_pa_or_va_secure(&stm32_rng->base, 571ea8ba295SGatien Chevallier dt_rng.reg_size); 572ea8ba295SGatien Chevallier assert(stm32_rng->base.va); 573f3c22059SEtienne Carriere 574ea8ba295SGatien Chevallier res = rstctrl_dt_get_by_index(fdt, node, 0, &stm32_rng->rstctrl); 575ea8ba295SGatien Chevallier if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND) 576ea8ba295SGatien Chevallier return res; 57768c4a16bSEtienne Carriere 57845da6509SGatien Chevallier if (stm32_rng->ddata->nb_clock > 1) { 57945da6509SGatien Chevallier res = clk_dt_get_by_name(fdt, node, "rng_clk", 58045da6509SGatien Chevallier &stm32_rng->clock); 58145da6509SGatien Chevallier if (res) 58245da6509SGatien Chevallier return res; 58345da6509SGatien Chevallier 58445da6509SGatien Chevallier res = clk_dt_get_by_name(fdt, node, "rng_hclk", 58545da6509SGatien Chevallier &stm32_rng->bus_clock); 58645da6509SGatien Chevallier if (res) 58745da6509SGatien Chevallier return res; 58845da6509SGatien Chevallier } else { 589d7a1a7d2SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &stm32_rng->clock); 590d7a1a7d2SEtienne Carriere if (res) 591d7a1a7d2SEtienne Carriere return res; 59245da6509SGatien Chevallier } 593d7a1a7d2SEtienne Carriere 5943c752300SGatien Chevallier if (fdt_getprop(fdt, node, "clock-error-detect", NULL)) 5953c752300SGatien Chevallier stm32_rng->clock_error = true; 5963c752300SGatien Chevallier 597*cc707b85SEtienne Carriere /* Release device if not used after initialization */ 598*cc707b85SEtienne Carriere stm32_rng->release_post_boot = IS_ENABLED(CFG_WITH_SOFTWARE_PRNG); 599f3c22059SEtienne Carriere 6005959d83fSGatien Chevallier stm32_rng->rng_config = stm32_rng->ddata->cr; 6015959d83fSGatien Chevallier if (stm32_rng->rng_config & ~RNG_CR_ENTROPY_SRC_MASK) 6025959d83fSGatien Chevallier panic("Incorrect entropy source configuration"); 6035959d83fSGatien Chevallier stm32_rng->health_test_conf = stm32_rng->ddata->htcr; 6045959d83fSGatien Chevallier stm32_rng->noise_ctrl_conf = stm32_rng->ddata->nscr; 6055959d83fSGatien Chevallier if (stm32_rng->noise_ctrl_conf & ~RNG_NSCR_MASK) 6065959d83fSGatien Chevallier panic("Incorrect noise source control configuration"); 6075959d83fSGatien Chevallier 608f3c22059SEtienne Carriere return TEE_SUCCESS; 609f3c22059SEtienne Carriere } 610f3c22059SEtienne Carriere 611ea8ba295SGatien Chevallier static TEE_Result stm32_rng_probe(const void *fdt, int offs, 612f9508605SGatien Chevallier const void *compat_data) 613ea8ba295SGatien Chevallier { 614ea8ba295SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 615b82b7e73SGatien Chevallier unsigned int __maybe_unused version = 0; 616ea8ba295SGatien Chevallier 617ea8ba295SGatien Chevallier /* Expect a single RNG instance */ 618ea8ba295SGatien Chevallier assert(!stm32_rng); 619ea8ba295SGatien Chevallier 620ea8ba295SGatien Chevallier stm32_rng = calloc(1, sizeof(*stm32_rng)); 621ea8ba295SGatien Chevallier if (!stm32_rng) 622ea8ba295SGatien Chevallier panic(); 623ea8ba295SGatien Chevallier 6245959d83fSGatien Chevallier stm32_rng->ddata = compat_data; 6255959d83fSGatien Chevallier assert(stm32_rng->ddata); 6265959d83fSGatien Chevallier 627ea8ba295SGatien Chevallier res = stm32_rng_parse_fdt(fdt, offs); 628ea8ba295SGatien Chevallier if (res) 629ea8ba295SGatien Chevallier goto err; 630ea8ba295SGatien Chevallier 631ea8ba295SGatien Chevallier res = clk_enable(stm32_rng->clock); 632ea8ba295SGatien Chevallier if (res) 633ea8ba295SGatien Chevallier goto err; 634ea8ba295SGatien Chevallier 63545da6509SGatien Chevallier if (stm32_rng->bus_clock) { 63645da6509SGatien Chevallier res = clk_enable(stm32_rng->bus_clock); 63745da6509SGatien Chevallier if (res) { 63845da6509SGatien Chevallier clk_disable(stm32_rng->clock); 63945da6509SGatien Chevallier goto err; 64045da6509SGatien Chevallier } 64145da6509SGatien Chevallier } 64245da6509SGatien Chevallier 643b82b7e73SGatien Chevallier version = io_read32(get_base() + RNG_VERR); 644b82b7e73SGatien Chevallier DMSG("RNG version Major %u, Minor %u", 645b82b7e73SGatien Chevallier (version & RNG_VERR_MAJOR_MASK) >> RNG_VERR_MAJOR_SHIFT, 646b82b7e73SGatien Chevallier version & RNG_VERR_MINOR_MASK); 647b82b7e73SGatien Chevallier 648ea8ba295SGatien Chevallier if (stm32_rng->rstctrl && 649ea8ba295SGatien Chevallier rstctrl_assert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) { 650ea8ba295SGatien Chevallier res = TEE_ERROR_GENERIC; 651ea8ba295SGatien Chevallier goto err_clk; 652ea8ba295SGatien Chevallier } 653ea8ba295SGatien Chevallier 654ea8ba295SGatien Chevallier if (stm32_rng->rstctrl && 655ea8ba295SGatien Chevallier rstctrl_deassert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) { 656ea8ba295SGatien Chevallier res = TEE_ERROR_GENERIC; 657ea8ba295SGatien Chevallier goto err_clk; 658ea8ba295SGatien Chevallier } 659ea8ba295SGatien Chevallier 660f63f11bdSGatien Chevallier res = init_rng(); 661f63f11bdSGatien Chevallier if (res) 662f63f11bdSGatien Chevallier goto err_clk; 663f63f11bdSGatien Chevallier 664ea8ba295SGatien Chevallier clk_disable(stm32_rng->clock); 66545da6509SGatien Chevallier if (stm32_rng->bus_clock) 66645da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 667ea8ba295SGatien Chevallier 668ea8ba295SGatien Chevallier if (stm32_rng->release_post_boot) 669ea8ba295SGatien Chevallier stm32mp_register_non_secure_periph_iomem(stm32_rng->base.pa); 670ea8ba295SGatien Chevallier else 671ea8ba295SGatien Chevallier stm32mp_register_secure_periph_iomem(stm32_rng->base.pa); 672ea8ba295SGatien Chevallier 6735959d83fSGatien Chevallier /* Power management implementation expects both or none are set */ 6745959d83fSGatien Chevallier assert(stm32_rng->ddata->has_power_optim == 6755959d83fSGatien Chevallier stm32_rng->ddata->has_cond_reset); 6765959d83fSGatien Chevallier 67729893549SGatien Chevallier register_pm_core_service_cb(stm32_rng_pm, &stm32_rng, "rng-service"); 67829893549SGatien Chevallier 679ea8ba295SGatien Chevallier return TEE_SUCCESS; 680ea8ba295SGatien Chevallier 681ea8ba295SGatien Chevallier err_clk: 682ea8ba295SGatien Chevallier clk_disable(stm32_rng->clock); 68345da6509SGatien Chevallier if (stm32_rng->bus_clock) 68445da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 685ea8ba295SGatien Chevallier err: 686ea8ba295SGatien Chevallier free(stm32_rng); 687ea8ba295SGatien Chevallier stm32_rng = NULL; 688ea8ba295SGatien Chevallier 689ea8ba295SGatien Chevallier return res; 690ea8ba295SGatien Chevallier } 691ea8ba295SGatien Chevallier 692091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp13_data[] = { 69345da6509SGatien Chevallier { 694aa12f203SGatien Chevallier .max_noise_clk_freq = U(48000000), 69545da6509SGatien Chevallier .nb_clock = 1, 69645da6509SGatien Chevallier .has_cond_reset = true, 6975959d83fSGatien Chevallier .has_power_optim = true, 6985959d83fSGatien Chevallier .cr = 0x00F00D00, 6995959d83fSGatien Chevallier .nscr = 0x2B5BB, 7005959d83fSGatien Chevallier .htcr = 0x969D, 70145da6509SGatien Chevallier }, 702091ef005SGatien Chevallier }; 703091ef005SGatien Chevallier 704091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp15_data[] = { 70545da6509SGatien Chevallier { 706aa12f203SGatien Chevallier .max_noise_clk_freq = U(48000000), 70745da6509SGatien Chevallier .nb_clock = 1, 70845da6509SGatien Chevallier .has_cond_reset = false, 7095959d83fSGatien Chevallier .has_power_optim = false, 71045da6509SGatien Chevallier }, 711091ef005SGatien Chevallier }; 712091ef005SGatien Chevallier DECLARE_KEEP_PAGER(mp15_data); 713091ef005SGatien Chevallier 71445da6509SGatien Chevallier static const struct stm32_rng_driver_data mp25_data[] = { 71545da6509SGatien Chevallier { 716aa12f203SGatien Chevallier .max_noise_clk_freq = U(48000000), 71745da6509SGatien Chevallier .nb_clock = 2, 71845da6509SGatien Chevallier .has_cond_reset = true, 7195959d83fSGatien Chevallier .has_power_optim = true, 7205959d83fSGatien Chevallier .cr = 0x00F00D00, 7215959d83fSGatien Chevallier .nscr = 0x2B5BB, 7225959d83fSGatien Chevallier .htcr = 0x969D, 72345da6509SGatien Chevallier }, 72445da6509SGatien Chevallier }; 72545da6509SGatien Chevallier 726ea8ba295SGatien Chevallier static const struct dt_device_match rng_match_table[] = { 727091ef005SGatien Chevallier { .compatible = "st,stm32-rng", .compat_data = &mp15_data }, 728091ef005SGatien Chevallier { .compatible = "st,stm32mp13-rng", .compat_data = &mp13_data }, 72945da6509SGatien Chevallier { .compatible = "st,stm32mp25-rng", .compat_data = &mp25_data }, 730ea8ba295SGatien Chevallier { } 731ea8ba295SGatien Chevallier }; 732ea8ba295SGatien Chevallier 733ea8ba295SGatien Chevallier DEFINE_DT_DRIVER(stm32_rng_dt_driver) = { 734ea8ba295SGatien Chevallier .name = "stm32_rng", 735ea8ba295SGatien Chevallier .match_table = rng_match_table, 736ea8ba295SGatien Chevallier .probe = stm32_rng_probe, 737ea8ba295SGatien Chevallier }; 738d8682c4cSEtienne Carriere 739d8682c4cSEtienne Carriere static TEE_Result stm32_rng_release(void) 740d8682c4cSEtienne Carriere { 741d8682c4cSEtienne Carriere if (stm32_rng && stm32_rng->release_post_boot) { 742d8682c4cSEtienne Carriere DMSG("Release RNG driver"); 743d8682c4cSEtienne Carriere free(stm32_rng); 744d8682c4cSEtienne Carriere stm32_rng = NULL; 745d8682c4cSEtienne Carriere } 746d8682c4cSEtienne Carriere 747d8682c4cSEtienne Carriere return TEE_SUCCESS; 748d8682c4cSEtienne Carriere } 749d8682c4cSEtienne Carriere 750d8682c4cSEtienne Carriere release_init_resource(stm32_rng_release); 751