diff --git a/src/system/kernel/arch/arm/arch_timer.cpp b/src/system/kernel/arch/arm/arch_timer.cpp index 5cf8574279..6c291ed6bb 100644 --- a/src/system/kernel/arch/arm/arch_timer.cpp +++ b/src/system/kernel/arch/arm/arch_timer.cpp @@ -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; +} diff --git a/src/system/kernel/lib/arch/arm/Jamfile b/src/system/kernel/lib/arch/arm/Jamfile index 084a552ca8..1bdf0f1501 100644 --- a/src/system/kernel/lib/arch/arm/Jamfile +++ b/src/system/kernel/lib/arch/arm/Jamfile @@ -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