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 <drivers/stm32_rng.h> 11f3c22059SEtienne Carriere #include <io.h> 12f3c22059SEtienne Carriere #include <kernel/delay.h> 13a2fc83d1SJerome Forissier #include <kernel/dt.h> 14ea8ba295SGatien Chevallier #include <kernel/dt_driver.h> 1565401337SJens Wiklander #include <kernel/boot.h> 16f3c22059SEtienne Carriere #include <kernel/panic.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> 25f3c22059SEtienne Carriere 260817aa6fSGatien Chevallier #define RNG_CR U(0x00) 270817aa6fSGatien Chevallier #define RNG_SR U(0x04) 280817aa6fSGatien Chevallier #define RNG_DR U(0x08) 29f3c22059SEtienne Carriere 30f3c22059SEtienne Carriere #define RNG_CR_RNGEN BIT(2) 31f3c22059SEtienne Carriere #define RNG_CR_IE BIT(3) 32f3c22059SEtienne Carriere #define RNG_CR_CED BIT(5) 33*091ef005SGatien Chevallier #define RNG_CR_CLKDIV GENMASK_32(19, 16) 34*091ef005SGatien Chevallier #define RNG_CR_CLKDIV_SHIFT U(16) 35*091ef005SGatien Chevallier #define RNG_CR_CONDRST BIT(30) 36f3c22059SEtienne Carriere 37f3c22059SEtienne Carriere #define RNG_SR_DRDY BIT(0) 38f3c22059SEtienne Carriere #define RNG_SR_CECS BIT(1) 39f3c22059SEtienne Carriere #define RNG_SR_SECS BIT(2) 40f3c22059SEtienne Carriere #define RNG_SR_CEIS BIT(5) 41f3c22059SEtienne Carriere #define RNG_SR_SEIS BIT(6) 42f3c22059SEtienne Carriere 430817aa6fSGatien Chevallier #if TRACE_LEVEL > TRACE_DEBUG 440817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US U(100000) 450817aa6fSGatien Chevallier #else 460817aa6fSGatien Chevallier #define RNG_READY_TIMEOUT_US U(10000) 470817aa6fSGatien Chevallier #endif 48ea8ba295SGatien Chevallier #define RNG_RESET_TIMEOUT_US U(1000) 49f3c22059SEtienne Carriere 500817aa6fSGatien Chevallier #define RNG_FIFO_BYTE_DEPTH U(16) 510817aa6fSGatien Chevallier 52*091ef005SGatien Chevallier #define RNG_NIST_CONFIG_A U(0x0F00D00) 53*091ef005SGatien Chevallier #define RNG_NIST_CONFIG_B U(0x1801000) 54*091ef005SGatien Chevallier #define RNG_NIST_CONFIG_MASK GENMASK_32(25, 8) 55*091ef005SGatien Chevallier 56*091ef005SGatien Chevallier #define RNG_MAX_NOISE_CLK_FREQ U(3000000) 57*091ef005SGatien Chevallier 58*091ef005SGatien Chevallier struct stm32_rng_driver_data { 59*091ef005SGatien Chevallier bool has_cond_reset; 60*091ef005SGatien Chevallier }; 61*091ef005SGatien Chevallier 62f3c22059SEtienne Carriere struct stm32_rng_instance { 63f3c22059SEtienne Carriere struct io_pa_va base; 64d7a1a7d2SEtienne Carriere struct clk *clock; 65ea8ba295SGatien Chevallier struct rstctrl *rstctrl; 66*091ef005SGatien Chevallier const struct stm32_rng_driver_data *ddata; 67f3c22059SEtienne Carriere unsigned int lock; 68d8682c4cSEtienne Carriere bool release_post_boot; 69*091ef005SGatien Chevallier bool error_conceal; 70*091ef005SGatien Chevallier uint64_t error_to_ref; 71f3c22059SEtienne Carriere }; 72f3c22059SEtienne Carriere 73ea8ba295SGatien Chevallier /* Expect at most a single RNG instance */ 74f3c22059SEtienne Carriere static struct stm32_rng_instance *stm32_rng; 75f3c22059SEtienne Carriere 76f63f11bdSGatien Chevallier static vaddr_t get_base(void) 77f63f11bdSGatien Chevallier { 78f63f11bdSGatien Chevallier assert(stm32_rng); 79f63f11bdSGatien Chevallier 80f63f11bdSGatien Chevallier return io_pa_or_va(&stm32_rng->base, 1); 81f63f11bdSGatien Chevallier } 82f63f11bdSGatien Chevallier 83f3c22059SEtienne Carriere /* 84*091ef005SGatien Chevallier * Extracts from the STM32 RNG specification when RNG supports CONDRST. 85f3c22059SEtienne Carriere * 86f3c22059SEtienne Carriere * When a noise source (or seed) error occurs, the RNG stops generating 87f3c22059SEtienne Carriere * random numbers and sets to “1” both SEIS and SECS bits to indicate 88f3c22059SEtienne Carriere * that a seed error occurred. (...) 89*091ef005SGatien Chevallier * 90*091ef005SGatien Chevallier * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield 91*091ef005SGatien Chevallier * description for details). This step is needed only if SECS is set. 92*091ef005SGatien Chevallier * Indeed, when SEIS is set and SECS is cleared it means RNG performed 93*091ef005SGatien Chevallier * the reset automatically (auto-reset). 94*091ef005SGatien Chevallier * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST 95*091ef005SGatien Chevallier * to be cleared in the RNG_CR register, then confirm that SEIS is 96*091ef005SGatien Chevallier * cleared in the RNG_SR register. Otherwise just clear SEIS bit in 97*091ef005SGatien Chevallier * the RNG_SR register. 98*091ef005SGatien Chevallier * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be 99*091ef005SGatien Chevallier * cleared by RNG. The random number generation is now back to normal. 100*091ef005SGatien Chevallier */ 101*091ef005SGatien Chevallier static void conceal_seed_error_cond_reset(void) 102*091ef005SGatien Chevallier { 103*091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 104*091ef005SGatien Chevallier vaddr_t rng_base = get_base(); 105f3c22059SEtienne Carriere 106*091ef005SGatien Chevallier if (!dev->error_conceal) { 107*091ef005SGatien Chevallier uint32_t sr = io_read32(rng_base + RNG_SR); 108*091ef005SGatien Chevallier 109*091ef005SGatien Chevallier if (sr & RNG_SR_SECS) { 110*091ef005SGatien Chevallier /* Conceal by resetting the subsystem (step 1.) */ 111*091ef005SGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 112*091ef005SGatien Chevallier io_clrbits32(rng_base + RNG_CR, RNG_CR_CONDRST); 113*091ef005SGatien Chevallier 114*091ef005SGatien Chevallier /* Arm timeout for error_conceal sequence */ 115*091ef005SGatien Chevallier dev->error_to_ref = 116*091ef005SGatien Chevallier timeout_init_us(RNG_READY_TIMEOUT_US); 117*091ef005SGatien Chevallier dev->error_conceal = true; 118*091ef005SGatien Chevallier } else { 119*091ef005SGatien Chevallier /* RNG auto-reset (step 2.) */ 120*091ef005SGatien Chevallier io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS); 121*091ef005SGatien Chevallier } 122*091ef005SGatien Chevallier } else { 123*091ef005SGatien Chevallier /* Measure time before possible reschedule */ 124*091ef005SGatien Chevallier bool timed_out = timeout_elapsed(dev->error_to_ref); 125*091ef005SGatien Chevallier 126*091ef005SGatien Chevallier /* Wait CONDRST is cleared (step 2.) */ 127*091ef005SGatien Chevallier if (io_read32(rng_base + RNG_CR) & RNG_CR_CONDRST) { 128*091ef005SGatien Chevallier if (timed_out) 129*091ef005SGatien Chevallier panic(); 130*091ef005SGatien Chevallier 131*091ef005SGatien Chevallier /* Wait subsystem reset cycle completes */ 132*091ef005SGatien Chevallier return; 133*091ef005SGatien Chevallier } 134*091ef005SGatien Chevallier 135*091ef005SGatien Chevallier /* Check SEIS is cleared (step 2.) */ 136*091ef005SGatien Chevallier if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 137*091ef005SGatien Chevallier panic(); 138*091ef005SGatien Chevallier 139*091ef005SGatien Chevallier /* Wait SECS is cleared (step 3.) */ 140*091ef005SGatien Chevallier if (io_read32(rng_base + RNG_SR) & RNG_SR_SECS) { 141*091ef005SGatien Chevallier if (timed_out) 142*091ef005SGatien Chevallier panic(); 143*091ef005SGatien Chevallier 144*091ef005SGatien Chevallier /* Wait subsystem reset cycle completes */ 145*091ef005SGatien Chevallier return; 146*091ef005SGatien Chevallier } 147*091ef005SGatien Chevallier 148*091ef005SGatien Chevallier dev->error_conceal = false; 149*091ef005SGatien Chevallier } 150*091ef005SGatien Chevallier } 151*091ef005SGatien Chevallier 152*091ef005SGatien Chevallier /* 153*091ef005SGatien Chevallier * Extracts from the STM32 RNG specification, when CONDRST is not supported 154*091ef005SGatien Chevallier * 155*091ef005SGatien Chevallier * When a noise source (or seed) error occurs, the RNG stops generating 156*091ef005SGatien Chevallier * random numbers and sets to “1” both SEIS and SECS bits to indicate 157*091ef005SGatien Chevallier * that a seed error occurred. (...) 158*091ef005SGatien Chevallier * 159f3c22059SEtienne Carriere * The following sequence shall be used to fully recover from a seed 160f3c22059SEtienne Carriere * error after the RNG initialization: 161f3c22059SEtienne Carriere * 1. Clear the SEIS bit by writing it to “0”. 162f3c22059SEtienne Carriere * 2. Read out 12 words from the RNG_DR register, and discard each of 163f3c22059SEtienne Carriere * them in order to clean the pipeline. 164f3c22059SEtienne Carriere * 3. Confirm that SEIS is still cleared. Random number generation is 165f3c22059SEtienne Carriere * back to normal. 166f3c22059SEtienne Carriere */ 167*091ef005SGatien Chevallier static void conceal_seed_error_sw_reset(void) 168f3c22059SEtienne Carriere { 1696a6b6168SGatien Chevallier vaddr_t rng_base = get_base(); 170f3c22059SEtienne Carriere size_t i = 0; 171f3c22059SEtienne Carriere 1726a6b6168SGatien Chevallier io_clrbits32(rng_base + RNG_SR, RNG_SR_SEIS); 173f3c22059SEtienne Carriere 174f3c22059SEtienne Carriere for (i = 12; i != 0; i--) 175f3c22059SEtienne Carriere (void)io_read32(rng_base + RNG_DR); 176f3c22059SEtienne Carriere 177f3c22059SEtienne Carriere if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 178f3c22059SEtienne Carriere panic("RNG noise"); 179f3c22059SEtienne Carriere } 180f3c22059SEtienne Carriere 181*091ef005SGatien Chevallier static void conceal_seed_error(void) 182*091ef005SGatien Chevallier { 183*091ef005SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) 184*091ef005SGatien Chevallier conceal_seed_error_cond_reset(); 185*091ef005SGatien Chevallier else 186*091ef005SGatien Chevallier conceal_seed_error_sw_reset(); 187*091ef005SGatien Chevallier } 188*091ef005SGatien Chevallier 189c99311c8SEtienne Carriere static TEE_Result read_available(vaddr_t rng_base, uint8_t *out, size_t *size) 190f3c22059SEtienne Carriere { 191*091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 192c99311c8SEtienne Carriere uint8_t *buf = NULL; 193c99311c8SEtienne Carriere size_t req_size = 0; 194c99311c8SEtienne Carriere size_t len = 0; 195f3c22059SEtienne Carriere 196*091ef005SGatien Chevallier if (dev->error_conceal || io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) 1976a6b6168SGatien Chevallier conceal_seed_error(); 198f3c22059SEtienne Carriere 19923123473SEtienne Carriere if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) { 20023123473SEtienne Carriere FMSG("RNG not ready"); 201c99311c8SEtienne Carriere return TEE_ERROR_NO_DATA; 20223123473SEtienne Carriere } 203f3c22059SEtienne Carriere 20423123473SEtienne Carriere if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) { 20523123473SEtienne Carriere FMSG("RNG noise error"); 206c99311c8SEtienne Carriere return TEE_ERROR_NO_DATA; 20723123473SEtienne Carriere } 208c99311c8SEtienne Carriere 209c99311c8SEtienne Carriere buf = out; 210c99311c8SEtienne Carriere req_size = MIN(RNG_FIFO_BYTE_DEPTH, *size); 211c99311c8SEtienne Carriere len = req_size; 212f3c22059SEtienne Carriere 213f3c22059SEtienne Carriere /* RNG is ready: read up to 4 32bit words */ 214f3c22059SEtienne Carriere while (len) { 215f3c22059SEtienne Carriere uint32_t data32 = io_read32(rng_base + RNG_DR); 216f3c22059SEtienne Carriere size_t sz = MIN(len, sizeof(uint32_t)); 217f3c22059SEtienne Carriere 218f3c22059SEtienne Carriere memcpy(buf, &data32, sz); 219f3c22059SEtienne Carriere buf += sz; 220f3c22059SEtienne Carriere len -= sz; 221f3c22059SEtienne Carriere } 222c99311c8SEtienne Carriere 223f3c22059SEtienne Carriere *size = req_size; 224f3c22059SEtienne Carriere 225c99311c8SEtienne Carriere return TEE_SUCCESS; 226f3c22059SEtienne Carriere } 227f3c22059SEtienne Carriere 228*091ef005SGatien Chevallier static uint32_t stm32_rng_clock_freq_restrain(void) 229*091ef005SGatien Chevallier { 230*091ef005SGatien Chevallier struct stm32_rng_instance *dev = stm32_rng; 231*091ef005SGatien Chevallier unsigned long clock_rate = 0; 232*091ef005SGatien Chevallier uint32_t clock_div = 0; 233*091ef005SGatien Chevallier 234*091ef005SGatien Chevallier clock_rate = clk_get_rate(dev->clock); 235*091ef005SGatien Chevallier 236*091ef005SGatien Chevallier /* 237*091ef005SGatien Chevallier * Get the exponent to apply on the CLKDIV field in RNG_CR register 238*091ef005SGatien Chevallier * No need to handle the case when clock-div > 0xF as it is physically 239*091ef005SGatien Chevallier * impossible 240*091ef005SGatien Chevallier */ 241*091ef005SGatien Chevallier while ((clock_rate >> clock_div) > RNG_MAX_NOISE_CLK_FREQ) 242*091ef005SGatien Chevallier clock_div++; 243*091ef005SGatien Chevallier 244*091ef005SGatien Chevallier DMSG("RNG clk rate : %lu", clk_get_rate(dev->clock) >> clock_div); 245*091ef005SGatien Chevallier 246*091ef005SGatien Chevallier return clock_div; 247*091ef005SGatien Chevallier } 248*091ef005SGatien Chevallier 249f63f11bdSGatien Chevallier static TEE_Result init_rng(void) 250f3c22059SEtienne Carriere { 251f63f11bdSGatien Chevallier vaddr_t rng_base = get_base(); 252f63f11bdSGatien Chevallier uint64_t timeout_ref = 0; 253f3c22059SEtienne Carriere 254f63f11bdSGatien Chevallier /* Clean error indications */ 255f63f11bdSGatien Chevallier io_write32(rng_base + RNG_SR, 0); 256f3c22059SEtienne Carriere 257*091ef005SGatien Chevallier if (stm32_rng->ddata->has_cond_reset) { 258*091ef005SGatien Chevallier uint32_t clock_div = stm32_rng_clock_freq_restrain(); 259*091ef005SGatien Chevallier 260*091ef005SGatien Chevallier /* Update configuration fields */ 261*091ef005SGatien Chevallier io_clrsetbits32(rng_base + RNG_CR, RNG_NIST_CONFIG_MASK, 262*091ef005SGatien Chevallier RNG_NIST_CONFIG_B | RNG_CR_CONDRST | 263*091ef005SGatien Chevallier RNG_CR_CED); 264*091ef005SGatien Chevallier io_clrsetbits32(rng_base + RNG_CR, RNG_CR_CLKDIV, 265*091ef005SGatien Chevallier clock_div << RNG_CR_CLKDIV_SHIFT); 266*091ef005SGatien Chevallier 267*091ef005SGatien Chevallier /* No need to wait for RNG_CR_CONDRST toggle as we enable clk */ 268*091ef005SGatien Chevallier io_clrsetbits32(rng_base + RNG_CR, RNG_CR_CONDRST, 269*091ef005SGatien Chevallier RNG_CR_RNGEN); 270*091ef005SGatien Chevallier } else { 271f63f11bdSGatien Chevallier io_setbits32(rng_base + RNG_CR, RNG_CR_RNGEN | RNG_CR_CED); 272*091ef005SGatien Chevallier } 273f63f11bdSGatien Chevallier 2740817aa6fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 275f63f11bdSGatien Chevallier while (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) 276f63f11bdSGatien Chevallier if (timeout_elapsed(timeout_ref)) 277f63f11bdSGatien Chevallier break; 278f63f11bdSGatien Chevallier 279f63f11bdSGatien Chevallier if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) 280f63f11bdSGatien Chevallier return TEE_ERROR_GENERIC; 281f63f11bdSGatien Chevallier 282f63f11bdSGatien Chevallier return TEE_SUCCESS; 283f3c22059SEtienne Carriere } 284f3c22059SEtienne Carriere 285f3c22059SEtienne Carriere TEE_Result stm32_rng_read(uint8_t *out, size_t size) 286f3c22059SEtienne Carriere { 287c99311c8SEtienne Carriere TEE_Result rc = TEE_ERROR_GENERIC; 288c99311c8SEtienne Carriere bool burst_timeout = false; 289c99311c8SEtienne Carriere uint64_t timeout_ref = 0; 290f3c22059SEtienne Carriere uint32_t exceptions = 0; 291f3c22059SEtienne Carriere uint8_t *out_ptr = out; 292c99311c8SEtienne Carriere vaddr_t rng_base = 0; 293f3c22059SEtienne Carriere size_t out_size = 0; 294f3c22059SEtienne Carriere 295f3c22059SEtienne Carriere if (!stm32_rng) { 296f3c22059SEtienne Carriere DMSG("No RNG"); 297f3c22059SEtienne Carriere return TEE_ERROR_NOT_SUPPORTED; 298f3c22059SEtienne Carriere } 299f3c22059SEtienne Carriere 300f63f11bdSGatien Chevallier clk_enable(stm32_rng->clock); 301f63f11bdSGatien Chevallier rng_base = get_base(); 302c99311c8SEtienne Carriere 303c99311c8SEtienne Carriere /* Arm timeout */ 3040817aa6fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 305c99311c8SEtienne Carriere burst_timeout = false; 306f3c22059SEtienne Carriere 307f3c22059SEtienne Carriere while (out_size < size) { 308f3c22059SEtienne Carriere /* Read by chunks of the size the RNG FIFO depth */ 309f3c22059SEtienne Carriere size_t sz = size - out_size; 310f3c22059SEtienne Carriere 311f3c22059SEtienne Carriere exceptions = may_spin_lock(&stm32_rng->lock); 312f3c22059SEtienne Carriere 313c99311c8SEtienne Carriere rc = read_available(rng_base, out_ptr, &sz); 314c99311c8SEtienne Carriere 315c99311c8SEtienne Carriere /* Raise timeout only if we failed to get some samples */ 316c99311c8SEtienne Carriere assert(!rc || rc == TEE_ERROR_NO_DATA); 317c99311c8SEtienne Carriere if (rc) 318c99311c8SEtienne Carriere burst_timeout = timeout_elapsed(timeout_ref); 319f3c22059SEtienne Carriere 320f3c22059SEtienne Carriere may_spin_unlock(&stm32_rng->lock, exceptions); 321f3c22059SEtienne Carriere 322c99311c8SEtienne Carriere if (burst_timeout) { 323c99311c8SEtienne Carriere rc = TEE_ERROR_GENERIC; 324c99311c8SEtienne Carriere goto out; 325f3c22059SEtienne Carriere } 326f3c22059SEtienne Carriere 327c99311c8SEtienne Carriere if (!rc) { 328c99311c8SEtienne Carriere out_size += sz; 329c99311c8SEtienne Carriere out_ptr += sz; 330c99311c8SEtienne Carriere /* Re-arm timeout */ 3310817aa6fSGatien Chevallier timeout_ref = timeout_init_us(RNG_READY_TIMEOUT_US); 332c99311c8SEtienne Carriere burst_timeout = false; 333c99311c8SEtienne Carriere } 334c99311c8SEtienne Carriere } 335c99311c8SEtienne Carriere 336c99311c8SEtienne Carriere out: 337c99311c8SEtienne Carriere assert(!rc || rc == TEE_ERROR_GENERIC); 338f63f11bdSGatien Chevallier clk_disable(stm32_rng->clock); 339f3c22059SEtienne Carriere 340f3c22059SEtienne Carriere return rc; 341f3c22059SEtienne Carriere } 342f3c22059SEtienne Carriere 343cd451498SEtienne Carriere #ifdef CFG_WITH_SOFTWARE_PRNG 344cd451498SEtienne Carriere /* Override weak plat_rng_init with platform handler to seed PRNG */ 345cd451498SEtienne Carriere void plat_rng_init(void) 346cd451498SEtienne Carriere { 347cd451498SEtienne Carriere uint8_t seed[RNG_FIFO_BYTE_DEPTH] = { }; 348cd451498SEtienne Carriere 349cd451498SEtienne Carriere if (stm32_rng_read(seed, sizeof(seed))) 350cd451498SEtienne Carriere panic(); 351cd451498SEtienne Carriere 352cd451498SEtienne Carriere if (crypto_rng_init(seed, sizeof(seed))) 353cd451498SEtienne Carriere panic(); 354cd451498SEtienne Carriere 355cd451498SEtienne Carriere DMSG("PRNG seeded with RNG"); 356cd451498SEtienne Carriere } 357cd451498SEtienne Carriere #else 358cb2478efSAndrew Davis TEE_Result hw_get_random_bytes(void *out, size_t size) 359097f329aSEtienne Carriere { 360097f329aSEtienne Carriere return stm32_rng_read(out, size); 361097f329aSEtienne Carriere } 362097f329aSEtienne Carriere #endif 363097f329aSEtienne Carriere 364f3c22059SEtienne Carriere #ifdef CFG_EMBED_DTB 365ea8ba295SGatien Chevallier static TEE_Result stm32_rng_parse_fdt(const void *fdt, int node) 366f3c22059SEtienne Carriere { 367d7a1a7d2SEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 368ea8ba295SGatien Chevallier struct dt_node_info dt_rng = { }; 369f3c22059SEtienne Carriere 370ea8ba295SGatien Chevallier _fdt_fill_device_info(fdt, &dt_rng, node); 371ea8ba295SGatien Chevallier if (dt_rng.reg == DT_INFO_INVALID_REG) 372ea8ba295SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS; 373f3c22059SEtienne Carriere 374ea8ba295SGatien Chevallier stm32_rng->base.pa = dt_rng.reg; 375ea8ba295SGatien Chevallier stm32_rng->base.va = io_pa_or_va_secure(&stm32_rng->base, 376ea8ba295SGatien Chevallier dt_rng.reg_size); 377ea8ba295SGatien Chevallier assert(stm32_rng->base.va); 378f3c22059SEtienne Carriere 379ea8ba295SGatien Chevallier res = rstctrl_dt_get_by_index(fdt, node, 0, &stm32_rng->rstctrl); 380ea8ba295SGatien Chevallier if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND) 381ea8ba295SGatien Chevallier return res; 38268c4a16bSEtienne Carriere 383d7a1a7d2SEtienne Carriere res = clk_dt_get_by_index(fdt, node, 0, &stm32_rng->clock); 384d7a1a7d2SEtienne Carriere if (res) 385d7a1a7d2SEtienne Carriere return res; 386d7a1a7d2SEtienne Carriere 387ea8ba295SGatien Chevallier /* Release device if not used at runtime or for pm transitions */ 388ea8ba295SGatien Chevallier stm32_rng->release_post_boot = IS_ENABLED(CFG_WITH_SOFTWARE_PRNG) && 389ea8ba295SGatien Chevallier !IS_ENABLED(CFG_PM); 390f3c22059SEtienne Carriere 391f3c22059SEtienne Carriere return TEE_SUCCESS; 392f3c22059SEtienne Carriere } 393f3c22059SEtienne Carriere 394ea8ba295SGatien Chevallier static TEE_Result stm32_rng_probe(const void *fdt, int offs, 395ea8ba295SGatien Chevallier const void *compat_data __unused) 396ea8ba295SGatien Chevallier { 397ea8ba295SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 398ea8ba295SGatien Chevallier 399ea8ba295SGatien Chevallier /* Expect a single RNG instance */ 400ea8ba295SGatien Chevallier assert(!stm32_rng); 401ea8ba295SGatien Chevallier 402ea8ba295SGatien Chevallier stm32_rng = calloc(1, sizeof(*stm32_rng)); 403ea8ba295SGatien Chevallier if (!stm32_rng) 404ea8ba295SGatien Chevallier panic(); 405ea8ba295SGatien Chevallier 406ea8ba295SGatien Chevallier res = stm32_rng_parse_fdt(fdt, offs); 407ea8ba295SGatien Chevallier if (res) 408ea8ba295SGatien Chevallier goto err; 409ea8ba295SGatien Chevallier 410*091ef005SGatien Chevallier stm32_rng->ddata = compat_data; 411*091ef005SGatien Chevallier assert(stm32_rng->ddata); 412*091ef005SGatien Chevallier 413ea8ba295SGatien Chevallier res = clk_enable(stm32_rng->clock); 414ea8ba295SGatien Chevallier if (res) 415ea8ba295SGatien Chevallier goto err; 416ea8ba295SGatien Chevallier 417ea8ba295SGatien Chevallier if (stm32_rng->rstctrl && 418ea8ba295SGatien Chevallier rstctrl_assert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) { 419ea8ba295SGatien Chevallier res = TEE_ERROR_GENERIC; 420ea8ba295SGatien Chevallier goto err_clk; 421ea8ba295SGatien Chevallier } 422ea8ba295SGatien Chevallier 423ea8ba295SGatien Chevallier if (stm32_rng->rstctrl && 424ea8ba295SGatien Chevallier rstctrl_deassert_to(stm32_rng->rstctrl, RNG_RESET_TIMEOUT_US)) { 425ea8ba295SGatien Chevallier res = TEE_ERROR_GENERIC; 426ea8ba295SGatien Chevallier goto err_clk; 427ea8ba295SGatien Chevallier } 428ea8ba295SGatien Chevallier 429f63f11bdSGatien Chevallier res = init_rng(); 430f63f11bdSGatien Chevallier if (res) 431f63f11bdSGatien Chevallier goto err_clk; 432f63f11bdSGatien Chevallier 433ea8ba295SGatien Chevallier clk_disable(stm32_rng->clock); 434ea8ba295SGatien Chevallier 435ea8ba295SGatien Chevallier if (stm32_rng->release_post_boot) 436ea8ba295SGatien Chevallier stm32mp_register_non_secure_periph_iomem(stm32_rng->base.pa); 437ea8ba295SGatien Chevallier else 438ea8ba295SGatien Chevallier stm32mp_register_secure_periph_iomem(stm32_rng->base.pa); 439ea8ba295SGatien Chevallier 440ea8ba295SGatien Chevallier return TEE_SUCCESS; 441ea8ba295SGatien Chevallier 442ea8ba295SGatien Chevallier err_clk: 443ea8ba295SGatien Chevallier clk_disable(stm32_rng->clock); 444ea8ba295SGatien Chevallier err: 445ea8ba295SGatien Chevallier free(stm32_rng); 446ea8ba295SGatien Chevallier stm32_rng = NULL; 447ea8ba295SGatien Chevallier 448ea8ba295SGatien Chevallier return res; 449ea8ba295SGatien Chevallier } 450ea8ba295SGatien Chevallier 451*091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp13_data[] = { 452*091ef005SGatien Chevallier { .has_cond_reset = true }, 453*091ef005SGatien Chevallier }; 454*091ef005SGatien Chevallier 455*091ef005SGatien Chevallier static const struct stm32_rng_driver_data mp15_data[] = { 456*091ef005SGatien Chevallier { .has_cond_reset = false }, 457*091ef005SGatien Chevallier }; 458*091ef005SGatien Chevallier DECLARE_KEEP_PAGER(mp15_data); 459*091ef005SGatien Chevallier 460ea8ba295SGatien Chevallier static const struct dt_device_match rng_match_table[] = { 461*091ef005SGatien Chevallier { .compatible = "st,stm32-rng", .compat_data = &mp15_data }, 462*091ef005SGatien Chevallier { .compatible = "st,stm32mp13-rng", .compat_data = &mp13_data }, 463ea8ba295SGatien Chevallier { } 464ea8ba295SGatien Chevallier }; 465ea8ba295SGatien Chevallier 466ea8ba295SGatien Chevallier DEFINE_DT_DRIVER(stm32_rng_dt_driver) = { 467ea8ba295SGatien Chevallier .name = "stm32_rng", 468ea8ba295SGatien Chevallier .match_table = rng_match_table, 469ea8ba295SGatien Chevallier .probe = stm32_rng_probe, 470ea8ba295SGatien Chevallier }; 471d8682c4cSEtienne Carriere 472d8682c4cSEtienne Carriere static TEE_Result stm32_rng_release(void) 473d8682c4cSEtienne Carriere { 474d8682c4cSEtienne Carriere if (stm32_rng && stm32_rng->release_post_boot) { 475d8682c4cSEtienne Carriere DMSG("Release RNG driver"); 476d8682c4cSEtienne Carriere free(stm32_rng); 477d8682c4cSEtienne Carriere stm32_rng = NULL; 478d8682c4cSEtienne Carriere } 479d8682c4cSEtienne Carriere 480d8682c4cSEtienne Carriere return TEE_SUCCESS; 481d8682c4cSEtienne Carriere } 482d8682c4cSEtienne Carriere 483d8682c4cSEtienne Carriere release_init_resource(stm32_rng_release); 484f3c22059SEtienne Carriere #endif /*CFG_EMBED_DTB*/ 485