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