1use crate::{CounterInterface, Timer, TimerInterface};
9use bitflags::bitflags;
10use safe_mmio::{
11 SharedMmioPointer, UniqueMmioPointer, field, field_shared,
12 fields::{ReadPure, ReadPureWrite},
13};
14use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
15
16#[repr(transparent)]
18#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
19pub struct CntCr(u32);
20
21#[repr(transparent)]
23#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
24pub struct CntSr(u32);
25
26#[repr(transparent)]
28#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
29pub struct CntId(u32);
30
31#[repr(transparent)]
33#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
34pub struct CntAcr(u32);
35
36#[repr(transparent)]
38#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
39pub struct Features(u8);
40
41#[repr(transparent)]
43#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
44pub struct CntEl0Acr(u32);
45
46#[repr(transparent)]
49#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
50pub struct TimerControl(u32);
51
52bitflags! {
53 impl CntCr: u32 {
54 const SCEN = 1 << 2;
56 const HDBG = 1 << 1;
58 const EN = 1 << 0;
60 }
61
62 impl CntSr: u32 {
63 const HDBG = 1 << 1;
65 }
66
67 impl CntAcr: u32 {
68 const RWPT = 1 << 5;
70 const RWVT = 1 << 4;
72 const RVOFF = 1 << 3;
74 const RFRQ = 1 << 2;
76 const RVCT = 1 << 1;
78 const RPCT = 1 << 0;
80 }
81
82 impl Features: u8 {
83 const CNTEL0BASE = 1 << 2;
85 const VIRTUAL = 1 << 1;
87 const IMPLEMENTED = 1 << 0;
89 }
90
91 impl CntEl0Acr: u32 {
92 const EL0PTEN = 1 << 9;
94 const EL0VTEN = 1 << 8;
96 const EL0VCTEN = 1 << 1;
98 const EL0PCTEN = 1 << 0;
100 }
101
102 impl TimerControl: u32 {
103 const ISTATUS = 1 << 2;
105 const IMASK = 1 << 1;
107 const ENABLE = 1 << 0;
109 }
110}
111
112impl CntCr {
113 const FCREQ_MASK: u32 = 0x0000_03ff;
114 const FCREQ_SHIFT: u32 = 8;
115
116 pub fn set_fcreq(&mut self, index: usize) {
118 let mut value = self.0 & !(Self::FCREQ_MASK << Self::FCREQ_SHIFT);
119 value |= ((index as u32) & Self::FCREQ_MASK) << Self::FCREQ_SHIFT;
120 self.0 = value;
121 }
122}
123
124impl CntSr {
125 const FCACK_MASK: u32 = 0x0000_03ff;
126 const FCACK_SHIFT: u32 = 8;
127
128 pub fn fcack(&self) -> usize {
130 ((self.0 >> Self::FCACK_SHIFT) & Self::FCACK_MASK) as usize
131 }
132}
133
134impl CntId {
135 const CNTSC_MASK: u32 = 0b1111;
136 const CNTSC_IMPLEMENTED: u32 = 0b0001;
137
138 pub fn scaling_implemented(&self) -> bool {
140 self.0 & Self::CNTSC_MASK == Self::CNTSC_IMPLEMENTED
141 }
142}
143
144#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
146#[repr(C, align(4))]
147pub struct CntControlBase {
148 cntcr: ReadPureWrite<CntCr>,
150 cntsr: ReadPure<CntSr>,
152 cntcv: ReadPureWrite<u64>,
154 cntscr: ReadPureWrite<u32>,
156 reserved_14: [u32; 2],
157 cntid: ReadPure<CntId>,
159 cntfid: [ReadPureWrite<u32>; 40],
161 impdef_0c0: [u32; 16],
163 reserved_100: [u32; 948],
164 counter_id: [ReadPure<u32>; 12],
166}
167
168#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
170#[repr(C, align(4))]
171pub struct CntReadBase {
172 cntcv: ReadPure<u64>,
174 reserved_8: [u32; 1010],
175 counter_id: [ReadPure<u32>; 12],
177}
178
179#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
181#[repr(C, align(4))]
182pub struct CntCtlBase {
183 cntfrq: ReadPureWrite<u32>,
185 cntnsar: ReadPureWrite<u32>,
187 cnttidr: ReadPure<u32>,
189 reserved_00c: [u32; 13],
190 cntacr: [ReadPureWrite<CntAcr>; 8],
192 reserved_060: [u32; 8],
193 cntvoff: [ReadPureWrite<u64>; 8],
195 reserved_0c0: [u32; 16],
196 impdef_100: [u32; 448],
198 reserved_800: [u32; 496],
199 impdef_fc0: [u32; 4],
200 counter_id: [ReadPure<u32>; 12],
202}
203
204#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
207#[repr(C, align(4))]
208pub struct TimerRegs {
209 cval: ReadPureWrite<u64>,
211 tval: ReadPureWrite<i32>,
213 ctl: ReadPureWrite<TimerControl>,
215}
216
217#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
219#[repr(C, align(4))]
220pub struct CntBase {
221 cntpct: ReadPure<u64>,
223 cntvct: ReadPure<u64>,
225 cntfrq: ReadPure<u32>,
227 cntel0acr: ReadPureWrite<CntEl0Acr>,
229 cntvoff: ReadPure<u64>,
231 cntp: TimerRegs,
233 cntv: TimerRegs,
235 reserved: [u32; 996],
236 counter_id: [ReadPure<u32>; 12],
238}
239
240#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
244#[repr(C, align(4))]
245pub struct CntEl0Base {
246 cntpct: ReadPure<u64>,
248 cntvct: ReadPure<u64>,
250 cntfrq: ReadPure<u32>,
252 reserved_014: [u32; 3],
253 cntp: TimerRegs,
255 cntv: TimerRegs,
257 reserved: [u32; 996],
258 counter_id: [ReadPure<u32>; 12],
260}
261
262pub struct GenericTimerControl<'a> {
264 regs: UniqueMmioPointer<'a, CntControlBase>,
265}
266
267impl<'a> GenericTimerControl<'a> {
268 pub fn new(regs: UniqueMmioPointer<'a, CntControlBase>) -> Self {
270 Self { regs }
271 }
272
273 pub fn set_enable(&mut self, enable: bool) {
275 let mut cntcr = field!(self.regs, cntcr).read();
276 cntcr.set(CntCr::EN, enable);
277 field!(self.regs, cntcr).write(cntcr);
278 }
279
280 pub fn request_frequency(&mut self, index: usize) {
282 let mut cntcr = field!(self.regs, cntcr).read();
283 cntcr.set_fcreq(index);
284 field!(self.regs, cntcr).write(cntcr);
285 }
286
287 pub fn frequency_index(&self) -> usize {
289 field_shared!(self.regs, cntsr).read().fcack()
290 }
291
292 pub fn count(&self) -> u64 {
294 field_shared!(self.regs, cntcv).read()
295 }
296
297 pub fn set_count(&mut self, count: u64) {
299 field!(self.regs, cntcv).write(count);
300 }
301
302 pub fn scaling_implemented(&self) -> bool {
304 field_shared!(self.regs, cntid).read().scaling_implemented()
305 }
306
307 pub fn scale(&self) -> u32 {
309 field_shared!(self.regs, cntscr).read()
310 }
311
312 pub fn enable_scaling(&mut self, scale: u32) {
314 field!(self.regs, cntscr).write(scale);
315 let cntcr = field!(self.regs, cntcr).read();
316 field!(self.regs, cntcr).write(cntcr | CntCr::SCEN);
317 }
318
319 pub fn disable_scaling(&mut self) {
321 let cntcr = field!(self.regs, cntcr).read();
322 field!(self.regs, cntcr).write(cntcr - CntCr::SCEN);
323 field!(self.regs, cntscr).write(0);
324 }
325
326 pub fn base_frequency(&self) -> u32 {
328 field_shared!(self.regs, cntfid).get(0).unwrap().read()
329 }
330
331 pub fn frequency_mode(&self, index: usize) -> Option<u32> {
334 let frequency = field_shared!(self.regs, cntfid).get(index).unwrap().read();
335
336 if frequency != 0 {
337 Some(frequency)
338 } else {
339 None
340 }
341 }
342
343 pub fn set_frequency_mode(&mut self, index: usize, frequency: u32) {
346 field!(self.regs, cntfid)
347 .get(index)
348 .unwrap()
349 .write(frequency)
350 }
351}
352
353pub struct GenericTimerCtl<'a> {
355 regs: UniqueMmioPointer<'a, CntCtlBase>,
356}
357
358impl<'a> GenericTimerCtl<'a> {
359 pub fn new(regs: UniqueMmioPointer<'a, CntCtlBase>) -> Self {
361 Self { regs }
362 }
363
364 pub fn frequency(&self) -> u32 {
366 field_shared!(self.regs, cntfrq).read()
367 }
368
369 pub fn set_frequency(&mut self, frequency: u32) {
371 field!(self.regs, cntfrq).write(frequency);
372 }
373
374 pub fn non_secure_access(&self, index: usize) -> bool {
376 assert!(index < 8);
377
378 let cntnsar = field_shared!(self.regs, cntnsar).read();
379 cntnsar & (1 << index) != 0
380 }
381
382 pub fn set_non_secure_access(&mut self, index: usize, enable: bool) {
385 assert!(index < 8);
386
387 let mut cntnsar = field_shared!(self.regs, cntnsar).read();
388 if enable {
389 cntnsar |= 1 << index;
390 } else {
391 cntnsar &= !(1 << index);
392 }
393 field!(self.regs, cntnsar).write(cntnsar);
394 }
395
396 pub fn features(&self, index: usize) -> Features {
398 assert!(index < 8);
399
400 let cnttidr = field_shared!(self.regs, cnttidr).read();
401 Features::from_bits_truncate((cnttidr >> (index * 8)) as u8)
402 }
403
404 pub fn access_control(&self, index: usize) -> CntAcr {
406 field_shared!(self.regs, cntacr).get(index).unwrap().read()
407 }
408
409 pub fn set_access_control(&mut self, index: usize, cntacr: CntAcr) {
411 field!(self.regs, cntacr).get(index).unwrap().write(cntacr);
412 }
413
414 pub fn virtual_offset(&self, index: usize) -> u64 {
416 field_shared!(self.regs, cntvoff).get(index).unwrap().read()
417 }
418
419 pub fn set_virtual_offset(&mut self, index: usize, offset: u64) {
422 field!(self.regs, cntvoff).get(index).unwrap().write(offset);
423 }
424}
425
426pub struct MmioTimer<'a> {
429 regs: UniqueMmioPointer<'a, TimerRegs>,
430 frequency: u32,
431}
432
433impl<'a> TimerInterface for MmioTimer<'a> {
434 fn enable(&mut self) {
435 let control = field_shared!(self.regs, ctl).read();
436 field!(self.regs, ctl).write(control | TimerControl::ENABLE);
437 }
438
439 fn timer_value(&self) -> i32 {
440 field_shared!(self.regs, tval).read()
441 }
442
443 fn frequency(&self) -> u32 {
444 self.frequency
445 }
446
447 fn enable_interrupt(&mut self, enabled: bool) {
448 let mut control = field_shared!(self.regs, ctl).read();
449 control.set(TimerControl::IMASK, !enabled);
450
451 field!(self.regs, ctl).write(control);
452 }
453
454 fn compare_value(&self) -> u64 {
455 field_shared!(self.regs, cval).read()
456 }
457
458 fn set_timer_value(&mut self, timer_value: i32) {
459 field!(self.regs, tval).write(timer_value);
460 }
461
462 fn set_compare_value(&mut self, compare_value: u64) {
463 field!(self.regs, cval).write(compare_value);
464 }
465}
466
467pub struct MmioCounter<'a> {
469 counter: SharedMmioPointer<'a, ReadPure<u64>>,
470 frequency: u32,
471}
472
473impl CounterInterface for MmioCounter<'_> {
474 fn counter_value(&self) -> u64 {
475 self.counter.read()
476 }
477
478 fn frequency(&self) -> u32 {
479 self.frequency
480 }
481}
482
483pub struct GenericTimerCnt<'a> {
485 regs: UniqueMmioPointer<'a, CntBase>,
486}
487
488impl<'a> GenericTimerCnt<'a> {
489 pub fn new(regs: UniqueMmioPointer<'a, CntBase>) -> Self {
491 Self { regs }
492 }
493
494 pub fn physical_count(&self) -> u64 {
496 field_shared!(self.regs, cntpct).read()
497 }
498
499 pub fn virtual_count(&self) -> u64 {
501 field_shared!(self.regs, cntvct).read()
502 }
503
504 pub fn frequency(&self) -> u32 {
506 field_shared!(self.regs, cntfrq).read()
507 }
508
509 pub fn el0_access(&self) -> CntEl0Acr {
511 field_shared!(self.regs, cntel0acr).read()
512 }
513
514 pub fn set_el0_access(&mut self, value: CntEl0Acr) {
516 field!(self.regs, cntel0acr).write(value)
517 }
518
519 pub fn virtual_offset(&self) -> u64 {
521 field_shared!(self.regs, cntvoff).read()
522 }
523
524 pub fn physical_timer(&mut self) -> Timer<MmioTimer<'_>> {
526 let frequency = self.frequency();
527 Timer::new(MmioTimer {
528 regs: field!(self.regs, cntp),
529 frequency,
530 })
531 }
532
533 pub fn virtual_timer(&mut self) -> Timer<MmioTimer<'_>> {
535 let frequency = self.frequency();
536 Timer::new(MmioTimer {
537 regs: field!(self.regs, cntv),
538 frequency,
539 })
540 }
541
542 pub fn physical_counter(&self) -> MmioCounter<'_> {
544 let frequency = self.frequency();
545 MmioCounter {
546 counter: field_shared!(self.regs, cntpct),
547 frequency,
548 }
549 }
550
551 pub fn virtual_counter(&self) -> MmioCounter<'_> {
553 let frequency = self.frequency();
554 MmioCounter {
555 counter: field_shared!(self.regs, cntvct),
556 frequency,
557 }
558 }
559}
560
561pub struct GenericTimerCntEl0<'a> {
563 regs: UniqueMmioPointer<'a, CntEl0Base>,
564}
565
566impl<'a> GenericTimerCntEl0<'a> {
567 pub fn new(regs: UniqueMmioPointer<'a, CntEl0Base>) -> Self {
569 Self { regs }
570 }
571
572 pub fn physical_count(&self) -> u64 {
574 field_shared!(self.regs, cntpct).read()
575 }
576
577 pub fn virtual_count(&self) -> u64 {
579 field_shared!(self.regs, cntvct).read()
580 }
581
582 pub fn frequency(&self) -> u32 {
584 field_shared!(self.regs, cntfrq).read()
585 }
586
587 pub fn physical_timer(&mut self) -> Timer<MmioTimer<'_>> {
589 let frequency = self.frequency();
590 Timer::new(MmioTimer {
591 regs: field!(self.regs, cntp),
592 frequency,
593 })
594 }
595
596 pub fn virtual_timer(&mut self) -> Timer<MmioTimer<'_>> {
598 let frequency = self.frequency();
599 Timer::new(MmioTimer {
600 regs: field!(self.regs, cntv),
601 frequency,
602 })
603 }
604
605 pub fn physical_counter(&self) -> MmioCounter<'_> {
607 let frequency = self.frequency();
608 MmioCounter {
609 counter: field_shared!(self.regs, cntpct),
610 frequency,
611 }
612 }
613
614 pub fn virtual_counter(&self) -> MmioCounter<'_> {
616 let frequency = self.frequency();
617 MmioCounter {
618 counter: field_shared!(self.regs, cntvct),
619 frequency,
620 }
621 }
622}
623
624#[cfg(test)]
625mod tests {
626 use super::*;
627
628 #[test]
629 fn sizes() {
630 assert_eq!(0x1000, core::mem::size_of::<CntControlBase>());
631 assert_eq!(0x1000, core::mem::size_of::<CntReadBase>());
632 assert_eq!(0x1000, core::mem::size_of::<CntCtlBase>());
633 assert_eq!(0x1000, core::mem::size_of::<CntBase>());
634 assert_eq!(0x1000, core::mem::size_of::<CntEl0Base>());
635 }
636}