blob: 5156f773b9d28415fc1726da055be28abbbd5348 [file] [log] [blame]
Imre Kisae5c7402025-01-10 17:57:58 +01001// SPDX-FileCopyrightText: Copyright 2023-2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
Imre Kiscd007ad2024-08-14 15:53:11 +02002// 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 Kiscd007ad2024-08-14 15:53:11 +020010use bitflags::bitflags;
Imre Kis826b8612025-03-12 13:07:15 +010011use safe_mmio::{
12 field,
13 fields::{ReadPure, ReadPureWrite, WriteOnly},
14 UniqueMmioPointer,
15};
16use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
17
18#[repr(transparent)]
19#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
20struct ControlRegister(u32);
21
22#[repr(transparent)]
23#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
24struct Interrupts(u32);
Imre Kiscd007ad2024-08-14 15:53:11 +020025
26bitflags! {
27 /// Control register
Imre Kis826b8612025-03-12 13:07:15 +010028 impl ControlRegister : u32 {
Imre Kiscd007ad2024-08-14 15:53:11 +020029 /// Enable Watchdog module reset output
30 const RESEN = 1 << 1;
31 /// Break error
32 const INTEN = 1 << 0;
33 }
34
35 /// Raw Interrupt Status Register
Imre Kis826b8612025-03-12 13:07:15 +010036 impl Interrupts : u32 {
Imre Kiscd007ad2024-08-14 15:53:11 +020037 /// Raw interrupt status from the counter
38 const WDOGRIS = 1 << 0;
39 }
Imre Kiscd007ad2024-08-14 15:53:11 +020040}
41
42/// SP805 register map
Imre Kis826b8612025-03-12 13:07:15 +010043#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
Imre Kiscd007ad2024-08-14 15:53:11 +020044#[repr(C, align(4))]
45pub struct SP805Registers {
Imre Kis826b8612025-03-12 13:07:15 +010046 /// 0x000 Load Register
47 wdog_load: ReadPureWrite<u32>,
48 /// 0x004 Value Register
49 wdog_value: ReadPure<u32>,
50 /// 0x008 Control register
51 wdog_control: ReadPureWrite<ControlRegister>,
52 /// 0x00c Interrupt Clear Register
53 wdog_intclr: WriteOnly<u32>,
54 /// 0x010 Raw Interrupt Status Register
55 wdog_ris: ReadPure<Interrupts>,
56 /// 0x014 Masked Interrupt Status Register
57 wdog_mis: ReadPure<Interrupts>,
58 /// 0x018 - 0xbfc
59 reserved_18: [u32; 762],
60 /// 0xc00 Lock Register
61 wdog_lock: ReadPureWrite<u32>,
62 /// 0xc04 - 0xefc
63 reserved_c04: [u32; 191],
64 /// 0xf00 Integration Test Control Register,
65 wdog_itcr: ReadPureWrite<u32>,
66 /// 0xf04 Integration Test Output Set
67 wdog_itop: WriteOnly<u32>,
68 /// 0xf08 - 0xfdc
69 reserved_f08: [u32; 54],
70 /// 0xfe0 Peripheral Identification Register 0
71 wdog_periph_id0: ReadPure<u32>,
72 /// 0xfe4 Peripheral Identification Register 1
73 wdog_periph_id1: ReadPure<u32>,
74 /// 0xfe8 Peripheral Identification Register 2
75 wdog_periph_id2: ReadPure<u32>,
76 /// 0xfec Peripheral Identification Register 3
77 wdog_periph_id3: ReadPure<u32>,
78 /// 0xff0 PrimeCell Identification Register 0
79 wdog_pcell_id0: ReadPure<u32>,
80 /// 0xff4 PrimeCell Identification Register 1
81 wdog_pcell_id1: ReadPure<u32>,
82 /// 0xff8 PrimeCell Identification Register 2
83 wdog_pcell_id2: ReadPure<u32>,
84 /// 0xffc PrimeCell Identification Register 3
85 wdog_pcell_id3: ReadPure<u32>,
Imre Kiscd007ad2024-08-14 15:53:11 +020086}
87
88/// SP805 Watchdog implementation
Imre Kis826b8612025-03-12 13:07:15 +010089pub struct Watchdog<'a> {
90 regs: UniqueMmioPointer<'a, SP805Registers>,
Imre Kiscd007ad2024-08-14 15:53:11 +020091 load_value: u32,
92}
93
Imre Kis826b8612025-03-12 13:07:15 +010094impl<'a> Watchdog<'a> {
95 const LOCK: u32 = 0x00000001;
96 const UNLOCK: u32 = 0x1ACCE551;
97
Imre Kiscd007ad2024-08-14 15:53:11 +020098 /// Create new watchdog instance
Imre Kis826b8612025-03-12 13:07:15 +010099 pub fn new(regs: UniqueMmioPointer<'a, SP805Registers>, load_value: u32) -> Self {
Imre Kiscd007ad2024-08-14 15:53:11 +0200100 Self { regs, load_value }
101 }
102
103 /// Enable watchdog
Imre Kise05daa42024-09-26 11:20:06 +0200104 pub fn enable(&mut self) {
105 let load_value = self.load_value;
Imre Kiscd007ad2024-08-14 15:53:11 +0200106
Imre Kis826b8612025-03-12 13:07:15 +0100107 self.with_unlock(|mut regs| {
108 field!(regs, wdog_load).write(load_value);
109 field!(regs, wdog_intclr).write(1);
110 field!(regs, wdog_control)
111 .write(ControlRegister::INTEN | ControlRegister::RESEN);
112 });
Imre Kiscd007ad2024-08-14 15:53:11 +0200113 }
114
115 /// Disable watchdog
Imre Kise05daa42024-09-26 11:20:06 +0200116 pub fn disable(&mut self) {
Imre Kis826b8612025-03-12 13:07:15 +0100117 self.with_unlock(|mut regs| {
118 field!(regs, wdog_control).write(ControlRegister::empty())
119 });
Imre Kiscd007ad2024-08-14 15:53:11 +0200120 }
121
122 /// Update watchdog
Imre Kise05daa42024-09-26 11:20:06 +0200123 pub fn update(&mut self) {
124 let load_value = self.load_value;
125
Imre Kis826b8612025-03-12 13:07:15 +0100126 self.with_unlock(|mut regs| field!(regs, wdog_load).write(load_value));
Imre Kiscd007ad2024-08-14 15:53:11 +0200127 }
128
Imre Kis826b8612025-03-12 13:07:15 +0100129 fn with_unlock<F>(&mut self, f: F)
130 where
131 F: FnOnce(&mut UniqueMmioPointer<SP805Registers>),
132 {
133 field!(self.regs, wdog_lock).write(Self::UNLOCK);
134 f(&mut self.regs);
135 field!(self.regs, wdog_lock).write(Self::LOCK);
Imre Kiscd007ad2024-08-14 15:53:11 +0200136 }
137}