1 /*
2 * Copyright (c) 2023 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #ifndef HPM_EWDG_DRV_H
9 #define HPM_EWDG_DRV_H
10
11 #include "hpm_common.h"
12 #include "hpm_ewdg_regs.h"
13 #include "hpm_soc_feature.h"
14
15 /**
16 * @brief EWDG driver APIs
17 * @defgroup ewdg_interface EWDG driver APIs
18 * @addtogroup ewdg_interface
19 * @{
20 */
21
22
23 /**
24 * @brief EWDG error codes
25 */
26 enum {
27 status_ewdg_tick_out_of_range = MAKE_STATUS(status_group_ewdg, 0), /*!< The tick is out of range */
28 status_ewdg_div_out_of_range = MAKE_STATUS(status_group_ewdg, 1), /*!< Clock Divider is out of range */
29 status_ewdg_feature_unsupported = MAKE_STATUS(status_group_ewdg, 2), /*!< Feature is not supported */
30 };
31
32 /**
33 * @brief EWDG Password Definitions
34 *
35 * @defgroup ewdg_password_def
36 * @ingroup ewdg_password_def
37 * @{
38 */
39 #define EWDG_REFRESH_UNLOCK_PASSWORD_DEFAULT (0xED09U) /*!< Default EWDG Refresh Password */
40 #define EWDG_UPDATE_PASSWORD_DEFAULT (0xECF9U) /*!< Default EWDG Update Password */
41 #define EWDG_REFRESH_UNLOCK_FIXED_KEY (0x55AAU) /*!< EWDG Unlock Fixed key */
42 #define EWDG_REFRESH_KEY (0x5A45524FUL) /*!< EWDG Refresh key */
43 /**
44 * @}
45 */
46
47 /**
48 * @brief EWDG Events
49 *
50 * @defgroup ewdg_event
51 * @ingroup ewdg_event
52 * @{
53 */
54 #define EWDG_EVENT_PARITY_ERROR (1UL << 6) /*!< Parity Error Event */
55 #define EWDG_EVENT_TIMEOUT_RESET (1UL << 5) /*!< Timeout Reset Event */
56 #define EWDG_EVENT_TIMEOUT_INTERRUPT (1UL << 4) /*!< Timeout Interrupt Event */
57 #define EWDG_EVENT_CFG_REG_UPDATE_UNLOCK_FAIL (1UL << 3) /*!< Update Unlock Fail Event */
58 #define EWDG_EVENT_CFG_REG_UPDATE_VIOLATION (1UL << 2) /*!< Update Violation Event */
59 #define EWDG_EVENT_REFRESH_UNLOCK_FAIL (1UL << 1) /*!< Refresh Unlock Fail Event */
60 #define EWDG_EVENT_REFRESH_VIOLATION (1UL << 0) /*!< Refresh Violation Event */
61 /**
62 * @}
63 */
64
65 /**
66 * @brief EWDG Interrupts
67 * @defgroup ewdg_interrupt
68 * @ingroup ewdg_interrupt
69 * @{
70 */
71 #define EWDG_INT_PARITY_FAIL (1UL << 2) /*!< Parity Error Interrupt */
72 #define EWDG_INT_CTRL_REG_UNLOCK_FAIL (1UL << 4) /*!< Unlock Control Register Fail Interrupt */
73 #define EWDG_INT_CTRL_REG_UPDATE_FAIL (1UL << 6) /*!< Update Control Register Violation Interrupt */
74 #define EWDG_INT_TIMEOUT (1UL << 16) /*!< Watchdog Timeout Interrupt */
75 #define EWDG_INT_REFRESH_UNLOCK_FAIL (1UL << 20) /*!< Refresh Register Unlock Fail interrupt */
76 #define EWDG_INT_REFRESH_VIOLATION (1UL << 22) /*!< Refresh Register Violation interrupt */
77 /*! All Interrupt masks */
78 #define EWDG_INT_ALL (EWDG_INT_PARITY_FAIL | EWDG_INT_CTRL_REG_UNLOCK_FAIL | EWDG_INT_CTRL_REG_UPDATE_FAIL | \
79 EWDG_INT_TIMEOUT | EWDG_INT_REFRESH_UNLOCK_FAIL | EWDG_INT_REFRESH_VIOLATION)
80 /**
81 * @}
82 */
83
84 /**
85 * @brief EWDG Resets
86 *
87 * @defgroup ewdg_reset_source
88 * @ingroup ewdg_reset_source
89 * @{
90 */
91 #define EWDG_RST_PARITY_FAIL (1UL << 3) /*!< Parity Error Reset */
92 #define EWDG_RST_CTRL_REG_UNLOCK_FAIL (1UL << 5) /*!< Unlock Control Register Fail Reset */
93 #define EWDG_RST_CTRL_REG_UPDATE_FAIL (1UL << 7) /*!< Update Control Register Violation Reset */
94 #define EWDG_RST_TIMEOUT (1UL << 17) /*!< Watchdog Timeout Reset */
95 #define EWDG_RST_REFRESH_UNLOCK_FAIL (1UL << 21) /*!< Refresh Register Unlock Fail Reset */
96 #define EWDG_RST_REFRESH_VIOLATION (1UL << 23) /*!< Refresh Register Violation Reset */
97 /*! All Reset masks */
98 #define EWDG_RST_ALL (EWDG_RST_PARITY_FAIL | EWDG_RST_CTRL_REG_UNLOCK_FAIL | EWDG_RST_CTRL_REG_UPDATE_FAIL | \
99 EWDG_RST_TIMEOUT | EWDG_RST_REFRESH_UNLOCK_FAIL | EWDG_RST_REFRESH_VIOLATION)
100 /**
101 * @}
102 */
103
104
105
106 /**
107 * @brief EWDG Refresh Unlock Methods
108 */
109 typedef enum {
110 /*! Use the Unlock Password directly */
111 ewdg_refresh_unlock_method_password = 0,
112 /*! Use password[14:0] | password[15] */
113 ewdg_refresh_unlock_method_ring_left_shift_password_by_1 = 1,
114 /*! Use fixed key: 0x55AA */
115 ewdg_refresh_unlock_method_fixed_key = 2,
116 /*! Use last_password[14:0] | (last_password[15] ^ password[0]) */
117 ewdg_refresh_unlock_method_ring_left_shift_password_by_1_bit0_xor_password_bit0 = 3,
118 /*! Max allowed range */
119 ewdg_refresh_unlock_method_max = ewdg_refresh_unlock_method_ring_left_shift_password_by_1_bit0_xor_password_bit0
120 } ewdg_refresh_unlock_method_t;
121
122 /**
123 * @brief EWDG Clock source for internal counter
124 */
125 typedef enum {
126 ewdg_cnt_clk_src_bus_clk, /*!< Clock is from BUS clock */
127 ewdg_cnt_clk_src_ext_osc_clk, /*!< Clock is from External OSC */
128 } ewdg_cnt_clk_sel_t;
129
130 /**
131 * @brief EWDG Lower Window Limitations
132 */
133 typedef enum {
134 /*! Refresh should be issued after 8/16 of timeout period */
135 ewdg_window_lower_timeout_period_8_div_16 = 0,
136 /*! Refresh should be issued after 10/16 of timeout period */
137 ewdg_window_lower_timeout_period_10_div_16 = 1,
138 /*! Refresh should be issued after 12/16 of timeout period */
139 ewdg_window_lower_timeout_period_12_div_16 = 2,
140 /*! Refresh should be issued after 14/16 of timeout period */
141 ewdg_window_lower_timeout_period_14_div_16 = 3,
142 /*! Maximum allowed limit value */
143 ewdg_window_lower_timeout_period_max = ewdg_window_lower_timeout_period_14_div_16
144 } ewdg_window_low_limit_t;
145
146 /**
147 * @brief EWDG Upper Window Limitations
148 *
149 * The Actual Upper Window = Lower Window + Upper Window Limit
150 */
151 typedef enum {
152 ewdg_window_upper_timeout_period_8_div_16 = 0, /*!< 8/16 of @ref timeout_reset_val */
153 ewdg_window_upper_timeout_period_1_div_16 = 1, /*!< 1/16 of @ref timeout_reset_val */
154 ewdg_window_upper_timeout_period_2_div_16 = 2, /*!< 2/16 of @ref timeout_reset_val */
155 ewdg_window_upper_timeout_period_3_div_16 = 3, /*!< 3/16 of @ref timeout_reset_val */
156 ewdg_window_upper_timeout_period_4_div_16 = 4, /*!< 4/16 of @ref timeout_reset_val */
157 ewdg_window_upper_timeout_period_5_div_16 = 5, /*!< 5/16 of @ref timeout_reset_val */
158 ewdg_window_upper_timeout_period_6_div_16 = 6, /*!< 6/16 of @ref timeout_reset_val */
159 ewdg_window_upper_timeout_period_7_div_16 = 8, /*!< 7/16 of @ref timeout_reset_val */
160 /*! Maximum allowed upper limit */
161 ewdg_window_upper_timeout_period_max = ewdg_window_upper_timeout_period_7_div_16
162 } ewdg_window_upper_limit_t;
163
164 typedef enum {
165 ewdg_low_power_mode_halt = 0, /*!< Watchdog is halted in low power mode */
166 ewdg_low_power_mode_work_clock_div_4 = 1, /*!< Watchdog is will work with 1/4 normal clock in low power mode */
167 ewdg_low_power_mode_work_clock_div_2 = 2, /*!< Watchdog is will work with 1/2 normal clock in low power mode */
168 ewdg_low_power_mode_work_clock_normal = 3, /*!< Watchdog is will work with normal clock in low power mode */
169 } ewdg_low_power_mode_t;
170
171 /***
172 * @brief EWDG Function Control Configurations
173 */
174 typedef struct {
175 ewdg_cnt_clk_sel_t cnt_clk_sel; /*!< Clock source for counter */
176 bool enable_window_mode; /*!< Enable window mode */
177 ewdg_window_low_limit_t window_lower_limit; /*!< Lower limit of the window */
178 /*! Upper limit of the window
179 * The real upper window = (window_lower_limit/8 + window_upper_limit/16) * timeout_reset_val
180 */
181 ewdg_window_upper_limit_t window_upper_limit;
182
183 bool enable_config_lock; /*!< Enable Lock for the Configuration Registers */
184
185 bool enable_refresh_period; /*!< Enable Refresh period */
186 bool enable_refresh_lock; /*!< Enable Refresh lock */
187 ewdg_refresh_unlock_method_t refresh_unlock_method; /*!< Method to unlock REFRESH_REG */
188
189 bool enable_overtime_self_clear; /*!< Enable Over time self clear */
190
191 bool keep_running_in_debug_mode; /*!< Keep running even in debug mode */
192 ewdg_low_power_mode_t low_power_mode; /*!< Watchdog behavior in low power mode */
193 /*!
194 * Select timeout value type
195 * - true: use the IP-level value (in terms of EWDG counter ticks)
196 * - false: Use the user friendly timeout value (in terms of microseconds)
197 */
198 bool use_lowlevel_timeout;
199 union {
200 struct {
201 uint32_t timeout_interrupt_us; /*!< Timeout value for interrupt (in terms of microseconds) */
202 uint32_t timeout_reset_us; /*!< Timeout value for reset (in terms of microseconds */
203 };
204 struct {
205 uint32_t timeout_interrupt_val; /*!< Timeout value for interrupt (in terms of counter ticks) */
206 /*! Timeout value for reset (in terms of counter ticks
207 * Note: timeout_reset_val must > timeout_interrupt_val
208 */
209 uint32_t timeout_reset_val;
210 uint32_t clock_div_by_power_of_2; /*!< Power of 2 Divider */
211 };
212 };
213
214 uint16_t refresh_period_in_bus_cycles; /*!< Refresh period */
215 uint16_t refresh_unlock_password; /*!< Password for unlocking write to REFRESH_REG */
216
217 uint16_t ctrl_reg_update_password; /*!< Update Password */
218 uint16_t ctrl_reg_update_period_bus_clk_x_128; /*!< Update Period */
219 } ewdg_func_ctrl_config_t;
220
221 /**
222 * @brief EWDG Reset and Interrupt Configurations
223 */
224 typedef struct {
225 bool enable_ctrl_parity_fail_interrupt; /*!< Enable Parity Fail Interrupt */
226 bool enable_ctrl_parity_fail_reset; /*!< Enable Parity Fail Reset */
227 bool enable_ctrl_unlock_fail_interrupt; /*!< Enable Control Register Unlock Fail Interrupt */
228 bool enable_ctrl_unlock_fail_reset; /*!< Enable Control Register Unlock Fail Reset */
229 bool enable_ctrl_update_violation_interrupt; /*!< Enable Control Register Update Violation Interrupt */
230 bool enable_ctrl_update_violation_reset; /*!< Enable Control Register Update Violation Reset */
231 bool enable_timeout_interrupt; /*!< Enable Timeout Interrupt */
232 bool enable_timeout_reset; /*!< Enable Timeout Reset */
233 bool enable_refresh_unlock_fail_interrupt; /*!< Enable Refresh Unlock Fail Interrupt */
234 bool enable_refresh_unlock_fail_reset; /*!< Enable Refresh Unlock Fail Reset */
235 bool enable_refresh_violation_interrupt; /*!< Enable Refresh Violation Interrupt */
236 bool enable_refresh_violation_reset; /*!< Enable Refresh Violation Reset */
237 } ewdg_interrupt_reset_config_t;
238
239 /**
240 * @brief Enhanced Watchdog Configuration Structure
241 */
242 typedef struct {
243 ewdg_interrupt_reset_config_t int_rst_config; /*!< Error Control Configuration */
244 ewdg_func_ctrl_config_t ctrl_config; /*!< Function Control Configuration */
245 bool enable_watchdog; /*!< Enable Watchdog */
246 uint32_t cnt_src_freq; /*!< Frequency for the clock used as the counter clock source */
247 } ewdg_config_t;
248
249 /**
250 * @brief Check whether the Control Registers are locked
251 *
252 * @param [in] ptr EWDG base
253 *
254 * @retval true Control Registers are locked
255 * @retval false Control Registers are unlocked
256 */
ewdg_is_ctrl_reg_locked(EWDG_Type * ptr)257 static inline bool ewdg_is_ctrl_reg_locked(EWDG_Type *ptr)
258 {
259 return ((ptr->CTRL0 & EWDG_CTRL0_CFG_LOCK_MASK) != 0U);
260 }
261
262 /**
263 * @brief Get the Divider for Counter Clock
264 *
265 * @param [in] ptr EWDG base
266 *
267 * @return divider value
268 */
ewdg_get_count_clk_divider(EWDG_Type * ptr)269 static inline uint32_t ewdg_get_count_clk_divider(EWDG_Type *ptr)
270 {
271 return (1UL << EWDG_CTRL0_DIV_VALUE_GET(ptr->CTRL0));
272 }
273
274 /**
275 * @brief Check whether the Refresh register is locked
276 *
277 * @param [in] ptr EWDG base
278 *
279 * @retval true Control Registers are locked
280 * @retval false Control Registers are unlocked
281 */
ewdg_is_refresh_locked(EWDG_Type * ptr)282 static inline bool ewdg_is_refresh_locked(EWDG_Type *ptr)
283 {
284 return ((ptr->CTRL0 & EWDG_CTRL0_REF_LOCK_MASK) != 0U);
285 }
286
287 /**
288 * @brief Unlock Write to Control Registers
289 *
290 * @param [in] ptr EWDG base
291 */
ewdg_unlock_ctrl_regs(EWDG_Type * ptr)292 static inline void ewdg_unlock_ctrl_regs(EWDG_Type *ptr)
293 {
294 uint32_t ctrl_update_prot = ptr->CFG_PROT;
295 ptr->CFG_PROT = ctrl_update_prot;
296 }
297
298 /**
299 * @brief Write Refresh Magic Number to EWDG Refresh register
300 * @param [in] ptr EWDG base
301 */
ewdg_write_refresh_reg(EWDG_Type * ptr)302 static inline void ewdg_write_refresh_reg(EWDG_Type *ptr)
303 {
304 ptr->WDT_REFRESH_REG = EWDG_REFRESH_KEY;
305 }
306
307 /**
308 * @brief Get the Timeout Reset ticks
309 * @param [in] ptr EWDG base
310 * @return Timeout Reset ticks
311 */
ewdg_get_timeout_reset_ticks(EWDG_Type * ptr)312 static inline uint32_t ewdg_get_timeout_reset_ticks(EWDG_Type *ptr)
313 {
314 return ptr->OT_RST_VAL;
315 }
316
317 #if !defined(EWDG_SOC_SUPPORT_TIMEOUT_INTERRUPT) || (EWDG_SOC_SUPPORT_TIMEOUT_INTERRUPT == 1)
318 /**
319 * @brief Get the Timeout Interrupt ticks
320 * @param [in] ptr EWDG base
321 * @return Timeout Interrupt ticks
322 */
ewdg_get_timeout_interrupt_ticks(EWDG_Type * ptr)323 static inline uint32_t ewdg_get_timeout_interrupt_ticks(EWDG_Type *ptr)
324 {
325 return ptr->OT_INT_VAL;
326 }
327 #endif
328
329 /**
330 * @brief Clear Interrupt Status for EWDG
331 *
332 * @note The TIMEOUT_INT_EVENT cannot be cleared directly, it needs to be cleared by the refresh sequence
333 *
334 * @param [in] ptr EWDG base
335 * @param [in] mask Status Mask Bits, @ref ewdg_event
336 */
ewdg_clear_status_flags(EWDG_Type * ptr,uint32_t mask)337 static inline void ewdg_clear_status_flags(EWDG_Type *ptr, uint32_t mask)
338 {
339 ptr->WDT_STATUS = mask;
340 }
341
342 /**
343 * @brief Get the Status of EWDG
344 *
345 * @param [in] ptr EWDG base
346 *
347 * @return STATUS register value
348 */
ewdg_get_status_flags(EWDG_Type * ptr)349 static inline uint32_t ewdg_get_status_flags(EWDG_Type *ptr)
350 {
351 return ptr->WDT_STATUS;
352 }
353
354 /**
355 * @brief Get the Refresh Unlock Mechanism
356 * @param [in] ptr EWDG base
357 * @return EWDG refresh unlock method
358 */
ewdg_get_refresh_unlock_method(EWDG_Type * ptr)359 static inline ewdg_refresh_unlock_method_t ewdg_get_refresh_unlock_method(EWDG_Type *ptr)
360 {
361 return (ewdg_refresh_unlock_method_t) (EWDG_CTRL0_REF_UNLOCK_MEC_GET(ptr->CTRL0));
362 }
363
364 /**
365 * @brief Enable EWDG
366 *
367 * This function enables the functionality of the EWDG and start the watchdog timer
368 *
369 * @param [in] ptr EWDG base
370 *
371 * @note Once the EWDG is enabled,
372 * - if the software needs to update the control register, the update unlock must be
373 * performed first if the control register lock is enabled.
374 *
375 */
376 void ewdg_enable(EWDG_Type *ptr);
377
378
379 /**
380 * @brief Disable EWDG
381 * @param [in] ptr EWDG base
382 */
383 void ewdg_disable(EWDG_Type *ptr);
384
385 /**
386 * @brief Initialize the Control function for EWDG
387 *
388 * @param [in] ptr EWDG base
389 * @param [in] config Control Function Configuration
390 *
391 * @retval status_invalid_argument Invalid argument was detected
392 * @retval status_success No error happened
393 */
394 hpm_stat_t ewdg_init_ctrl_func(EWDG_Type *ptr, ewdg_func_ctrl_config_t *config, uint32_t cnt_src_freq);
395
396 /**
397 * @brief Initialize the Error function for EWDG
398 *
399 * @param [in] ptr EWDG base
400 * @param [in] config Error Function Configuration
401 *
402 * @retval status_invalid_argument Invalid argument was detected
403 * @retval status_success No error happened
404 */
405 hpm_stat_t ewdg_init_interrupt_reset(EWDG_Type *ptr, ewdg_interrupt_reset_config_t *config);
406
407 /**
408 * @brief Get default configuration for EWDG
409 * @param [in] ptr EWDG base
410 * @param [out] config EWDG Configuration
411 */
412 void ewdg_get_default_config(EWDG_Type *ptr, ewdg_config_t *config);
413
414 /**
415 * @brief Initialize the EWDG module
416 *
417 * @param [in] ptr EWDG base
418 * @param [in] config EWDG configuration
419 *
420 * @retval status_invalid_argument Invalid argument was detected
421 * @retval status_success No error happened
422 */
423 hpm_stat_t ewdg_init(EWDG_Type *ptr, ewdg_config_t *config);
424
425 /**
426 * @brief Unlock the write to refresh register
427 *
428 * @param [in] ptr EWDG base
429 *
430 * @retval status_invalid_argument Invalid argument was detected
431 * @retval status_success No error happened
432 */
433 hpm_stat_t ewdg_unlock_refresh(EWDG_Type *ptr);
434
435 /**
436 * @brief Refresh EWDG
437 *
438 * @param [in] ptr EWDG base
439 *
440 * @retval status_invalid_argument Invalid argument was detected
441 * @retval status_success No error happened
442 */
443 hpm_stat_t ewdg_refresh(EWDG_Type *ptr);
444
445 /**
446 * @brief Get the Divided Counter Clock Frequency for EWDG
447 *
448 * @param [in] ptr EWDG base
449 * @param [in] src_clk_freq Source clock of the Counter clock
450 *
451 * @return divided Counter clock Frequency
452 */
453 uint32_t ewdg_get_count_clock_freq(EWDG_Type *ptr, uint32_t src_clk_freq);
454
455 /**
456 * @brief Convert the timeout in terms of microseconds to the timeout in terms of timeout ticks
457 *
458 * @param [in] src_clk_freq Clock Frequency of the counter clock source
459 * @param [in] timeout_us Timeout in terms of microseconds
460 *
461 * @return timeout in terms of counter clock ticks
462 */
463 uint64_t ewdg_convert_timeout_us_to_timeout_ticks(uint32_t src_clk_freq, uint32_t timeout_us);
464
465 /**
466 * @brief Convert the timeout in terms of timeout ticks to the timeout in terms of microseconds
467 *
468 * @param [in] ptr EWDG base
469 * @param [in] src_clk_freq Clock Frequency of the counter clock source
470 * @param [in] timeout_ticks Timeout in terms of ticks
471 *
472 * @return timeout in terms of counter clock ticks
473 */
474 uint32_t ewdg_convert_timeout_ticks_to_timeout_us(EWDG_Type *ptr, uint32_t srk_clk_freq, uint32_t timeout_ticks);
475
476 /**
477 * @brief Enable EWDG interrupt
478 * @param [in] ptr EWDG base
479 * @param [in] mask Interrupt Mask, valid value refer to @ref ewdg_interrupt
480 */
481 void ewdg_enable_interrupt(EWDG_Type *ptr, uint32_t mask);
482
483 /**
484 * @brief Disable EWDG interrupt
485 * @param [in] ptr EWDG base
486 * @param [in] mask Interrupt Mask, valid value refer to @ref ewdg_interrupt
487 */
488 void ewdg_disable_interrupt(EWDG_Type *ptr, uint32_t mask);
489
490 /**
491 * @brief Enable EWDG Reset
492 * @param [in] ptr EWDG base
493 * @param [in] mask Reset Mask, valid value refer to @ref ewdg_reset_source
494 */
495 void ewdg_enable_reset(EWDG_Type *ptr, uint32_t mask);
496
497 /**
498 * @brief Disable EWDG Reset
499 * @param [in] ptr EWDG base
500 * @param [in] mask Reset Mask, valid value refer to @ref ewdg_reset_source
501 */
502 void ewdg_disable_reset(EWDG_Type *ptr, uint32_t mask);
503
504 /**
505 * @brief Switch the EWDG clock source
506 * @param [in] ptr EWDG base
507 * @param [in] clk_sel Clock source selection for EWDG counter
508 */
509 void ewdg_switch_clock_source(EWDG_Type *ptr, ewdg_cnt_clk_sel_t clk_sel);
510
511 #ifdef __cplusplus
512 extern "C" {
513 #endif
514
515 #ifdef __cplusplus
516 }
517 #endif
518
519 /**
520 * @}
521 */
522
523 #endif /* HPM_EWDG_DRV_H */
524