• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 #include "hpm_ewdg_drv.h"
8 
9 /***********************************************************************************************************************
10  *
11  * Definitions
12  *
13  **********************************************************************************************************************/
14 #define EWDG_CTRL_REG_PARITY_BIT_MASK (1UL << 31)       /*!< Parity bit for Control Register */
15 
16 #ifdef EWDG_SOC_CLK_DIV_VAL_MAX
17 #define EWDG_CTRL_DIV_VAL_MAX EWDG_SOC_CLK_DIV_VAL_MAX
18 #else
19 #define EWDG_CTRL_DIV_VAL_MAX (EWDG_CTRL0_DIV_VALUE_MASK >> EWDG_CTRL0_DIV_VALUE_SHIFT)
20 #endif
21 #define EWDG_CTRL_WIN_UPPER_MAX (EWDG_CTRL0_WIN_UPPER_MASK >> EWDG_CTRL0_WIN_UPPER_SHIFT)
22 
23 #define EWDG_CTRL_REG_UPDATE_PERIOD_DEFAULT (4UL)       /* 512 Bus clock */
24 
25 #define EWDG_RING_LEFT_SHIFT_1(val) (((uint16_t)(val) << 1) | ((uint16_t)(val) >> 15))
26 
27 #define EWDG_REFRESH_PERIOD_DEFAULT             (10000U)
28 
29 #define EWDG_INTERRUPT_TIMEOUT_TICKS_DEFAULT    (0UL)
30 #define EWDG_RESET_TIMEOUT_TICKS_DEFAULT        (65535UL)
31 
32 #if defined(EWDG_SOC_OVERTIME_REG_WIDTH) && (EWDG_SOC_OVERTIME_REG_WIDTH == 16)
33 #define EWDG_TIMEOUT_TICK_MAX (65535)
34 #else
35 #define EWDG_TIMEOUT_TICK_MAX (0xFFFFFFFFUL)
36 #endif
37 
38 /***********************************************************************************************************************
39  *
40  * Prototypes
41  *
42  **********************************************************************************************************************/
43 static bool ewdg_need_set_parity_bit(uint32_t reg_val);
44 
45 /***********************************************************************************************************************
46  *
47  * Codes
48  *
49  **********************************************************************************************************************/
ewdg_need_set_parity_bit(uint32_t reg_val)50 static bool ewdg_need_set_parity_bit(uint32_t reg_val)
51 {
52     uint32_t non_zero_bits = 0;
53     while (reg_val > 0) {
54         reg_val &= (reg_val - 1UL);
55         ++non_zero_bits;
56     }
57     return ((non_zero_bits & 1UL) != 0);
58 }
59 
ewdg_get_default_config(EWDG_Type * ptr,ewdg_config_t * config)60 void ewdg_get_default_config(EWDG_Type *ptr, ewdg_config_t *config)
61 {
62     if ((ptr != NULL) && (config != NULL)) {
63 
64         (void) memset(config, 0, sizeof(ewdg_config_t));
65 
66         config->ctrl_config.cnt_clk_sel = ewdg_cnt_clk_src_ext_osc_clk;
67         config->ctrl_config.use_lowlevel_timeout = true;
68 
69         config->ctrl_config.refresh_unlock_method = ewdg_refresh_unlock_method_password;
70         config->ctrl_config.enable_overtime_self_clear = false;
71 
72         config->ctrl_config.timeout_interrupt_val = EWDG_INTERRUPT_TIMEOUT_TICKS_DEFAULT;
73         config->ctrl_config.timeout_reset_val = EWDG_RESET_TIMEOUT_TICKS_DEFAULT;
74         config->ctrl_config.clock_div_by_power_of_2 = 0;
75 
76         config->ctrl_config.refresh_unlock_password = EWDG_REFRESH_UNLOCK_PASSWORD_DEFAULT;
77         config->ctrl_config.ctrl_reg_update_password = EWDG_UPDATE_PASSWORD_DEFAULT;
78         config->ctrl_config.ctrl_reg_update_period_bus_clk_x_128 = EWDG_CTRL_REG_UPDATE_PERIOD_DEFAULT;
79 
80         config->ctrl_config.low_power_mode = ewdg_low_power_mode_work_clock_normal;
81 
82         config->ctrl_config.refresh_period_in_bus_cycles = EWDG_REFRESH_PERIOD_DEFAULT;
83     }
84 }
85 
ewdg_init_ctrl_func(EWDG_Type * ptr,ewdg_func_ctrl_config_t * config,uint32_t cnt_src_freq)86 hpm_stat_t ewdg_init_ctrl_func(EWDG_Type *ptr, ewdg_func_ctrl_config_t *config, uint32_t cnt_src_freq)
87 {
88     hpm_stat_t status = status_invalid_argument;
89 
90     do {
91         if ((ptr == NULL) || (config == NULL) || (cnt_src_freq == 0)) {
92             break;
93         }
94         if (config->window_lower_limit > ewdg_window_lower_timeout_period_max) {
95             break;
96         }
97         if (config->window_upper_limit > ewdg_window_upper_timeout_period_max) {
98             break;
99         }
100         if (config->refresh_unlock_method > ewdg_refresh_unlock_method_max) {
101             break;
102         }
103 
104         uint32_t ctrl0 = 0;
105 
106         uint32_t ot_int_ticks;
107         uint32_t ot_reset_ticks;
108         uint32_t clock_div_by_pwr_2 = 0;
109         if (!config->use_lowlevel_timeout) {
110             uint64_t timeout_interrupt_ticks = ewdg_convert_timeout_us_to_timeout_ticks(config->timeout_interrupt_us,
111                                                                                         cnt_src_freq);
112             uint64_t timeout_reset_ticks = ewdg_convert_timeout_us_to_timeout_ticks(config->timeout_reset_us,
113                                                                                     cnt_src_freq);
114             clock_div_by_pwr_2 = 0;
115             while ((timeout_interrupt_ticks > EWDG_TIMEOUT_TICK_MAX) || (timeout_reset_ticks > EWDG_TIMEOUT_TICK_MAX)) {
116                 ++clock_div_by_pwr_2;
117                 timeout_interrupt_ticks >>= 1;
118                 timeout_reset_ticks >>= 1;
119             }
120             if (clock_div_by_pwr_2 > EWDG_SOC_CLK_DIV_VAL_MAX) {
121                 status = status_ewdg_div_out_of_range;
122                 /* Cannot get the expected EWDG setting via the specified timeout input */
123                 break;
124             }
125             ot_int_ticks = (uint32_t) (timeout_interrupt_ticks & 0xFFFFFFFFUL);
126             ot_reset_ticks = (uint32_t) (timeout_reset_ticks & 0xFFFFFFFFUL);
127 
128         } else {
129             clock_div_by_pwr_2 = config->clock_div_by_power_of_2;
130             ot_int_ticks = config->timeout_interrupt_val;
131             ot_reset_ticks = config->timeout_reset_val;
132 
133             if (clock_div_by_pwr_2 > EWDG_SOC_CLK_DIV_VAL_MAX) {
134                 status = status_ewdg_div_out_of_range;
135                 /* Cannot get the expected EWDG setting via the specified timeout input */
136                 break;
137             }
138             if ((ot_int_ticks > EWDG_TIMEOUT_TICK_MAX) || (ot_reset_ticks > EWDG_TIMEOUT_TICK_MAX)) {
139                 status = status_ewdg_tick_out_of_range;
140                 break;
141             }
142         }
143 
144         if (config->cnt_clk_sel == ewdg_cnt_clk_src_ext_osc_clk) {
145             ctrl0 |= EWDG_CTRL0_CLK_SEL_MASK;
146         }
147         ctrl0 |= EWDG_CTRL0_DIV_VALUE_SET(clock_div_by_pwr_2);
148         if (config->enable_window_mode) {
149             ctrl0 |= EWDG_CTRL0_WIN_EN_MASK;
150 
151             ctrl0 |= EWDG_CTRL0_WIN_LOWER_SET(config->window_lower_limit);
152             ctrl0 |= EWDG_CTRL0_WIN_UPPER_SET(config->window_upper_limit);
153         }
154 
155         if (config->enable_config_lock) {
156             ctrl0 |= EWDG_CTRL0_CFG_LOCK_MASK;
157         }
158 
159         if (config->enable_refresh_period) {
160             ctrl0 |= EWDG_CTRL0_REF_OT_REQ_MASK;
161         }
162         if (config->enable_refresh_lock) {
163             ctrl0 |= EWDG_CTRL0_REF_LOCK_MASK;
164         }
165         ctrl0 |= EWDG_CTRL0_REF_UNLOCK_MEC_SET(config->refresh_unlock_method);
166 
167         if (config->enable_overtime_self_clear) {
168             ctrl0 |= EWDG_CTRL0_OT_SELF_CLEAR_MASK;
169         }
170         if (config->keep_running_in_debug_mode) {
171             ctrl0 |= EWDG_CTRL0_EN_DBG_MASK;
172         }
173         ctrl0 |= EWDG_CTRL0_EN_LP_SET(config->low_power_mode);
174 
175         /* Set Parity bit if necessary */
176         if (ewdg_need_set_parity_bit(ctrl0)) {
177             ctrl0 |= EWDG_CTRL_REG_PARITY_BIT_MASK;
178         }
179 
180         if (ewdg_is_ctrl_reg_locked(ptr)) {
181             ewdg_unlock_ctrl_regs(ptr);
182         }
183         ptr->CTRL0 = ctrl0;
184 
185         ptr->CFG_PROT = EWDG_CFG_PROT_UPD_OT_TIME_SET(config->ctrl_reg_update_period_bus_clk_x_128) |
186                         EWDG_CFG_PROT_UPD_PSD_SET(config->ctrl_reg_update_password);
187 
188         ptr->REF_TIME = config->refresh_period_in_bus_cycles;
189         ptr->REF_PROT = EWDG_REF_PROT_REF_UNL_PSD_SET(config->refresh_unlock_password);
190 
191 
192 #if !defined(EWDG_SOC_SUPPORT_TIMEOUT_INTERRUPT) || (EWDG_SOC_SUPPORT_TIMEOUT_INTERRUPT == 1)
193         ptr->OT_INT_VAL = ot_int_ticks;
194 #endif
195         ptr->OT_RST_VAL = ot_reset_ticks;
196 
197         status = status_success;
198 
199     } while (false);
200 
201     return status;
202 }
203 
ewdg_init_interrupt_reset(EWDG_Type * ptr,ewdg_interrupt_reset_config_t * config)204 hpm_stat_t ewdg_init_interrupt_reset(EWDG_Type *ptr, ewdg_interrupt_reset_config_t *config)
205 {
206     hpm_stat_t status = status_invalid_argument;
207 
208     do {
209         if ((ptr == NULL) || (config == NULL)) {
210             break;
211         }
212 
213         uint32_t ctrl1 = 0;
214         if (config->enable_ctrl_parity_fail_reset) {
215             ctrl1 |= EWDG_RST_PARITY_FAIL;
216         }
217         if (config->enable_ctrl_unlock_fail_reset) {
218             ctrl1 |= EWDG_RST_CTRL_REG_UNLOCK_FAIL;
219         }
220         if (config->enable_refresh_unlock_fail_reset) {
221             ctrl1 |= EWDG_RST_REFRESH_UNLOCK_FAIL;
222         }
223         if (config->enable_ctrl_update_violation_reset) {
224             ctrl1 |= EWDG_RST_CTRL_REG_UPDATE_FAIL;
225         }
226         if (config->enable_timeout_reset) {
227             ctrl1 |= EWDG_RST_TIMEOUT;
228         }
229         if (config->enable_refresh_violation_reset) {
230             ctrl1 |= EWDG_RST_REFRESH_VIOLATION;
231         }
232 
233 #if defined(EWDG_SOC_SUPPORT_INTERRUPT) && (EWDG_SOC_SUPPORT_INTERRUPT == 0)
234         if (config->enable_timeout_interrupt) {
235             status = status_ewdg_feature_unsupported;
236             break;
237         }
238 #else
239         if (config->enable_timeout_interrupt) {
240             ctrl1 |= EWDG_INT_TIMEOUT;
241         }
242 #endif
243         if (config->enable_ctrl_parity_fail_interrupt) {
244             ctrl1 |= EWDG_INT_PARITY_FAIL;
245         }
246         if (config->enable_ctrl_unlock_fail_interrupt) {
247             ctrl1 |= EWDG_INT_CTRL_REG_UNLOCK_FAIL;
248         }
249         if (config->enable_refresh_unlock_fail_interrupt) {
250             ctrl1 |= EWDG_INT_REFRESH_UNLOCK_FAIL;
251         }
252         if (config->enable_ctrl_update_violation_interrupt) {
253             ctrl1 |= EWDG_INT_CTRL_REG_UPDATE_FAIL;
254         }
255         if (config->enable_refresh_violation_interrupt) {
256             ctrl1 |= EWDG_INT_REFRESH_VIOLATION;
257         }
258 
259         /* Set Parity bit if necessary */
260         if (ewdg_need_set_parity_bit(ctrl1)) {
261             ctrl1 |= EWDG_CTRL_REG_PARITY_BIT_MASK;
262         }
263 
264         if (ewdg_is_ctrl_reg_locked(ptr)) {
265             ewdg_unlock_ctrl_regs(ptr);
266         }
267         ptr->CTRL1 = ctrl1;
268 
269         status = status_success;
270 
271     } while (false);
272 
273     return status;
274 }
275 
ewdg_init(EWDG_Type * ptr,ewdg_config_t * config)276 hpm_stat_t ewdg_init(EWDG_Type *ptr, ewdg_config_t *config)
277 {
278     hpm_stat_t status = status_invalid_argument;
279 
280     do {
281         if ((ptr == NULL) || (config == NULL)) {
282             break;
283         }
284 
285         status = ewdg_init_ctrl_func(ptr, &config->ctrl_config, config->cnt_src_freq);
286         if (status != status_success) {
287             break;
288         }
289         status = ewdg_init_interrupt_reset(ptr, &config->int_rst_config);
290         if (status != status_success) {
291             break;
292         }
293 
294         if (ewdg_is_ctrl_reg_locked(ptr)) {
295             ewdg_unlock_ctrl_regs(ptr);
296         }
297         ptr->WDT_EN = (config->enable_watchdog) ? 1UL : 0UL;
298 
299     } while (false);
300 
301     return status;
302 }
303 
ewdg_unlock_refresh(EWDG_Type * ptr)304 hpm_stat_t ewdg_unlock_refresh(EWDG_Type *ptr)
305 {
306     hpm_stat_t status = status_invalid_argument;
307 
308     do {
309         if (ptr == NULL) {
310             break;
311         }
312 
313         if (!ewdg_is_refresh_locked(ptr)) {
314             status = status_success;
315             break;
316         }
317 
318         ewdg_refresh_unlock_method_t unlock_method = ewdg_get_refresh_unlock_method(ptr);
319         uint32_t unlock_password;
320         uint32_t reg_unlock_password = EWDG_REF_PROT_REF_UNL_PSD_GET(ptr->REF_PROT);
321         if (unlock_method == ewdg_refresh_unlock_method_password) {
322             unlock_password = reg_unlock_password;
323         } else if (unlock_method == ewdg_refresh_unlock_method_fixed_key) {
324             unlock_password = EWDG_REFRESH_UNLOCK_FIXED_KEY;
325         } else if (unlock_method == ewdg_refresh_unlock_method_ring_left_shift_password_by_1) {
326             unlock_password = EWDG_RING_LEFT_SHIFT_1(reg_unlock_password);
327         } else if (unlock_method == ewdg_refresh_unlock_method_ring_left_shift_password_by_1_bit0_xor_password_bit0) {
328             uint16_t high_15 = (reg_unlock_password << 1) & 0xFFFFU;
329             uint16_t low_0 = reg_unlock_password >> 15;
330             low_0 ^= reg_unlock_password;
331             unlock_password = high_15 | (low_0 & 0x1UL);
332         } else {
333             /* Should never reach this branch */
334             break;
335         }
336 
337         ptr->REF_PROT = unlock_password;
338 
339         status = status_success;
340 
341     } while (false);
342 
343     return status;
344 }
345 
ewdg_refresh(EWDG_Type * ptr)346 hpm_stat_t ewdg_refresh(EWDG_Type *ptr)
347 {
348     hpm_stat_t status = ewdg_unlock_refresh(ptr);
349     if (status == status_success) {
350         ewdg_write_refresh_reg(ptr);
351     }
352     return status;
353 }
354 
ewdg_get_count_clock_freq(EWDG_Type * ptr,uint32_t src_clk_freq)355 uint32_t ewdg_get_count_clock_freq(EWDG_Type *ptr, uint32_t src_clk_freq)
356 {
357     uint32_t divided_freq = 0;
358     if (ptr != NULL) {
359         uint32_t divider = ewdg_get_count_clk_divider(ptr);
360         divided_freq = src_clk_freq / divider;
361     }
362     return divided_freq;
363 }
364 
ewdg_convert_timeout_us_to_timeout_ticks(uint32_t src_clk_freq,uint32_t timeout_us)365 uint64_t ewdg_convert_timeout_us_to_timeout_ticks(uint32_t src_clk_freq, uint32_t timeout_us)
366 {
367     uint64_t timeout_ticks = 0;
368     if (src_clk_freq != 0U) {
369         uint32_t ns_per_tick = 1000000000UL / src_clk_freq;
370         uint64_t timeout_ns = (uint64_t) timeout_us * 1000UL;
371         timeout_ticks = (timeout_ns + ns_per_tick - 1U) / ns_per_tick;
372     }
373     return timeout_ticks;
374 }
375 
ewdg_convert_timeout_ticks_to_timeout_us(EWDG_Type * ptr,uint32_t src_clk_freq,uint32_t timeout_ticks)376 uint32_t ewdg_convert_timeout_ticks_to_timeout_us(EWDG_Type *ptr, uint32_t src_clk_freq, uint32_t timeout_ticks)
377 {
378     uint32_t timeout_us;
379     if (src_clk_freq == 0U) {
380         timeout_us = 0;
381     } else {
382         uint32_t actual_clk_freq = src_clk_freq / ewdg_get_count_clk_divider(ptr);
383         uint32_t ns_per_tick = 1000000000UL / actual_clk_freq;
384         uint64_t timeout_ns = (uint64_t) timeout_ticks * ns_per_tick;
385         timeout_us = timeout_ns / 1000UL;
386     }
387     return timeout_us;
388 }
389 
ewdg_enable_interrupt(EWDG_Type * ptr,uint32_t mask)390 void ewdg_enable_interrupt(EWDG_Type *ptr, uint32_t mask)
391 {
392     uint32_t interrupt_mask = mask & EWDG_INT_ALL;
393     if (ptr != NULL) {
394         uint32_t ctrl1 = ptr->CTRL1 | interrupt_mask;
395         /* Set Parity bit if necessary */
396         if (ewdg_need_set_parity_bit(ctrl1)) {
397             ctrl1 |= EWDG_CTRL_REG_PARITY_BIT_MASK;
398         }
399         if (ewdg_is_ctrl_reg_locked(ptr)) {
400             ewdg_unlock_ctrl_regs(ptr);
401         }
402         ptr->CTRL1 = ctrl1;
403     }
404 }
405 
ewdg_disable_interrupt(EWDG_Type * ptr,uint32_t mask)406 void ewdg_disable_interrupt(EWDG_Type *ptr, uint32_t mask)
407 {
408     uint32_t interrupt_mask = mask & EWDG_INT_ALL;
409     if (ptr != NULL) {
410         uint32_t ctrl1 = ptr->CTRL1 & ~interrupt_mask;
411         /* Set Parity bit if necessary */
412         if (ewdg_need_set_parity_bit(ctrl1)) {
413             ctrl1 |= EWDG_CTRL_REG_PARITY_BIT_MASK;
414         }
415         if (ewdg_is_ctrl_reg_locked(ptr)) {
416             ewdg_unlock_ctrl_regs(ptr);
417         }
418         ptr->CTRL1 = ctrl1;
419     }
420 }
421 
ewdg_enable_reset(EWDG_Type * ptr,uint32_t mask)422 void ewdg_enable_reset(EWDG_Type *ptr, uint32_t mask)
423 {
424     uint32_t reset_mask = mask & EWDG_RST_ALL;
425     if (ptr != NULL) {
426         uint32_t ctrl1 = ptr->CTRL1 | reset_mask;
427         /* Set Parity bit if necessary */
428         if (ewdg_need_set_parity_bit(ctrl1)) {
429             ctrl1 |= EWDG_CTRL_REG_PARITY_BIT_MASK;
430         }
431         if (ewdg_is_ctrl_reg_locked(ptr)) {
432             ewdg_unlock_ctrl_regs(ptr);
433         }
434         ptr->CTRL1 = ctrl1;
435     }
436 }
437 
ewdg_disable_reset(EWDG_Type * ptr,uint32_t mask)438 void ewdg_disable_reset(EWDG_Type *ptr, uint32_t mask)
439 {
440     uint32_t reset_mask = mask & EWDG_RST_ALL;
441     if (ptr != NULL) {
442         uint32_t ctrl1 = ptr->CTRL1 & ~reset_mask;
443         /* Set Parity bit if necessary */
444         if (ewdg_need_set_parity_bit(ctrl1)) {
445             ctrl1 |= EWDG_CTRL_REG_PARITY_BIT_MASK;
446         }
447         if (ewdg_is_ctrl_reg_locked(ptr)) {
448             ewdg_unlock_ctrl_regs(ptr);
449         }
450         ptr->CTRL1 = ctrl1;
451     }
452 }
453 
ewdg_switch_clock_source(EWDG_Type * ptr,ewdg_cnt_clk_sel_t clk_sel)454 void ewdg_switch_clock_source(EWDG_Type *ptr, ewdg_cnt_clk_sel_t clk_sel)
455 {
456     if (ptr != NULL) {
457         uint32_t ctrl0 = ptr->CTRL0 & ~EWDG_CTRL0_CLK_SEL_MASK;
458         /* Set Parity bit if necessary */
459         if (clk_sel == ewdg_cnt_clk_src_ext_osc_clk) {
460             ctrl0 |= EWDG_CTRL0_CLK_SEL_MASK;
461         }
462         if (ewdg_need_set_parity_bit(ctrl0)) {
463             ctrl0 |= EWDG_CTRL_REG_PARITY_BIT_MASK;
464         }
465         if (ewdg_is_ctrl_reg_locked(ptr)) {
466             ewdg_unlock_ctrl_regs(ptr);
467         }
468         ptr->CTRL0 = ctrl0;
469     }
470 }
471 
ewdg_enable(EWDG_Type * ptr)472 void ewdg_enable(EWDG_Type *ptr)
473 {
474     if (ewdg_is_ctrl_reg_locked(ptr)) {
475         ewdg_unlock_ctrl_regs(ptr);
476     }
477     ptr->WDT_EN = 1;
478 }
479 
ewdg_disable(EWDG_Type * ptr)480 void ewdg_disable(EWDG_Type *ptr)
481 {
482     if (ewdg_is_ctrl_reg_locked(ptr)) {
483         ewdg_unlock_ctrl_regs(ptr);
484     }
485     ptr->WDT_EN = 0;
486 }
487