From bdce546c9f1e9339cf11a0d1999042bcc2656f46 Mon Sep 17 00:00:00 2001 From: David Karoly Date: Sat, 30 Jul 2022 21:05:57 +0200 Subject: [PATCH] kernel/arm: implement generic timer Change-Id: I5edb7e36013d5e5d9d45ec3cf31014f99601a4c6 Reviewed-on: https://review.haiku-os.org/c/haiku/+/5519 Tested-by: Commit checker robot Reviewed-by: Fredrik Holmqvist --- src/system/kernel/arch/arm/Jamfile | 1 + src/system/kernel/arch/arm/arch_timer.cpp | 21 ++-- .../kernel/arch/arm/arch_timer_generic.cpp | 98 +++++++++++++++++++ .../kernel/arch/arm/arch_timer_generic.h | 35 +++++++ src/system/kernel/arch/arm/soc.h | 10 +- 5 files changed, 151 insertions(+), 14 deletions(-) create mode 100644 src/system/kernel/arch/arm/arch_timer_generic.cpp create mode 100644 src/system/kernel/arch/arm/arch_timer_generic.h diff --git a/src/system/kernel/arch/arm/Jamfile b/src/system/kernel/arch/arm/Jamfile index 546627358d..c995490d64 100644 --- a/src/system/kernel/arch/arm/Jamfile +++ b/src/system/kernel/arch/arm/Jamfile @@ -36,6 +36,7 @@ KernelMergeObject kernel_arch_arm.o : arch_atomic32.cpp arch_int_gicv2.cpp + arch_timer_generic.cpp # SoC minimal kernel-required support # (timers, interrupts, rtc?) diff --git a/src/system/kernel/arch/arm/arch_timer.cpp b/src/system/kernel/arch/arm/arch_timer.cpp index 52096afa01..b98302bc78 100644 --- a/src/system/kernel/arch/arm/arch_timer.cpp +++ b/src/system/kernel/arch/arm/arch_timer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2007-2021, Haiku Inc. All rights reserved. + * Copyright 2007-2022, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -20,6 +20,7 @@ #include #include +#include "arch_timer_generic.h" #include "soc.h" #include "soc_pxa.h" @@ -27,12 +28,11 @@ //#define TRACE_ARCH_TIMER #ifdef TRACE_ARCH_TIMER -# define TRACE(x) dprintf x +# define TRACE(x...) dprintf(x) #else -# define TRACE(x) ; +# define TRACE(x...) ; #endif -//static fdt_module_info *sFdtModule; #if 0 static struct fdt_device_info intc_table[] = { @@ -68,7 +68,15 @@ arch_timer_clear_hardware_timer() int arch_init_timer(kernel_args *args) { - TRACE(("%s\n", __func__)); + TRACE("%s\n", __func__); + + if (ARMGenericTimer::IsAvailable()) { + TRACE("init ARMv7 generic timer\n"); + ARMGenericTimer::Init(); + } + + //TODO: use SoC-specific timer as a fallback + //if the generic timer is not available #if 0 status_t rc = get_module(B_FDT_MODULE_NAME, (module_info**)&sFdtModule); @@ -77,12 +85,13 @@ arch_init_timer(kernel_args *args) rc = sFdtModule->setup_devices(intc_table, intc_count, NULL); if (rc != B_OK) - panic("No interrupt controllers found!\n"); + panic("No hardware timer found!\n"); #endif return B_OK; } + bigtime_t system_time(void) { diff --git a/src/system/kernel/arch/arm/arch_timer_generic.cpp b/src/system/kernel/arch/arm/arch_timer_generic.cpp new file mode 100644 index 0000000000..142b749f36 --- /dev/null +++ b/src/system/kernel/arch/arm/arch_timer_generic.cpp @@ -0,0 +1,98 @@ +/* + * 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 * fTimerFrequency / 1000000; + 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() / fTimerFrequency; +} + + +int32 +ARMGenericTimer::_InterruptWrapper(void *data) +{ + return ((ARMGenericTimer*)data)->HandleInterrupt(); +} + + +int32 +ARMGenericTimer::HandleInterrupt() +{ + return timer_interrupt(); +} + + +ARMGenericTimer::ARMGenericTimer() +: HardwareTimer() +{ + Clear(); + + reserve_io_interrupt_vectors(1, TIMER_IRQ, INTERRUPT_TYPE_IRQ); + install_io_interrupt_handler(TIMER_IRQ, + &ARMGenericTimer::_InterruptWrapper, this, 0); + + fTimerFrequency = get_counter_freq(); +} + + +bool +ARMGenericTimer::IsAvailable() +{ + uint32_t pfr1; + asm volatile("MRC p15, 0, %0, c0, c1, 1": "=r" (pfr1)); + return (pfr1 & 0x000F0000) == 0x00010000; +} diff --git a/src/system/kernel/arch/arm/arch_timer_generic.h b/src/system/kernel/arch/arm/arch_timer_generic.h new file mode 100644 index 0000000000..7d1e66234a --- /dev/null +++ b/src/system/kernel/arch/arm/arch_timer_generic.h @@ -0,0 +1,35 @@ +/* + * Copyright 2022 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef ARCH_ARM_TIMER_GENERIC_H +#define ARCH_ARM_TIMER_GENERIC_H + +#include +#include + +#include "soc.h" + +class ARMGenericTimer : public HardwareTimer { +public: + void SetTimeout(bigtime_t timeout); + void Clear(); + bigtime_t Time(); + + static status_t Init() { + ARMGenericTimer *timer = new(std::nothrow) ARMGenericTimer(); + return timer != NULL ? B_OK : B_NO_MEMORY; + } + + static bool IsAvailable(); +protected: + ARMGenericTimer(); + +private: + static int32 _InterruptWrapper(void *data); + int32 HandleInterrupt(); + + uint32_t fTimerFrequency; +}; + +#endif /* ARCH_ARM_TIMER_GENERIC_H */ diff --git a/src/system/kernel/arch/arm/soc.h b/src/system/kernel/arch/arm/soc.h index 3bbfcb6131..c3921b1223 100644 --- a/src/system/kernel/arch/arm/soc.h +++ b/src/system/kernel/arch/arm/soc.h @@ -46,20 +46,14 @@ public: } protected: -#if 0 - HardwareTimer(fdt_module_info *fdtModule, fdt_device_node node) - : fFDT(fdtModule), fNode(node) { + HardwareTimer() + { if (sInstance) { panic("Multiple HardwareTimer objects created; that is currently unsupported!"); } sInstance = this; } - // Keep our node around as we might want to grab attributes from it - fdt_module_info *fFDT; - fdt_device_node fNode; -#endif - static HardwareTimer *sInstance; };