Imre Kis | ae5c740 | 2025-01-10 17:57:58 +0100 | [diff] [blame] | 1 | // SPDX-FileCopyrightText: Copyright 2023-2025 Arm Limited and/or its affiliates <open-source-office@arm.com> |
Imre Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 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 Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 10 | use bitflags::bitflags; |
Imre Kis | 826b861 | 2025-03-12 13:07:15 +0100 | [diff] [blame^] | 11 | use safe_mmio::{ |
| 12 | field, |
| 13 | fields::{ReadPure, ReadPureWrite, WriteOnly}, |
| 14 | UniqueMmioPointer, |
| 15 | }; |
| 16 | use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout}; |
| 17 | |
| 18 | #[repr(transparent)] |
| 19 | #[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)] |
| 20 | struct ControlRegister(u32); |
| 21 | |
| 22 | #[repr(transparent)] |
| 23 | #[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)] |
| 24 | struct Interrupts(u32); |
Imre Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 25 | |
| 26 | bitflags! { |
| 27 | /// Control register |
Imre Kis | 826b861 | 2025-03-12 13:07:15 +0100 | [diff] [blame^] | 28 | impl ControlRegister : u32 { |
Imre Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 29 | /// 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 Kis | 826b861 | 2025-03-12 13:07:15 +0100 | [diff] [blame^] | 36 | impl Interrupts : u32 { |
Imre Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 37 | /// Raw interrupt status from the counter |
| 38 | const WDOGRIS = 1 << 0; |
| 39 | } |
Imre Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 40 | } |
| 41 | |
| 42 | /// SP805 register map |
Imre Kis | 826b861 | 2025-03-12 13:07:15 +0100 | [diff] [blame^] | 43 | #[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)] |
Imre Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 44 | #[repr(C, align(4))] |
| 45 | pub struct SP805Registers { |
Imre Kis | 826b861 | 2025-03-12 13:07:15 +0100 | [diff] [blame^] | 46 | /// 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 Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 86 | } |
| 87 | |
| 88 | /// SP805 Watchdog implementation |
Imre Kis | 826b861 | 2025-03-12 13:07:15 +0100 | [diff] [blame^] | 89 | pub struct Watchdog<'a> { |
| 90 | regs: UniqueMmioPointer<'a, SP805Registers>, |
Imre Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 91 | load_value: u32, |
| 92 | } |
| 93 | |
Imre Kis | 826b861 | 2025-03-12 13:07:15 +0100 | [diff] [blame^] | 94 | impl<'a> Watchdog<'a> { |
| 95 | const LOCK: u32 = 0x00000001; |
| 96 | const UNLOCK: u32 = 0x1ACCE551; |
| 97 | |
Imre Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 98 | /// Create new watchdog instance |
Imre Kis | 826b861 | 2025-03-12 13:07:15 +0100 | [diff] [blame^] | 99 | pub fn new(regs: UniqueMmioPointer<'a, SP805Registers>, load_value: u32) -> Self { |
Imre Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 100 | Self { regs, load_value } |
| 101 | } |
| 102 | |
| 103 | /// Enable watchdog |
Imre Kis | e05daa4 | 2024-09-26 11:20:06 +0200 | [diff] [blame] | 104 | pub fn enable(&mut self) { |
| 105 | let load_value = self.load_value; |
Imre Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 106 | |
Imre Kis | 826b861 | 2025-03-12 13:07:15 +0100 | [diff] [blame^] | 107 | 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 Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | /// Disable watchdog |
Imre Kis | e05daa4 | 2024-09-26 11:20:06 +0200 | [diff] [blame] | 116 | pub fn disable(&mut self) { |
Imre Kis | 826b861 | 2025-03-12 13:07:15 +0100 | [diff] [blame^] | 117 | self.with_unlock(|mut regs| { |
| 118 | field!(regs, wdog_control).write(ControlRegister::empty()) |
| 119 | }); |
Imre Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 120 | } |
| 121 | |
| 122 | /// Update watchdog |
Imre Kis | e05daa4 | 2024-09-26 11:20:06 +0200 | [diff] [blame] | 123 | pub fn update(&mut self) { |
| 124 | let load_value = self.load_value; |
| 125 | |
Imre Kis | 826b861 | 2025-03-12 13:07:15 +0100 | [diff] [blame^] | 126 | self.with_unlock(|mut regs| field!(regs, wdog_load).write(load_value)); |
Imre Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 127 | } |
| 128 | |
Imre Kis | 826b861 | 2025-03-12 13:07:15 +0100 | [diff] [blame^] | 129 | 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 Kis | cd007ad | 2024-08-14 15:53:11 +0200 | [diff] [blame] | 136 | } |
| 137 | } |