blob: ef4dd83a7d3897048b8dc12480fffc731ac9eb7f [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
10use core::ops::Deref;
11
12use bitflags::bitflags;
13use volatile_register::{RO, RW, WO};
14
15bitflags! {
16 /// Control register
17 #[repr(transparent)]
18 #[derive(Copy, Clone)]
19 struct ControlRegister : u32 {
20 /// Enable Watchdog module reset output
21 const RESEN = 1 << 1;
22 /// Break error
23 const INTEN = 1 << 0;
24 }
25
26 /// Raw Interrupt Status Register
27 #[repr(transparent)]
28 #[derive(Copy, Clone)]
29 struct RawInterruptStatusRegister : u32 {
30 /// Raw interrupt status from the counter
31 const WDOGRIS = 1 << 0;
32 }
33
34 /// Masked Interrupt Status Register
35 struct MaskedInterruptStatusRegister : u32 {
36 /// Enabled interrupt status from the counter
37 const WDOGMIS = 1 << 0;
38 }
39}
40
41/// SP805 register map
42#[repr(C, align(4))]
43pub struct SP805Registers {
44 wdog_load: RW<u32>, // 0x000 Load Register
45 wdog_value: RO<u32>, // 0x004 Value Register
46 wdog_control: RW<u32>, // 0x008 Control register
47 wdog_intclr: WO<u32>, // 0x00c Interrupt Clear Register
48 wdog_ris: RO<u32>, // 0x010 Raw Interrupt Status Register
49 wdog_mis: RO<u32>, // 0x014 Masked Interrupt Status Register
50 reserved_18: [u32; 762], // 0x018 - 0xbfc
51 wdog_lock: RW<u32>, // 0xc00 Lock Register
52 reserved_c04: [u32; 191], // 0xc04 - 0xefc
53 wdog_itcr: RW<u32>, // 0xf00 Integration Test Control Register,
54 wdog_itop: WO<u32>, // 0xf04 Integration Test Output Set
55 reserved_f08: [u32; 54], // 0xf08 - 0xfdc
56 wdog_periph_id0: RO<u32>, // 0xfe0 Peripheral Identification Register 0
57 wdog_periph_id1: RO<u32>, // 0xfe4 Peripheral Identification Register 1
58 wdog_periph_id2: RO<u32>, // 0xfe8 Peripheral Identification Register 2
59 wdog_periph_id3: RO<u32>, // 0xfec Peripheral Identification Register 3
60 wdog_pcell_id0: RO<u32>, // 0xff0 PrimeCell Identification Register 0
61 wdog_pcell_id1: RO<u32>, // 0xff4 PrimeCell Identification Register 1
62 wdog_pcell_id2: RO<u32>, // 0xff8 PrimeCell Identification Register 2
63 wdog_pcell_id3: RO<u32>, // 0xffc PrimeCell Identification Register 3
64}
65
66struct WatchdogUnlockGuard<'a, R>
67where
68 R: Deref<Target = SP805Registers>,
69{
70 regs: &'a R,
71}
72
73impl<'a, R> WatchdogUnlockGuard<'a, R>
74where
75 R: Deref<Target = SP805Registers>,
76{
77 const LOCK: u32 = 0x00000001;
78 const UNLOCK: u32 = 0x1ACCE551;
79
80 pub fn new(regs: &'a R) -> Self {
81 unsafe {
82 regs.wdog_lock.write(Self::UNLOCK);
83 }
84 Self { regs }
85 }
86}
87
88impl<'a, R> Deref for WatchdogUnlockGuard<'a, R>
89where
90 R: Deref<Target = SP805Registers>,
91{
92 type Target = R;
93
94 fn deref(&self) -> &Self::Target {
95 self.regs
96 }
97}
98
99impl<'a, R> Drop for WatchdogUnlockGuard<'a, R>
100where
101 R: Deref<Target = SP805Registers>,
102{
103 fn drop(&mut self) {
104 unsafe {
105 self.regs.wdog_lock.write(Self::LOCK);
106 }
107 }
108}
109
110/// SP805 Watchdog implementation
111pub struct Watchdog<R>
112where
113 R: Deref<Target = SP805Registers>,
114{
115 regs: R,
116 load_value: u32,
117}
118
119impl<R> Watchdog<R>
120where
121 R: Deref<Target = SP805Registers>,
122{
123 /// Create new watchdog instance
124 pub fn new(regs: R, load_value: u32) -> Self {
125 Self { regs, load_value }
126 }
127
128 /// Enable watchdog
129 pub fn enable(&self) {
130 let regs = self.unlock();
131
132 unsafe {
133 regs.wdog_load.write(self.load_value);
134 regs.wdog_intclr.write(1);
135 regs.wdog_control
136 .write((ControlRegister::INTEN | ControlRegister::RESEN).bits());
137 }
138 }
139
140 /// Disable watchdog
141 pub fn disable(&self) {
142 unsafe {
143 self.unlock()
144 .wdog_control
145 .write(ControlRegister::empty().bits());
146 }
147 }
148
149 /// Update watchdog
150 pub fn update(&self) {
151 unsafe {
152 self.unlock().wdog_load.write(self.load_value);
153 }
154 }
155
156 fn unlock(&self) -> WatchdogUnlockGuard<R> {
157 WatchdogUnlockGuard::new(&self.regs)
158 }
159}