Move memory mapped timers into separate module

Move the MMIO register definitions and driver implementations into
separate module.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I293077b2fa84674836b68c1c552c8420b6ae7adf
diff --git a/src/lib.rs b/src/lib.rs
index ca130ff..ed33b83 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,14 +6,12 @@
 #![deny(clippy::undocumented_unsafe_blocks)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
-use core::{hint::spin_loop, time::Duration};
+/// Memory mapped timer driver implementations.
+///
+/// See I5.6 Generic Timer memory-mapped registers overview.
+pub mod memory_mapped;
 
-use bitflags::bitflags;
-use safe_mmio::{
-    UniqueMmioPointer, field, field_shared,
-    fields::{ReadPure, ReadPureWrite},
-};
-use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
+use core::{hint::spin_loop, time::Duration};
 
 /// Interface for accessing common timer registers.
 pub trait TimerInterface {
@@ -59,557 +57,11 @@
     }
 }
 
-/// Counter Control Register
-#[repr(transparent)]
-#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
-pub struct CntCr(u32);
-
-/// Counter Status Register
-#[repr(transparent)]
-#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
-pub struct CntSr(u32);
-
-/// Counter Identification Register.
-#[repr(transparent)]
-#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
-pub struct CntId(u32);
-
-/// Counter-timer Access Control Register.
-#[repr(transparent)]
-#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
-pub struct CntAcr(u32);
-
-/// Timer feature bits, defined at I5.7.16 CNTTIDR, Counter-timer Timer ID Register description.
-#[repr(transparent)]
-#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
-pub struct Features(u8);
-
-/// Counter-timer EL0 Access Control Register.
-#[repr(transparent)]
-#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
-pub struct CntEl0Acr(u32);
-
-/// Common control register of the physical and virtual timers. Defined at I5.7.10 CNTP_CTL,
-/// Counter-timer Physical Timer Control and at CNTV_CTL, Counter-timer Virtual Timer Control.
-#[repr(transparent)]
-#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
-pub struct TimerControl(u32);
-
-bitflags! {
-    impl CntCr: u32 {
-        /// Scaling is enabled. This bit depends on the presence of FEAT_CNTSC.
-        const SCEN = 1 << 2;
-        /// Halt-on-debug.
-        const HDBG = 1 << 1;
-        /// System counter enabled.
-        const EN = 1 << 0;
-    }
-
-    impl CntSr: u32 {
-        /// Halt-on-debug.
-        const HDBG = 1 << 1;
-    }
-
-    impl CntAcr: u32 {
-        /// Read/write access to the EL1 Physical Timer registers
-        const RWPT = 1 << 5;
-        /// Read/write access to the Virtual Timer registers
-        const RWVT = 1 << 4;
-        /// Read-only access to CNTVOFF
-        const RVOFF = 1 << 3;
-        /// Read-only access to CNTFRQ
-        const RFRQ = 1 << 2;
-        /// Read-only access to CNTVCT
-        const RVCT = 1 << 1;
-        /// Read-only access to CNTPCT
-        const RPCT = 1 << 0;
-    }
-
-    impl Features: u8 {
-        /// Frame<n> has a second view, CNTEL0Base<n>.
-        const CNTEL0BASE = 1 << 2;
-        /// Frame<n> has virtual capability. The virtual time and offset registers are implemented.
-        const VIRTUAL = 1 << 1;
-        /// Frame<n> is implemented.
-        const IMPLEMENTED = 1 << 0;
-    }
-
-    impl CntEl0Acr: u32 {
-        /// Second view read access control for CNTP_CVAL, CNTP_TVAL, and CNTP_CTL.
-        const EL0PTEN = 1 << 9;
-        /// Second view read access control for CNTV_CVAL, CNTV_TVAL, and CNTV_CTL.
-        const EL0VTEN = 1 << 8;
-        /// Second view read access control for CNTVCT and CNTFRQ.
-        const EL0VCTEN = 1 << 1;
-        /// Second view read access control for CNTPCT and CNTFRQ.
-        const EL0PCTEN = 1 << 0;
-    }
-
-    impl TimerControl: u32 {
-        /// Timer condition is met.
-        const ISTATUS = 1 << 2;
-        /// Timer interrupt is masked.
-        const IMASK = 1 << 1;
-        /// Timer enabled.
-        const ENABLE = 1 << 0;
-    }
-}
-
-impl CntCr {
-    const FCREQ_MASK: u32 = 0x0000_03ff;
-    const FCREQ_SHIFT: u32 = 8;
-
-    /// Write FCREQ field of the register.
-    pub fn set_fcreq(&mut self, index: usize) {
-        let mut value = self.0 & !(Self::FCREQ_MASK << Self::FCREQ_SHIFT);
-        value |= ((index as u32) & Self::FCREQ_MASK) << Self::FCREQ_SHIFT;
-        self.0 = value;
-    }
-}
-
-impl CntSr {
-    const FCACK_MASK: u32 = 0x0000_03ff;
-    const FCACK_SHIFT: u32 = 8;
-
-    /// Read FCACK field of the register.
-    pub fn fcack(&self) -> usize {
-        ((self.0 >> Self::FCACK_SHIFT) & Self::FCACK_MASK) as usize
-    }
-}
-
-impl CntId {
-    const CNTSC_MASK: u32 = 0b1111;
-    const CNTSC_IMPLEMENTED: u32 = 0b0001;
-
-    /// Indicates whether Counter Scaling is implemented.
-    pub fn scaling_implemented(&self) -> bool {
-        self.0 & Self::CNTSC_MASK == Self::CNTSC_IMPLEMENTED
-    }
-}
-
-/// Table I2-1 CNTControlBase memory map
-#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
-#[repr(C, align(4))]
-pub struct CntControlBase {
-    /// 0x000 Counter Control Register
-    cntcr: ReadPureWrite<CntCr>,
-    /// 0x004 Counter Status Register
-    cntsr: ReadPure<CntSr>,
-    /// 0x008 Counter Count Value register
-    cntcv: ReadPureWrite<u64>,
-    /// 0x010 Counter Counter Scale register
-    cntscr: ReadPureWrite<u32>,
-    reserved_14: [u32; 2],
-    /// 0x01c Counter ID register
-    cntid: ReadPure<CntId>,
-    /// 0x020 Counter Frequency IDs
-    cntfid: [ReadPureWrite<u32>; 40],
-    /// 0x0c0 Implementation defined
-    impdef_0c0: [u32; 16],
-    reserved_100: [u32; 948],
-    /// 0xfd0 Counter ID registers
-    counter_id: [ReadPure<u32>; 12],
-}
-
-/// Table I2-2 CNTReadBase memory map
-#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
-#[repr(C, align(4))]
-pub struct CntReadBase {
-    /// 0x000 Counter Count Value register
-    cntcv: ReadPure<u64>,
-    reserved_8: [u32; 1010],
-    /// 0xfd0 Counter ID registers
-    counter_id: [ReadPure<u32>; 12],
-}
-
-/// Table I2-3 CNTCTLBase memory map
-#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
-#[repr(C, align(4))]
-pub struct CntCtlBase {
-    /// 0x000 Counter-timer Frequency
-    cntfrq: ReadPureWrite<u32>,
-    /// 0x004 Counter-timer Non-secure Access Register
-    cntnsar: ReadPureWrite<u32>,
-    /// 0x008 Counter-timer Timer ID Register
-    cnttidr: ReadPure<u32>,
-    reserved_00c: [u32; 13],
-    /// 0x040 Counter-timer Access Control Registers
-    cntacr: [ReadPureWrite<CntAcr>; 8],
-    reserved_060: [u32; 8],
-    /// 0x080 Counter-timer Virtual Offsets
-    cntvoff: [ReadPureWrite<u64>; 8],
-    reserved_0c0: [u32; 16],
-    /// 0x100 Implementation defined
-    impdef_100: [u32; 448],
-    reserved_800: [u32; 496],
-    impdef_fc0: [u32; 4],
-    /// 0xfd0 Counter ID registers
-    counter_id: [ReadPure<u32>; 12],
-}
-
-/// Repeated subset of register that describe a physical or virtual timer in the CntBase or
-/// CntEl0Base blocks.
-#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
-#[repr(C, align(4))]
-pub struct TimerRegs {
-    /// 0x000 Counter-timer Timer CompareValue
-    cval: ReadPureWrite<u64>,
-    /// 0x008 Counter-timer Timer TimerValue
-    tval: ReadPureWrite<u32>,
-    /// 0x00c Counter-timer Timer Control
-    ctl: ReadPureWrite<TimerControl>,
-}
-
-/// Table I2-4 CNTBaseN memory map
-#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
-#[repr(C, align(4))]
-pub struct CntBase {
-    /// 0x000 Counter-timer Physical Count
-    cntpct: ReadPure<u64>,
-    /// 0x008 Counter-timer Virtual Count
-    cntvct: ReadPure<u64>,
-    /// 0x010 Counter-timer Frequency
-    cntfrq: ReadPure<u32>,
-    /// 0x014 Counter-timer EL0 Access Control Register
-    cntel0acr: ReadPureWrite<CntEl0Acr>,
-    /// 0x018 Counter-timer Virtual Offset
-    cntvoff: ReadPure<u64>,
-    /// 0x020-0x02c Physical timer block
-    cntp: TimerRegs,
-    /// 0x030-0x03c Virtual timer block
-    cntv: TimerRegs,
-    reserved: [u32; 996],
-    /// 0xfd0 Counter ID registers
-    counter_id: [ReadPure<u32>; 12],
-}
-
-/// CntEl0Base frame is identical to the CntBase frame, except that CNTVOFF, CNTEL0ACR registers are
-/// never visible and CNTEL0ACR of the corresponding CntBase controls the access of the physical and
-/// virtual timer registers.
-#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
-#[repr(C, align(4))]
-pub struct CntEl0Base {
-    /// 0x000 Counter-timer Physical Count
-    cntpct: ReadPure<u64>,
-    /// 0x008 Counter-timer Virtual Count
-    cntvct: ReadPure<u64>,
-    /// 0x010 Counter-timer Frequency
-    cntfrq: ReadPure<u32>,
-    reserved_014: [u32; 3],
-    /// 0x020-0x02c Physical timer block
-    cntp: TimerRegs,
-    /// 0x030-0x03c Virtual timer block
-    cntv: TimerRegs,
-    reserved: [u32; 996],
-    /// 0xfd0 Counter ID registers
-    counter_id: [ReadPure<u32>; 12],
-}
-
-/// Driver for the CNTControlBase block.
-pub struct GenericTimerControl<'a> {
-    regs: UniqueMmioPointer<'a, CntControlBase>,
-}
-
-impl<'a> GenericTimerControl<'a> {
-    /// Creates new instance.
-    pub fn new(regs: UniqueMmioPointer<'a, CntControlBase>) -> Self {
-        Self { regs }
-    }
-
-    /// Enables or disables the timer.
-    pub fn set_enable(&mut self, enable: bool) {
-        let mut cntcr = field!(self.regs, cntcr).read();
-        cntcr.set(CntCr::EN, enable);
-        field!(self.regs, cntcr).write(cntcr);
-    }
-
-    /// Sets the number of the entry in the Frequency modes table to select.
-    pub fn request_frequency(&mut self, index: usize) {
-        let mut cntcr = field!(self.regs, cntcr).read();
-        cntcr.set_fcreq(index);
-        field!(self.regs, cntcr).write(cntcr);
-    }
-
-    /// Gets currently selected entry index in the Frequency modes table.
-    pub fn frequency_index(&self) -> usize {
-        field_shared!(self.regs, cntsr).read().fcack()
-    }
-
-    /// Gets timer count value.
-    pub fn count(&self) -> u64 {
-        field_shared!(self.regs, cntcv).read()
-    }
-
-    /// Sets timer count value.
-    pub fn set_count(&mut self, count: u64) {
-        field!(self.regs, cntcv).write(count);
-    }
-
-    /// Checks whether scaling is implemented by the timer.
-    pub fn scaling_implemented(&self) -> bool {
-        field_shared!(self.regs, cntid).read().scaling_implemented()
-    }
-
-    /// Gets scale value.
-    pub fn scale(&self) -> u32 {
-        field_shared!(self.regs, cntscr).read()
-    }
-
-    /// Sets scale and enable scaling.
-    pub fn enable_scaling(&mut self, scale: u32) {
-        field!(self.regs, cntscr).write(scale);
-        let cntcr = field!(self.regs, cntcr).read();
-        field!(self.regs, cntcr).write(cntcr | CntCr::SCEN);
-    }
-
-    /// Disables scaling.
-    pub fn disable_scaling(&mut self) {
-        let cntcr = field!(self.regs, cntcr).read();
-        field!(self.regs, cntcr).write(cntcr - CntCr::SCEN);
-        field!(self.regs, cntscr).write(0);
-    }
-
-    /// Indicates the base frequency of the system counter in Hz.
-    pub fn base_frequency(&self) -> u32 {
-        field_shared!(self.regs, cntfid).get(0).unwrap().read()
-    }
-
-    /// Gets frequency mode of the given index in Hz. The availablity of the frequency mode is
-    /// implementation defined.
-    pub fn frequency_mode(&self, index: usize) -> Option<u32> {
-        let frequency = field_shared!(self.regs, cntfid).get(index).unwrap().read();
-
-        if frequency != 0 {
-            Some(frequency)
-        } else {
-            None
-        }
-    }
-
-    /// Sets frequency mode of the given index. The availablity of the frequency mode is
-    /// implementation defined.
-    pub fn set_frequency_mode(&mut self, index: usize, frequency: u32) {
-        field!(self.regs, cntfid)
-            .get(index)
-            .unwrap()
-            .write(frequency)
-    }
-}
-
-/// Driver for the CNTCTLBase block.
-pub struct GenericTimerCtl<'a> {
-    regs: UniqueMmioPointer<'a, CntCtlBase>,
-}
-
-impl<'a> GenericTimerCtl<'a> {
-    /// Creates new instance.
-    pub fn new(regs: UniqueMmioPointer<'a, CntCtlBase>) -> Self {
-        Self { regs }
-    }
-
-    /// Gets counter frequency in Hz.
-    pub fn frequency(&self) -> u32 {
-        field_shared!(self.regs, cntfrq).read()
-    }
-
-    /// Sets counter frequency in Hz.
-    pub fn set_frequency(&mut self, frequency: u32) {
-        field!(self.regs, cntfrq).write(frequency);
-    }
-
-    /// Gets non-secure access state.
-    pub fn non_secure_access(&self, index: usize) -> bool {
-        assert!(index < 8);
-
-        let cntnsar = field_shared!(self.regs, cntnsar).read();
-        cntnsar & (1 << index) != 0
-    }
-
-    /// Provides the highest-level control of whether frames CNTBaseN and CNTEL0BaseN are accessible
-    /// by Non-secure accesses.
-    pub fn set_non_secure_access(&mut self, index: usize, enable: bool) {
-        assert!(index < 8);
-
-        let mut cntnsar = field_shared!(self.regs, cntnsar).read();
-        if enable {
-            cntnsar |= 1 << index;
-        } else {
-            cntnsar &= !(1 << index);
-        }
-        field!(self.regs, cntnsar).write(cntnsar);
-    }
-
-    /// Queries features of the timer.
-    pub fn features(&self, index: usize) -> Features {
-        assert!(index < 8);
-
-        let cnttidr = field_shared!(self.regs, cnttidr).read();
-        Features::from_bits_truncate((cnttidr >> (index * 8)) as u8)
-    }
-
-    /// Gets current top-level access controls for the elements of a timer frame.
-    pub fn access_control(&self, index: usize) -> CntAcr {
-        field_shared!(self.regs, cntacr).get(index).unwrap().read()
-    }
-
-    /// Sets top-level access controls for the elements of a timer frame.
-    pub fn set_access_control(&mut self, index: usize, cntacr: CntAcr) {
-        field!(self.regs, cntacr).get(index).unwrap().write(cntacr);
-    }
-
-    /// Gets the 64-bit virtual offset for frame CNTBase.
-    pub fn virtual_offset(&self, index: usize) -> u64 {
-        field_shared!(self.regs, cntvoff).get(index).unwrap().read()
-    }
-
-    /// Sets the 64-bit virtual offset for frame CNTBase. This is the offset between real time
-    /// and virtual time.
-    pub fn set_virtual_offset(&mut self, index: usize, offset: u64) {
-        field!(self.regs, cntvoff).get(index).unwrap().write(offset);
-    }
-}
-
-/// `TimerInterface` implementation of the MMIO based physical or virtual timer instance of the
-/// CNTBase block.
-pub struct MmioTimer<'a> {
-    regs: UniqueMmioPointer<'a, TimerRegs>,
-    frequency: u32,
-}
-
-impl<'a> TimerInterface for MmioTimer<'a> {
-    fn enable(&mut self) {
-        let control = field_shared!(self.regs, ctl).read();
-        field!(self.regs, ctl).write(control | TimerControl::ENABLE);
-    }
-
-    fn timer_value(&self) -> u32 {
-        field_shared!(self.regs, tval).read()
-    }
-
-    fn frequency(&self) -> u32 {
-        self.frequency
-    }
-}
-
-/// Driver for the CNTBase timer block.
-pub struct GenericTimerCnt<'a> {
-    regs: UniqueMmioPointer<'a, CntBase>,
-}
-
-impl<'a> GenericTimerCnt<'a> {
-    /// Creates new instance.
-    pub fn new(regs: UniqueMmioPointer<'a, CntBase>) -> Self {
-        Self { regs }
-    }
-
-    /// Gets physical count.
-    pub fn physical_count(&self) -> u64 {
-        field_shared!(self.regs, cntpct).read()
-    }
-
-    /// Gets virtual count.
-    pub fn virtual_count(&self) -> u64 {
-        field_shared!(self.regs, cntvct).read()
-    }
-
-    /// Gets frequency in Hz.
-    pub fn frequency(&self) -> u32 {
-        field_shared!(self.regs, cntfrq).read()
-    }
-
-    /// Gets second view access rights.
-    pub fn el0_access(&self) -> CntEl0Acr {
-        field_shared!(self.regs, cntel0acr).read()
-    }
-
-    /// Sets second view access rights.
-    pub fn set_el0_access(&mut self, value: CntEl0Acr) {
-        field!(self.regs, cntel0acr).write(value)
-    }
-
-    /// Gets the 64-bit virtual offset for frame CNTBase.
-    pub fn virtual_offset(&self) -> u64 {
-        field_shared!(self.regs, cntvoff).read()
-    }
-
-    /// Gets physical timer.
-    pub fn physical_timer(&mut self) -> Timer<MmioTimer<'_>> {
-        let frequency = self.frequency();
-        Timer::new(MmioTimer {
-            regs: field!(self.regs, cntp),
-            frequency,
-        })
-    }
-
-    /// Gets virtual timer.
-    pub fn virtual_timer(&mut self) -> Timer<MmioTimer<'_>> {
-        let frequency = self.frequency();
-        Timer::new(MmioTimer {
-            regs: field!(self.regs, cntv),
-            frequency,
-        })
-    }
-}
-
-/// Driver for the CNTEL0Base timer block.
-pub struct GenericTimerCntEl0<'a> {
-    regs: UniqueMmioPointer<'a, CntEl0Base>,
-}
-
-impl<'a> GenericTimerCntEl0<'a> {
-    /// Creates new instance.
-    pub fn new(regs: UniqueMmioPointer<'a, CntEl0Base>) -> Self {
-        Self { regs }
-    }
-
-    /// Gets physical count.
-    pub fn physical_count(&self) -> u64 {
-        field_shared!(self.regs, cntpct).read()
-    }
-
-    /// Gets virtual count.
-    pub fn virtual_count(&self) -> u64 {
-        field_shared!(self.regs, cntvct).read()
-    }
-
-    /// Gets frequency in Hz.
-    pub fn frequency(&self) -> u32 {
-        field_shared!(self.regs, cntfrq).read()
-    }
-
-    /// Gets physical timer.
-    pub fn physical_timer(&mut self) -> Timer<MmioTimer<'_>> {
-        let frequency = self.frequency();
-        Timer::new(MmioTimer {
-            regs: field!(self.regs, cntp),
-            frequency,
-        })
-    }
-
-    /// Gets virtual timer.
-    pub fn virtual_timer(&mut self) -> Timer<MmioTimer<'_>> {
-        let frequency = self.frequency();
-        Timer::new(MmioTimer {
-            regs: field!(self.regs, cntv),
-            frequency,
-        })
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
     use core::cell::Cell;
 
-    #[test]
-    fn sizes() {
-        assert_eq!(0x1000, core::mem::size_of::<CntControlBase>());
-        assert_eq!(0x1000, core::mem::size_of::<CntReadBase>());
-        assert_eq!(0x1000, core::mem::size_of::<CntCtlBase>());
-        assert_eq!(0x1000, core::mem::size_of::<CntBase>());
-        assert_eq!(0x1000, core::mem::size_of::<CntEl0Base>());
-    }
-
     struct MockTimer<'a> {
         frequency: u32,
         timer_values: &'a [u32],
diff --git a/src/memory_mapped.rs b/src/memory_mapped.rs
new file mode 100644
index 0000000..31f5abf
--- /dev/null
+++ b/src/memory_mapped.rs
@@ -0,0 +1,561 @@
+// SPDX-FileCopyrightText: Copyright The arm-generic-timer Contributors.
+// SPDX-License-Identifier: MIT OR Apache-2.0
+
+use crate::{Timer, TimerInterface};
+use bitflags::bitflags;
+use safe_mmio::{
+    UniqueMmioPointer, field, field_shared,
+    fields::{ReadPure, ReadPureWrite},
+};
+use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
+
+/// Counter Control Register
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+pub struct CntCr(u32);
+
+/// Counter Status Register
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+pub struct CntSr(u32);
+
+/// Counter Identification Register.
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+pub struct CntId(u32);
+
+/// Counter-timer Access Control Register.
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+pub struct CntAcr(u32);
+
+/// Timer feature bits, defined at I5.7.16 CNTTIDR, Counter-timer Timer ID Register description.
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+pub struct Features(u8);
+
+/// Counter-timer EL0 Access Control Register.
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+pub struct CntEl0Acr(u32);
+
+/// Common control register of the physical and virtual timers. Defined at I5.7.10 CNTP_CTL,
+/// Counter-timer Physical Timer Control and at CNTV_CTL, Counter-timer Virtual Timer Control.
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+pub struct TimerControl(u32);
+
+bitflags! {
+    impl CntCr: u32 {
+        /// Scaling is enabled. This bit depends on the presence of FEAT_CNTSC.
+        const SCEN = 1 << 2;
+        /// Halt-on-debug.
+        const HDBG = 1 << 1;
+        /// System counter enabled.
+        const EN = 1 << 0;
+    }
+
+    impl CntSr: u32 {
+        /// Halt-on-debug.
+        const HDBG = 1 << 1;
+    }
+
+    impl CntAcr: u32 {
+        /// Read/write access to the EL1 Physical Timer registers
+        const RWPT = 1 << 5;
+        /// Read/write access to the Virtual Timer registers
+        const RWVT = 1 << 4;
+        /// Read-only access to CNTVOFF
+        const RVOFF = 1 << 3;
+        /// Read-only access to CNTFRQ
+        const RFRQ = 1 << 2;
+        /// Read-only access to CNTVCT
+        const RVCT = 1 << 1;
+        /// Read-only access to CNTPCT
+        const RPCT = 1 << 0;
+    }
+
+    impl Features: u8 {
+        /// Frame<n> has a second view, CNTEL0Base<n>.
+        const CNTEL0BASE = 1 << 2;
+        /// Frame<n> has virtual capability. The virtual time and offset registers are implemented.
+        const VIRTUAL = 1 << 1;
+        /// Frame<n> is implemented.
+        const IMPLEMENTED = 1 << 0;
+    }
+
+    impl CntEl0Acr: u32 {
+        /// Second view read access control for CNTP_CVAL, CNTP_TVAL, and CNTP_CTL.
+        const EL0PTEN = 1 << 9;
+        /// Second view read access control for CNTV_CVAL, CNTV_TVAL, and CNTV_CTL.
+        const EL0VTEN = 1 << 8;
+        /// Second view read access control for CNTVCT and CNTFRQ.
+        const EL0VCTEN = 1 << 1;
+        /// Second view read access control for CNTPCT and CNTFRQ.
+        const EL0PCTEN = 1 << 0;
+    }
+
+    impl TimerControl: u32 {
+        /// Timer condition is met.
+        const ISTATUS = 1 << 2;
+        /// Timer interrupt is masked.
+        const IMASK = 1 << 1;
+        /// Timer enabled.
+        const ENABLE = 1 << 0;
+    }
+}
+
+impl CntCr {
+    const FCREQ_MASK: u32 = 0x0000_03ff;
+    const FCREQ_SHIFT: u32 = 8;
+
+    /// Write FCREQ field of the register.
+    pub fn set_fcreq(&mut self, index: usize) {
+        let mut value = self.0 & !(Self::FCREQ_MASK << Self::FCREQ_SHIFT);
+        value |= ((index as u32) & Self::FCREQ_MASK) << Self::FCREQ_SHIFT;
+        self.0 = value;
+    }
+}
+
+impl CntSr {
+    const FCACK_MASK: u32 = 0x0000_03ff;
+    const FCACK_SHIFT: u32 = 8;
+
+    /// Read FCACK field of the register.
+    pub fn fcack(&self) -> usize {
+        ((self.0 >> Self::FCACK_SHIFT) & Self::FCACK_MASK) as usize
+    }
+}
+
+impl CntId {
+    const CNTSC_MASK: u32 = 0b1111;
+    const CNTSC_IMPLEMENTED: u32 = 0b0001;
+
+    /// Indicates whether Counter Scaling is implemented.
+    pub fn scaling_implemented(&self) -> bool {
+        self.0 & Self::CNTSC_MASK == Self::CNTSC_IMPLEMENTED
+    }
+}
+
+/// Table I2-1 CNTControlBase memory map
+#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+#[repr(C, align(4))]
+pub struct CntControlBase {
+    /// 0x000 Counter Control Register
+    cntcr: ReadPureWrite<CntCr>,
+    /// 0x004 Counter Status Register
+    cntsr: ReadPure<CntSr>,
+    /// 0x008 Counter Count Value register
+    cntcv: ReadPureWrite<u64>,
+    /// 0x010 Counter Counter Scale register
+    cntscr: ReadPureWrite<u32>,
+    reserved_14: [u32; 2],
+    /// 0x01c Counter ID register
+    cntid: ReadPure<CntId>,
+    /// 0x020 Counter Frequency IDs
+    cntfid: [ReadPureWrite<u32>; 40],
+    /// 0x0c0 Implementation defined
+    impdef_0c0: [u32; 16],
+    reserved_100: [u32; 948],
+    /// 0xfd0 Counter ID registers
+    counter_id: [ReadPure<u32>; 12],
+}
+
+/// Table I2-2 CNTReadBase memory map
+#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+#[repr(C, align(4))]
+pub struct CntReadBase {
+    /// 0x000 Counter Count Value register
+    cntcv: ReadPure<u64>,
+    reserved_8: [u32; 1010],
+    /// 0xfd0 Counter ID registers
+    counter_id: [ReadPure<u32>; 12],
+}
+
+/// Table I2-3 CNTCTLBase memory map
+#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+#[repr(C, align(4))]
+pub struct CntCtlBase {
+    /// 0x000 Counter-timer Frequency
+    cntfrq: ReadPureWrite<u32>,
+    /// 0x004 Counter-timer Non-secure Access Register
+    cntnsar: ReadPureWrite<u32>,
+    /// 0x008 Counter-timer Timer ID Register
+    cnttidr: ReadPure<u32>,
+    reserved_00c: [u32; 13],
+    /// 0x040 Counter-timer Access Control Registers
+    cntacr: [ReadPureWrite<CntAcr>; 8],
+    reserved_060: [u32; 8],
+    /// 0x080 Counter-timer Virtual Offsets
+    cntvoff: [ReadPureWrite<u64>; 8],
+    reserved_0c0: [u32; 16],
+    /// 0x100 Implementation defined
+    impdef_100: [u32; 448],
+    reserved_800: [u32; 496],
+    impdef_fc0: [u32; 4],
+    /// 0xfd0 Counter ID registers
+    counter_id: [ReadPure<u32>; 12],
+}
+
+/// Repeated subset of register that describe a physical or virtual timer in the CntBase or
+/// CntEl0Base blocks.
+#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+#[repr(C, align(4))]
+pub struct TimerRegs {
+    /// 0x000 Counter-timer Timer CompareValue
+    cval: ReadPureWrite<u64>,
+    /// 0x008 Counter-timer Timer TimerValue
+    tval: ReadPureWrite<u32>,
+    /// 0x00c Counter-timer Timer Control
+    ctl: ReadPureWrite<TimerControl>,
+}
+
+/// Table I2-4 CNTBaseN memory map
+#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+#[repr(C, align(4))]
+pub struct CntBase {
+    /// 0x000 Counter-timer Physical Count
+    cntpct: ReadPure<u64>,
+    /// 0x008 Counter-timer Virtual Count
+    cntvct: ReadPure<u64>,
+    /// 0x010 Counter-timer Frequency
+    cntfrq: ReadPure<u32>,
+    /// 0x014 Counter-timer EL0 Access Control Register
+    cntel0acr: ReadPureWrite<CntEl0Acr>,
+    /// 0x018 Counter-timer Virtual Offset
+    cntvoff: ReadPure<u64>,
+    /// 0x020-0x02c Physical timer block
+    cntp: TimerRegs,
+    /// 0x030-0x03c Virtual timer block
+    cntv: TimerRegs,
+    reserved: [u32; 996],
+    /// 0xfd0 Counter ID registers
+    counter_id: [ReadPure<u32>; 12],
+}
+
+/// CntEl0Base frame is identical to the CntBase frame, except that CNTVOFF, CNTEL0ACR registers are
+/// never visible and CNTEL0ACR of the corresponding CntBase controls the access of the physical and
+/// virtual timer registers.
+#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+#[repr(C, align(4))]
+pub struct CntEl0Base {
+    /// 0x000 Counter-timer Physical Count
+    cntpct: ReadPure<u64>,
+    /// 0x008 Counter-timer Virtual Count
+    cntvct: ReadPure<u64>,
+    /// 0x010 Counter-timer Frequency
+    cntfrq: ReadPure<u32>,
+    reserved_014: [u32; 3],
+    /// 0x020-0x02c Physical timer block
+    cntp: TimerRegs,
+    /// 0x030-0x03c Virtual timer block
+    cntv: TimerRegs,
+    reserved: [u32; 996],
+    /// 0xfd0 Counter ID registers
+    counter_id: [ReadPure<u32>; 12],
+}
+
+/// Driver for the CNTControlBase block.
+pub struct GenericTimerControl<'a> {
+    regs: UniqueMmioPointer<'a, CntControlBase>,
+}
+
+impl<'a> GenericTimerControl<'a> {
+    /// Creates new instance.
+    pub fn new(regs: UniqueMmioPointer<'a, CntControlBase>) -> Self {
+        Self { regs }
+    }
+
+    /// Enables or disables the timer.
+    pub fn set_enable(&mut self, enable: bool) {
+        let mut cntcr = field!(self.regs, cntcr).read();
+        cntcr.set(CntCr::EN, enable);
+        field!(self.regs, cntcr).write(cntcr);
+    }
+
+    /// Sets the number of the entry in the Frequency modes table to select.
+    pub fn request_frequency(&mut self, index: usize) {
+        let mut cntcr = field!(self.regs, cntcr).read();
+        cntcr.set_fcreq(index);
+        field!(self.regs, cntcr).write(cntcr);
+    }
+
+    /// Gets currently selected entry index in the Frequency modes table.
+    pub fn frequency_index(&self) -> usize {
+        field_shared!(self.regs, cntsr).read().fcack()
+    }
+
+    /// Gets timer count value.
+    pub fn count(&self) -> u64 {
+        field_shared!(self.regs, cntcv).read()
+    }
+
+    /// Sets timer count value.
+    pub fn set_count(&mut self, count: u64) {
+        field!(self.regs, cntcv).write(count);
+    }
+
+    /// Checks whether scaling is implemented by the timer.
+    pub fn scaling_implemented(&self) -> bool {
+        field_shared!(self.regs, cntid).read().scaling_implemented()
+    }
+
+    /// Gets scale value.
+    pub fn scale(&self) -> u32 {
+        field_shared!(self.regs, cntscr).read()
+    }
+
+    /// Sets scale and enable scaling.
+    pub fn enable_scaling(&mut self, scale: u32) {
+        field!(self.regs, cntscr).write(scale);
+        let cntcr = field!(self.regs, cntcr).read();
+        field!(self.regs, cntcr).write(cntcr | CntCr::SCEN);
+    }
+
+    /// Disables scaling.
+    pub fn disable_scaling(&mut self) {
+        let cntcr = field!(self.regs, cntcr).read();
+        field!(self.regs, cntcr).write(cntcr - CntCr::SCEN);
+        field!(self.regs, cntscr).write(0);
+    }
+
+    /// Indicates the base frequency of the system counter in Hz.
+    pub fn base_frequency(&self) -> u32 {
+        field_shared!(self.regs, cntfid).get(0).unwrap().read()
+    }
+
+    /// Gets frequency mode of the given index in Hz. The availablity of the frequency mode is
+    /// implementation defined.
+    pub fn frequency_mode(&self, index: usize) -> Option<u32> {
+        let frequency = field_shared!(self.regs, cntfid).get(index).unwrap().read();
+
+        if frequency != 0 {
+            Some(frequency)
+        } else {
+            None
+        }
+    }
+
+    /// Sets frequency mode of the given index. The availablity of the frequency mode is
+    /// implementation defined.
+    pub fn set_frequency_mode(&mut self, index: usize, frequency: u32) {
+        field!(self.regs, cntfid)
+            .get(index)
+            .unwrap()
+            .write(frequency)
+    }
+}
+
+/// Driver for the CNTCTLBase block.
+pub struct GenericTimerCtl<'a> {
+    regs: UniqueMmioPointer<'a, CntCtlBase>,
+}
+
+impl<'a> GenericTimerCtl<'a> {
+    /// Creates new instance.
+    pub fn new(regs: UniqueMmioPointer<'a, CntCtlBase>) -> Self {
+        Self { regs }
+    }
+
+    /// Gets counter frequency in Hz.
+    pub fn frequency(&self) -> u32 {
+        field_shared!(self.regs, cntfrq).read()
+    }
+
+    /// Sets counter frequency in Hz.
+    pub fn set_frequency(&mut self, frequency: u32) {
+        field!(self.regs, cntfrq).write(frequency);
+    }
+
+    /// Gets non-secure access state.
+    pub fn non_secure_access(&self, index: usize) -> bool {
+        assert!(index < 8);
+
+        let cntnsar = field_shared!(self.regs, cntnsar).read();
+        cntnsar & (1 << index) != 0
+    }
+
+    /// Provides the highest-level control of whether frames CNTBaseN and CNTEL0BaseN are accessible
+    /// by Non-secure accesses.
+    pub fn set_non_secure_access(&mut self, index: usize, enable: bool) {
+        assert!(index < 8);
+
+        let mut cntnsar = field_shared!(self.regs, cntnsar).read();
+        if enable {
+            cntnsar |= 1 << index;
+        } else {
+            cntnsar &= !(1 << index);
+        }
+        field!(self.regs, cntnsar).write(cntnsar);
+    }
+
+    /// Queries features of the timer.
+    pub fn features(&self, index: usize) -> Features {
+        assert!(index < 8);
+
+        let cnttidr = field_shared!(self.regs, cnttidr).read();
+        Features::from_bits_truncate((cnttidr >> (index * 8)) as u8)
+    }
+
+    /// Gets current top-level access controls for the elements of a timer frame.
+    pub fn access_control(&self, index: usize) -> CntAcr {
+        field_shared!(self.regs, cntacr).get(index).unwrap().read()
+    }
+
+    /// Sets top-level access controls for the elements of a timer frame.
+    pub fn set_access_control(&mut self, index: usize, cntacr: CntAcr) {
+        field!(self.regs, cntacr).get(index).unwrap().write(cntacr);
+    }
+
+    /// Gets the 64-bit virtual offset for frame CNTBase.
+    pub fn virtual_offset(&self, index: usize) -> u64 {
+        field_shared!(self.regs, cntvoff).get(index).unwrap().read()
+    }
+
+    /// Sets the 64-bit virtual offset for frame CNTBase. This is the offset between real time
+    /// and virtual time.
+    pub fn set_virtual_offset(&mut self, index: usize, offset: u64) {
+        field!(self.regs, cntvoff).get(index).unwrap().write(offset);
+    }
+}
+
+/// `TimerInterface` implementation of the MMIO based physical or virtual timer instance of the
+/// CNTBase block.
+pub struct MmioTimer<'a> {
+    regs: UniqueMmioPointer<'a, TimerRegs>,
+    frequency: u32,
+}
+
+impl<'a> TimerInterface for MmioTimer<'a> {
+    fn enable(&mut self) {
+        let control = field_shared!(self.regs, ctl).read();
+        field!(self.regs, ctl).write(control | TimerControl::ENABLE);
+    }
+
+    fn timer_value(&self) -> u32 {
+        field_shared!(self.regs, tval).read()
+    }
+
+    fn frequency(&self) -> u32 {
+        self.frequency
+    }
+}
+
+/// Driver for the CNTBase timer block.
+pub struct GenericTimerCnt<'a> {
+    regs: UniqueMmioPointer<'a, CntBase>,
+}
+
+impl<'a> GenericTimerCnt<'a> {
+    /// Creates new instance.
+    pub fn new(regs: UniqueMmioPointer<'a, CntBase>) -> Self {
+        Self { regs }
+    }
+
+    /// Gets physical count.
+    pub fn physical_count(&self) -> u64 {
+        field_shared!(self.regs, cntpct).read()
+    }
+
+    /// Gets virtual count.
+    pub fn virtual_count(&self) -> u64 {
+        field_shared!(self.regs, cntvct).read()
+    }
+
+    /// Gets frequency in Hz.
+    pub fn frequency(&self) -> u32 {
+        field_shared!(self.regs, cntfrq).read()
+    }
+
+    /// Gets second view access rights.
+    pub fn el0_access(&self) -> CntEl0Acr {
+        field_shared!(self.regs, cntel0acr).read()
+    }
+
+    /// Sets second view access rights.
+    pub fn set_el0_access(&mut self, value: CntEl0Acr) {
+        field!(self.regs, cntel0acr).write(value)
+    }
+
+    /// Gets the 64-bit virtual offset for frame CNTBase.
+    pub fn virtual_offset(&self) -> u64 {
+        field_shared!(self.regs, cntvoff).read()
+    }
+
+    /// Gets physical timer.
+    pub fn physical_timer(&mut self) -> Timer<MmioTimer<'_>> {
+        let frequency = self.frequency();
+        Timer::new(MmioTimer {
+            regs: field!(self.regs, cntp),
+            frequency,
+        })
+    }
+
+    /// Gets virtual timer.
+    pub fn virtual_timer(&mut self) -> Timer<MmioTimer<'_>> {
+        let frequency = self.frequency();
+        Timer::new(MmioTimer {
+            regs: field!(self.regs, cntv),
+            frequency,
+        })
+    }
+}
+
+/// Driver for the CNTEL0Base timer block.
+pub struct GenericTimerCntEl0<'a> {
+    regs: UniqueMmioPointer<'a, CntEl0Base>,
+}
+
+impl<'a> GenericTimerCntEl0<'a> {
+    /// Creates new instance.
+    pub fn new(regs: UniqueMmioPointer<'a, CntEl0Base>) -> Self {
+        Self { regs }
+    }
+
+    /// Gets physical count.
+    pub fn physical_count(&self) -> u64 {
+        field_shared!(self.regs, cntpct).read()
+    }
+
+    /// Gets virtual count.
+    pub fn virtual_count(&self) -> u64 {
+        field_shared!(self.regs, cntvct).read()
+    }
+
+    /// Gets frequency in Hz.
+    pub fn frequency(&self) -> u32 {
+        field_shared!(self.regs, cntfrq).read()
+    }
+
+    /// Gets physical timer.
+    pub fn physical_timer(&mut self) -> Timer<MmioTimer<'_>> {
+        let frequency = self.frequency();
+        Timer::new(MmioTimer {
+            regs: field!(self.regs, cntp),
+            frequency,
+        })
+    }
+
+    /// Gets virtual timer.
+    pub fn virtual_timer(&mut self) -> Timer<MmioTimer<'_>> {
+        let frequency = self.frequency();
+        Timer::new(MmioTimer {
+            regs: field!(self.regs, cntv),
+            frequency,
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn sizes() {
+        assert_eq!(0x1000, core::mem::size_of::<CntControlBase>());
+        assert_eq!(0x1000, core::mem::size_of::<CntReadBase>());
+        assert_eq!(0x1000, core::mem::size_of::<CntCtlBase>());
+        assert_eq!(0x1000, core::mem::size_of::<CntBase>());
+        assert_eq!(0x1000, core::mem::size_of::<CntEl0Base>());
+    }
+}