From f771cca719c09feb8da6ce5b670d85fa4c9920db Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Thu, 2 Feb 2012 17:00:53 +0000 Subject: [PATCH] stm32l: add watchdog support Use the Independant WatchDog. The Window WatchDog would provide a nice early warning interrupt before actually rebooting but the max period (128 ms) is probably too short for our purpose. The full GPIO support and the reboot cause detection will be implemented in later steps. Signed-off-by: Vincent Palatin BUG=None TEST=on Discovery board, do blocking waits of 500ms and 1500ms, and check the latter reboots the platform and the former does not. Change-Id: I26e4d8b26b733269b7811cc3b3a09daf98ea364a --- board/discovery/board.c | 6 +++ board/discovery/ec.tasklist | 1 + chip/stm32l/build.mk | 1 + chip/stm32l/registers.h | 9 +++++ chip/stm32l/watchdog.c | 75 +++++++++++++++++++++++++++++++++++++ 5 files changed, 92 insertions(+) create mode 100644 chip/stm32l/watchdog.c diff --git a/board/discovery/board.c b/board/discovery/board.c index ec18af63e3..560773d829 100644 --- a/board/discovery/board.c +++ b/board/discovery/board.c @@ -20,6 +20,9 @@ void configure_board(void) (0x7 << 12) | (0x7 << 8); STM32L_GPIO_MODER(B) = (STM32L_GPIO_MODER(B) & ~0x00F00000) | 0x00A00000; + + /* Green and blue LEDs : configure port 6 and 7 as output */ + STM32L_GPIO_MODER(B) |= (1 << (7 * 2)) | (1 << (6 * 2)); } /** @@ -28,6 +31,9 @@ void configure_board(void) */ int jtag_pre_init(void) { + /* stop TIM2, TIM3 and watchdogs when the JTAG stops the CPU */ + STM32L_DBGMCU_APB1FZ |= 0x00001803; + return EC_SUCCESS; } diff --git a/board/discovery/ec.tasklist b/board/discovery/ec.tasklist index 8e52f9f1c2..0e5992b96b 100644 --- a/board/discovery/ec.tasklist +++ b/board/discovery/ec.tasklist @@ -14,4 +14,5 @@ * 'd' in an opaque parameter passed to the routine at startup */ #define CONFIG_TASK_LIST \ + TASK(WATCHDOG, watchdog_task, NULL) \ TASK(CONSOLE, console_task, NULL) diff --git a/chip/stm32l/build.mk b/chip/stm32l/build.mk index e28b56d6c4..bb354c2f92 100644 --- a/chip/stm32l/build.mk +++ b/chip/stm32l/build.mk @@ -9,3 +9,4 @@ CORE:=cortex-m chip-y=uart.o clock.o hwtimer.o system.o +chip-$(CONFIG_TASK_WATCHDOG)+=watchdog.o diff --git a/chip/stm32l/registers.h b/chip/stm32l/registers.h index ad06983cc5..7fa8ec88d3 100644 --- a/chip/stm32l/registers.h +++ b/chip/stm32l/registers.h @@ -221,6 +221,15 @@ #define STM32L_RTC_TAFCR REG32(STM32L_RTC_BASE + 0x40) #define STM32L_RTC_BACKUP(n) REG32(STM32L_RTC_BASE + 0x50 + 4 * (n)) +/* --- Debug --- */ + +#define STM32L_DBGMCU_BASE 0xE0042000 + +#define STM32L_DBGMCU_IDCODE REG32(STM32L_DBGMCU_BASE + 0x00) +#define STM32L_DBGMCU_CR REG32(STM32L_DBGMCU_BASE + 0x04) +#define STM32L_DBGMCU_APB1FZ REG32(STM32L_DBGMCU_BASE + 0x08) +#define STM32L_DBGMCU_APB2FZ REG32(STM32L_DBGMCU_BASE + 0x0C) + /* --- MISC --- */ #define STM32L_RI_BASE 0x40007C04 diff --git a/chip/stm32l/watchdog.c b/chip/stm32l/watchdog.c new file mode 100644 index 0000000000..114c3e9211 --- /dev/null +++ b/chip/stm32l/watchdog.c @@ -0,0 +1,75 @@ +/* Copyright (c) 2012 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. + */ + +/* Watchdog driver */ + +#include + +#include "board.h" +#include "common.h" +#include "config.h" +#include "registers.h" +#include "gpio.h" +#include "task.h" +#include "timer.h" +#include "uart.h" +#include "util.h" + +/* LSI oscillator frequency is typically 38 kHz + * but might vary from 28 to 56kHz. + * So let's pick 56kHz to ensure we reload + * early enough. + */ +#define LSI_CLOCK 56000 + +/* Prescaler divider = /256 */ +#define IWDG_PRESCALER 6 +#define IWDG_PRESCALER_DIV (1 << ((IWDG_PRESCALER) + 2)) + +void watchdog_reload(void) +{ + /* Reload the watchdog */ + STM32L_IWDG_KR = 0xaaaa; +} + +int watchdog_init(int period_ms) +{ + uint32_t watchdog_period; + + /* set the time-out period */ + watchdog_period = period_ms * (LSI_CLOCK / IWDG_PRESCALER_DIV) / 1000; + + /* Unlock watchdog registers */ + STM32L_IWDG_KR = 0x5555; + + /* Set the prescaler between the LSI clock and the watchdog counter */ + STM32L_IWDG_PR = IWDG_PRESCALER & 7; + /* Set the reload value of the watchdog counter */ + STM32L_IWDG_RLR = watchdog_period & 0x7FF ; + + /* Start the watchdog (and re-lock registers) */ + STM32L_IWDG_KR = 0xcccc; + + return EC_SUCCESS; +} + +/* Low priority task to reload the watchdog */ +void watchdog_task(void) +{ + while (1) { +#ifdef BOARD_discovery + /* TODO use GPIO API: gpio_set_level(GPIO_GREEN_LED, 1); */ + STM32L_GPIO_ODR(B) |= (1 << 7) ; +#endif + usleep(500000); + watchdog_reload(); +#ifdef BOARD_discovery + /* TODO use GPIO API: gpio_set_level(GPIO_GREEN_LED, 0); */ + STM32L_GPIO_ODR(B) &= ~(1 << 7) ; +#endif + usleep(500000); + watchdog_reload(); + } +}