/* * 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; }