libboard_zynq: add GlobalTimer implementation

This commit is contained in:
Astro 2020-04-25 00:18:45 +02:00
parent 04c47b9bdb
commit f835192c0a
5 changed files with 103 additions and 0 deletions

View File

@ -15,3 +15,5 @@ pub mod ddr;
pub mod mpcore;
pub mod flash;
pub mod dmac;
pub mod time;
pub mod timer;

View File

@ -18,6 +18,34 @@ pub struct RegisterBlock {
reserved1: [u32; 2],
pub scu_access_control: RW<u32>,
pub scu_non_secure_access_control: RW<u32>,
reserved2: [u32; 42],
pub iccicr: RW<u32>,
pub iccpmw: RW<u32>,
pub iccbpr: RW<u32>,
pub icciar: RW<u32>,
pub icceoir: RW<u32>,
pub iccrpr: RW<u32>,
pub icchpir: RW<u32>,
pub iccabpr: RW<u32>,
reserved3: [u32; 55],
pub iccidr: RW<u32>,
pub global_timer_counter0: ValueRegister,
pub global_timer_counter1: ValueRegister,
pub global_timer_control: GlobalTimerControl,
pub global_timer_interrupt_status: RW<u32>,
pub comparator_value0: ValueRegister,
pub comparator_value1: ValueRegister,
pub auto_increment: ValueRegister,
reserved4: [u32; 249],
pub private_timer_load: ValueRegister,
pub private_timer_counter: ValueRegister,
pub private_timer_control: RW<u32>,
pub private_timer_interrupt_status: RW<u32>,
reserved5: [u32; 4],
pub watchdog_load: ValueRegister,
pub watchdog_counter: ValueRegister,
pub watchdog_control: RW<u32>,
pub watchdog_interrupt_status: RW<u32>,
// there is plenty more (unimplemented)
}
register_at!(RegisterBlock, 0xF8F00000, new);
@ -59,3 +87,13 @@ impl ScuInvalidate {
);
}
}
register!(value_register, ValueRegister, RW, u32);
register_bits!(value_register, value, u32, 0, 31);
register!(global_timer_control, GlobalTimerControl, RW, u32);
register_bits!(global_timer_control, prescaler, u16, 8, 15);
register_bit!(global_timer_control, auto_increment_mode, 3);
register_bit!(global_timer_control, irq_enable, 2);
register_bit!(global_timer_control, comp_enablea, 1);
register_bit!(global_timer_control, timer_enable, 0);

View File

@ -0,0 +1,2 @@
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Milliseconds(pub u64);

View File

@ -0,0 +1,59 @@
use libregister::{RegisterR, RegisterW};
use crate::{
clocks::Clocks,
mpcore,
time::Milliseconds,
};
pub struct GlobalTimer {
regs: &'static mut mpcore::RegisterBlock,
}
impl GlobalTimer {
pub fn new() -> GlobalTimer {
let regs = mpcore::RegisterBlock::new();
GlobalTimer { regs }
}
pub fn reset(&mut self) {
// Disable
self.regs.global_timer_control.write(
mpcore::GlobalTimerControl::zeroed()
);
// Reset counters
self.regs.global_timer_counter0.write(
mpcore::ValueRegister::zeroed()
);
self.regs.global_timer_counter1.write(
mpcore::ValueRegister::zeroed()
);
// Start
self.regs.global_timer_control.write(
mpcore::GlobalTimerControl::zeroed()
.prescaler(255)
.auto_increment_mode(true)
.timer_enable(true)
);
}
pub fn get_counter(&self) -> u64 {
loop {
let c1 = self.regs.global_timer_counter1.read().value();
let c0 = self.regs.global_timer_counter0.read().value();
let c1_post = self.regs.global_timer_counter1.read().value();
if c1 == c1_post {
return ((c1 as u64) << 32) | (c0 as u64);
}
}
}
pub fn get_time(&self) -> Milliseconds {
let prescaler = self.regs.global_timer_control.read().prescaler() as u64;
let clocks = Clocks::get();
Milliseconds(self.get_counter() * (prescaler + 1) / (clocks.cpu_3x2x() as u64 / 1000))
}
}

View File

@ -0,0 +1,2 @@
mod global;
pub use global::GlobalTimer;