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 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 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 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 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 59 ARMGenericTimer::Time() 60 { 61 return get_counter() / fTimerFrequencyMHz; 62 } 63 64 65 int32 66 ARMGenericTimer::_InterruptWrapper(void *data) 67 { 68 return ((ARMGenericTimer*)data)->HandleInterrupt(); 69 } 70 71 72 int32 73 ARMGenericTimer::HandleInterrupt() 74 { 75 return timer_interrupt(); 76 } 77 78 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 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