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 13static uint32_t 14get_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 22static uint64_t 23get_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 35void 36ARMGenericTimer::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 49void 50ARMGenericTimer::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 58bigtime_t 59ARMGenericTimer::Time() 60{ 61 return get_counter() / fTimerFrequencyMHz; 62} 63 64 65int32 66ARMGenericTimer::_InterruptWrapper(void *data) 67{ 68 return ((ARMGenericTimer*)data)->HandleInterrupt(); 69} 70 71 72int32 73ARMGenericTimer::HandleInterrupt() 74{ 75 return timer_interrupt(); 76} 77 78 79ARMGenericTimer::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 92bool 93ARMGenericTimer::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