1f3c22059SEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause 2f3c22059SEtienne Carriere /* 3*d773ec0bSGatien Chevallier * Copyright (c) 2018-2024, 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> 10*d773ec0bSGatien Chevallier #include <drivers/stm32_etzpc.h> 11*d773ec0bSGatien Chevallier #if defined(CFG_STM32MP15) 12*d773ec0bSGatien Chevallier #include <drivers/stm32mp1_etzpc.h> 13*d773ec0bSGatien Chevallier #endif /* defined(CFG_STM32MP15) */ 14f3c22059SEtienne Carriere #include <io.h> 15f3c22059SEtienne Carriere #include <kernel/delay.h> 16a2fc83d1SJerome Forissier #include <kernel/dt.h> 17ea8ba295SGatien Chevallier #include <kernel/dt_driver.h> 18*d773ec0bSGatien Chevallier #include <kernel/boot.h> 19f3c22059SEtienne Carriere #include <kernel/panic.h> 2029893549SGatien Chevallier #include <kernel/pm.h> 2165b5ada4SMarouene Boubakri #include <kernel/thread.h> 22a2fc83d1SJerome Forissier #include <libfdt.h> 23f3c22059SEtienne Carriere #include <mm/core_memprot.h> 24097f329aSEtienne Carriere #include <rng_support.h> 25f3c22059SEtienne Carriere #include <stdbool.h> 26f3c22059SEtienne Carriere #include <stm32_util.h> 27f3c22059SEtienne Carriere #include <string.h> 28cd451498SEtienne Carriere #include <tee/tee_cryp_utl.h> 29f3c22059SEtienne Carriere 300817aa6fSGatien Chevallier #define RNG_CR U(0x00) 310817aa6fSGatien Chevallier #define RNG_SR U(0x04) 320817aa6fSGatien Chevallier #define RNG_DR U(0x08) 335959d83fSGatien Chevallier #define RNG_NSCR U(0x0C) 345959d83fSGatien Chevallier #define RNG_HTCR U(0x10) 35b82b7e73SGatien Chevallier #define RNG_VERR U(0x3F4) 36f3c22059SEtienne Carriere 37f3c22059SEtienne Carriere #define RNG_CR_RNGEN BIT(2) 38f3c22059SEtienne Carriere #define RNG_CR_IE BIT(3) 39f3c22059SEtienne Carriere #define RNG_CR_CED BIT(5) 405959d83fSGatien Chevallier #define RNG_CR_CONFIG1 GENMASK_32(11, 8) 415959d83fSGatien Chevallier #define RNG_CR_NISTC BIT(12) 425959d83fSGatien Chevallier #define RNG_CR_POWER_OPTIM BIT(13) 435959d83fSGatien Chevallier #define RNG_CR_CONFIG2 GENMASK_32(15, 13) 44091ef005SGatien Chevallier #define RNG_CR_CLKDIV GENMASK_32(19, 16) 45091ef005SGatien Chevallier #define RNG_CR_CLKDIV_SHIFT U(16) 465959d83fSGatien Chevallier #define RNG_CR_CONFIG3 GENMASK_32(25, 20) 47091ef005SGatien Chevallier #define RNG_CR_CONDRST BIT(30) 485959d83fSGatien Chevallier #define RNG_CR_ENTROPY_SRC_MASK (RNG_CR_CONFIG1 | RNG_CR_NISTC | \ 495959d83fSGatien Chevallier RNG_CR_CONFIG2 | RNG_CR_CONFIG3) 50f3c22059SEtienne Carriere 51f3c22059SEtienne Carriere #define RNG_SR_DRDY BIT(0) 52f3c22059SEtienne Carriere #define RNG_SR_CECS BIT(1) 53f3c22059SEtienne Carriere #define RNG_SR_SECS BIT(2) 54f3c22059SEtienne Carriere #define RNG_SR_CEIS BIT(5) 55f3c22059SEtienne Carriere #define RNG_SR_SEIS BIT(6) 56f3c22059SEtienne Carriere 575959d83fSGatien Chevallier #define RNG_NSCR_MASK GENMASK_32(17, 0) 585959d83fSGatien Chevallier 59b82b7e73SGatien Chevallier #define RNG_VERR_MINOR_MASK GENMASK_32(3, 0) 60b82b7e73SGatien Chevallier #define RNG_VERR_MAJOR_MASK GENMASK_32(7, 4) 61b82b7e73SGatien Chevallier #define RNG_VERR_MAJOR_SHIFT U(4) 62b82b7e73SGatien Chevallier 630817aa6fSGatien Chevallier #if TRACE_LEVEL > TRACE_DEBUG 640817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US U(100000) 650817aa6fSGatien Chevallier #else 660817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US U(10000) 670817aa6fSGatien Chevallier #endif 68ea8ba295SGatien Chevallier #define RNG_RESET_TIMEOUT_US U(1000) 69f3c22059SEtienne Carriere 700817aa6fSGatien Chevallier #define RNG_FIFO_BYTE_DEPTH U(16) 710817aa6fSGatien Chevallier 725959d83fSGatien Chevallier #define RNG_CONFIG_MASK (RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED | \ 735959d83fSGatien Chevallier RNG_CR_CLKDIV) 74091ef005SGatien Chevallier 75091ef005SGatien Chevallier struct stm32_rng_driver_data { 76aa12f203SGatien Chevallier unsigned long max_noise_clk_freq; 7745da6509SGatien Chevallier unsigned long nb_clock; 785959d83fSGatien Chevallier uint32_t cr; 795959d83fSGatien Chevallier uint32_t nscr; 805959d83fSGatien Chevallier uint32_t htcr; 815959d83fSGatien Chevallier bool has_power_optim; 82091ef005SGatien Chevallier bool has_cond_reset; 83091ef005SGatien Chevallier }; 84091ef005SGatien Chevallier 85f3c22059SEtienne Carriere struct stm32_rng_instance { 86f3c22059SEtienne Carriere struct io_pa_va base; 87d7a1a7d2SEtienne Carriere struct clk *clock; 8845da6509SGatien Chevallier struct clk *bus_clock; 89ea8ba295SGatien Chevallier struct rstctrl *rstctrl; 90091ef005SGatien Chevallier const struct stm32_rng_driver_data *ddata; 91f3c22059SEtienne Carriere unsigned int lock; 925959d83fSGatien Chevallier uint64_t error_to_ref; 935959d83fSGatien Chevallier uint32_t pm_cr; 945959d83fSGatien Chevallier uint32_t pm_health; 955959d83fSGatien Chevallier uint32_t pm_noise_ctrl; 965959d83fSGatien Chevallier uint32_t health_test_conf; 975959d83fSGatien Chevallier uint32_t noise_ctrl_conf; 985959d83fSGatien Chevallier uint32_t rng_config; 993c752300SGatien Chevallier bool clock_error; 100091ef005SGatien Chevallier bool error_conceal; 101f3c22059SEtienne Carriere }; 102f3c22059SEtienne Carriere 103ea8ba295SGatien Chevallier /* Expect at most a single RNG instance */ 104f3c22059SEtienne Carriere static struct stm32_rng_instance *stm32_rng; 105f3c22059SEtienne Carriere 106f63f11bdSGatien Chevallier static vaddr_t get_base(void) 107f63f11bdSGatien Chevallier { 108f63f11bdSGatien Chevallier assert(stm32_rng); 109f63f11bdSGatien Chevallier 110f63f11bdSGatien Chevallier return io_pa_or_va(&stm32_rng->base, 1); 111f63f11bdSGatien Chevallier } 112f63f11bdSGatien Chevallier 113f3c22059SEtienne Carriere /* 114091ef005SGatien Chevallier * Extracts from the STM32 RNG specification when RNG supports CONDRST. 115f3c22059SEtienne Carriere * 116f3c22059SEtienne Carriere * When a noise source (or seed) error occurs, the RNG stops generating 117f3c22059SEtienne Carriere * random numbers and sets to “1” both SEIS and SECS bits to indicate 118f3c22059SEtienne Carriere * that a seed error occurred. (...) 119091ef005SGatien Chevallier * 120091ef005SGatien Chevallier * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield 121091ef005SGatien Chevallier * description for details). This step is needed only if SECS is set. 122091ef005SGatien Chevallier * Indeed, when SEIS is set and SECS is cleared it means RNG performed 123091ef005SGatien Chevallier * the reset automatically (auto-reset). 124091ef005SGatien Chevallier * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST 125091ef005SGatien Chevallier * to be cleared in the RNG_CR register, then confirm that SEIS is 126091ef005SGatien Chevallier * cleared in the RNG_SR register. Otherwise just clear SEIS bit in 127091ef005SGatien Chevallier * the RNG_SR register. 128091ef005SGatien Chevallier * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be 129091ef005SGatien Chevallier * cleared by RNG. The random number generation is now back to normal. 130091ef005SGatien Chevallier */ 131091ef005SGatien Chevallier static void conceal_seed_error_cond_reset(void) 132091ef005SGatien Chevallier { 133091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 134091ef005SGatien Chevallier vaddr_t rng_base = get_base(); 135f3c22059SEtienne Carriere 136091ef005SGatien Chevallier if (!dev->error_conceal) { 137091ef005SGatien Chevallier uint32_t sr = io_read32(rng_base + RNG_SR); 138091ef005SGatien Chevallier 139091ef005SGatien Chevallier if (sr & RNG_SR_SECS) { 140091ef005SGatien Chevallier /* Conceal by resetting the subsystem (step 1.) */ 141091ef005SGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 142091ef005SGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 143091ef005SGatien Chevallier 144091ef005SGatien Chevallier /* Arm timeout for error_conceal sequence */ 145091ef005SGatien Chevallier dev->error_to_ref = 146091ef005SGatien Chevallier timeout_init_us(RNG_READY_TIMEOUT_US); 147091ef005SGatien Chevallier dev->error_conceal = true; 148091ef005SGatien Chevallier } else { 149091ef005SGatien Chevallier /* RNG auto-reset (step 2.) */ 150091ef005SGatien Chevallier io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS); 151091ef005SGatien Chevallier } 152091ef005SGatien Chevallier } else { 153091ef005SGatien Chevallier /* Measure time before possible reschedule */ 154091ef005SGatien Chevallier bool timed_out = timeout_elapsed(dev->error_to_ref); 155091ef005SGatien Chevallier 156091ef005SGatien Chevallier /* Wait CONDRST is cleared (step 2.) */ 157091ef005SGatien Chevallier if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) { 158091ef005SGatien Chevallier if (timed_out) 159091ef005SGatien Chevallier panic(); 160091ef005SGatien Chevallier 161091ef005SGatien Chevallier /* Wait subsystem reset cycle completes */ 162091ef005SGatien Chevallier return; 163091ef005SGatien Chevallier } 164091ef005SGatien Chevallier 165091ef005SGatien Chevallier /* Check SEIS is cleared (step 2.) */ 166091ef005SGatien Chevallier if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 167091ef005SGatien Chevallier panic(); 168091ef005SGatien Chevallier 169091ef005SGatien Chevallier /* Wait SECS is cleared (step 3.) */ 170091ef005SGatien Chevallier if (io_read32(rng_base + RNG_SR) & RNG_SR_SECS) { 171091ef005SGatien Chevallier if (timed_out) 172091ef005SGatien Chevallier panic(); 173091ef005SGatien Chevallier 174091ef005SGatien Chevallier /* Wait subsystem reset cycle completes */ 175091ef005SGatien Chevallier return; 176091ef005SGatien Chevallier } 177091ef005SGatien Chevallier 178091ef005SGatien Chevallier dev->error_conceal = false; 179091ef005SGatien Chevallier } 180091ef005SGatien Chevallier } 181091ef005SGatien Chevallier 182091ef005SGatien Chevallier /* 183091ef005SGatien Chevallier * Extracts from the STM32 RNG specification, when CONDRST is not supported 184091ef005SGatien Chevallier * 185091ef005SGatien Chevallier * When a noise source (or seed) error occurs, the RNG stops generating 186091ef005SGatien Chevallier * random numbers and sets to “1” both SEIS and SECS bits to indicate 187091ef005SGatien Chevallier * that a seed error occurred. (...) 188091ef005SGatien Chevallier * 189f3c22059SEtienne Carriere * The following sequence shall be used to fully recover from a seed 190f3c22059SEtienne Carriere * error after the RNG initialization: 191f3c22059SEtienne Carriere * 1. Clear the SEIS bit by writing it to “0”. 192f3c22059SEtienne Carriere * 2. Read out 12 words from the RNG_DR register, and discard each of 193f3c22059SEtienne Carriere * them in order to clean the pipeline. 194f3c22059SEtienne Carriere * 3. Confirm that SEIS is still cleared. Random number generation is 195f3c22059SEtienne Carriere * back to normal. 196f3c22059SEtienne Carriere */ 197091ef005SGatien Chevallier static void conceal_seed_error_sw_reset(void) 198f3c22059SEtienne Carriere { 1996a6b6168SGatien Chevallier vaddr_t rng_base = get_base(); 200f3c22059SEtienne Carriere size_t i = 0; 201f3c22059SEtienne Carriere 2026a6b6168SGatien Chevallier io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS); 203f3c22059SEtienne Carriere 204f3c22059SEtienne Carriere for (i = 12; i != 0; i--) 205f3c22059SEtienne Carriere (void)io_read32(rng_base + RNG_DR); 206f3c22059SEtienne Carriere 207f3c22059SEtienne Carriere if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 208f3c22059SEtienne Carriere panic("RNG noise"); 209f3c22059SEtienne Carriere } 210f3c22059SEtienne Carriere 211091ef005SGatien Chevallier static void conceal_seed_error(void) 212091ef005SGatien Chevallier { 213091ef005SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) 214091ef005SGatien Chevallier conceal_seed_error_cond_reset(); 215091ef005SGatien Chevallier else 216091ef005SGatien Chevallier conceal_seed_error_sw_reset(); 217091ef005SGatien Chevallier } 218091ef005SGatien Chevallier 219c99311c8SEtienne Carriere static TEE_Result read_available(vaddr_t rng_base, uint8_t *out, size_t *size) 220f3c22059SEtienne Carriere { 221091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 222c99311c8SEtienne Carriere uint8_t *buf = NULL; 223c99311c8SEtienne Carriere size_t req_size = 0; 224c99311c8SEtienne Carriere size_t len = 0; 225f3c22059SEtienne Carriere 226091ef005SGatien Chevallier if (dev->error_conceal || io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 2276a6b6168SGatien Chevallier conceal_seed_error(); 228f3c22059SEtienne Carriere 22923123473SEtienne Carriere if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) { 23023123473SEtienne Carriere FMSG("RNG not ready"); 231c99311c8SEtienne Carriere return TEE_ERROR_NO_DATA; 23223123473SEtienne Carriere } 233f3c22059SEtienne Carriere 23423123473SEtienne Carriere if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) { 23523123473SEtienne Carriere FMSG("RNG noise error"); 236c99311c8SEtienne Carriere return TEE_ERROR_NO_DATA; 23723123473SEtienne Carriere } 238c99311c8SEtienne Carriere 239c99311c8SEtienne Carriere buf = out; 240c99311c8SEtienne Carriere req_size = MIN(RNG_FIFO_BYTE_DEPTH, *size); 241c99311c8SEtienne Carriere len = req_size; 242f3c22059SEtienne Carriere 243f3c22059SEtienne Carriere /* RNG is ready: read up to 4 32bit words */ 244f3c22059SEtienne Carriere while (len) { 24523bdf063SEtienne Carriere uint32_t data32 = 0; 246f3c22059SEtienne Carriere size_t sz = MIN(len, sizeof(uint32_t)); 247f3c22059SEtienne Carriere 24823bdf063SEtienne Carriere if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) 24923bdf063SEtienne Carriere break; 25023bdf063SEtienne Carriere data32 = io_read32(rng_base + RNG_DR); 25123bdf063SEtienne Carriere 2523e64c635SGatien Chevallier /* Late seed error case: DR being 0 is an error status */ 2533e64c635SGatien Chevallier if (!data32) { 2543e64c635SGatien Chevallier conceal_seed_error(); 2553e64c635SGatien Chevallier return TEE_ERROR_NO_DATA; 2563e64c635SGatien Chevallier } 2573e64c635SGatien Chevallier 258f3c22059SEtienne Carriere memcpy(buf, &data32, sz); 259f3c22059SEtienne Carriere buf += sz; 260f3c22059SEtienne Carriere len -= sz; 261f3c22059SEtienne Carriere } 262c99311c8SEtienne Carriere 26323bdf063SEtienne Carriere *size = req_size - len; 264f3c22059SEtienne Carriere 265c99311c8SEtienne Carriere return TEE_SUCCESS; 266f3c22059SEtienne Carriere } 267f3c22059SEtienne Carriere 268091ef005SGatien Chevallier static uint32_t stm32_rng_clock_freq_restrain(void) 269091ef005SGatien Chevallier { 270091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 271091ef005SGatien Chevallier unsigned long clock_rate = 0; 272091ef005SGatien Chevallier uint32_t clock_div = 0; 273091ef005SGatien Chevallier 274091ef005SGatien Chevallier clock_rate = clk_get_rate(dev->clock); 275091ef005SGatien Chevallier 276091ef005SGatien Chevallier /* 277091ef005SGatien Chevallier * Get the exponent to apply on the CLKDIV field in RNG_CR register 278091ef005SGatien Chevallier * No need to handle the case when clock-div > 0xF as it is physically 279091ef005SGatien Chevallier * impossible 280091ef005SGatien Chevallier */ 281aa12f203SGatien Chevallier while ((clock_rate >> clock_div) > dev->ddata->max_noise_clk_freq) 282091ef005SGatien Chevallier clock_div++; 283091ef005SGatien Chevallier 284091ef005SGatien Chevallier DMSG("RNG clk rate : %lu", clk_get_rate(dev->clock) >> clock_div); 285091ef005SGatien Chevallier 286091ef005SGatien Chevallier return clock_div; 287091ef005SGatien Chevallier } 288091ef005SGatien Chevallier 289*d773ec0bSGatien Chevallier static TEE_Result enable_rng_clock(void) 290f3c22059SEtienne Carriere { 291*d773ec0bSGatien Chevallier TEE_Result res = clk_enable(stm32_rng->clock); 292*d773ec0bSGatien Chevallier 293*d773ec0bSGatien Chevallier if (!res && stm32_rng->bus_clock) { 294*d773ec0bSGatien Chevallier res = clk_enable(stm32_rng->bus_clock); 295*d773ec0bSGatien Chevallier if (res) 296*d773ec0bSGatien Chevallier clk_disable(stm32_rng->clock); 297*d773ec0bSGatien Chevallier } 298*d773ec0bSGatien Chevallier 299*d773ec0bSGatien Chevallier return res; 300*d773ec0bSGatien Chevallier } 301*d773ec0bSGatien Chevallier 302*d773ec0bSGatien Chevallier static void disable_rng_clock(void) 303*d773ec0bSGatien Chevallier { 304*d773ec0bSGatien Chevallier clk_disable(stm32_rng->clock); 305*d773ec0bSGatien Chevallier if (stm32_rng->bus_clock) 306*d773ec0bSGatien Chevallier clk_disable(stm32_rng->bus_clock); 307*d773ec0bSGatien Chevallier } 308*d773ec0bSGatien Chevallier 309*d773ec0bSGatien Chevallier static TEE_Result stm32_rng_init(void) 310*d773ec0bSGatien Chevallier { 311*d773ec0bSGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 312f63f11bdSGatien Chevallier vaddr_t rng_base = get_base(); 3133c752300SGatien Chevallier uint32_t cr_ced_mask = 0; 3145959d83fSGatien Chevallier uint32_t value = 0; 3153c752300SGatien Chevallier 316*d773ec0bSGatien Chevallier res = enable_rng_clock(); 317*d773ec0bSGatien Chevallier if (res) 318*d773ec0bSGatien Chevallier return res; 319*d773ec0bSGatien Chevallier 320*d773ec0bSGatien Chevallier if (stm32_rng->rstctrl && 321*d773ec0bSGatien Chevallier rstctrl_assert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) { 322*d773ec0bSGatien Chevallier res = TEE_ERROR_GENERIC; 323*d773ec0bSGatien Chevallier goto out; 324*d773ec0bSGatien Chevallier } 325*d773ec0bSGatien Chevallier 326*d773ec0bSGatien Chevallier if (stm32_rng->rstctrl && 327*d773ec0bSGatien Chevallier rstctrl_deassert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) { 328*d773ec0bSGatien Chevallier res = TEE_ERROR_GENERIC; 329*d773ec0bSGatien Chevallier goto out; 330*d773ec0bSGatien Chevallier } 331*d773ec0bSGatien Chevallier 3323c752300SGatien Chevallier if (!stm32_rng->clock_error) 3333c752300SGatien Chevallier cr_ced_mask = RNG_CR_CED; 334f3c22059SEtienne Carriere 335f63f11bdSGatien Chevallier /* Clean error indications */ 336f63f11bdSGatien Chevallier io_write32(rng_base + RNG_SR, 0); 337f3c22059SEtienne Carriere 338091ef005SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 339091ef005SGatien Chevallier uint32_t clock_div = stm32_rng_clock_freq_restrain(); 340091ef005SGatien Chevallier 3415959d83fSGatien Chevallier /* 3425959d83fSGatien Chevallier * Keep default RNG configuration if none was specified. 3435959d83fSGatien Chevallier * 0 is an invalid value as it disables all entropy sources. 3445959d83fSGatien Chevallier */ 3455959d83fSGatien Chevallier if (!stm32_rng->rng_config) 3465959d83fSGatien Chevallier stm32_rng->rng_config = io_read32(rng_base + RNG_CR) & 3475959d83fSGatien Chevallier RNG_CR_ENTROPY_SRC_MASK; 3485959d83fSGatien Chevallier 3495959d83fSGatien Chevallier /* 3505959d83fSGatien Chevallier * Configuration must be set in the same access that sets 3515959d83fSGatien Chevallier * RNG_CR_CONDRST bit. Otherwise, the configuration setting is 3525959d83fSGatien Chevallier * not taken into account. CONFIGLOCK bit is always cleared at 3535959d83fSGatien Chevallier * this stage. 3545959d83fSGatien Chevallier */ 3555959d83fSGatien Chevallier io_clrsetbits32(rng_base + RNG_CR, RNG_CONFIG_MASK, 3565959d83fSGatien Chevallier stm32_rng->rng_config | RNG_CR_CONDRST | 3575959d83fSGatien Chevallier cr_ced_mask | 3585959d83fSGatien Chevallier SHIFT_U32(clock_div, RNG_CR_CLKDIV_SHIFT)); 3595959d83fSGatien Chevallier 3605959d83fSGatien Chevallier /* 3615959d83fSGatien Chevallier * Write health test and noise source control configuration 3625959d83fSGatien Chevallier * according to current RNG entropy source configuration 3635959d83fSGatien Chevallier */ 3645959d83fSGatien Chevallier if (stm32_rng->noise_ctrl_conf) 3655959d83fSGatien Chevallier io_write32(rng_base + RNG_NSCR, 3665959d83fSGatien Chevallier stm32_rng->noise_ctrl_conf); 3675959d83fSGatien Chevallier 3685959d83fSGatien Chevallier if (stm32_rng->health_test_conf) 3695959d83fSGatien Chevallier io_write32(rng_base + RNG_HTCR, 3705959d83fSGatien Chevallier stm32_rng->health_test_conf); 371091ef005SGatien Chevallier 372091ef005SGatien Chevallier io_clrsetbits32(rng_base + RNG_CR, RNG_CR_CONDRST, 373091ef005SGatien Chevallier RNG_CR_RNGEN); 374eb5cf770SGatien Chevallier 3755959d83fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_CR, value, 3765959d83fSGatien Chevallier !(value & RNG_CR_CONDRST), 0, 3775959d83fSGatien Chevallier RNG_READY_TIMEOUT_US)) 378eb5cf770SGatien Chevallier panic(); 3795959d83fSGatien Chevallier 3805959d83fSGatien Chevallier DMSG("RNG control register %#"PRIx32, 3815959d83fSGatien Chevallier io_read32(rng_base + RNG_CR)); 3825959d83fSGatien Chevallier DMSG("RNG noise source control register %#"PRIx32, 3835959d83fSGatien Chevallier io_read32(rng_base + RNG_NSCR)); 3845959d83fSGatien Chevallier DMSG("RNG health test register %#"PRIx32, 3855959d83fSGatien Chevallier io_read32(rng_base + RNG_HTCR)); 386091ef005SGatien Chevallier } else { 3873c752300SGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_RNGEN | cr_ced_mask); 388091ef005SGatien Chevallier } 389f63f11bdSGatien Chevallier 3905959d83fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(rng_base + RNG_SR, value, 3915959d83fSGatien Chevallier value & RNG_SR_DRDY, 0, 3925959d83fSGatien Chevallier RNG_READY_TIMEOUT_US)) 393f63f11bdSGatien Chevallier return TEE_ERROR_GENERIC; 394f63f11bdSGatien Chevallier 395*d773ec0bSGatien Chevallier res = TEE_SUCCESS; 396*d773ec0bSGatien Chevallier 397*d773ec0bSGatien Chevallier out: 398*d773ec0bSGatien Chevallier disable_rng_clock(); 399*d773ec0bSGatien Chevallier 400*d773ec0bSGatien Chevallier return res; 401f3c22059SEtienne Carriere } 402f3c22059SEtienne Carriere 40398c36268SGatien Chevallier static TEE_Result stm32_rng_read(uint8_t *out, size_t size) 404f3c22059SEtienne Carriere { 405c99311c8SEtienne Carriere TEE_Result rc = TEE_ERROR_GENERIC; 406c99311c8SEtienne Carriere bool burst_timeout = false; 407c99311c8SEtienne Carriere uint64_t timeout_ref = 0; 408f3c22059SEtienne Carriere uint32_t exceptions = 0; 409f3c22059SEtienne Carriere uint8_t *out_ptr = out; 410c99311c8SEtienne Carriere vaddr_t rng_base = 0; 411f3c22059SEtienne Carriere size_t out_size = 0; 412f3c22059SEtienne Carriere 413f3c22059SEtienne Carriere if (!stm32_rng) { 414f3c22059SEtienne Carriere DMSG("No RNG"); 415f3c22059SEtienne Carriere return TEE_ERROR_NOT_SUPPORTED; 416f3c22059SEtienne Carriere } 417f3c22059SEtienne Carriere 418*d773ec0bSGatien Chevallier rc = enable_rng_clock(); 419fb1681dfSGatien Chevallier if (rc) 420fb1681dfSGatien Chevallier return rc; 421fb1681dfSGatien Chevallier 422f63f11bdSGatien Chevallier rng_base = get_base(); 423c99311c8SEtienne Carriere 424c99311c8SEtienne Carriere /* Arm timeout */ 4250817aa6fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 426c99311c8SEtienne Carriere burst_timeout = false; 427f3c22059SEtienne Carriere 428f3c22059SEtienne Carriere while (out_size < size) { 429f3c22059SEtienne Carriere /* Read by chunks of the size the RNG FIFO depth */ 430f3c22059SEtienne Carriere size_t sz = size - out_size; 431f3c22059SEtienne Carriere 432f3c22059SEtienne Carriere exceptions = may_spin_lock(&stm32_rng->lock); 433f3c22059SEtienne Carriere 434c99311c8SEtienne Carriere rc = read_available(rng_base, out_ptr, &sz); 435c99311c8SEtienne Carriere 436c99311c8SEtienne Carriere /* Raise timeout only if we failed to get some samples */ 437c99311c8SEtienne Carriere assert(!rc || rc == TEE_ERROR_NO_DATA); 438c99311c8SEtienne Carriere if (rc) 439c99311c8SEtienne Carriere burst_timeout = timeout_elapsed(timeout_ref); 440f3c22059SEtienne Carriere 441f3c22059SEtienne Carriere may_spin_unlock(&stm32_rng->lock, exceptions); 442f3c22059SEtienne Carriere 443c99311c8SEtienne Carriere if (burst_timeout) { 444c99311c8SEtienne Carriere rc = TEE_ERROR_GENERIC; 445c99311c8SEtienne Carriere goto out; 446f3c22059SEtienne Carriere } 447f3c22059SEtienne Carriere 448c99311c8SEtienne Carriere if (!rc) { 449c99311c8SEtienne Carriere out_size += sz; 450c99311c8SEtienne Carriere out_ptr += sz; 451c99311c8SEtienne Carriere /* Re-arm timeout */ 4520817aa6fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 453c99311c8SEtienne Carriere burst_timeout = false; 454c99311c8SEtienne Carriere } 455c99311c8SEtienne Carriere } 456c99311c8SEtienne Carriere 457c99311c8SEtienne Carriere out: 458c99311c8SEtienne Carriere assert(!rc || rc == TEE_ERROR_GENERIC); 459*d773ec0bSGatien Chevallier disable_rng_clock(); 460f3c22059SEtienne Carriere 461f3c22059SEtienne Carriere return rc; 462f3c22059SEtienne Carriere } 463f3c22059SEtienne Carriere 464cd451498SEtienne Carriere #ifdef CFG_WITH_SOFTWARE_PRNG 465f2fe4f00SThomas Bourgoin /* Override weak plat_rng_init with platform handler to attempt to seed PRNG */ 466cd451498SEtienne Carriere void plat_rng_init(void) 467cd451498SEtienne Carriere { 468cd451498SEtienne Carriere uint8_t seed[RNG_FIFO_BYTE_DEPTH] = { }; 469cd451498SEtienne Carriere 470f2fe4f00SThomas Bourgoin if (!stm32_rng) { 471f2fe4f00SThomas Bourgoin __plat_rng_init(); 472f2fe4f00SThomas Bourgoin DMSG("PRNG seeded without RNG"); 473f2fe4f00SThomas Bourgoin return; 474f2fe4f00SThomas Bourgoin } 475f2fe4f00SThomas Bourgoin 476cd451498SEtienne Carriere if (stm32_rng_read(seed, sizeof(seed))) 477cd451498SEtienne Carriere panic(); 478cd451498SEtienne Carriere 479cd451498SEtienne Carriere if (crypto_rng_init(seed, sizeof(seed))) 480cd451498SEtienne Carriere panic(); 481cd451498SEtienne Carriere 482cd451498SEtienne Carriere DMSG("PRNG seeded with RNG"); 483cd451498SEtienne Carriere } 484cd451498SEtienne Carriere #else 485cb2478efSAndrew Davis TEE_Result hw_get_random_bytes(void *out, size_t size) 486097f329aSEtienne Carriere { 487097f329aSEtienne Carriere return stm32_rng_read(out, size); 488097f329aSEtienne Carriere } 48927f3087bSGatien Chevallier 49027f3087bSGatien Chevallier void plat_rng_init(void) 49127f3087bSGatien Chevallier { 49227f3087bSGatien Chevallier } 493097f329aSEtienne Carriere #endif 494097f329aSEtienne Carriere 4955959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_resume(void) 49629893549SGatien Chevallier { 49729893549SGatien Chevallier vaddr_t base = get_base(); 49829893549SGatien Chevallier 49929893549SGatien Chevallier /* Clean error indications */ 50029893549SGatien Chevallier io_write32(base + RNG_SR, 0); 50129893549SGatien Chevallier 50229893549SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 503eb5cf770SGatien Chevallier uint64_t timeout_ref = 0; 504eb5cf770SGatien Chevallier 50529893549SGatien Chevallier /* 506c2c5b4beSGatien Chevallier * Configuration must be set in the same access that sets 507c2c5b4beSGatien Chevallier * RNG_CR_CONDRST bit. Otherwise, the configuration setting is 508c2c5b4beSGatien Chevallier * not taken into account. CONFIGLOCK bit is always cleared in 509c2c5b4beSGatien Chevallier * this configuration. 51029893549SGatien Chevallier */ 5115959d83fSGatien Chevallier io_write32(base + RNG_CR, stm32_rng->pm_cr | RNG_CR_CONDRST); 5125959d83fSGatien Chevallier 5135959d83fSGatien Chevallier /* Restore health test and noise control configuration */ 5145959d83fSGatien Chevallier io_write32(base + RNG_NSCR, stm32_rng->pm_noise_ctrl); 5155959d83fSGatien Chevallier io_write32(base + RNG_HTCR, stm32_rng->pm_health); 51629893549SGatien Chevallier 51729893549SGatien Chevallier io_clrsetbits32(base + RNG_CR, RNG_CR_CONDRST, RNG_CR_RNGEN); 518eb5cf770SGatien Chevallier 519eb5cf770SGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 520eb5cf770SGatien Chevallier while (io_read32(base + RNG_CR) & RNG_CR_CONDRST) 521eb5cf770SGatien Chevallier if (timeout_elapsed(timeout_ref)) 522eb5cf770SGatien Chevallier break; 523eb5cf770SGatien Chevallier if (io_read32(base + RNG_CR) & RNG_CR_CONDRST) 524eb5cf770SGatien Chevallier panic(); 52529893549SGatien Chevallier } else { 5265959d83fSGatien Chevallier io_write32(base + RNG_CR, RNG_CR_RNGEN | stm32_rng->pm_cr); 5275959d83fSGatien Chevallier } 5285959d83fSGatien Chevallier 5295959d83fSGatien Chevallier return TEE_SUCCESS; 5305959d83fSGatien Chevallier } 5315959d83fSGatien Chevallier 5325959d83fSGatien Chevallier static TEE_Result stm32_rng_pm_suspend(void) 5335959d83fSGatien Chevallier { 5345959d83fSGatien Chevallier vaddr_t rng_base = get_base(); 5355959d83fSGatien Chevallier 5365959d83fSGatien Chevallier stm32_rng->pm_cr = io_read32(rng_base + RNG_CR); 5375959d83fSGatien Chevallier 5385959d83fSGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 5395959d83fSGatien Chevallier stm32_rng->pm_health = io_read32(rng_base + RNG_HTCR); 5405959d83fSGatien Chevallier stm32_rng->pm_noise_ctrl = io_read32(rng_base + RNG_NSCR); 5415959d83fSGatien Chevallier } 5425959d83fSGatien Chevallier 5435959d83fSGatien Chevallier if (stm32_rng->ddata->has_power_optim) { 5445959d83fSGatien Chevallier uint64_t timeout_ref = 0; 5455959d83fSGatien Chevallier 5465959d83fSGatien Chevallier /* 5475959d83fSGatien Chevallier * As per reference manual, it is recommended to set 5485959d83fSGatien Chevallier * RNG_CONFIG2[bit0] when RNG power consumption is critical. 5495959d83fSGatien Chevallier */ 5505959d83fSGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_POWER_OPTIM | 5515959d83fSGatien Chevallier RNG_CR_CONDRST); 5525959d83fSGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 5535959d83fSGatien Chevallier 5545959d83fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 5555959d83fSGatien Chevallier while (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) 5565959d83fSGatien Chevallier if (timeout_elapsed(timeout_ref)) 5575959d83fSGatien Chevallier break; 5585959d83fSGatien Chevallier if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) 5595959d83fSGatien Chevallier panic(); 5605959d83fSGatien Chevallier } else { 5615959d83fSGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_RNGEN); 56229893549SGatien Chevallier } 56329893549SGatien Chevallier 56429893549SGatien Chevallier return TEE_SUCCESS; 56529893549SGatien Chevallier } 56629893549SGatien Chevallier 56729893549SGatien Chevallier static TEE_Result 56829893549SGatien Chevallier stm32_rng_pm(enum pm_op op, unsigned int pm_hint __unused, 56929893549SGatien Chevallier const struct pm_callback_handle *pm_handle __unused) 57029893549SGatien Chevallier { 57129893549SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 57229893549SGatien Chevallier 57329893549SGatien Chevallier assert(stm32_rng && (op == PM_OP_SUSPEND || op == PM_OP_RESUME)); 57429893549SGatien Chevallier 575*d773ec0bSGatien Chevallier res = enable_rng_clock(); 57629893549SGatien Chevallier if (res) 57729893549SGatien Chevallier return res; 57829893549SGatien Chevallier 5795959d83fSGatien Chevallier if (op == PM_OP_RESUME) 5805959d83fSGatien Chevallier res = stm32_rng_pm_resume(); 58129893549SGatien Chevallier else 5825959d83fSGatien Chevallier res = stm32_rng_pm_suspend(); 58329893549SGatien Chevallier 584*d773ec0bSGatien Chevallier disable_rng_clock(); 58529893549SGatien Chevallier 58629893549SGatien Chevallier return res; 58729893549SGatien Chevallier } 58829893549SGatien Chevallier DECLARE_KEEP_PAGER(stm32_rng_pm); 58929893549SGatien Chevallier 590ea8ba295SGatien Chevallier static TEE_Result stm32_rng_parse_fdt(const void *fdt, int node) 591f3c22059SEtienne Carriere { 592d7a1a7d2SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 593ea8ba295SGatien Chevallier struct dt_node_info dt_rng = { }; 594f3c22059SEtienne Carriere 595f354a5d8SGatien Chevallier fdt_fill_device_info(fdt, &dt_rng, node); 596ea8ba295SGatien Chevallier if (dt_rng.reg == DT_INFO_INVALID_REG) 597ea8ba295SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS; 598f3c22059SEtienne Carriere 599ea8ba295SGatien Chevallier stm32_rng->base.pa = dt_rng.reg; 600ea8ba295SGatien Chevallier stm32_rng->base.va = io_pa_or_va_secure(&stm32_rng->base, 601ea8ba295SGatien Chevallier dt_rng.reg_size); 602ea8ba295SGatien Chevallier assert(stm32_rng->base.va); 603f3c22059SEtienne Carriere 604ea8ba295SGatien Chevallier res = rstctrl_dt_get_by_index(fdt, node, 0, &stm32_rng->rstctrl); 605ea8ba295SGatien Chevallier if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND) 606ea8ba295SGatien Chevallier return res; 60768c4a16bSEtienne Carriere 60845da6509SGatien Chevallier if (stm32_rng->ddata->nb_clock > 1) { 60945da6509SGatien Chevallier res = clk_dt_get_by_name(fdt, node, "rng_clk", 61045da6509SGatien Chevallier &stm32_rng->clock); 61145da6509SGatien Chevallier if (res) 61245da6509SGatien Chevallier return res; 61345da6509SGatien Chevallier 61445da6509SGatien Chevallier res = clk_dt_get_by_name(fdt, node, "rng_hclk", 61545da6509SGatien Chevallier &stm32_rng->bus_clock); 61645da6509SGatien Chevallier if (res) 61745da6509SGatien Chevallier return res; 61845da6509SGatien Chevallier } else { 619d7a1a7d2SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &stm32_rng->clock); 620d7a1a7d2SEtienne Carriere if (res) 621d7a1a7d2SEtienne Carriere return res; 62245da6509SGatien Chevallier } 623d7a1a7d2SEtienne Carriere 6243c752300SGatien Chevallier if (fdt_getprop(fdt, node, "clock-error-detect", NULL)) 6253c752300SGatien Chevallier stm32_rng->clock_error = true; 6263c752300SGatien Chevallier 6275959d83fSGatien Chevallier stm32_rng->rng_config = stm32_rng->ddata->cr; 6285959d83fSGatien Chevallier if (stm32_rng->rng_config & ~RNG_CR_ENTROPY_SRC_MASK) 6295959d83fSGatien Chevallier panic("Incorrect entropy source configuration"); 6305959d83fSGatien Chevallier stm32_rng->health_test_conf = stm32_rng->ddata->htcr; 6315959d83fSGatien Chevallier stm32_rng->noise_ctrl_conf = stm32_rng->ddata->nscr; 6325959d83fSGatien Chevallier if (stm32_rng->noise_ctrl_conf & ~RNG_NSCR_MASK) 6335959d83fSGatien Chevallier panic("Incorrect noise source control configuration"); 6345959d83fSGatien Chevallier 635f3c22059SEtienne Carriere return TEE_SUCCESS; 636f3c22059SEtienne Carriere } 637f3c22059SEtienne Carriere 638ea8ba295SGatien Chevallier static TEE_Result stm32_rng_probe(const void *fdt, int offs, 639f9508605SGatien Chevallier const void *compat_data) 640ea8ba295SGatien Chevallier { 641b82b7e73SGatien Chevallier unsigned int __maybe_unused version = 0; 642*d773ec0bSGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 643ea8ba295SGatien Chevallier 644ea8ba295SGatien Chevallier /* Expect a single RNG instance */ 645ea8ba295SGatien Chevallier assert(!stm32_rng); 646ea8ba295SGatien Chevallier 647ea8ba295SGatien Chevallier stm32_rng = calloc(1, sizeof(*stm32_rng)); 648ea8ba295SGatien Chevallier if (!stm32_rng) 649ea8ba295SGatien Chevallier panic(); 650ea8ba295SGatien Chevallier 6515959d83fSGatien Chevallier stm32_rng->ddata = compat_data; 6525959d83fSGatien Chevallier assert(stm32_rng->ddata); 6535959d83fSGatien Chevallier 654ea8ba295SGatien Chevallier res = stm32_rng_parse_fdt(fdt, offs); 655ea8ba295SGatien Chevallier if (res) 656ea8ba295SGatien Chevallier goto err; 657ea8ba295SGatien Chevallier 658*d773ec0bSGatien Chevallier res = enable_rng_clock(); 659ea8ba295SGatien Chevallier if (res) 660ea8ba295SGatien Chevallier goto err; 661ea8ba295SGatien Chevallier 662b82b7e73SGatien Chevallier version = io_read32(get_base() + RNG_VERR); 663b82b7e73SGatien Chevallier DMSG("RNG version Major %u, Minor %u", 664b82b7e73SGatien Chevallier (version & RNG_VERR_MAJOR_MASK) >> RNG_VERR_MAJOR_SHIFT, 665b82b7e73SGatien Chevallier version & RNG_VERR_MINOR_MASK); 666b82b7e73SGatien Chevallier 667*d773ec0bSGatien Chevallier disable_rng_clock(); 668ea8ba295SGatien Chevallier 669*d773ec0bSGatien Chevallier res = stm32_rng_init(); 670f63f11bdSGatien Chevallier if (res) 671*d773ec0bSGatien Chevallier goto err; 672f63f11bdSGatien Chevallier 673*d773ec0bSGatien Chevallier #if defined(CFG_STM32MP15) 674*d773ec0bSGatien Chevallier /* Only STM32MP15 requires a software registering of RNG secure state */ 675*d773ec0bSGatien Chevallier if (etzpc_get_decprot(STM32MP1_ETZPC_RNG1_ID) == ETZPC_DECPROT_NS_RW) 676ea8ba295SGatien Chevallier stm32mp_register_non_secure_periph_iomem(stm32_rng->base.pa); 677ea8ba295SGatien Chevallier else 678ea8ba295SGatien Chevallier stm32mp_register_secure_periph_iomem(stm32_rng->base.pa); 679*d773ec0bSGatien Chevallier #endif /* defined(CFG_STM32MP15) */ 680ea8ba295SGatien Chevallier 6815959d83fSGatien Chevallier /* Power management implementation expects both or none are set */ 6825959d83fSGatien Chevallier assert(stm32_rng->ddata->has_power_optim == 6835959d83fSGatien Chevallier stm32_rng->ddata->has_cond_reset); 6845959d83fSGatien Chevallier 685*d773ec0bSGatien Chevallier if (!IS_ENABLED(CFG_WITH_SOFTWARE_PRNG)) 686*d773ec0bSGatien Chevallier register_pm_core_service_cb(stm32_rng_pm, &stm32_rng, 687*d773ec0bSGatien Chevallier "rng-service"); 68829893549SGatien Chevallier 689ea8ba295SGatien Chevallier return TEE_SUCCESS; 690ea8ba295SGatien Chevallier 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 { 747*d773ec0bSGatien Chevallier if (stm32_rng && IS_ENABLED(CFG_WITH_SOFTWARE_PRNG)) { 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