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
+ /*
27
+ * Copyright (c) 2006-2025, RT-Thread Development Team
28
+ *
29
+ * SPDX-License-Identifier: Apache-2.0
30
+ */
31
+
32
+ #include <rtthread.h>
33
+ #include <rtdevice.h>
34
+ #include <riscv_io.h>
35
+ #include "board.h"
36
+ #include "ioremap.h"
37
+ #include "sysctl_clk.h"
38
+ #include "drv_wdt.h"
39
+ #include <rtdbg.h>
40
+ #include <sys/ioctl.h>
41
+
42
+ struct k230_wdt_dev
43
+ {
44
+ struct rt_watchdog_device device ;
45
+ const char * name ;
46
+ rt_ubase_t base ;
47
+ size_t size ;
48
+ sysctl_clk_node_e clk ; /* clock source */
49
+ };
50
+
51
+ /* There are sixteen TOPs (timeout periods) that can be set in the watchdog. */
52
+
53
+ static const rt_uint32_t * tops ;
54
+
55
+ static const rt_uint32_t k230_wdt_fix_tops [KD_WDT_NUM_TOPS ] = {
56
+ KD_WDT_FIX_TOP (0 ), KD_WDT_FIX_TOP (1 ), KD_WDT_FIX_TOP (2 ),
57
+ KD_WDT_FIX_TOP (3 ), KD_WDT_FIX_TOP (4 ), KD_WDT_FIX_TOP (5 ),
58
+ KD_WDT_FIX_TOP (6 ), KD_WDT_FIX_TOP (7 ), KD_WDT_FIX_TOP (8 ),
59
+ KD_WDT_FIX_TOP (9 ), KD_WDT_FIX_TOP (10 ), KD_WDT_FIX_TOP (11 ),
60
+ KD_WDT_FIX_TOP (12 ), KD_WDT_FIX_TOP (13 ), KD_WDT_FIX_TOP (14 ),
61
+ KD_WDT_FIX_TOP (15 )
62
+ };
63
+
64
+ static struct k230_wdt_timeout timeouts [KD_WDT_NUM_TOPS ];
65
+ static char rmod ; /* wdt reset mode, */
66
+
67
+ static void k230_wdt_timeouts_init (struct k230_wdt_dev * dev )
68
+ {
69
+ rt_uint32_t wdt_clk ;
70
+ rt_uint32_t time_value ;
71
+ rt_uint32_t i , t ;
72
+ rt_uint64_t msec ;
73
+ struct k230_wdt_timeout tout , * dst ;
74
+ /* caculate timeout value */
75
+ wdt_clk = sysctl_clk_get_leaf_freq (dev -> clk );
76
+
77
+ for (i = 0 ; i < KD_WDT_NUM_TOPS ; ++ i )
78
+ {
79
+ tout .top_val = i ;
80
+ tout .sec = tops [i ] / wdt_clk ;
81
+ msec = (rt_uint64_t )tops [i ] * (rt_uint64_t )1000L ;
82
+ msec = msec / wdt_clk ;
83
+ tout .msec = msec - (rt_uint64_t )tout .sec * (rt_uint64_t )1000L ;
84
+
85
+ for (t = 0 ; t < i ; ++ t )
86
+ {
87
+ dst = & timeouts [t ];
88
+ if (tout .sec > dst -> sec || (tout .sec == dst -> sec &&
89
+ tout .msec >= dst -> msec ))
90
+ continue ;
91
+ else
92
+ swap (* dst , tout );
93
+ }
94
+
95
+ timeouts [i ] = tout ;
96
+ }
97
+ rt_kprintf ("watchdog timeout table init OK!\n" );
98
+ }
99
+
100
+ static rt_err_t k230_wdt_feed (struct k230_wdt_dev * dev )
101
+ {
102
+ k230_wdt_t * reg = (k230_wdt_t * )dev -> base ;
103
+ reg -> crr = 0x76 ;
104
+
105
+ return RT_EOK ;
106
+ }
107
+
108
+ static rt_err_t k230_wdt_enable (struct k230_wdt_dev * dev )
109
+ {
110
+ k230_wdt_t * reg = (k230_wdt_t * )dev -> base ;
111
+ reg -> crr = 0x76 ;
112
+ reg -> cr |= 0x1 ;
113
+
114
+ return RT_EOK ;
115
+ }
116
+
117
+ static rt_err_t k230_wdt_disable (struct k230_wdt_dev * dev )
118
+ {
119
+ k230_wdt_t * reg = (k230_wdt_t * )dev -> base ;
120
+ reg -> crr = 0x76 ;
121
+ reg -> cr &= ~0x1 ;
122
+
123
+ return RT_EOK ;
124
+ }
125
+
126
+ static rt_err_t k230_wdt_set_timeout (struct k230_wdt_dev * dev , rt_uint64_t timeout )
127
+ {
128
+ k230_wdt_t * reg = (k230_wdt_t * )dev -> base ;
129
+ rt_uint32_t top_val ;
130
+ rt_uint32_t i ;
131
+ rt_uint32_t time = (timeout + rmod - 1 ) / rmod ;
132
+
133
+ for (i = 0 ; i < KD_WDT_NUM_TOPS ; ++ i )
134
+ {
135
+ if (timeouts [i ].sec >= time )
136
+ break ;
137
+ }
138
+
139
+ if (i == KD_WDT_NUM_TOPS )
140
+ -- i ;
141
+
142
+ top_val = timeouts [i ].top_val ;
143
+
144
+ reg -> torr = (top_val << 4 ) | (top_val << 0 );
145
+
146
+ return RT_EOK ;
147
+ }
148
+
149
+ static rt_err_t k230_wdt_get_timeout (struct k230_wdt_dev * dev , void * timeout )
150
+ {
151
+ rt_uint64_t top_val ;
152
+ rt_uint32_t i ;
153
+ k230_wdt_t * reg = (k230_wdt_t * )dev -> base ;
154
+ top_val = ((reg -> torr ) & 0xf );
155
+
156
+ for (i = 0 ; i < KD_WDT_NUM_TOPS ; ++ i )
157
+ {
158
+ if (timeouts [i ].top_val == top_val )
159
+ break ;
160
+ }
161
+
162
+ * ((rt_uint64_t * )timeout ) = timeouts [i ].sec * rmod ;
163
+
164
+ return RT_EOK ;
165
+ }
166
+
167
+ static rt_err_t k230_wdt_init (rt_watchdog_t * wdt )
168
+ {
169
+ RT_ASSERT (wdt != NULL );
170
+
171
+ struct k230_wdt_dev * dev = rt_container_of (wdt , struct k230_wdt_dev , device );
172
+ k230_wdt_t * reg = (k230_wdt_t * )dev -> base ;
173
+
174
+ reg -> cr &= ~(0x01 << 1 );
175
+ reg -> cr |= (0x0 << 1 ); /* default set wdt reset mode */
176
+ rmod = KD_WDT_RMOD_RESET ;
177
+
178
+ if (reg -> comp_param_1 & (1 << 6 ))
179
+ {
180
+ tops = k230_wdt_fix_tops ;
181
+ }
182
+
183
+ k230_wdt_timeouts_init (dev );
184
+
185
+ if (!timeouts [KD_WDT_NUM_TOPS - 1 ].sec )
186
+ {
187
+ rt_kprintf ("No any valid Timeout period detected\n" );
188
+ return - RT_EINVAL ;
189
+ }
190
+
191
+ return RT_EOK ;
192
+ }
193
+
194
+ static rt_err_t k230_wdt_control (rt_watchdog_t * wdt , int cmd , void * args )
195
+ {
196
+ RT_ASSERT (wdt != NULL );
197
+
198
+ struct k230_wdt_dev * dev = rt_container_of (wdt , struct k230_wdt_dev , device );
199
+
200
+ switch (cmd )
201
+ {
202
+ case KD_DEVICE_CTRL_WDT_GET_TIMEOUT :
203
+ k230_wdt_get_timeout (dev , args );
204
+ break ;
205
+ case KD_DEVICE_CTRL_WDT_SET_TIMEOUT :
206
+ k230_wdt_set_timeout (dev , * ((rt_uint32_t * )args ));
207
+ break ;
208
+ case KD_DEVICE_CTRL_WDT_KEEPALIVE :
209
+ k230_wdt_feed (dev );
210
+ break ;
211
+ case KD_DEVICE_CTRL_WDT_START :
212
+ k230_wdt_enable (dev );
213
+ break ;
214
+ case RT_DEVICE_CTRL_WDT_STOP :
215
+ case KD_DEVICE_CTRL_WDT_STOP :
216
+ k230_wdt_disable (dev );
217
+ break ;
218
+ default :
219
+ return - RT_EINVAL ;
220
+ }
221
+
222
+ return RT_EOK ;
223
+ }
224
+
225
+ static struct rt_watchdog_ops k230_wdt_ops =
226
+ {
227
+ .init = k230_wdt_init ,
228
+ .control = k230_wdt_control ,
229
+ };
230
+
231
+ static struct k230_wdt_dev wdt_devices [] =
232
+ {
233
+ #ifdef BSP_USING_WDT0
234
+ {
235
+ .name = "wdt0" ,
236
+ .base = WDT0_BASE_ADDR ,
237
+ .size = WDT0_IO_SIZE ,
238
+ .clk = SYSCTL_CLK_WDT0 ,
239
+ },
240
+ #endif /* BSP_USING_WDT0 */
241
+
242
+ #ifdef BSP_USING_WDT1
243
+ {
244
+ .name = "wdt1" ,
245
+ .base = WDT1_BASE_ADDR ,
246
+ .size = WDT1_IO_SIZE ,
247
+ .clk = SYSCTL_CLK_WDT1 ,
248
+ },
249
+ #endif /* BSP_USING_WDT1 */
250
+
251
+ #if !defined (BSP_USING_WDT0 ) && !defined (BSP_USING_WDT1 )
252
+ #error "No watchdog device defined!"
253
+ #endif
254
+ };
255
+
256
+ int rt_hw_wdt_init (void )
257
+ {
258
+ rt_uint8_t i ;
259
+ for (i = 0 ; i < sizeof (wdt_devices ) / sizeof (struct k230_wdt_dev ); i ++ )
260
+ {
261
+ wdt_devices [i ].device .ops = & k230_wdt_ops ;
262
+ wdt_devices [i ].base = (rt_ubase_t )rt_ioremap ((void * )wdt_devices [i ].base , wdt_devices [i ].size );
263
+
264
+ if (rt_hw_watchdog_register (& wdt_devices [i ].device , wdt_devices [i ].name , RT_DEVICE_FLAG_RDWR , RT_NULL ) != RT_EOK )
265
+ {
266
+ LOG_E ("%s register failed!" , wdt_devices [i ].name );
267
+ return - RT_ERROR ;
268
+ }
269
+ LOG_D ("%s register OK!" , wdt_devices [i ].name );
270
+ }
271
+
272
+ return RT_EOK ;
273
+ }
274
+ INIT_DEVICE_EXPORT (rt_hw_wdt_init );
0 commit comments