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:
parent
0404f954c1
commit
fe2b6d7706
@ -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 */
|
||||
|
25
headers/private/kernel/boot/timer.h
Normal file
25
headers/private/kernel/boot/timer.h
Normal 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 */
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user