2021-09-27 00:46:51 -04:00
/*
2023-07-21 00:36:57 -04:00
* SPDX - FileCopyrightText : 2015 - 2023 Espressif Systems ( Shanghai ) CO LTD
2021-09-27 00:46:51 -04:00
*
* SPDX - License - Identifier : Apache - 2.0
*/
2019-12-26 03:30:03 -05:00
# include <stdint.h>
# include <stdio.h>
# include <stdbool.h>
2020-12-28 23:31:54 -05:00
# include "sdkconfig.h"
2022-05-05 05:04:59 -04:00
# include "soc/soc_caps.h"
# include "hal/wdt_hal.h"
2023-02-17 01:51:00 -05:00
# include "hal/mwdt_ll.h"
2023-08-18 01:26:46 -04:00
# include "hal/timer_ll.h"
2019-12-26 03:30:03 -05:00
# include "freertos/FreeRTOS.h"
2022-07-21 07:24:42 -04:00
# include "esp_cpu.h"
2019-12-26 03:30:03 -05:00
# include "esp_err.h"
# include "esp_attr.h"
2021-11-06 05:24:45 -04:00
# include "esp_log.h"
2022-05-05 05:04:59 -04:00
# include "esp_intr_alloc.h"
2022-01-12 01:53:47 -05:00
# include "esp_chip_info.h"
2019-12-26 03:30:03 -05:00
# include "esp_freertos_hooks.h"
2021-10-25 05:13:46 -04:00
# include "esp_private/periph_ctrl.h"
2022-05-05 03:38:49 -04:00
# include "esp_private/esp_int_wdt.h"
2019-12-26 03:30:03 -05:00
2023-02-17 01:51:00 -05:00
# if SOC_TIMER_GROUPS > 1
/* If we have two hardware timer groups, use the second one for interrupt watchdog. */
# define WDT_LEVEL_INTR_SOURCE ETS_TG1_WDT_LEVEL_INTR_SOURCE
# define IWDT_PRESCALER MWDT_LL_DEFAULT_CLK_PRESCALER // Tick period of 500us if WDT source clock is 80MHz
# define IWDT_TICKS_PER_US 500
# define IWDT_INSTANCE WDT_MWDT1
# define IWDT_INITIAL_TIMEOUT_S 5
2023-08-18 01:26:46 -04:00
# define IWDT_PERIPH PERIPH_TIMG1_MODULE
# define IWDT_TIMER_GROUP 1
2023-02-17 01:51:00 -05:00
# else
# define WDT_LEVEL_INTR_SOURCE ETS_TG0_WDT_LEVEL_INTR_SOURCE
# define IWDT_PRESCALER MWDT_LL_DEFAULT_CLK_PRESCALER // Tick period of 500us if WDT source clock is 80MHz
# define IWDT_TICKS_PER_US 500
# define IWDT_INSTANCE WDT_MWDT0
# define IWDT_INITIAL_TIMEOUT_S 5
2023-08-18 01:26:46 -04:00
# define IWDT_PERIPH PERIPH_TIMG0_MODULE
# define IWDT_TIMER_GROUP 0
2023-02-17 01:51:00 -05:00
# endif // SOC_TIMER_GROUPS > 1
2019-12-26 03:30:03 -05:00
# if CONFIG_ESP_INT_WDT
static wdt_hal_context_t iwdt_context ;
2020-05-29 02:53:30 -04:00
# if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
/*
2020-12-28 23:31:54 -05:00
* This parameter is used to indicate the response time of Interrupt watchdog to
2020-05-29 02:53:30 -04:00
* identify the live lock .
*/
# define IWDT_LIVELOCK_TIMEOUT_MS (20)
2021-09-02 09:10:29 -04:00
extern uint32_t _lx_intr_livelock_counter , _lx_intr_livelock_max ;
2020-05-29 02:53:30 -04:00
# endif
2019-12-26 03:30:03 -05:00
# if CONFIG_ESP_INT_WDT_CHECK_CPU1
2022-05-05 05:04:59 -04:00
volatile bool int_wdt_cpu1_ticked = false ;
# endif
2019-12-26 03:30:03 -05:00
2020-12-28 23:31:54 -05:00
static void IRAM_ATTR tick_hook ( void )
{
2022-05-05 05:04:59 -04:00
# if CONFIG_ESP_INT_WDT_CHECK_CPU1
2022-07-21 07:24:42 -04:00
if ( esp_cpu_get_core_id ( ) ! = 0 ) {
2022-05-05 05:04:59 -04:00
int_wdt_cpu1_ticked = true ;
2019-12-26 03:30:03 -05:00
} else {
2022-05-05 05:04:59 -04:00
// Only feed wdt if app cpu also ticked.
if ( int_wdt_cpu1_ticked ) {
// Todo: Check if there's a way to avoid reconfiguring the stages on each feed.
2019-12-26 03:30:03 -05:00
wdt_hal_write_protect_disable ( & iwdt_context ) ;
2022-05-05 05:04:59 -04:00
// Reconfigure stage timeouts
2020-05-29 02:53:30 -04:00
# if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
2021-09-02 09:10:29 -04:00
_lx_intr_livelock_counter = 0 ;
2020-05-29 02:53:30 -04:00
wdt_hal_config_stage ( & iwdt_context , WDT_STAGE0 ,
2022-05-05 05:04:59 -04:00
CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US / ( _lx_intr_livelock_max + 1 ) , WDT_STAGE_ACTION_INT ) ; // Set timeout before interrupt
2020-05-29 02:53:30 -04:00
# else
2022-05-05 05:04:59 -04:00
wdt_hal_config_stage ( & iwdt_context , WDT_STAGE0 , CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US , WDT_STAGE_ACTION_INT ) ; // Set timeout before interrupt
2020-05-29 02:53:30 -04:00
# endif
2022-05-05 05:04:59 -04:00
wdt_hal_config_stage ( & iwdt_context , WDT_STAGE1 , 2 * CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US , WDT_STAGE_ACTION_RESET_SYSTEM ) ; // Set timeout before reset
2019-12-26 03:30:03 -05:00
wdt_hal_feed ( & iwdt_context ) ;
wdt_hal_write_protect_enable ( & iwdt_context ) ;
2022-05-05 05:04:59 -04:00
int_wdt_cpu1_ticked = false ;
2019-12-26 03:30:03 -05:00
}
}
2022-05-05 05:04:59 -04:00
# else // CONFIG_ESP_INT_WDT_CHECK_CPU1
2022-07-21 07:24:42 -04:00
if ( esp_cpu_get_core_id ( ) ! = 0 ) {
2019-12-26 03:30:03 -05:00
return ;
2022-05-05 05:04:59 -04:00
} else {
// Todo: Check if there's a way to avoid reconfiguring the stages on each feed.
wdt_hal_write_protect_disable ( & iwdt_context ) ;
// Reconfigure stage timeouts
wdt_hal_config_stage ( & iwdt_context , WDT_STAGE0 , CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US , WDT_STAGE_ACTION_INT ) ; // Set timeout before interrupt
wdt_hal_config_stage ( & iwdt_context , WDT_STAGE1 , 2 * CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US , WDT_STAGE_ACTION_RESET_SYSTEM ) ; // Set timeout before reset
wdt_hal_feed ( & iwdt_context ) ;
wdt_hal_write_protect_enable ( & iwdt_context ) ;
2019-12-26 03:30:03 -05:00
}
2022-05-05 05:04:59 -04:00
# endif // CONFIG_ESP_INT_WDT_CHECK_CPU1
2019-12-26 03:30:03 -05:00
}
2020-12-28 23:31:54 -05:00
void esp_int_wdt_init ( void )
{
2023-08-18 01:26:46 -04:00
PERIPH_RCC_ACQUIRE_ATOMIC ( IWDT_PERIPH , ref_count ) {
if ( ref_count = = 0 ) {
timer_ll_enable_bus_clock ( IWDT_TIMER_GROUP , true ) ;
timer_ll_reset_register ( IWDT_TIMER_GROUP ) ;
}
}
2022-05-05 05:04:59 -04:00
/*
* Initialize the WDT timeout stages . Note that the initial timeout is set to 5 seconds as variable startup times of
* each CPU can lead to a timeout . The tick hooks will set the WDT timers to the actual timeout .
* Todo : Fix this
*/
2019-12-26 03:30:03 -05:00
wdt_hal_init ( & iwdt_context , IWDT_INSTANCE , IWDT_PRESCALER , true ) ;
wdt_hal_write_protect_disable ( & iwdt_context ) ;
wdt_hal_config_stage ( & iwdt_context , WDT_STAGE0 , IWDT_INITIAL_TIMEOUT_S * 1000000 / IWDT_TICKS_PER_US , WDT_STAGE_ACTION_INT ) ;
wdt_hal_config_stage ( & iwdt_context , WDT_STAGE1 , IWDT_INITIAL_TIMEOUT_S * 1000000 / IWDT_TICKS_PER_US , WDT_STAGE_ACTION_RESET_SYSTEM ) ;
wdt_hal_enable ( & iwdt_context ) ;
wdt_hal_write_protect_enable ( & iwdt_context ) ;
2021-09-02 08:54:21 -04:00
2021-09-02 09:49:30 -04:00
# if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
2022-05-05 05:04:59 -04:00
# define APB_DCRSET (0x200c)
# define APB_ITCTRL (0x3f00)
# define ERI_ADDR(APB) (0x100000 + (APB))
# define _SYM2STR(x) # x
# define SYM2STR(x) _SYM2STR(x)
2021-09-02 08:54:21 -04:00
uint32_t eriadrs , scratch = 0 , immediate = 0 ;
if ( soc_has_cache_lock_bug ( ) ) {
if ( xPortGetCoreID ( ) ! = CONFIG_BTDM_CTRL_PINNED_TO_CORE ) {
__asm__ __volatile__ (
2022-05-05 05:04:59 -04:00
/* Enable Xtensa Debug Module Integration Mode */
" movi %[ERI], " SYM2STR ( ERI_ADDR ( APB_ITCTRL ) ) " \n "
" rer %[REG], %[ERI] \n "
" movi %[IMM], 1 \n "
" or %[REG], %[IMM], %[REG] \n "
" wer %[REG], %[ERI] \n "
/* Enable Xtensa Debug Module BreakIn signal */
" movi %[ERI], " SYM2STR ( ERI_ADDR ( APB_DCRSET ) ) " \n "
" rer %[REG], %[ERI] \n "
" movi %[IMM], 0x10000 \n "
" or %[REG], %[IMM], %[REG] \n "
" wer %[REG], %[ERI] \n "
: [ ERI ] " =r " ( eriadrs ) , [ REG ] " +r " ( scratch ) , [ IMM ] " +r " ( immediate )
) ;
2021-09-02 08:54:21 -04:00
}
}
2022-05-05 05:04:59 -04:00
# endif // (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
2019-12-26 03:30:03 -05:00
}
void esp_int_wdt_cpu_init ( void )
{
2022-05-05 05:04:59 -04:00
assert ( ( CONFIG_ESP_INT_WDT_TIMEOUT_MS > = ( portTICK_PERIOD_MS < < 1 ) ) & & " Interrupt watchdog timeout needs to be at least twice the RTOS tick period! " ) ;
// Register tick hook for current CPU to feed the INT WDT
2022-07-21 07:24:42 -04:00
esp_register_freertos_tick_hook_for_cpu ( tick_hook , esp_cpu_get_core_id ( ) ) ;
2022-05-05 05:04:59 -04:00
/*
* Register INT WDT interrupt for current CPU . We do this manually as the timeout interrupt should call an assembly
* panic handler ( see riscv / vector . S and xtensa_vectors . S ) .
*/
2022-07-07 02:54:15 -04:00
esp_intr_disable_source ( ETS_INT_WDT_INUM ) ;
esp_rom_route_intr_matrix ( esp_cpu_get_core_id ( ) , WDT_LEVEL_INTR_SOURCE , ETS_INT_WDT_INUM ) ;
2020-12-28 23:31:54 -05:00
# if SOC_CPU_HAS_FLEXIBLE_INTC
2022-07-07 02:54:15 -04:00
esp_cpu_intr_set_type ( ETS_INT_WDT_INUM , INTR_TYPE_LEVEL ) ;
esp_cpu_intr_set_priority ( ETS_INT_WDT_INUM , SOC_INTERRUPT_LEVEL_MEDIUM ) ;
2020-12-03 04:17:43 -05:00
# endif
2020-05-29 02:53:30 -04:00
# if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
/*
* This is a workaround for issue 3.15 in " ESP32 ECO and workarounds for
* Bugs " document.
*/
2021-09-02 09:10:29 -04:00
_lx_intr_livelock_counter = 0 ;
2020-05-29 02:53:30 -04:00
if ( soc_has_cache_lock_bug ( ) ) {
2020-12-28 23:31:54 -05:00
assert ( ( portTICK_PERIOD_MS < < 1 ) < = IWDT_LIVELOCK_TIMEOUT_MS ) ;
assert ( CONFIG_ESP_INT_WDT_TIMEOUT_MS > = ( IWDT_LIVELOCK_TIMEOUT_MS * 3 ) ) ;
2021-09-02 09:10:29 -04:00
_lx_intr_livelock_max = CONFIG_ESP_INT_WDT_TIMEOUT_MS / IWDT_LIVELOCK_TIMEOUT_MS - 1 ;
2020-05-29 02:53:30 -04:00
}
# endif
2022-07-07 02:54:15 -04:00
esp_intr_enable_source ( ETS_INT_WDT_INUM ) ;
2019-12-26 03:30:03 -05:00
}
2022-05-05 05:04:59 -04:00
# endif // CONFIG_ESP_INT_WDT