diff --git a/drivers/clock_control/clock_control_esp32.c b/drivers/clock_control/clock_control_esp32.c index 199e0d5357a..766076544d5 100644 --- a/drivers/clock_control/clock_control_esp32.c +++ b/drivers/clock_control/clock_control_esp32.c @@ -20,6 +20,7 @@ #include #include #include "clock_control_esp32.h" +#include "driver/periph_ctrl.h" struct esp32_clock_config { uint32_t clk_src_sel; @@ -176,6 +177,16 @@ static inline uint32_t clk_val_to_reg_val(uint32_t val) return (val & UINT16_MAX) | ((val & UINT16_MAX) << 16); } +int IRAM_ATTR esp_clk_cpu_freq(void) +{ + return MHZ(esp32_rom_g_ticks_per_us_pro); +} + +int IRAM_ATTR esp_clk_apb_freq(void) +{ + return MHZ(MIN(esp32_rom_g_ticks_per_us_pro, 80)); +} + void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us) { /* Update scale factors used by ets_delay_us */ @@ -326,6 +337,9 @@ static int clock_control_esp32_init(const struct device *dev) return -EINVAL; } + /* Enable RNG clock. */ + periph_module_enable(PERIPH_RNG_MODULE); + /* Re-calculate the CCOUNT register value to make time calculation correct. * This should be updated on each frequency change * New CCOUNT = Current CCOUNT * (new freq / old freq) diff --git a/drivers/clock_control/clock_control_esp32.h b/drivers/clock_control/clock_control_esp32.h index d95327d7026..76da35adffb 100644 --- a/drivers/clock_control/clock_control_esp32.h +++ b/drivers/clock_control/clock_control_esp32.h @@ -18,15 +18,6 @@ #define I2C_READREG_RTC(block, reg_add) \ esp32_rom_i2c_readReg(block, block##_HOSTID, reg_add) - -# define XTHAL_GET_CCOUNT() ({ int __ccount; \ - __asm__ __volatile__ ("rsr.ccount %0" : "=a" (__ccount)); \ - __ccount; }) - -# define XTHAL_SET_CCOUNT(v) do { int __ccount = (int)(v); \ - __asm__ __volatile__ ("wsr.ccount %0" : : "a" (__ccount) : "memory"); \ - } while (0) - /* * Get voltage level for CPU to run at 240 MHz, or for flash/PSRAM to run at 80 MHz. * 0x0: level 7; 0x1: level 6; 0x2: level 5; 0x3: level 4. (RO) diff --git a/drivers/entropy/Kconfig.esp32 b/drivers/entropy/Kconfig.esp32 index d680708d948..21d4cacadf7 100644 --- a/drivers/entropy/Kconfig.esp32 +++ b/drivers/entropy/Kconfig.esp32 @@ -7,6 +7,7 @@ config ENTROPY_ESP32_RNG bool "ESP32 entropy number generator driver" depends on SOC_ESP32 select ENTROPY_HAS_DRIVER + default y help This option enables the entropy number generator for ESP32 SoCs. diff --git a/drivers/entropy/entropy_esp32.c b/drivers/entropy/entropy_esp32.c index f8751059aa0..f3c235a1097 100644 --- a/drivers/entropy/entropy_esp32.c +++ b/drivers/entropy/entropy_esp32.c @@ -8,41 +8,53 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + +extern int esp_clk_cpu_freq(void); +extern int esp_clk_apb_freq(void); static inline uint32_t entropy_esp32_get_u32(void) { - /* - * APB Address: 0x60035144 (Safe,slower writes) - * DPORT Address: 0x3ff75144 (write bug, fast writes) - * In this case it won't make a difference because it is read only - * More info available at: - * https://www.esp32.com/viewtopic.php?f=2&t=3033&p=14227 - * also check: ECO and Workarounds for Bugs Document, point 3.3 + /* The PRNG which implements WDEV_RANDOM register gets 2 bits + * of extra entropy from a hardware randomness source every APB clock cycle + * (provided WiFi or BT are enabled). To make sure entropy is not drained + * faster than it is added, this function needs to wait for at least 16 APB + * clock cycles after reading previous word. This implementation may actually + * wait a bit longer due to extra time spent in arithmetic and branch statements. */ - volatile uint32_t *rng_data_reg = (uint32_t *)DT_INST_REG_ADDR(0); - /* Read just once. This is not optimal as the generator has - * limited throughput due to scarce sources of entropy, specially - * with the radios turned off. Might want to revisit this. - */ - return *rng_data_reg; + uint32_t cpu_to_apb_freq_ratio = + esp_clk_cpu_freq() / esp_clk_apb_freq(); + + static uint32_t last_ccount; + uint32_t ccount; + + do { + ccount = XTHAL_GET_CCOUNT(); + } while (ccount - last_ccount < cpu_to_apb_freq_ratio * 16); + last_ccount = ccount; + return REG_READ(WDEV_RND_REG); } -static int entropy_esp32_get_entropy(const struct device *device, - uint8_t *buf, uint16_t len) +static int entropy_esp32_get_entropy(const struct device *device, uint8_t *buf, + uint16_t len) { - while (len) { - uint32_t v = entropy_esp32_get_u32(); + assert(buf != NULL); + uint8_t *buf_bytes = (uint8_t *)buf; - if (len >= sizeof(v)) { - memcpy(buf, &v, sizeof(v)); + while (len > 0) { + uint32_t word = entropy_esp32_get_u32(); + uint32_t to_copy = MIN(sizeof(word), len); - buf += sizeof(v); - len -= sizeof(v); - } else { - memcpy(buf, &v, len); - break; - } + memcpy(buf_bytes, &word, to_copy); + buf_bytes += to_copy; + len -= to_copy; } return 0; @@ -50,10 +62,11 @@ static int entropy_esp32_get_entropy(const struct device *device, static int entropy_esp32_init(const struct device *device) { + /* clock initialization handled by clock manager */ return 0; } -static struct entropy_driver_api entropy_esp32_api_funcs = { +static const struct entropy_driver_api entropy_esp32_api_funcs = { .get_entropy = entropy_esp32_get_entropy }; diff --git a/include/arch/xtensa/xtensa_api.h b/include/arch/xtensa/xtensa_api.h index 67cd578deb8..324d9a36e26 100644 --- a/include/arch/xtensa/xtensa_api.h +++ b/include/arch/xtensa/xtensa_api.h @@ -7,6 +7,7 @@ #define ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_API_H_ #include +#include #include "xtensa_rtos.h" #include "xtensa_context.h"