diff options
author | Randall Spangler <rspangler@chromium.org> | 2013-06-21 14:17:38 -0700 |
---|---|---|
committer | ChromeBot <chrome-bot@google.com> | 2013-06-24 14:03:59 -0700 |
commit | 8a66ae3182268d51fe616a71148ccf0091f8005d (patch) | |
tree | 11f1b0d3586a6979757410377936339eaeb9a3a7 | |
parent | c7e60d03aa4b60122aacaf77e0fd2491771b6662 (diff) | |
download | chrome-ec-8a66ae3182268d51fe616a71148ccf0091f8005d.tar.gz |
pit: Fix watchdog help for STM32L
Clean up timer initialization code to be more general, so that we can
use timer 9 for the LSB on STM32L. Then use timer 4 for the watchdog
helper.
BUG=chrome-os-partner:18781
BRANCH=none
TEST=From EC console:
timerinfo -> current time still counts up properly
waitms 2000 -> prints watchdog info before rebooting
Change-Id: Ib0ba496b0eadb93756dcd1841857546910baf2a9
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/59612
Reviewed-by: Simon Glass <sjg@chromium.org>
-rw-r--r-- | board/mccroskey/board.h | 1 | ||||
-rw-r--r-- | board/pit/board.h | 7 | ||||
-rw-r--r-- | board/snow/board.h | 1 | ||||
-rw-r--r-- | board/spring/board.h | 1 | ||||
-rw-r--r-- | chip/stm32/hwtimer.c | 103 | ||||
-rw-r--r-- | include/hwtimer.h | 7 |
6 files changed, 86 insertions, 34 deletions
diff --git a/board/mccroskey/board.h b/board/mccroskey/board.h index a290ddc691..b5fe645496 100644 --- a/board/mccroskey/board.h +++ b/board/mccroskey/board.h @@ -49,6 +49,7 @@ /* Timer selection */ #define TIM_CLOCK_MSB 3 #define TIM_CLOCK_LSB 4 +#define TIM_WATCHDOG 1 /* GPIO signal list */ enum gpio_signal { diff --git a/board/pit/board.h b/board/pit/board.h index ba6a4df593..a076abf882 100644 --- a/board/pit/board.h +++ b/board/pit/board.h @@ -18,7 +18,8 @@ #define CONFIG_ASSERT_HELP #define CONFIG_CONSOLE_CMDHELP #define CONFIG_PANIC_HELP -#define CONFIG_TASK_PROFILING +#define CONFIG_TASK_PROFILING +#define CONFIG_WATCHDOG_HELP /* Optional features */ #define CONFIG_BATTERY_BQ20Z453 @@ -44,7 +45,6 @@ #ifdef PORT_TO_PIT /* TODO(rspangler): enable these features when they compile */ #define CONFIG_LOW_POWER_IDLE -#define CONFIG_WATCHDOG_HELP #endif #ifndef __ASSEMBLER__ @@ -74,7 +74,8 @@ /* Timer selection */ #define TIM_CLOCK_MSB 3 -#define TIM_CLOCK_LSB 4 +#define TIM_CLOCK_LSB 9 +#define TIM_WATCHDOG 4 /* GPIO signal list */ enum gpio_signal { diff --git a/board/snow/board.h b/board/snow/board.h index 83b7a3c65d..73619a1d9f 100644 --- a/board/snow/board.h +++ b/board/snow/board.h @@ -66,6 +66,7 @@ /* Timer selection */ #define TIM_CLOCK_MSB 3 #define TIM_CLOCK_LSB 4 +#define TIM_WATCHDOG 1 /* GPIO signal list */ enum gpio_signal { diff --git a/board/spring/board.h b/board/spring/board.h index 3c342db10a..4938c90a72 100644 --- a/board/spring/board.h +++ b/board/spring/board.h @@ -67,6 +67,7 @@ /* Timer selection */ #define TIM_CLOCK_MSB 2 #define TIM_CLOCK_LSB 4 +#define TIM_WATCHDOG 1 /* ADC signal */ enum adc_channel { diff --git a/chip/stm32/hwtimer.c b/chip/stm32/hwtimer.c index 0231bab5fb..bb036619dc 100644 --- a/chip/stm32/hwtimer.c +++ b/chip/stm32/hwtimer.c @@ -16,21 +16,59 @@ /* Divider to get microsecond for the clock */ #define CLOCKSOURCE_DIVIDER (CPU_CLOCK / SECOND) -#define TIM_WD_IRQ STM32_IRQ_TIM1_UP_TIM16 -#define TIM_WD 1 /* Timer to use for watchdog */ +/* + * Trigger select mapping for slave timer from master timer. This is + * unfortunately not very straightforward; there's no tidy way to do this + * algorithmically. To avoid burning memory for a lookup table, use macros to + * compute the offset. This also has the benefit that compilation will fail if + * an unsupported master/slave pairing is used. + * + * Slave Master + * 1 15 2 3 4 (STM32F100 only) + * 2 9 10 3 4 + * 3 9 2 11 4 + * 4 10 2 3 9 + * 9 2 3 10 11 (STM32L15x only) + * -------------------- + * ts = 0 1 2 3 + */ +#define STM32_TIM_TS_SLAVE_1_MASTER_15 0 +#define STM32_TIM_TS_SLAVE_1_MASTER_2 1 +#define STM32_TIM_TS_SLAVE_1_MASTER_3 2 +#define STM32_TIM_TS_SLAVE_1_MASTER_4 3 +#define STM32_TIM_TS_SLAVE_2_MASTER_9 0 +#define STM32_TIM_TS_SLAVE_2_MASTER_10 1 +#define STM32_TIM_TS_SLAVE_2_MASTER_3 2 +#define STM32_TIM_TS_SLAVE_2_MASTER_4 3 +#define STM32_TIM_TS_SLAVE_3_MASTER_9 0 +#define STM32_TIM_TS_SLAVE_3_MASTER_2 1 +#define STM32_TIM_TS_SLAVE_3_MASTER_11 2 +#define STM32_TIM_TS_SLAVE_3_MASTER_4 3 +#define STM32_TIM_TS_SLAVE_4_MASTER_10 0 +#define STM32_TIM_TS_SLAVE_4_MASTER_2 1 +#define STM32_TIM_TS_SLAVE_4_MASTER_3 2 +#define STM32_TIM_TS_SLAVE_4_MASTER_9 3 +#define STM32_TIM_TS_SLAVE_9_MASTER_2 0 +#define STM32_TIM_TS_SLAVE_9_MASTER_3 1 +#define STM32_TIM_TS_SLAVE_9_MASTER_10 2 +#define STM32_TIM_TS_SLAVE_9_MASTER_11 3 +#define TSMAP1(slave, master) STM32_TIM_TS_SLAVE_ ## slave ## _MASTER_ ## master +#define TSMAP(slave, master) TSMAP1(slave, master) /* - * TIM_CLOCK_MSB and TIM_CLOCK_LSB must be defined per board. The available - * values are 2, 3, and 4. This gives us flexibility to make any of the three - * timer as a PWM source. + * Timers are defined per board. This gives us flexibility to work around + * timers which are dedicated to board-specific PWM sources. */ #define IRQ_TIM(n) STM32_CAT(STM32_IRQ_TIM, n, ) #define IRQ_MSB IRQ_TIM(TIM_CLOCK_MSB) #define IRQ_LSB IRQ_TIM(TIM_CLOCK_LSB) +#define IRQ_WD IRQ_TIM(TIM_WATCHDOG) + +/* TIM1 has fancy names for its IRQs; remap count-up IRQ for the macro above */ +#define STM32_IRQ_TIM1 STM32_IRQ_TIM1_UP_TIM16 -enum { - TIM_WD_BASE = STM32_TIM1_BASE, -}; +#define TIM_BASE(n) STM32_CAT(STM32_TIM, n, _BASE) +#define TIM_WD_BASE TIM_BASE(TIM_WATCHDOG) static uint32_t last_deadline; @@ -123,6 +161,16 @@ static void __hw_clock_source_irq(void) DECLARE_IRQ(IRQ_MSB, __hw_clock_source_irq, 1); DECLARE_IRQ(IRQ_LSB, __hw_clock_source_irq, 1); +void __hw_timer_enable_clock(int n) +{ + if (n == 1) /* STM32F only */ + STM32_RCC_APB2ENR |= 1 << 11; + else if (n >= 2 && n <= 7) + STM32_RCC_APB1ENR |= 1 << (n - 2); + else if (n >= 9 && n <= 11) /* STM32L only */ + STM32_RCC_APB2ENR |= 1 << (n - 7); +} + int __hw_clock_source_init(uint32_t start_t) { /* @@ -132,8 +180,8 @@ int __hw_clock_source_init(uint32_t start_t) */ /* Enable TIM_CLOCK_MSB and TIM_CLOCK_LSB clocks */ - STM32_RCC_APB1ENR |= (1 << (TIM_CLOCK_MSB - 2)) | - (1 << (TIM_CLOCK_LSB - 2)); + __hw_timer_enable_clock(TIM_CLOCK_MSB); + __hw_timer_enable_clock(TIM_CLOCK_LSB); /* * Timer configuration : Upcounter, counter disabled, update event only @@ -147,9 +195,11 @@ int __hw_clock_source_init(uint32_t start_t) */ STM32_TIM_CR2(TIM_CLOCK_MSB) = 0x0000; STM32_TIM_CR2(TIM_CLOCK_LSB) = 0x0020; - /* TIM_CLOCK_MSB (slave mode) uses TIM_CLOCK_LSB as internal trigger */ - STM32_TIM_SMCR(TIM_CLOCK_MSB) = 0x0007 | ((TIM_CLOCK_LSB - 1) << 4); + + STM32_TIM_SMCR(TIM_CLOCK_MSB) = 0x0007 | + (TSMAP(TIM_CLOCK_MSB, TIM_CLOCK_LSB) << 4); STM32_TIM_SMCR(TIM_CLOCK_LSB) = 0x0000; + /* Auto-reload value : 16-bit free-running counters */ STM32_TIM_ARR(TIM_CLOCK_MSB) = 0xffff; STM32_TIM_ARR(TIM_CLOCK_LSB) = 0xffff; @@ -184,12 +234,7 @@ int __hw_clock_source_init(uint32_t start_t) return IRQ_LSB; } -/* - * We don't have TIM1 on STM32L, so don't support this function for now. TIM5 - * doesn't appear to exist in either variant, and TIM9 cannot be triggered as a - * slave from TIM4. We could perhaps use TIM9 as our fast counter on STM32L. - */ -#if defined(CONFIG_WATCHDOG) && !defined(CHIP_VARIANT_stm32l15x) +#ifdef CONFIG_WATCHDOG_HELP void watchdog_check(uint32_t excep_lr, uint32_t excep_sp) { @@ -201,8 +246,8 @@ void watchdog_check(uint32_t excep_lr, uint32_t excep_sp) watchdog_trace(excep_lr, excep_sp); } -void IRQ_HANDLER(TIM_WD_IRQ)(void) __attribute__((naked)); -void IRQ_HANDLER(TIM_WD_IRQ)(void) +void IRQ_HANDLER(IRQ_WD)(void) __attribute__((naked)); +void IRQ_HANDLER(IRQ_WD)(void) { /* Naked call so we can extract raw LR and SP */ asm volatile("mov r0, lr\n" @@ -215,9 +260,9 @@ void IRQ_HANDLER(TIM_WD_IRQ)(void) "pop {r0, lr}\n" "b task_resched_if_needed\n"); } -const struct irq_priority IRQ_BUILD_NAME(prio_, TIM_WD_IRQ, ) +const struct irq_priority IRQ_BUILD_NAME(prio_, IRQ_WD, ) __attribute__((section(".rodata.irqprio"))) - = {TIM_WD_IRQ, 0}; /* put the watchdog at the highest + = {IRQ_WD, 0}; /* put the watchdog at the highest priority */ void hwtimer_setup_watchdog(void) @@ -225,11 +270,7 @@ void hwtimer_setup_watchdog(void) struct timer_ctlr *timer = (struct timer_ctlr *)TIM_WD_BASE; /* Enable clock */ -#if TIM_WD == 1 - STM32_RCC_APB2ENR |= 1 << 11; -#else - STM32_RCC_APB1ENR |= 1 << (TIM_WD - 2); -#endif + __hw_timer_enable_clock(TIM_WATCHDOG); /* * Timer configuration : Down counter, counter disabled, update @@ -238,7 +279,7 @@ void hwtimer_setup_watchdog(void) timer->cr1 = 0x0014 | (1 << 7); /* TIM (slave mode) uses TIM_CLOCK_LSB as internal trigger */ - timer->smcr = 0x0007 | ((TIM_CLOCK_LSB - 1) << 4); + timer->smcr = 0x0007 | (TSMAP(TIM_WATCHDOG, TIM_CLOCK_LSB) << 4); /* * The auto-reload value is based on the period between rollovers for @@ -247,7 +288,7 @@ void hwtimer_setup_watchdog(void) * to obtain the number of times TIM_CLOCK_LSB can overflow before we * generate an interrupt. */ - timer->arr = timer->cnt = WATCHDOG_PERIOD_MS * 1000 / (1 << 16); + timer->arr = timer->cnt = WATCHDOG_PERIOD_MS * MSEC / (1 << 16); /* count on every TIM_CLOCK_LSB overflow */ timer->psc = 0; @@ -262,7 +303,7 @@ void hwtimer_setup_watchdog(void) timer->cr1 |= 1; /* Enable timer interrupts */ - task_enable_irq(TIM_WD_IRQ); + task_enable_irq(IRQ_WD); } void hwtimer_reset_watchdog(void) @@ -272,4 +313,4 @@ void hwtimer_reset_watchdog(void) timer->cnt = timer->arr; } -#endif /* defined(CONFIG_WATCHDOG) && !defined(CHIP_VARIANT_stm32l15x) */ +#endif /* defined(CONFIG_WATCHDOG) */ diff --git a/include/hwtimer.h b/include/hwtimer.h index 06344bbb4b..0b5f4e27df 100644 --- a/include/hwtimer.h +++ b/include/hwtimer.h @@ -27,6 +27,13 @@ uint32_t __hw_clock_source_read(void); void __hw_clock_source_set(uint32_t ts); /** + * Enable clock to a timer. + * + * @param n Timer number to enable + */ +void __hw_timer_enable_clock(int n); + +/** * Initializes the hardware timer used to provide clock services, using the * specified start timer value. * |