1 // Copyright (C) 2022 Beken Corporation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <common/bk_include.h>
16 #include <os/os.h>
17 #include <os/mem.h>
18 #include <driver/wdt.h>
19 #include "wdt_driver.h"
20 #include "wdt_hal.h"
21 #include "reset_reason.h"
22 #include "bk_fake_clock.h"
23 #include "icu_driver.h"
24 #include "power_driver.h"
25 #include "bk_rtos_debug.h"
26 #include <components/system.h>
27 #include "sys_driver.h"
28 #include <driver/timer.h>
29 #include "bk_wdt.h"
30 #include "aon_pmu_driver.h"
31
32 typedef struct {
33 wdt_hal_t hal;
34 uint8_t init_bits;
35 } wdt_driver_t;
36
37 #define DUMP_THREAD_WHEN_TASK_WDG_TIGGERED 1
38 #define DUMP_STACK_WHEN_TASK_WDG_TIGGERED 1
39
40 #define INT_WDG_FEED_PERIOD_TICK ((BK_MS_TO_TICKS(CONFIG_INT_WDT_PERIOD_MS)) >> 4)
41 #define TASK_WDG_PERIOD_TICK (BK_MS_TO_TICKS(CONFIG_TASK_WDT_PERIOD_MS))
42
43 #define WDT_RETURN_ON_DRIVER_NOT_INIT() do {\
44 if (!s_wdt_driver_is_init) {\
45 WDT_LOGE("WDT driver not init\r\n");\
46 return BK_ERR_WDT_DRIVER_NOT_INIT;\
47 }\
48 } while(0)
49
50 #define WDT_RETURN_ON_NOT_INIT() do {\
51 if (!(s_wdt.init_bits & BIT(0))) {\
52 return BK_ERR_WDT_NOT_INIT;\
53 }\
54 } while(0)
55
56 #define WDT_RETURN_ON_INVALID_PERIOD(timeout) do {\
57 if ((timeout) > WDT_F_PERIOD_V) {\
58 WDT_LOGE("WDT invalid timeout\r\n");\
59 return BK_ERR_WDT_INVALID_PERIOD;\
60 }\
61 } while(0)
62
63
64 #define WDT_BARK_TIME_MS 2000
65 #define NMI_WDT_CLK_DIV_16 3
66
67 static wdt_driver_t s_wdt = {0};
68 static bool s_wdt_driver_is_init = false;
69 static uint32_t s_wdt_period = CONFIG_INT_WDT_PERIOD_MS;
70 static bool s_wdt_debug_enabled = true;
71
72 #if (CONFIG_TASK_WDT)
73 static uint64_t s_last_task_wdt_feed_tick = 0;
74 static uint64_t s_last_task_wdt_log_tick = 0;
75 static bool s_task_wdt_enabled = true;
76 #endif
77
78 # if (CONFIG_INT_WDT)
79 static uint32_t s_feed_watchdog_time = INT_WDG_FEED_PERIOD_TICK;
80 #endif
81
wdt_init_common(void)82 static void wdt_init_common(void)
83 {
84 #if (CONFIG_SOC_BK7256XX)
85 sys_drv_dev_clk_pwr_up(CLK_PWR_ID_WDG_CPU, CLK_PWR_CTRL_PWR_UP);
86 #else
87 power_up_wdt();
88 #endif
89 }
90
wdt_deinit_common(void)91 static void wdt_deinit_common(void)
92 {
93 s_wdt_period = CONFIG_INT_WDT_PERIOD_MS;
94 wdt_hal_reset_config_to_default(&s_wdt.hal);
95 #if (CONFIG_SOC_BK7256XX)
96 extern void close_wdt(void);
97 close_wdt();
98 sys_drv_dev_clk_pwr_up(CLK_PWR_ID_WDG_CPU, CLK_PWR_CTRL_PWR_DOWN);
99 #else
100 power_down_wdt();
101 #endif
102 }
103
bk_wdt_driver_init(void)104 bk_err_t bk_wdt_driver_init(void)
105 {
106 if (s_wdt_driver_is_init) {
107 return BK_OK;
108 }
109
110 os_memset(&s_wdt, 0, sizeof(s_wdt));
111 wdt_hal_init(&s_wdt.hal);
112 #if ((CONFIG_SOC_BK7256XX) && (!CONFIG_SLAVE_CORE))
113 bk_timer_start(TIMER_ID2, WDT_BARK_TIME_MS, (timer_isr_t)bk_wdt_feed_handle);
114 sys_drv_nmi_wdt_set_clk_div(NMI_WDT_CLK_DIV_16);
115 aon_pmu_drv_wdt_rst_dev_enable();
116 #endif
117 s_wdt_driver_is_init = true;
118
119 return BK_OK;
120 }
121
bk_wdt_driver_deinit(void)122 bk_err_t bk_wdt_driver_deinit(void)
123 {
124 if (!s_wdt_driver_is_init) {
125 return BK_OK;
126 }
127 wdt_deinit_common();
128 #if ((CONFIG_SOC_BK7256XX) && (!CONFIG_SLAVE_CORE))
129 bk_timer_stop(TIMER_ID2);
130 #endif
131 s_wdt_driver_is_init = false;
132
133 return BK_OK;
134 }
135
136 /* 1. power up wdt
137 * 2. set period
138 */
bk_wdt_start(uint32_t timeout_ms)139 bk_err_t bk_wdt_start(uint32_t timeout_ms)
140 {
141 WDT_RETURN_ON_DRIVER_NOT_INIT();
142 WDT_RETURN_ON_INVALID_PERIOD(timeout_ms);
143
144 if (!s_wdt_debug_enabled) {
145 return BK_ERR_WDT_DEBUG_DISABLED;
146 }
147
148 if (!timeout_ms) {
149 timeout_ms = CONFIG_INT_WDT_PERIOD_MS;
150 }
151
152 s_wdt_period = timeout_ms;
153 wdt_init_common();
154 wdt_hal_init_wdt(&s_wdt.hal, timeout_ms);
155 s_wdt.init_bits |= BIT(0);
156 WDT_LOGD("bk_wdt_start, s_wdt.init_bits:%x\n", s_wdt.init_bits);
157
158 return BK_OK;
159 }
160
bk_wdt_stop(void)161 bk_err_t bk_wdt_stop(void)
162 {
163 WDT_RETURN_ON_DRIVER_NOT_INIT();
164 wdt_deinit_common();
165 s_wdt.init_bits &= ~BIT(0);
166 WDT_LOGD("bk_wdt_stop, s_wdt.init_bits:%x\n", s_wdt.init_bits);
167 return BK_OK;
168 }
169
bk_wdt_feed(void)170 bk_err_t bk_wdt_feed(void)
171 {
172 WDT_RETURN_ON_DRIVER_NOT_INIT();
173 WDT_RETURN_ON_NOT_INIT();
174
175 wdt_hal_init_wdt(&s_wdt.hal, s_wdt_period);
176 bk_misc_update_set_type(RESET_SOURCE_WATCHDOG);
177
178 return BK_OK;
179 }
180
181 #if (CONFIG_INT_WDT)
bk_int_wdt_feed(void)182 void bk_int_wdt_feed(void)
183 {
184 static uint64_t s_last_int_wdt_feed_tick = 0;
185 uint64_t current_tick = bk_get_tick();
186
187 if ((current_tick - s_last_int_wdt_feed_tick) >= s_feed_watchdog_time) {
188 bk_wdt_feed();
189 s_last_int_wdt_feed_tick = current_tick;
190 //WDT_LOGD("feed interrupt watchdog, s_feed_watchdog_time = %u ms.\n", s_feed_watchdog_time);
191 }
192 }
193
bk_wdt_get_feed_time()194 uint32_t bk_wdt_get_feed_time()
195 {
196 return s_feed_watchdog_time;
197 }
198
bk_wdt_set_feed_time(uint32_t dw_set_time)199 void bk_wdt_set_feed_time(uint32_t dw_set_time)
200 {
201 s_feed_watchdog_time = dw_set_time;
202 }
203
204 #endif
205
206 #if (CONFIG_TASK_WDT)
bk_task_wdt_start()207 void bk_task_wdt_start()
208 {
209 if (!s_wdt_debug_enabled) {
210 return;
211 }
212
213 s_task_wdt_enabled = true;
214 }
215
bk_task_wdt_stop()216 void bk_task_wdt_stop()
217 {
218 s_task_wdt_enabled = false;
219 }
220
bk_task_wdt_feed(void)221 void bk_task_wdt_feed(void)
222 {
223 s_last_task_wdt_feed_tick = bk_get_tick();
224 }
225
bk_task_wdt_timeout_check(void)226 void bk_task_wdt_timeout_check(void)
227 {
228 if (s_last_task_wdt_feed_tick && s_task_wdt_enabled) {
229 uint64_t current_tick = bk_get_tick();
230 if ((current_tick - s_last_task_wdt_feed_tick) > TASK_WDG_PERIOD_TICK) {
231 if ((current_tick - s_last_task_wdt_log_tick) > TASK_WDG_PERIOD_TICK) {
232 WDT_LOGW("task watchdog tiggered\n");
233 s_last_task_wdt_log_tick = current_tick;
234 #if DUMP_THREAD_WHEN_TASK_WDG_TIGGERED
235 rtos_dump_task_list();
236 #endif
237 #if DUMP_STACK_WHEN_TASK_WDG_TIGGERED
238 rtos_dump_backtrace();
239 #endif
240 }
241 }
242 }
243 }
244
bk_wdt_is_driver_inited()245 bool bk_wdt_is_driver_inited()
246 {
247 return s_wdt_driver_is_init;
248 }
249
250 #endif
251
bk_wdt_feed_handle(void)252 void bk_wdt_feed_handle(void)
253 {
254 GLOBAL_INT_DECLARATION();
255 GLOBAL_INT_DISABLE();
256
257 #if (CONFIG_INT_WDT)
258 bk_int_wdt_feed();
259 #endif
260
261 #if (CONFIG_TASK_WDT)
262 bk_task_wdt_timeout_check();
263 #endif
264 GLOBAL_INT_RESTORE();
265 }
266
wdt_debug_enable(void)267 void wdt_debug_enable(void)
268 {
269 s_wdt_debug_enabled = true;
270 }
271
wdt_debug_disable(void)272 void wdt_debug_disable(void)
273 {
274 s_wdt_debug_enabled = false;
275 }
276