1use zynq7000::gtc::MmioGlobalTimerCounter;
8
9use crate::{clocks::ArmClocks, time::Hertz};
10
11pub struct GlobalTimerCounter {
17 regs: MmioGlobalTimerCounter<'static>,
18 cpu_3x2x_clock: Option<Hertz>,
19}
20
21unsafe impl Send for GlobalTimerCounter {}
22
23pub const fn frequency_to_ticks(clock: Hertz, frequency: Hertz) -> u32 {
24 clock.raw().div_ceil(frequency.raw())
25}
26
27impl GlobalTimerCounter {
28 #[inline]
30 pub const fn new(_regs: MmioGlobalTimerCounter<'static>, clocks: &ArmClocks) -> Self {
31 unsafe { Self::steal_fixed(Some(clocks.cpu_3x2x_clk())) }
32 }
33
34 #[inline]
43 pub const unsafe fn steal_fixed(cpu_3x2x_clk: Option<Hertz>) -> Self {
44 Self {
45 regs: unsafe { zynq7000::gtc::GlobalTimerCounter::new_mmio_fixed() },
46 cpu_3x2x_clock: cpu_3x2x_clk,
47 }
48 }
49
50 #[inline]
51 pub fn set_cpu_3x2x_clock(&mut self, clock: Hertz) {
52 self.cpu_3x2x_clock = Some(clock);
53 }
54
55 #[inline]
58 pub fn read_timer(&self) -> u64 {
59 let upper = self.regs.read_count_upper();
64 loop {
65 let lower = self.regs.read_count_lower();
66 if self.regs.read_count_upper() == upper {
67 return ((upper as u64) << 32) | (lower as u64);
68 }
69 }
71 }
72
73 #[inline]
75 pub fn set_comparator(&mut self, comparator: u64) {
76 self.regs.modify_ctrl(|mut ctrl| {
77 ctrl.set_comparator_enable(false);
78 ctrl
79 });
80 self.regs.write_comparator_upper((comparator >> 32) as u32);
81 self.regs.write_comparator_lower(comparator as u32);
82 self.regs.modify_ctrl(|mut ctrl| {
83 ctrl.set_comparator_enable(true);
84 ctrl
85 });
86 }
87
88 pub fn frequency_to_ticks(&self, frequency: Hertz) -> u32 {
89 if self.cpu_3x2x_clock.is_none() {
90 return 0;
91 }
92 frequency_to_ticks(self.cpu_3x2x_clock.unwrap(), frequency)
93 }
94
95 #[inline]
98 pub fn set_auto_increment_value(&mut self, value: u32) {
99 self.regs.write_auto_increment(value);
100 }
101
102 #[inline]
103 pub fn set_auto_increment_value_for_frequency(&mut self, frequency: Hertz) {
104 self.regs
105 .write_auto_increment(self.frequency_to_ticks(frequency));
106 }
107
108 #[inline]
109 pub fn enable(&mut self) {
110 self.regs.modify_ctrl(|mut ctrl| {
111 ctrl.set_enable(true);
112 ctrl
113 });
114 }
115
116 #[inline]
117 pub fn enable_auto_increment(&mut self) {
118 self.regs.modify_ctrl(|mut ctrl| {
119 ctrl.set_auto_increment(true);
120 ctrl
121 });
122 }
123
124 #[inline]
125 pub fn set_prescaler(&mut self, prescaler: u8) {
126 self.regs.modify_ctrl(|mut ctrl| {
127 ctrl.set_prescaler(prescaler);
128 ctrl
129 });
130 }
131
132 #[inline]
133 pub fn disable(&mut self) {
134 self.regs.modify_ctrl(|mut ctrl| {
135 ctrl.set_enable(false);
136 ctrl
137 });
138 }
139
140 #[inline]
142 pub fn enable_interrupt(&mut self) {
143 self.regs.modify_ctrl(|mut ctrl| {
144 ctrl.set_irq_enable(true);
145 ctrl
146 });
147 }
148
149 #[inline]
151 pub fn disable_interrupt(&mut self) {
152 self.regs.modify_ctrl(|mut ctrl| {
153 ctrl.set_irq_enable(false);
154 ctrl
155 });
156 }
157}
158
159impl embedded_hal::delay::DelayNs for GlobalTimerCounter {
161 fn delay_ns(&mut self, ns: u32) {
162 if self.cpu_3x2x_clock.is_none() {
163 return;
164 }
165 let end_of_delay = self.read_timer()
166 + (((ns as u64) * self.cpu_3x2x_clock.unwrap().raw() as u64) / 1_000_000_000);
167 while self.read_timer() < end_of_delay {}
168 }
169}