Skip to main content

arm_generic_timer/
memory_mapped.rs

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