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 431*f2fe4f00SThomas Bourgoin /* Override weak plat_rng_init with platform handler to attempt to seed PRNG */ 432cd451498SEtienne Carriere void plat_rng_init(void) 433cd451498SEtienne Carriere { 434cd451498SEtienne Carriere uint8_t seed[RNG_FIFO_BYTE_DEPTH] = { }; 435cd451498SEtienne Carriere 436*f2fe4f00SThomas Bourgoin if (!stm32_rng) { 437*f2fe4f00SThomas Bourgoin __plat_rng_init(); 438*f2fe4f00SThomas Bourgoin DMSG("PRNG seeded without RNG"); 439*f2fe4f00SThomas Bourgoin return; 440*f2fe4f00SThomas Bourgoin } 441*f2fe4f00SThomas Bourgoin 442cd451498SEtienne Carriere if (stm32_rng_read(seed, sizeof(seed))) 443cd451498SEtienne Carriere panic(); 444cd451498SEtienne Carriere 445cd451498SEtienne Carriere if (crypto_rng_init(seed, sizeof(seed))) 446cd451498SEtienne Carriere panic(); 447cd451498SEtienne Carriere 448cd451498SEtienne Carriere DMSG("PRNG seeded with RNG"); 449cd451498SEtienne Carriere } 450cd451498SEtienne Carriere #else 451cb2478efSAndrew Davis TEE_Result hw_get_random_bytes(void *out, size_t size) 452097f329aSEtienne Carriere { 453097f329aSEtienne Carriere return stm32_rng_read(out, size); 454097f329aSEtienne Carriere } 45527f3087bSGatien Chevallier 45627f3087bSGatien Chevallier void plat_rng_init(void) 45727f3087bSGatien Chevallier { 45827f3087bSGatien Chevallier } 459097f329aSEtienne Carriere #endif 460097f329aSEtienne Carriere 4615959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_resume(void) 46229893549SGatien Chevallier { 46329893549SGatien Chevallier vaddr_t base = get_base(); 46429893549SGatien Chevallier 46529893549SGatien Chevallier /* Clean error indications */ 46629893549SGatien Chevallier io_write32(base + RNG_SR, 0); 46729893549SGatien Chevallier 46829893549SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 469eb5cf770SGatien Chevallier uint64_t timeout_ref = 0; 470eb5cf770SGatien Chevallier 47129893549SGatien Chevallier /* 472c2c5b4beSGatien Chevallier * Configuration must be set in the same access that sets 473c2c5b4beSGatien Chevallier * RNG_CR_CONDRST bit. Otherwise, the configuration setting is 474c2c5b4beSGatien Chevallier * not taken into account. CONFIGLOCK bit is always cleared in 475c2c5b4beSGatien Chevallier * this configuration. 47629893549SGatien Chevallier */ 4775959d83fSGatien Chevallier io_write32(base + RNG_CR, stm32_rng->pm_cr | RNG_CR_CONDRST); 4785959d83fSGatien Chevallier 4795959d83fSGatien Chevallier /* Restore health test and noise control configuration */ 4805959d83fSGatien Chevallier io_write32(base + RNG_NSCR, stm32_rng->pm_noise_ctrl); 4815959d83fSGatien Chevallier io_write32(base + RNG_HTCR, stm32_rng->pm_health); 48229893549SGatien Chevallier 48329893549SGatien Chevallier io_clrsetbits32(base + RNG_CR, RNG_CR_CONDRST, RNG_CR_RNGEN); 484eb5cf770SGatien Chevallier 485eb5cf770SGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 486eb5cf770SGatien Chevallier while (io_read32(base + RNG_CR) & RNG_CR_CONDRST) 487eb5cf770SGatien Chevallier if (timeout_elapsed(timeout_ref)) 488eb5cf770SGatien Chevallier break; 489eb5cf770SGatien Chevallier if (io_read32(base + RNG_CR) & RNG_CR_CONDRST) 490eb5cf770SGatien Chevallier panic(); 49129893549SGatien Chevallier } else { 4925959d83fSGatien Chevallier io_write32(base + RNG_CR, RNG_CR_RNGEN | stm32_rng->pm_cr); 4935959d83fSGatien Chevallier } 4945959d83fSGatien Chevallier 4955959d83fSGatien Chevallier return TEE_SUCCESS; 4965959d83fSGatien Chevallier } 4975959d83fSGatien Chevallier 4985959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_suspend(void) 4995959d83fSGatien Chevallier { 5005959d83fSGatien Chevallier vaddr_t rng_base = get_base(); 5015959d83fSGatien Chevallier 5025959d83fSGatien Chevallier stm32_rng->pm_cr = io_read32(rng_base + RNG_CR); 5035959d83fSGatien Chevallier 5045959d83fSGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 5055959d83fSGatien Chevallier stm32_rng->pm_health = io_read32(rng_base + RNG_HTCR); 5065959d83fSGatien Chevallier stm32_rng->pm_noise_ctrl = io_read32(rng_base + RNG_NSCR); 5075959d83fSGatien Chevallier } 5085959d83fSGatien Chevallier 5095959d83fSGatien Chevallier if (stm32_rng->ddata->has_power_optim) { 5105959d83fSGatien Chevallier uint64_t timeout_ref = 0; 5115959d83fSGatien Chevallier 5125959d83fSGatien Chevallier /* 5135959d83fSGatien Chevallier * As per reference manual, it is recommended to set 5145959d83fSGatien Chevallier * RNG_CONFIG2[bit0] when RNG power consumption is critical. 5155959d83fSGatien Chevallier */ 5165959d83fSGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_POWER_OPTIM | 5175959d83fSGatien Chevallier RNG_CR_CONDRST); 5185959d83fSGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 5195959d83fSGatien Chevallier 5205959d83fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 5215959d83fSGatien Chevallier while (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) 5225959d83fSGatien Chevallier if (timeout_elapsed(timeout_ref)) 5235959d83fSGatien Chevallier break; 5245959d83fSGatien Chevallier if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) 5255959d83fSGatien Chevallier panic(); 5265959d83fSGatien Chevallier } else { 5275959d83fSGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_RNGEN); 52829893549SGatien Chevallier } 52929893549SGatien Chevallier 53029893549SGatien Chevallier return TEE_SUCCESS; 53129893549SGatien Chevallier } 53229893549SGatien Chevallier 53329893549SGatien Chevallier static TEE_Result 53429893549SGatien Chevallier stm32_rng_pm(enum pm_op op, unsigned int pm_hint __unused, 53529893549SGatien Chevallier const struct pm_callback_handle *pm_handle __unused) 53629893549SGatien Chevallier { 53729893549SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 53829893549SGatien Chevallier 53929893549SGatien Chevallier assert(stm32_rng && (op == PM_OP_SUSPEND || op == PM_OP_RESUME)); 54029893549SGatien Chevallier 54129893549SGatien Chevallier res = clk_enable(stm32_rng->clock); 54229893549SGatien Chevallier if (res) 54329893549SGatien Chevallier return res; 54429893549SGatien Chevallier 54545da6509SGatien Chevallier if (stm32_rng->bus_clock) { 54645da6509SGatien Chevallier res = clk_enable(stm32_rng->bus_clock); 54745da6509SGatien Chevallier if (res) { 54845da6509SGatien Chevallier clk_disable(stm32_rng->clock); 54945da6509SGatien Chevallier return res; 55045da6509SGatien Chevallier } 55145da6509SGatien Chevallier } 55245da6509SGatien Chevallier 5535959d83fSGatien Chevallier if (op == PM_OP_RESUME) 5545959d83fSGatien Chevallier res = stm32_rng_pm_resume(); 55529893549SGatien Chevallier else 5565959d83fSGatien Chevallier res = stm32_rng_pm_suspend(); 55729893549SGatien Chevallier 55829893549SGatien Chevallier clk_disable(stm32_rng->clock); 55945da6509SGatien Chevallier if (stm32_rng->bus_clock) 56045da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 56129893549SGatien Chevallier 56229893549SGatien Chevallier return res; 56329893549SGatien Chevallier } 56429893549SGatien Chevallier DECLARE_KEEP_PAGER(stm32_rng_pm); 56529893549SGatien Chevallier 566ea8ba295SGatien Chevallier static TEE_Result stm32_rng_parse_fdt(const void *fdt, int node) 567f3c22059SEtienne Carriere { 568d7a1a7d2SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 569ea8ba295SGatien Chevallier struct dt_node_info dt_rng = { }; 570f3c22059SEtienne Carriere 571f354a5d8SGatien Chevallier fdt_fill_device_info(fdt, &dt_rng, node); 572ea8ba295SGatien Chevallier if (dt_rng.reg == DT_INFO_INVALID_REG) 573ea8ba295SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS; 574f3c22059SEtienne Carriere 575ea8ba295SGatien Chevallier stm32_rng->base.pa = dt_rng.reg; 576ea8ba295SGatien Chevallier stm32_rng->base.va = io_pa_or_va_secure(&stm32_rng->base, 577ea8ba295SGatien Chevallier dt_rng.reg_size); 578ea8ba295SGatien Chevallier assert(stm32_rng->base.va); 579f3c22059SEtienne Carriere 580ea8ba295SGatien Chevallier res = rstctrl_dt_get_by_index(fdt, node, 0, &stm32_rng->rstctrl); 581ea8ba295SGatien Chevallier if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND) 582ea8ba295SGatien Chevallier return res; 58368c4a16bSEtienne Carriere 58445da6509SGatien Chevallier if (stm32_rng->ddata->nb_clock > 1) { 58545da6509SGatien Chevallier res = clk_dt_get_by_name(fdt, node, "rng_clk", 58645da6509SGatien Chevallier &stm32_rng->clock); 58745da6509SGatien Chevallier if (res) 58845da6509SGatien Chevallier return res; 58945da6509SGatien Chevallier 59045da6509SGatien Chevallier res = clk_dt_get_by_name(fdt, node, "rng_hclk", 59145da6509SGatien Chevallier &stm32_rng->bus_clock); 59245da6509SGatien Chevallier if (res) 59345da6509SGatien Chevallier return res; 59445da6509SGatien Chevallier } else { 595d7a1a7d2SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &stm32_rng->clock); 596d7a1a7d2SEtienne Carriere if (res) 597d7a1a7d2SEtienne Carriere return res; 59845da6509SGatien Chevallier } 599d7a1a7d2SEtienne Carriere 6003c752300SGatien Chevallier if (fdt_getprop(fdt, node, "clock-error-detect", NULL)) 6013c752300SGatien Chevallier stm32_rng->clock_error = true; 6023c752300SGatien Chevallier 603cc707b85SEtienne Carriere /* Release device if not used after initialization */ 604cc707b85SEtienne Carriere stm32_rng->release_post_boot = IS_ENABLED(CFG_WITH_SOFTWARE_PRNG); 605f3c22059SEtienne Carriere 6065959d83fSGatien Chevallier stm32_rng->rng_config = stm32_rng->ddata->cr; 6075959d83fSGatien Chevallier if (stm32_rng->rng_config & ~RNG_CR_ENTROPY_SRC_MASK) 6085959d83fSGatien Chevallier panic("Incorrect entropy source configuration"); 6095959d83fSGatien Chevallier stm32_rng->health_test_conf = stm32_rng->ddata->htcr; 6105959d83fSGatien Chevallier stm32_rng->noise_ctrl_conf = stm32_rng->ddata->nscr; 6115959d83fSGatien Chevallier if (stm32_rng->noise_ctrl_conf & ~RNG_NSCR_MASK) 6125959d83fSGatien Chevallier panic("Incorrect noise source control configuration"); 6135959d83fSGatien Chevallier 614f3c22059SEtienne Carriere return TEE_SUCCESS; 615f3c22059SEtienne Carriere } 616f3c22059SEtienne Carriere 617ea8ba295SGatien Chevallier static TEE_Result stm32_rng_probe(const void *fdt, int offs, 618f9508605SGatien Chevallier const void *compat_data) 619ea8ba295SGatien Chevallier { 620ea8ba295SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 621b82b7e73SGatien Chevallier unsigned int __maybe_unused version = 0; 622ea8ba295SGatien Chevallier 623ea8ba295SGatien Chevallier /* Expect a single RNG instance */ 624ea8ba295SGatien Chevallier assert(!stm32_rng); 625ea8ba295SGatien Chevallier 626ea8ba295SGatien Chevallier stm32_rng = calloc(1, sizeof(*stm32_rng)); 627ea8ba295SGatien Chevallier if (!stm32_rng) 628ea8ba295SGatien Chevallier panic(); 629ea8ba295SGatien Chevallier 6305959d83fSGatien Chevallier stm32_rng->ddata = compat_data; 6315959d83fSGatien Chevallier assert(stm32_rng->ddata); 6325959d83fSGatien Chevallier 633ea8ba295SGatien Chevallier res = stm32_rng_parse_fdt(fdt, offs); 634ea8ba295SGatien Chevallier if (res) 635ea8ba295SGatien Chevallier goto err; 636ea8ba295SGatien Chevallier 637ea8ba295SGatien Chevallier res = clk_enable(stm32_rng->clock); 638ea8ba295SGatien Chevallier if (res) 639ea8ba295SGatien Chevallier goto err; 640ea8ba295SGatien Chevallier 64145da6509SGatien Chevallier if (stm32_rng->bus_clock) { 64245da6509SGatien Chevallier res = clk_enable(stm32_rng->bus_clock); 64345da6509SGatien Chevallier if (res) { 64445da6509SGatien Chevallier clk_disable(stm32_rng->clock); 64545da6509SGatien Chevallier goto err; 64645da6509SGatien Chevallier } 64745da6509SGatien Chevallier } 64845da6509SGatien Chevallier 649b82b7e73SGatien Chevallier version = io_read32(get_base() + RNG_VERR); 650b82b7e73SGatien Chevallier DMSG("RNG version Major %u, Minor %u", 651b82b7e73SGatien Chevallier (version & RNG_VERR_MAJOR_MASK) >> RNG_VERR_MAJOR_SHIFT, 652b82b7e73SGatien Chevallier version & RNG_VERR_MINOR_MASK); 653b82b7e73SGatien Chevallier 654ea8ba295SGatien Chevallier if (stm32_rng->rstctrl && 655ea8ba295SGatien Chevallier rstctrl_assert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) { 656ea8ba295SGatien Chevallier res = TEE_ERROR_GENERIC; 657ea8ba295SGatien Chevallier goto err_clk; 658ea8ba295SGatien Chevallier } 659ea8ba295SGatien Chevallier 660ea8ba295SGatien Chevallier if (stm32_rng->rstctrl && 661ea8ba295SGatien Chevallier rstctrl_deassert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) { 662ea8ba295SGatien Chevallier res = TEE_ERROR_GENERIC; 663ea8ba295SGatien Chevallier goto err_clk; 664ea8ba295SGatien Chevallier } 665ea8ba295SGatien Chevallier 666f63f11bdSGatien Chevallier res = init_rng(); 667f63f11bdSGatien Chevallier if (res) 668f63f11bdSGatien Chevallier goto err_clk; 669f63f11bdSGatien Chevallier 670ea8ba295SGatien Chevallier clk_disable(stm32_rng->clock); 67145da6509SGatien Chevallier if (stm32_rng->bus_clock) 67245da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 673ea8ba295SGatien Chevallier 674ea8ba295SGatien Chevallier if (stm32_rng->release_post_boot) 675ea8ba295SGatien Chevallier stm32mp_register_non_secure_periph_iomem(stm32_rng->base.pa); 676ea8ba295SGatien Chevallier else 677ea8ba295SGatien Chevallier stm32mp_register_secure_periph_iomem(stm32_rng->base.pa); 678ea8ba295SGatien Chevallier 6795959d83fSGatien Chevallier /* Power management implementation expects both or none are set */ 6805959d83fSGatien Chevallier assert(stm32_rng->ddata->has_power_optim == 6815959d83fSGatien Chevallier stm32_rng->ddata->has_cond_reset); 6825959d83fSGatien Chevallier 68329893549SGatien Chevallier register_pm_core_service_cb(stm32_rng_pm, &stm32_rng, "rng-service"); 68429893549SGatien Chevallier 685ea8ba295SGatien Chevallier return TEE_SUCCESS; 686ea8ba295SGatien Chevallier 687ea8ba295SGatien Chevallier err_clk: 688ea8ba295SGatien Chevallier clk_disable(stm32_rng->clock); 68945da6509SGatien Chevallier if (stm32_rng->bus_clock) 69045da6509SGatien Chevallier clk_disable(stm32_rng->bus_clock); 691ea8ba295SGatien Chevallier err: 692ea8ba295SGatien Chevallier free(stm32_rng); 693ea8ba295SGatien Chevallier stm32_rng = NULL; 694ea8ba295SGatien Chevallier 695ea8ba295SGatien Chevallier return res; 696ea8ba295SGatien Chevallier } 697ea8ba295SGatien Chevallier 698091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp13_data[] = { 69945da6509SGatien Chevallier { 700aa12f203SGatien Chevallier .max_noise_clk_freq = U(48000000), 70145da6509SGatien Chevallier .nb_clock = 1, 70245da6509SGatien Chevallier .has_cond_reset = true, 7035959d83fSGatien Chevallier .has_power_optim = true, 7045959d83fSGatien Chevallier .cr = 0x00F00D00, 7055959d83fSGatien Chevallier .nscr = 0x2B5BB, 7065959d83fSGatien Chevallier .htcr = 0x969D, 70745da6509SGatien Chevallier }, 708091ef005SGatien Chevallier }; 709091ef005SGatien Chevallier 710091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp15_data[] = { 71145da6509SGatien Chevallier { 712aa12f203SGatien Chevallier .max_noise_clk_freq = U(48000000), 71345da6509SGatien Chevallier .nb_clock = 1, 71445da6509SGatien Chevallier .has_cond_reset = false, 7155959d83fSGatien Chevallier .has_power_optim = false, 71645da6509SGatien Chevallier }, 717091ef005SGatien Chevallier }; 718091ef005SGatien Chevallier DECLARE_KEEP_PAGER(mp15_data); 719091ef005SGatien Chevallier 72045da6509SGatien Chevallier static const struct stm32_rng_driver_data mp25_data[] = { 72145da6509SGatien Chevallier { 722aa12f203SGatien Chevallier .max_noise_clk_freq = U(48000000), 72345da6509SGatien Chevallier .nb_clock = 2, 72445da6509SGatien Chevallier .has_cond_reset = true, 7255959d83fSGatien Chevallier .has_power_optim = true, 7265959d83fSGatien Chevallier .cr = 0x00F00D00, 7275959d83fSGatien Chevallier .nscr = 0x2B5BB, 7285959d83fSGatien Chevallier .htcr = 0x969D, 72945da6509SGatien Chevallier }, 73045da6509SGatien Chevallier }; 73145da6509SGatien Chevallier 732ea8ba295SGatien Chevallier static const struct dt_device_match rng_match_table[] = { 733091ef005SGatien Chevallier { .compatible = "st,stm32-rng", .compat_data = &mp15_data }, 734091ef005SGatien Chevallier { .compatible = "st,stm32mp13-rng", .compat_data = &mp13_data }, 73545da6509SGatien Chevallier { .compatible = "st,stm32mp25-rng", .compat_data = &mp25_data }, 736ea8ba295SGatien Chevallier { } 737ea8ba295SGatien Chevallier }; 738ea8ba295SGatien Chevallier 739ea8ba295SGatien Chevallier DEFINE_DT_DRIVER(stm32_rng_dt_driver) = { 740ea8ba295SGatien Chevallier .name = "stm32_rng", 741ea8ba295SGatien Chevallier .match_table = rng_match_table, 742ea8ba295SGatien Chevallier .probe = stm32_rng_probe, 743ea8ba295SGatien Chevallier }; 744d8682c4cSEtienne Carriere 745d8682c4cSEtienne Carriere static TEE_Result stm32_rng_release(void) 746d8682c4cSEtienne Carriere { 747d8682c4cSEtienne Carriere if (stm32_rng && stm32_rng->release_post_boot) { 748d8682c4cSEtienne Carriere DMSG("Release RNG driver"); 749d8682c4cSEtienne Carriere free(stm32_rng); 750d8682c4cSEtienne Carriere stm32_rng = NULL; 751d8682c4cSEtienne Carriere } 752d8682c4cSEtienne Carriere 753d8682c4cSEtienne Carriere return TEE_SUCCESS; 754d8682c4cSEtienne Carriere } 755d8682c4cSEtienne Carriere 756d8682c4cSEtienne Carriere release_init_resource(stm32_rng_release); 757