ARM: kernel: fix timer resolution and implement basic timekeeping.
The previously used method for programming the timer did not take into account that our timespec is 64bit while the register we poke it into is 32 bit. Since the PXA (SoC in Verdex target) has a limited scale of resolution (us,ms,second) we dynamicly determine the one that we can most closely match, and set that. For f.ex. snooze to work however, we also need system_time to work. The current implementation uses a system timer at microsecond resolution to keep track of time. Although the code is far from perfect, committing it now before it gets lost, since I'm working on the infrastructure code to properly factor out the SoC specific code out of the core ARM architecture code (so the kernel can support more then our poor old Verdex QEMU target ;))
This commit is contained in:
parent
4f4270c990
commit
ba06f07660
@ -35,35 +35,63 @@
|
||||
#define PXA_OSSR 0x05
|
||||
#define PXA_OIER 0x07
|
||||
#define PXA_OSCR4 0x10
|
||||
#define PXA_OSCR5 0x11
|
||||
#define PXA_OSMR4 0x20
|
||||
#define PXA_OSMR5 0x21
|
||||
#define PXA_OMCR4 0x30
|
||||
#define PXA_OMCR5 0x31
|
||||
|
||||
#define PXA_RES_S (3 << 0)
|
||||
#define PXA_RES_MS (1 << 1)
|
||||
#define PXA_RES_US (1 << 2)
|
||||
|
||||
static area_id sPxaTimersArea;
|
||||
static uint32 *sPxaTimersBase;
|
||||
#define US2S(bt) ((bt) / 1000000ULL)
|
||||
#define US2MS(bt) ((bt) / 1000ULL)
|
||||
|
||||
static area_id sPxaTimersArea = B_ERROR;
|
||||
static uint32 *sPxaTimersBase = NULL;
|
||||
static bigtime_t sSystemTime = 0;
|
||||
|
||||
static int32
|
||||
pxa_timer_interrupt(void *data)
|
||||
{
|
||||
int32 ret = timer_interrupt();
|
||||
sPxaTimersBase[PXA_OSSR] |= (1 << 4);
|
||||
if (sPxaTimersBase[PXA_OSSR] & (1 << 4)) {
|
||||
sPxaTimersBase[PXA_OSSR] |= (1 << 4);
|
||||
return timer_interrupt();
|
||||
}
|
||||
|
||||
return ret;
|
||||
if (sPxaTimersBase[PXA_OSSR] & (1 << 5)) {
|
||||
sPxaTimersBase[PXA_OSSR] |= (1 << 5);
|
||||
sSystemTime += UINT_MAX + 1ULL;
|
||||
}
|
||||
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_timer_set_hardware_timer(bigtime_t timeout)
|
||||
{
|
||||
TRACE(("arch_timer_set_hardware_timer(%lld)\n", timeout));
|
||||
uint32 val = timeout & UINT_MAX;
|
||||
uint32 res = PXA_RES_US;
|
||||
|
||||
if (sPxaTimersBase) {
|
||||
sPxaTimersBase[PXA_OIER] |= (1 << 4);
|
||||
sPxaTimersBase[PXA_OMCR4] = 4; // set to exactly single milisecond resolution
|
||||
sPxaTimersBase[PXA_OSMR4] = timeout;
|
||||
sPxaTimersBase[PXA_OSCR4] = 0; // start counting from 0 again
|
||||
if (timeout & ~UINT_MAX) {
|
||||
// Does not fit, so scale resolution down to milliseconds
|
||||
if (US2MS(timeout) & ~UINT_MAX) {
|
||||
// Still does not fit, scale down to seconds as last ditch attempt
|
||||
val = US2S(timeout) & UINT_MAX;
|
||||
res = PXA_RES_S;
|
||||
} else {
|
||||
// Fits in millisecond resolution
|
||||
val = US2MS(timeout) & UINT_MAX;
|
||||
res = PXA_RES_MS;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE(("arch_timer_set_hardware_timer(val=%lu, res=%lu)\n", val, res));
|
||||
sPxaTimersBase[PXA_OIER] |= (1 << 4);
|
||||
sPxaTimersBase[PXA_OMCR4] = res;
|
||||
sPxaTimersBase[PXA_OSMR4] = val;
|
||||
sPxaTimersBase[PXA_OSCR4] = 0; // start counting from 0 again
|
||||
}
|
||||
|
||||
|
||||
@ -72,13 +100,10 @@ arch_timer_clear_hardware_timer()
|
||||
{
|
||||
TRACE(("arch_timer_clear_hardware_timer\n"));
|
||||
|
||||
if (sPxaTimersBase) {
|
||||
sPxaTimersBase[PXA_OMCR4] = 0; // disable our timer
|
||||
sPxaTimersBase[PXA_OIER] &= ~(4 << 1);
|
||||
}
|
||||
sPxaTimersBase[PXA_OMCR4] = 0; // disable our timer
|
||||
sPxaTimersBase[PXA_OIER] &= ~(1 << 4);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
arch_init_timer(kernel_args *args)
|
||||
{
|
||||
@ -88,9 +113,20 @@ arch_init_timer(kernel_args *args)
|
||||
if (sPxaTimersArea < 0)
|
||||
return sPxaTimersArea;
|
||||
|
||||
sPxaTimersBase[PXA_OMCR4] = 0; // disable our timer
|
||||
sPxaTimersBase[PXA_OIER] |= (1 << 5); // enable timekeeping timer
|
||||
sPxaTimersBase[PXA_OMCR5] = PXA_RES_US | (1 << 7);
|
||||
sPxaTimersBase[PXA_OSMR5] = UINT_MAX;
|
||||
sPxaTimersBase[PXA_OSCR5] = 0;
|
||||
|
||||
install_io_interrupt_handler(PXA_TIMERS_INTERRUPT, &pxa_timer_interrupt, NULL, 0);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
bigtime_t
|
||||
system_time(void)
|
||||
{
|
||||
return (sPxaTimersBase != NULL) ?
|
||||
sSystemTime + sPxaTimersBase[PXA_OSCR5] :
|
||||
0ULL;
|
||||
}
|
||||
|
@ -11,8 +11,6 @@ SEARCH_SOURCE += [ FDirName $(librootSources) os arch generic ] ;
|
||||
KernelMergeObject kernel_os_arch_$(TARGET_ARCH).o :
|
||||
atomic.S
|
||||
byteorder.S
|
||||
# system_time_asm.S
|
||||
system_time.c
|
||||
|
||||
generic_system_time_nsecs.cpp
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user