Skip to content

Commit 3699911

Browse files
committed
bsp: k230: add hwtimer support
K230 support 6 general hardware timers and 3 stc timers. This patch only implement drivers for general hw timers. Signed-off-by: Chen Wang <[email protected]>
1 parent 890a4ba commit 3699911

File tree

7 files changed

+635
-0
lines changed

7 files changed

+635
-0
lines changed

bsp/k230/.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,7 @@ CONFIG_BSP_USING_SDIO0=y
14971497
# CONFIG_BSP_SDIO0_1V8 is not set
14981498
# CONFIG_BSP_USING_SDIO1 is not set
14991499
CONFIG_BSP_SD_MNT_DEVNAME="sd0p1"
1500+
# CONFIG_BSP_USING_TIMERS is not set
15001501
# CONFIG_BSP_USING_WDT is not set
15011502
# CONFIG_BSP_UTEST_DRIVERS is not set
15021503
# end of Drivers Configuration

bsp/k230/board/Kconfig

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,37 @@ menu "Drivers Configuration"
3939
default "sd0p1"
4040
endif
4141

42+
menuconfig BSP_USING_TIMERS
43+
bool "Enable Hardware Timers"
44+
select RT_USING_HWTIMER
45+
default n
46+
47+
if BSP_USING_TIMERS
48+
config BSP_USING_TIMER0
49+
bool "Enable Timer0"
50+
default n
51+
52+
config BSP_USING_TIMER1
53+
bool "Enable Timer1"
54+
default n
55+
56+
config BSP_USING_TIMER2
57+
bool "Enable Timer2"
58+
default n
59+
60+
config BSP_USING_TIMER3
61+
bool "Enable Timer3"
62+
default n
63+
64+
config BSP_USING_TIMER4
65+
bool "Enable Timer4"
66+
default n
67+
68+
config BSP_USING_TIMER5
69+
bool "Enable Timer5"
70+
default n
71+
endif
72+
4273
menuconfig BSP_USING_WDT
4374
bool "Enable Watchdog Timer"
4475
select RT_USING_WDT
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# RT-Thread building script for component
2+
3+
from building import *
4+
5+
cwd = GetCurrentDir()
6+
src = Glob('*.c')
7+
CPPPATH = [cwd]
8+
9+
group = DefineGroup('TIMER', src, depend = ['BSP_USING_TIMERS'], CPPPATH = CPPPATH)
10+
11+
objs = [group]
12+
13+
list = os.listdir(cwd)
14+
15+
for item in list:
16+
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
17+
objs = objs + SConscript(os.path.join(item, 'SConscript'))
18+
19+
Return('objs')
Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
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

Comments
 (0)