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