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 <[email protected]> Reviewed-by: David Karoly <[email protected]>
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <util/FixedWidthPointer.h>
|
#include <util/FixedWidthPointer.h>
|
||||||
#include <boot/interrupt_controller.h>
|
#include <boot/interrupt_controller.h>
|
||||||
|
#include <boot/timer.h>
|
||||||
#include <boot/uart.h>
|
#include <boot/uart.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -42,8 +43,9 @@ typedef struct {
|
|||||||
FixedWidthPointer<void> acpi_root;
|
FixedWidthPointer<void> acpi_root;
|
||||||
FixedWidthPointer<void> fdt;
|
FixedWidthPointer<void> fdt;
|
||||||
|
|
||||||
uart_info uart;
|
uart_info uart;
|
||||||
intc_info interrupt_controller;
|
intc_info interrupt_controller;
|
||||||
|
boot_timer_info timer;
|
||||||
} _PACKED arch_kernel_args;
|
} _PACKED arch_kernel_args;
|
||||||
|
|
||||||
#endif /* KERNEL_ARCH_ARM_KERNEL_ARGS_H */
|
#endif /* KERNEL_ARCH_ARM_KERNEL_ARGS_H */
|
||||||
|
|||||||
@@ -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
|
void
|
||||||
arch_handle_fdt(const void* fdt, int node)
|
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.start,
|
||||||
interrupt_controller.regs2.size);
|
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)
|
dtb_get_interrupt(const void* fdt, int node)
|
||||||
{
|
{
|
||||||
uint32 interruptCells = dtb_get_interrupt_cells(fdt, node);
|
uint32 interruptCells = dtb_get_interrupt_cells(fdt, node);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ extern void dtb_init();
|
|||||||
extern void dtb_set_kernel_args();
|
extern void dtb_set_kernel_args();
|
||||||
|
|
||||||
bool dtb_get_reg(const void* fdt, int node, size_t idx, addr_range& range);
|
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);
|
bool dtb_has_fdt_string(const char* prop, int size, const char* pattern);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,20 +34,6 @@
|
|||||||
#endif
|
#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
|
void
|
||||||
arch_timer_set_hardware_timer(bigtime_t timeout)
|
arch_timer_set_hardware_timer(bigtime_t timeout)
|
||||||
{
|
{
|
||||||
@@ -73,20 +59,16 @@ arch_init_timer(kernel_args *args)
|
|||||||
if (ARMGenericTimer::IsAvailable()) {
|
if (ARMGenericTimer::IsAvailable()) {
|
||||||
TRACE("init ARMv7 generic timer\n");
|
TRACE("init ARMv7 generic timer\n");
|
||||||
ARMGenericTimer::Init();
|
ARMGenericTimer::Init();
|
||||||
}
|
} else if (strncmp(args->arch_args.timer.kind, TIMER_KIND_OMAP3,
|
||||||
|
sizeof(args->arch_args.timer.kind)) == 0) {
|
||||||
//TODO: use SoC-specific timer as a fallback
|
OMAP3Timer::Init(args->arch_args.timer.regs.start,
|
||||||
//if the generic timer is not available
|
args->arch_args.timer.interrupt);
|
||||||
|
} else if (strncmp(args->arch_args.timer.kind, TIMER_KIND_PXA,
|
||||||
#if 0
|
sizeof(args->arch_args.timer.kind)) == 0) {
|
||||||
status_t rc = get_module(B_FDT_MODULE_NAME, (module_info**)&sFdtModule);
|
PXATimer::Init(args->arch_args.timer.regs.start);
|
||||||
if (rc != B_OK)
|
} else {
|
||||||
panic("Unable to get FDT module: %08lx!\n", rc);
|
|
||||||
|
|
||||||
rc = sFdtModule->setup_devices(intc_table, intc_count, NULL);
|
|
||||||
if (rc != B_OK)
|
|
||||||
panic("No hardware timer found!\n");
|
panic("No hardware timer found!\n");
|
||||||
#endif
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ OMAP3InterruptController::SoftReset()
|
|||||||
{
|
{
|
||||||
uint32 tmp = fRegBase[INTCPS_REVISION] & 0xff;
|
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);
|
fRegBase, tmp >> 4, tmp & 0xf);
|
||||||
|
|
||||||
tmp = fRegBase[INTCPS_SYSCONFIG];
|
tmp = fRegBase[INTCPS_SYSCONFIG];
|
||||||
@@ -184,21 +184,22 @@ OMAP3Timer::Clear()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
OMAP3Timer::OMAP3Timer(uint32_t reg_base, uint32_t interrupt)
|
||||||
OMAP3Timer::OMAP3Timer(fdt_module_info *fdtModule, fdt_device_node node)
|
: fSystemTime(0)
|
||||||
: HardwareTimer(fdtModule, node),
|
|
||||||
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)
|
if (fRegArea < 0)
|
||||||
panic("Cannot map OMAP3Timer registers!");
|
panic("Cannot map OMAP3Timer registers!");
|
||||||
|
|
||||||
fInterrupt = fFDT->get_interrupt(node, 0);
|
fInterrupt = interrupt;
|
||||||
if (fInterrupt < 0)
|
if (fInterrupt < 0)
|
||||||
panic("Cannot get OMAP3Timer interrupt!");
|
panic("Cannot get OMAP3Timer interrupt!");
|
||||||
|
|
||||||
uint32 rev = fRegBase[TIDR];
|
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)
|
// Let the timer run (so we can use it as clocksource)
|
||||||
fRegBase[TCLR] |= 1;
|
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);
|
install_io_interrupt_handler(fInterrupt, &OMAP3Timer::_InterruptWrapper, this, 0);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -29,10 +29,9 @@ public:
|
|||||||
bigtime_t Time();
|
bigtime_t Time();
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
#if 0
|
static status_t Init(uint32_t reg_base, uint32_t interrupt) {
|
||||||
static status_t Init(fdt_module_info *fdt, fdt_device_node node, void *cookie) {
|
|
||||||
if (sInstance == NULL) {
|
if (sInstance == NULL) {
|
||||||
OMAP3Timer *timer = new(std::nothrow) OMAP3Timer(fdt, node);
|
OMAP3Timer *timer = new(std::nothrow) OMAP3Timer(reg_base, interrupt);
|
||||||
// XXX implement InitCheck() functionality
|
// XXX implement InitCheck() functionality
|
||||||
return timer != NULL ? B_OK : B_NO_MEMORY;
|
return timer != NULL ? B_OK : B_NO_MEMORY;
|
||||||
} else {
|
} else {
|
||||||
@@ -41,10 +40,9 @@ public:
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//OMAP3Timer(fdt_module_info *fdtModule, fdt_device_node node);
|
OMAP3Timer(uint32_t reg_base, uint32_t interrupt);
|
||||||
|
|
||||||
static int32 _InterruptWrapper(void *data);
|
static int32 _InterruptWrapper(void *data);
|
||||||
int32 HandleInterrupt();
|
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_OIER] |= (1 << 4);
|
||||||
fRegBase[PXA_OMCR4] = res;
|
fRegBase[PXA_OMCR4] = res;
|
||||||
fRegBase[PXA_OSMR4] = val;
|
fRegBase[PXA_OSMR4] = val;
|
||||||
@@ -143,11 +143,11 @@ PXATimer::HandleInterrupt()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
PXATimer::PXATimer(uint32_t reg_base)
|
||||||
PXATimer::PXATimer(fdt_module_info *fdt, fdt_device_node node)
|
|
||||||
: HardwareTimer(fdt, node)
|
|
||||||
{
|
{
|
||||||
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)
|
if (fRegArea < 0)
|
||||||
panic("Cannot map PXATimer registers!");
|
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);
|
install_io_interrupt_handler(PXA_TIMERS_INTERRUPT, &PXATimer::_InterruptWrapper, NULL, 0);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -27,16 +27,14 @@ public:
|
|||||||
void Clear();
|
void Clear();
|
||||||
bigtime_t Time();
|
bigtime_t Time();
|
||||||
|
|
||||||
#if 0
|
static status_t Init(uint32_t reg_base) {
|
||||||
static status_t Init(fdt_module_info *fdt, fdt_device_node node, void *cookie) {
|
PXATimer *timer = new(std::nothrow) PXATimer(reg_base);
|
||||||
PXATimer *timer = new(std::nothrow) PXATimer(fdt, node);
|
|
||||||
// XXX implement InitCheck() functionality
|
// XXX implement InitCheck() functionality
|
||||||
return timer != NULL ? B_OK : B_NO_MEMORY;
|
return timer != NULL ? B_OK : B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//PXATimer(fdt_module_info *fdt, fdt_device_node node);
|
PXATimer(uint32_t reg_base);
|
||||||
|
|
||||||
area_id fRegArea;
|
area_id fRegArea;
|
||||||
uint32 *fRegBase;
|
uint32 *fRegBase;
|
||||||
|
|||||||
Reference in New Issue
Block a user