1 /*
2  * Copyright (c) 2017 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT espressif_esp32_trng
8 
9 #include <string.h>
10 #include <soc/rtc.h>
11 #include <soc/wdev_reg.h>
12 #include <soc/rtc_cntl_reg.h>
13 #include <soc/apb_ctrl_reg.h>
14 #include <esp_system.h>
15 #include <soc.h>
16 #include <hal/cpu_hal.h>
17 #include <zephyr/drivers/entropy.h>
18 
entropy_esp32_get_u32(void)19 static inline uint32_t entropy_esp32_get_u32(void)
20 {
21 	/* The PRNG which implements WDEV_RANDOM register gets 2 bits
22 	 * of extra entropy from a hardware randomness source every APB clock cycle
23 	 * (provided WiFi or BT are enabled). To make sure entropy is not drained
24 	 * faster than it is added, this function needs to wait for at least 16 APB
25 	 * clock cycles after reading previous word. This implementation may actually
26 	 * wait a bit longer due to extra time spent in arithmetic and branch statements.
27 	 */
28 
29 	uint32_t cpu_to_apb_freq_ratio =
30 		esp_clk_cpu_freq() / esp_clk_apb_freq();
31 
32 	static uint32_t last_ccount;
33 	uint32_t ccount;
34 
35 	do {
36 		ccount = cpu_hal_get_cycle_count();
37 	} while (ccount - last_ccount < cpu_to_apb_freq_ratio * 16);
38 	last_ccount = ccount;
39 
40 	return REG_READ(WDEV_RND_REG);
41 }
42 
entropy_esp32_get_entropy(const struct device * dev,uint8_t * buf,uint16_t len)43 static int entropy_esp32_get_entropy(const struct device *dev, uint8_t *buf,
44 				     uint16_t len)
45 {
46 	assert(buf != NULL);
47 	uint8_t *buf_bytes = (uint8_t *)buf;
48 
49 	while (len > 0) {
50 		uint32_t word = entropy_esp32_get_u32();
51 		uint32_t to_copy = MIN(sizeof(word), len);
52 
53 		memcpy(buf_bytes, &word, to_copy);
54 		buf_bytes += to_copy;
55 		len -= to_copy;
56 	}
57 
58 	return 0;
59 }
60 
entropy_esp32_init(const struct device * dev)61 static int entropy_esp32_init(const struct device *dev)
62 {
63 	/* clock initialization handled by clock manager */
64 	return 0;
65 }
66 
67 static const struct entropy_driver_api entropy_esp32_api_funcs = {
68 	.get_entropy = entropy_esp32_get_entropy
69 };
70 
71 DEVICE_DT_INST_DEFINE(0,
72 		    entropy_esp32_init, NULL, NULL, NULL,
73 		    PRE_KERNEL_1, CONFIG_ENTROPY_INIT_PRIORITY,
74 		    &entropy_esp32_api_funcs);
75