arm: detect SoC timer from FDT for OMAP3 and PXA

Change-Id: Ib03a11f016cb937d748d2696a17158e17c86e317
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5522
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Reviewed-by: David Karoly <karolyd577@gmail.com>
This commit is contained in:
David Karoly 2022-08-09 15:45:31 +02:00
parent 0404f954c1
commit fe2b6d7706
10 changed files with 97 additions and 55 deletions

View File

@ -12,6 +12,7 @@
#include <util/FixedWidthPointer.h>
#include <boot/interrupt_controller.h>
#include <boot/timer.h>
#include <boot/uart.h>
@ -42,8 +43,9 @@ typedef struct {
FixedWidthPointer<void> acpi_root;
FixedWidthPointer<void> fdt;
uart_info uart;
intc_info interrupt_controller;
uart_info uart;
intc_info interrupt_controller;
boot_timer_info timer;
} _PACKED arch_kernel_args;
#endif /* KERNEL_ARCH_ARM_KERNEL_ARGS_H */

View File

@ -0,0 +1,25 @@
/*
* Copyright 2022 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef KERNEL_BOOT_TIMER_H
#define KERNEL_BOOT_TIMER_H
#include <boot/addr_range.h>
#include <SupportDefs.h>
#define TIMER_KIND_ARMV7 "armv7"
#define TIMER_KIND_OMAP3 "omap3"
#define TIMER_KIND_PXA "pxa"
typedef struct {
char kind[32];
addr_range regs;
uint32_t interrupt;
} __attribute__((packed)) boot_timer_info;
#endif /* KERNEL_BOOT_TIMER_H */

View File

@ -32,6 +32,16 @@ const struct supported_interrupt_controllers {
};
const struct supported_timers {
const char* dtb_compat;
const char* kind;
} kSupportedTimers[] = {
{ "arm,armv7-timer", TIMER_KIND_ARMV7 },
{ "ti,omap3430-timer", TIMER_KIND_OMAP3 },
{ "marvell,pxa-timers", TIMER_KIND_PXA },
};
void
arch_handle_fdt(const void* fdt, int node)
{
@ -73,6 +83,21 @@ arch_handle_fdt(const void* fdt, int node)
}
}
}
boot_timer_info &timer = gKernelArgs.arch_args.timer;
if (timer.kind[0] == 0) {
for (uint32 i = 0; i < B_COUNT_OF(kSupportedTimers); i++) {
if (dtb_has_fdt_string(compatible, compatibleLen,
kSupportedTimers[i].dtb_compat)) {
memcpy(timer.kind, kSupportedTimers[i].kind,
sizeof(timer.kind));
dtb_get_reg(fdt, node, 0, timer.regs);
timer.interrupt = dtb_get_interrupt(fdt, node);
}
}
}
}
@ -92,4 +117,16 @@ arch_dtb_set_kernel_args(void)
interrupt_controller.regs2.start,
interrupt_controller.regs2.size);
}
boot_timer_info &timer = gKernelArgs.arch_args.timer;
dprintf("Chosen timer:\n");
if (timer.kind[0] == 0) {
dprintf("kind: None!\n");
} else {
dprintf(" kind: %s\n", timer.kind);
dprintf(" regs: %#" B_PRIx64 ", %#" B_PRIx64 "\n",
timer.regs.start,
timer.regs.size);
dprintf(" irq: %" B_PRIu32 "\n", timer.interrupt);
}
}

View File

@ -482,7 +482,7 @@ dtb_get_interrupt_cells(const void* fdt, int node)
}
static uint32
uint32
dtb_get_interrupt(const void* fdt, int node)
{
uint32 interruptCells = dtb_get_interrupt_cells(fdt, node);

View File

@ -16,6 +16,7 @@ extern void dtb_init();
extern void dtb_set_kernel_args();
bool dtb_get_reg(const void* fdt, int node, size_t idx, addr_range& range);
uint32 dtb_get_interrupt(const void* fdt, int node);
bool dtb_has_fdt_string(const char* prop, int size, const char* pattern);

View File

@ -34,20 +34,6 @@
#endif
#if 0
static struct fdt_device_info intc_table[] = {
{
.compatible = "marvell,pxa-timers", // XXX not in FDT (also not in upstream!)
.init = PXATimer::Init,
}, {
.compatible = "ti,omap3430-timer",
.init = OMAP3Timer::Init,
}
};
static int intc_count = sizeof(intc_table) / sizeof(struct fdt_device_info);
#endif
void
arch_timer_set_hardware_timer(bigtime_t timeout)
{
@ -73,20 +59,16 @@ arch_init_timer(kernel_args *args)
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);
if (rc != B_OK)
panic("Unable to get FDT module: %08lx!\n", rc);
rc = sFdtModule->setup_devices(intc_table, intc_count, NULL);
if (rc != B_OK)
} else if (strncmp(args->arch_args.timer.kind, TIMER_KIND_OMAP3,
sizeof(args->arch_args.timer.kind)) == 0) {
OMAP3Timer::Init(args->arch_args.timer.regs.start,
args->arch_args.timer.interrupt);
} else if (strncmp(args->arch_args.timer.kind, TIMER_KIND_PXA,
sizeof(args->arch_args.timer.kind)) == 0) {
PXATimer::Init(args->arch_args.timer.regs.start);
} else {
panic("No hardware timer found!\n");
#endif
}
return B_OK;
}

View File

@ -79,7 +79,7 @@ OMAP3InterruptController::SoftReset()
{
uint32 tmp = fRegBase[INTCPS_REVISION] & 0xff;
dprintf("OMAP: INTC found at 0x%p (rev %ld.%ld)\n",
dprintf("OMAP: INTC found at 0x%p (rev %" B_PRIu32 ".%" B_PRIu32 ")\n",
fRegBase, tmp >> 4, tmp & 0xf);
tmp = fRegBase[INTCPS_SYSCONFIG];
@ -184,21 +184,22 @@ OMAP3Timer::Clear()
}
#if 0
OMAP3Timer::OMAP3Timer(fdt_module_info *fdtModule, fdt_device_node node)
: HardwareTimer(fdtModule, node),
fSystemTime(0)
OMAP3Timer::OMAP3Timer(uint32_t reg_base, uint32_t interrupt)
: fSystemTime(0)
{
fRegArea = fFDT->map_reg_range(node, 0, (void**)&fRegBase);
fRegArea = vm_map_physical_memory(B_SYSTEM_TEAM, "timer-omap3", (void**)&fRegBase,
B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
reg_base, false);
if (fRegArea < 0)
panic("Cannot map OMAP3Timer registers!");
fInterrupt = fFDT->get_interrupt(node, 0);
fInterrupt = interrupt;
if (fInterrupt < 0)
panic("Cannot get OMAP3Timer interrupt!");
uint32 rev = fRegBase[TIDR];
dprintf("OMAP: Found timer @ 0x%p, IRQ %d (rev %ld.%ld)\n", fRegBase, fInterrupt, (rev >> 4) & 0xf, rev & 0xf);
dprintf("OMAP: Found timer @ 0x%p, IRQ %d (rev %" B_PRIu32 ".%" B_PRIu32 ")\n",
fRegBase, fInterrupt, (rev >> 4) & 0xf, rev & 0xf);
// Let the timer run (so we can use it as clocksource)
fRegBase[TCLR] |= 1;
@ -206,4 +207,3 @@ OMAP3Timer::OMAP3Timer(fdt_module_info *fdtModule, fdt_device_node node)
install_io_interrupt_handler(fInterrupt, &OMAP3Timer::_InterruptWrapper, this, 0);
}
#endif

View File

@ -29,10 +29,9 @@ public:
bigtime_t Time();
void Clear();
#if 0
static status_t Init(fdt_module_info *fdt, fdt_device_node node, void *cookie) {
static status_t Init(uint32_t reg_base, uint32_t interrupt) {
if (sInstance == NULL) {
OMAP3Timer *timer = new(std::nothrow) OMAP3Timer(fdt, node);
OMAP3Timer *timer = new(std::nothrow) OMAP3Timer(reg_base, interrupt);
// XXX implement InitCheck() functionality
return timer != NULL ? B_OK : B_NO_MEMORY;
} else {
@ -41,10 +40,9 @@ public:
return B_OK;
}
}
#endif
private:
//OMAP3Timer(fdt_module_info *fdtModule, fdt_device_node node);
OMAP3Timer(uint32_t reg_base, uint32_t interrupt);
static int32 _InterruptWrapper(void *data);
int32 HandleInterrupt();

View File

@ -92,7 +92,7 @@ PXATimer::SetTimeout(bigtime_t timeout)
}
}
dprintf("arch_timer_set_hardware_timer(val=%lu, res=%lu)\n", val, res);
dprintf("arch_timer_set_hardware_timer(val=%" B_PRIu32 ", res=%" B_PRIu32 ")\n", val, res);
fRegBase[PXA_OIER] |= (1 << 4);
fRegBase[PXA_OMCR4] = res;
fRegBase[PXA_OSMR4] = val;
@ -143,11 +143,11 @@ PXATimer::HandleInterrupt()
}
#if 0
PXATimer::PXATimer(fdt_module_info *fdt, fdt_device_node node)
: HardwareTimer(fdt, node)
PXATimer::PXATimer(uint32_t reg_base)
{
fRegArea = fFDT->map_reg_range(node, 0, (void**)&fRegBase);
fRegArea = vm_map_physical_memory(B_SYSTEM_TEAM, "pxa-timer", (void**)&fRegBase,
B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
reg_base, false);
if (fRegArea < 0)
panic("Cannot map PXATimer registers!");
@ -158,4 +158,3 @@ PXATimer::PXATimer(fdt_module_info *fdt, fdt_device_node node)
install_io_interrupt_handler(PXA_TIMERS_INTERRUPT, &PXATimer::_InterruptWrapper, NULL, 0);
}
#endif

View File

@ -27,16 +27,14 @@ public:
void Clear();
bigtime_t Time();
#if 0
static status_t Init(fdt_module_info *fdt, fdt_device_node node, void *cookie) {
PXATimer *timer = new(std::nothrow) PXATimer(fdt, node);
static status_t Init(uint32_t reg_base) {
PXATimer *timer = new(std::nothrow) PXATimer(reg_base);
// XXX implement InitCheck() functionality
return timer != NULL ? B_OK : B_NO_MEMORY;
}
#endif
protected:
//PXATimer(fdt_module_info *fdt, fdt_device_node node);
PXATimer(uint32_t reg_base);
area_id fRegArea;
uint32 *fRegBase;