| /* |
| * Copyright (c) 2018 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| #include <drivers/system_timer.h> |
| #include <sys_clock.h> |
| #include <spinlock.h> |
| #include <arch/arm/cortex_m/cmsis.h> |
| |
| void z_ExcExit(void); |
| |
| #define COUNTER_MAX 0x00ffffff |
| #define TIMER_STOPPED 0xff000000 |
| |
| #define CYC_PER_TICK (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC \ |
| / CONFIG_SYS_CLOCK_TICKS_PER_SEC) |
| #define MAX_TICKS ((COUNTER_MAX / CYC_PER_TICK) - 1) |
| #define MAX_CYCLES (MAX_TICKS * CYC_PER_TICK) |
| |
| /* Minimum cycles in the future to try to program. Note that this is |
| * NOT simply "enough cycles to get the counter read and reprogrammed |
| * reliably" -- it becomes the minimum value of the LOAD register, and |
| * thus reflects how much time we can reliably see expire between |
| * calls to elapsed() to read the COUNTFLAG bit. So it needs to be |
| * set to be larger than the maximum time the interrupt might be |
| * masked. Choosing a fraction of a tick is probably a good enough |
| * default, with an absolute minimum of 1k cyc. |
| */ |
| #define MIN_DELAY MAX(1024, (CYC_PER_TICK/16)) |
| |
| #define TICKLESS (IS_ENABLED(CONFIG_TICKLESS_KERNEL) && \ |
| !IS_ENABLED(CONFIG_QEMU_TICKLESS_WORKAROUND)) |
| |
| /* VAL value above which we assume that a subsequent COUNTFLAG |
| * overflow seen in CTRL is real and not an artifact of wraparound |
| * timing. |
| */ |
| #define VAL_ABOUT_TO_WRAP 8 |
| |
| static struct k_spinlock lock; |
| |
| static u32_t last_load; |
| |
| static u32_t cycle_count; |
| |
| static u32_t announced_cycles; |
| |
| static volatile u32_t overflow_cyc; |
| |
| static u32_t elapsed(void) |
| { |
| u32_t val, ctrl1, ctrl2; |
| |
| /* SysTick is infuriatingly racy. The counter wraps at zero |
| * automatically, setting a 1 in the COUNTFLAG bit of the CTRL |
| * register when it does. But reading the control register |
| * automatically resets that bit, so we need to save it for |
| * future calls. And ordering is critical and race-prone: if |
| * we read CTRL first, then it is possible for VAL to wrap |
| * after that read but before we read VAL and we'll miss the |
| * overflow. If we read VAL first, then it can wrap after we |
| * read it and we'll see an "extra" overflow in CTRL. And we |
| * want to handle multiple overflows, so we effectively must |
| * read CTRL first otherwise there will be no way to detect |
| * the double-overflow if called at the end of a cycle. There |
| * is no safe algorithm here, so we split the difference by |
| * reading CTRL twice, suppressing the second overflow bit if |
| * VAL was "about to overflow". |
| */ |
| ctrl1 = SysTick->CTRL; |
| val = SysTick->VAL & COUNTER_MAX; |
| ctrl2 = SysTick->CTRL; |
| |
| overflow_cyc += (ctrl1 & SysTick_CTRL_COUNTFLAG_Msk) ? last_load : 0; |
| if (val > VAL_ABOUT_TO_WRAP) { |
| int wrap = ctrl2 & SysTick_CTRL_COUNTFLAG_Msk; |
| |
| overflow_cyc += (wrap != 0) ? last_load : 0; |
| } |
| |
| return (last_load - val) + overflow_cyc; |
| } |
| |
| /* Callout out of platform assembly, not hooked via IRQ_CONNECT... */ |
| void z_clock_isr(void *arg) |
| { |
| ARG_UNUSED(arg); |
| u32_t dticks; |
| |
| cycle_count += last_load; |
| dticks = (cycle_count - announced_cycles) / CYC_PER_TICK; |
| announced_cycles += dticks * CYC_PER_TICK; |
| |
| overflow_cyc = SysTick->CTRL; /* Reset overflow flag */ |
| overflow_cyc = 0U; |
| |
| z_clock_announce(TICKLESS ? dticks : 1); |
| z_ExcExit(); |
| } |
| |
| int z_clock_driver_init(struct device *device) |
| { |
| NVIC_SetPriority(SysTick_IRQn, _IRQ_PRIO_OFFSET); |
| last_load = CYC_PER_TICK - 1; |
| overflow_cyc = 0U; |
| SysTick->LOAD = last_load; |
| SysTick->VAL = 0; /* resets timer to last_load */ |
| SysTick->CTRL |= (SysTick_CTRL_ENABLE_Msk | |
| SysTick_CTRL_TICKINT_Msk | |
| SysTick_CTRL_CLKSOURCE_Msk); |
| return 0; |
| } |
| |
| void z_clock_set_timeout(s32_t ticks, bool idle) |
| { |
| /* Fast CPUs and a 24 bit counter mean that even idle systems |
| * need to wake up multiple times per second. If the kernel |
| * allows us to miss tick announcements in idle, then shut off |
| * the counter. (Note: we can assume if idle==true that |
| * interrupts are already disabled) |
| */ |
| if (IS_ENABLED(CONFIG_TICKLESS_IDLE) && idle && ticks == K_FOREVER) { |
| SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; |
| last_load = TIMER_STOPPED; |
| return; |
| } |
| |
| #if defined(CONFIG_TICKLESS_KERNEL) && !defined(CONFIG_QEMU_TICKLESS_WORKAROUND) |
| u32_t delay; |
| |
| ticks = MIN(MAX_TICKS, MAX(ticks - 1, 0)); |
| |
| /* Desired delay in the future */ |
| delay = (ticks == 0) ? MIN_DELAY : ticks * CYC_PER_TICK; |
| |
| k_spinlock_key_t key = k_spin_lock(&lock); |
| |
| cycle_count += elapsed(); |
| |
| /* Round delay up to next tick boundary */ |
| delay = delay + (cycle_count - announced_cycles); |
| delay = ((delay + CYC_PER_TICK - 1) / CYC_PER_TICK) * CYC_PER_TICK; |
| last_load = delay - (cycle_count - announced_cycles); |
| |
| overflow_cyc = 0U; |
| SysTick->LOAD = last_load - 1; |
| SysTick->VAL = 0; /* resets timer to last_load */ |
| |
| k_spin_unlock(&lock, key); |
| #endif |
| } |
| |
| u32_t z_clock_elapsed(void) |
| { |
| if (!TICKLESS) { |
| return 0; |
| } |
| |
| k_spinlock_key_t key = k_spin_lock(&lock); |
| u32_t cyc = elapsed() + cycle_count - announced_cycles; |
| |
| k_spin_unlock(&lock, key); |
| return cyc / CYC_PER_TICK; |
| } |
| |
| u32_t z_timer_cycle_get_32(void) |
| { |
| k_spinlock_key_t key = k_spin_lock(&lock); |
| u32_t ret = elapsed() + cycle_count; |
| |
| k_spin_unlock(&lock, key); |
| return ret; |
| } |
| |
| void z_clock_idle_exit(void) |
| { |
| if (last_load == TIMER_STOPPED) { |
| SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; |
| } |
| } |
| |
| void sys_clock_disable(void) |
| { |
| SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; |
| } |