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:
@@ -36,6 +36,7 @@ KernelMergeObject kernel_arch_arm.o :
|
|||||||
arch_atomic32.cpp
|
arch_atomic32.cpp
|
||||||
|
|
||||||
arch_int_gicv2.cpp
|
arch_int_gicv2.cpp
|
||||||
|
arch_timer_generic.cpp
|
||||||
|
|
||||||
# SoC minimal kernel-required support
|
# SoC minimal kernel-required support
|
||||||
# (timers, interrupts, rtc?)
|
# (timers, interrupts, rtc?)
|
||||||
|
|||||||
@@ -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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
|
|
||||||
#include <drivers/bus/FDT.h>
|
#include <drivers/bus/FDT.h>
|
||||||
|
#include "arch_timer_generic.h"
|
||||||
#include "soc.h"
|
#include "soc.h"
|
||||||
|
|
||||||
#include "soc_pxa.h"
|
#include "soc_pxa.h"
|
||||||
@@ -27,12 +28,11 @@
|
|||||||
|
|
||||||
//#define TRACE_ARCH_TIMER
|
//#define TRACE_ARCH_TIMER
|
||||||
#ifdef TRACE_ARCH_TIMER
|
#ifdef TRACE_ARCH_TIMER
|
||||||
# define TRACE(x) dprintf x
|
# define TRACE(x...) dprintf(x)
|
||||||
#else
|
#else
|
||||||
# define TRACE(x) ;
|
# define TRACE(x...) ;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//static fdt_module_info *sFdtModule;
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static struct fdt_device_info intc_table[] = {
|
static struct fdt_device_info intc_table[] = {
|
||||||
@@ -68,7 +68,15 @@ arch_timer_clear_hardware_timer()
|
|||||||
int
|
int
|
||||||
arch_init_timer(kernel_args *args)
|
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
|
#if 0
|
||||||
status_t rc = get_module(B_FDT_MODULE_NAME, (module_info**)&sFdtModule);
|
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);
|
rc = sFdtModule->setup_devices(intc_table, intc_count, NULL);
|
||||||
if (rc != B_OK)
|
if (rc != B_OK)
|
||||||
panic("No interrupt controllers found!\n");
|
panic("No hardware timer found!\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bigtime_t
|
bigtime_t
|
||||||
system_time(void)
|
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 */
|
||||||
@@ -46,20 +46,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
#if 0
|
HardwareTimer()
|
||||||
HardwareTimer(fdt_module_info *fdtModule, fdt_device_node node)
|
{
|
||||||
: fFDT(fdtModule), fNode(node) {
|
|
||||||
if (sInstance) {
|
if (sInstance) {
|
||||||
panic("Multiple HardwareTimer objects created; that is currently unsupported!");
|
panic("Multiple HardwareTimer objects created; that is currently unsupported!");
|
||||||
}
|
}
|
||||||
sInstance = this;
|
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;
|
static HardwareTimer *sInstance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user