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