Add Peripheral Access Crate for Arm Fixed Virtual Platform

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I1aa0e799299931c4cf28980e1a4fb6943fb94228
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..e58a839
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,191 @@
+// SPDX-FileCopyrightText: Copyright 2023-2024 Arm Limited and/or its affiliates <open-source-office@arm.com>
+// SPDX-License-Identifier: MIT OR Apache-2.0
+
+//! # Peripheral Access Crate fro Arm Fixed Virtual Platform
+//!
+//! The crate provides access to the peripherals of [Arm Fixed Virtual Platform](https://developer.arm.com/Tools%20and%20Software/Fixed%20Virtual%20Platforms).
+
+#![no_std]
+
+use core::{marker::PhantomData, ops::Deref};
+
+use spin::mutex::Mutex;
+
+use arm_gic::GICDRegisters;
+use arm_pl011::PL011Registers;
+use arm_sp805::SP805Registers;
+
+/// UART0 - PL011
+pub struct UART0 {
+    _marker: PhantomData<*const ()>,
+}
+
+impl UART0 {
+    pub const PTR: *const PL011Registers = 0x1c09_0000 as *const _;
+}
+
+impl Deref for UART0 {
+    type Target = PL011Registers;
+
+    #[inline(always)]
+    fn deref(&self) -> &Self::Target {
+        unsafe { &*Self::PTR }
+    }
+}
+
+unsafe impl Send for UART0 {}
+
+/// UART1 - PL011
+pub struct UART1 {
+    _marker: PhantomData<*const ()>,
+}
+
+impl UART1 {
+    pub const PTR: *const PL011Registers = 0x1c0a_0000 as *const _;
+}
+
+impl Deref for UART1 {
+    type Target = PL011Registers;
+
+    #[inline(always)]
+    fn deref(&self) -> &Self::Target {
+        unsafe { &*Self::PTR }
+    }
+}
+
+unsafe impl Send for UART1 {}
+
+/// UART2 - PL011
+pub struct UART2 {
+    _marker: PhantomData<*const ()>,
+}
+
+impl UART2 {
+    pub const PTR: *const PL011Registers = 0x1c0b_0000 as *const _;
+}
+
+impl Deref for UART2 {
+    type Target = PL011Registers;
+
+    #[inline(always)]
+    fn deref(&self) -> &Self::Target {
+        unsafe { &*Self::PTR }
+    }
+}
+
+unsafe impl Send for UART2 {}
+
+/// UART3 - PL011
+pub struct UART3 {
+    _marker: PhantomData<*const ()>,
+}
+
+impl UART3 {
+    pub const PTR: *const PL011Registers = 0x1c0c_0000 as *const _;
+}
+
+impl Deref for UART3 {
+    type Target = PL011Registers;
+
+    #[inline(always)]
+    fn deref(&self) -> &Self::Target {
+        unsafe { &*Self::PTR }
+    }
+}
+
+unsafe impl Send for UART3 {}
+
+/// Watchdog - SP805
+#[allow(clippy::upper_case_acronyms)]
+pub struct WATCHDOG {
+    _marker: PhantomData<*const ()>,
+}
+
+impl WATCHDOG {
+    pub const PTR: *const SP805Registers = 0x1c0f_0000 as *const _;
+}
+
+impl Deref for WATCHDOG {
+    type Target = SP805Registers;
+
+    #[inline(always)]
+    fn deref(&self) -> &Self::Target {
+        unsafe { &*Self::PTR }
+    }
+}
+
+unsafe impl Send for WATCHDOG {}
+
+/// GIC Distributor
+#[allow(clippy::upper_case_acronyms)]
+pub struct GICD {
+    _marker: PhantomData<*const ()>,
+}
+
+impl GICD {
+    pub const PTR: *const GICDRegisters = 0x2f00_0000 as *const _;
+}
+
+impl Deref for GICD {
+    type Target = GICDRegisters;
+
+    #[inline(always)]
+    fn deref(&self) -> &Self::Target {
+        unsafe { &*Self::PTR }
+    }
+}
+
+unsafe impl Send for GICD {}
+
+static PERIPHERALS_TAKEN: Mutex<bool> = Mutex::new(false);
+
+/// FVP peripherals
+#[allow(non_snake_case)]
+pub struct Peripherals {
+    pub UART0: UART0,
+    pub UART1: UART1,
+    pub UART2: UART2,
+    pub UART3: UART3,
+    pub WATCHDOG: WATCHDOG,
+    pub GICD: GICD,
+}
+
+impl Peripherals {
+    /// Take the peripherals once
+    pub fn take() -> Option<Self> {
+        if !*PERIPHERALS_TAKEN.lock() {
+            Some(unsafe { Self::steal() })
+        } else {
+            None
+        }
+    }
+
+    /// Unsafe version of take()
+    ///
+    /// # Safety
+    /// The caller has to ensure that each peripheral is only used once.
+    pub unsafe fn steal() -> Self {
+        *PERIPHERALS_TAKEN.lock() = true;
+
+        Peripherals {
+            UART0: UART0 {
+                _marker: PhantomData,
+            },
+            UART1: UART1 {
+                _marker: PhantomData,
+            },
+            UART2: UART2 {
+                _marker: PhantomData,
+            },
+            UART3: UART3 {
+                _marker: PhantomData,
+            },
+            WATCHDOG: WATCHDOG {
+                _marker: PhantomData,
+            },
+            GICD: GICD {
+                _marker: PhantomData,
+            },
+        }
+    }
+}