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+ /*
33+ * K230 Hardware Timer Driver
34+ *
35+ * K230 provides 9 timers, 6 general-purpose timers (TIMER0-TIMER5) and
36+ * 3 STC timers.
37+ * This driver only implements the general-purpose timers (TIMER0-TIMER5).
38+ * This driver only supports the ONESHOT mode.
39+ * Support frequency options: 12.5M(min), 25M, 50M, 100M(max)
40+ */
41+
42+ #include <rtthread.h>
43+ #include <rtdevice.h>
44+ #include "riscv_io.h"
45+ #include "board.h"
46+ #include "ioremap.h"
47+ #include <rtdbg.h>
48+ #include <stdbool.h>
49+ #include <stdio.h>
50+ #include <rthw.h>
51+ #include "sysctl_rst.h"
52+ #include "drv_timer.h"
53+ #include <dfs_posix.h>
54+
55+ static void k230_timer_stop (rt_hwtimer_t * timer );
56+ static void k230_timer_init (rt_hwtimer_t * timer , rt_uint32_t state )
57+ {
58+ struct k230_timer * kd_timer = rt_container_of (timer , struct k230_timer , device );
59+
60+ uint8_t id = kd_timer -> id ;
61+ if (state == 0 )
62+ {
63+ k230_timer_stop (timer );
64+ }
65+ else
66+ {
67+ sysctl_clk_set_leaf_parent (kd_timer -> clk , kd_timer -> clk_src );
68+ if (timer -> freq == timer -> info -> minfreq )
69+ sysctl_clk_set_leaf_div (kd_timer -> clk_src , 1 , 8 );
70+ if (timer -> freq == timer -> info -> maxfreq )
71+ sysctl_clk_set_leaf_div (kd_timer -> clk_src , 1 , 1 );
72+ if (timer -> freq == 50 * MHz )
73+ sysctl_clk_set_leaf_div (kd_timer -> clk_src , 1 , 2 );
74+ if (timer -> freq == 25 * MHz )
75+ sysctl_clk_set_leaf_div (kd_timer -> clk_src , 1 , 4 );
76+ }
77+ }
78+
79+ static rt_err_t k230_timer_start (rt_hwtimer_t * timer , rt_uint32_t cnt , rt_hwtimer_mode_t mode )
80+ {
81+ struct k230_timer * kd_timer = rt_container_of (timer , struct k230_timer , device );
82+ uint8_t id = kd_timer -> id ;
83+ k230_timer_regs_t * reg = (k230_timer_regs_t * )kd_timer -> base ;
84+ reg -> channel [id ].load_count = cnt ;
85+ reg -> channel [id ].control &= ~(TIMER_CR_INTERRUPT_MASK );
86+ reg -> channel [id ].control |= (TIMER_CR_USER_MODE | TIMER_CR_ENABLE );
87+ return RT_EOK ;
88+ }
89+
90+ static void k230_timer_stop (rt_hwtimer_t * timer )
91+ {
92+ struct k230_timer * kd_timer = rt_container_of (timer , struct k230_timer , device );
93+ uint8_t id = kd_timer -> id ;
94+ k230_timer_regs_t * reg = (k230_timer_regs_t * )kd_timer -> base ;
95+ reg -> channel [id ].control &= ~TIMER_CR_ENABLE ;
96+ reg -> channel [id ].control |= TIMER_CR_INTERRUPT_MASK ;
97+ }
98+
99+ static rt_uint32_t k230_timer_get (rt_hwtimer_t * timer )
100+ {
101+ struct k230_timer * kd_timer = rt_container_of (timer , struct k230_timer , device );
102+ uint8_t id = kd_timer -> id ;
103+ k230_timer_regs_t * reg = (k230_timer_regs_t * )kd_timer -> base ;
104+ return reg -> channel [id ].current_value ;
105+ }
106+
107+ static rt_err_t k230_timer_ctrl (rt_hwtimer_t * timer , rt_uint32_t cmd , void * arg )
108+ {
109+ struct k230_timer * kd_timer = rt_container_of (timer , struct k230_timer , device );
110+
111+ switch (cmd )
112+ {
113+ case HWTIMER_CTRL_FREQ_SET :
114+ timer -> freq = * ((rt_uint32_t * )arg );
115+ sysctl_clk_set_leaf_parent (kd_timer -> clk , kd_timer -> clk_src );
116+ if (timer -> freq == timer -> info -> minfreq )
117+ sysctl_clk_set_leaf_div (kd_timer -> clk_src , 1 , 8 );
118+ if (timer -> freq == timer -> info -> maxfreq )
119+ sysctl_clk_set_leaf_div (kd_timer -> clk_src , 1 , 1 );
120+ if (timer -> freq == 50 * MHz )
121+ sysctl_clk_set_leaf_div (kd_timer -> clk_src , 1 , 2 );
122+ if (timer -> freq == 25 * MHz )
123+ sysctl_clk_set_leaf_div (kd_timer -> clk_src , 1 , 4 );
124+ break ;
125+ case HWTIMER_CTRL_STOP :
126+ k230_timer_stop (timer );
127+ break ;
128+ case HWTIMER_CTRL_INFO_GET :
129+ if (arg == RT_NULL )
130+ {
131+ LOG_E ("HWTIMER_CTRL_INFO_GET arg is NULL" );
132+ return - RT_ERROR ;
133+ }
134+ * (struct rt_hwtimer_info * )arg = * (kd_timer -> device .info );
135+ break ;
136+ case HWTIMER_CTRL_MODE_SET :
137+ if (arg == RT_NULL )
138+ {
139+ LOG_E ("HWTIMER_CTRL_MODE_SET arg is NULL" );
140+ return - RT_ERROR ;
141+ }
142+ timer -> mode = * (rt_hwtimer_mode_t * )arg ;
143+ if (timer -> mode != HWTIMER_MODE_ONESHOT )
144+ {
145+ LOG_E ("mode is invalid/unsupported, only ONESHOT is supported" );
146+ return - RT_ERROR ;
147+ }
148+ break ;
149+ default :
150+ LOG_E ("HWTIMER_CTRL cmd is invalid" );
151+ return - RT_ERROR ;
152+ }
153+ return RT_EOK ;
154+ }
155+
156+ static int k230_timer_fops_open (struct dfs_file * fd )
157+ {
158+ rt_device_t device = (rt_device_t )fd -> vnode -> data ;
159+ return rt_device_open (device , RT_DEVICE_OFLAG_RDWR );
160+ }
161+
162+ static int k230_timer_fops_close (struct dfs_file * fd )
163+ {
164+ rt_device_t device = (rt_device_t )fd -> vnode -> data ;
165+ return rt_device_close (device );
166+ }
167+
168+ static const struct rt_hwtimer_info k230_timer_info =
169+ {
170+ 100000000 , /* the maximum count frequency can be set */
171+ 12500000 , /* the minimum count frequency can be set */
172+ 0xFFFFFFFF , /* the maximum counter value */
173+ HWTIMER_CNTMODE_DW , /* Increment or Decreasing count mode */
174+ };
175+
176+ static const struct rt_hwtimer_ops k230_timer_ops =
177+ {
178+ .init = k230_timer_init ,
179+ .start = k230_timer_start ,
180+ .stop = k230_timer_stop ,
181+ .count_get = k230_timer_get ,
182+ .control = k230_timer_ctrl ,
183+ };
184+
185+ static const struct dfs_file_ops k230_timer_fops = {
186+ k230_timer_fops_open ,
187+ k230_timer_fops_close ,
188+ };
189+
190+ void k230_hwtimer_isr (int vector , void * param )
191+ {
192+ uint32_t ret ;
193+ struct k230_timer * kd_timer = (struct k230_timer * )param ;
194+ rt_hwtimer_t * hwtimer = (rt_hwtimer_t * )& (kd_timer -> device );
195+
196+ RT_ASSERT (kd_timer != RT_NULL && hwtimer != RT_NULL );
197+
198+ int id = kd_timer -> id ;
199+ k230_timer_regs_t * reg = (k230_timer_regs_t * )kd_timer -> base ;
200+
201+ ret = (reg -> channel [id ].eoi );
202+
203+ rt_device_hwtimer_isr (hwtimer );
204+ }
205+
206+ static struct k230_timer timer_devices [] =
207+ {
208+ #ifdef BSP_USING_TIMER0
209+ {
210+ .device .info = & k230_timer_info ,
211+ .device .ops = & k230_timer_ops ,
212+ .device .parent .fops = & k230_timer_fops ,
213+
214+ .name = "hwtimer0" ,
215+ .id = 0 ,
216+ .clk = SYSCTL_CLK_TIMER0 ,
217+ .clk_src = SYSCTL_CLK_TIMER0_SRC ,
218+ .irq_num = IRQN_TIMER_0_INTERRUPT
219+ },
220+ #endif /* BSP_USING_TIMER0 */
221+
222+ #ifdef BSP_USING_TIMER1
223+ {
224+ .device .info = & k230_timer_info ,
225+ .device .ops = & k230_timer_ops ,
226+ .device .parent .fops = & k230_timer_fops ,
227+
228+ .name = "hwtimer1" ,
229+ .id = 1 ,
230+ .clk = SYSCTL_CLK_TIMER1 ,
231+ .clk_src = SYSCTL_CLK_TIMER1_SRC ,
232+ .irq_num = IRQN_TIMER_1_INTERRUPT
233+ },
234+ #endif /* BSP_USING_TIMER1 */
235+
236+ #ifdef BSP_USING_TIMER2
237+ {
238+ .device .info = & k230_timer_info ,
239+ .device .ops = & k230_timer_ops ,
240+ .device .parent .fops = & k230_timer_fops ,
241+
242+ .name = "hwtimer2" ,
243+ .id = 2 ,
244+ .clk = SYSCTL_CLK_TIMER2 ,
245+ .clk_src = SYSCTL_CLK_TIMER2_SRC ,
246+ .irq_num = IRQN_TIMER_2_INTERRUPT
247+ },
248+ #endif /* BSP_USING_TIMER0 */
249+
250+ #ifdef BSP_USING_TIMER3
251+ {
252+ .device .info = & k230_timer_info ,
253+ .device .ops = & k230_timer_ops ,
254+ .device .parent .fops = & k230_timer_fops ,
255+
256+ .name = "hwtimer3" ,
257+ .id = 3 ,
258+ .clk = SYSCTL_CLK_TIMER3 ,
259+ .clk_src = SYSCTL_CLK_TIMER3_SRC ,
260+ .irq_num = IRQN_TIMER_3_INTERRUPT
261+ },
262+ #endif /* BSP_USING_TIMER3 */
263+
264+ #ifdef BSP_USING_TIMER4
265+ {
266+ .device .info = & k230_timer_info ,
267+ .device .ops = & k230_timer_ops ,
268+ .device .parent .fops = & k230_timer_fops ,
269+
270+ .name = "hwtimer4" ,
271+ .id = 0 ,
272+ .clk = SYSCTL_CLK_TIMER4 ,
273+ .clk_src = SYSCTL_CLK_TIMER4_SRC ,
274+ .irq_num = IRQN_TIMER_4_INTERRUPT
275+ },
276+ #endif /* BSP_USING_TIMER4 */
277+
278+ #ifdef BSP_USING_TIMER5
279+ {
280+ .device .info = & k230_timer_info ,
281+ .device .ops = & k230_timer_ops ,
282+ .device .parent .fops = & k230_timer_fops ,
283+
284+ .name = "hwtimer5" ,
285+ .id = 0 ,
286+ .clk = SYSCTL_CLK_TIMER5 ,
287+ .clk_src = SYSCTL_CLK_TIMER5_SRC ,
288+ .irq_num = IRQN_TIMER_5_INTERRUPT
289+ },
290+ #endif /* BSP_USING_TIMER5 */
291+
292+ #if !defined (BSP_USING_TIMER0 ) && \
293+ !defined (BSP_USING_TIMER1 ) && \
294+ !defined (BSP_USING_TIMER2 ) && \
295+ !defined (BSP_USING_TIMER3 ) && \
296+ !defined (BSP_USING_TIMER4 ) && \
297+ !defined (BSP_USING_TIMER5 )
298+ #error "No hardware timer device enabled !"
299+ #endif
300+ };
301+
302+ int rt_hw_timer_init (void )
303+ {
304+ rt_uint8_t i , array_size ;
305+
306+ array_size = sizeof (timer_devices ) / sizeof (struct k230_timer );
307+ if (array_size == 0 )
308+ {
309+ LOG_E ("No timer device defined!" );
310+ return - RT_ERROR ;
311+ }
312+
313+ volatile void * base = (void * )rt_ioremap ((void * )HW_TIMER_BASE_ADDR , HW_TIMER_IO_SIZE );
314+ for (i = 0 ; i < array_size ; i ++ )
315+ {
316+ timer_devices [i ].base = (rt_ubase_t )base ;
317+
318+ if (rt_device_hwtimer_register (& timer_devices [i ].device , timer_devices [i ].name , RT_NULL ) != RT_EOK )
319+ {
320+ LOG_E ("%s register failed!" , timer_devices [i ].name );
321+ return - RT_ERROR ;
322+ }
323+ LOG_D ("%s register OK!" , timer_devices [i ].name );
324+
325+ rt_hw_interrupt_install (timer_devices [i ].irq_num ,
326+ k230_hwtimer_isr ,
327+ & timer_devices [i ],
328+ timer_devices [i ].name );
329+ rt_hw_interrupt_umask (timer_devices [i ].irq_num );
330+ }
331+ }
332+ INIT_BOARD_EXPORT (rt_hw_timer_init );
0 commit comments