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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//! Blocking driver for the BCM Power Management (PM) block's watchdog
//! timer: arms a hardware countdown that triggers a full board reset
//! (equivalent to a power cycle) if it's not re-armed before it
//! expires, for automatic recovery from a hang that leaves nothing
//! running to notice or act on it.
//!
//! Like `rng.rs`, this peripheral isn't modeled in `bcm2837-lpa`'s SVD,
//! so this pokes its known physical addresses directly. Register
//! layout, the password requirement, and the reset-type encodings
//! follow Linux's `bcm2835_wdt` driver (`drivers/watchdog/
//! bcm2835_wdt.c`), the standard reference for this undocumented-by-
//! Broadcom corner of the PM block.
//!
//! ## Password
//!
//! `PM_RSTC`/`PM_WDOG` only accept a write whose top byte is
//! `PM_PASSWORD` — any other value is silently ignored by the
//! hardware. This isn't a security mechanism, just a guard against
//! accidental writes to a register block that can reset the whole
//! board; every write here ORs the password into the value that
//! matters rather than clearing the rest of the register, so it never
//! needs separate handling beyond that OR.
//!
//! ## Countdown units and range
//!
//! `PM_WDOG` is a 20-bit tick count clocked at a fixed 65536 Hz, so the
//! representable range tops out around 16 seconds — see
//! [`MAX_TIMEOUT_MS`]. There's no way to
//! ask for a longer single timeout; a caller needing to survive a longer
//! expected stall must re-arm
//! ([`Watchdog::feed`]) more often than
//! that, not request one
//! long period.
//!
//! ## Stopping
//!
//! [`Watchdog::disable`] writes
//! `PM_RSTC_RESET`, the same "reset type" value Linux's driver uses to stop
//! the watchdog — distinct from the `WRCFG_FULL_RESET` type
//! [`Watchdog::start`]/
//! [`Watchdog::feed`] arm.
//! Broadcom hasn't published what every `PM_RSTC` reset-type encoding
//! means; this one is taken on faith from the reference driver rather
//! than independently derived.
/// PM block base address: `crate::soc::PERIPHERAL_BASE` (BCM2836/2837 or,
/// under the `bcm2711` feature, BCM2711) plus the block's `0x0010_0000`
/// offset, same on both -- the PM block is unchanged IP, just relocated
/// with the rest of the peripheral block.
const PM_BASE: usize = cratePERIPHERAL_BASE as usize + 0x0010_0000;
/// Reset controller register: bits [5:4] select the reset type applied
/// when the watchdog countdown reaches zero (or immediately, for
/// [`PM_RSTC_RESET`]).
const PM_RSTC: *mut u32 = as *mut u32;
/// Watchdog register: bits [19:0] are the countdown, in ticks of a
/// fixed 65536Hz clock; writing it loads a new countdown, reading it
/// returns the countdown remaining.
const PM_WDOG: *mut u32 = as *mut u32;
/// Password required in the top byte of every `PM_RSTC`/`PM_WDOG`
/// write for the hardware to accept it (see this module's doc
/// comment).
const PM_PASSWORD: u32 = 0x5a00_0000;
/// `PM_WDOG`'s 20-bit countdown field.
const PM_WDOG_TIME_MASK: u32 = 0x000f_ffff;
/// `PM_RSTC`'s reset-type field (bits [5:4]).
const PM_RSTC_WRCFG_MASK: u32 = 0x0000_0030;
/// `PM_RSTC` reset-type value that arms a full board reset once the
/// watchdog countdown reaches zero.
const PM_RSTC_WRCFG_FULL_RESET: u32 = 0x0000_0020;
/// `PM_RSTC` reset-type value that disarms the watchdog (see
/// [`Watchdog::disable`]).
const PM_RSTC_RESET: u32 = 0x0000_0102;
/// `PM_WDOG`'s countdown clock rate, fixed in hardware.
const WDOG_TICKS_PER_SEC: u64 = 1 << 16;
/// Largest timeout [`Watchdog::start`]/[`Watchdog::feed`] can arm,
/// imposed by `PM_WDOG`'s 20-bit countdown field at its fixed 65536Hz
/// clock rate (`0xF_FFFF` ticks, truncated down to a whole
/// millisecond).
pub const MAX_TIMEOUT_MS: u32 = as u32;
/// Blocking driver for the PM block's watchdog timer.