1use kernel::platform;
8use kernel::utilities::registers::interfaces::{Readable, Writeable};
9use kernel::utilities::registers::{register_bitfields, register_structs, ReadWrite, WriteOnly};
10use kernel::utilities::StaticRef;
11
12register_structs! {
15    pub AonTimerRegisters {
16        (0x000 => alert_test: WriteOnly<u32, ALERT_TEST::Register>),
18        (0x004 => wkup_ctrl: ReadWrite<u32, WKUP_CTRL::Register>),
20        (0x008 => wkup_thold: ReadWrite<u32, THRESHOLD::Register>),
22        (0x00C => wkup_count: ReadWrite<u32, WKUP_COUNT::Register>),
24        (0x010 => wdog_regwen: ReadWrite<u32, WDOG_REGWEN::Register>),
26        (0x014 => wdog_ctrl: ReadWrite<u32, WDOG_CTRL::Register>),
28        (0x018 => wdog_bark_thold: ReadWrite<u32, THRESHOLD::Register>),
30        (0x01C => wdog_bite_thold: ReadWrite<u32, THRESHOLD::Register>),
32        (0x020 => wdog_count: ReadWrite<u32, WDOG_COUNT::Register>),
34        (0x024 => intr_state: ReadWrite<u32, INTR::Register>),
36        (0x028 => intr_test: WriteOnly<u32, INTR::Register>),
38        (0x02C => wkup_cause: ReadWrite<u32, WKUP_CAUSE::Register>),
40        (0x030 => @END),
41    }
42}
43
44register_bitfields![u32,
45    ALERT_TEST[
46        FATAL_FAULT OFFSET(0) NUMBITS(1) []
47    ],
48    WKUP_CTRL[
49        ENABLE OFFSET(0) NUMBITS(1) [],
50        PRESCALER OFFSET(1) NUMBITS(12) []
51    ],
52    THRESHOLD[
53        THRESHOLD OFFSET(0) NUMBITS(32) []
54    ],
55    WKUP_COUNT[
56        COUNT OFFSET(0) NUMBITS(32) []
57    ],
58    WDOG_REGWEN[
59        REGWEN OFFSET(0) NUMBITS(1) []
60    ],
61    WDOG_CTRL[
62        ENABLE OFFSET(0) NUMBITS(1) [],
63        PAUSE_IN_SLEEP OFFSET(1) NUMBITS(1) []
64    ],
65    WDOG_COUNT[
66        COUNT OFFSET(0) NUMBITS(32) [],
67    ],
68    INTR[
69        WKUP_TIMER_EXPIRED OFFSET(0) NUMBITS(1) [],
70        WDOG_TIMER_BARK OFFSET(1) NUMBITS(1) []
71    ],
72    WKUP_CAUSE[
73        CAUSE OFFSET(0) NUMBITS(1) [],
74    ]
75];
76
77pub struct AonTimer {
78    registers: StaticRef<AonTimerRegisters>,
79    aon_clk_freq: u32, }
81
82impl AonTimer {
83    pub const fn new(base: StaticRef<AonTimerRegisters>, aon_clk_freq: u32) -> AonTimer {
84        AonTimer {
85            registers: base,
86            aon_clk_freq,
87        }
88    }
89
90    fn reset_timers(&self) {
92        let regs = self.registers;
93        regs.wkup_count.set(0x00);
94        regs.wdog_count.set(0x00);
95    }
96
97    fn wdog_start_count(&self) {
100        self.registers
101            .wdog_ctrl
102            .write(WDOG_CTRL::ENABLE::SET + WDOG_CTRL::PAUSE_IN_SLEEP::SET);
103    }
104
105    fn set_wdog_thresh(&self) {
107        let regs = self.registers;
108        let bark_cycles = self.ms_to_cycles(500);
112        let bite_cycles = bark_cycles.saturating_mul(2);
114
115        regs.wdog_bark_thold
116            .write(THRESHOLD::THRESHOLD.val(bark_cycles));
117        regs.wdog_bite_thold
118            .write(THRESHOLD::THRESHOLD.val(bite_cycles));
119    }
120
121    fn wdog_pet(&self) {
123        self.registers.wdog_count.set(0x00);
124    }
125
126    fn wdog_suspend(&self) {
127        self.registers.wdog_ctrl.write(WDOG_CTRL::ENABLE::CLEAR);
128    }
129
130    fn wdog_resume(&self) {
131        self.registers.wdog_ctrl.write(WDOG_CTRL::ENABLE::SET);
132    }
133
134    fn lock_wdog_conf(&self) {
136        self.registers.wdog_regwen.write(WDOG_REGWEN::REGWEN::SET)
137    }
138
139    fn ms_to_cycles(&self, ms: u32) -> u32 {
141        ms.saturating_mul(self.aon_clk_freq).saturating_div(1000)
143    }
144
145    fn reset_wkup_count(&self) {
146        self.registers.wkup_count.set(0x00);
147    }
148
149    pub fn handle_interrupt(&self) {
150        let regs = self.registers;
151        let intr = self.registers.intr_state.extract();
152
153        if intr.is_set(INTR::WKUP_TIMER_EXPIRED) {
154            regs.wkup_cause.set(0x00);
156            regs.wkup_count.set(0x00); self.reset_wkup_count();
158            regs.intr_state.write(INTR::WKUP_TIMER_EXPIRED::SET);
160        }
161
162        if intr.is_set(INTR::WDOG_TIMER_BARK) {
163            regs.intr_state.write(INTR::WDOG_TIMER_BARK::SET);
165            self.wdog_pet();
166        }
167    }
168}
169
170impl platform::watchdog::WatchDog for AonTimer {
171    fn setup(&self) {
180        self.reset_timers();
182
183        self.set_wdog_thresh();
185
186        self.wdog_start_count();
188
189        self.lock_wdog_conf();
193    }
194
195    fn tickle(&self) {
196        self.wdog_pet();
198    }
199
200    fn suspend(&self) {
201        self.wdog_suspend();
202    }
203
204    fn resume(&self) {
205        self.wdog_resume();
206    }
207}