blob: c99684e0326ee983a5e2876221c737bffb411ea5 [file] [log] [blame]
Imre Kisdb5d9562025-08-01 16:36:01 +02001// SPDX-FileCopyrightText: Copyright The arm-generic-timer Contributors.
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4#![no_std]
5#![doc = include_str!("../README.md")]
6#![deny(clippy::undocumented_unsafe_blocks)]
7#![deny(unsafe_op_in_unsafe_fn)]
8
9use core::time::Duration;
10
11use bitflags::bitflags;
12use safe_mmio::{
13 field, field_shared,
14 fields::{ReadPure, ReadPureWrite},
15 UniqueMmioPointer,
16};
17use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
18
19/// Counter Control Register
20#[repr(transparent)]
21#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
22pub struct CntCr(u32);
23
24/// Counter Status Register
25#[repr(transparent)]
26#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
27pub struct CntSr(u32);
28
29/// Counter Identification Register.
30#[repr(transparent)]
31#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
32pub struct CntId(u32);
33
34/// Counter-timer Access Control Register.
35#[repr(transparent)]
36#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
37pub struct CntAcr(u32);
38
39/// Timer feature bits, defined at I5.7.16 CNTTIDR, Counter-timer Timer ID Register description.
40#[repr(transparent)]
41#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
42pub struct Features(u8);
43
44/// Counter-timer EL0 Access Control Register.
45#[repr(transparent)]
46#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
47pub struct CntEl0Acr(u32);
48
49/// Common control register of the physical and virtual timers. Defined at I5.7.10 CNTP_CTL,
50/// Counter-timer Physical Timer Control and at CNTV_CTL, Counter-timer Virtual Timer Control.
51#[repr(transparent)]
52#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
53pub struct TimerControl(u32);
54
55bitflags! {
56 impl CntCr: u32 {
57 /// Scaling is enabled. This bit depends on the presence of FEAT_CNTSC.
58 const SCEN = 1 << 2;
59 /// Halt-on-debug.
60 const HDBG = 1 << 1;
61 /// System counter enabled.
62 const EN = 1 << 0;
63 }
64
65 impl CntSr: u32 {
66 /// Halt-on-debug.
67 const HDBG = 1 << 1;
68 }
69
70 impl CntAcr: u32 {
71 /// Read/write access to the EL1 Physical Timer registers
72 const RWPT = 1 << 5;
73 /// Read/write access to the Virtual Timer registers
74 const RWVT = 1 << 4;
75 /// Read-only access to CNTVOFF
76 const RVOFF = 1 << 3;
77 /// Read-only access to CNTFRQ
78 const RFRQ = 1 << 2;
79 /// Read-only access to CNTVCT
80 const RVCT = 1 << 1;
81 /// Read-only access to CNTPCT
82 const RPCT = 1 << 0;
83 }
84
85 impl Features: u8 {
86 /// Frame<n> has a second view, CNTEL0Base<n>.
87 const CNTEL0BASE = 1 << 2;
88 /// Frame<n> has virtual capability. The virtual time and offset registers are implemented.
89 const VIRTUAL = 1 << 1;
90 /// Frame<n> is implemented.
91 const IMPLEMENTED = 1 << 0;
92 }
93
94 impl CntEl0Acr: u32 {
95 /// Second view read access control for CNTP_CVAL, CNTP_TVAL, and CNTP_CTL.
96 const EL0PTEN = 1 << 9;
97 /// Second view read access control for CNTV_CVAL, CNTV_TVAL, and CNTV_CTL.
98 const EL0VTEN = 1 << 8;
99 /// Second view read access control for CNTVCT and CNTFRQ.
100 const EL0VCTEN = 1 << 1;
101 /// Second view read access control for CNTPCT and CNTFRQ.
102 const EL0PCTEN = 1 << 0;
103 }
104
105 impl TimerControl: u32 {
106 /// Timer condition is met.
107 const ISTATUS = 1 << 2;
108 /// Timer interrupt is masked.
109 const IMASK = 1 << 1;
110 /// Timer enabled.
111 const ENABLE = 1 << 0;
112 }
113}
114
115impl CntCr {
116 const FCREQ_MASK: u32 = 0x0000_03ff;
117 const FCREQ_SHIFT: u32 = 8;
118
119 /// Write FCREQ field of the register.
120 pub fn set_fcreq(&mut self, index: usize) {
121 let mut value = self.0 & !(Self::FCREQ_MASK << Self::FCREQ_SHIFT);
122 value |= ((index as u32) & Self::FCREQ_MASK) << Self::FCREQ_SHIFT;
123 self.0 = value;
124 }
125}
126
127impl CntSr {
128 const FCACK_MASK: u32 = 0x0000_03ff;
129 const FCACK_SHIFT: u32 = 8;
130
131 /// Read FCACK field of the register.
132 pub fn fcack(&self) -> usize {
133 ((self.0 >> Self::FCACK_SHIFT) & Self::FCACK_MASK) as usize
134 }
135}
136
137impl CntId {
138 const CNTSC_MASK: u32 = 0b1111;
139 const CNTSC_IMPLEMENTED: u32 = 0b0001;
140
141 /// Indicates whether Counter Scaling is implemented.
142 pub fn scaling_implemented(&self) -> bool {
143 self.0 & Self::CNTSC_MASK == Self::CNTSC_IMPLEMENTED
144 }
145}
146
147/// Table I2-1 CNTControlBase memory map
148#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
149#[repr(C, align(4))]
150pub struct CntControlBase {
151 /// 0x000 Counter Control Register
152 cntcr: ReadPureWrite<CntCr>,
153 /// 0x004 Counter Status Register
154 cntsr: ReadPure<CntSr>,
155 /// 0x008 Counter Count Value register
156 cntcv: ReadPureWrite<u64>,
157 /// 0x010 Counter Counter Scale register
158 cntscr: ReadPureWrite<u32>,
159 reserved_14: [u32; 2],
160 /// 0x01c Counter ID register
161 cntid: ReadPure<CntId>,
162 /// 0x020 Counter Frequency IDs
163 cntfid: [ReadPureWrite<u32>; 40],
164 /// 0x0c0 Implementation defined
165 impdef_0c0: [u32; 16],
166 reserved_100: [u32; 948],
167 /// 0xfd0 Counter ID registers
168 counter_id: [ReadPure<u32>; 12],
169}
170
171/// Table I2-2 CNTReadBase memory map
172#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
173#[repr(C, align(4))]
174pub struct CntReadBase {
175 /// 0x000 Counter Count Value register
176 cntcv: ReadPure<u64>,
177 reserved_8: [u32; 1010],
178 /// 0xfd0 Counter ID registers
179 counter_id: [ReadPure<u32>; 12],
180}
181
182/// Table I2-3 CNTCTLBase memory map
183#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
184#[repr(C, align(4))]
185pub struct CntCtlBase {
186 /// 0x000 Counter-timer Frequency
187 cntfrq: ReadPureWrite<u32>,
188 /// 0x004 Counter-timer Non-secure Access Register
189 cntnsar: ReadPureWrite<u32>,
190 /// 0x008 Counter-timer Timer ID Register
191 cnttidr: ReadPure<u32>,
192 reserved_00c: [u32; 13],
193 /// 0x040 Counter-timer Access Control Registers
194 cntacr: [ReadPureWrite<CntAcr>; 8],
195 reserved_060: [u32; 8],
196 /// 0x080 Counter-timer Virtual Offsets
197 cntvoff: [ReadPureWrite<u64>; 8],
198 reserved_0c0: [u32; 16],
199 /// 0x100 Implementation defined
200 impdef_100: [u32; 448],
201 reserved_800: [u32; 496],
202 impdef_fc0: [u32; 4],
203 /// 0xfd0 Counter ID registers
204 counter_id: [ReadPure<u32>; 12],
205}
206
207/// Repeated subset of register that describe a physical or virtual timer in the CntBase or
208/// CntEl0Base blocks.
209#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
210#[repr(C, align(4))]
211pub struct TimerRegs {
212 /// 0x000 Counter-timer Timer CompareValue
213 cval: ReadPureWrite<u64>,
214 /// 0x008 Counter-timer Timer TimerValue
215 tval: ReadPureWrite<u32>,
216 /// 0x00c Counter-timer Timer Control
217 ctl: ReadPureWrite<TimerControl>,
218}
219
220/// Table I2-4 CNTBaseN memory map
221#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
222#[repr(C, align(4))]
223pub struct CntBase {
224 /// 0x000 Counter-timer Physical Count
225 cntpct: ReadPure<u64>,
226 /// 0x008 Counter-timer Virtual Count
227 cntvct: ReadPure<u64>,
228 /// 0x010 Counter-timer Frequency
229 cntfrq: ReadPure<u32>,
230 /// 0x014 Counter-timer EL0 Access Control Register
231 cntel0acr: ReadPureWrite<CntEl0Acr>,
232 /// 0x018 Counter-timer Virtual Offset
233 cntvoff: ReadPure<u64>,
234 /// 0x020-0x02c Physical timer block
235 cntp: TimerRegs,
236 /// 0x030-0x03c Virtual timer block
237 cntv: TimerRegs,
238 reserved: [u32; 996],
239 /// 0xfd0 Counter ID registers
240 counter_id: [ReadPure<u32>; 12],
241}
242
243/// CntEl0Base frame is identical to the CntBase frame, except that CNTVOFF, CNTEL0ACR registers are
244/// never visible and CNTEL0ACR of the corresponding CntBase controls the access of the physical and
245/// virtual timer registers.
246#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
247#[repr(C, align(4))]
248pub struct CntEl0Base {
249 /// 0x000 Counter-timer Physical Count
250 cntpct: ReadPure<u64>,
251 /// 0x008 Counter-timer Virtual Count
252 cntvct: ReadPure<u64>,
253 /// 0x010 Counter-timer Frequency
254 cntfrq: ReadPure<u32>,
255 reserved_014: [u32; 3],
256 /// 0x020-0x02c Physical timer block
257 cntp: TimerRegs,
258 /// 0x030-0x03c Virtual timer block
259 cntv: TimerRegs,
260 reserved: [u32; 996],
261 /// 0xfd0 Counter ID registers
262 counter_id: [ReadPure<u32>; 12],
263}
264
265/// Driver for the CNTControlBase block.
266pub struct GenericTimerControl<'a> {
267 regs: UniqueMmioPointer<'a, CntControlBase>,
268}
269
270impl<'a> GenericTimerControl<'a> {
271 /// Creates new instance.
272 pub fn new(regs: UniqueMmioPointer<'a, CntControlBase>) -> Self {
273 Self { regs }
274 }
275
276 /// Enables or disables the timer.
277 pub fn set_enable(&mut self, enable: bool) {
278 let mut cntcr = field!(self.regs, cntcr).read();
279 cntcr.set(CntCr::EN, enable);
280 field!(self.regs, cntcr).write(cntcr);
281 }
282
283 /// Sets the number of the entry in the Frequency modes table to select.
284 pub fn request_frequency(&mut self, index: usize) {
285 let mut cntcr = field!(self.regs, cntcr).read();
286 cntcr.set_fcreq(index);
287 field!(self.regs, cntcr).write(cntcr);
288 }
289
290 /// Gets currently selected entry index in the Frequency modes table.
291 pub fn frequency_index(&self) -> usize {
292 field_shared!(self.regs, cntsr).read().fcack()
293 }
294
295 /// Gets timer count value.
296 pub fn count(&self) -> u64 {
297 field_shared!(self.regs, cntcv).read()
298 }
299
300 /// Sets timer count value.
301 pub fn set_count(&mut self, count: u64) {
302 field!(self.regs, cntcv).write(count);
303 }
304
305 /// Checks whether scaling is implemented by the timer.
306 pub fn scaling_implemented(&self) -> bool {
307 field_shared!(self.regs, cntid).read().scaling_implemented()
308 }
309
310 /// Gets scale value.
311 pub fn scale(&self) -> u32 {
312 field_shared!(self.regs, cntscr).read()
313 }
314
315 /// Sets scale and enable scaling.
316 pub fn enable_scaling(&mut self, scale: u32) {
317 field!(self.regs, cntscr).write(scale);
318 let cntcr = field!(self.regs, cntcr).read();
319 field!(self.regs, cntcr).write(cntcr | CntCr::SCEN);
320 }
321
322 /// Disables scaling.
323 pub fn disable_scaling(&mut self) {
324 let cntcr = field!(self.regs, cntcr).read();
325 field!(self.regs, cntcr).write(cntcr - CntCr::SCEN);
326 field!(self.regs, cntscr).write(0);
327 }
328
329 /// Indicates the base frequency of the system counter in Hz.
330 pub fn base_frequency(&self) -> u32 {
331 field_shared!(self.regs, cntfid).get(0).unwrap().read()
332 }
333
334 /// Gets frequency mode of the given index in Hz. The availablity of the frequency mode is
335 /// implementation defined.
336 pub fn frequency_mode(&self, index: usize) -> Option<u32> {
337 let frequency = field_shared!(self.regs, cntfid).get(index).unwrap().read();
338
339 if frequency != 0 {
340 Some(frequency)
341 } else {
342 None
343 }
344 }
345
346 /// Sets frequency mode of the given index. The availablity of the frequency mode is
347 /// implementation defined.
348 pub fn set_frequency_mode(&mut self, index: usize, frequency: u32) {
349 field!(self.regs, cntfid)
350 .get(index)
351 .unwrap()
352 .write(frequency)
353 }
354}
355
356/// Driver for the CNTCTLBase block.
357pub struct GenericTimerCtl<'a> {
358 regs: UniqueMmioPointer<'a, CntCtlBase>,
359}
360
361impl<'a> GenericTimerCtl<'a> {
362 /// Creates new instance.
363 pub fn new(regs: UniqueMmioPointer<'a, CntCtlBase>) -> Self {
364 Self { regs }
365 }
366
367 /// Gets counter frequency in Hz.
368 pub fn frequency(&self) -> u32 {
369 field_shared!(self.regs, cntfrq).read()
370 }
371
372 /// Sets counter frequency in Hz.
373 pub fn set_frequency(&mut self, frequency: u32) {
374 field!(self.regs, cntfrq).write(frequency);
375 }
376
377 /// Gets non-secure access state.
378 pub fn non_secure_access(&self, index: usize) -> bool {
379 assert!(index < 8);
380
381 let cntnsar = field_shared!(self.regs, cntnsar).read();
382 cntnsar & (1 << index) != 0
383 }
384
385 /// Provides the highest-level control of whether frames CNTBaseN and CNTEL0BaseN are accessible
386 /// by Non-secure accesses.
387 pub fn set_non_secure_access(&mut self, index: usize, enable: bool) {
388 assert!(index < 8);
389
390 let mut cntnsar = field_shared!(self.regs, cntnsar).read();
391 if enable {
392 cntnsar |= 1 << index;
393 } else {
394 cntnsar &= !(1 << index);
395 }
396 field!(self.regs, cntnsar).write(cntnsar);
397 }
398
399 /// Queries features of the timer.
400 pub fn features(&self, index: usize) -> Features {
401 assert!(index < 8);
402
403 let cnttidr = field_shared!(self.regs, cnttidr).read();
404 Features::from_bits_truncate((cnttidr >> (index * 8)) as u8)
405 }
406
407 /// Gets current top-level access controls for the elements of a timer frame.
408 pub fn access_control(&self, index: usize) -> CntAcr {
409 field_shared!(self.regs, cntacr).get(index).unwrap().read()
410 }
411
412 /// Sets top-level access controls for the elements of a timer frame.
413 pub fn set_access_control(&mut self, index: usize, cntacr: CntAcr) {
414 field!(self.regs, cntacr).get(index).unwrap().write(cntacr);
415 }
416
417 /// Gets the 64-bit virtual offset for frame CNTBase.
418 pub fn virtual_offset(&self, index: usize) -> u64 {
419 field_shared!(self.regs, cntvoff).get(index).unwrap().read()
420 }
421
422 /// Sets the 64-bit virtual offset for frame CNTBase. This is the offset between real time
423 /// and virtual time.
424 pub fn set_virtual_offset(&mut self, index: usize, offset: u64) {
425 field!(self.regs, cntvoff).get(index).unwrap().write(offset);
426 }
427}
428
429/// Driver for the physical or virtual timer instance of the CNTBase block.
430pub struct Timer<'a> {
431 regs: UniqueMmioPointer<'a, TimerRegs>,
432 frequency: u32,
433}
434
435impl<'a> Timer<'a> {
436 /// Creates new instance.
437 pub fn new(regs: UniqueMmioPointer<'a, TimerRegs>, frequency: u32) -> Self {
438 Self { regs, frequency }
439 }
440
441 /// Sets up timer to generate an interrupt after the given duration.
442 ///
443 /// # Safety
444 ///
445 /// The system must be prepared to take an interrupt. The vector table has to be set and the
446 /// interrupt controller must be configured properly.
447 pub unsafe fn generate_interrupt_after(&mut self, duration: Duration) {
448 self.set_deadline(duration);
449 self.set_control(TimerControl::ENABLE);
450 }
451
452 /// Disables the timer and masks the interrupt.
453 pub fn cancel_interrupt(&mut self) {
454 self.set_control(TimerControl::IMASK);
455 }
456
457 /// Blocking waits for a duration.
458 pub fn wait(&mut self, duration: Duration) {
459 self.set_deadline(duration);
460 self.set_control(TimerControl::ENABLE | TimerControl::IMASK);
461
462 while !self.control().contains(TimerControl::ISTATUS) {
463 core::hint::spin_loop();
464 }
465 }
466
467 /// Sets the compare register to trigger after the given duration.
468 fn set_deadline(&mut self, duration: Duration) {
469 let increment = self.frequency as u64 * duration.as_micros() as u64 / 1_000_000;
470
471 let value = field!(self.regs, cval).read();
472 field!(self.regs, cval).write(value + increment);
473 }
474
475 /// Reads CTL register.
476 fn control(&self) -> TimerControl {
477 field_shared!(self.regs, ctl).read()
478 }
479
480 /// Sets CTL register.
481 fn set_control(&mut self, control: TimerControl) {
482 field!(self.regs, ctl).write(control)
483 }
484}
485
486/// Driver for the CNTBase timer block.
487pub struct GenericTimerCnt<'a> {
488 regs: UniqueMmioPointer<'a, CntBase>,
489}
490
491impl<'a> GenericTimerCnt<'a> {
492 /// Creates new instance.
493 pub fn new(regs: UniqueMmioPointer<'a, CntBase>) -> Self {
494 Self { regs }
495 }
496
497 /// Gets physical count.
498 pub fn physical_count(&self) -> u64 {
499 field_shared!(self.regs, cntpct).read()
500 }
501
502 /// Gets virtual count.
503 pub fn virtual_count(&self) -> u64 {
504 field_shared!(self.regs, cntvct).read()
505 }
506
507 /// Gets frequency in Hz.
508 pub fn frequency(&self) -> u32 {
509 field_shared!(self.regs, cntfrq).read()
510 }
511
512 /// Gets second view access rights.
513 pub fn el0_access(&self) -> CntEl0Acr {
514 field_shared!(self.regs, cntel0acr).read()
515 }
516
517 /// Sets second view access rights.
518 pub fn set_el0_access(&mut self, value: CntEl0Acr) {
519 field!(self.regs, cntel0acr).write(value)
520 }
521
522 /// Gets the 64-bit virtual offset for frame CNTBase.
523 pub fn virtual_offset(&self) -> u64 {
524 field_shared!(self.regs, cntvoff).read()
525 }
526
527 /// Gets physical timer.
528 pub fn physical_timer(&mut self) -> Timer<'_> {
529 let frequency = self.frequency();
530 Timer::new(field!(self.regs, cntp), frequency)
531 }
532
533 /// Gets virtual timer.
534 pub fn virtual_timer(&mut self) -> Timer<'_> {
535 let frequency = self.frequency();
536 Timer::new(field!(self.regs, cntv), frequency)
537 }
538}
539
540/// Driver for the CNTEL0Base timer block.
541pub struct GenericTimerCntEl0<'a> {
542 regs: UniqueMmioPointer<'a, CntEl0Base>,
543}
544
545impl<'a> GenericTimerCntEl0<'a> {
546 /// Creates new instance.
547 pub fn new(regs: UniqueMmioPointer<'a, CntEl0Base>) -> Self {
548 Self { regs }
549 }
550
551 /// Gets physical count.
552 pub fn physical_count(&self) -> u64 {
553 field_shared!(self.regs, cntpct).read()
554 }
555
556 /// Gets virtual count.
557 pub fn virtual_count(&self) -> u64 {
558 field_shared!(self.regs, cntvct).read()
559 }
560
561 /// Gets frequency in Hz.
562 pub fn frequency(&self) -> u32 {
563 field_shared!(self.regs, cntfrq).read()
564 }
565
566 /// Gets physical timer.
567 pub fn physical_timer(&mut self) -> Timer<'_> {
568 let frequency = self.frequency();
569 Timer::new(field!(self.regs, cntp), frequency)
570 }
571
572 /// Gets virtual timer.
573 pub fn virtual_timer(&mut self) -> Timer<'_> {
574 let frequency = self.frequency();
575 Timer::new(field!(self.regs, cntv), frequency)
576 }
577}
578
579#[cfg(test)]
580mod tests {
581 use super::*;
582
583 #[test]
584 fn sizes() {
585 assert_eq!(0x1000, core::mem::size_of::<CntControlBase>());
586 assert_eq!(0x1000, core::mem::size_of::<CntReadBase>());
587 assert_eq!(0x1000, core::mem::size_of::<CntCtlBase>());
588 assert_eq!(0x1000, core::mem::size_of::<CntBase>());
589 assert_eq!(0x1000, core::mem::size_of::<CntEl0Base>());
590 }
591}