1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
/* Copyright 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 "common.h"
#include "gpio.h"
#include "hooks.h"
#include "hwtimer.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
#include "util.h"
#include "watchdog.h"
/*
* LSI oscillator frequency is typically 38 kHz, but it may be between 28-56
* kHz and we don't calibrate it to know. Use 56 kHz so that we pick a counter
* value large enough that we reload before the worst-case watchdog delay
* (fastest LSI clock).
*/
#ifdef CHIP_FAMILY_STM32L4
#define LSI_CLOCK 34000
#else
#define LSI_CLOCK 56000
#endif
/* The timeout value is multiplied by 1000 to be converted into ms */
#define HAL_IWDG_DEFAULT_TIMEOUT ((6UL * 256UL * 1000UL) / LSI_CLOCK)
/*
* Use largest prescaler divider = /256. This gives a worst-case watchdog
* clock of 56000/256 = 218 Hz, and a maximum timeout period of (4095/218 Hz) =
* 18.7 sec.
*
* For STM32L4, Max LSI is 34000. Watchdog clock is 34000 / 256 = 132Hz,
* Max timeout = 4095 / 132 = 31 sec.
*/
#define IWDG_PRESCALER 6
#define IWDG_PRESCALER_DIV (4 << IWDG_PRESCALER)
void watchdog_reload(void)
{
/* Reload the watchdog */
STM32_IWDG_KR = STM32_IWDG_KR_RELOAD;
#ifdef CONFIG_WATCHDOG_HELP
hwtimer_reset_watchdog();
#endif
}
DECLARE_HOOK(HOOK_TICK, watchdog_reload, HOOK_PRIO_DEFAULT);
int watchdog_init(void)
{
#ifdef CHIP_FAMILY_STM32L4
timestamp_t tickstart, ticknow;
/* Enable watchdog registers */
STM32_IWDG_KR = STM32_IWDG_KR_START;
#endif
/* Unlock watchdog registers */
STM32_IWDG_KR = STM32_IWDG_KR_UNLOCK;
/* Set the prescaler between the LSI clock and the watchdog counter */
STM32_IWDG_PR = IWDG_PRESCALER & 7;
/* Set the reload value of the watchdog counter */
STM32_IWDG_RLR = MIN(STM32_IWDG_RLR_MAX, CONFIG_WATCHDOG_PERIOD_MS *
(LSI_CLOCK / IWDG_PRESCALER_DIV) / 1000);
#ifdef CHIP_FAMILY_STM32L4
tickstart = get_time();
/* Wait for SR */
while (STM32_IWDG_SR != 0x00u) {
ticknow = get_time();
if ((ticknow.val - tickstart.val) >
HAL_IWDG_DEFAULT_TIMEOUT * 1000) {
return EC_ERROR_TIMEOUT;
}
}
/* Reload the watchdog */
STM32_IWDG_KR = STM32_IWDG_KR_RELOAD;
#else
/* Start the watchdog (and re-lock registers) */
STM32_IWDG_KR = STM32_IWDG_KR_START;
/*
* We should really wait for IWDG_PR and IWDG_RLR value to be updated
* but updating those registers can take about 48ms (found
* empirically, it's 6 LSI cycles at 32kHz). Such a big delay is not
* desired during system init.
*
* However documentation allows us to continue code execution, but
* we should wait for RVU bit to be clear before updating IWDG_RLR
* once again (hard reboot for STM32H7 and STM32F4).
*
* RM0433 Rev 7
* Section 45.4.4 Page 1920
* https://www.st.com/resource/en/reference_manual/dm00314099.pdf
* If several reload, prescaler, or window values are used by the
* application, it is mandatory to wait until RVU bit is reset before
* changing the reload value, to wait until PVU bit is reset before
* changing the prescaler value, and to wait until WVU bit is reset
* before changing the window value. However, after updating the
* prescaler and/or the reload/window value it is not necessary to wait
* until RVU or PVU or WVU is reset before continuing code execution
* except in case of low-power mode entry.
*/
#endif
#ifdef CONFIG_WATCHDOG_HELP
/* Use a harder timer to warn about an impending watchdog reset */
hwtimer_setup_watchdog();
#endif
return EC_SUCCESS;
}
|