Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

driver: timer: npcx: fix timer accuracy issue #82905

Merged
merged 2 commits into from
Dec 16, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 24 additions & 19 deletions drivers/timer/npcx_itim_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,6 @@ 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.
Expand All @@ -152,7 +150,7 @@ static int npcx_itim_start_evt_tmr_by_tick(int32_t ticks)
} else {
uint64_t next_cycs;
uint64_t curr = npcx_itim_get_sys_cyc64();
uint32_t dcycles;
uint64_t dcycles;

if (ticks <= 0) {
ticks = 1;
Expand All @@ -162,11 +160,13 @@ static int npcx_itim_start_evt_tmr_by_tick(int32_t ticks)
if (unlikely(next_cycs <= curr)) {
cyc_evt_timeout = 1;
} else {
uint32_t dticks;

dcycles = next_cycs - curr;
cyc_evt_timeout =
CLAMP((dcycles / SYS_CYC_PER_EVT_CYC), 1, NPCX_ITIM32_MAX_CNT);
dticks = DIV_ROUND_UP(dcycles * EVT_CYCLES_PER_SEC,
sys_clock_hw_cycles_per_sec());
cyc_evt_timeout = CLAMP(dticks, 1, NPCX_ITIM32_MAX_CNT);
}

}
LOG_DBG("ticks %x, cyc_evt_timeout %x", ticks, cyc_evt_timeout);

Expand All @@ -178,7 +178,6 @@ 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();
}
Expand Down Expand Up @@ -218,15 +217,18 @@ static inline uint32_t npcx_itim_get_evt_cyc32(void)
{
uint32_t cnt1, cnt2;

cnt1 = evt_tmr->ITCNT32;
/*
* Wait for two consecutive equal values are read since the source clock
* of event timer is 32KHz.
*/
while ((cnt2 = evt_tmr->ITCNT32) != cnt1) {
cnt1 = cnt2;
}

__asm__ volatile(
"ldr %[c2], [%[tmr], %[itcnt32_off]]\n\t"
".read_itim_cnt_loop_%=:\n\t"
"mov %[c1], %[c2]\n\t"
"ldr %[c2], [%[tmr], %[itcnt32_off]]\n\t"
"nop\n\t"
"nop\n\t"
"cmp %[c1], %[c2]\n\t"
"bne .read_itim_cnt_loop_%=\n\t"
: [c1] "=&r"(cnt1), [c2] "=&r"(cnt2)
: [tmr] "r"(evt_tmr), [itcnt32_off] "i"(offsetof(struct itim32_reg, ITCNT32))
: "memory");
/* Return current value of 32-bit counter of event timer */
return cnt2;
}
Expand All @@ -235,13 +237,13 @@ static uint32_t npcx_itim_evt_elapsed_cyc32(void)
{
uint32_t cnt1 = npcx_itim_get_evt_cyc32();
uint8_t sys_cts = evt_tmr->ITCTS32;
uint16_t cnt2 = npcx_itim_get_evt_cyc32();
uint32_t cnt2 = npcx_itim_get_evt_cyc32();

/* Event has been triggered but timer ISR doesn't handle it */
if (IS_BIT_SET(sys_cts, NPCX_ITCTSXX_TO_STS) || (cnt2 > cnt1)) {
cnt2 = cyc_evt_timeout;
} else {
cnt2 = cyc_evt_timeout - cnt2;
cnt2 = cyc_evt_timeout - cnt2 - 1;
}

/* Return elapsed cycles of 32-bit counter of event timer */
Expand All @@ -261,7 +263,10 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)

LOG_DBG("timeout is %d", ticks);
/* Start a event timer in ticks */

k_spinlock_key_t key = k_spin_lock(&lock);
npcx_itim_start_evt_tmr_by_tick(ticks);
k_spin_unlock(&lock, key);
}

uint32_t sys_clock_elapsed(void)
Expand All @@ -273,7 +278,7 @@ 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;
uint32_t delta_ticks = (uint32_t)(delta_cycle / SYS_CYCLES_PER_TICK);

last_elapsed = delta_ticks;
k_spin_unlock(&lock, key);
Expand Down
Loading