1 /* SPDX-License-Identifier: Apache-2.0 */
2 /*
3  * Copyright (c) 2023 Intel Corporation
4  *
5  * Author: Adrian Warecki <adrian.warecki@intel.com>
6  */
7 
8 #include <zephyr/drivers/watchdog.h>
9 #include <zephyr/logging/log.h>
10 #include <zephyr/sys_clock.h>
11 #include <zephyr/math/ilog2.h>
12 
13 #include "wdt_dw_common.h"
14 #include "wdt_dw.h"
15 
16 LOG_MODULE_REGISTER(wdt_dw_common, CONFIG_WDT_LOG_LEVEL);
17 
18 #define WDT_DW_FLAG_CONFIGURED	0x80000000
19 
dw_wdt_check_options(const uint8_t options)20 int dw_wdt_check_options(const uint8_t options)
21 {
22 	if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) {
23 		LOG_WRN("Pausing watchdog by debugger is not configurable");
24 	}
25 
26 	if (options & WDT_OPT_PAUSE_IN_SLEEP) {
27 		LOG_WRN("Pausing watchdog in sleep is not configurable");
28 	}
29 
30 	return 0;
31 }
32 
dw_wdt_configure(const uint32_t base,const uint32_t config)33 int dw_wdt_configure(const uint32_t base, const uint32_t config)
34 {
35 	uint32_t period;
36 
37 	if (!(config & WDT_DW_FLAG_CONFIGURED)) {
38 		LOG_ERR("Timeout not installed.");
39 		return -ENOTSUP;
40 	}
41 
42 	/* Configure timeout */
43 	period = config & ~WDT_DW_FLAG_CONFIGURED;
44 
45 	if (dw_wdt_dual_timeout_period_get(base)) {
46 		dw_wdt_timeout_period_init_set(base, period);
47 	}
48 
49 	dw_wdt_timeout_period_set(base, period);
50 
51 	/* Enable watchdog */
52 	dw_wdt_enable(base);
53 	dw_wdt_counter_restart(base);
54 
55 	return 0;
56 }
57 
dw_wdt_calc_period(const uint32_t base,const uint32_t clk_freq,const struct wdt_timeout_cfg * config,uint32_t * period_out)58 int dw_wdt_calc_period(const uint32_t base, const uint32_t clk_freq,
59 		       const struct wdt_timeout_cfg *config, uint32_t *period_out)
60 {
61 	uint64_t period64;
62 	uint32_t period;
63 
64 	/* Window timeout is not supported by this driver */
65 	if (config->window.min) {
66 		LOG_ERR("Window timeout is not supported.");
67 		return -ENOTSUP;
68 	}
69 
70 	period64 = (uint64_t)clk_freq * config->window.max;
71 	period64 /= 1000;
72 	if (!period64 || (period64 >> 31)) {
73 		LOG_ERR("Window max is out of range.");
74 		return -EINVAL;
75 	}
76 
77 	period = period64 - 1;
78 	period = ilog2(period);
79 
80 	if (period >= dw_wdt_cnt_width_get(base)) {
81 		LOG_ERR("Watchdog timeout too long.");
82 		return -EINVAL;
83 	}
84 
85 	/* The minimum counter value is 64k, maximum 2G */
86 	*period_out = WDT_DW_FLAG_CONFIGURED | (period >= 15 ? period - 15 : 0);
87 	return 0;
88 }
89 
dw_wdt_probe(const uint32_t base,const uint32_t reset_pulse_length)90 int dw_wdt_probe(const uint32_t base, const uint32_t reset_pulse_length)
91 {
92 	/* Check component type */
93 	const uint32_t type = dw_wdt_comp_type_get(base);
94 
95 	if (type != WDT_COMP_TYPE_VALUE) {
96 		LOG_ERR("Invalid component type %x", type);
97 		return -ENODEV;
98 	}
99 
100 	dw_wdt_reset_pulse_length_set(base, reset_pulse_length);
101 
102 	return 0;
103 }
104