Use safe-mmio

Refactor driver to use safe-mmio for accessing register and handling
the ownership and lifetime of the peripheral.

Change-Id: I6890a3dde5fa3960a9ab24b46023a21391335fda
Signed-off-by: Imre Kis <imre.kis@arm.com>
diff --git a/Cargo.lock b/Cargo.lock
index 1625550..85d351b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -7,10 +7,76 @@
 version = "0.1.0"
 dependencies = [
  "bitflags",
+ "safe-mmio",
+ "zerocopy",
 ]
 
 [[package]]
 name = "bitflags"
-version = "2.6.0"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.94"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "safe-mmio"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3bc59a975d8faa0b4475145266e9f9eac01f0b3f393d0e5eecc8b88646ca2d29"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "zerocopy"
+version = "0.8.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 297377e..ec18ddd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,4 +18,6 @@
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-bitflags = "2.6"
+bitflags = "2.9"
+safe-mmio = "0.2"
+zerocopy = "0.8"
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index da2994d..5156f77 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -7,15 +7,25 @@
 
 #![no_std]
 
-use core::ops::{Deref, DerefMut};
-
 use bitflags::bitflags;
+use safe_mmio::{
+    field,
+    fields::{ReadPure, ReadPureWrite, WriteOnly},
+    UniqueMmioPointer,
+};
+use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
+
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+struct ControlRegister(u32);
+
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+struct Interrupts(u32);
 
 bitflags! {
     /// Control register
-    #[repr(transparent)]
-    #[derive(Copy, Clone)]
-    struct ControlRegister : u32 {
+    impl ControlRegister : u32 {
         /// Enable Watchdog module reset output
         const RESEN = 1 << 1;
         /// Break error
@@ -23,151 +33,105 @@
     }
 
     /// Raw Interrupt Status Register
-    #[repr(transparent)]
-    #[derive(Copy, Clone)]
-    struct RawInterruptStatusRegister : u32 {
+    impl Interrupts : u32 {
         /// Raw interrupt status from the counter
         const WDOGRIS = 1 << 0;
     }
-
-    /// Masked Interrupt Status Register
-      struct MaskedInterruptStatusRegister : u32 {
-        /// Enabled interrupt status from the counter
-        const WDOGMIS = 1 << 0;
-    }
 }
 
 /// SP805 register map
+#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
 #[repr(C, align(4))]
 pub struct SP805Registers {
-    wdog_load: u32,           // 0x000 Load Register
-    wdog_value: u32,          // 0x004 Value Register
-    wdog_control: u32,        // 0x008 Control register
-    wdog_intclr: u32,         // 0x00c Interrupt Clear Register
-    wdog_ris: u32,            // 0x010 Raw Interrupt Status Register
-    wdog_mis: u32,            // 0x014 Masked Interrupt Status Register
-    reserved_18: [u32; 762],  // 0x018 - 0xbfc
-    wdog_lock: u32,           // 0xc00 Lock Register
-    reserved_c04: [u32; 191], // 0xc04 - 0xefc
-    wdog_itcr: u32,           // 0xf00 Integration Test Control Register,
-    wdog_itop: u32,           // 0xf04 Integration Test Output Set
-    reserved_f08: [u32; 54],  // 0xf08 - 0xfdc
-    wdog_periph_id0: u32,     // 0xfe0 Peripheral Identification Register 0
-    wdog_periph_id1: u32,     // 0xfe4 Peripheral Identification Register 1
-    wdog_periph_id2: u32,     // 0xfe8 Peripheral Identification Register 2
-    wdog_periph_id3: u32,     // 0xfec Peripheral Identification Register 3
-    wdog_pcell_id0: u32,      // 0xff0 PrimeCell Identification Register 0
-    wdog_pcell_id1: u32,      // 0xff4 PrimeCell Identification Register 1
-    wdog_pcell_id2: u32,      // 0xff8 PrimeCell Identification Register 2
-    wdog_pcell_id3: u32,      // 0xffc PrimeCell Identification Register 3
-}
-
-struct WatchdogUnlockGuard<'a, R>
-where
-    R: DerefMut<Target = SP805Registers>,
-{
-    regs: &'a mut R,
-}
-
-impl<'a, R> WatchdogUnlockGuard<'a, R>
-where
-    R: DerefMut<Target = SP805Registers>,
-{
-    const LOCK: u32 = 0x00000001;
-    const UNLOCK: u32 = 0x1ACCE551;
-
-    pub fn new(regs: &'a mut R) -> Self {
-        // SAFETY: regs can be dereferenced as a valid SP805 register block
-        unsafe {
-            (&raw mut regs.wdog_lock).write_volatile(Self::UNLOCK);
-        }
-        Self { regs }
-    }
-}
-
-impl<R> Deref for WatchdogUnlockGuard<'_, R>
-where
-    R: DerefMut<Target = SP805Registers>,
-{
-    type Target = R;
-
-    fn deref(&self) -> &Self::Target {
-        self.regs
-    }
-}
-
-impl<R> DerefMut for WatchdogUnlockGuard<'_, R>
-where
-    R: DerefMut<Target = SP805Registers>,
-{
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        self.regs
-    }
-}
-
-impl<R> Drop for WatchdogUnlockGuard<'_, R>
-where
-    R: DerefMut<Target = SP805Registers>,
-{
-    fn drop(&mut self) {
-        // SAFETY: self.regs can be dereferenced as a valid SP805 register block
-        unsafe {
-            (&raw mut self.regs.wdog_lock).write_volatile(Self::LOCK);
-        }
-    }
+    /// 0x000 Load Register
+    wdog_load: ReadPureWrite<u32>,
+    /// 0x004 Value Register
+    wdog_value: ReadPure<u32>,
+    /// 0x008 Control register
+    wdog_control: ReadPureWrite<ControlRegister>,
+    /// 0x00c Interrupt Clear Register
+    wdog_intclr: WriteOnly<u32>,
+    /// 0x010 Raw Interrupt Status Register
+    wdog_ris: ReadPure<Interrupts>,
+    /// 0x014 Masked Interrupt Status Register
+    wdog_mis: ReadPure<Interrupts>,
+    /// 0x018 - 0xbfc
+    reserved_18: [u32; 762],
+    /// 0xc00 Lock Register
+    wdog_lock: ReadPureWrite<u32>,
+    /// 0xc04 - 0xefc
+    reserved_c04: [u32; 191],
+    /// 0xf00 Integration Test Control Register,
+    wdog_itcr: ReadPureWrite<u32>,
+    /// 0xf04 Integration Test Output Set
+    wdog_itop: WriteOnly<u32>,
+    /// 0xf08 - 0xfdc
+    reserved_f08: [u32; 54],
+    /// 0xfe0 Peripheral Identification Register 0
+    wdog_periph_id0: ReadPure<u32>,
+    /// 0xfe4 Peripheral Identification Register 1
+    wdog_periph_id1: ReadPure<u32>,
+    /// 0xfe8 Peripheral Identification Register 2
+    wdog_periph_id2: ReadPure<u32>,
+    /// 0xfec Peripheral Identification Register 3
+    wdog_periph_id3: ReadPure<u32>,
+    /// 0xff0 PrimeCell Identification Register 0
+    wdog_pcell_id0: ReadPure<u32>,
+    /// 0xff4 PrimeCell Identification Register 1
+    wdog_pcell_id1: ReadPure<u32>,
+    /// 0xff8 PrimeCell Identification Register 2
+    wdog_pcell_id2: ReadPure<u32>,
+    /// 0xffc PrimeCell Identification Register 3
+    wdog_pcell_id3: ReadPure<u32>,
 }
 
 /// SP805 Watchdog implementation
-pub struct Watchdog<R>
-where
-    R: Deref<Target = SP805Registers>,
-{
-    regs: R,
+pub struct Watchdog<'a> {
+    regs: UniqueMmioPointer<'a, SP805Registers>,
     load_value: u32,
 }
 
-impl<R> Watchdog<R>
-where
-    R: DerefMut<Target = SP805Registers>,
-{
+impl<'a> Watchdog<'a> {
+    const LOCK: u32 = 0x00000001;
+    const UNLOCK: u32 = 0x1ACCE551;
+
     /// Create new watchdog instance
-    pub fn new(regs: R, load_value: u32) -> Self {
+    pub fn new(regs: UniqueMmioPointer<'a, SP805Registers>, load_value: u32) -> Self {
         Self { regs, load_value }
     }
 
     /// Enable watchdog
     pub fn enable(&mut self) {
         let load_value = self.load_value;
-        let mut regs = self.unlock();
 
-        // SAFETY: self.regs can be dereferenced as a valid SP805 register block
-        unsafe {
-            (&raw mut regs.wdog_load).write_volatile(load_value);
-            (&raw mut regs.wdog_intclr).write_volatile(1);
-            (&raw mut regs.wdog_control)
-                .write_volatile((ControlRegister::INTEN | ControlRegister::RESEN).bits());
-        }
+        self.with_unlock(|mut regs| {
+            field!(regs, wdog_load).write(load_value);
+            field!(regs, wdog_intclr).write(1);
+            field!(regs, wdog_control)
+                .write(ControlRegister::INTEN | ControlRegister::RESEN);
+        });
     }
 
     /// Disable watchdog
     pub fn disable(&mut self) {
-        // SAFETY: self.regs can be dereferenced as a valid SP805 register block
-        unsafe {
-            (&raw mut self.unlock().wdog_control).write_volatile(ControlRegister::empty().bits());
-        }
+        self.with_unlock(|mut regs| {
+            field!(regs, wdog_control).write(ControlRegister::empty())
+        });
     }
 
     /// Update watchdog
     pub fn update(&mut self) {
         let load_value = self.load_value;
 
-        // SAFETY: self.regs can be dereferenced as a valid SP805 register block
-        unsafe {
-            (&raw mut self.unlock().wdog_load).write_volatile(load_value);
-        }
+        self.with_unlock(|mut regs| field!(regs, wdog_load).write(load_value));
     }
 
-    fn unlock(&mut self) -> WatchdogUnlockGuard<R> {
-        WatchdogUnlockGuard::new(&mut self.regs)
+    fn with_unlock<F>(&mut self, f: F)
+    where
+        F: FnOnce(&mut UniqueMmioPointer<SP805Registers>),
+    {
+        field!(self.regs, wdog_lock).write(Self::UNLOCK);
+        f(&mut self.regs);
+        field!(self.regs, wdog_lock).write(Self::LOCK);
     }
 }