esp_hw_support/bootloader: made ESP32-C6 and ESP32-H2 RNG available

This commit is contained in:
Jakob Hasse 2023-02-10 14:13:20 +08:00
parent a8a2b08b4c
commit d3f77ec352
7 changed files with 270 additions and 14 deletions

View File

@ -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,11 +24,29 @@
#else
#if !defined CONFIG_IDF_TARGET_ESP32S3
#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 */
#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)
{
uint8_t *buffer_bytes = (uint8_t *)buffer;
@ -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
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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"

View File

@ -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);
}

View File

@ -26,6 +26,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"

View File

@ -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