2021-09-27 00:46:51 -04:00
/*
2022-01-17 21:32:56 -05:00
* SPDX - FileCopyrightText : 2015 - 2022 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"
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
# include "esp_private/system_internal.h"
# if CONFIG_ESP_INT_WDT
2022-05-05 05:04:59 -04:00
# define WDT_INT_NUM ETS_T1_WDT_INUM
2019-12-26 03:30:03 -05:00
# define IWDT_INSTANCE WDT_MWDT1
2022-05-05 05:04:59 -04:00
# define IWDT_PRESCALER MWDT1_TICK_PRESCALER // Tick period of 500us if WDT source clock is 80MHz
2019-12-26 03:30:03 -05:00
# define IWDT_TICKS_PER_US MWDT1_TICKS_PER_US
# define IWDT_INITIAL_TIMEOUT_S 5
2022-05-05 05:04:59 -04:00
2019-12-26 03:30:03 -05:00
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 )
{
2019-12-26 03:30:03 -05:00
periph_module_enable ( PERIPH_TIMG1_MODULE ) ;
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-06 06:57:14 -04:00
# if SOC_TIMER_GROUPS > 1
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 ) .
*/
esp_intr_disable_source ( WDT_INT_NUM ) ;
2022-07-21 07:24:42 -04:00
esp_rom_route_intr_matrix ( esp_cpu_get_core_id ( ) , ETS_TG1_WDT_LEVEL_INTR_SOURCE , WDT_INT_NUM ) ;
2020-12-28 23:31:54 -05:00
# if SOC_CPU_HAS_FLEXIBLE_INTC
2022-07-21 07:24:42 -04:00
esp_cpu_intr_set_type ( WDT_INT_NUM , INTR_TYPE_LEVEL ) ;
esp_cpu_intr_set_priority ( WDT_INT_NUM , 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-05-05 05:04:59 -04:00
esp_intr_enable_source ( WDT_INT_NUM ) ;
# else // SOC_TIMER_GROUPS > 1
// TODO: Clean up code for ESP32-C2, IDF-4114
ESP_EARLY_LOGW ( " INT_WDT " , " ESP32-C2 only has one timer group " ) ;
# endif // SOC_TIMER_GROUPS > 1
2019-12-26 03:30:03 -05:00
}
2022-05-05 05:04:59 -04:00
# endif // CONFIG_ESP_INT_WDT