1 /*
2 * Copyright (c) 2021-2023 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7 #include "hpm_wdg_drv.h"
8
9 #define TICKS_1K (1024UL)
10 #define TICKS_1M (1024UL * TICKS_1K)
11 #define TICKS_1G (1024UL * TICKS_1M)
12 #define ONE_SECOND_TICKS_IN_NS (1000UL * 1000UL * 1000UL)
13
14 typedef struct {
15 uint32_t top;
16 reset_interval_t interval;
17 } reset_interval_map_t;
18
19 typedef struct {
20 uint32_t top;
21 interrupt_interval_t interval;
22 } interrupt_interval_map_t;
23
24 static const reset_interval_map_t k_reset_interval_map[reset_interval_out_of_range + 1U] = {
25 {128UL, reset_interval_clock_period_mult_128},
26 {256UL, reset_interval_clock_period_mult_256},
27 {512UL, reset_interval_clock_period_mult_512},
28 {1UL * TICKS_1K, reset_interval_clock_period_mult_1k},
29 {2UL * TICKS_1K, reset_interval_clock_period_mult_2k},
30 {4UL * TICKS_1K, reset_interval_clock_period_mult_4k},
31 {8UL * TICKS_1K, reset_interval_clock_period_mult_8k},
32 {16UL * TICKS_1K, reset_interval_clock_period_mult_16k},
33 {0xFFFFFFFFUL, reset_interval_out_of_range},
34 };
35
36 static const interrupt_interval_map_t k_interrupt_interval_map[interrupt_interval_out_of_range + 1U] = {
37 {64UL, interrupt_interval_clock_period_multi_64},
38 {256UL, interrupt_interval_clock_period_multi_256},
39 {1UL * TICKS_1K, interrupt_interval_clock_period_multi_1k},
40 {2UL * TICKS_1K, interrupt_interval_clock_period_multi_2k},
41 {4UL * TICKS_1K, interrupt_interval_clock_period_multi_4k},
42 {8UL * TICKS_1K, interrupt_interval_clock_period_multi_8k},
43 {16UL * TICKS_1K, interrupt_interval_clock_period_multi_16k},
44 {32UL * TICKS_1K, interrupt_interval_clock_period_multi_32k},
45 {128UL * TICKS_1K, interrupt_interval_clock_period_multi_128k},
46 {512UL * TICKS_1K, interrupt_interval_clock_period_multi_512k},
47 {2UL * TICKS_1M, interrupt_interval_clock_period_multi_2m},
48 {8UL * TICKS_1M, interrupt_interval_clock_period_multi_8m},
49 {32UL * TICKS_1M, interrupt_interval_clock_period_multi_32m},
50 {128UL * TICKS_1M, interrupt_interval_clock_period_multi_128m},
51 {512UL * TICKS_1M, interrupt_interval_clock_period_multi_512m},
52 {2UL * TICKS_1G, interrupt_interval_clock_period_multi_2g},
53 {0xFFFFFFFFUL, interrupt_interval_out_of_range}
54
55 };
56
57 /* See hpm_wdg_drv.h for more details */
wdg_init(WDG_Type * base,wdg_control_t * wdg_ctrl)58 hpm_stat_t wdg_init(WDG_Type *base, wdg_control_t *wdg_ctrl)
59 {
60 hpm_stat_t status = status_invalid_argument;
61 do {
62 HPM_BREAK_IF((base == NULL) || (wdg_ctrl == NULL));
63
64 HPM_BREAK_IF((wdg_ctrl->reset_interval > reset_interval_max) ||
65 (wdg_ctrl->interrupt_interval > interrupt_interval_max) ||
66 (wdg_ctrl->clksrc > wdg_clksrc_pclk));
67
68 uint32_t rst_time = (uint32_t) wdg_ctrl->reset_interval;
69 uint32_t int_time = (uint32_t) wdg_ctrl->interrupt_interval;
70 uint32_t reset_en = wdg_ctrl->reset_enable ? 1UL : 0UL;
71 uint32_t int_en = wdg_ctrl->interrupt_enable ? 1UL : 0UL;
72 uint32_t clk_src = (wdg_ctrl->clksrc == wdg_clksrc_pclk) ? 1UL : 0UL;
73 uint32_t wdg_en = wdg_ctrl->wdg_enable ? 1UL : 0UL;
74
75 uint32_t wdg_ctrl = WDG_CTRL_RSTTIME_SET(rst_time)
76 | WDG_CTRL_INTTIME_SET(int_time)
77 | WDG_CTRL_CLKSEL_SET(clk_src)
78 | WDG_CTRL_RSTEN_SET(reset_en)
79 | WDG_CTRL_INTEN_SET(int_en)
80 | WDG_CTRL_EN_SET(wdg_en);
81
82 wdg_write_enable(base);
83
84 base->CTRL = wdg_ctrl;
85
86 status = status_success;
87
88 } while (false);
89
90 return status;
91 }
92
93 /* See hpm_wdg_drv.h for more details */
wdg_convert_reset_interval_from_us(const uint32_t src_freq,const uint32_t reset_us)94 reset_interval_t wdg_convert_reset_interval_from_us(const uint32_t src_freq, const uint32_t reset_us)
95 {
96 reset_interval_t reset_interval = reset_interval_out_of_range;
97
98 uint32_t src_clk_one_tick_in_ns = ONE_SECOND_TICKS_IN_NS / src_freq;
99 if (src_clk_one_tick_in_ns < 1U) {
100 src_clk_one_tick_in_ns = 1U;
101 }
102
103 uint32_t reset_interval_ticks = (reset_us * 1000UL) / src_clk_one_tick_in_ns;
104
105 for (uint32_t i = 0; i < ARRAY_SIZE(k_reset_interval_map); i++) {
106 if (reset_interval_ticks <= k_reset_interval_map[i].top) {
107 reset_interval = k_reset_interval_map[i].interval;
108 break;
109 }
110 }
111
112 return reset_interval;
113 }
114
115 /* See hpm_wdg_drv.h for more details */
wdg_convert_interrupt_interval_from_us(const uint32_t src_freq,uint32_t interval_us)116 interrupt_interval_t wdg_convert_interrupt_interval_from_us(const uint32_t src_freq, uint32_t interval_us)
117 {
118 interrupt_interval_t interrupt_interval = interrupt_interval_out_of_range;
119
120 uint32_t src_clk_one_tick_in_ns = ONE_SECOND_TICKS_IN_NS / src_freq;
121 if (src_clk_one_tick_in_ns < 1U) {
122 src_clk_one_tick_in_ns = 1U;
123 }
124
125 uint32_t interrupt_interval_ticks = ((uint64_t) interval_us * 1000L) / src_clk_one_tick_in_ns;
126 for (uint32_t i = 0; i < ARRAY_SIZE(k_interrupt_interval_map); i++) {
127 if (interrupt_interval_ticks <= k_interrupt_interval_map[i].top) {
128 interrupt_interval = k_interrupt_interval_map[i].interval;
129 break;
130 }
131 }
132
133 return interrupt_interval;
134 }
135
wdg_convert_interrupt_interval_to_us(const uint32_t src_freq,interrupt_interval_t interval)136 uint64_t wdg_convert_interrupt_interval_to_us(const uint32_t src_freq, interrupt_interval_t interval)
137 {
138 uint64_t time_in_us = 0;
139 if ((src_freq != 0) && (interval < interrupt_interval_out_of_range)) {
140 uint32_t interrupt_interval_in_reg = (uint32_t) interval;
141
142 double tick_in_ns = 1.0 * ONE_SECOND_TICKS_IN_NS / src_freq;
143 uint64_t
144 total_interval_in_ns = (uint64_t)(tick_in_ns * k_interrupt_interval_map[interrupt_interval_in_reg].top);
145
146 time_in_us = total_interval_in_ns / 1000UL;
147 }
148
149 return time_in_us;
150 }
151
wdg_convert_reset_interval_to_us(const uint32_t src_freq,reset_interval_t interval)152 uint32_t wdg_convert_reset_interval_to_us(const uint32_t src_freq, reset_interval_t interval)
153 {
154 uint32_t time_in_us = 0;
155 if ((src_freq != 0) && (interval < reset_interval_out_of_range)) {
156 uint32_t reset_interval_in_reg = (uint32_t) interval;
157 double tick_in_ns = 1.0 * ONE_SECOND_TICKS_IN_NS / src_freq;
158 uint64_t total_interval_in_ns = (uint64_t)(tick_in_ns * k_reset_interval_map[reset_interval_in_reg].top);
159
160 time_in_us = (uint32_t)(total_interval_in_ns / 1000UL);
161 }
162
163 return time_in_us;
164 }
165
wdg_get_interrupt_interval_in_us(WDG_Type * base,const uint32_t src_freq)166 uint64_t wdg_get_interrupt_interval_in_us(WDG_Type *base, const uint32_t src_freq)
167 {
168 uint64_t time_in_us = 0;
169 if ((base != NULL) && (src_freq != 0)) {
170 interrupt_interval_t interval = (interrupt_interval_t) WDG_CTRL_INTTIME_GET(base->CTRL);
171
172 time_in_us = wdg_convert_interrupt_interval_to_us(src_freq, interval);
173 }
174
175 return time_in_us;
176 }
177
wdg_get_total_reset_interval_in_us(WDG_Type * base,const uint32_t src_freq)178 uint64_t wdg_get_total_reset_interval_in_us(WDG_Type *base, const uint32_t src_freq)
179 {
180 uint64_t time_in_us = 0;
181 if ((base != NULL) && (src_freq != 0)) {
182 reset_interval_t reset_interval = (reset_interval_t) WDG_CTRL_RSTTIME_GET(base->CTRL);
183 interrupt_interval_t interrupt_interval = (interrupt_interval_t) WDG_CTRL_INTTIME_GET(base->CTRL);
184 time_in_us = wdg_convert_reset_interval_to_us(src_freq, reset_interval) +
185 wdg_convert_interrupt_interval_to_us(src_freq, interrupt_interval);
186 }
187
188 return time_in_us;
189 }
190