From b0e2f3308275cba6a668e0b10bc10f725b662dbd Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Fri, 10 Feb 2023 14:13:20 +0800 Subject: [PATCH] esp_hw_support/bootloader: made ESP32-C6 and ESP32-H2 RNG available --- .../src/bootloader_random.c | 42 ++++++++- .../src/bootloader_random_esp32c6.c | 89 +++++++++++++++++-- .../src/bootloader_random_esp32h2.c | 79 ++++++++++++++-- components/esp_hw_support/CMakeLists.txt | 4 + components/esp_hw_support/hw_random.c | 38 ++++++++ components/hal/CMakeLists.txt | 4 + .../soc/esp32h2/include/soc/regi2c_saradc.h | 28 ++++++ 7 files changed, 270 insertions(+), 14 deletions(-) diff --git a/components/bootloader_support/src/bootloader_random.c b/components/bootloader_support/src/bootloader_random.c index f89badc4e7..c3abdcc92a 100644 --- a/components/bootloader_support/src/bootloader_random.c +++ b/components/bootloader_support/src/bootloader_random.c @@ -8,6 +8,10 @@ #include "esp_cpu.h" #include "soc/wdev_reg.h" +#if defined CONFIG_IDF_TARGET_ESP32C6 +#include "hal/lp_timer_hal.h" +#endif + #ifndef BOOTLOADER_BUILD #include "esp_random.h" #include "esp_private/periph_ctrl.h" @@ -20,9 +24,27 @@ #else #if !defined CONFIG_IDF_TARGET_ESP32S3 -#define RNG_CPU_WAIT_CYCLE_NUM (80 * 32 * 2) /* extra factor of 2 is precautionary */ + #if (defined CONFIG_IDF_TARGET_ESP32C6 || defined CONFIG_IDF_TARGET_ESP32H2) + #define RNG_CPU_WAIT_CYCLE_NUM (80 * 12) // higher frequency because we are reading bytes instead of words + #else + #define RNG_CPU_WAIT_CYCLE_NUM (80 * 32 * 2) /* extra factor of 2 is precautionary */ + #endif #else -#define RNG_CPU_WAIT_CYCLE_NUM (80 * 23) /* 45 KHz reading frequency is the maximum we have tested so far on S3 */ + #define RNG_CPU_WAIT_CYCLE_NUM (80 * 23) /* 45 KHz reading frequency is the maximum we have tested so far on S3 */ +#endif + +#if defined CONFIG_IDF_TARGET_ESP32H2 + +// TODO: temporary definition until IDF-6270 is implemented +#include "soc/lp_timer_reg.h" + +static inline uint32_t lp_timer_hal_get_cycle_count(void) +{ + REG_SET_BIT(LP_TIMER_UPDATE_REG, LP_TIMER_MAIN_TIMER_UPDATE); + + uint32_t lo = REG_GET_FIELD(LP_TIMER_MAIN_BUF0_LOW_REG, LP_TIMER_MAIN_TIMER_BUF0_LOW); + return lo; +} #endif __attribute__((weak)) void bootloader_fill_random(void *buffer, size_t length) @@ -34,6 +56,21 @@ assert(buffer != NULL); for (size_t i = 0; i < length; i++) { +#if (defined CONFIG_IDF_TARGET_ESP32C6 || defined CONFIG_IDF_TARGET_ESP32H2) + random = REG_READ(WDEV_RND_REG); + start = esp_cpu_get_cycle_count(); + do { + random ^= REG_READ(WDEV_RND_REG); + now = esp_cpu_get_cycle_count(); + } while (now - start < RNG_CPU_WAIT_CYCLE_NUM); + + // XOR the RT slow clock, which is asynchronous, to add some entropy and improve + // the distribution + uint32_t current_rtc_timer_counter = (lp_timer_hal_get_cycle_count() & 0xFF); + random = random ^ current_rtc_timer_counter; + + buffer_bytes[i] = random & 0xFF; +#else if (i == 0 || i % 4 == 0) { /* redundant check is for a compiler warning */ /* in bootloader with ADC feeding HWRNG, we accumulate 1 bit of entropy per 40 APB cycles (==80 CPU cycles.) @@ -50,6 +87,7 @@ } while (now - start < RNG_CPU_WAIT_CYCLE_NUM); } buffer_bytes[i] = random >> ((i % 4) * 8); +#endif } } diff --git a/components/bootloader_support/src/bootloader_random_esp32c6.c b/components/bootloader_support/src/bootloader_random_esp32c6.c index 378e84744e..682e48544c 100644 --- a/components/bootloader_support/src/bootloader_random_esp32c6.c +++ b/components/bootloader_support/src/bootloader_random_esp32c6.c @@ -1,22 +1,99 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "sdkconfig.h" #include "bootloader_random.h" +#include "soc/soc.h" +#include "soc/pcr_reg.h" +#include "soc/apb_saradc_reg.h" +#include "soc/pmu_reg.h" +#include "hal/regi2c_ctrl.h" +#include "soc/regi2c_saradc.h" #include "esp_log.h" -static const char *TAG = "bootloader_random"; +static const uint32_t SAR2_CHANNEL = 9; +static const uint32_t PATTERN_BIT_WIDTH = 6; +static const uint32_t SAR1_ATTEN = 1; +static const uint32_t SAR2_ATTEN = 1; void bootloader_random_enable(void) { - // TODO: IDF-5352 - ESP_EARLY_LOGW(TAG, "bootloader_random_enable() has not been implemented yet"); + // pull SAR ADC out of reset + REG_SET_BIT(PCR_SARADC_CONF_REG, PCR_SARADC_RST_EN); + REG_CLR_BIT(PCR_SARADC_CONF_REG, PCR_SARADC_RST_EN); + + // enable SAR ADC APB clock + REG_SET_BIT(PCR_SARADC_CONF_REG, PCR_SARADC_REG_CLK_EN); + + // enable ADC_CTRL_CLK (SAR ADC function clock) + REG_SET_BIT(PCR_SARADC_CLKM_CONF_REG, PCR_SARADC_CLKM_EN); + + // select XTAL clock (40 MHz) source for ADC_CTRL_CLK + REG_SET_FIELD(PCR_SARADC_CLKM_CONF_REG, PCR_SARADC_CLKM_SEL, 0); + + // set the clock divider for ADC_CTRL_CLK to default value (in case it has been changed) + REG_SET_FIELD(PCR_SARADC_CLKM_CONF_REG, PCR_SARADC_CLKM_DIV_NUM, 0); + + // some ADC sensor registers are in power group PERIF_I2C and need to be enabled via PMU + SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_PERIF_I2C_RSTB); + SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_PERIF_I2C); + + // Config ADC circuit (Analog part) with I2C(HOST ID 0x69) and chose internal voltage as sampling source + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_DTEST_RTC_ADDR , 2); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_RTC_ADDR , 1); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC1_ENCAL_REF_ADDR, 1); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC2_ENCAL_REF_ADDR, 1); + + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_INITIAL_CODE_HIGH_ADDR, 0x08); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_INITIAL_CODE_LOW_ADDR, 0x66); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_HIGH_ADDR, 0x08); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_LOW_ADDR, 0x66); + + // create patterns and set them in pattern table + uint32_t pattern_one = (SAR2_CHANNEL << 2) | SAR2_ATTEN; // we want channel 9 with max attenuation + uint32_t pattern_two = SAR1_ATTEN; // we want channel 0 with max attenuation, channel doesn't really matter here + uint32_t pattern_table = 0 | (pattern_two << 3 * PATTERN_BIT_WIDTH) | pattern_one << 2 * PATTERN_BIT_WIDTH; + REG_WRITE(APB_SARADC_SAR_PATT_TAB1_REG, pattern_table); + + // set pattern length to 2 (APB_SARADC_SAR_PATT_LEN counts from 0) + REG_SET_FIELD(APB_SARADC_CTRL_REG, APB_SARADC_SARADC_SAR_PATT_LEN, 1); + + // Same as in C3 + REG_SET_FIELD(APB_SARADC_CTRL_REG, APB_SARADC_SARADC_SAR_CLK_DIV, 15); + + // set timer expiry (timer is ADC_CTRL_CLK) + REG_SET_FIELD(APB_SARADC_CTRL2_REG, APB_SARADC_SARADC_TIMER_TARGET, 200); + + // enable timer + REG_SET_BIT(APB_SARADC_CTRL2_REG, APB_SARADC_SARADC_TIMER_EN); } void bootloader_random_disable(void) { - // TODO: IDF-5352 - ESP_EARLY_LOGW(TAG, "bootloader_random_enable() has not been implemented yet"); + // disable timer + REG_CLR_BIT(APB_SARADC_CTRL2_REG, APB_SARADC_SARADC_TIMER_EN); + + // Write reset value of this register + REG_WRITE(APB_SARADC_SAR_PATT_TAB1_REG, 0xFFFFFF); + + // Revert ADC I2C configuration and initial voltage source setting + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_INITIAL_CODE_HIGH_ADDR, 0x60); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_INITIAL_CODE_LOW_ADDR, 0x0); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_HIGH_ADDR, 0x60); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_LOW_ADDR, 0x0); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_DTEST_RTC_ADDR, 0); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_RTC_ADDR, 0); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC1_ENCAL_REF_ADDR, 0); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC2_ENCAL_REF_ADDR, 0); + + // Revert PMU_RF_PWC_REG to it's initial value + CLEAR_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_PERIF_I2C_RSTB); + + // disable ADC_CTRL_CLK (SAR ADC function clock) + REG_WRITE(PCR_SARADC_CLKM_CONF_REG, 0x00404000); + + // Set PCR_SARADC_CONF_REG to initial state + REG_WRITE(PCR_SARADC_CONF_REG, 0x5); } diff --git a/components/bootloader_support/src/bootloader_random_esp32h2.c b/components/bootloader_support/src/bootloader_random_esp32h2.c index 3950a44cf7..0b4e382025 100644 --- a/components/bootloader_support/src/bootloader_random_esp32h2.c +++ b/components/bootloader_support/src/bootloader_random_esp32h2.c @@ -1,21 +1,88 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "sdkconfig.h" #include "bootloader_random.h" +#include "soc/soc.h" +#include "soc/pcr_reg.h" +#include "soc/apb_saradc_reg.h" +#include "soc/pmu_reg.h" +#include "hal/regi2c_ctrl.h" +#include "soc/regi2c_saradc.h" #include "esp_log.h" -static const char *TAG = "bootloader_random"; +static const uint32_t SAR2_CHANNEL = 9; +static const uint32_t PATTERN_BIT_WIDTH = 6; +static const uint32_t SAR1_ATTEN = 1; +static const uint32_t SAR2_ATTEN = 1; + void bootloader_random_enable(void) { - // ESP32H2-TODO: IDF-6274 - ESP_EARLY_LOGW(TAG, "bootloader_random_enable() has not been implemented yet"); + REG_SET_BIT(PCR_SARADC_CONF_REG, PCR_SARADC_RST_EN); + REG_CLR_BIT(PCR_SARADC_CONF_REG, PCR_SARADC_RST_EN); + + REG_SET_BIT(PCR_SARADC_CONF_REG, PCR_SARADC_REG_CLK_EN); + + REG_SET_BIT(PCR_SARADC_CLKM_CONF_REG, PCR_SARADC_CLKM_EN); + + // select XTAL clock (40 MHz) source for ADC_CTRL_CLK + REG_SET_FIELD(PCR_SARADC_CLKM_CONF_REG, PCR_SARADC_CLKM_SEL, 0); + + REG_SET_FIELD(PCR_SARADC_CLKM_CONF_REG, PCR_SARADC_CLKM_DIV_NUM, 0); + + // some ADC sensor registers are in power group PERIF_I2C and need to be enabled via PMU + SET_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_XPD_PERIF_I2C); + + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_DTEST, 0); + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_ENT_SAR, 1); + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_EN_TOUT_SAR1_BUS, 1); + + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_SAR2_INIT_CODE_MSB, 0X08); + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_SAR2_INIT_CODE_LSB, 0X66); + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_SAR1_INIT_CODE_MSB, 0X08); + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_SAR1_INIT_CODE_LSB, 0X66); + + // create patterns and set them in pattern table + uint32_t pattern_one = (SAR2_CHANNEL << 2) | SAR2_ATTEN; + uint32_t pattern_two = SAR1_ATTEN; // we want channel 0 with max attenuation, channel doesn't really matter here + uint32_t pattern_table = 0 | (pattern_two << 3 * PATTERN_BIT_WIDTH) | pattern_one << 2 * PATTERN_BIT_WIDTH; + REG_WRITE(APB_SARADC_SAR_PATT_TAB1_REG, pattern_table); + + // set pattern length to 2 (APB_SARADC_SAR_PATT_LEN counts from 0) + REG_SET_FIELD(APB_SARADC_CTRL_REG, APB_SARADC_SARADC_SAR_PATT_LEN, 0); + + // Same as in C3 + REG_SET_FIELD(APB_SARADC_CTRL_REG, APB_SARADC_SARADC_SAR_CLK_DIV, 15); + + // set timer expiry (timer is ADC_CTRL_CLK) + REG_SET_FIELD(APB_SARADC_CTRL2_REG, APB_SARADC_SARADC_TIMER_TARGET, 200); + + // ENABLE_TIMER + REG_SET_BIT(APB_SARADC_CTRL2_REG, APB_SARADC_SARADC_TIMER_EN); } void bootloader_random_disable(void) { - // ESP32H2-TODO: IDF-6274 - ESP_EARLY_LOGW(TAG, "bootloader_random_disable() has not been implemented yet"); + // disable timer + REG_CLR_BIT(APB_SARADC_CTRL2_REG, APB_SARADC_SARADC_TIMER_EN); + + // Write reset value of this register + REG_WRITE(APB_SARADC_SAR_PATT_TAB1_REG, 0xFFFFFF); + + // Revert ADC I2C configuration and initial voltage source setting + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_SAR2_INIT_CODE_MSB, 0x60); + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_SAR2_INIT_CODE_LSB, 0x0); + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_SAR1_INIT_CODE_MSB, 0x60); + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_SAR1_INIT_CODE_LSB, 0x0); + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_DTEST, 0); + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_ENT_SAR, 0); + REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SARADC_EN_TOUT_SAR1_BUS, 0); + + // disable ADC_CTRL_CLK (SAR ADC function clock) + REG_WRITE(PCR_SARADC_CLKM_CONF_REG, 0x00404000); + + // Set PCR_SARADC_CONF_REG to initial state + REG_WRITE(PCR_SARADC_CONF_REG, 0x5); } diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 9d25fc6f39..2145784ec4 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -12,6 +12,10 @@ set(requires soc) # only esp_hw_support/adc_share_hw_ctrl.c requires efuse component set(priv_requires efuse spi_flash bootloader_support) +if(${target} STREQUAL "esp32c6") + list(APPEND priv_requires hal) +endif() + set(srcs "cpu.c" "esp_memory_utils.c" "port/${IDF_TARGET}/cpu_region_protect.c") if(NOT BOOTLOADER_BUILD) list(APPEND srcs "esp_clk.c" diff --git a/components/esp_hw_support/hw_random.c b/components/esp_hw_support/hw_random.c index 6307163f29..a05cc49094 100644 --- a/components/esp_hw_support/hw_random.c +++ b/components/esp_hw_support/hw_random.c @@ -14,13 +14,40 @@ #include "soc/wdev_reg.h" #include "esp_private/esp_clk.h" +#if defined CONFIG_IDF_TARGET_ESP32C6 +#include "hal/lp_timer_hal.h" +#endif + #if defined CONFIG_IDF_TARGET_ESP32S3 #define APB_CYCLE_WAIT_NUM (1778) /* If APB clock is 80 MHz, maximum sampling frequency is around 45 KHz*/ /* 45 KHz reading frequency is the maximum we have tested so far on S3 */ +#elif defined CONFIG_IDF_TARGET_ESP32C6 +#define APB_CYCLE_WAIT_NUM (160 * 5) /* We want to have a maximum sampling frequency below 50KHz for + * 32-bit samples. But on ESP32C6, we only read one byte at a time, + * hence, the wait time is 4 times lower. The current value translates + * to a sampling frequency of 50 KHz for reading 32 bit samples, + * plus additional overhead for the calculation, making it slower. */ +#elif defined CONFIG_IDF_TARGET_ESP32H2 +#define APB_CYCLE_WAIT_NUM (160 * 3) /* Same reasoning as for ESP32C6, but the CPU frequency on ESP32H2 is + * 96MHz instead of 160 MHz */ #else #define APB_CYCLE_WAIT_NUM (16) #endif +#if defined CONFIG_IDF_TARGET_ESP32H2 + +// TODO: temporary definition until IDF-6270 is implemented +#include "soc/lp_timer_reg.h" + +static uint32_t IRAM_ATTR lp_timer_hal_get_cycle_count(void) +{ + REG_SET_BIT(LP_TIMER_UPDATE_REG, LP_TIMER_MAIN_TIMER_UPDATE); + + uint32_t lo = REG_GET_FIELD(LP_TIMER_MAIN_BUF0_LOW_REG, LP_TIMER_MAIN_TIMER_BUF0_LOW); + return lo; +} +#endif + uint32_t IRAM_ATTR esp_random(void) { /* The PRNG which implements WDEV_RANDOM register gets 2 bits @@ -46,10 +73,21 @@ uint32_t IRAM_ATTR esp_random(void) static uint32_t last_ccount = 0; uint32_t ccount; uint32_t result = 0; +#if (defined CONFIG_IDF_TARGET_ESP32C6 || defined CONFIG_IDF_TARGET_ESP32H2) + for (size_t i = 0; i < sizeof(result); i++) { + do { + ccount = esp_cpu_get_cycle_count(); + result ^= REG_READ(WDEV_RND_REG); + } while (ccount - last_ccount < cpu_to_apb_freq_ratio * APB_CYCLE_WAIT_NUM); + uint32_t current_rtc_timer_counter = (lp_timer_hal_get_cycle_count() & 0xFF); + result ^= ((result ^ current_rtc_timer_counter) & 0xFF) << (i * 8); + } +#else do { ccount = esp_cpu_get_cycle_count(); result ^= REG_READ(WDEV_RND_REG); } while (ccount - last_ccount < cpu_to_apb_freq_ratio * APB_CYCLE_WAIT_NUM); +#endif last_ccount = ccount; return result ^ REG_READ(WDEV_RND_REG); } diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 43f0508f1e..29f7b1edc1 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -25,6 +25,10 @@ if(NOT ${target} STREQUAL "esp32" AND NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP) list(APPEND srcs "cache_hal.c") endif() +if(${target} STREQUAL "esp32c6") + list(APPEND srcs "esp32c6/lp_timer_hal.c") +endif() + if(NOT BOOTLOADER_BUILD) list(APPEND srcs "rtc_io_hal.c" diff --git a/components/soc/esp32h2/include/soc/regi2c_saradc.h b/components/soc/esp32h2/include/soc/regi2c_saradc.h index 87112b2901..7d211bf6aa 100644 --- a/components/soc/esp32h2/include/soc/regi2c_saradc.h +++ b/components/soc/esp32h2/include/soc/regi2c_saradc.h @@ -41,3 +41,31 @@ #define I2C_SARADC_TSENS_DAC 0x6 #define I2C_SARADC_TSENS_DAC_MSB 3 #define I2C_SARADC_TSENS_DAC_LSB 3 + +#define I2C_SARADC_DTEST 7 +#define I2C_SARADC_DTEST_MSB 1 +#define I2C_SARADC_DTEST_LSB 0 + +#define I2C_SARADC_ENT_SAR 7 +#define I2C_SARADC_ENT_SAR_MSB 3 +#define I2C_SARADC_ENT_SAR_LSB 1 + +#define I2C_SARADC_EN_TOUT_SAR1_BUS 7 +#define I2C_SARADC_EN_TOUT_SAR1_BUS_MSB 5 +#define I2C_SARADC_EN_TOUT_SAR1_BUS_LSB 5 + +#define I2C_SARADC_SAR1_INIT_CODE_LSB 0 +#define I2C_SARADC_SAR1_INIT_CODE_LSB_MSB 7 +#define I2C_SARADC_SAR1_INIT_CODE_LSB_LSB 0 + +#define I2C_SARADC_SAR1_INIT_CODE_MSB 1 +#define I2C_SARADC_SAR1_INIT_CODE_MSB_MSB 3 +#define I2C_SARADC_SAR1_INIT_CODE_MSB_LSB 0 + +#define I2C_SARADC_SAR2_INIT_CODE_LSB 3 +#define I2C_SARADC_SAR2_INIT_CODE_LSB_MSB 7 +#define I2C_SARADC_SAR2_INIT_CODE_LSB_LSB 0 + +#define I2C_SARADC_SAR2_INIT_CODE_MSB 4 +#define I2C_SARADC_SAR2_INIT_CODE_MSB_MSB 3 +#define I2C_SARADC_SAR2_INIT_CODE_MSB_LSB 0