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;
}