aarch32_cpu/generic_timer/
el0.rs

1//! Code and types for Generic Timer support at EL0 on Armv8-R.
2
3use crate::register;
4
5/// Represents our Generic Timer when we are running at EL0.
6///
7/// Note that for most of these APIs to work, EL0 needs to have been granted
8/// access using methods like
9/// [El1PhysicalTimer::el0_access_physical_counter](crate::generic_timer::El1PhysicalTimer::el0_access_physical_counter).
10pub struct El0PhysicalTimer();
11
12impl El0PhysicalTimer {
13    /// Create an EL0 Timer handle for the Physical Timer.
14    ///
15    /// EL2/EL1 has to grant permission for EL0 to use the Physical Timer, so
16    /// check they did that.
17    ///
18    /// # Safety
19    ///
20    /// Only create one of these at any given time, as they access shared
21    /// mutable state within the processor and do read-modify-writes on that
22    /// state.
23    pub unsafe fn new() -> El0PhysicalTimer {
24        El0PhysicalTimer()
25    }
26}
27
28impl super::GenericTimer for El0PhysicalTimer {
29    fn frequency_hz(&self) -> u32 {
30        register::Cntfrq::read().0
31    }
32
33    fn counter(&self) -> u64 {
34        register::CntPct::read().0
35    }
36
37    fn counter_compare(&self) -> u64 {
38        register::CntpCval::read().0
39    }
40
41    fn counter_compare_set(&mut self, value: u64) {
42        register::CntpCval::write(register::CntpCval(value))
43    }
44
45    fn countdown(&self) -> u32 {
46        register::CntpTval::read().0
47    }
48
49    fn countdown_set(&mut self, duration_ticks: u32) {
50        register::CntpTval::write(register::CntpTval(duration_ticks))
51    }
52
53    fn enabled(&self) -> bool {
54        register::CntpCtl::read().enable()
55    }
56
57    fn enable(&self, enabled: bool) {
58        register::CntpCtl::modify(|r| {
59            r.set_enable(enabled);
60        });
61    }
62
63    fn interrupt_masked(&self) -> bool {
64        register::CntpCtl::read().imask()
65    }
66
67    fn interrupt_mask(&mut self, mask: bool) {
68        register::CntpCtl::modify(|r| {
69            r.set_imask(mask);
70        });
71    }
72
73    fn interrupt_status(&self) -> bool {
74        register::CntpCtl::read().istatus()
75    }
76}
77
78pub struct El0VirtualTimer();
79
80impl El0VirtualTimer {
81    /// Create an EL0 Timer handle for the Virtual Timer.
82    ///
83    /// # Safety
84    ///
85    /// Only create one of these at any given time, as they access shared
86    /// mutable state within the processor and do read-modify-writes on that state.
87    pub unsafe fn new() -> El0VirtualTimer {
88        El0VirtualTimer()
89    }
90}
91
92impl super::GenericTimer for El0VirtualTimer {
93    fn frequency_hz(&self) -> u32 {
94        register::Cntfrq::read().0
95    }
96
97    fn counter(&self) -> u64 {
98        register::CntVct::read().0
99    }
100
101    fn counter_compare(&self) -> u64 {
102        register::CntvCval::read().0
103    }
104
105    fn counter_compare_set(&mut self, value: u64) {
106        register::CntvCval::write(register::CntvCval(value))
107    }
108
109    fn countdown(&self) -> u32 {
110        register::CntvTval::read().0
111    }
112
113    fn countdown_set(&mut self, duration_ticks: u32) {
114        register::CntvTval::write(register::CntvTval(duration_ticks))
115    }
116
117    fn enabled(&self) -> bool {
118        register::CntvCtl::read().enable()
119    }
120
121    fn enable(&self, enabled: bool) {
122        register::CntvCtl::modify(|r| {
123            r.set_enable(enabled);
124        });
125    }
126
127    fn interrupt_masked(&self) -> bool {
128        register::CntvCtl::read().imask()
129    }
130
131    fn interrupt_mask(&mut self, mask: bool) {
132        register::CntvCtl::modify(|r| {
133            r.set_imask(mask);
134        });
135    }
136
137    fn interrupt_status(&self) -> bool {
138        register::CntvCtl::read().istatus()
139    }
140}