sel4_sp804_driver/
lib.rs

1//
2// Copyright 2023, Colias Group, LLC
3//
4// SPDX-License-Identifier: BSD-2-Clause
5//
6
7#![no_std]
8
9use core::convert::Infallible;
10use core::time::Duration;
11use tock_registers::interfaces::ReadWriteable;
12
13use sel4_driver_interfaces::timer::{Clock, ErrorType, Timer as TimerTrait};
14use sel4_driver_interfaces::HandleInterrupt;
15
16mod device;
17
18use device::{Control, Device, Timer};
19
20pub struct Driver {
21    device: Device,
22    freq: u64, // Hz
23    high_bits: u32,
24    most_recent_value: u32,
25}
26
27impl Driver {
28    #[allow(clippy::missing_safety_doc)]
29    pub const unsafe fn new_uninit(ptr: *mut (), freq: u64) -> Self {
30        Self {
31            device: Device::new(ptr),
32            freq,
33            high_bits: 0,
34            most_recent_value: !0,
35        }
36    }
37
38    #[allow(clippy::missing_safety_doc)]
39    pub unsafe fn new(ptr: *mut (), freq: u64) -> Self {
40        let mut this = Self::new_uninit(ptr, freq);
41        this.init();
42        this
43    }
44
45    pub fn init(&mut self) {
46        let control_common =
47            Control::TimerEn::Disabled + Control::TimerPre::Div256 + Control::TimerSize::Use32Bit;
48
49        self.timer_for_reading()
50            .control()
51            .modify(control_common + Control::IntEnable::Enabled);
52        self.timer_for_reading().set_free_running_mode();
53        self.timer_for_reading().clear_interrupt();
54        self.timer_for_reading().set_load(!0);
55
56        self.timer_for_writing()
57            .control()
58            .modify(control_common + Control::IntEnable::Disabled);
59        self.timer_for_writing().set_one_shot_mode();
60        self.timer_for_writing().clear_interrupt();
61        self.timer_for_writing().set_load(0);
62
63        self.timer_for_reading()
64            .control()
65            .modify(Control::TimerEn::Enabled);
66    }
67
68    fn scaled_freq(&self) -> u64 {
69        self.freq / 256
70    }
71
72    fn timer_for_reading(&self) -> &Timer {
73        self.device.timer_1()
74    }
75
76    fn timer_for_writing(&self) -> &Timer {
77        self.device.timer_2()
78    }
79
80    fn current_value_checking_for_overflow(&mut self) -> u32 {
81        let value = self.timer_for_reading().current_value();
82        if value > self.most_recent_value {
83            self.high_bits += 1;
84        }
85        self.most_recent_value = value;
86        value
87    }
88
89    fn check_for_overflow(&mut self) {
90        let _ = self.current_value_checking_for_overflow();
91    }
92
93    fn ticks_to_duration(&self, ticks: u64) -> Duration {
94        Duration::from_nanos(
95            u64::try_from((u128::from(ticks) * 1_000_000_000) / u128::from(self.scaled_freq()))
96                .unwrap(),
97        )
98    }
99
100    fn duration_to_ticks(&self, d: Duration) -> u128 {
101        (d.as_nanos() * u128::from(self.scaled_freq())) / 1_000_000_000
102    }
103}
104
105impl HandleInterrupt for Driver {
106    fn handle_interrupt(&mut self) {
107        if self.timer_for_reading().masked_interrupt_status() {
108            self.check_for_overflow();
109            self.timer_for_reading().clear_interrupt();
110        }
111        if self.timer_for_writing().masked_interrupt_status() {
112            self.clear_timeout().unwrap();
113            self.timer_for_writing().clear_interrupt();
114        }
115    }
116}
117
118impl ErrorType for Driver {
119    type Error = Infallible;
120}
121
122impl Clock for Driver {
123    fn get_time(&mut self) -> Result<Duration, Self::Error> {
124        let value = self.current_value_checking_for_overflow();
125        let ticks = ((u64::from(self.high_bits) + 1) << 32) - u64::from(value);
126        let t = self.ticks_to_duration(ticks);
127        Ok(t)
128    }
129}
130
131impl TimerTrait for Driver {
132    fn set_timeout(&mut self, relative: Duration) -> Result<(), Self::Error> {
133        self.clear_timeout().unwrap();
134        self.timer_for_writing()
135            .set_load(self.duration_to_ticks(relative).try_into().unwrap());
136        self.timer_for_writing()
137            .control()
138            .modify(Control::TimerEn::Enabled + Control::IntEnable::Enabled);
139        Ok(())
140    }
141
142    fn clear_timeout(&mut self) -> Result<(), Self::Error> {
143        self.timer_for_writing()
144            .control()
145            .modify(Control::TimerEn::Disabled + Control::IntEnable::Disabled);
146        self.timer_for_writing().set_load(0);
147        Ok(())
148    }
149}