1 /* 2 * Copyright (c) 2022, STMicroelectronics - All Rights Reserved 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <errno.h> 9 #include <stdbool.h> 10 11 #include <arch_helpers.h> 12 #include <drivers/clk.h> 13 #include <drivers/delay_timer.h> 14 #include <drivers/st/stm32_rng.h> 15 #include <drivers/st/stm32mp_reset.h> 16 #include <lib/mmio.h> 17 #include <libfdt.h> 18 19 #include <platform_def.h> 20 21 #if STM32_RNG_VER == 2 22 #define DT_RNG_COMPAT "st,stm32-rng" 23 #endif 24 #if STM32_RNG_VER == 4 25 #define DT_RNG_COMPAT "st,stm32mp13-rng" 26 #endif 27 #define RNG_CR 0x00U 28 #define RNG_SR 0x04U 29 #define RNG_DR 0x08U 30 31 #define RNG_CR_RNGEN BIT(2) 32 #define RNG_CR_IE BIT(3) 33 #define RNG_CR_CED BIT(5) 34 #define RNG_CR_CLKDIV GENMASK(19, 16) 35 #define RNG_CR_CLKDIV_SHIFT 16U 36 #define RNG_CR_CONDRST BIT(30) 37 38 #define RNG_SR_DRDY BIT(0) 39 #define RNG_SR_CECS BIT(1) 40 #define RNG_SR_SECS BIT(2) 41 #define RNG_SR_CEIS BIT(5) 42 #define RNG_SR_SEIS BIT(6) 43 44 #define RNG_TIMEOUT_US 100000U 45 #define RNG_TIMEOUT_STEP_US 10U 46 47 #define TIMEOUT_US_1MS 1000U 48 49 #define RNG_NIST_CONFIG_A 0x00F40F00U 50 #define RNG_NIST_CONFIG_B 0x01801000U 51 #define RNG_NIST_CONFIG_C 0x00F00D00U 52 #define RNG_NIST_CONFIG_MASK GENMASK(25, 8) 53 54 #define RNG_MAX_NOISE_CLK_FREQ 48000000U 55 56 struct stm32_rng_instance { 57 uintptr_t base; 58 unsigned long clock; 59 }; 60 61 static struct stm32_rng_instance stm32_rng; 62 63 static void seed_error_recovery(void) 64 { 65 uint8_t i __maybe_unused; 66 67 /* Recommended by the SoC reference manual */ 68 mmio_clrbits_32(stm32_rng.base + RNG_SR, RNG_SR_SEIS); 69 dmbsy(); 70 71 #if STM32_RNG_VER == 2 72 /* No Auto-reset on version 2, need to clean FIFO */ 73 for (i = 12U; i != 0U; i--) { 74 (void)mmio_read_32(stm32_rng.base + RNG_DR); 75 } 76 77 dmbsy(); 78 #endif 79 80 if ((mmio_read_32(stm32_rng.base + RNG_SR) & RNG_SR_SEIS) != 0U) { 81 ERROR("RNG noise\n"); 82 panic(); 83 } 84 } 85 86 static uint32_t stm32_rng_clock_freq_restrain(void) 87 { 88 unsigned long clock_rate; 89 uint32_t clock_div = 0U; 90 91 clock_rate = clk_get_rate(stm32_rng.clock); 92 93 /* 94 * Get the exponent to apply on the CLKDIV field in RNG_CR register 95 * No need to handle the case when clock-div > 0xF as it is physically 96 * impossible 97 */ 98 while ((clock_rate >> clock_div) > RNG_MAX_NOISE_CLK_FREQ) { 99 clock_div++; 100 } 101 102 VERBOSE("RNG clk rate : %lu\n", clk_get_rate(stm32_rng.clock) >> clock_div); 103 104 return clock_div; 105 } 106 107 static int stm32_rng_enable(void) 108 { 109 uint32_t sr; 110 uint64_t timeout; 111 uint32_t clock_div __maybe_unused; 112 113 #if STM32_RNG_VER == 2 114 mmio_write_32(stm32_rng.base + RNG_CR, RNG_CR_RNGEN | RNG_CR_CED); 115 #endif 116 #if STM32_RNG_VER == 4 117 /* Reset internal block and disable CED bit */ 118 clock_div = stm32_rng_clock_freq_restrain(); 119 120 /* Update configuration fields */ 121 mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_NIST_CONFIG_MASK, 122 RNG_NIST_CONFIG_A | RNG_CR_CONDRST | RNG_CR_CED); 123 124 mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_CR_CLKDIV, 125 (clock_div << RNG_CR_CLKDIV_SHIFT)); 126 127 mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_CR_CONDRST, RNG_CR_RNGEN); 128 #endif 129 timeout = timeout_init_us(RNG_TIMEOUT_US); 130 sr = mmio_read_32(stm32_rng.base + RNG_SR); 131 while ((sr & RNG_SR_DRDY) == 0U) { 132 if (timeout_elapsed(timeout)) { 133 WARN("Timeout waiting\n"); 134 return -ETIMEDOUT; 135 } 136 137 if ((sr & (RNG_SR_SECS | RNG_SR_SEIS)) != 0U) { 138 seed_error_recovery(); 139 timeout = timeout_init_us(RNG_TIMEOUT_US); 140 } 141 142 udelay(RNG_TIMEOUT_STEP_US); 143 sr = mmio_read_32(stm32_rng.base + RNG_SR); 144 } 145 146 VERBOSE("Init RNG done\n"); 147 148 return 0; 149 } 150 151 /* 152 * stm32_rng_read - Read a number of random bytes from RNG 153 * out: pointer to the output buffer 154 * size: number of bytes to be read 155 * Return 0 on success, non-0 on failure 156 */ 157 int stm32_rng_read(uint8_t *out, uint32_t size) 158 { 159 uint8_t *buf = out; 160 size_t len = size; 161 int nb_tries; 162 uint32_t data32; 163 int rc = 0; 164 unsigned int count; 165 166 if (stm32_rng.base == 0U) { 167 return -EPERM; 168 } 169 170 while (len != 0U) { 171 nb_tries = RNG_TIMEOUT_US / RNG_TIMEOUT_STEP_US; 172 do { 173 uint32_t status = mmio_read_32(stm32_rng.base + RNG_SR); 174 175 if ((status & (RNG_SR_SECS | RNG_SR_SEIS)) != 0U) { 176 seed_error_recovery(); 177 } 178 179 udelay(RNG_TIMEOUT_STEP_US); 180 nb_tries--; 181 if (nb_tries == 0) { 182 rc = -ETIMEDOUT; 183 goto bail; 184 } 185 } while ((mmio_read_32(stm32_rng.base + RNG_SR) & 186 RNG_SR_DRDY) == 0U); 187 188 count = 4U; 189 while (len != 0U) { 190 data32 = mmio_read_32(stm32_rng.base + RNG_DR); 191 count--; 192 193 memcpy(buf, &data32, MIN(len, sizeof(uint32_t))); 194 buf += MIN(len, sizeof(uint32_t)); 195 len -= MIN(len, sizeof(uint32_t)); 196 197 if (count == 0U) { 198 break; 199 } 200 } 201 } 202 203 bail: 204 if (rc != 0) { 205 memset(out, 0, buf - out); 206 } 207 208 return rc; 209 } 210 211 /* 212 * stm32_rng_init: Initialize rng from DT 213 * return 0 on success, negative value on failure 214 */ 215 int stm32_rng_init(void) 216 { 217 void *fdt; 218 struct dt_node_info dt_rng; 219 int node; 220 221 if (stm32_rng.base != 0U) { 222 /* Driver is already initialized */ 223 return 0; 224 } 225 226 if (fdt_get_address(&fdt) == 0) { 227 panic(); 228 } 229 230 node = dt_get_node(&dt_rng, -1, DT_RNG_COMPAT); 231 if (node < 0) { 232 return 0; 233 } 234 235 if (dt_rng.status == DT_DISABLED) { 236 return 0; 237 } 238 239 assert(dt_rng.base != 0U); 240 241 stm32_rng.base = dt_rng.base; 242 243 if (dt_rng.clock < 0) { 244 panic(); 245 } 246 247 stm32_rng.clock = (unsigned long)dt_rng.clock; 248 clk_enable(stm32_rng.clock); 249 250 if (dt_rng.reset >= 0) { 251 int ret; 252 253 ret = stm32mp_reset_assert((unsigned long)dt_rng.reset, 254 TIMEOUT_US_1MS); 255 if (ret != 0) { 256 panic(); 257 } 258 259 udelay(20); 260 261 ret = stm32mp_reset_deassert((unsigned long)dt_rng.reset, 262 TIMEOUT_US_1MS); 263 if (ret != 0) { 264 panic(); 265 } 266 } 267 268 return stm32_rng_enable(); 269 } 270