aarch32_cpu/generic_timer/
el2.rs

1//! Code and types for Generic Timer support at EL2 on Armv8-R.
2
3use crate::register;
4
5use super::{El1PhysicalTimer, El1VirtualTimer, GenericTimer};
6
7/// Represents our Physical Timer when we are running at EL2.
8pub struct El2PhysicalTimer(El1PhysicalTimer);
9
10impl El2PhysicalTimer {
11    /// Create an EL1 Generic Timer handle
12    ///
13    /// # Safety
14    ///
15    /// Only create one of these at any given time, as they access shared
16    /// mutable state within the processor and do read-modify-writes on that state.
17    pub unsafe fn new() -> El2PhysicalTimer {
18        unsafe { El2PhysicalTimer(El1PhysicalTimer::new()) }
19    }
20
21    /// Set frequency
22    ///
23    /// Sets the frequency, in Hz, that the counters are incrementing at. You
24    /// might need to call this if your system doesn't initialise the frequency
25    /// value to something appropriate, or if you change the clock speed of the
26    /// timer.
27    pub fn frequency_hz_set(&mut self, new_frequency_hz: u32) {
28        register::Cntfrq::write(register::Cntfrq(new_frequency_hz))
29    }
30}
31
32impl GenericTimer for El2PhysicalTimer {
33    fn frequency_hz(&self) -> u32 {
34        self.0.frequency_hz()
35    }
36
37    fn counter(&self) -> u64 {
38        self.0.counter()
39    }
40
41    fn counter_compare(&self) -> u64 {
42        self.0.counter_compare()
43    }
44
45    fn counter_compare_set(&mut self, value: u64) {
46        self.0.counter_compare_set(value)
47    }
48
49    fn countdown(&self) -> u32 {
50        self.0.countdown()
51    }
52
53    fn countdown_set(&mut self, duration_ticks: u32) {
54        self.0.countdown_set(duration_ticks)
55    }
56
57    fn enabled(&self) -> bool {
58        self.0.enabled()
59    }
60
61    fn enable(&self, enabled: bool) {
62        self.0.enable(enabled)
63    }
64
65    fn interrupt_masked(&self) -> bool {
66        self.0.interrupt_masked()
67    }
68
69    fn interrupt_mask(&mut self, mask: bool) {
70        self.0.interrupt_mask(mask)
71    }
72
73    fn interrupt_status(&self) -> bool {
74        self.0.interrupt_status()
75    }
76}
77
78/// Represents our Virtual Timer when we are running at EL1.
79pub struct El2VirtualTimer(El1VirtualTimer);
80
81impl El2VirtualTimer {
82    /// Create an EL1 Generic Timer handle
83    ///
84    /// # Safety
85    ///
86    /// Only create one of these at any given time, as they access shared
87    /// mutable state within the processor and do read-modify-writes on that state.
88    pub unsafe fn new() -> El2VirtualTimer {
89        unsafe { El2VirtualTimer(El1VirtualTimer::new()) }
90    }
91
92    /// Set frequency
93    ///
94    /// Sets the frequency, in Hz, that the counters are incrementing at. You
95    /// might need to call this if your system doesn't initialise the frequency
96    /// value to something appropriate, or if you change the clock speed of the
97    /// timer.
98    pub fn frequency_hz_set(&mut self, new_frequency_hz: u32) {
99        register::Cntfrq::write(register::Cntfrq(new_frequency_hz))
100    }
101}
102
103impl GenericTimer for El2VirtualTimer {
104    fn frequency_hz(&self) -> u32 {
105        self.0.frequency_hz()
106    }
107
108    fn counter(&self) -> u64 {
109        self.0.counter()
110    }
111
112    fn counter_compare(&self) -> u64 {
113        self.0.counter_compare()
114    }
115
116    fn counter_compare_set(&mut self, value: u64) {
117        self.0.counter_compare_set(value)
118    }
119
120    fn countdown(&self) -> u32 {
121        self.0.countdown()
122    }
123
124    fn countdown_set(&mut self, duration_ticks: u32) {
125        self.0.countdown_set(duration_ticks)
126    }
127
128    fn enabled(&self) -> bool {
129        self.0.enabled()
130    }
131
132    fn enable(&self, enabled: bool) {
133        self.0.enable(enabled)
134    }
135
136    fn interrupt_masked(&self) -> bool {
137        self.0.interrupt_masked()
138    }
139
140    fn interrupt_mask(&mut self, mask: bool) {
141        self.0.interrupt_mask(mask)
142    }
143
144    fn interrupt_status(&self) -> bool {
145        self.0.interrupt_status()
146    }
147}
148
149/// Represents our Hypervisor-specific Physical Timer when we are running at EL1.
150pub struct El2HypPhysicalTimer();
151
152impl El2HypPhysicalTimer {
153    /// Create a Timer handle for the EL2-specific Hyp Physical Timer.
154    ///
155    /// # Safety
156    ///
157    /// Only create one of these at any given time, as they access shared
158    /// mutable state within the processor and do read-modify-writes on that state.
159    pub unsafe fn new() -> El2HypPhysicalTimer {
160        El2HypPhysicalTimer()
161    }
162}
163
164impl super::GenericTimer for El2HypPhysicalTimer {
165    fn frequency_hz(&self) -> u32 {
166        register::Cntfrq::read().0
167    }
168
169    fn counter(&self) -> u64 {
170        register::CntPct::read().0
171    }
172
173    fn counter_compare(&self) -> u64 {
174        register::CnthpCval::read().0
175    }
176
177    fn counter_compare_set(&mut self, value: u64) {
178        register::CnthpCval::write(register::CnthpCval(value))
179    }
180
181    fn countdown(&self) -> u32 {
182        register::CnthpTval::read().0
183    }
184
185    fn countdown_set(&mut self, duration_ticks: u32) {
186        register::CnthpTval::write(register::CnthpTval(duration_ticks))
187    }
188
189    fn enabled(&self) -> bool {
190        register::CnthpCtl::read().enable()
191    }
192
193    fn enable(&self, enabled: bool) {
194        register::CnthpCtl::modify(|r| {
195            r.set_enable(enabled);
196        });
197    }
198
199    fn interrupt_masked(&self) -> bool {
200        register::CnthpCtl::read().imask()
201    }
202
203    fn interrupt_mask(&mut self, mask: bool) {
204        register::CnthpCtl::modify(|r| {
205            r.set_imask(mask);
206        });
207    }
208
209    fn interrupt_status(&self) -> bool {
210        register::CnthpCtl::read().istatus()
211    }
212}