diff --git a/components/bootloader_support/src/bootloader_random_esp32c2.c b/components/bootloader_support/src/bootloader_random_esp32c2.c index 507da1c5be..0ad0c4bd33 100644 --- a/components/bootloader_support/src/bootloader_random_esp32c2.c +++ b/components/bootloader_support/src/bootloader_random_esp32c2.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,56 +12,60 @@ #include "soc/system_reg.h" #include "esp_private/regi2c_ctrl.h" #include "soc/regi2c_saradc.h" +#include "hal/adc_ll.h" +#include "hal/sar_ctrl_ll.h" +#include "hal/clk_gate_ll.h" + +#define ADC_RNG_CLKM_DIV_NUM 15 +#define ADC_RNG_CLKM_DIV_B 0 +#define ADC_RNG_CLKM_DIV_A 0 void bootloader_random_enable(void) { - /* RNG module is always clock enabled */ - REG_SET_FIELD(RTC_CNTL_SENSOR_CTRL_REG, RTC_CNTL_FORCE_XPD_SAR, 0x3); + sar_ctrl_ll_set_power_mode(SAR_CTRL_LL_POWER_ON); SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_PU_M); - // Bridging sar2 internal reference voltage - REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC2_ENCAL_REF_ADDR, 1); - 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_SARADC_ENT_TSENS_ADDR, 0); +#ifndef BOOTLOADER_BUILD + regi2c_saradc_enable(); +#else + regi2c_ctrl_ll_i2c_sar_periph_enable(); +#endif + ANALOG_CLOCK_ENABLE(); + adc_ll_regi2c_init(); - // Enable SAR ADC2 internal channel to read adc2 ref voltage for additional entropy - SET_PERI_REG_MASK(SYSTEM_PERIP_CLK_EN0_REG, SYSTEM_APB_SARADC_CLK_EN_M); - CLEAR_PERI_REG_MASK(SYSTEM_PERIP_RST_EN0_REG, SYSTEM_APB_SARADC_RST_M); - REG_SET_FIELD(APB_SARADC_APB_ADC_CLKM_CONF_REG, APB_SARADC_REG_CLK_SEL, 0x2); - SET_PERI_REG_MASK(APB_SARADC_APB_ADC_CLKM_CONF_REG, APB_SARADC_CLK_EN_M); - SET_PERI_REG_MASK(APB_SARADC_CTRL_REG, APB_SARADC_SAR_CLK_GATED_M); - REG_SET_FIELD(APB_SARADC_CTRL_REG, APB_SARADC_XPD_SAR_FORCE, 0x3); - REG_SET_FIELD(APB_SARADC_CTRL_REG, APB_SARADC_SAR_CLK_DIV, 1); + _adc_ll_enable_bus_clock(true); + _adc_ll_reset_register(); + adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_PLL_F80M); + adc_ll_digi_controller_clk_div(ADC_RNG_CLKM_DIV_NUM, ADC_RNG_CLKM_DIV_B, ADC_RNG_CLKM_DIV_A); + adc_ll_digi_set_power_manage(ADC_LL_POWER_SW_ON); + adc_ll_digi_set_clk_div(1); - REG_SET_FIELD(APB_SARADC_FSM_WAIT_REG, APB_SARADC_RSTB_WAIT, 8); - REG_SET_FIELD(APB_SARADC_FSM_WAIT_REG, APB_SARADC_XPD_WAIT, 5); - REG_SET_FIELD(APB_SARADC_FSM_WAIT_REG, APB_SARADC_STANDBY_WAIT, 100); + adc_ll_digi_set_fsm_time(ADC_LL_FSM_RSTB_WAIT_DEFAULT, ADC_LL_FSM_START_WAIT_DEFAULT, + ADC_LL_FSM_STANDBY_WAIT_DEFAULT); - SET_PERI_REG_MASK(APB_SARADC_CTRL_REG, APB_SARADC_SAR_PATT_P_CLEAR_M); - CLEAR_PERI_REG_MASK(APB_SARADC_CTRL_REG, APB_SARADC_SAR_PATT_P_CLEAR_M); - REG_SET_FIELD(APB_SARADC_CTRL_REG, APB_SARADC_SAR_PATT_LEN, 0); - REG_SET_FIELD(APB_SARADC_SAR_PATT_TAB1_REG, APB_SARADC_SAR_PATT_TAB1, 0x9cffff);// Set adc2 internal channel & atten - REG_SET_FIELD(APB_SARADC_SAR_PATT_TAB2_REG, APB_SARADC_SAR_PATT_TAB2, 0xffffff); - // Set ADC sampling frequency - REG_SET_FIELD(APB_SARADC_CTRL2_REG, APB_SARADC_TIMER_TARGET, 100); - REG_SET_FIELD(APB_SARADC_APB_ADC_CLKM_CONF_REG, APB_SARADC_REG_CLKM_DIV_NUM, 15); - CLEAR_PERI_REG_MASK(APB_SARADC_CTRL2_REG, APB_SARADC_MEAS_NUM_LIMIT); - SET_PERI_REG_MASK(APB_SARADC_DMA_CONF_REG, APB_SARADC_APB_ADC_TRANS_M); - SET_PERI_REG_MASK(APB_SARADC_CTRL2_REG, APB_SARADC_TIMER_EN); + adc_digi_pattern_config_t pattern_config = {}; + pattern_config.unit = ADC_UNIT_2; + pattern_config.atten = ADC_ATTEN_DB_12; + pattern_config.channel = ADC_CHANNEL_1; //Use reserved channel 1 to get internal voltage + adc_ll_digi_set_pattern_table(ADC_UNIT_2, 0, pattern_config); + adc_ll_digi_set_pattern_table_len(ADC_UNIT_2, 1); + + + adc_ll_digi_set_trigger_interval(100); + adc_ll_digi_convert_limit_enable(false); + adc_ll_digi_dma_enable(); + adc_ll_digi_trigger_enable(); } void bootloader_random_disable(void) { - /* Restore internal I2C bus state */ - REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC2_ENCAL_REF_ADDR, 0); - - /* Restore SARADC to default mode */ - CLEAR_PERI_REG_MASK(APB_SARADC_CTRL2_REG, APB_SARADC_TIMER_EN); - CLEAR_PERI_REG_MASK(APB_SARADC_DMA_CONF_REG, APB_SARADC_APB_ADC_TRANS_M); - REG_SET_FIELD(APB_SARADC_SAR_PATT_TAB1_REG, APB_SARADC_SAR_PATT_TAB1, 0xffffff); - REG_SET_FIELD(APB_SARADC_SAR_PATT_TAB2_REG, APB_SARADC_SAR_PATT_TAB2, 0xffffff); - CLEAR_PERI_REG_MASK(APB_SARADC_APB_ADC_CLKM_CONF_REG, APB_SARADC_CLK_EN_M); - REG_SET_FIELD(APB_SARADC_CTRL_REG, APB_SARADC_XPD_SAR_FORCE, 0); - REG_SET_FIELD(RTC_CNTL_SENSOR_CTRL_REG, RTC_CNTL_FORCE_XPD_SAR, 0); + _adc_ll_enable_bus_clock(false); + adc_ll_digi_trigger_disable(); + adc_ll_digi_reset_pattern_table(); + adc_ll_regi2c_adc_deinit(); +#ifndef BOOTLOADER_BUILD + regi2c_saradc_disable(); +#endif + // disable analog i2c master clock + ANALOG_CLOCK_DISABLE(); } diff --git a/components/hal/esp32c2/include/hal/adc_ll.h b/components/hal/esp32c2/include/hal/adc_ll.h index 38f129eea9..1cd85c16ca 100644 --- a/components/hal/esp32c2/include/hal/adc_ll.h +++ b/components/hal/esp32c2/include/hal/adc_ll.h @@ -67,6 +67,18 @@ typedef enum { ADC_LL_CTRL_DIG = 0, ///< For ADC1. Select DIG controller. } adc_ll_controller_t; +typedef struct { + union { + struct { + uint8_t atten: 2; + uint8_t channel: 3; + uint8_t unit: 1; + uint8_t reserved: 2; + }; + uint8_t val; + }; +} __attribute__((packed)) adc_ll_digi_pattern_table_t; + /*--------------------------------------------------------------- Digital controller setting ---------------------------------------------------------------*/ @@ -114,6 +126,28 @@ static inline void adc_ll_digi_set_clk_div(uint32_t div) HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.saradc_ctrl, saradc_saradc_sar_clk_div, div); } +/** + * Enable max conversion number detection for digital controller. + * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + * + * @note Only used for bootloader RNG. + * @param enable true: enable; false: disable + */ +static inline void adc_ll_digi_convert_limit_enable(bool enable) +{ + APB_SARADC.saradc_ctrl2.saradc_saradc_meas_num_limit = enable; +} + +/** + * Enable output data to DMA from adc digital controller. + * + * @note Only used for bootloader RNG. + */ +static inline void adc_ll_digi_dma_enable(void) +{ + APB_SARADC.saradc_dma_conf.saradc_apb_adc_trans = 1; +} + /** * Sets the number of cycles required for the conversion to complete and wait for the arbiter to stabilize. * @@ -140,6 +174,39 @@ static inline void adc_ll_digi_output_invert(adc_unit_t adc_n, bool inv_en) } } +/** + * Set the interval clock cycle for the digital controller to trigger the measurement. + * Expression: `trigger_meas_freq` = `controller_clk` / 2 / interval. + * + * @note The trigger interval should not be smaller than the sampling time of the SAR ADC. + * @note Only used for bootloader RNG. + * @param cycle The clock cycle (trigger interval) of the measurement. Range: 30 ~ 4095. + */ +static inline void adc_ll_digi_set_trigger_interval(uint32_t cycle) +{ + APB_SARADC.saradc_ctrl2.saradc_saradc_timer_target = cycle; +} + +/** + * Enable digital controller timer to trigger the measurement. + * + * @note Only used for bootloader RNG. + */ +static inline void adc_ll_digi_trigger_enable(void) +{ + APB_SARADC.saradc_ctrl2.saradc_saradc_timer_en = 1; +} + +/** + * Disable digital controller timer to trigger the measurement. + * + * @note Only used for bootloader RNG. + */ +static inline void adc_ll_digi_trigger_disable(void) +{ + APB_SARADC.saradc_ctrl2.saradc_saradc_timer_en = 0; +} + /** * Set ADC digital controller clock division factor. The clock divided from `APLL` or `APB` clock. * Expression: controller_clk = (APLL or APB) / (div_num + div_a / div_b + 1). @@ -294,20 +361,20 @@ static inline uint32_t adc_ll_pwdet_get_cct(void) * @brief Enable the ADC clock * @param enable true to enable, false to disable */ -static inline void adc_ll_enable_bus_clock(bool enable) +static inline void _adc_ll_enable_bus_clock(bool enable) { SYSTEM.perip_clk_en0.apb_saradc_clk_en = enable; } // SYSTEM.perip_clk_en0 is a shared register, so this function must be used in an atomic way #define adc_ll_enable_bus_clock(...) do { \ (void)__DECLARE_RCC_ATOMIC_ENV; \ - adc_ll_enable_bus_clock(__VA_ARGS__); \ + _adc_ll_enable_bus_clock(__VA_ARGS__); \ } while(0) /** * @brief Reset ADC module */ -static inline void adc_ll_reset_register(void) +static inline void _adc_ll_reset_register(void) { SYSTEM.perip_rst_en0.apb_saradc_rst = 1; SYSTEM.perip_rst_en0.apb_saradc_rst = 0; @@ -315,7 +382,7 @@ static inline void adc_ll_reset_register(void) // SYSTEM.perip_rst_en0 is a shared register, so this function must be used in an atomic way #define adc_ll_reset_register(...) do { \ (void)__DECLARE_RCC_ATOMIC_ENV; \ - adc_ll_reset_register(__VA_ARGS__); \ + _adc_ll_reset_register(__VA_ARGS__); \ } while(0) /** @@ -346,6 +413,70 @@ static inline void adc_ll_set_controller(adc_unit_t adc_n, adc_ll_controller_t c //Not used on ESP32-C2 } +/** + * Set pattern table length for digital controller. + * The pattern table that defines the conversion rules for each SAR ADC. Each table has 8 items, in which channel selection, + * resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the + * pattern table one by one. For each controller the scan sequence has at most 8 different rules before repeating itself. + * + * @param adc_n ADC unit. + * @param patt_len Items range: 1 ~ 8. + * + * @note Only used for bootloader RNG. + */ +static inline void adc_ll_digi_set_pattern_table_len(adc_unit_t adc_n, uint32_t patt_len) +{ + (void)adc_n; + APB_SARADC.saradc_ctrl.saradc_saradc_sar_patt_len = patt_len - 1; +} + +/** + * Reset pattern table to default value + * + * @note Only used for bootloader RNG. + */ +static inline void adc_ll_digi_reset_pattern_table(void) +{ + APB_SARADC.saradc_sar_patt_tab1.saradc_saradc_sar_patt_tab1 = 0xffffff; + APB_SARADC.saradc_sar_patt_tab2.saradc_saradc_sar_patt_tab2 = 0xffffff; +} + +/** + * Set pattern table for digital controller. + * The pattern table that defines the conversion rules for each SAR ADC. Each table has 8 items, in which channel selection, + * resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the + * pattern table one by one. For each controller the scan sequence has at most 8 different rules before repeating itself. + * + * @param adc_n ADC unit. + * @param pattern_index Items index. Range: 0 ~ 7. + * @param table Stored conversion rules. + * + * @note Only used for bootloader RNG. + */ +static inline void adc_ll_digi_set_pattern_table(adc_unit_t adc_n, uint32_t pattern_index, adc_digi_pattern_config_t table) +{ + uint32_t tab; + uint8_t index = pattern_index / 4; + uint8_t offset = (pattern_index % 4) * 6; + adc_ll_digi_pattern_table_t pattern = {0}; + + (void)adc_n; + + pattern.val = (table.atten & 0x3) | ((table.channel & 0x7) << 2) | ((table.unit & 0x1) << 5); + + if (index == 0) { + tab = APB_SARADC.saradc_sar_patt_tab1.saradc_saradc_sar_patt_tab1; // Read old register value + tab &= (~(0xFC0000 >> offset)); // Clear old data + tab |= ((uint32_t)(pattern.val & 0x3F) << 18) >> offset; // Fill in the new data + APB_SARADC.saradc_sar_patt_tab1.saradc_saradc_sar_patt_tab1 = tab; // Write back + } else { + tab = APB_SARADC.saradc_sar_patt_tab2.saradc_saradc_sar_patt_tab2; // Read old register value + tab &= (~(0xFC0000 >> offset)); // Clear old data + tab |= ((uint32_t)(pattern.val & 0x3F) << 18) >> offset; // Fill in the new data + APB_SARADC.saradc_sar_patt_tab2.saradc_saradc_sar_patt_tab2 = tab; // Write back + } +} + /* ADC calibration code. */ /** * @brief Set common calibration configuration. Should be shared with other parts (PWDET). @@ -405,6 +536,69 @@ static inline void adc_ll_set_calibration_param(adc_unit_t adc_n, uint32_t param REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_LOW_ADDR, lsb); } +/** + * Set the SAR DTEST param + * + * @param param DTEST value + */ +__attribute__((always_inline)) +static inline void adc_ll_set_dtest_param(uint32_t param) +{ + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_DTEST_RTC_ADDR, param); +} + +/** + * Set the SAR ENT param + * + * @param param ENT value + */ +__attribute__((always_inline)) +static inline void adc_ll_set_ent_param(uint32_t param) +{ + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_TSENS_ADDR, param); +} + +/** + * Enable/disable the calibration voltage reference for ADC unit. + * + * @param adc_n ADC index number. + * @param en true to enable, false to disable + */ +__attribute__((always_inline)) +static inline void adc_ll_enable_calibration_ref(adc_unit_t adc_n, bool en) +{ + if (adc_n == ADC_UNIT_1) { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC1_ENCAL_REF_ADDR, en); + } else { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC2_ENCAL_REF_ADDR, en); + } +} + +/** + * Init regi2c SARADC registers + */ +__attribute__((always_inline)) +static inline void adc_ll_regi2c_init(void) +{ + adc_ll_set_dtest_param(0); + adc_ll_set_ent_param(0); + // Config ADC circuit (Analog part) with I2C(HOST ID 0x69) and chose internal voltage as sampling source + adc_ll_enable_calibration_ref(ADC_UNIT_1, true); + adc_ll_enable_calibration_ref(ADC_UNIT_2, true); +} + +/** + * Deinit regi2c SARADC registers + */ +__attribute__((always_inline)) +static inline void adc_ll_regi2c_adc_deinit(void) +{ + adc_ll_set_dtest_param(0); + adc_ll_set_ent_param(0); + adc_ll_enable_calibration_ref(ADC_UNIT_1, false); + adc_ll_enable_calibration_ref(ADC_UNIT_2, false); +} + /*--------------------------------------------------------------- Oneshot Read ---------------------------------------------------------------*/