* Copyright 2022 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "arch_timer_generic.h"
#define TIMER_IRQ 30
static uint32_t
get_counter_freq(void)
{
uint32_t freq;
asm volatile ("MRC p15, 0, %0, c14, c0, 0": "=r" (freq));
return freq;
}
static uint64_t
get_counter(void)
{
uint32_t counter_low;
uint32_t counter_high;
asm volatile ("ISB\n"
"MRRC p15, 0, %0, %1, c14"
: "=r" (counter_low), "=r" (counter_high));
return ((uint64_t)counter_high << 32) | counter_low;
}
void
ARMGenericTimer::SetTimeout(bigtime_t timeout)
{
uint32_t timeout_ticks = timeout * fTimerFrequencyMHz;
asm volatile ("ISB\n"
"MCR p15, 0, %0, c14, c2, 0"
: : "r"(timeout_ticks));
uint32_t timer_ctl = 1;
asm volatile ("MCR p15, 0, %0, c14, c2, 1"
: : "r"(timer_ctl));
}
void
ARMGenericTimer::Clear()
{
uint32_t timer_ctl = 2;
asm volatile ("MCR p15, 0, %0, c14, c2, 1"
: : "r"(timer_ctl));
}
bigtime_t
ARMGenericTimer::Time()
{
return get_counter() / fTimerFrequencyMHz;
}
int32
ARMGenericTimer::_InterruptWrapper(void *data)
{
return ((ARMGenericTimer*)data)->HandleInterrupt();
}
int32
ARMGenericTimer::HandleInterrupt()
{
return timer_interrupt();
}
ARMGenericTimer::ARMGenericTimer()
: HardwareTimer()
{
Clear();
install_io_interrupt_handler(TIMER_IRQ,
&ARMGenericTimer::_InterruptWrapper, this, 0);
fTimerFrequency = get_counter_freq();
fTimerFrequencyMHz = fTimerFrequency / 1000000;
}
bool
ARMGenericTimer::IsAvailable()
{
uint32_t pfr1;
asm volatile("MRC p15, 0, %0, c0, c1, 1": "=r" (pfr1));
return (pfr1 & 0x000F0000) == 0x00010000;
}