1 /*
2 * Copyright 2022 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include "arch_timer_generic.h"
8
9
10 #define TIMER_IRQ 30
11
12
13 static uint32_t
get_counter_freq(void)14 get_counter_freq(void)
15 {
16 uint32_t freq;
17 asm volatile ("MRC p15, 0, %0, c14, c0, 0": "=r" (freq));
18 return freq;
19 }
20
21
22 static uint64_t
get_counter(void)23 get_counter(void)
24 {
25 uint32_t counter_low;
26 uint32_t counter_high;
27
28 asm volatile ("ISB\n"
29 "MRRC p15, 0, %0, %1, c14"
30 : "=r" (counter_low), "=r" (counter_high));
31 return ((uint64_t)counter_high << 32) | counter_low;
32 }
33
34
35 void
SetTimeout(bigtime_t timeout)36 ARMGenericTimer::SetTimeout(bigtime_t timeout)
37 {
38 uint32_t timeout_ticks = timeout * fTimerFrequencyMHz;
39 asm volatile ("ISB\n"
40 "MCR p15, 0, %0, c14, c2, 0"
41 : : "r"(timeout_ticks));
42
43 uint32_t timer_ctl = 1;
44 asm volatile ("MCR p15, 0, %0, c14, c2, 1"
45 : : "r"(timer_ctl));
46 }
47
48
49 void
Clear()50 ARMGenericTimer::Clear()
51 {
52 uint32_t timer_ctl = 2;
53 asm volatile ("MCR p15, 0, %0, c14, c2, 1"
54 : : "r"(timer_ctl));
55 }
56
57
58 bigtime_t
Time()59 ARMGenericTimer::Time()
60 {
61 return get_counter() / fTimerFrequencyMHz;
62 }
63
64
65 int32
_InterruptWrapper(void * data)66 ARMGenericTimer::_InterruptWrapper(void *data)
67 {
68 return ((ARMGenericTimer*)data)->HandleInterrupt();
69 }
70
71
72 int32
HandleInterrupt()73 ARMGenericTimer::HandleInterrupt()
74 {
75 return timer_interrupt();
76 }
77
78
ARMGenericTimer()79 ARMGenericTimer::ARMGenericTimer()
80 : HardwareTimer()
81 {
82 Clear();
83
84 install_io_interrupt_handler(TIMER_IRQ,
85 &ARMGenericTimer::_InterruptWrapper, this, 0);
86
87 fTimerFrequency = get_counter_freq();
88 fTimerFrequencyMHz = fTimerFrequency / 1000000;
89 }
90
91
92 bool
IsAvailable()93 ARMGenericTimer::IsAvailable()
94 {
95 uint32_t pfr1;
96 asm volatile("MRC p15, 0, %0, c0, c1, 1": "=r" (pfr1));
97 return (pfr1 & 0x000F0000) == 0x00010000;
98 }
99