From f5e1760079d558bc1a91b577b01e5c6ad573f8db Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Wed, 11 Dec 2024 17:51:12 +0800 Subject: [PATCH] driver: timer: npcx: bypass timer counter reading issue Originally, when the timer's source clock is 32.768 kHz, the timer driver uses two consecutive reads to ensure the timer reading is correct. However, it is not robust enough due to an asynchronous timing issue in the chip. The workaround is to add at least two NOPs between the LDR and CMP instructions. This commit implements the workaround in the assembly code to ensure it is not affected by the compiler toolchain or optimization flags. Signed-off-by: Jun Lin --- drivers/timer/npcx_itim_timer.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/timer/npcx_itim_timer.c b/drivers/timer/npcx_itim_timer.c index c55000b102adceb..ce93fd908aecbbd 100644 --- a/drivers/timer/npcx_itim_timer.c +++ b/drivers/timer/npcx_itim_timer.c @@ -216,15 +216,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; }