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