1 /*
2  * Copyright (c) 2021 - 2022 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <rthw.h>
9 #include <rtdevice.h>
10 #include <rtdbg.h>
11 #include "board.h"
12 #include "drv_wdt.h"
13 #include "hpm_wdg_drv.h"
14 #include "hpm_sysctl_drv.h"
15 
16 
17 
18 #ifdef BSP_USING_WDG
19 
20 
21 typedef struct hpm_wdog
22 {
23     WDG_Type *wdog_base;
24     char *device_name;
25     clock_name_t clock_name;
26     uint32_t irq_num;
27     rt_watchdog_t *wdog;
28 }hpm_wdog_t;
29 
30 static rt_err_t hpm_wdog_init(rt_watchdog_t *wdt);
31 static rt_err_t hpm_wdog_open(rt_watchdog_t *wdt, rt_uint16_t oflag);
32 static rt_err_t hpm_wdog_close(rt_watchdog_t *wdt);
33 static rt_err_t hpm_wdog_refresh(rt_watchdog_t *wdt);
34 static rt_err_t hpm_wdog_control(rt_watchdog_t *wdt, int cmd, void *args);
35 
36 static void hpm_wdog_isr(rt_watchdog_t *wdt);
37 
38 static wdg_control_t wdog_ctrl = {
39     .reset_interval = reset_interval_clock_period_mult_16k,
40     .interrupt_interval = interrupt_interval_clock_period_multi_8k,
41     .reset_enable = true,
42     .interrupt_enable = false,
43     .clksrc = wdg_clksrc_extclk,
44     .wdg_enable = false,
45 };
46 
47 #if defined(BSP_USING_WDG0)
48 rt_watchdog_t wdog0;
wdog0_isr(void)49 void wdog0_isr(void)
50 {
51     hpm_wdog_isr(&wdog0);
52 }
SDK_DECLARE_EXT_ISR_M(IRQn_WDG0,wdog0_isr)53 SDK_DECLARE_EXT_ISR_M(IRQn_WDG0, wdog0_isr)
54 #endif
55 
56 #if defined(BSP_USING_WDG1)
57 rt_watchdog_t wdog1;
58 void wdog1_isr(void)
59 {
60     hpm_wdog_isr(&wdog1);
61 }
SDK_DECLARE_EXT_ISR_M(IRQn_WDG1,wdog1_isr)62 SDK_DECLARE_EXT_ISR_M(IRQn_WDG1, wdog1_isr)
63 #endif
64 
65 #if defined(BSP_USING_WDG2)
66 rt_watchdog_t wdog2;
67 void wdog2_isr(void)
68 {
69     hpm_wdog_isr(&wdog2);
70 }
SDK_DECLARE_EXT_ISR_M(IRQn_WDG2,wdog2_isr)71 SDK_DECLARE_EXT_ISR_M(IRQn_WDG2, wdog2_isr)
72 #endif
73 
74 #if defined(BSP_USING_WDG3)
75 rt_watchdog_t wdog3;
76 void wdog3_isr(void)
77 {
78     hpm_wdog_isr(&wdog3);
79 }
80 SDK_DECLARE_EXT_ISR_M(IRQn_WDG3, wdog3_isr)
81 #endif
82 
83 static hpm_wdog_t wdogs[] = {
84 #ifdef BSP_USING_WDG0
85     {
86         .wdog_base = HPM_WDG0,
87         .device_name = "wdt0",
88         .clock_name = clock_watchdog0,
89         .irq_num = IRQn_WDG0,
90         .wdog = &wdog0,
91     },
92 #endif
93 
94 #ifdef BSP_USING_WDG1
95     {
96         .wdog_base = HPM_WDG1,
97         .device_name = "wdt1",
98         .clock_name = clock_watchdog1,
99         .irq_num = IRQn_WDG1,
100         .wdog = &wdog1,
101     },
102 #endif
103 
104 #ifdef BSP_USING_WDG2
105     {
106         .wdog_base = HPM_WDG2,
107         .device_name = "wdt2",
108         .clock_name = clock_watchdog2,
109         .irq_num = IRQn_WDG2,
110         .wdog = &wdog2,
111     },
112 #endif
113 
114 #ifdef BSP_USING_WDG3
115     {
116         .wdog_name = HPM_WDG3,
117         .device_name = "wdt3",
118         .clock_name = clock_watchdog3,
119         .irq_num = IRQn_WDG3,
120         .wdog = &wdog3,
121     },
122 #endif
123 };
124 
125 static struct rt_watchdog_ops hpm_wdog_ops = {
126     .init = hpm_wdog_init,
127     .control = hpm_wdog_control,
128 };
129 
hpm_wdog_init(rt_watchdog_t * wdt)130 static rt_err_t hpm_wdog_init(rt_watchdog_t *wdt)
131 {
132     hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
133     WDG_Type *base = hpm_wdog->wdog_base;
134 
135     wdg_init(base, &wdog_ctrl);
136 
137     return RT_EOK;
138 }
139 
hpm_wdog_open(rt_watchdog_t * wdt,rt_uint16_t oflag)140 static rt_err_t hpm_wdog_open(rt_watchdog_t *wdt, rt_uint16_t oflag)
141 {
142     hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
143     WDG_Type *base = hpm_wdog->wdog_base;
144 
145     rt_enter_critical();
146     wdg_enable(base);
147     rt_exit_critical();
148 }
149 
hpm_wdog_close(rt_watchdog_t * wdt)150 static rt_err_t hpm_wdog_close(rt_watchdog_t *wdt)
151 {
152     hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
153     WDG_Type *base = hpm_wdog->wdog_base;
154 
155     rt_enter_critical();
156     wdg_disable(base);
157     rt_exit_critical();
158 
159     return RT_EOK;
160 }
161 
hpm_wdog_refresh(rt_watchdog_t * wdt)162 static rt_err_t hpm_wdog_refresh(rt_watchdog_t *wdt)
163 {
164     hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
165     WDG_Type *base = hpm_wdog->wdog_base;
166 
167     rt_enter_critical();
168     wdg_restart(base);
169     rt_exit_critical();
170 
171     return RT_EOK;
172 }
173 
hpm_wdog_control(rt_watchdog_t * wdt,int cmd,void * args)174 static rt_err_t hpm_wdog_control(rt_watchdog_t *wdt, int cmd, void *args)
175 {
176     rt_err_t ret = RT_EOK;
177 
178     hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
179     WDG_Type *base = hpm_wdog->wdog_base;
180 
181     uint32_t temp;
182     switch (cmd)
183     {
184     case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
185         temp = wdg_get_total_reset_interval_in_us(base, WDG_EXT_CLK_FREQ);
186         temp /= 1000000UL; /* Convert to seconds */
187         *(uint32_t *)args = temp;
188         break;
189     case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
190         RT_ASSERT(*(uint32_t *)args != 0);
191         temp = *(uint32_t *)args;
192         temp *= 1000000U; /* Convert to microseconds */
193         wdog_ctrl.interrupt_interval = wdg_convert_interrupt_interval_from_us(WDG_EXT_CLK_FREQ, temp);
194         wdog_ctrl.reset_interval = reset_interval_clock_period_mult_128;
195         wdog_ctrl.reset_enable = true;
196         wdog_ctrl.interrupt_enable = true;
197         wdog_ctrl.clksrc = wdg_clksrc_extclk;
198         wdog_ctrl.wdg_enable = false;
199         hpm_wdog_init(wdt);
200         break;
201     case RT_DEVICE_CTRL_WDT_KEEPALIVE:
202         hpm_wdog_refresh(wdt);
203         break;
204     case RT_DEVICE_CTRL_WDT_START:
205         hpm_wdog_open(wdt, *(uint16_t*)args);
206         break;
207     case RT_DEVICE_CTRL_WDT_STOP:
208         hpm_wdog_close(wdt);
209         break;
210     default:
211         ret = RT_EINVAL;
212         break;
213     }
214 
215     return RT_EOK;
216 }
217 
hpm_wdog_isr(rt_watchdog_t * wdt)218 void hpm_wdog_isr(rt_watchdog_t *wdt)
219 {
220     hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
221     WDG_Type *base = hpm_wdog->wdog_base;
222 
223     uint32_t status = wdg_get_status(base);
224 
225     if (IS_HPM_BITMASK_SET(status, WDG_ST_INTEXPIRED_MASK)) {
226         wdg_clear_status(base, WDG_ST_INTEXPIRED_MASK);
227     }
228 }
229 
rt_hw_wdt_init(void)230 int rt_hw_wdt_init(void)
231 {
232     rt_err_t err = RT_EOK;
233 
234 #if defined(BSP_USING_WDG)
235     for (uint32_t i = 0; i < sizeof(wdogs) / sizeof(wdogs[0]); i++)
236     {
237         wdogs[i].wdog->ops = &hpm_wdog_ops;
238         clock_add_to_group(wdogs[i].clock_name, 0);
239         err = rt_hw_watchdog_register(wdogs[i].wdog, wdogs[i].device_name, RT_DEVICE_FLAG_RDWR, (void *)&wdogs[i]);
240         if (err != RT_EOK)
241         {
242             LOG_E("rt device %s failed, status=%d\n", wdogs[i].device_name, err);
243         }
244     }
245 #endif
246     return err;
247 }
248 
249 INIT_BOARD_EXPORT(rt_hw_wdt_init);
250 #endif /* RT_USING_WDT */