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