1#![no_std]
2use core::cell::{Cell, RefCell};
3
4use critical_section::{CriticalSection, Mutex};
5use embassy_time_driver::{Driver, TICK_HZ, time_driver_impl};
6use embassy_time_queue_utils::Queue;
7use once_cell::sync::OnceCell;
8
9use zynq7000_hal::{clocks::ArmClocks, gtc::GlobalTimerCounter, time::Hertz};
10
11static SCALE: OnceCell<u64> = OnceCell::new();
12static CPU_3X2X_CLK: OnceCell<Hertz> = OnceCell::new();
13
14struct AlarmState {
15 timestamp: Cell<u64>,
16}
17
18impl AlarmState {
19 const fn new() -> Self {
20 Self {
21 timestamp: Cell::new(u64::MAX),
22 }
23 }
24}
25
26unsafe impl Send for AlarmState {}
27
28pub fn init(arm_clocks: &ArmClocks, gtc: GlobalTimerCounter) {
32 if SCALE.get().is_some() || CPU_3X2X_CLK.get().is_some() {
33 return;
34 }
35 unsafe { GTC_TIME_DRIVER.init(arm_clocks, gtc) };
36}
37
38pub unsafe fn on_interrupt() {
45 unsafe { GTC_TIME_DRIVER.on_interrupt() };
46}
47
48pub struct GtcTimerDriver {
49 gtc: Mutex<RefCell<GlobalTimerCounter>>,
50 alarms: Mutex<AlarmState>,
52 queue: Mutex<RefCell<Queue>>,
53}
54
55impl GtcTimerDriver {
56 pub unsafe fn init(&'static self, arm_clock: &ArmClocks, mut gtc: GlobalTimerCounter) {
62 CPU_3X2X_CLK.set(arm_clock.cpu_3x2x_clk()).unwrap();
63 SCALE
64 .set(arm_clock.cpu_3x2x_clk().raw() as u64 / TICK_HZ)
65 .unwrap();
66 gtc.set_cpu_3x2x_clock(arm_clock.cpu_3x2x_clk());
67 gtc.set_prescaler(0);
68 gtc.enable();
69 }
70
71 pub unsafe fn on_interrupt(&self) {
79 critical_section::with(|cs| {
80 self.trigger_alarm(cs);
81 })
82 }
83
84 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
85 if SCALE.get().is_none() {
86 return false;
87 }
88 let mut gtc = self.gtc.borrow(cs).borrow_mut();
89 let alarm = &self.alarms.borrow(cs);
90 alarm.timestamp.set(timestamp);
91
92 let t = self.now();
93 if timestamp <= t {
94 gtc.disable_interrupt();
95 alarm.timestamp.set(u64::MAX);
96 return false;
97 }
98
99 let safe_timestamp = timestamp.max(t + 3);
110 let opt_comparator = safe_timestamp.checked_mul(*SCALE.get().unwrap());
111 if opt_comparator.is_none() {
112 return true;
113 }
114 gtc.set_comparator(opt_comparator.unwrap());
115 gtc.enable_interrupt();
116 true
117 }
118
119 fn trigger_alarm(&self, cs: CriticalSection) {
120 let mut gtc = self.gtc.borrow(cs).borrow_mut();
121 gtc.disable_interrupt();
122 drop(gtc);
123
124 let alarm = &self.alarms.borrow(cs);
125 alarm.timestamp.set(u64::MAX);
127
128 let mut next = self
130 .queue
131 .borrow(cs)
132 .borrow_mut()
133 .next_expiration(self.now());
134 while !self.set_alarm(cs, next) {
135 next = self
136 .queue
137 .borrow(cs)
138 .borrow_mut()
139 .next_expiration(self.now());
140 }
141 }
142}
143impl Driver for GtcTimerDriver {
144 #[inline]
145 fn now(&self) -> u64 {
146 if SCALE.get().is_none() {
147 return 0;
148 }
149 let gtc = unsafe { GlobalTimerCounter::steal_fixed(Some(*CPU_3X2X_CLK.get().unwrap())) };
152
153 gtc.read_timer() / SCALE.get().unwrap()
154 }
155
156 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
157 critical_section::with(|cs| {
158 let mut queue = self.queue.borrow(cs).borrow_mut();
159
160 if queue.schedule_wake(at, waker) {
161 let mut next = queue.next_expiration(self.now());
162 while !self.set_alarm(cs, next) {
163 next = queue.next_expiration(self.now());
164 }
165 }
166 })
167 }
168}
169
170time_driver_impl!(
171 static GTC_TIME_DRIVER: GtcTimerDriver = GtcTimerDriver {
173 gtc: Mutex::new(RefCell::new(unsafe { GlobalTimerCounter::steal_fixed(None)})),
174 alarms: Mutex::new(AlarmState::new()),
175 queue: Mutex::new(RefCell::new(Queue::new())),
176});