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