1 /*
2  * Copyright (c) 2006-2022, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2021-12-20     GuEe-GUI     first version
9  * 2022-08-24     GuEe-GUI     Add OFW support
10  */
11 
12 #include <rthw.h>
13 #include <rtthread.h>
14 #include <rtdevice.h>
15 
16 /* support registers access and timer registers in libcpu */
17 #include <cpu.h>
18 #include <cpuport.h>
19 
20 typedef void (*timer_ctrl_handle)(rt_bool_t enable);
21 typedef rt_uint64_t (*timer_value_handle)(rt_uint64_t val);
22 
23 static volatile rt_uint64_t timer_step;
24 
25 static int arm_arch_timer_irq = -1;
26 static timer_ctrl_handle arm_arch_timer_ctrl_handle = RT_NULL;
27 static timer_value_handle arm_arch_timer_value_handle = RT_NULL;
28 
29 /* CTL */
mon_ptimer_ctrl(rt_bool_t enable)30 static void mon_ptimer_ctrl(rt_bool_t enable)
31 {
32     rt_hw_sysreg_write(CNTPS_CTL, !!enable);
33 }
34 
hyp_s_ptimer_ctrl(rt_bool_t enable)35 static void hyp_s_ptimer_ctrl(rt_bool_t enable)
36 {
37 #if ARCH_ARMV8_EXTENSIONS > 1
38     rt_hw_sysreg_write(CNTHPS_CTL, !!enable);
39 #endif
40 }
41 
hyp_ns_ptimer_ctrl(rt_bool_t enable)42 static void hyp_ns_ptimer_ctrl(rt_bool_t enable)
43 {
44     rt_hw_sysreg_write(CNTHP_CTL, !!enable);
45 }
46 
hyp_s_vtimer_ctrl(rt_bool_t enable)47 static void hyp_s_vtimer_ctrl(rt_bool_t enable)
48 {
49 #if ARCH_ARMV8_EXTENSIONS > 1
50     rt_hw_sysreg_write(CNTHVS_CTL, !!enable);
51 #endif
52 }
53 
hyp_ns_vtimer_ctrl(rt_bool_t enable)54 static void hyp_ns_vtimer_ctrl(rt_bool_t enable)
55 {
56 #if ARCH_ARMV8_EXTENSIONS > 1
57     rt_hw_sysreg_write(CNTHV_CTL, !!enable);
58 #endif
59 }
60 
os_ptimer_ctrl(rt_bool_t enable)61 static void os_ptimer_ctrl(rt_bool_t enable)
62 {
63     rt_hw_sysreg_write(CNTP_CTL, !!enable);
64 }
65 
os_vtimer_ctrl(rt_bool_t enable)66 static void os_vtimer_ctrl(rt_bool_t enable)
67 {
68     rt_hw_sysreg_write(CNTV_CTL, !!enable);
69 }
70 
71 /* TVAL */
mon_ptimer_value(rt_uint64_t val)72 static rt_uint64_t mon_ptimer_value(rt_uint64_t val)
73 {
74     if (val)
75     {
76         rt_hw_sysreg_write(CNTPS_TVAL, val);
77     }
78     else
79     {
80         rt_hw_sysreg_read(CNTPS_TVAL, val);
81     }
82 
83     return val;
84 }
85 
hyp_s_ptimer_value(rt_uint64_t val)86 static rt_uint64_t hyp_s_ptimer_value(rt_uint64_t val)
87 {
88 #if ARCH_ARMV8_EXTENSIONS > 1
89     if (val)
90     {
91         rt_hw_sysreg_write(CNTHPS_TVAL, val);
92     }
93     else
94     {
95         rt_hw_sysreg_read(CNTHPS_TVAL, val);
96     }
97 
98     return val;
99 #else
100     return 0;
101 #endif
102 }
103 
hyp_ns_ptimer_value(rt_uint64_t val)104 static rt_uint64_t hyp_ns_ptimer_value(rt_uint64_t val)
105 {
106     if (val)
107     {
108         rt_hw_sysreg_write(CNTHP_TVAL, val);
109     }
110     else
111     {
112         rt_hw_sysreg_read(CNTHP_TVAL, val);
113     }
114 
115     return val;
116 }
117 
hyp_s_vtimer_value(rt_uint64_t val)118 static rt_uint64_t hyp_s_vtimer_value(rt_uint64_t val)
119 {
120 #if ARCH_ARMV8_EXTENSIONS > 1
121     if (val)
122     {
123         rt_hw_sysreg_write(CNTHVS_TVAL, val);
124     }
125     else
126     {
127         rt_hw_sysreg_read(CNTHVS_TVAL, val);
128     }
129 
130     return val;
131 #else
132     return 0;
133 #endif
134 }
135 
hyp_ns_vtimer_value(rt_uint64_t val)136 static rt_uint64_t hyp_ns_vtimer_value(rt_uint64_t val)
137 {
138 #if ARCH_ARMV8_EXTENSIONS > 1
139     if (val)
140     {
141         rt_hw_sysreg_write(CNTHV_TVAL, val);
142     }
143     else
144     {
145         rt_hw_sysreg_read(CNTHV_TVAL, val);
146     }
147 
148     return val;
149 #else
150     return 0;
151 #endif
152 }
153 
os_ptimer_value(rt_uint64_t val)154 static rt_uint64_t os_ptimer_value(rt_uint64_t val)
155 {
156     if (val)
157     {
158         rt_hw_sysreg_write(CNTP_TVAL, val);
159     }
160     else
161     {
162         rt_hw_sysreg_read(CNTP_TVAL, val);
163     }
164 
165     return val;
166 }
167 
os_vtimer_value(rt_uint64_t val)168 static rt_uint64_t os_vtimer_value(rt_uint64_t val)
169 {
170     if (val)
171     {
172         rt_hw_sysreg_write(CNTV_TVAL, val);
173     }
174     else
175     {
176         rt_hw_sysreg_read(CNTV_TVAL, val);
177     }
178 
179     return val;
180 }
181 
182 static timer_ctrl_handle ctrl_handle[] =
183 {
184     mon_ptimer_ctrl,
185     hyp_s_ptimer_ctrl,
186     hyp_ns_ptimer_ctrl,
187     hyp_s_vtimer_ctrl,
188     hyp_ns_vtimer_ctrl,
189     os_ptimer_ctrl,
190     os_vtimer_ctrl,
191 };
192 
193 static timer_value_handle value_handle[] =
194 {
195     mon_ptimer_value,
196     hyp_s_ptimer_value,
197     hyp_ns_ptimer_value,
198     hyp_s_vtimer_value,
199     hyp_ns_vtimer_value,
200     os_ptimer_value,
201     os_vtimer_value,
202 };
203 
arm_arch_timer_local_enable(void)204 static rt_err_t arm_arch_timer_local_enable(void)
205 {
206     rt_err_t ret = RT_EOK;
207 
208     if (arm_arch_timer_irq >= 0)
209     {
210         arm_arch_timer_ctrl_handle(RT_FALSE);
211         arm_arch_timer_value_handle(timer_step);
212 
213         rt_hw_interrupt_umask(arm_arch_timer_irq);
214 
215         arm_arch_timer_ctrl_handle(RT_TRUE);
216     }
217     else
218     {
219         ret = -RT_ENOSYS;
220     }
221 
222     return ret;
223 }
224 
225 rt_used
arm_arch_timer_local_disable(void)226 static rt_err_t arm_arch_timer_local_disable(void)
227 {
228     rt_err_t ret = RT_EOK;
229 
230     if (arm_arch_timer_ctrl_handle)
231     {
232         arm_arch_timer_ctrl_handle(RT_FALSE);
233         rt_hw_interrupt_mask(arm_arch_timer_irq);
234     }
235     else
236     {
237         ret = -RT_ENOSYS;
238     }
239 
240     return ret;
241 }
242 
243 rt_used
arm_arch_timer_set_frequency(rt_uint64_t frq)244 static rt_err_t arm_arch_timer_set_frequency(rt_uint64_t frq)
245 {
246     rt_err_t ret = RT_EOK;
247 
248 #ifdef ARCH_SUPPORT_TEE
249     rt_hw_isb();
250     rt_hw_sysreg_write(CNTFRQ, frq);
251     rt_hw_dsb();
252 #else
253     ret = -RT_ENOSYS;
254 #endif
255 
256     return ret;
257 }
258 
259 rt_used
arm_arch_timer_get_frequency(void)260 static rt_uint64_t arm_arch_timer_get_frequency(void)
261 {
262     rt_uint64_t frq;
263 
264     rt_hw_isb();
265     rt_hw_sysreg_read(CNTFRQ, frq);
266     rt_hw_isb();
267 
268     return frq;
269 }
270 
271 rt_used
arm_arch_timer_set_value(rt_uint64_t val)272 static rt_err_t arm_arch_timer_set_value(rt_uint64_t val)
273 {
274     rt_err_t ret = RT_EOK;
275 
276     if (arm_arch_timer_value_handle)
277     {
278         val = arm_arch_timer_value_handle(val);
279     }
280     else
281     {
282         ret = -RT_ENOSYS;
283     }
284 
285     return ret;
286 }
287 
288 rt_used
arm_arch_timer_get_value(void)289 static rt_uint64_t arm_arch_timer_get_value(void)
290 {
291     rt_uint64_t val = 0;
292 
293     if (arm_arch_timer_value_handle)
294     {
295         val = arm_arch_timer_value_handle(0);
296     }
297 
298     return val;
299 }
300 
arm_arch_timer_isr(int vector,void * param)301 static void arm_arch_timer_isr(int vector, void *param)
302 {
303     arm_arch_timer_set_value(timer_step);
304 
305     rt_tick_increase();
306 }
307 
arm_arch_timer_post_init(void)308 static int arm_arch_timer_post_init(void)
309 {
310     arm_arch_timer_local_enable();
311 
312     return 0;
313 }
314 INIT_SECONDARY_CPU_EXPORT(arm_arch_timer_post_init);
315 
arm_arch_timer_probe(struct rt_platform_device * pdev)316 static rt_err_t arm_arch_timer_probe(struct rt_platform_device *pdev)
317 {
318     int mode_idx, irq_idx;
319     const char *irq_name[] =
320     {
321         "phys",     /* Secure Phys IRQ */
322         "virt",     /* Non-secure Phys IRQ */
323         "hyp-phys", /* Virt IRQ */
324         "hyp-virt", /* Hyp IRQ */
325     };
326 
327 #if defined(ARCH_SUPPORT_TEE)
328     mode_idx = 0;
329     irq_idx = 0;
330 #elif defined(ARCH_SUPPORT_HYP)
331     mode_idx = 2;
332     irq_idx = 3;
333 #else
334     mode_idx = 5;
335     irq_idx = 1;
336 #endif
337 
338     arm_arch_timer_irq = rt_dm_dev_get_irq_by_name(&pdev->parent, irq_name[irq_idx]);
339 
340     if (arm_arch_timer_irq < 0)
341     {
342         arm_arch_timer_irq = rt_dm_dev_get_irq(&pdev->parent, irq_idx);
343     }
344 
345     if (arm_arch_timer_irq < 0)
346     {
347         return -RT_EEMPTY;
348     }
349 
350     arm_arch_timer_ctrl_handle = ctrl_handle[mode_idx];
351     arm_arch_timer_value_handle = value_handle[mode_idx];
352 
353     rt_hw_interrupt_install(arm_arch_timer_irq, arm_arch_timer_isr, RT_NULL, "tick-arm-timer");
354 
355     timer_step = arm_arch_timer_get_frequency() / RT_TICK_PER_SECOND;
356 
357     arm_arch_timer_local_enable();
358 
359     return RT_EOK;
360 }
361 
362 static const struct rt_ofw_node_id arm_arch_timer_ofw_ids[] =
363 {
364     { .compatible = "arm,armv7-timer", },
365     { .compatible = "arm,armv8-timer", },
366     { /* sentinel */ }
367 };
368 
369 static struct rt_platform_driver arm_arch_timer_driver =
370 {
371     .name = "arm-arch-timer",
372     .ids = arm_arch_timer_ofw_ids,
373 
374     .probe = arm_arch_timer_probe,
375 };
376 
arm_arch_timer_drv_register(void)377 static int arm_arch_timer_drv_register(void)
378 {
379     rt_platform_driver_register(&arm_arch_timer_driver);
380 
381     return 0;
382 }
383 INIT_SUBSYS_EXPORT(arm_arch_timer_drv_register);
384