Skip to main content

axplat_arm_peripherals/
generic_timer.rs

1//! ARM Generic Timer.
2
3use axcpu::generic_timer::{GenericTimer, PhysicalTimer as Timer};
4use int_ratio::Ratio;
5
6static mut CNTPCT_TO_NANOS_RATIO: Ratio = Ratio::zero();
7static mut NANOS_TO_CNTPCT_RATIO: Ratio = Ratio::zero();
8
9/// Returns the current clock time in hardware ticks.
10#[inline]
11pub fn current_ticks() -> u64 {
12    Timer::counter()
13}
14
15/// Converts hardware ticks to nanoseconds.
16#[inline]
17pub fn ticks_to_nanos(ticks: u64) -> u64 {
18    unsafe { CNTPCT_TO_NANOS_RATIO.mul_trunc(ticks) }
19}
20
21/// Converts nanoseconds to hardware ticks.
22#[inline]
23pub fn nanos_to_ticks(nanos: u64) -> u64 {
24    unsafe { NANOS_TO_CNTPCT_RATIO.mul_trunc(nanos) }
25}
26
27/// Set a one-shot timer.
28///
29/// A timer interrupt will be triggered at the specified monotonic time deadline (in nanoseconds).
30pub fn set_oneshot_timer(deadline_ns: u64) {
31    let cur_ticks = current_ticks();
32    let deadline_ticks = nanos_to_ticks(deadline_ns);
33    if cur_ticks < deadline_ticks {
34        let interval = deadline_ticks - cur_ticks;
35        debug_assert!(interval <= u32::MAX as u64);
36        Timer::set_countdown(interval as u32);
37    } else {
38        Timer::set_countdown(0);
39    }
40}
41
42/// Early stage initialization: stores the timer frequency.
43pub fn init_early() {
44    let freq = Timer::frequency();
45    unsafe {
46        CNTPCT_TO_NANOS_RATIO = Ratio::new(axplat::time::NANOS_PER_SEC as u32, freq);
47        NANOS_TO_CNTPCT_RATIO = CNTPCT_TO_NANOS_RATIO.inverse();
48    }
49}
50
51/// Enable timer interrupts.
52///
53/// It should be called on all CPUs, as the timer interrupt is a PPI (Private
54/// Peripheral Interrupt).
55#[cfg(feature = "irq")]
56pub fn enable_irqs(timer_irq_num: usize) {
57    Timer::set_enable(true);
58    Timer::set_countdown(0);
59    axplat::irq::set_enable(timer_irq_num, true);
60}
61
62/// Default implementation of [`axplat::time::TimeIf`] using the generic
63/// timer.
64#[macro_export]
65macro_rules! time_if_impl {
66    ($name:ident) => {
67        struct $name;
68
69        #[impl_interface]
70        impl axplat::time::TimeIf for $name {
71            /// Returns the current clock time in hardware ticks.
72            fn current_ticks() -> u64 {
73                $crate::generic_timer::current_ticks()
74            }
75
76            /// Converts hardware ticks to nanoseconds.
77            fn ticks_to_nanos(ticks: u64) -> u64 {
78                $crate::generic_timer::ticks_to_nanos(ticks)
79            }
80
81            /// Converts nanoseconds to hardware ticks.
82            fn nanos_to_ticks(nanos: u64) -> u64 {
83                $crate::generic_timer::nanos_to_ticks(nanos)
84            }
85
86            /// Return epoch offset in nanoseconds (wall time offset to monotonic
87            /// clock start).
88            fn epochoffset_nanos() -> u64 {
89                $crate::pl031::epochoffset_nanos()
90            }
91
92            /// Set a one-shot timer.
93            ///
94            /// A timer interrupt will be triggered at the specified monotonic time
95            /// deadline (in nanoseconds).
96            #[cfg(feature = "irq")]
97            fn set_oneshot_timer(deadline_ns: u64) {
98                $crate::generic_timer::set_oneshot_timer(deadline_ns)
99            }
100        }
101    };
102}