1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! The public interface for the SP804 Dual Timer driver.
use r3_core::kernel::{InterruptNum, InterruptPriority};

/// Attach the implementation of [`PortTimer`] that is based on
/// [Arm PrimeCell SP804 Dual Timer] to a given kernel trait type. This macro
/// also implements [`Timer`] on the kernel trait type.
/// **Requires [`Sp804Options`].**
///
/// [`PortTimer`]: r3_kernel::PortTimer
/// [`Timer`]: crate::Timer
/// [Arm PrimeCell SP804 Dual Timer]: https://developer.arm.com/documentation/ddi0271/d/
///
/// You should do the following:
///
///  - Implement [`Sp804Options`] on the kernel trait type `$Traits`.
///  - Call `$Traits::configure_sp804()` in your configuration function.
///    See the following example.
///
/// ```rust,ignore
/// r3_port_arm::use_sp804!(unsafe impl PortTimer for SystemTraits);
///
/// impl r3_port_arm::Sp804Options for SystemTraits {
///     const SP804_BASE: usize = 0x1001_1000;
///     const FREQUENCY: u64 = 1_000_000;
///     const INTERRUPT_NUM: InterruptNum = 36;
/// }
///
/// const fn configure_app<C>(b: &mut Cfg<SystemTraits>) -> Objects
/// where
///     C: ~const traits::CfgBase<System = System<SystemTraits>>,
/// {
///     SystemTraits::configure_sp804(b);
///     /* ... */
/// }
/// ```
///
/// # Safety
///
///  - `Sp804Options` must be configured correctly.
///
#[macro_export]
macro_rules! use_sp804 {
    (unsafe impl PortTimer for $Traits:ty) => {
        const _: () = {
            use $crate::r3_core::{
                kernel::{traits, Cfg},
                utils::Init,
            };
            use $crate::r3_kernel::{PortTimer, System, UTicks};
            use $crate::r3_portkit::tickless;
            use $crate::{sp804, Sp804Options, Timer};

            impl PortTimer for $Traits {
                const MAX_TICK_COUNT: UTicks = u32::MAX;
                const MAX_TIMEOUT: UTicks = u32::MAX;

                unsafe fn tick_count() -> UTicks {
                    // Safety: We are just forwarding the call
                    unsafe { sp804::imp::tick_count::<Self>() }
                }

                unsafe fn pend_tick() {
                    // Safety: We are just forwarding the call
                    unsafe { sp804::imp::pend_tick::<Self>() }
                }

                unsafe fn pend_tick_after(tick_count_delta: UTicks) {
                    // Safety: We are just forwarding the call
                    unsafe { sp804::imp::pend_tick_after::<Self>(tick_count_delta) }
                }
            }

            impl Timer for $Traits {
                unsafe fn init() {
                    unsafe { sp804::imp::init::<Self>() }
                }
            }

            static mut TIMER_STATE: <$Traits as sp804::imp::Sp804Instance>::TicklessState =
                Init::INIT;

            // Safety: Only `use_sp804!` is allowed to `impl` this
            unsafe impl sp804::imp::Sp804Instance for $Traits {
                type TicklessState = tickless::TicklessState<{ Self::TICKLESS_CFG }>;

                fn tickless_state() -> *mut Self::TicklessState {
                    unsafe { core::ptr::addr_of_mut!(TIMER_STATE) }
                }
            }

            impl $Traits {
                pub const fn configure_sp804<C>(b: &mut Cfg<C>)
                where
                    C: ~const traits::CfgInterruptLine<System = System<Self>>,
                {
                    sp804::imp::configure(b);
                }
            }
        };
    };
}

/// The options for [`use_sp804!`].
pub trait Sp804Options {
    /// The base address of SP804's memory-mapped registers.
    const SP804_BASE: usize;

    /// The numerator of the effective timer clock rate of the dual timer.
    const FREQUENCY: u64;

    /// The denominator of the effective timer clock rate of the dual timer.
    /// Defaults to `1`.
    const FREQUENCY_DENOMINATOR: u64 = 1;

    /// The maximum permissible timer interrupt latency, measured in hardware
    /// timer cycles.
    ///
    /// Defaults to `min(FREQUENCY * 60 / FREQUENCY_DENOMINATOR, 0x40000000)`.
    const HEADROOM: u32 =
        (Self::FREQUENCY as u128 * 60 / Self::FREQUENCY_DENOMINATOR as u128).min(0x40000000) as u32;

    /// The interrupt priority of the timer interrupt line.
    /// Defaults to `0xc0`.
    const INTERRUPT_PRIORITY: InterruptPriority = 0xc0;

    /// The timer's interrupt number.
    const INTERRUPT_NUM: InterruptNum;
}