blob: a5cbea04d9511e4d270c9f5da68db5bb5ae30ae0 [file] [log] [blame]
Imre Kiscd007ad2024-08-14 15:53:11 +02001// SPDX-FileCopyrightText: Copyright 2023-2024 Arm Limited and/or its affiliates <open-source-office@arm.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Arm Watchdog Module (SP805) driver
5//!
6//! Driver implementation for the [SP805 watchdog module](https://developer.arm.com/documentation/ddi0270/latest/).
7
8#![no_std]
9
Imre Kise05daa42024-09-26 11:20:06 +020010use core::{
11 ops::{Deref, DerefMut},
12 ptr::addr_of_mut,
13};
Imre Kiscd007ad2024-08-14 15:53:11 +020014
15use bitflags::bitflags;
Imre Kiscd007ad2024-08-14 15:53:11 +020016
17bitflags! {
18 /// Control register
19 #[repr(transparent)]
20 #[derive(Copy, Clone)]
21 struct ControlRegister : u32 {
22 /// Enable Watchdog module reset output
23 const RESEN = 1 << 1;
24 /// Break error
25 const INTEN = 1 << 0;
26 }
27
28 /// Raw Interrupt Status Register
29 #[repr(transparent)]
30 #[derive(Copy, Clone)]
31 struct RawInterruptStatusRegister : u32 {
32 /// Raw interrupt status from the counter
33 const WDOGRIS = 1 << 0;
34 }
35
36 /// Masked Interrupt Status Register
37 struct MaskedInterruptStatusRegister : u32 {
38 /// Enabled interrupt status from the counter
39 const WDOGMIS = 1 << 0;
40 }
41}
42
43/// SP805 register map
44#[repr(C, align(4))]
45pub struct SP805Registers {
Imre Kise05daa42024-09-26 11:20:06 +020046 wdog_load: u32, // 0x000 Load Register
47 wdog_value: u32, // 0x004 Value Register
48 wdog_control: u32, // 0x008 Control register
49 wdog_intclr: u32, // 0x00c Interrupt Clear Register
50 wdog_ris: u32, // 0x010 Raw Interrupt Status Register
51 wdog_mis: u32, // 0x014 Masked Interrupt Status Register
Imre Kiscd007ad2024-08-14 15:53:11 +020052 reserved_18: [u32; 762], // 0x018 - 0xbfc
Imre Kise05daa42024-09-26 11:20:06 +020053 wdog_lock: u32, // 0xc00 Lock Register
Imre Kiscd007ad2024-08-14 15:53:11 +020054 reserved_c04: [u32; 191], // 0xc04 - 0xefc
Imre Kise05daa42024-09-26 11:20:06 +020055 wdog_itcr: u32, // 0xf00 Integration Test Control Register,
56 wdog_itop: u32, // 0xf04 Integration Test Output Set
Imre Kiscd007ad2024-08-14 15:53:11 +020057 reserved_f08: [u32; 54], // 0xf08 - 0xfdc
Imre Kise05daa42024-09-26 11:20:06 +020058 wdog_periph_id0: u32, // 0xfe0 Peripheral Identification Register 0
59 wdog_periph_id1: u32, // 0xfe4 Peripheral Identification Register 1
60 wdog_periph_id2: u32, // 0xfe8 Peripheral Identification Register 2
61 wdog_periph_id3: u32, // 0xfec Peripheral Identification Register 3
62 wdog_pcell_id0: u32, // 0xff0 PrimeCell Identification Register 0
63 wdog_pcell_id1: u32, // 0xff4 PrimeCell Identification Register 1
64 wdog_pcell_id2: u32, // 0xff8 PrimeCell Identification Register 2
65 wdog_pcell_id3: u32, // 0xffc PrimeCell Identification Register 3
Imre Kiscd007ad2024-08-14 15:53:11 +020066}
67
68struct WatchdogUnlockGuard<'a, R>
69where
Imre Kise05daa42024-09-26 11:20:06 +020070 R: DerefMut<Target = SP805Registers>,
Imre Kiscd007ad2024-08-14 15:53:11 +020071{
Imre Kise05daa42024-09-26 11:20:06 +020072 regs: &'a mut R,
Imre Kiscd007ad2024-08-14 15:53:11 +020073}
74
75impl<'a, R> WatchdogUnlockGuard<'a, R>
76where
Imre Kise05daa42024-09-26 11:20:06 +020077 R: DerefMut<Target = SP805Registers>,
Imre Kiscd007ad2024-08-14 15:53:11 +020078{
79 const LOCK: u32 = 0x00000001;
80 const UNLOCK: u32 = 0x1ACCE551;
81
Imre Kise05daa42024-09-26 11:20:06 +020082 pub fn new(regs: &'a mut R) -> Self {
Imre Kis03f96f02024-10-02 14:11:25 +020083 // SAFETY: regs can be dereferenced as a valid SP805 register block
Imre Kiscd007ad2024-08-14 15:53:11 +020084 unsafe {
Imre Kise05daa42024-09-26 11:20:06 +020085 addr_of_mut!(regs.wdog_lock).write_volatile(Self::UNLOCK);
Imre Kiscd007ad2024-08-14 15:53:11 +020086 }
87 Self { regs }
88 }
89}
90
91impl<'a, R> Deref for WatchdogUnlockGuard<'a, R>
92where
Imre Kise05daa42024-09-26 11:20:06 +020093 R: DerefMut<Target = SP805Registers>,
Imre Kiscd007ad2024-08-14 15:53:11 +020094{
95 type Target = R;
96
97 fn deref(&self) -> &Self::Target {
98 self.regs
99 }
100}
101
Imre Kise05daa42024-09-26 11:20:06 +0200102impl<'a, R> DerefMut for WatchdogUnlockGuard<'a, R>
103where
104 R: DerefMut<Target = SP805Registers>,
105{
106 fn deref_mut(&mut self) -> &mut Self::Target {
107 self.regs
108 }
109}
110
Imre Kiscd007ad2024-08-14 15:53:11 +0200111impl<'a, R> Drop for WatchdogUnlockGuard<'a, R>
112where
Imre Kise05daa42024-09-26 11:20:06 +0200113 R: DerefMut<Target = SP805Registers>,
Imre Kiscd007ad2024-08-14 15:53:11 +0200114{
115 fn drop(&mut self) {
Imre Kis03f96f02024-10-02 14:11:25 +0200116 // SAFETY: self.regs can be dereferenced as a valid SP805 register block
Imre Kiscd007ad2024-08-14 15:53:11 +0200117 unsafe {
Imre Kise05daa42024-09-26 11:20:06 +0200118 addr_of_mut!(self.regs.wdog_lock).write_volatile(Self::LOCK);
Imre Kiscd007ad2024-08-14 15:53:11 +0200119 }
120 }
121}
122
123/// SP805 Watchdog implementation
124pub struct Watchdog<R>
125where
126 R: Deref<Target = SP805Registers>,
127{
128 regs: R,
129 load_value: u32,
130}
131
132impl<R> Watchdog<R>
133where
Imre Kise05daa42024-09-26 11:20:06 +0200134 R: DerefMut<Target = SP805Registers>,
Imre Kiscd007ad2024-08-14 15:53:11 +0200135{
136 /// Create new watchdog instance
137 pub fn new(regs: R, load_value: u32) -> Self {
138 Self { regs, load_value }
139 }
140
141 /// Enable watchdog
Imre Kise05daa42024-09-26 11:20:06 +0200142 pub fn enable(&mut self) {
143 let load_value = self.load_value;
144 let mut regs = self.unlock();
Imre Kiscd007ad2024-08-14 15:53:11 +0200145
Imre Kis03f96f02024-10-02 14:11:25 +0200146 // SAFETY: self.regs can be dereferenced as a valid SP805 register block
Imre Kiscd007ad2024-08-14 15:53:11 +0200147 unsafe {
Imre Kise05daa42024-09-26 11:20:06 +0200148 addr_of_mut!(regs.wdog_load).write_volatile(load_value);
149 addr_of_mut!(regs.wdog_intclr).write_volatile(1);
150 addr_of_mut!(regs.wdog_control)
151 .write_volatile((ControlRegister::INTEN | ControlRegister::RESEN).bits());
Imre Kiscd007ad2024-08-14 15:53:11 +0200152 }
153 }
154
155 /// Disable watchdog
Imre Kise05daa42024-09-26 11:20:06 +0200156 pub fn disable(&mut self) {
Imre Kis03f96f02024-10-02 14:11:25 +0200157 // SAFETY: self.regs can be dereferenced as a valid SP805 register block
Imre Kiscd007ad2024-08-14 15:53:11 +0200158 unsafe {
Imre Kise05daa42024-09-26 11:20:06 +0200159 addr_of_mut!(self.unlock().wdog_control)
160 .write_volatile(ControlRegister::empty().bits());
Imre Kiscd007ad2024-08-14 15:53:11 +0200161 }
162 }
163
164 /// Update watchdog
Imre Kise05daa42024-09-26 11:20:06 +0200165 pub fn update(&mut self) {
166 let load_value = self.load_value;
167
Imre Kis03f96f02024-10-02 14:11:25 +0200168 // SAFETY: self.regs can be dereferenced as a valid SP805 register block
Imre Kiscd007ad2024-08-14 15:53:11 +0200169 unsafe {
Imre Kise05daa42024-09-26 11:20:06 +0200170 addr_of_mut!(self.unlock().wdog_load).write_volatile(load_value);
Imre Kiscd007ad2024-08-14 15:53:11 +0200171 }
172 }
173
Imre Kise05daa42024-09-26 11:20:06 +0200174 fn unlock(&mut self) -> WatchdogUnlockGuard<R> {
175 WatchdogUnlockGuard::new(&mut self.regs)
Imre Kiscd007ad2024-08-14 15:53:11 +0200176 }
177}