1use core::cell::Cell;
8
9use crate::pm::{self, Clock, PBDClock};
10
11use cortexm4::support;
12
13use kernel::utilities::StaticRef;
14use kernel::utilities::math::log_base_two_u64;
15use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
16use kernel::utilities::registers::{
17 FieldValue, ReadOnly, ReadWrite, WriteOnly, register_bitfields, register_structs,
18};
19
20register_structs! {
21 pub WdtRegisters {
22 (0x000 => cr: ReadWrite<u32, Control::Register>),
23 (0x004 => clr: WriteOnly<u32, Clear::Register>),
24 (0x008 => sr: ReadOnly<u32, Status::Register>),
25 (0x00C => ier: WriteOnly<u32, Interrupt::Register>),
26 (0x010 => idr: WriteOnly<u32, Interrupt::Register>),
27 (0x014 => imr: ReadOnly<u32, Interrupt::Register>),
28 (0x018 => isr: ReadOnly<u32, Interrupt::Register>),
29 (0x01C => icr: WriteOnly<u32, Interrupt::Register>),
30 (0x020 => @END),
31 }
32}
33
34register_bitfields![u32,
35 Control [
36 KEY OFFSET(24) NUMBITS(8) [
38 KEY1 = 0x55,
39 KEY2 = 0xAA
40 ],
41 TBAN OFFSET(18) NUMBITS(5) [],
43 CSSEL OFFSET(17) NUMBITS(1) [
45 RCSYS = 0,
46 OSC32K = 1
47 ],
48 CEN OFFSET(16) NUMBITS(1) [
50 ClockDisable = 0,
51 ClockEnable = 1
52 ],
53 PSEL OFFSET(8) NUMBITS(5) [],
55 FCD OFFSET(7) NUMBITS(1) [
57 RedoCalibration = 0,
58 DoNotRedoCalibration = 1
59 ],
60 IM OFFSET(4) NUMBITS(1) [
62 InterruptModeDisabled = 0,
63 InterruptModeEnabled = 1
64 ],
65 SFV OFFSET(3) NUMBITS(1) [
67 NotLocked = 0,
68 Locked = 1
69 ],
70 MODE OFFSET(2) NUMBITS(1) [
72 Basic = 0,
73 Window = 1
74 ],
75 DAR OFFSET(1) NUMBITS(1) [
77 EnableAfterReset = 0,
78 DisableAfterReset = 1
79 ],
80 EN OFFSET(0) NUMBITS(1) [
82 Disable = 0,
83 Enable = 1
84 ]
85 ],
86
87 Clear [
88 KEY OFFSET(24) NUMBITS(8) [
90 KEY1 = 0x55,
91 KEY2 = 0xAA
92 ],
93 WDTCLR OFFSET(0) NUMBITS(1) []
95 ],
96
97 Status [
98 CLEARED 1,
100 WINDOW 0
102 ],
103
104 Interrupt [
105 WINT 2
106 ]
107];
108
109const WDT_BASE: *mut WdtRegisters = 0x400F0C00 as *mut WdtRegisters;
111const WDT_REGS: StaticRef<WdtRegisters> = unsafe { StaticRef::new(WDT_BASE.cast_const()) };
112
113pub struct Wdt {
114 enabled: Cell<bool>,
115}
116
117#[derive(Copy, Clone)]
118pub enum WdtClockSource {
119 ClockRCSys = 0,
120 ClockOsc32 = 1,
121}
122
123impl From<WdtClockSource> for FieldValue<u32, Control::Register> {
124 fn from(clock: WdtClockSource) -> Self {
125 match clock {
126 WdtClockSource::ClockRCSys => Control::CSSEL::RCSYS,
127 WdtClockSource::ClockOsc32 => Control::CSSEL::OSC32K,
128 }
129 }
130}
131
132impl Wdt {
133 pub const fn new() -> Wdt {
134 Wdt {
135 enabled: Cell::new(false),
136 }
137 }
138
139 fn write_cr(&self, control: FieldValue<u32, Control::Register>) {
146 WDT_REGS.cr.modify(Control::KEY::KEY1 + control);
147 WDT_REGS.cr.modify(Control::KEY::KEY2 + control);
148
149 for _ in 0..10000 {
156 support::nop();
157 }
158 }
159
160 fn select_clock(&self, clock: WdtClockSource) {
161 if !(WDT_REGS.cr.matches_all(From::from(clock))) {
162 let clock_enabled = WDT_REGS.cr.is_set(Control::CEN);
163
164 if clock_enabled {
165 self.write_cr(Control::CEN::CLEAR);
167 while WDT_REGS.cr.is_set(Control::CEN) {}
168 }
169
170 self.write_cr(From::from(clock));
172
173 if clock_enabled {
174 self.write_cr(Control::CEN::SET);
176 while !WDT_REGS.cr.is_set(Control::CEN) {}
177 }
178 }
179 }
180
181 fn start(&self, period: usize) {
182 self.enabled.set(true);
183
184 pm::enable_clock(Clock::PBD(PBDClock::WDT));
185
186 self.select_clock(WdtClockSource::ClockOsc32);
191
192 let f_clk_khz: u64 = if WDT_REGS.cr.matches_all(Control::CSSEL::RCSYS) {
200 115
201 } else {
202 32
204 };
205 let mult: u64 = f_clk_khz * (period as u64);
206 let scaler = log_base_two_u64(mult); let control = Control::CEN::ClockEnable
209 + Control::PSEL.val(scaler)
210 + Control::FCD::DoNotRedoCalibration
211 + Control::DAR::DisableAfterReset
212 + Control::EN::Enable;
213 self.write_cr(control);
214 }
215
216 fn stop(&self) {
217 self.write_cr(Control::EN::CLEAR);
218
219 pm::disable_clock(Clock::PBD(PBDClock::WDT));
220
221 self.enabled.set(false);
222 }
223
224 fn tickle(&self) {
225 WDT_REGS.clr.write(Clear::KEY::KEY1 + Clear::WDTCLR::SET);
227 WDT_REGS.clr.write(Clear::KEY::KEY2 + Clear::WDTCLR::SET);
228 }
229}
230
231impl kernel::platform::watchdog::WatchDog for Wdt {
232 fn setup(&self) {
233 self.start(100);
235 }
236
237 fn tickle(&self) {
238 self.tickle();
239 }
240
241 fn suspend(&self) {
242 self.stop();
243 }
244}