Skip to main content

arm_generic_timer/
sysreg.rs

1// SPDX-FileCopyrightText: Copyright The arm-generic-timer Contributors.
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! System register based timer driver implementations.
5//!
6//! See D24.10 Generic Timer registers.
7
8use crate::{CounterInterface, TimerInterface};
9use arm_sysregs::el0::{
10    accessors::{
11        read_cntfrq_el0, read_cntp_ctl_el0, read_cntp_cval_el0, read_cntp_tval_el0,
12        read_cntpct_el0, read_cntv_ctl_el0, read_cntv_cval_el0, read_cntv_tval_el0,
13        read_cntvct_el0, write_cntp_ctl_el0, write_cntp_cval_el0, write_cntp_tval_el0,
14        write_cntv_ctl_el0, write_cntv_cval_el0, write_cntv_tval_el0,
15    },
16    registers::{CntpCtlEl0, CntpCvalEl0, CntpTvalEl0, CntvCtlEl0, CntvCvalEl0, CntvTvalEl0},
17};
18#[cfg(feature = "el1")]
19use arm_sysregs::el1::{
20    accessors::{
21        read_cntps_ctl_el1, read_cntps_cval_el1, read_cntps_tval_el1, write_cntps_ctl_el1,
22        write_cntps_cval_el1, write_cntps_tval_el1,
23    },
24    registers::{CntpsCtlEl1, CntpsCvalEl1, CntpsTvalEl1},
25};
26#[cfg(feature = "el2")]
27use arm_sysregs::el2::{
28    accessors::{
29        read_cnthp_ctl_el2, read_cnthp_cval_el2, read_cnthp_tval_el2, read_cnthps_ctl_el2,
30        read_cnthps_cval_el2, read_cnthps_tval_el2, read_cnthv_ctl_el2, read_cnthv_cval_el2,
31        read_cnthv_tval_el2, read_cnthvs_ctl_el2, read_cnthvs_cval_el2, read_cnthvs_tval_el2,
32        write_cnthp_ctl_el2, write_cnthp_cval_el2, write_cnthp_tval_el2, write_cnthps_ctl_el2,
33        write_cnthps_cval_el2, write_cnthps_tval_el2, write_cnthv_ctl_el2, write_cnthv_cval_el2,
34        write_cnthv_tval_el2, write_cnthvs_ctl_el2, write_cnthvs_cval_el2, write_cnthvs_tval_el2,
35    },
36    registers::{
37        CnthpCtlEl2, CnthpCvalEl2, CnthpTvalEl2, CnthpsCtlEl2, CnthpsCvalEl2, CnthpsTvalEl2,
38        CnthvCtlEl2, CnthvCvalEl2, CnthvTvalEl2, CnthvsCtlEl2, CnthvsCvalEl2, CnthvsTvalEl2,
39    },
40};
41
42/// Physical Secure Timer
43///
44/// Uses `CNTPS_*` system registers.
45#[cfg(feature = "el1")]
46pub struct PhysicalSecureTimer(());
47
48#[cfg(feature = "el1")]
49impl PhysicalSecureTimer {
50    /// Creates an instance of the Physical Secure Timer.
51    ///
52    /// # Safety
53    ///
54    /// The caller must ensure that no other instance exists and that there is
55    /// no concurrent access to the CNTPS_* system registers.
56    pub const unsafe fn new() -> Self {
57        Self(())
58    }
59}
60
61#[cfg(feature = "el1")]
62impl TimerInterface for PhysicalSecureTimer {
63    fn enable(&mut self) {
64        let control = read_cntps_ctl_el1();
65        write_cntps_ctl_el1(control | CntpsCtlEl1::ENABLE);
66    }
67
68    fn frequency(&self) -> u32 {
69        read_cntfrq_el0().clockfreq()
70    }
71
72    fn timer_value(&self) -> i32 {
73        read_cntps_tval_el1().timervalue() as i32
74    }
75
76    fn enable_interrupt(&mut self, enabled: bool) {
77        let mut control = read_cntps_ctl_el1();
78        control.set(CntpsCtlEl1::IMASK, !enabled);
79
80        write_cntps_ctl_el1(control);
81    }
82
83    fn compare_value(&self) -> u64 {
84        read_cntps_cval_el1().comparevalue()
85    }
86
87    fn set_timer_value(&mut self, timer_value: i32) {
88        write_cntps_tval_el1(CntpsTvalEl1::empty().with_timervalue(timer_value as u32));
89    }
90
91    fn set_compare_value(&mut self, compare_value: u64) {
92        write_cntps_cval_el1(CntpsCvalEl1::empty().with_comparevalue(compare_value));
93    }
94}
95
96/// Hypervisor Physical Timer
97///
98/// Uses `CNTHP_*` system registers.
99#[cfg(feature = "el2")]
100pub struct HypervisorPhysicalTimer(());
101
102#[cfg(feature = "el2")]
103impl HypervisorPhysicalTimer {
104    /// Creates an instance of the Hypervisor Physical Timer.
105    ///
106    /// # Safety
107    ///
108    /// The caller must ensure that no other instance exists and that there is
109    /// no concurrent access to the CNTHP_* system registers.
110    pub const unsafe fn new() -> Self {
111        Self(())
112    }
113}
114
115#[cfg(feature = "el2")]
116impl TimerInterface for HypervisorPhysicalTimer {
117    fn enable(&mut self) {
118        let control = read_cnthp_ctl_el2();
119        write_cnthp_ctl_el2(control | CnthpCtlEl2::ENABLE);
120    }
121
122    fn frequency(&self) -> u32 {
123        read_cntfrq_el0().clockfreq()
124    }
125
126    fn timer_value(&self) -> i32 {
127        read_cnthp_tval_el2().timervalue() as i32
128    }
129
130    fn enable_interrupt(&mut self, enabled: bool) {
131        let mut control = read_cnthp_ctl_el2();
132        control.set(CnthpCtlEl2::IMASK, !enabled);
133
134        write_cnthp_ctl_el2(control);
135    }
136
137    fn compare_value(&self) -> u64 {
138        read_cnthp_cval_el2().comparevalue()
139    }
140
141    fn set_timer_value(&mut self, timer_value: i32) {
142        write_cnthp_tval_el2(CnthpTvalEl2::empty().with_timervalue(timer_value as u32));
143    }
144
145    fn set_compare_value(&mut self, compare_value: u64) {
146        write_cnthp_cval_el2(CnthpCvalEl2::empty().with_comparevalue(compare_value));
147    }
148}
149
150/// Secure EL2 Physical Timer
151///
152/// Uses `CNTHPS_*` system registers.
153#[cfg(feature = "el2")]
154pub struct SecureEl2PhysicalTimer(());
155
156#[cfg(feature = "el2")]
157impl SecureEl2PhysicalTimer {
158    /// Creates an instance of the Secure EL2 Physical Timer.
159    ///
160    /// # Safety
161    ///
162    /// The caller must ensure that no other instance exists and that there is
163    /// no concurrent access to the CNTHPS_* system registers.
164    pub const unsafe fn new() -> Self {
165        Self(())
166    }
167}
168
169#[cfg(feature = "el2")]
170impl TimerInterface for SecureEl2PhysicalTimer {
171    fn enable(&mut self) {
172        let control = read_cnthps_ctl_el2();
173        write_cnthps_ctl_el2(control | CnthpsCtlEl2::ENABLE);
174    }
175
176    fn frequency(&self) -> u32 {
177        read_cntfrq_el0().clockfreq()
178    }
179
180    fn timer_value(&self) -> i32 {
181        read_cnthps_tval_el2().timervalue() as i32
182    }
183
184    fn enable_interrupt(&mut self, enabled: bool) {
185        let mut control = read_cnthps_ctl_el2();
186        control.set(CnthpsCtlEl2::IMASK, !enabled);
187
188        write_cnthps_ctl_el2(control);
189    }
190
191    fn compare_value(&self) -> u64 {
192        read_cnthps_cval_el2().comparevalue()
193    }
194
195    fn set_timer_value(&mut self, timer_value: i32) {
196        write_cnthps_tval_el2(CnthpsTvalEl2::empty().with_timervalue(timer_value as u32));
197    }
198
199    fn set_compare_value(&mut self, compare_value: u64) {
200        write_cnthps_cval_el2(CnthpsCvalEl2::empty().with_comparevalue(compare_value));
201    }
202}
203
204/// EL2 Virtual Timer
205///
206/// Uses `CNTHV_*` system registers
207#[cfg(feature = "el2")]
208pub struct El2VirtualTimer(());
209
210#[cfg(feature = "el2")]
211impl El2VirtualTimer {
212    /// Creates an instance of the EL2 Virtual Timer.
213    ///
214    /// # Safety
215    ///
216    /// The caller must ensure that no other instance exists and that there is
217    /// no concurrent access to the CNTHV_* system registers.
218    pub const unsafe fn new() -> Self {
219        Self(())
220    }
221}
222
223#[cfg(feature = "el2")]
224impl TimerInterface for El2VirtualTimer {
225    fn enable(&mut self) {
226        let control = read_cnthv_ctl_el2();
227        write_cnthv_ctl_el2(control | CnthvCtlEl2::ENABLE);
228    }
229
230    fn frequency(&self) -> u32 {
231        read_cntfrq_el0().clockfreq()
232    }
233
234    fn timer_value(&self) -> i32 {
235        read_cnthv_tval_el2().timervalue() as i32
236    }
237
238    fn enable_interrupt(&mut self, enabled: bool) {
239        let mut control = read_cnthv_ctl_el2();
240        control.set(CnthvCtlEl2::IMASK, !enabled);
241
242        write_cnthv_ctl_el2(control);
243    }
244
245    fn compare_value(&self) -> u64 {
246        read_cnthv_cval_el2().comparevalue()
247    }
248
249    fn set_timer_value(&mut self, timer_value: i32) {
250        write_cnthv_tval_el2(CnthvTvalEl2::empty().with_timervalue(timer_value as u32));
251    }
252
253    fn set_compare_value(&mut self, compare_value: u64) {
254        write_cnthv_cval_el2(CnthvCvalEl2::empty().with_comparevalue(compare_value));
255    }
256}
257
258/// Secure EL2 Virtual Timer
259///
260/// Uses `CNTHVS_*` system registers
261#[cfg(feature = "el2")]
262pub struct SecureEl2VirtualTimer(());
263
264#[cfg(feature = "el2")]
265impl SecureEl2VirtualTimer {
266    /// Creates an instance of the Secure EL2 Virtual Timer.
267    ///
268    /// # Safety
269    ///
270    /// The caller must ensure that no other instance exists and that there is
271    /// no concurrent access to the CNTHVS_* system registers.
272    pub const unsafe fn new() -> Self {
273        Self(())
274    }
275}
276
277#[cfg(feature = "el2")]
278impl TimerInterface for SecureEl2VirtualTimer {
279    fn enable(&mut self) {
280        let control = read_cnthvs_ctl_el2();
281        write_cnthvs_ctl_el2(control | CnthvsCtlEl2::ENABLE);
282    }
283
284    fn frequency(&self) -> u32 {
285        read_cntfrq_el0().clockfreq()
286    }
287
288    fn timer_value(&self) -> i32 {
289        read_cnthvs_tval_el2().timervalue() as i32
290    }
291
292    fn enable_interrupt(&mut self, enabled: bool) {
293        let mut control = read_cnthvs_ctl_el2();
294        control.set(CnthvsCtlEl2::IMASK, !enabled);
295
296        write_cnthvs_ctl_el2(control);
297    }
298
299    fn compare_value(&self) -> u64 {
300        read_cnthvs_cval_el2().comparevalue()
301    }
302
303    fn set_timer_value(&mut self, timer_value: i32) {
304        write_cnthvs_tval_el2(CnthvsTvalEl2::empty().with_timervalue(timer_value as u32));
305    }
306
307    fn set_compare_value(&mut self, compare_value: u64) {
308        write_cnthvs_cval_el2(CnthvsCvalEl2::empty().with_comparevalue(compare_value));
309    }
310}
311
312/// Physical Timer
313///
314/// Uses `CNTP_*` system registers.
315pub struct PhysicalTimer(());
316
317impl PhysicalTimer {
318    /// Creates an instance of the Physical Timer.
319    ///
320    /// # Safety
321    ///
322    /// The caller must ensure that no other instance exists and that there is
323    /// no concurrent access to the CNTP_* system registers.
324    pub const unsafe fn new() -> Self {
325        Self(())
326    }
327}
328
329impl TimerInterface for PhysicalTimer {
330    fn enable(&mut self) {
331        let control = read_cntp_ctl_el0();
332        write_cntp_ctl_el0(control | CntpCtlEl0::ENABLE);
333    }
334
335    fn frequency(&self) -> u32 {
336        read_cntfrq_el0().clockfreq()
337    }
338
339    fn timer_value(&self) -> i32 {
340        read_cntp_tval_el0().timervalue() as i32
341    }
342
343    fn enable_interrupt(&mut self, enabled: bool) {
344        let mut control = read_cntp_ctl_el0();
345        control.set(CntpCtlEl0::IMASK, !enabled);
346
347        write_cntp_ctl_el0(control);
348    }
349
350    fn compare_value(&self) -> u64 {
351        read_cntp_cval_el0().comparevalue()
352    }
353
354    fn set_timer_value(&mut self, timer_value: i32) {
355        write_cntp_tval_el0(CntpTvalEl0::empty().with_timervalue(timer_value as u32));
356    }
357
358    fn set_compare_value(&mut self, compare_value: u64) {
359        write_cntp_cval_el0(CntpCvalEl0::empty().with_comparevalue(compare_value));
360    }
361}
362
363/// Virtual Timer
364///
365/// Uses `CNTV_*` system registers.
366pub struct VirtualTimer(());
367
368impl VirtualTimer {
369    /// Creates an instance of the Virtual Timer.
370    ///
371    /// # Safety
372    ///
373    /// The caller must ensure that no other instance exists and that there is
374    /// no concurrent access to the CNTV_* system registers.
375    pub const unsafe fn new() -> Self {
376        Self(())
377    }
378}
379
380impl TimerInterface for VirtualTimer {
381    fn enable(&mut self) {
382        let control = read_cntv_ctl_el0();
383        write_cntv_ctl_el0(control | CntvCtlEl0::ENABLE);
384    }
385
386    fn frequency(&self) -> u32 {
387        read_cntfrq_el0().clockfreq()
388    }
389
390    fn timer_value(&self) -> i32 {
391        read_cntv_tval_el0().timervalue() as i32
392    }
393
394    fn enable_interrupt(&mut self, enabled: bool) {
395        let mut control = read_cntv_ctl_el0();
396        control.set(CntvCtlEl0::IMASK, !enabled);
397
398        write_cntv_ctl_el0(control);
399    }
400
401    fn compare_value(&self) -> u64 {
402        read_cntv_cval_el0().comparevalue()
403    }
404
405    fn set_timer_value(&mut self, timer_value: i32) {
406        write_cntv_tval_el0(CntvTvalEl0::empty().with_timervalue(timer_value as u32));
407    }
408
409    fn set_compare_value(&mut self, compare_value: u64) {
410        write_cntv_cval_el0(CntvCvalEl0::empty().with_comparevalue(compare_value));
411    }
412}
413
414/// Physical Counter.
415pub struct PhysicalCounter;
416
417impl CounterInterface for PhysicalCounter {
418    fn counter_value(&self) -> u64 {
419        read_cntpct_el0().physicalcount()
420    }
421
422    fn frequency(&self) -> u32 {
423        read_cntfrq_el0().clockfreq()
424    }
425}
426
427/// Virtual Counter.
428pub struct VirtualCounter;
429
430impl CounterInterface for VirtualCounter {
431    fn counter_value(&self) -> u64 {
432        read_cntvct_el0().virtualcount()
433    }
434
435    fn frequency(&self) -> u32 {
436        read_cntfrq_el0().clockfreq()
437    }
438}