diff options
author | Patryk Duda <pdk@semihalf.com> | 2021-12-20 12:12:21 +0100 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2022-01-19 17:57:52 +0000 |
commit | 8e2f1ed611679ae42779748596e5f6482bd9f6b6 (patch) | |
tree | acc4899eba38bcf3c4cdbf6ffabc1aefcccc0ff1 | |
parent | a13821d34669aa01a863ad1ea5cc6292234fe006 (diff) | |
download | chrome-ec-8e2f1ed611679ae42779748596e5f6482bd9f6b6.tar.gz |
stm32/hwtimer: Clear status register after counter is set
Whenever a timer interrupt occurs, the status register is checked for
overflow and the overflow status is passed to process_timers(), which
increments clksrc_high. When setting the clock to a new time, we don't
want the previous overflow state to trigger this process.
To avoid this problem, just clear status register when new value is
assigned to counter. To avoid race between updating counter and clearing
status, operation is performed when counters are disabled.
BUG=b:200828093
BRANCH=none
TEST=make -j buildall
Signed-off-by: Patryk Duda <pdk@semihalf.com>
Change-Id: Ifa3f2ff293483e167b5c7b6ff136708a876e8054
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3378344
Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Reviewed-by: Bobby Casey <bobbycasey@google.com>
-rw-r--r-- | chip/stm32/hwtimer.c | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/chip/stm32/hwtimer.c b/chip/stm32/hwtimer.c index c215484a22..84a193c14a 100644 --- a/chip/stm32/hwtimer.c +++ b/chip/stm32/hwtimer.c @@ -209,8 +209,32 @@ uint32_t __hw_clock_source_read(void) void __hw_clock_source_set(uint32_t ts) { + ASSERT(!is_interrupt_enabled()); + + /* Stop counting (LSB first, then MSB) */ + STM32_TIM_CR1(TIM_CLOCK_LSB) &= ~1; + STM32_TIM_CR1(TIM_CLOCK_MSB) &= ~1; + + /* Set new value to counters */ STM32_TIM_CNT(TIM_CLOCK_MSB) = ts >> 16; STM32_TIM_CNT(TIM_CLOCK_LSB) = ts & 0xffff; + + /* + * Clear status. We may clear information other than timer overflow + * (eg. event timestamp was matched) but: + * - Bits other than overflow are unused (see __hw_clock_source_irq()) + * - After setting timestamp software will trigger timer interrupt using + * task_trigger_irq() (see force_time() in common/timer.c). + * process_timers() is called from timer interrupt, so if "match" bit + * was present in status (think: some task timers are expired) + * process_timers() will handle that correctly. + */ + STM32_TIM_SR(TIM_CLOCK_MSB) = 0; + STM32_TIM_SR(TIM_CLOCK_LSB) = 0; + + /* Start counting (MSB first, then LSB) */ + STM32_TIM_CR1(TIM_CLOCK_MSB) |= 1; + STM32_TIM_CR1(TIM_CLOCK_LSB) |= 1; } static void __hw_clock_source_irq(void) @@ -356,14 +380,14 @@ int __hw_clock_source_init(uint32_t start_t) STM32_TIM_DIER(TIM_CLOCK_MSB) = 0x0001; STM32_TIM_DIER(TIM_CLOCK_LSB) = 0x0000; + /* Override the count with the start value */ + STM32_TIM_CNT(TIM_CLOCK_MSB) = start_t >> 16; + STM32_TIM_CNT(TIM_CLOCK_LSB) = start_t & 0xffff; + /* Start counting */ STM32_TIM_CR1(TIM_CLOCK_MSB) |= 1; STM32_TIM_CR1(TIM_CLOCK_LSB) |= 1; - /* Override the count with the start value now that counting has - * started. */ - __hw_clock_source_set(start_t); - /* Enable timer interrupts */ task_enable_irq(IRQ_MSB); task_enable_irq(IRQ_LSB); |