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 if ((mmio_read_32(stm32_rng.base + RNG_SR) & RNG_SR_DRDY) == 0U) { 191 break; 192 } 193 194 data32 = mmio_read_32(stm32_rng.base + RNG_DR); 195 count--; 196 197 memcpy(buf, &data32, MIN(len, sizeof(uint32_t))); 198 buf += MIN(len, sizeof(uint32_t)); 199 len -= MIN(len, sizeof(uint32_t)); 200 201 if (count == 0U) { 202 break; 203 } 204 } 205 } 206 207 bail: 208 if (rc != 0) { 209 memset(out, 0, buf - out); 210 } 211 212 return rc; 213 } 214 215 /* 216 * stm32_rng_init: Initialize rng from DT 217 * return 0 on success, negative value on failure 218 */ 219 int stm32_rng_init(void) 220 { 221 void *fdt; 222 struct dt_node_info dt_rng; 223 int node; 224 225 if (stm32_rng.base != 0U) { 226 /* Driver is already initialized */ 227 return 0; 228 } 229 230 if (fdt_get_address(&fdt) == 0) { 231 panic(); 232 } 233 234 node = dt_get_node(&dt_rng, -1, DT_RNG_COMPAT); 235 if (node < 0) { 236 return 0; 237 } 238 239 if (dt_rng.status == DT_DISABLED) { 240 return 0; 241 } 242 243 assert(dt_rng.base != 0U); 244 245 stm32_rng.base = dt_rng.base; 246 247 if (dt_rng.clock < 0) { 248 panic(); 249 } 250 251 stm32_rng.clock = (unsigned long)dt_rng.clock; 252 clk_enable(stm32_rng.clock); 253 254 if (dt_rng.reset >= 0) { 255 int ret; 256 257 ret = stm32mp_reset_assert((unsigned long)dt_rng.reset, 258 TIMEOUT_US_1MS); 259 if (ret != 0) { 260 panic(); 261 } 262 263 udelay(20); 264 265 ret = stm32mp_reset_deassert((unsigned long)dt_rng.reset, 266 TIMEOUT_US_1MS); 267 if (ret != 0) { 268 panic(); 269 } 270 } 271 272 return stm32_rng_enable(); 273 } 274