diff --git a/drivers/timer/npcx_itim_timer.c b/drivers/timer/npcx_itim_timer.c index a54db566d9..fba2bc2b3c 100644 --- a/drivers/timer/npcx_itim_timer.c +++ b/drivers/timer/npcx_itim_timer.c @@ -58,6 +58,7 @@ LOG_MODULE_REGISTER(itim, LOG_LEVEL_ERR); #define NPCX_ITIM_CLK_SEL_DELAY 92 /* Delay for clock selection (Unit:us) */ /* Timeout for enabling ITIM module: 100us (Unit:cycles) */ #define NPCX_ITIM_EN_TIMEOUT_CYCLES (100 * SYS_CYCLES_PER_USEC) +#define SYS_CYC_PER_EVT_CYC (sys_clock_hw_cycles_per_sec() / EVT_CYCLES_PER_SEC) /* Instance of system and event timers */ static struct itim64_reg *const sys_tmr = (struct itim64_reg *) @@ -70,6 +71,9 @@ static const struct npcx_clk_cfg itim_clk_cfg[] = NPCX_DT_CLK_CFG_ITEMS_LIST(0); static struct k_spinlock lock; /* Announced cycles in system timer before executing sys_clock_announce() */ static uint64_t cyc_sys_announced; +static uint64_t last_ticks; +static uint32_t last_elapsed; + /* Current target cycles of time-out signal in event timer */ static uint32_t cyc_evt_timeout; /* Total cycles of system timer stopped in "sleep/deep sleep" mode */ @@ -136,18 +140,33 @@ static inline void npcx_itim_evt_disable(void) /* ITIM local functions */ static int npcx_itim_start_evt_tmr_by_tick(int32_t ticks) { + k_spinlock_key_t key = k_spin_lock(&lock); + /* * Get desired cycles of event timer from the requested ticks which * round up to next tick boundary. */ + if (ticks == K_TICKS_FOREVER) { cyc_evt_timeout = NPCX_ITIM32_MAX_CNT; } else { + uint64_t next_cycs; + uint64_t curr = npcx_itim_get_sys_cyc64(); + uint32_t dcycles; + if (ticks <= 0) { ticks = 1; } - cyc_evt_timeout = MIN(EVT_CYCLES_FROM_TICKS(ticks), - NPCX_ITIM32_MAX_CNT); + + next_cycs = (last_ticks + last_elapsed + ticks) * SYS_CYCLES_PER_TICK; + if (unlikely(next_cycs <= curr)) { + cyc_evt_timeout = 1; + } else { + dcycles = next_cycs - curr; + cyc_evt_timeout = + CLAMP((dcycles / SYS_CYC_PER_EVT_CYC), 1, NPCX_ITIM32_MAX_CNT); + } + } LOG_DBG("ticks %x, cyc_evt_timeout %x", ticks, cyc_evt_timeout); @@ -159,9 +178,9 @@ static int npcx_itim_start_evt_tmr_by_tick(int32_t ticks) /* Upload counter of event timer */ evt_tmr->ITCNT32 = MAX(cyc_evt_timeout - 1, 1); + k_spin_unlock(&lock, key); /* Enable event timer and start ticking */ return npcx_itim_evt_enable(); - } static void npcx_itim_evt_isr(const struct device *dev) @@ -175,11 +194,12 @@ static void npcx_itim_evt_isr(const struct device *dev) if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { k_spinlock_key_t key = k_spin_lock(&lock); - uint32_t delta_ticks = (uint32_t)((npcx_itim_get_sys_cyc64() - - cyc_sys_announced) / SYS_CYCLES_PER_TICK); + uint64_t curr = npcx_itim_get_sys_cyc64(); + uint32_t delta_ticks = (uint32_t)((curr - cyc_sys_announced) / SYS_CYCLES_PER_TICK); - /* Store announced cycles of system timer */ - cyc_sys_announced = npcx_itim_get_sys_cyc64(); + cyc_sys_announced += delta_ticks * SYS_CYCLES_PER_TICK; + last_ticks += delta_ticks; + last_elapsed = 0; k_spin_unlock(&lock, key); /* Informs kernel that specified number of ticks have elapsed */ @@ -252,11 +272,13 @@ uint32_t sys_clock_elapsed(void) k_spinlock_key_t key = k_spin_lock(&lock); uint64_t delta_cycle = npcx_itim_get_sys_cyc64() - cyc_sys_announced; + uint32_t delta_ticks = (uint32_t)delta_cycle / SYS_CYCLES_PER_TICK; + last_elapsed = delta_ticks; k_spin_unlock(&lock, key); /* Return how many ticks elapsed since last sys_clock_announce() call */ - return (uint32_t)(delta_cycle / SYS_CYCLES_PER_TICK); + return delta_ticks; } uint32_t sys_clock_cycle_get_32(void)