arm_generic_timer/
lib.rs

1// SPDX-FileCopyrightText: Copyright The arm-generic-timer Contributors.
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4#![no_std]
5#![doc = include_str!("../README.md")]
6#![deny(clippy::undocumented_unsafe_blocks)]
7#![deny(unsafe_op_in_unsafe_fn)]
8
9use core::time::Duration;
10
11use bitflags::bitflags;
12use safe_mmio::{
13    field, field_shared,
14    fields::{ReadPure, ReadPureWrite},
15    UniqueMmioPointer,
16};
17use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
18
19/// Counter Control Register
20#[repr(transparent)]
21#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
22pub struct CntCr(u32);
23
24/// Counter Status Register
25#[repr(transparent)]
26#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
27pub struct CntSr(u32);
28
29/// Counter Identification Register.
30#[repr(transparent)]
31#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
32pub struct CntId(u32);
33
34/// Counter-timer Access Control Register.
35#[repr(transparent)]
36#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
37pub struct CntAcr(u32);
38
39/// Timer feature bits, defined at I5.7.16 CNTTIDR, Counter-timer Timer ID Register description.
40#[repr(transparent)]
41#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
42pub struct Features(u8);
43
44/// Counter-timer EL0 Access Control Register.
45#[repr(transparent)]
46#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
47pub struct CntEl0Acr(u32);
48
49/// Common control register of the physical and virtual timers. Defined at I5.7.10 CNTP_CTL,
50/// Counter-timer Physical Timer Control and at CNTV_CTL, Counter-timer Virtual Timer Control.
51#[repr(transparent)]
52#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
53pub struct TimerControl(u32);
54
55bitflags! {
56    impl CntCr: u32 {
57        /// Scaling is enabled. This bit depends on the presence of FEAT_CNTSC.
58        const SCEN = 1 << 2;
59        /// Halt-on-debug.
60        const HDBG = 1 << 1;
61        /// System counter enabled.
62        const EN = 1 << 0;
63    }
64
65    impl CntSr: u32 {
66        /// Halt-on-debug.
67        const HDBG = 1 << 1;
68    }
69
70    impl CntAcr: u32 {
71        /// Read/write access to the EL1 Physical Timer registers
72        const RWPT = 1 << 5;
73        /// Read/write access to the Virtual Timer registers
74        const RWVT = 1 << 4;
75        /// Read-only access to CNTVOFF
76        const RVOFF = 1 << 3;
77        /// Read-only access to CNTFRQ
78        const RFRQ = 1 << 2;
79        /// Read-only access to CNTVCT
80        const RVCT = 1 << 1;
81        /// Read-only access to CNTPCT
82        const RPCT = 1 << 0;
83    }
84
85    impl Features: u8 {
86        /// Frame<n> has a second view, CNTEL0Base<n>.
87        const CNTEL0BASE = 1 << 2;
88        /// Frame<n> has virtual capability. The virtual time and offset registers are implemented.
89        const VIRTUAL = 1 << 1;
90        /// Frame<n> is implemented.
91        const IMPLEMENTED = 1 << 0;
92    }
93
94    impl CntEl0Acr: u32 {
95        /// Second view read access control for CNTP_CVAL, CNTP_TVAL, and CNTP_CTL.
96        const EL0PTEN = 1 << 9;
97        /// Second view read access control for CNTV_CVAL, CNTV_TVAL, and CNTV_CTL.
98        const EL0VTEN = 1 << 8;
99        /// Second view read access control for CNTVCT and CNTFRQ.
100        const EL0VCTEN = 1 << 1;
101        /// Second view read access control for CNTPCT and CNTFRQ.
102        const EL0PCTEN = 1 << 0;
103    }
104
105    impl TimerControl: u32 {
106        /// Timer condition is met.
107        const ISTATUS = 1 << 2;
108        /// Timer interrupt is masked.
109        const IMASK = 1 << 1;
110        /// Timer enabled.
111        const ENABLE = 1 << 0;
112    }
113}
114
115impl CntCr {
116    const FCREQ_MASK: u32 = 0x0000_03ff;
117    const FCREQ_SHIFT: u32 = 8;
118
119    /// Write FCREQ field of the register.
120    pub fn set_fcreq(&mut self, index: usize) {
121        let mut value = self.0 & !(Self::FCREQ_MASK << Self::FCREQ_SHIFT);
122        value |= ((index as u32) & Self::FCREQ_MASK) << Self::FCREQ_SHIFT;
123        self.0 = value;
124    }
125}
126
127impl CntSr {
128    const FCACK_MASK: u32 = 0x0000_03ff;
129    const FCACK_SHIFT: u32 = 8;
130
131    /// Read FCACK field of the register.
132    pub fn fcack(&self) -> usize {
133        ((self.0 >> Self::FCACK_SHIFT) & Self::FCACK_MASK) as usize
134    }
135}
136
137impl CntId {
138    const CNTSC_MASK: u32 = 0b1111;
139    const CNTSC_IMPLEMENTED: u32 = 0b0001;
140
141    /// Indicates whether Counter Scaling is implemented.
142    pub fn scaling_implemented(&self) -> bool {
143        self.0 & Self::CNTSC_MASK == Self::CNTSC_IMPLEMENTED
144    }
145}
146
147/// Table I2-1 CNTControlBase memory map
148#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
149#[repr(C, align(4))]
150pub struct CntControlBase {
151    /// 0x000 Counter Control Register
152    cntcr: ReadPureWrite<CntCr>,
153    /// 0x004 Counter Status Register
154    cntsr: ReadPure<CntSr>,
155    /// 0x008 Counter Count Value register
156    cntcv: ReadPureWrite<u64>,
157    /// 0x010 Counter Counter Scale register
158    cntscr: ReadPureWrite<u32>,
159    reserved_14: [u32; 2],
160    /// 0x01c Counter ID register
161    cntid: ReadPure<CntId>,
162    /// 0x020 Counter Frequency IDs
163    cntfid: [ReadPureWrite<u32>; 40],
164    /// 0x0c0 Implementation defined
165    impdef_0c0: [u32; 16],
166    reserved_100: [u32; 948],
167    /// 0xfd0 Counter ID registers
168    counter_id: [ReadPure<u32>; 12],
169}
170
171/// Table I2-2 CNTReadBase memory map
172#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
173#[repr(C, align(4))]
174pub struct CntReadBase {
175    /// 0x000 Counter Count Value register
176    cntcv: ReadPure<u64>,
177    reserved_8: [u32; 1010],
178    /// 0xfd0 Counter ID registers
179    counter_id: [ReadPure<u32>; 12],
180}
181
182/// Table I2-3 CNTCTLBase memory map
183#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
184#[repr(C, align(4))]
185pub struct CntCtlBase {
186    /// 0x000 Counter-timer Frequency
187    cntfrq: ReadPureWrite<u32>,
188    /// 0x004 Counter-timer Non-secure Access Register
189    cntnsar: ReadPureWrite<u32>,
190    /// 0x008 Counter-timer Timer ID Register
191    cnttidr: ReadPure<u32>,
192    reserved_00c: [u32; 13],
193    /// 0x040 Counter-timer Access Control Registers
194    cntacr: [ReadPureWrite<CntAcr>; 8],
195    reserved_060: [u32; 8],
196    /// 0x080 Counter-timer Virtual Offsets
197    cntvoff: [ReadPureWrite<u64>; 8],
198    reserved_0c0: [u32; 16],
199    /// 0x100 Implementation defined
200    impdef_100: [u32; 448],
201    reserved_800: [u32; 496],
202    impdef_fc0: [u32; 4],
203    /// 0xfd0 Counter ID registers
204    counter_id: [ReadPure<u32>; 12],
205}
206
207/// Repeated subset of register that describe a physical or virtual timer in the CntBase or
208/// CntEl0Base blocks.
209#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
210#[repr(C, align(4))]
211pub struct TimerRegs {
212    /// 0x000 Counter-timer Timer CompareValue
213    cval: ReadPureWrite<u64>,
214    /// 0x008 Counter-timer Timer TimerValue
215    tval: ReadPureWrite<u32>,
216    /// 0x00c Counter-timer Timer Control
217    ctl: ReadPureWrite<TimerControl>,
218}
219
220/// Table I2-4 CNTBaseN memory map
221#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
222#[repr(C, align(4))]
223pub struct CntBase {
224    /// 0x000 Counter-timer Physical Count
225    cntpct: ReadPure<u64>,
226    /// 0x008 Counter-timer Virtual Count
227    cntvct: ReadPure<u64>,
228    /// 0x010 Counter-timer Frequency
229    cntfrq: ReadPure<u32>,
230    /// 0x014 Counter-timer EL0 Access Control Register
231    cntel0acr: ReadPureWrite<CntEl0Acr>,
232    /// 0x018 Counter-timer Virtual Offset
233    cntvoff: ReadPure<u64>,
234    /// 0x020-0x02c Physical timer block
235    cntp: TimerRegs,
236    /// 0x030-0x03c Virtual timer block
237    cntv: TimerRegs,
238    reserved: [u32; 996],
239    /// 0xfd0 Counter ID registers
240    counter_id: [ReadPure<u32>; 12],
241}
242
243/// CntEl0Base frame is identical to the CntBase frame, except that CNTVOFF, CNTEL0ACR registers are
244/// never visible and CNTEL0ACR of the corresponding CntBase controls the access of the physical and
245/// virtual timer registers.
246#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
247#[repr(C, align(4))]
248pub struct CntEl0Base {
249    /// 0x000 Counter-timer Physical Count
250    cntpct: ReadPure<u64>,
251    /// 0x008 Counter-timer Virtual Count
252    cntvct: ReadPure<u64>,
253    /// 0x010 Counter-timer Frequency
254    cntfrq: ReadPure<u32>,
255    reserved_014: [u32; 3],
256    /// 0x020-0x02c Physical timer block
257    cntp: TimerRegs,
258    /// 0x030-0x03c Virtual timer block
259    cntv: TimerRegs,
260    reserved: [u32; 996],
261    /// 0xfd0 Counter ID registers
262    counter_id: [ReadPure<u32>; 12],
263}
264
265/// Driver for the CNTControlBase block.
266pub struct GenericTimerControl<'a> {
267    regs: UniqueMmioPointer<'a, CntControlBase>,
268}
269
270impl<'a> GenericTimerControl<'a> {
271    /// Creates new instance.
272    pub fn new(regs: UniqueMmioPointer<'a, CntControlBase>) -> Self {
273        Self { regs }
274    }
275
276    /// Enables or disables the timer.
277    pub fn set_enable(&mut self, enable: bool) {
278        let mut cntcr = field!(self.regs, cntcr).read();
279        cntcr.set(CntCr::EN, enable);
280        field!(self.regs, cntcr).write(cntcr);
281    }
282
283    /// Sets the number of the entry in the Frequency modes table to select.
284    pub fn request_frequency(&mut self, index: usize) {
285        let mut cntcr = field!(self.regs, cntcr).read();
286        cntcr.set_fcreq(index);
287        field!(self.regs, cntcr).write(cntcr);
288    }
289
290    /// Gets currently selected entry index in the Frequency modes table.
291    pub fn frequency_index(&self) -> usize {
292        field_shared!(self.regs, cntsr).read().fcack()
293    }
294
295    /// Gets timer count value.
296    pub fn count(&self) -> u64 {
297        field_shared!(self.regs, cntcv).read()
298    }
299
300    /// Sets timer count value.
301    pub fn set_count(&mut self, count: u64) {
302        field!(self.regs, cntcv).write(count);
303    }
304
305    /// Checks whether scaling is implemented by the timer.
306    pub fn scaling_implemented(&self) -> bool {
307        field_shared!(self.regs, cntid).read().scaling_implemented()
308    }
309
310    /// Gets scale value.
311    pub fn scale(&self) -> u32 {
312        field_shared!(self.regs, cntscr).read()
313    }
314
315    /// Sets scale and enable scaling.
316    pub fn enable_scaling(&mut self, scale: u32) {
317        field!(self.regs, cntscr).write(scale);
318        let cntcr = field!(self.regs, cntcr).read();
319        field!(self.regs, cntcr).write(cntcr | CntCr::SCEN);
320    }
321
322    /// Disables scaling.
323    pub fn disable_scaling(&mut self) {
324        let cntcr = field!(self.regs, cntcr).read();
325        field!(self.regs, cntcr).write(cntcr - CntCr::SCEN);
326        field!(self.regs, cntscr).write(0);
327    }
328
329    /// Indicates the base frequency of the system counter in Hz.
330    pub fn base_frequency(&self) -> u32 {
331        field_shared!(self.regs, cntfid).get(0).unwrap().read()
332    }
333
334    /// Gets frequency mode of the given index in Hz. The availablity of the frequency mode is
335    /// implementation defined.
336    pub fn frequency_mode(&self, index: usize) -> Option<u32> {
337        let frequency = field_shared!(self.regs, cntfid).get(index).unwrap().read();
338
339        if frequency != 0 {
340            Some(frequency)
341        } else {
342            None
343        }
344    }
345
346    /// Sets frequency mode of the given index. The availablity of the frequency mode is
347    /// implementation defined.
348    pub fn set_frequency_mode(&mut self, index: usize, frequency: u32) {
349        field!(self.regs, cntfid)
350            .get(index)
351            .unwrap()
352            .write(frequency)
353    }
354}
355
356/// Driver for the CNTCTLBase block.
357pub struct GenericTimerCtl<'a> {
358    regs: UniqueMmioPointer<'a, CntCtlBase>,
359}
360
361impl<'a> GenericTimerCtl<'a> {
362    /// Creates new instance.
363    pub fn new(regs: UniqueMmioPointer<'a, CntCtlBase>) -> Self {
364        Self { regs }
365    }
366
367    /// Gets counter frequency in Hz.
368    pub fn frequency(&self) -> u32 {
369        field_shared!(self.regs, cntfrq).read()
370    }
371
372    /// Sets counter frequency in Hz.
373    pub fn set_frequency(&mut self, frequency: u32) {
374        field!(self.regs, cntfrq).write(frequency);
375    }
376
377    /// Gets non-secure access state.
378    pub fn non_secure_access(&self, index: usize) -> bool {
379        assert!(index < 8);
380
381        let cntnsar = field_shared!(self.regs, cntnsar).read();
382        cntnsar & (1 << index) != 0
383    }
384
385    /// Provides the highest-level control of whether frames CNTBaseN and CNTEL0BaseN are accessible
386    /// by Non-secure accesses.
387    pub fn set_non_secure_access(&mut self, index: usize, enable: bool) {
388        assert!(index < 8);
389
390        let mut cntnsar = field_shared!(self.regs, cntnsar).read();
391        if enable {
392            cntnsar |= 1 << index;
393        } else {
394            cntnsar &= !(1 << index);
395        }
396        field!(self.regs, cntnsar).write(cntnsar);
397    }
398
399    /// Queries features of the timer.
400    pub fn features(&self, index: usize) -> Features {
401        assert!(index < 8);
402
403        let cnttidr = field_shared!(self.regs, cnttidr).read();
404        Features::from_bits_truncate((cnttidr >> (index * 8)) as u8)
405    }
406
407    /// Gets current top-level access controls for the elements of a timer frame.
408    pub fn access_control(&self, index: usize) -> CntAcr {
409        field_shared!(self.regs, cntacr).get(index).unwrap().read()
410    }
411
412    /// Sets top-level access controls for the elements of a timer frame.
413    pub fn set_access_control(&mut self, index: usize, cntacr: CntAcr) {
414        field!(self.regs, cntacr).get(index).unwrap().write(cntacr);
415    }
416
417    /// Gets the 64-bit virtual offset for frame CNTBase.
418    pub fn virtual_offset(&self, index: usize) -> u64 {
419        field_shared!(self.regs, cntvoff).get(index).unwrap().read()
420    }
421
422    /// Sets the 64-bit virtual offset for frame CNTBase. This is the offset between real time
423    /// and virtual time.
424    pub fn set_virtual_offset(&mut self, index: usize, offset: u64) {
425        field!(self.regs, cntvoff).get(index).unwrap().write(offset);
426    }
427}
428
429/// Driver for the physical or virtual timer instance of the CNTBase block.
430pub struct Timer<'a> {
431    regs: UniqueMmioPointer<'a, TimerRegs>,
432    frequency: u32,
433}
434
435impl<'a> Timer<'a> {
436    /// Creates new instance.
437    pub fn new(regs: UniqueMmioPointer<'a, TimerRegs>, frequency: u32) -> Self {
438        Self { regs, frequency }
439    }
440
441    /// Sets up timer to generate an interrupt after the given duration.
442    ///
443    /// # Safety
444    ///
445    /// The system must be prepared to take an interrupt. The vector table has to be set and the
446    /// interrupt controller must be configured properly.
447    pub unsafe fn generate_interrupt_after(&mut self, duration: Duration) {
448        self.set_deadline(duration);
449        self.set_control(TimerControl::ENABLE);
450    }
451
452    /// Disables the timer and masks the interrupt.
453    pub fn cancel_interrupt(&mut self) {
454        self.set_control(TimerControl::IMASK);
455    }
456
457    /// Blocking waits for a duration.
458    pub fn wait(&mut self, duration: Duration) {
459        self.set_deadline(duration);
460        self.set_control(TimerControl::ENABLE | TimerControl::IMASK);
461
462        while !self.control().contains(TimerControl::ISTATUS) {
463            core::hint::spin_loop();
464        }
465    }
466
467    /// Sets the compare register to trigger after the given duration.
468    fn set_deadline(&mut self, duration: Duration) {
469        let increment = self.frequency as u64 * duration.as_micros() as u64 / 1_000_000;
470
471        let value = field!(self.regs, cval).read();
472        field!(self.regs, cval).write(value + increment);
473    }
474
475    /// Reads CTL register.
476    fn control(&self) -> TimerControl {
477        field_shared!(self.regs, ctl).read()
478    }
479
480    /// Sets CTL register.
481    fn set_control(&mut self, control: TimerControl) {
482        field!(self.regs, ctl).write(control)
483    }
484}
485
486/// Driver for the CNTBase timer block.
487pub struct GenericTimerCnt<'a> {
488    regs: UniqueMmioPointer<'a, CntBase>,
489}
490
491impl<'a> GenericTimerCnt<'a> {
492    /// Creates new instance.
493    pub fn new(regs: UniqueMmioPointer<'a, CntBase>) -> Self {
494        Self { regs }
495    }
496
497    /// Gets physical count.
498    pub fn physical_count(&self) -> u64 {
499        field_shared!(self.regs, cntpct).read()
500    }
501
502    /// Gets virtual count.
503    pub fn virtual_count(&self) -> u64 {
504        field_shared!(self.regs, cntvct).read()
505    }
506
507    /// Gets frequency in Hz.
508    pub fn frequency(&self) -> u32 {
509        field_shared!(self.regs, cntfrq).read()
510    }
511
512    /// Gets second view access rights.
513    pub fn el0_access(&self) -> CntEl0Acr {
514        field_shared!(self.regs, cntel0acr).read()
515    }
516
517    /// Sets second view access rights.
518    pub fn set_el0_access(&mut self, value: CntEl0Acr) {
519        field!(self.regs, cntel0acr).write(value)
520    }
521
522    /// Gets the 64-bit virtual offset for frame CNTBase.
523    pub fn virtual_offset(&self) -> u64 {
524        field_shared!(self.regs, cntvoff).read()
525    }
526
527    /// Gets physical timer.
528    pub fn physical_timer(&mut self) -> Timer<'_> {
529        let frequency = self.frequency();
530        Timer::new(field!(self.regs, cntp), frequency)
531    }
532
533    /// Gets virtual timer.
534    pub fn virtual_timer(&mut self) -> Timer<'_> {
535        let frequency = self.frequency();
536        Timer::new(field!(self.regs, cntv), frequency)
537    }
538}
539
540/// Driver for the CNTEL0Base timer block.
541pub struct GenericTimerCntEl0<'a> {
542    regs: UniqueMmioPointer<'a, CntEl0Base>,
543}
544
545impl<'a> GenericTimerCntEl0<'a> {
546    /// Creates new instance.
547    pub fn new(regs: UniqueMmioPointer<'a, CntEl0Base>) -> Self {
548        Self { regs }
549    }
550
551    /// Gets physical count.
552    pub fn physical_count(&self) -> u64 {
553        field_shared!(self.regs, cntpct).read()
554    }
555
556    /// Gets virtual count.
557    pub fn virtual_count(&self) -> u64 {
558        field_shared!(self.regs, cntvct).read()
559    }
560
561    /// Gets frequency in Hz.
562    pub fn frequency(&self) -> u32 {
563        field_shared!(self.regs, cntfrq).read()
564    }
565
566    /// Gets physical timer.
567    pub fn physical_timer(&mut self) -> Timer<'_> {
568        let frequency = self.frequency();
569        Timer::new(field!(self.regs, cntp), frequency)
570    }
571
572    /// Gets virtual timer.
573    pub fn virtual_timer(&mut self) -> Timer<'_> {
574        let frequency = self.frequency();
575        Timer::new(field!(self.regs, cntv), frequency)
576    }
577}
578
579#[cfg(test)]
580mod tests {
581    use super::*;
582
583    #[test]
584    fn sizes() {
585        assert_eq!(0x1000, core::mem::size_of::<CntControlBase>());
586        assert_eq!(0x1000, core::mem::size_of::<CntReadBase>());
587        assert_eq!(0x1000, core::mem::size_of::<CntCtlBase>());
588        assert_eq!(0x1000, core::mem::size_of::<CntBase>());
589        assert_eq!(0x1000, core::mem::size_of::<CntEl0Base>());
590    }
591}