diff --git a/components/bootloader_support/src/bootloader_clock_init.c b/components/bootloader_support/src/bootloader_clock_init.c index 74288afa95..b4e98af47d 100644 --- a/components/bootloader_support/src/bootloader_clock_init.c +++ b/components/bootloader_support/src/bootloader_clock_init.c @@ -130,15 +130,13 @@ __attribute__((weak)) void bootloader_clock_configure(void) #elif CONFIG_IDF_TARGET_ESP32H4 // CLR ENA CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_SUPER_WDT_INT_ENA); /* SWD */ - // TODO [ESP32H4] IDF-12295 - // CLEAR_PERI_REG_MASK(LP_ANA_LP_INT_ENA_REG, LP_ANA_BOD_MODE0_LP_INT_ENA); /* BROWN_OUT */ + CLEAR_PERI_REG_MASK(LP_ANA_LP_INT_ENA_REG, LP_ANA_BOD_MODE0_LP_INT_ENA); /* BROWN_OUT */ CLEAR_PERI_REG_MASK(LP_WDT_INT_ENA_REG, LP_WDT_LP_WDT_INT_ENA); /* WDT */ CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_WAKEUP_INT_ENA); /* SLP_REJECT */ CLEAR_PERI_REG_MASK(PMU_HP_INT_ENA_REG, PMU_SOC_SLEEP_REJECT_INT_ENA); /* SLP_WAKEUP */ // SET CLR SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_SUPER_WDT_INT_CLR); /* SWD */ - // TODO [ESP32H4] IDF-12295 - // SET_PERI_REG_MASK(LP_ANA_LP_INT_CLR_REG, LP_ANA_BOD_MODE0_LP_INT_CLR); /* BROWN_OUT */ + SET_PERI_REG_MASK(LP_ANA_LP_INT_CLR_REG, LP_ANA_BOD_MODE0_LP_INT_CLR); /* BROWN_OUT */ SET_PERI_REG_MASK(LP_WDT_INT_CLR_REG, LP_WDT_LP_WDT_INT_CLR); /* WDT */ SET_PERI_REG_MASK(PMU_HP_INT_CLR_REG, PMU_SOC_WAKEUP_INT_CLR); /* SLP_REJECT */ SET_PERI_REG_MASK(PMU_HP_INT_CLR_REG, PMU_SOC_SLEEP_REJECT_INT_CLR); diff --git a/components/bootloader_support/src/esp32h4/bootloader_esp32h4.c b/components/bootloader_support/src/esp32h4/bootloader_esp32h4.c index 76229966db..81e714615e 100644 --- a/components/bootloader_support/src/esp32h4/bootloader_esp32h4.c +++ b/components/bootloader_support/src/esp32h4/bootloader_esp32h4.c @@ -41,6 +41,7 @@ #include "hal/efuse_hal.h" #include "hal/lpwdt_ll.h" #include "hal/assist_debug_ll.h" +#include "hal/brownout_ll.h" ESP_LOG_ATTR_TAG(TAG, "boot.esp32h4"); @@ -101,7 +102,7 @@ static inline void bootloader_ana_reset_config(void) //Enable super WDT reset. bootloader_ana_super_wdt_reset_config(true); //Enable BOD reset - //TODO: [ESP32H4] IDF-12295 need check + brownout_ll_ana_reset_enable(true); } static inline void bootloader_config_dcache(void) diff --git a/components/esp_hal_pmu/esp32h4/include/hal/brownout_ll.h b/components/esp_hal_pmu/esp32h4/include/hal/brownout_ll.h new file mode 100644 index 0000000000..ca37ffd9ae --- /dev/null +++ b/components/esp_hal_pmu/esp32h4/include/hal/brownout_ll.h @@ -0,0 +1,148 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The ll is not public api, don't use in application code. + * See readme.md in hal/readme.md + ******************************************************************************/ + +#pragma once +#include +#include "esp_bit_defs.h" +#include "soc/lp_analog_peri_struct.h" +#include "hal/regi2c_ctrl.h" +#include "hal/psdet_types.h" +#include "soc/regi2c_brownout.h" + +#define BROWNOUT_DETECTOR_LL_INTERRUPT_MASK (BIT(31)) +#define BROWNOUT_DETECTOR_LL_FIB_ENABLE (BIT(1)) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief suspend the flash when a brown out happens. + * + * @param enable true: suspend flash. false: not suspend + */ +static inline void brownout_ll_enable_flash_suspend(bool enable) +{ + LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_close_flash_ena = enable; +} + +/** + * @brief power down the RF circuits when a brown out happens + * + * @param enable true: power down. false: not power down. + */ +static inline void brownout_ll_enable_rf_power_down(bool enable) +{ + LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_pd_rf_ena = enable; +} + +/** + * @brief Configure the brown out detector to do a hardware reset + * + * @note: If brown out interrupt is also used, the hardware reset can be disabled, + * because we can call software reset in the interrupt handler. + * + * @param reset_ena true: enable reset. false: disable reset. + * @param reset_wait brown out reset wait cycles + * @param reset_level reset level + */ +static inline void brownout_ll_reset_config(bool reset_ena, uint32_t reset_wait, brownout_reset_level_t reset_level) +{ + LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_reset_wait = reset_wait; + LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_reset_ena = reset_ena; + LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_reset_sel = reset_level; +} + +/** + * @brief Set brown out threshold voltage + * + * @param threshold brownout threshold + */ +static inline void brownout_ll_set_threshold(uint8_t threshold) +{ + REGI2C_WRITE_MASK(I2C_BOD, I2C_BOD_THRESHOLD, threshold); +} + +/** + * @brief Set this bit to enable the brown out detection + * + * @param bod_enable true: enable, false: disable + */ +static inline void brownout_ll_bod_enable(bool bod_enable) +{ + LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_intr_ena = bod_enable; +} + +/** + * @brief configure the waiting cycles before sending an interrupt + * + * @param cycle waiting cycles. + */ +static inline void brownout_ll_set_intr_wait_cycles(uint8_t cycle) +{ + LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_intr_wait = cycle; +} + +/** + * @brief Enable brown out interrupt + * + * @param enable true: enable, false: disable + */ +static inline void brownout_ll_intr_enable(bool enable) +{ + LP_ANA_PERI.ana_int_ena.ana_bod_mode0_int_ena = enable; +} + +/** + * @brief Enable brownout hardware reset (mode1) + * + * @param enable true: enable, false: disable + */ +static inline void brownout_ll_ana_reset_enable(bool enable) +{ + // give BOD mode1 control permission to the software + LP_ANA_PERI.ana_fib_enable.val &= ~BROWNOUT_DETECTOR_LL_FIB_ENABLE; + // then we can enable or disable if we want the BOD mode1 to reset the system + LP_ANA_PERI.ana_bod_mode1_cntl.ana_bod_mode1_reset_ena = enable; +} + +/** + * @brief Clear interrupt bits. + */ +__attribute__((always_inline)) +static inline void brownout_ll_intr_clear(void) +{ + LP_ANA_PERI.ana_int_clr.val = BROWNOUT_DETECTOR_LL_INTERRUPT_MASK; +} + +/** + * @brief Clear BOD internal count. + */ +static inline void brownout_ll_clear_count(void) +{ + LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_cnt_clr = 1; + LP_ANA_PERI.ana_bod_mode0_cntl.ana_bod_mode0_cnt_clr = 0; +} + +/** + * @brief Get interrupt status register address + * + * @return Register address + */ +static inline volatile void *brownout_ll_intr_get_status_reg(void) +{ + return &LP_ANA_PERI.ana_int_st; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/power_supply/port/esp32h4/Kconfig.power b/components/esp_hw_support/power_supply/port/esp32h4/Kconfig.power new file mode 100644 index 0000000000..67bce99b87 --- /dev/null +++ b/components/esp_hw_support/power_supply/port/esp32h4/Kconfig.power @@ -0,0 +1,85 @@ +menu "Power Supplier" + + menu "Brownout Detector" + config ESP_BROWNOUT_DET + bool "Hardware brownout detect & reset" + depends on !IDF_ENV_FPGA + default y + help + The ESP32-H4 has a built-in brownout detector which can detect if the voltage is lower than + a specific value. If this happens, it will reset the chip in order to prevent unintended + behaviour. + + choice ESP_BROWNOUT_DET_LVL_SEL + prompt "Brownout voltage level" + depends on ESP_BROWNOUT_DET + default ESP_BROWNOUT_DET_LVL_SEL_4 + help + The brownout detector will reset the chip when the supply voltage is approximately + below this level. Note that there may be some variation of brownout voltage level + between each chip. + + #The voltage levels here are estimates, more work needs to be done to figure out the exact voltages + #of the brownout threshold levels. + config ESP_BROWNOUT_DET_LVL_SEL_15 + bool "3.77V" + config ESP_BROWNOUT_DET_LVL_SEL_14 + bool "3.68V" + config ESP_BROWNOUT_DET_LVL_SEL_13 + bool "3.58V" + config ESP_BROWNOUT_DET_LVL_SEL_12 + bool "3.47V" + config ESP_BROWNOUT_DET_LVL_SEL_11 + bool "3.37V" + config ESP_BROWNOUT_DET_LVL_SEL_10 + bool "3.26V" + config ESP_BROWNOUT_DET_LVL_SEL_9 + bool "3.16V" + config ESP_BROWNOUT_DET_LVL_SEL_8 + bool "3.06V" + config ESP_BROWNOUT_DET_LVL_SEL_7 + bool "2.96V" + config ESP_BROWNOUT_DET_LVL_SEL_6 + bool "2.86V" + config ESP_BROWNOUT_DET_LVL_SEL_5 + bool "2.75V" + config ESP_BROWNOUT_DET_LVL_SEL_4 + bool "2.66V" + config ESP_BROWNOUT_DET_LVL_SEL_3 + bool "2.55V" + config ESP_BROWNOUT_DET_LVL_SEL_2 + bool "2.45V" + + endchoice + + config ESP_BROWNOUT_DET_LVL + int + default 2 if ESP_BROWNOUT_DET_LVL_SEL_2 + default 3 if ESP_BROWNOUT_DET_LVL_SEL_3 + default 4 if ESP_BROWNOUT_DET_LVL_SEL_4 + default 5 if ESP_BROWNOUT_DET_LVL_SEL_5 + default 6 if ESP_BROWNOUT_DET_LVL_SEL_6 + default 7 if ESP_BROWNOUT_DET_LVL_SEL_7 + default 8 if ESP_BROWNOUT_DET_LVL_SEL_8 + default 9 if ESP_BROWNOUT_DET_LVL_SEL_9 + default 10 if ESP_BROWNOUT_DET_LVL_SEL_10 + default 11 if ESP_BROWNOUT_DET_LVL_SEL_11 + default 12 if ESP_BROWNOUT_DET_LVL_SEL_12 + default 13 if ESP_BROWNOUT_DET_LVL_SEL_13 + default 14 if ESP_BROWNOUT_DET_LVL_SEL_14 + default 15 if ESP_BROWNOUT_DET_LVL_SEL_15 + + + config ESP_BROWNOUT_USE_INTR + bool + default n + help + This config allows to trigger an interrupt when brownout detected. Software restart will be done + at the end of the default callback. + This is because for some special workflow, the chip needs do more things when brownout happens + before restart instead of restarting directly. This part needs to be done in callback function + of interrupt. + + endmenu + +endmenu diff --git a/components/esp_system/port/soc/esp32h4/Kconfig.system b/components/esp_system/port/soc/esp32h4/Kconfig.system deleted file mode 100644 index 042715a621..0000000000 --- a/components/esp_system/port/soc/esp32h4/Kconfig.system +++ /dev/null @@ -1,45 +0,0 @@ -menu "Brownout Detector" - config ESP_BROWNOUT_DET - bool "Hardware brownout detect & reset" - depends on !IDF_ENV_FPGA - default y - help - The ESP32-H4 has a built-in brownout detector which can detect if the voltage is lower than - a specific value. If this happens, it will reset the chip in order to prevent unintended - behaviour. - - choice ESP_BROWNOUT_DET_LVL_SEL - prompt "Brownout voltage level" - depends on ESP_BROWNOUT_DET - default ESP_BROWNOUT_DET_LVL_SEL_7 - help - The brownout detector will reset the chip when the supply voltage is approximately - below this level. Note that there may be some variation of brownout voltage level - between each chip. - - #The voltage levels here are estimates, more work needs to be done to figure out the exact voltages - #of the brownout threshold levels. - config ESP_BROWNOUT_DET_LVL_SEL_7 - bool "2.51V" - config ESP_BROWNOUT_DET_LVL_SEL_6 - bool "2.64V" - config ESP_BROWNOUT_DET_LVL_SEL_5 - bool "2.76V" - config ESP_BROWNOUT_DET_LVL_SEL_4 - bool "2.92V" - config ESP_BROWNOUT_DET_LVL_SEL_3 - bool "3.10V" - config ESP_BROWNOUT_DET_LVL_SEL_2 - bool "3.27V" - endchoice - - config ESP_BROWNOUT_DET_LVL - int - default 2 if ESP_BROWNOUT_DET_LVL_SEL_2 - default 3 if ESP_BROWNOUT_DET_LVL_SEL_3 - default 4 if ESP_BROWNOUT_DET_LVL_SEL_4 - default 5 if ESP_BROWNOUT_DET_LVL_SEL_5 - default 6 if ESP_BROWNOUT_DET_LVL_SEL_6 - default 7 if ESP_BROWNOUT_DET_LVL_SEL_7 - -endmenu diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index a721d4311f..957a5ccf29 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -147,6 +147,10 @@ config SOC_FLASH_ENC_SUPPORTED bool default n +config SOC_BOD_SUPPORTED + bool + default y + config SOC_PMU_SUPPORTED bool default y diff --git a/components/soc/esp32h4/include/soc/regi2c_brownout.h b/components/soc/esp32h4/include/soc/regi2c_brownout.h new file mode 100644 index 0000000000..4e890e1847 --- /dev/null +++ b/components/soc/esp32h4/include/soc/regi2c_brownout.h @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + */ + +#pragma once + +#include "regi2c_dcdc.h" + +/** + * @file regi2c_brownout.h + * @brief Register definitions for brownout detector + * + * This file lists register fields of the brownout detector, located on an internal configuration + * bus. These definitions are used via macros defined in regi2c_ctrl.h. + */ + +#define I2C_BOD I2C_DCDC +#define I2C_BOD_HOSTID I2C_DCDC_HOSTID + +#define I2C_BOD_THRESHOLD 0xD +#define I2C_BOD_THRESHOLD_MSB 6 +#define I2C_BOD_THRESHOLD_LSB 3 diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 101126959a..777d2f78b3 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -74,7 +74,7 @@ #define SOC_FLASH_ENC_SUPPORTED 0 // TODO: [ESP32H4] IDF-12261 // #define SOC_SECURE_BOOT_SUPPORTED 1 // TODO: [ESP32H4] IDF-12262 -// #define SOC_BOD_SUPPORTED 1 // TODO: [ESP32H4] IDF-12295 +#define SOC_BOD_SUPPORTED 1 // #define SOC_APM_SUPPORTED 1 // TODO: [ESP32H4] IDF-12256 #define SOC_PMU_SUPPORTED 1 // TODO: [ESP32H4] IDF-12286 #define SOC_PAU_SUPPORTED 1 diff --git a/components/soc/esp32h4/power_supply_periph.c b/components/soc/esp32h4/power_supply_periph.c new file mode 100644 index 0000000000..fa571d89fe --- /dev/null +++ b/components/soc/esp32h4/power_supply_periph.c @@ -0,0 +1,11 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + */ + +#include "soc/power_supply_periph.h" + +const power_supply_signal_conn_t power_supply_periph_signal = { + .irq = ETS_LP_RTC_TIMER_INTR_SOURCE, +};