• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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