289 lines
6.4 KiB
C
Raw Normal View History

2025-10-10 16:07:00 +08:00
// Copyright 2020-2021 Beken
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <common/bk_include.h>
#include <os/os.h>
#include <os/mem.h>
#include <driver/wdt.h>
#include "wdt_driver.h"
#include "wdt_hal.h"
#include "reset_reason.h"
#include "bk_fake_clock.h"
#include "icu_driver.h"
#include "power_driver.h"
#include <components/system.h>
#include "sys_driver.h"
#include <driver/timer.h>
#include "bk_wdt.h"
#include "aon_pmu_driver.h"
#if CONFIG_AON_RTC
#include <driver/aon_rtc.h>
#endif
#include <gpio_driver.h>
typedef struct {
wdt_hal_t hal;
uint8_t init_bits;
} wdt_driver_t;
#define DUMP_THREAD_WHEN_TASK_WDG_TIGGERED 1
#define DUMP_STACK_WHEN_TASK_WDG_TIGGERED 1
#define INT_WDG_FEED_PERIOD_TICK ((BK_MS_TO_TICKS(CONFIG_INT_WDT_PERIOD_MS)) >> 4)
#define TASK_WDG_PERIOD_TICK (BK_MS_TO_TICKS(CONFIG_TASK_WDT_PERIOD_MS))
#if CONFIG_AON_RTC
#define GET_TASK_CURRENT_TICK() (BK_MS_TO_TICKS(bk_aon_rtc_get_us()/1000))
#else
#define GET_TASK_CURRENT_TICK() (bk_get_tick())
#endif
#define WDT_RETURN_ON_DRIVER_NOT_INIT() do {\
if (!s_wdt_driver_is_init) {\
WDT_LOGE("WDT driver not init\r\n");\
return BK_ERR_WDT_DRIVER_NOT_INIT;\
}\
} while(0)
#define WDT_RETURN_ON_NOT_INIT() do {\
if (!(s_wdt.init_bits & BIT(0))) {\
return BK_ERR_WDT_NOT_INIT;\
}\
} while(0)
#define WDT_RETURN_ON_INVALID_PERIOD(timeout) do {\
if ((timeout) > WDT_F_PERIOD_V) {\
WDT_LOGE("WDT invalid timeout\r\n");\
return BK_ERR_WDT_INVALID_PERIOD;\
}\
} while(0)
#define WDT_BARK_TIME_MS 1000
#define NMI_WDT_CLK_DIV_16 3
static wdt_driver_t s_wdt = {0};
static bool s_wdt_driver_is_init = false;
static uint32_t s_wdt_period = CONFIG_INT_WDT_PERIOD_MS;
#if (CONFIG_TASK_WDT)
static uint64_t s_last_task_wdt_feed_tick = 0;
static uint64_t s_last_task_wdt_log_tick = 0;
static bool s_task_wdt_enabled = true;
#endif
# if (CONFIG_INT_WDT)
static uint32_t s_feed_watchdog_time = INT_WDG_FEED_PERIOD_TICK;
#endif
__IRAM_SEC static void wdt_init_common(void)
{
#if (CONFIG_SYSTEM_CTRL)
sys_drv_dev_clk_pwr_up(CLK_PWR_ID_WDG_CPU, CLK_PWR_CTRL_PWR_UP);
#else
power_up_wdt();
#endif
}
__attribute__((section(".itcm_sec_code"))) static void wdt_deinit_common(void)
{
s_wdt_period = CONFIG_INT_WDT_PERIOD_MS;
wdt_hal_reset_config_to_default(&s_wdt.hal);
#if (CONFIG_SYSTEM_CTRL)
close_wdt();
//sys_drv_dev_clk_pwr_up(CLK_PWR_ID_WDG_CPU, CLK_PWR_CTRL_PWR_DOWN);
#else
power_down_wdt();
#endif
}
bk_err_t bk_wdt_driver_init(void)
{
if (s_wdt_driver_is_init) {
return BK_OK;
}
os_memset(&s_wdt, 0, sizeof(s_wdt));
wdt_hal_init(&s_wdt.hal);
#if (CONFIG_SYS_CPU0)
bk_timer_start(TIMER_ID2, WDT_BARK_TIME_MS, (timer_isr_t)bk_wdt_feed_handle);
sys_drv_nmi_wdt_set_clk_div(NMI_WDT_CLK_DIV_16);
aon_pmu_drv_wdt_rst_dev_enable();
#endif
s_wdt_driver_is_init = true;
return BK_OK;
}
bk_err_t bk_wdt_driver_deinit(void)
{
if (!s_wdt_driver_is_init) {
return BK_OK;
}
wdt_deinit_common();
#if (CONFIG_SYS_CPU0)
bk_timer_stop(TIMER_ID2);
#endif
s_wdt_driver_is_init = false;
return BK_OK;
}
/* 1. power up wdt
* 2. set period
*/
__IRAM_SEC bk_err_t bk_wdt_start(uint32_t timeout_ms)
{
WDT_RETURN_ON_DRIVER_NOT_INIT();
WDT_RETURN_ON_INVALID_PERIOD(timeout_ms);
if (!timeout_ms) {
timeout_ms = CONFIG_INT_WDT_PERIOD_MS;
}
s_wdt_period = timeout_ms;
wdt_init_common();
wdt_hal_init_wdt(&s_wdt.hal, timeout_ms);
s_wdt.init_bits |= BIT(0);
WDT_LOGD("bk_wdt_start, s_wdt.init_bits:%x\n", s_wdt.init_bits);
return BK_OK;
}
__attribute__((section(".itcm_sec_code"))) bk_err_t bk_wdt_stop(void)
{
WDT_RETURN_ON_DRIVER_NOT_INIT();
wdt_deinit_common();
s_wdt.init_bits &= ~BIT(0);
//WDT_LOGD("bk_wdt_stop, s_wdt.init_bits:%x\n", s_wdt.init_bits);
return BK_OK;
}
bk_err_t bk_wdt_feed(void)
{
WDT_RETURN_ON_DRIVER_NOT_INIT();
WDT_RETURN_ON_NOT_INIT();
wdt_hal_init_wdt(&s_wdt.hal, s_wdt_period);
return BK_OK;
}
#if (CONFIG_INT_WDT)
void bk_int_wdt_feed(void)
{
static uint64_t s_last_int_wdt_feed_tick = 0;
uint64_t current_tick = GET_TASK_CURRENT_TICK();
if ((current_tick - s_last_int_wdt_feed_tick) >= s_feed_watchdog_time) {
bk_wdt_feed();
s_last_int_wdt_feed_tick = current_tick;
//WDT_LOGD("feed interrupt watchdog, s_feed_watchdog_time = %u ms.\n", s_feed_watchdog_time);
}
}
uint32_t bk_wdt_get_feed_time()
{
return s_feed_watchdog_time;
}
void bk_wdt_set_feed_time(uint32_t dw_set_time)
{
s_feed_watchdog_time = dw_set_time;
}
#endif
#if (CONFIG_TASK_WDT)
__IRAM_SEC void bk_task_wdt_start()
{
s_task_wdt_enabled = true;
}
__attribute__((section(".itcm_sec_code"))) void bk_task_wdt_stop()
{
s_task_wdt_enabled = false;
}
void bk_task_wdt_feed(void)
{
s_last_task_wdt_feed_tick = GET_TASK_CURRENT_TICK();
}
void bk_task_wdt_timeout_check(void)
{
if (s_last_task_wdt_feed_tick && s_task_wdt_enabled) {
const uint64_t c_last_feed_tick = s_last_task_wdt_feed_tick;
const uint64_t current_tick = GET_TASK_CURRENT_TICK();
if(current_tick > c_last_feed_tick) {
if ((current_tick - c_last_feed_tick) > TASK_WDG_PERIOD_TICK) {
if ((current_tick - s_last_task_wdt_log_tick) > TASK_WDG_PERIOD_TICK) {
WDT_LOGW("task watchdog triggered\r\n");
s_last_task_wdt_log_tick = current_tick;
BK_ASSERT(0);
}
}
}
}
}
#endif
bool bk_wdt_is_driver_inited()
{
return s_wdt_driver_is_init;
}
void bk_wdt_feed_handle(void)
{
GLOBAL_INT_DECLARATION();
GLOBAL_INT_DISABLE();
#if (CONFIG_INT_WDT)
bk_int_wdt_feed();
#endif
#if (CONFIG_TASK_WDT)
bk_task_wdt_timeout_check();
#endif
GLOBAL_INT_RESTORE();
}
__attribute__((section(".itcm_sec_code"))) void close_wdt(void)
{
wdt_hal_close();
}
void bk_wdt_force_feed(void)
{
wdt_hal_force_feed();
}
void bk_wdt_force_reboot(void)
{
GLOBAL_INT_DECLARATION();
GLOBAL_INT_DISABLE();
wdt_hal_force_reboot();
#if CONFIG_GPIO_RETENTION_SUPPORT
// lock gpio if retention map is set up
// Attention: hot-flash-write will not work if gpio locked
if (0 != gpio_retention_map_get())
{
sys_hal_gpio_state_switch(true);
}
#endif
while(1);
GLOBAL_INT_RESTORE();
}