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