1use crate::{Timer, TimerInterface};
5use bitflags::bitflags;
6use safe_mmio::{
7 UniqueMmioPointer, field, field_shared,
8 fields::{ReadPure, ReadPureWrite},
9};
10use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
11
12#[repr(transparent)]
14#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
15pub struct CntCr(u32);
16
17#[repr(transparent)]
19#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
20pub struct CntSr(u32);
21
22#[repr(transparent)]
24#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
25pub struct CntId(u32);
26
27#[repr(transparent)]
29#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
30pub struct CntAcr(u32);
31
32#[repr(transparent)]
34#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
35pub struct Features(u8);
36
37#[repr(transparent)]
39#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
40pub struct CntEl0Acr(u32);
41
42#[repr(transparent)]
45#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
46pub struct TimerControl(u32);
47
48bitflags! {
49 impl CntCr: u32 {
50 const SCEN = 1 << 2;
52 const HDBG = 1 << 1;
54 const EN = 1 << 0;
56 }
57
58 impl CntSr: u32 {
59 const HDBG = 1 << 1;
61 }
62
63 impl CntAcr: u32 {
64 const RWPT = 1 << 5;
66 const RWVT = 1 << 4;
68 const RVOFF = 1 << 3;
70 const RFRQ = 1 << 2;
72 const RVCT = 1 << 1;
74 const RPCT = 1 << 0;
76 }
77
78 impl Features: u8 {
79 const CNTEL0BASE = 1 << 2;
81 const VIRTUAL = 1 << 1;
83 const IMPLEMENTED = 1 << 0;
85 }
86
87 impl CntEl0Acr: u32 {
88 const EL0PTEN = 1 << 9;
90 const EL0VTEN = 1 << 8;
92 const EL0VCTEN = 1 << 1;
94 const EL0PCTEN = 1 << 0;
96 }
97
98 impl TimerControl: u32 {
99 const ISTATUS = 1 << 2;
101 const IMASK = 1 << 1;
103 const ENABLE = 1 << 0;
105 }
106}
107
108impl CntCr {
109 const FCREQ_MASK: u32 = 0x0000_03ff;
110 const FCREQ_SHIFT: u32 = 8;
111
112 pub fn set_fcreq(&mut self, index: usize) {
114 let mut value = self.0 & !(Self::FCREQ_MASK << Self::FCREQ_SHIFT);
115 value |= ((index as u32) & Self::FCREQ_MASK) << Self::FCREQ_SHIFT;
116 self.0 = value;
117 }
118}
119
120impl CntSr {
121 const FCACK_MASK: u32 = 0x0000_03ff;
122 const FCACK_SHIFT: u32 = 8;
123
124 pub fn fcack(&self) -> usize {
126 ((self.0 >> Self::FCACK_SHIFT) & Self::FCACK_MASK) as usize
127 }
128}
129
130impl CntId {
131 const CNTSC_MASK: u32 = 0b1111;
132 const CNTSC_IMPLEMENTED: u32 = 0b0001;
133
134 pub fn scaling_implemented(&self) -> bool {
136 self.0 & Self::CNTSC_MASK == Self::CNTSC_IMPLEMENTED
137 }
138}
139
140#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
142#[repr(C, align(4))]
143pub struct CntControlBase {
144 cntcr: ReadPureWrite<CntCr>,
146 cntsr: ReadPure<CntSr>,
148 cntcv: ReadPureWrite<u64>,
150 cntscr: ReadPureWrite<u32>,
152 reserved_14: [u32; 2],
153 cntid: ReadPure<CntId>,
155 cntfid: [ReadPureWrite<u32>; 40],
157 impdef_0c0: [u32; 16],
159 reserved_100: [u32; 948],
160 counter_id: [ReadPure<u32>; 12],
162}
163
164#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
166#[repr(C, align(4))]
167pub struct CntReadBase {
168 cntcv: ReadPure<u64>,
170 reserved_8: [u32; 1010],
171 counter_id: [ReadPure<u32>; 12],
173}
174
175#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
177#[repr(C, align(4))]
178pub struct CntCtlBase {
179 cntfrq: ReadPureWrite<u32>,
181 cntnsar: ReadPureWrite<u32>,
183 cnttidr: ReadPure<u32>,
185 reserved_00c: [u32; 13],
186 cntacr: [ReadPureWrite<CntAcr>; 8],
188 reserved_060: [u32; 8],
189 cntvoff: [ReadPureWrite<u64>; 8],
191 reserved_0c0: [u32; 16],
192 impdef_100: [u32; 448],
194 reserved_800: [u32; 496],
195 impdef_fc0: [u32; 4],
196 counter_id: [ReadPure<u32>; 12],
198}
199
200#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
203#[repr(C, align(4))]
204pub struct TimerRegs {
205 cval: ReadPureWrite<u64>,
207 tval: ReadPureWrite<u32>,
209 ctl: ReadPureWrite<TimerControl>,
211}
212
213#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
215#[repr(C, align(4))]
216pub struct CntBase {
217 cntpct: ReadPure<u64>,
219 cntvct: ReadPure<u64>,
221 cntfrq: ReadPure<u32>,
223 cntel0acr: ReadPureWrite<CntEl0Acr>,
225 cntvoff: ReadPure<u64>,
227 cntp: TimerRegs,
229 cntv: TimerRegs,
231 reserved: [u32; 996],
232 counter_id: [ReadPure<u32>; 12],
234}
235
236#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
240#[repr(C, align(4))]
241pub struct CntEl0Base {
242 cntpct: ReadPure<u64>,
244 cntvct: ReadPure<u64>,
246 cntfrq: ReadPure<u32>,
248 reserved_014: [u32; 3],
249 cntp: TimerRegs,
251 cntv: TimerRegs,
253 reserved: [u32; 996],
254 counter_id: [ReadPure<u32>; 12],
256}
257
258pub struct GenericTimerControl<'a> {
260 regs: UniqueMmioPointer<'a, CntControlBase>,
261}
262
263impl<'a> GenericTimerControl<'a> {
264 pub fn new(regs: UniqueMmioPointer<'a, CntControlBase>) -> Self {
266 Self { regs }
267 }
268
269 pub fn set_enable(&mut self, enable: bool) {
271 let mut cntcr = field!(self.regs, cntcr).read();
272 cntcr.set(CntCr::EN, enable);
273 field!(self.regs, cntcr).write(cntcr);
274 }
275
276 pub fn request_frequency(&mut self, index: usize) {
278 let mut cntcr = field!(self.regs, cntcr).read();
279 cntcr.set_fcreq(index);
280 field!(self.regs, cntcr).write(cntcr);
281 }
282
283 pub fn frequency_index(&self) -> usize {
285 field_shared!(self.regs, cntsr).read().fcack()
286 }
287
288 pub fn count(&self) -> u64 {
290 field_shared!(self.regs, cntcv).read()
291 }
292
293 pub fn set_count(&mut self, count: u64) {
295 field!(self.regs, cntcv).write(count);
296 }
297
298 pub fn scaling_implemented(&self) -> bool {
300 field_shared!(self.regs, cntid).read().scaling_implemented()
301 }
302
303 pub fn scale(&self) -> u32 {
305 field_shared!(self.regs, cntscr).read()
306 }
307
308 pub fn enable_scaling(&mut self, scale: u32) {
310 field!(self.regs, cntscr).write(scale);
311 let cntcr = field!(self.regs, cntcr).read();
312 field!(self.regs, cntcr).write(cntcr | CntCr::SCEN);
313 }
314
315 pub fn disable_scaling(&mut self) {
317 let cntcr = field!(self.regs, cntcr).read();
318 field!(self.regs, cntcr).write(cntcr - CntCr::SCEN);
319 field!(self.regs, cntscr).write(0);
320 }
321
322 pub fn base_frequency(&self) -> u32 {
324 field_shared!(self.regs, cntfid).get(0).unwrap().read()
325 }
326
327 pub fn frequency_mode(&self, index: usize) -> Option<u32> {
330 let frequency = field_shared!(self.regs, cntfid).get(index).unwrap().read();
331
332 if frequency != 0 {
333 Some(frequency)
334 } else {
335 None
336 }
337 }
338
339 pub fn set_frequency_mode(&mut self, index: usize, frequency: u32) {
342 field!(self.regs, cntfid)
343 .get(index)
344 .unwrap()
345 .write(frequency)
346 }
347}
348
349pub struct GenericTimerCtl<'a> {
351 regs: UniqueMmioPointer<'a, CntCtlBase>,
352}
353
354impl<'a> GenericTimerCtl<'a> {
355 pub fn new(regs: UniqueMmioPointer<'a, CntCtlBase>) -> Self {
357 Self { regs }
358 }
359
360 pub fn frequency(&self) -> u32 {
362 field_shared!(self.regs, cntfrq).read()
363 }
364
365 pub fn set_frequency(&mut self, frequency: u32) {
367 field!(self.regs, cntfrq).write(frequency);
368 }
369
370 pub fn non_secure_access(&self, index: usize) -> bool {
372 assert!(index < 8);
373
374 let cntnsar = field_shared!(self.regs, cntnsar).read();
375 cntnsar & (1 << index) != 0
376 }
377
378 pub fn set_non_secure_access(&mut self, index: usize, enable: bool) {
381 assert!(index < 8);
382
383 let mut cntnsar = field_shared!(self.regs, cntnsar).read();
384 if enable {
385 cntnsar |= 1 << index;
386 } else {
387 cntnsar &= !(1 << index);
388 }
389 field!(self.regs, cntnsar).write(cntnsar);
390 }
391
392 pub fn features(&self, index: usize) -> Features {
394 assert!(index < 8);
395
396 let cnttidr = field_shared!(self.regs, cnttidr).read();
397 Features::from_bits_truncate((cnttidr >> (index * 8)) as u8)
398 }
399
400 pub fn access_control(&self, index: usize) -> CntAcr {
402 field_shared!(self.regs, cntacr).get(index).unwrap().read()
403 }
404
405 pub fn set_access_control(&mut self, index: usize, cntacr: CntAcr) {
407 field!(self.regs, cntacr).get(index).unwrap().write(cntacr);
408 }
409
410 pub fn virtual_offset(&self, index: usize) -> u64 {
412 field_shared!(self.regs, cntvoff).get(index).unwrap().read()
413 }
414
415 pub fn set_virtual_offset(&mut self, index: usize, offset: u64) {
418 field!(self.regs, cntvoff).get(index).unwrap().write(offset);
419 }
420}
421
422pub struct MmioTimer<'a> {
425 regs: UniqueMmioPointer<'a, TimerRegs>,
426 frequency: u32,
427}
428
429impl<'a> TimerInterface for MmioTimer<'a> {
430 fn enable(&mut self) {
431 let control = field_shared!(self.regs, ctl).read();
432 field!(self.regs, ctl).write(control | TimerControl::ENABLE);
433 }
434
435 fn timer_value(&self) -> u32 {
436 field_shared!(self.regs, tval).read()
437 }
438
439 fn frequency(&self) -> u32 {
440 self.frequency
441 }
442}
443
444pub struct GenericTimerCnt<'a> {
446 regs: UniqueMmioPointer<'a, CntBase>,
447}
448
449impl<'a> GenericTimerCnt<'a> {
450 pub fn new(regs: UniqueMmioPointer<'a, CntBase>) -> Self {
452 Self { regs }
453 }
454
455 pub fn physical_count(&self) -> u64 {
457 field_shared!(self.regs, cntpct).read()
458 }
459
460 pub fn virtual_count(&self) -> u64 {
462 field_shared!(self.regs, cntvct).read()
463 }
464
465 pub fn frequency(&self) -> u32 {
467 field_shared!(self.regs, cntfrq).read()
468 }
469
470 pub fn el0_access(&self) -> CntEl0Acr {
472 field_shared!(self.regs, cntel0acr).read()
473 }
474
475 pub fn set_el0_access(&mut self, value: CntEl0Acr) {
477 field!(self.regs, cntel0acr).write(value)
478 }
479
480 pub fn virtual_offset(&self) -> u64 {
482 field_shared!(self.regs, cntvoff).read()
483 }
484
485 pub fn physical_timer(&mut self) -> Timer<MmioTimer<'_>> {
487 let frequency = self.frequency();
488 Timer::new(MmioTimer {
489 regs: field!(self.regs, cntp),
490 frequency,
491 })
492 }
493
494 pub fn virtual_timer(&mut self) -> Timer<MmioTimer<'_>> {
496 let frequency = self.frequency();
497 Timer::new(MmioTimer {
498 regs: field!(self.regs, cntv),
499 frequency,
500 })
501 }
502}
503
504pub struct GenericTimerCntEl0<'a> {
506 regs: UniqueMmioPointer<'a, CntEl0Base>,
507}
508
509impl<'a> GenericTimerCntEl0<'a> {
510 pub fn new(regs: UniqueMmioPointer<'a, CntEl0Base>) -> Self {
512 Self { regs }
513 }
514
515 pub fn physical_count(&self) -> u64 {
517 field_shared!(self.regs, cntpct).read()
518 }
519
520 pub fn virtual_count(&self) -> u64 {
522 field_shared!(self.regs, cntvct).read()
523 }
524
525 pub fn frequency(&self) -> u32 {
527 field_shared!(self.regs, cntfrq).read()
528 }
529
530 pub fn physical_timer(&mut self) -> Timer<MmioTimer<'_>> {
532 let frequency = self.frequency();
533 Timer::new(MmioTimer {
534 regs: field!(self.regs, cntp),
535 frequency,
536 })
537 }
538
539 pub fn virtual_timer(&mut self) -> Timer<MmioTimer<'_>> {
541 let frequency = self.frequency();
542 Timer::new(MmioTimer {
543 regs: field!(self.regs, cntv),
544 frequency,
545 })
546 }
547}
548
549#[cfg(test)]
550mod tests {
551 use super::*;
552
553 #[test]
554 fn sizes() {
555 assert_eq!(0x1000, core::mem::size_of::<CntControlBase>());
556 assert_eq!(0x1000, core::mem::size_of::<CntReadBase>());
557 assert_eq!(0x1000, core::mem::size_of::<CntCtlBase>());
558 assert_eq!(0x1000, core::mem::size_of::<CntBase>());
559 assert_eq!(0x1000, core::mem::size_of::<CntEl0Base>());
560 }
561}