diff options
-rw-r--r-- | chip/stm32/build.mk | 4 | ||||
-rw-r--r-- | chip/stm32/hwtimer32.c | 161 | ||||
-rw-r--r-- | chip/stm32/registers.h | 8 |
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; |