1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2022-07-15     Emuzit            first version
9  */
10 #include <rthw.h>
11 #include <drivers/hwtimer.h>
12 #include "ch56x_sys.h"
13 #include "ch56x_timer.h"
14 #include "isr_sp.h"
15 
16 #if !defined(BSP_USING_TMR0) && !defined(BSP_USING_TMR1) && !defined(BSP_USING_TMR2)
17     #error "Please define at least one TMRx"
18 #endif
19 
20 struct hwtimer_device
21 {
22     struct rt_hwtimer_device parent;
23     struct rt_hwtimer_info hwtimer_info;
24     volatile struct timer_registers *reg_base;
25     rt_hwtimer_mode_t tmode;
26     irq_number_t irqn;
27     char *name;
28 };
29 
30 #ifdef BSP_USING_TMR0
31 static struct hwtimer_device hwtimer_device_0 =
32 {
33     .hwtimer_info =
34     {
35         .maxfreq = 80000000,
36         .minfreq = 80000000,
37         .maxcnt  = 0x3ffffff,
38         .cntmode = HWTIMER_CNTMODE_UP,
39     },
40     .reg_base = (struct timer_registers *)TMR0_REG_BASE,
41     .tmode = HWTIMER_MODE_PERIOD,
42     .irqn = TMR0_IRQn,
43     .name = "timer0",
44 };
45 #endif
46 
47 #ifdef BSP_USING_TMR1
48 static struct hwtimer_device hwtimer_device_1 =
49 {
50     .hwtimer_info =
51     {
52         .maxfreq = 80000000,
53         .minfreq = 80000000,
54         .maxcnt  = 0x3ffffff,
55         .cntmode = HWTIMER_CNTMODE_UP,
56     },
57     .reg_base = (struct timer_registers *)TMR1_REG_BASE,
58     .tmode = HWTIMER_MODE_PERIOD,
59     .irqn = TMR1_IRQn,
60     .name = "timer1",
61 };
62 #endif
63 
64 #ifdef BSP_USING_TMR2
65 static struct hwtimer_device hwtimer_device_2 =
66 {
67     .hwtimer_info =
68     {
69         .maxfreq = 80000000,
70         .minfreq = 80000000,
71         .maxcnt  = 0x3ffffff,
72         .cntmode = HWTIMER_CNTMODE_UP,
73     },
74     .reg_base = (struct timer_registers *)TMR2_REG_BASE,
75     .tmode = HWTIMER_MODE_PERIOD,
76     .irqn = TMR2_IRQn,
77     .name = "timer2",
78 };
79 #endif
80 
81 static void hwtimer_stop(struct rt_hwtimer_device *timer);
82 
hwtimer_init(struct rt_hwtimer_device * timer,uint32_t state)83 static void hwtimer_init(struct rt_hwtimer_device *timer, uint32_t state)
84 {
85     struct hwtimer_device *hwtimer_device = (void *)timer;
86 
87     RT_ASSERT(hwtimer_device != RT_NULL);
88 
89     /* no resource processing, `state` ignored */
90     hwtimer_stop(timer);
91 
92     if (hwtimer_device->irqn != TMR0_IRQn)
93     {
94         hwtimer_device->reg_base->CTRL_DMA.reg = 0;
95     }
96 }
97 
hwtimer_start(struct rt_hwtimer_device * timer,uint32_t cnt,rt_hwtimer_mode_t mode)98 static rt_err_t hwtimer_start(struct rt_hwtimer_device *timer, uint32_t cnt, rt_hwtimer_mode_t mode)
99 {
100     struct hwtimer_device *hwtimer_device = (void *)timer;
101     volatile struct timer_registers *txreg;
102 
103     RT_ASSERT(hwtimer_device != RT_NULL);
104 
105     /* hwtimer_device->tmode may be different from timer->mode.
106      * For multi-cycle ONESHOT, tmode is set to PERIOD at hwtimer_start.
107     */
108     hwtimer_device->tmode = mode;
109 
110     sys_clk_off_by_irqn(hwtimer_device->irqn, SYS_SLP_CLK_ON);
111     txreg = hwtimer_device->reg_base;
112     txreg->CNT_END = cnt;
113     txreg->CTRL_MOD.reg = RB_TMR_ALL_CLEAR;
114     txreg->CTRL_MOD.reg = RB_TMR_COUNT_EN;
115     txreg->INTER_EN.cyc_end = 1;
116     rt_hw_interrupt_umask(hwtimer_device->irqn);
117 
118     return RT_EOK;
119 }
120 
hwtimer_stop(struct rt_hwtimer_device * timer)121 static void hwtimer_stop(struct rt_hwtimer_device *timer)
122 {
123     struct hwtimer_device *hwtimer_device = (void *)timer;
124     volatile struct timer_registers *txreg;
125 
126     RT_ASSERT(hwtimer_device != RT_NULL);
127 
128     rt_hw_interrupt_mask(hwtimer_device->irqn);
129     /* note: RB_TMR_COUNT_EN cleared */
130     txreg = hwtimer_device->reg_base;
131     txreg->CTRL_MOD.reg = RB_TMR_ALL_CLEAR;
132     txreg->INTER_EN.reg = 0;
133     sys_clk_off_by_irqn(hwtimer_device->irqn, SYS_SLP_CLK_OFF);
134 }
135 
hwtimer_count_get(struct rt_hwtimer_device * timer)136 static uint32_t hwtimer_count_get(struct rt_hwtimer_device *timer)
137 {
138     struct hwtimer_device *hwtimer_device = (void *)timer;
139 
140     RT_ASSERT(hwtimer_device != RT_NULL);
141 
142     return hwtimer_device->reg_base->COUNT;
143 }
144 
hwtimer_control(struct rt_hwtimer_device * timer,uint32_t cmd,void * args)145 static rt_err_t hwtimer_control(
146     struct rt_hwtimer_device *timer, uint32_t cmd, void *args)
147 {
148     struct hwtimer_device *hwtimer_device = (void *)timer;
149     rt_err_t result = RT_EOK;
150 
151     RT_ASSERT(hwtimer_device != RT_NULL);
152 
153     switch (cmd)
154     {
155     case HWTIMER_CTRL_FREQ_SET:
156         /*  clocking for ch56x timers are fixed to Fsys */
157         if (args == RT_NULL || *(uint32_t *)args != timer->info->minfreq)
158         {
159             result = -RT_EINVAL;
160         }
161         break;
162 
163     case HWTIMER_CTRL_STOP:
164     case HWTIMER_CTRL_INFO_GET:
165     case HWTIMER_CTRL_MODE_SET:
166     default:
167         result = -RT_ENOSYS;
168     }
169 
170     return result;
171 }
172 
173 static const struct rt_hwtimer_ops hwtimer_ops =
174 {
175     .init = hwtimer_init,
176     .start = hwtimer_start,
177     .stop = hwtimer_stop,
178     .count_get = hwtimer_count_get,
179     .control = hwtimer_control,
180 };
181 
rt_hw_hwtimer_init(void)182 static int rt_hw_hwtimer_init(void)
183 {
184     struct hwtimer_device *devices[3];
185 
186     uint32_t Fsys = sys_hclk_get();
187 
188     int n = 0;
189 
190 #ifdef BSP_USING_TMR2
191     devices[n++] = &hwtimer_device_2;
192 #endif
193 #ifdef BSP_USING_TMR1
194     devices[n++] = &hwtimer_device_1;
195 #endif
196 #ifdef BSP_USING_TMR0
197     devices[n++] = &hwtimer_device_0;
198 #endif
199 
200     while (--n >= 0)
201     {
202         struct hwtimer_device *hwtimer_device = devices[n];
203         /* counting frequency is fixed to Fsys */
204         hwtimer_device->hwtimer_info.maxfreq = Fsys;
205         hwtimer_device->hwtimer_info.minfreq = Fsys;
206         hwtimer_device->parent.info = &hwtimer_device->hwtimer_info;
207         hwtimer_device->parent.ops = &hwtimer_ops;
208         rt_device_hwtimer_register(
209             &hwtimer_device->parent, hwtimer_device->name, RT_NULL);
210     }
211     return RT_EOK;
212 }
213 INIT_DEVICE_EXPORT(rt_hw_hwtimer_init);
214 
_hwtimer_isr_common(struct hwtimer_device * hwtimer_device)215 static void _hwtimer_isr_common(struct hwtimer_device *hwtimer_device)
216 {
217     volatile struct timer_registers *txreg = hwtimer_device->reg_base;
218 
219     if (txreg->INT_FLAG.cyc_end)
220     {
221         if (hwtimer_device->tmode == HWTIMER_MODE_ONESHOT)
222         {
223             /* disable timer to emulate oneshot */
224             txreg->CTRL_MOD.reg = 0;
225         }
226         rt_device_hwtimer_isr(&hwtimer_device->parent);
227         txreg->INT_FLAG.cyc_end = 1;
228     }
229 }
230 
231 #ifdef BSP_USING_TMR0
232 void tmr0_irq_handler(void) __attribute__((interrupt()));
tmr0_irq_handler(void)233 void tmr0_irq_handler(void)
234 {
235     isr_sp_enter();
236     rt_interrupt_enter();
237     _hwtimer_isr_common(&hwtimer_device_0);
238     rt_interrupt_leave();
239     isr_sp_leave();
240 }
241 #endif
242 
243 #ifdef BSP_USING_TMR1
244 void tmr1_irq_handler(void) __attribute__((interrupt()));
tmr1_irq_handler(void)245 void tmr1_irq_handler(void)
246 {
247     isr_sp_enter();
248     rt_interrupt_enter();
249     _hwtimer_isr_common(&hwtimer_device_1);
250     rt_interrupt_leave();
251     isr_sp_leave();
252 }
253 #endif
254 
255 #ifdef BSP_USING_TMR2
256 void tmr2_irq_handler(void) __attribute__((interrupt()));
tmr2_irq_handler(void)257 void tmr2_irq_handler(void)
258 {
259     isr_sp_enter();
260     rt_interrupt_enter();
261     _hwtimer_isr_common(&hwtimer_device_2);
262     rt_interrupt_leave();
263     isr_sp_leave();
264 }
265 #endif
266