summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2014-03-13 12:38:55 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-03-14 03:45:35 +0000
commit8dc20291b2b77cf534d1d84ea94adcb941422074 (patch)
treea69dc001fcdb42c33cfd5405ed0e12af9f62af0f
parentc00675b909327f6563203b5083bbf2293188948e (diff)
downloadchrome-ec-stabilize-5656.B.tar.gz
stm32: add 32-bit timer supportstabilize-5656.B
Some STM32 variants have a 32-bit timer in addition the bunch of 16-bit timers. Add the option to use the 32-bit timer as the system clock source to lower the overhead of the timer code compared to a pair of 16-bit timers. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=none BUG=none TEST=run the EC on STM32F072 Discovery board with 32-bit TIM2 as the clock source. Change-Id: If55c4e23a3f68dd8f6ca32e93f3a27c1743c767b Reviewed-on: https://chromium-review.googlesource.com/189861 Reviewed-by: Vic Yang <victoryang@chromium.org> Commit-Queue: Vincent Palatin <vpalatin@chromium.org> Tested-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--chip/stm32/build.mk4
-rw-r--r--chip/stm32/hwtimer32.c161
-rw-r--r--chip/stm32/registers.h8
3 files changed, 172 insertions, 1 deletions
diff --git a/chip/stm32/build.mk b/chip/stm32/build.mk
index 82f1e34cad..2b0477518c 100644
--- a/chip/stm32/build.mk
+++ b/chip/stm32/build.mk
@@ -22,8 +22,10 @@ endif
FLASH_FAMILY=$(subst stm32f0,stm32f,$(CHIP_FAMILY))
# STM32F0xx chips will re-use STM32L I2C code
I2C_FAMILY=$(subst stm32f0,stm32l,$(CHIP_FAMILY))
+# Select between 16-bit and 32-bit timer for clock source
+TIMER_TYPE=$(if $(CONFIG_STM_HWTIMER32),32,)
-chip-y=dma.o hwtimer.o system.o uart.o
+chip-y=dma.o hwtimer$(TIMER_TYPE).o system.o uart.o
chip-y+=jtag-$(CHIP_FAMILY).o clock-$(CHIP_FAMILY).o gpio-$(CHIP_FAMILY).o
chip-$(CONFIG_SPI)+=spi.o
chip-$(CONFIG_I2C)+=i2c-$(I2C_FAMILY).o
diff --git a/chip/stm32/hwtimer32.c b/chip/stm32/hwtimer32.c
new file mode 100644
index 0000000000..e87ab3b77f
--- /dev/null
+++ b/chip/stm32/hwtimer32.c
@@ -0,0 +1,161 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Hardware 32-bit timer driver */
+
+#include "clock.h"
+#include "common.h"
+#include "hooks.h"
+#include "hwtimer.h"
+#include "panic.h"
+#include "registers.h"
+#include "task.h"
+#include "timer.h"
+#include "watchdog.h"
+
+#define IRQ_TIM(n) CONCAT2(STM32_IRQ_TIM, n)
+
+void __hw_clock_event_set(uint32_t deadline)
+{
+ /* set the match on the deadline */
+ STM32_TIM32_CCR1(TIM_CLOCK32) = deadline;
+ /* Clear the match flags */
+ STM32_TIM_SR(TIM_CLOCK32) = ~2;
+ /* Set the match interrupt */
+ STM32_TIM_DIER(TIM_CLOCK32) |= 2;
+}
+
+uint32_t __hw_clock_event_get(void)
+{
+ return STM32_TIM32_CCR1(TIM_CLOCK32);
+}
+
+void __hw_clock_event_clear(void)
+{
+ /* Disable the match interrupts */
+ STM32_TIM_DIER(TIM_CLOCK32) &= ~2;
+}
+
+uint32_t __hw_clock_source_read(void)
+{
+ return STM32_TIM32_CNT(TIM_CLOCK32);
+}
+
+void __hw_clock_source_set(uint32_t ts)
+{
+ STM32_TIM32_CNT(TIM_CLOCK32) = ts;
+}
+
+void __hw_clock_source_irq(void)
+{
+ uint32_t stat_tim = STM32_TIM_SR(TIM_CLOCK32);
+
+ /* Clear status */
+ STM32_TIM_SR(TIM_CLOCK32) = 0;
+
+ /*
+ * Find expired timers and set the new timer deadline
+ * signal overflow if the update interrupt flag is set.
+ */
+ process_timers(stat_tim & 0x01);
+}
+DECLARE_IRQ(IRQ_TIM(TIM_CLOCK32), __hw_clock_source_irq, 1);
+
+void __hw_timer_enable_clock(int n, int enable)
+{
+ volatile uint32_t *reg;
+ uint32_t mask = 0;
+
+ /*
+ * Mapping of timers to reg/mask is split into a few different ranges,
+ * some specific to individual chips.
+ */
+#if defined(CHIP_FAMILY_STM32F) || defined(CHIP_FAMILY_STM32F0)
+ if (n == 1) {
+ reg = &STM32_RCC_APB2ENR;
+ mask = STM32_RCC_PB2_TIM1;
+ }
+#elif defined(CHIP_FAMILY_STM32L)
+ if (n >= 9 && n <= 11) {
+ reg = &STM32_RCC_APB2ENR;
+ mask = STM32_RCC_PB2_TIM9 << (n - 9);
+ }
+#endif
+
+#if defined(CHIP_FAMILY_STM32F0)
+ if (n >= 15 && n <= 17) {
+ reg = &STM32_RCC_APB2ENR;
+ mask = STM32_RCC_PB2_TIM15 << (n - 15);
+ }
+ if (n == 14) {
+ reg = &STM32_RCC_APB1ENR;
+ mask = STM32_RCC_PB1_TIM14;
+ }
+#endif
+ if (n >= 2 && n <= 7) {
+ reg = &STM32_RCC_APB1ENR;
+ mask = STM32_RCC_PB1_TIM2 << (n - 2);
+ }
+
+ if (!mask)
+ return;
+
+ if (enable)
+ *reg |= mask;
+ else
+ *reg &= ~mask;
+}
+
+static void update_prescaler(void)
+{
+ /*
+ * Pre-scaler value :
+ * the timer is incrementing every microsecond
+ *
+ * This will take effect at the next update event (when the current
+ * prescaler counter ticks down, or if forced via EGR).
+ */
+ STM32_TIM_PSC(TIM_CLOCK32) = (clock_get_freq() / SECOND) - 1;
+}
+DECLARE_HOOK(HOOK_FREQ_CHANGE, update_prescaler, HOOK_PRIO_DEFAULT);
+
+int __hw_clock_source_init(uint32_t start_t)
+{
+ /* Enable TIM peripheral block clocks */
+ __hw_timer_enable_clock(TIM_CLOCK32, 1);
+
+ /*
+ * Timer configuration : Upcounter, counter disabled, update event only
+ * on overflow.
+ */
+ STM32_TIM_CR1(TIM_CLOCK32) = 0x0004;
+ /* No special configuration */
+ STM32_TIM_CR2(TIM_CLOCK32) = 0x0000;
+ STM32_TIM_SMCR(TIM_CLOCK32) = 0x0000;
+
+ /* Auto-reload value : 32-bit free-running counter */
+ STM32_TIM32_ARR(TIM_CLOCK32) = 0xffffffff;
+
+ /* Update prescaler */
+ update_prescaler();
+
+ /* Reload the pre-scaler */
+ STM32_TIM_EGR(TIM_CLOCK32) = 0x0001;
+
+ /* Set up the overflow interrupt */
+ STM32_TIM_DIER(TIM_CLOCK32) = 0x0001;
+
+ /* Start counting */
+ STM32_TIM_CR1(TIM_CLOCK32) |= 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_TIM(TIM_CLOCK32));
+
+ return IRQ_TIM(TIM_CLOCK32);
+}
diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h
index 7661a1daf7..51f99b3621 100644
--- a/chip/stm32/registers.h
+++ b/chip/stm32/registers.h
@@ -220,6 +220,8 @@
#define STM32_TIM_REG(n, offset) \
REG16(STM32_TIM_BASE(n) + (offset))
+#define STM32_TIM_REG32(n, offset) \
+ REG32(STM32_TIM_BASE(n) + (offset))
#define STM32_TIM_CR1(n) STM32_TIM_REG(n, 0x00)
#define STM32_TIM_CR2(n) STM32_TIM_REG(n, 0x04)
@@ -242,6 +244,12 @@
#define STM32_TIM_DMAR(n) STM32_TIM_REG(n, 0x4C)
#define STM32_TIM_OR(n) STM32_TIM_REG(n, 0x50)
+#define STM32_TIM32_CNT(n) STM32_TIM_REG32(n, 0x24)
+#define STM32_TIM32_ARR(n) STM32_TIM_REG32(n, 0x2C)
+#define STM32_TIM32_CCR1(n) STM32_TIM_REG32(n, 0x34)
+#define STM32_TIM32_CCR2(n) STM32_TIM_REG32(n, 0x38)
+#define STM32_TIM32_CCR3(n) STM32_TIM_REG32(n, 0x3C)
+#define STM32_TIM32_CCR4(n) STM32_TIM_REG32(n, 0x40)
/* Timer registers as struct */
struct timer_ctlr {
unsigned cr1;