blob: f601a82f1a60494fa2694436410bfc3572f1c682 [file] [log] [blame]
//! Timer driver.
use tock::kernel;
use kernel::common::cells::OptionalCell;
use kernel::common::registers::{register_bitfields, register_structs, ReadWrite, WriteOnly};
use kernel::common::StaticRef;
use kernel::hil::time;
use crate::chip::CHIP_FREQ;
const PRESCALE: u16 = ((CHIP_FREQ / 10_000) - 1) as u16; // 10Khz
/// 10KHz `Frequency`
#[derive(Debug)]
pub struct Freq10KHz;
impl time::Frequency for Freq10KHz {
fn frequency() -> u32 {
10_000
}
}
register_structs! {
pub TimerRegisters {
(0x000 => ctrl: ReadWrite<u32, ctrl::Register>),
(0x004 => _reserved),
(0x100 => config: ReadWrite<u32, config::Register>),
(0x104 => value_low: ReadWrite<u32>),
(0x108 => value_high: ReadWrite<u32>),
(0x10c => compare_low: ReadWrite<u32>),
(0x110 => compare_high: ReadWrite<u32>),
(0x114 => intr_enable: ReadWrite<u32, intr::Register>),
(0x118 => intr_state: ReadWrite<u32, intr::Register>),
(0x11c => intr_test: WriteOnly<u32, intr::Register>),
(0x120 => @END),
}
}
register_bitfields![u32,
ctrl [
enable OFFSET(0) NUMBITS(1) []
],
config [
prescale OFFSET(0) NUMBITS(12) [],
step OFFSET(16) NUMBITS(8) []
],
intr [
timer0 OFFSET(0) NUMBITS(1) []
]
];
pub struct RvTimer<'a> {
registers: StaticRef<TimerRegisters>,
client: OptionalCell<&'a dyn time::AlarmClient>,
}
impl RvTimer<'a> {
const fn new(base: StaticRef<TimerRegisters>) -> RvTimer<'a> {
RvTimer {
registers: base,
client: OptionalCell::empty(),
}
}
pub fn setup(&self) {
let regs = self.registers;
// Set proper prescaler and the like
regs.config
.write(config::prescale.val(PRESCALE as u32) + config::step.val(1u32));
regs.compare_high.set(0);
regs.intr_enable.write(intr::timer0::CLEAR);
regs.ctrl.write(ctrl::enable::SET);
}
pub fn service_interrupt(&self) {
let regs = self.registers;
regs.intr_enable.write(intr::timer0::CLEAR);
regs.intr_state.write(intr::timer0::SET);
self.client.map(|client| {
client.fired();
});
}
}
impl time::Time for RvTimer<'a> {
type Frequency = Freq10KHz;
fn now(&self) -> u32 {
self.registers.value_low.get()
}
fn max_tics(&self) -> u32 {
core::u32::MAX
}
}
impl time::Alarm<'a> for RvTimer<'a> {
fn set_client(&self, client: &'a dyn time::AlarmClient) {
self.client.set(client);
}
fn set_alarm(&self, tics: u32) {
let regs = self.registers;
// Make sure that any overlow into the high bits of the timer (which we are ignoring for
// now) do not have an effect on the alarm.
regs.value_high.set(0);
regs.compare_low.set(tics);
regs.intr_enable.write(intr::timer0::SET);
}
fn get_alarm(&self) -> u32 {
self.registers.compare_low.get()
}
fn disable(&self) {
self.registers.intr_enable.write(intr::timer0::CLEAR);
}
fn is_enabled(&self) -> bool {
self.registers.intr_enable.is_set(intr::timer0)
}
}
const TIMER_BASE: StaticRef<TimerRegisters> =
unsafe { StaticRef::new(0x4008_0000 as *const TimerRegisters) };
pub static mut TIMER: RvTimer = RvTimer::new(TIMER_BASE);