1
+ /* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
2
+ *
3
+ * Redistribution and use in source and binary forms, with or without
4
+ * modification, are permitted provided that the following conditions are met:
5
+ * 1. Redistributions of source code must retain the above copyright
6
+ * notice, this list of conditions and the following disclaimer.
7
+ * 2. Redistributions in binary form must reproduce the above copyright
8
+ * notice, this list of conditions and the following disclaimer in the
9
+ * documentation and/or other materials provided with the distribution.
10
+ *
11
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
12
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
13
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
14
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
16
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
+ */
25
+
26
+ #include <rtthread.h>
27
+ #include <rtdevice.h>
28
+ #include <riscv_io.h>
29
+ #include "board.h"
30
+ #include "ioremap.h"
31
+ #include "sysctl_clk.h"
32
+ #include "drv_wdt.h"
33
+ #include <rtdbg.h>
34
+ #include <sys/ioctl.h>
35
+ static rt_watchdog_t kd_watchdog ;
36
+ static kd_wdt_t * kd_wdt_reg ;
37
+
38
+ /* There are sixteen TOPs (timeout periods) that can be set in the watchdog. */
39
+
40
+ static const rt_uint32_t * tops ;
41
+
42
+ static const rt_uint32_t kd_wdt_fix_tops [KD_WDT_NUM_TOPS ] = {
43
+ KD_WDT_FIX_TOP (0 ), KD_WDT_FIX_TOP (1 ), KD_WDT_FIX_TOP (2 ),
44
+ KD_WDT_FIX_TOP (3 ), KD_WDT_FIX_TOP (4 ), KD_WDT_FIX_TOP (5 ),
45
+ KD_WDT_FIX_TOP (6 ), KD_WDT_FIX_TOP (7 ), KD_WDT_FIX_TOP (8 ),
46
+ KD_WDT_FIX_TOP (9 ), KD_WDT_FIX_TOP (10 ), KD_WDT_FIX_TOP (11 ),
47
+ KD_WDT_FIX_TOP (12 ), KD_WDT_FIX_TOP (13 ), KD_WDT_FIX_TOP (14 ),
48
+ KD_WDT_FIX_TOP (15 )
49
+ };
50
+
51
+ static struct kd_wdt_timeout timeouts [KD_WDT_NUM_TOPS ];
52
+ static char rmod ; //wdt reset mode,
53
+
54
+ static void kd_wdt_timeouts_init (void )
55
+ {
56
+ rt_uint32_t wdt_clk ;
57
+ rt_uint32_t time_value ;
58
+ rt_uint32_t i , t ;
59
+ rt_uint64_t msec ;
60
+ struct kd_wdt_timeout tout , * dst ;
61
+ /* caculate timeout value */
62
+ wdt_clk = sysctl_clk_get_leaf_freq (SYSCTL_CLK_WDT_1_CLK );
63
+
64
+ for (i = 0 ; i < KD_WDT_NUM_TOPS ; ++ i )
65
+ {
66
+ tout .top_val = i ;
67
+ tout .sec = tops [i ] / wdt_clk ;
68
+ msec = (rt_uint64_t )tops [i ] * (rt_uint64_t )1000L ;
69
+ msec = msec / wdt_clk ;
70
+ tout .msec = msec - (rt_uint64_t )tout .sec * (rt_uint64_t )1000L ;
71
+
72
+ for (t = 0 ; t < i ; ++ t )
73
+ {
74
+ dst = & timeouts [t ];
75
+ if (tout .sec > dst -> sec || (tout .sec == dst -> sec &&
76
+ tout .msec >= dst -> msec ))
77
+ continue ;
78
+ else
79
+ swap (* dst , tout );
80
+ }
81
+
82
+ timeouts [i ] = tout ;
83
+ }
84
+ rt_kprintf ("watchdog timeout table init OK!\n" );
85
+ }
86
+
87
+ static rt_err_t kd_wdt_feed (rt_watchdog_t * wdt )
88
+ {
89
+ kd_wdt_t * reg = (kd_wdt_t * )wdt -> parent .user_data ;
90
+ reg -> crr = 0x76 ;
91
+
92
+ return RT_EOK ;
93
+ }
94
+
95
+ static rt_err_t kd_wdt_enable (rt_watchdog_t * wdt )
96
+ {
97
+ kd_wdt_t * reg = (kd_wdt_t * )wdt -> parent .user_data ;
98
+ reg -> crr = 0x76 ;
99
+ reg -> cr |= 0x1 ;
100
+
101
+ return RT_EOK ;
102
+ }
103
+
104
+ static rt_err_t kd_wdt_disable (rt_watchdog_t * wdt )
105
+ {
106
+ kd_wdt_t * reg = (kd_wdt_t * )wdt -> parent .user_data ;
107
+ reg -> crr = 0x76 ;
108
+ reg -> cr &= ~0x1 ;
109
+
110
+ return RT_EOK ;
111
+ }
112
+
113
+ static rt_err_t kd_wdt_set_timeout (rt_watchdog_t * wdt , rt_uint64_t timeout )
114
+ {
115
+ kd_wdt_t * reg = (kd_wdt_t * )wdt -> parent .user_data ;
116
+ rt_uint32_t top_val ;
117
+ rt_uint32_t i ;
118
+ rt_uint32_t time = (timeout + rmod - 1 ) / rmod ;
119
+
120
+ for (i = 0 ; i < KD_WDT_NUM_TOPS ; ++ i )
121
+ {
122
+ if (timeouts [i ].sec >= time )
123
+ break ;
124
+ }
125
+
126
+ if (i == KD_WDT_NUM_TOPS )
127
+ -- i ;
128
+
129
+ top_val = timeouts [i ].top_val ;
130
+
131
+ reg -> torr = (top_val << 4 ) | (top_val << 0 );
132
+
133
+ return RT_EOK ;
134
+ }
135
+
136
+ static rt_err_t kd_wdt_get_timeout (rt_watchdog_t * wdt , void * timeout )
137
+ {
138
+ rt_uint64_t top_val ;
139
+ rt_uint32_t i ;
140
+ kd_wdt_t * reg = (kd_wdt_t * )wdt -> parent .user_data ;
141
+ top_val = ((reg -> torr ) & 0xf );
142
+
143
+ for (i = 0 ; i < KD_WDT_NUM_TOPS ; ++ i )
144
+ {
145
+ if (timeouts [i ].top_val == top_val )
146
+ break ;
147
+ }
148
+
149
+ * ((rt_uint64_t * )timeout ) = timeouts [i ].sec * rmod ;
150
+
151
+ return RT_EOK ;
152
+ }
153
+
154
+ static rt_err_t kd_wdt_init (rt_watchdog_t * wdt )
155
+ {
156
+ kd_wdt_t * reg = (kd_wdt_t * )wdt -> parent .user_data ;
157
+ reg -> cr &= ~(0x01 << 1 );
158
+ reg -> cr |= (0x0 << 1 ); //default set wdt reset mode
159
+ rmod = KD_WDT_RMOD_RESET ;
160
+
161
+ if (reg -> comp_param_1 & (1 << 6 ))
162
+ {
163
+ tops = kd_wdt_fix_tops ;
164
+ }
165
+
166
+ kd_wdt_timeouts_init ();
167
+
168
+ if (!timeouts [KD_WDT_NUM_TOPS - 1 ].sec )
169
+ {
170
+ rt_kprintf ("No any valid Timeout period detected\n" );
171
+ return - RT_EINVAL ;
172
+ }
173
+
174
+ return RT_EOK ;
175
+ }
176
+
177
+ static rt_err_t kd_wdt_control (rt_watchdog_t * wdt , int cmd , void * args )
178
+ {
179
+ RT_ASSERT (wdt != NULL );
180
+ kd_wdt_t * reg = (kd_wdt_t * )wdt -> parent .user_data ;
181
+
182
+ switch (cmd )
183
+ {
184
+ case KD_DEVICE_CTRL_WDT_GET_TIMEOUT :
185
+ kd_wdt_get_timeout (wdt , args );
186
+ break ;
187
+ case KD_DEVICE_CTRL_WDT_SET_TIMEOUT :
188
+ kd_wdt_set_timeout (wdt , * ((rt_uint32_t * )args ));
189
+ break ;
190
+ case KD_DEVICE_CTRL_WDT_KEEPALIVE :
191
+ kd_wdt_feed (wdt );
192
+ break ;
193
+ case KD_DEVICE_CTRL_WDT_START :
194
+ kd_wdt_enable (wdt );
195
+ break ;
196
+ case RT_DEVICE_CTRL_WDT_STOP :
197
+ case KD_DEVICE_CTRL_WDT_STOP :
198
+ kd_wdt_disable (wdt );
199
+ break ;
200
+ default :
201
+ return - RT_EINVAL ;
202
+ }
203
+
204
+ return RT_EOK ;
205
+ }
206
+
207
+ static struct rt_watchdog_ops kd_wdt_ops =
208
+ {
209
+ .init = kd_wdt_init ,
210
+ .control = kd_wdt_control ,
211
+ };
212
+
213
+ int rt_hw_wdt_init (void )
214
+ {
215
+ rt_err_t ret = RT_EOK ;
216
+ kd_wdt_reg = (kd_wdt_t * )rt_ioremap ((void * )WDT1_BASE_ADDR , WDT1_IO_SIZE );
217
+
218
+ kd_watchdog .ops = & kd_wdt_ops ;
219
+
220
+ ret = rt_hw_watchdog_register (& kd_watchdog , "watchdog1" , RT_DEVICE_FLAG_RDWR , kd_wdt_reg );
221
+
222
+ if (ret != RT_EOK )
223
+ {
224
+ LOG_E ("rt device register failed %d\n" , ret );
225
+ }
226
+ #ifndef RT_FASTBOOT
227
+ rt_kprintf ("watchdog register OK!\n" );
228
+ #endif
229
+ return ret ;
230
+ }
231
+ INIT_DEVICE_EXPORT (rt_hw_wdt_init );
0 commit comments