From f835192c0a3a1a4a82a7e2f545ef48865ba9733a Mon Sep 17 00:00:00 2001 From: Astro Date: Sat, 25 Apr 2020 00:18:45 +0200 Subject: [PATCH] libboard_zynq: add GlobalTimer implementation --- libboard_zynq/src/lib.rs | 2 ++ libboard_zynq/src/mpcore.rs | 38 ++++++++++++++++++++ libboard_zynq/src/time.rs | 2 ++ libboard_zynq/src/timer/global.rs | 59 +++++++++++++++++++++++++++++++ libboard_zynq/src/timer/mod.rs | 2 ++ 5 files changed, 103 insertions(+) create mode 100644 libboard_zynq/src/time.rs create mode 100644 libboard_zynq/src/timer/global.rs create mode 100644 libboard_zynq/src/timer/mod.rs diff --git a/libboard_zynq/src/lib.rs b/libboard_zynq/src/lib.rs index e07920e..9276c93 100644 --- a/libboard_zynq/src/lib.rs +++ b/libboard_zynq/src/lib.rs @@ -15,3 +15,5 @@ pub mod ddr; pub mod mpcore; pub mod flash; pub mod dmac; +pub mod time; +pub mod timer; diff --git a/libboard_zynq/src/mpcore.rs b/libboard_zynq/src/mpcore.rs index 7e974c2..8bb791c 100644 --- a/libboard_zynq/src/mpcore.rs +++ b/libboard_zynq/src/mpcore.rs @@ -18,6 +18,34 @@ pub struct RegisterBlock { reserved1: [u32; 2], pub scu_access_control: RW, pub scu_non_secure_access_control: RW, + reserved2: [u32; 42], + pub iccicr: RW, + pub iccpmw: RW, + pub iccbpr: RW, + pub icciar: RW, + pub icceoir: RW, + pub iccrpr: RW, + pub icchpir: RW, + pub iccabpr: RW, + reserved3: [u32; 55], + pub iccidr: RW, + pub global_timer_counter0: ValueRegister, + pub global_timer_counter1: ValueRegister, + pub global_timer_control: GlobalTimerControl, + pub global_timer_interrupt_status: RW, + 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, + pub private_timer_interrupt_status: RW, + reserved5: [u32; 4], + pub watchdog_load: ValueRegister, + pub watchdog_counter: ValueRegister, + pub watchdog_control: RW, + pub watchdog_interrupt_status: RW, // 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); diff --git a/libboard_zynq/src/time.rs b/libboard_zynq/src/time.rs new file mode 100644 index 0000000..f82c8fb --- /dev/null +++ b/libboard_zynq/src/time.rs @@ -0,0 +1,2 @@ +#[derive(Debug, Clone, PartialEq, PartialOrd)] +pub struct Milliseconds(pub u64); diff --git a/libboard_zynq/src/timer/global.rs b/libboard_zynq/src/timer/global.rs new file mode 100644 index 0000000..616ae03 --- /dev/null +++ b/libboard_zynq/src/timer/global.rs @@ -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)) + } +} diff --git a/libboard_zynq/src/timer/mod.rs b/libboard_zynq/src/timer/mod.rs new file mode 100644 index 0000000..2bb4e94 --- /dev/null +++ b/libboard_zynq/src/timer/mod.rs @@ -0,0 +1,2 @@ +mod global; +pub use global::GlobalTimer;