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
129
130
131
132
133
//! The public interface for the RZ/A1 OS Timer driver.
use r3::kernel::{InterruptNum, InterruptPriority};

/// Attach the implementation of [`PortTimer`] that is based on RZ/A1 OS Timer
/// to a given kernel trait type. This macro also implements [`Timer`] on the
/// kernel trait type.
/// **Requires [`OsTimerOptions`] and [`Gic`].**
///
/// [`PortTimer`]: r3_kernel::PortTimer
/// [`Timer`]: r3_port_arm::Timer
/// [`Gic`]: r3_port_arm::Gic
///
/// You should do the following:
///
///  - Implement [`OsTimerOptions`] on the kernel trait type `$Traits`.
///  - Call `$Traits::configure_os_timer()` in your configuration function.
///    See the following example.
///
/// ```rust,ignore
/// r3_support_rza1::use_os_timer!(unsafe impl PortTimer for SystemTraits);
///
/// impl r3_support_rza1::OsTimerOptions for SystemTraits {
///     const FREQUENCY: u64 = 1_000_000;
/// }
///
/// const fn configure_app(b: &mut Cfg<C>) -> Objects
/// where
///     C: ~const traits::CfgBase<System = System<SystemTraits>>,
/// {
///     SystemTraits::configure_os_timer(b);
///     /* ... */
/// }
/// ```
///
/// # Safety
///
///  - `OsTimerOptions` must be configured correctly.
///
#[macro_export]
macro_rules! use_os_timer {
    (unsafe impl PortTimer for $Traits:ty) => {
        const _: () = {
            use $crate::r3::{
                kernel::{traits, Cfg},
                utils::Init,
            };
            use $crate::r3_kernel::{PortTimer, System, UTicks};
            use $crate::r3_port_arm::Timer;
            use $crate::r3_portkit::tickless;
            use $crate::{os_timer, OsTimerOptions};

            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 { os_timer::imp::tick_count::<Self>() }
                }

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

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

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

            static mut TIMER_STATE: <$Traits as os_timer::imp::OsTimerInstance>::TicklessState =
                Init::INIT;

            // Safety: Only `use_os_timer!` is allowed to `impl` this
            unsafe impl os_timer::imp::OsTimerInstance 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_os_timer<C>(b: &mut Cfg<C>)
                where
                    C: ~const traits::CfgInterruptLine<System = System<Self>>,
                {
                    os_timer::imp::configure(b);
                }
            }
        };
    };
}

/// The options for [`use_os_timer!`].
pub trait OsTimerOptions {
    /// The base address of OS Timer's memory-mapped registers.
    const OSTM_BASE: usize = 0xfcfec000;

    /// The standby control register's memory address and bit position used to
    /// enable the clock supply to OS Timer.
    ///
    /// Defaults to `Some((0xfcfe0428, 1))` (STBCR5.MSTP51).
    const STBCR_OSTM: Option<(usize, u8)> = Some((0xfcfe0428, 1));

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

    /// The denominator of the timer clock rate of the 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_OSTM_PRIORITY: InterruptPriority = 0xc0;

    /// OS Timer's interrupt number.
    const INTERRUPT_OSTM: InterruptNum = 134;
}