kernel/arm: implement generic timer

Change-Id: I5edb7e36013d5e5d9d45ec3cf31014f99601a4c6
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5519
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Fredrik Holmqvist <[email protected]>
This commit is contained in:
David Karoly
2022-08-04 11:20:55 +00:00
parent 0263d2163f
commit bdce546c9f
5 changed files with 151 additions and 14 deletions
+1
View File
@@ -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?)
+15 -6
View File
@@ -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 <arch/cpu.h>
#include <drivers/bus/FDT.h>
#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)
{
@@ -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;
}
@@ -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 <new>
#include <SupportDefs.h>
#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 */
+2 -8
View File
@@ -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;
};