blob: 5c67eaa604319060b7e1feba50a969b7f0442750 [file] [log] [blame]
Imre Kis9c084c02024-08-14 15:53:45 +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//! # Peripheral Access Crate fro Arm Fixed Virtual Platform
5//!
6//! The crate provides access to the peripherals of [Arm Fixed Virtual Platform](https://developer.arm.com/Tools%20and%20Software/Fixed%20Virtual%20Platforms).
7
8#![no_std]
9
Imre Kis7c36bde2024-09-26 11:20:06 +020010use core::{
Andrew Walbran1a289d12025-02-11 14:55:39 +000011 fmt::{self, Debug, Formatter},
Imre Kis7c36bde2024-09-26 11:20:06 +020012 marker::PhantomData,
Imre Kis7c36bde2024-09-26 11:20:06 +020013};
Imre Kis9c084c02024-08-14 15:53:45 +020014
Imre Kis9c084c02024-08-14 15:53:45 +020015use arm_gic::GICDRegisters;
Balint Dobszay4292ed42025-01-09 13:52:32 +010016use arm_pl011_uart::PL011Registers;
Imre Kis9c084c02024-08-14 15:53:45 +020017use arm_sp805::SP805Registers;
Andrew Walbran1a289d12025-02-11 14:55:39 +000018use spin::mutex::Mutex;
Imre Kis9c084c02024-08-14 15:53:45 +020019
20static PERIPHERALS_TAKEN: Mutex<bool> = Mutex::new(false);
21
Andrew Walbran1a289d12025-02-11 14:55:39 +000022/// The physical instance of some device's MMIO space.
23pub struct PhysicalInstance<T> {
24 pa: usize,
25 _phantom: PhantomData<T>,
26}
27
28impl<T> Debug for PhysicalInstance<T> {
29 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
30 f.debug_struct("PhysicalInstance")
31 .field("pa", &self.pa)
32 .field("size", &size_of::<T>())
33 .finish()
34 }
35}
36
37impl<T> PhysicalInstance<T> {
38 /// # Safety
39 ///
40 /// This must refer to the physical address of a real set of device registers of type `T`, and
41 /// there must only ever be a single `PhysicalInstance` for those device registers.
42 pub unsafe fn new(pa: usize) -> Self {
43 Self {
44 pa,
45 _phantom: PhantomData,
46 }
47 }
48
49 /// Returns the physical base address of the device's registers.
50 pub fn pa(&self) -> usize {
51 self.pa
52 }
53}
54
Imre Kis9c084c02024-08-14 15:53:45 +020055/// FVP peripherals
Andrew Walbran1a289d12025-02-11 14:55:39 +000056#[derive(Debug)]
Imre Kis9c084c02024-08-14 15:53:45 +020057pub struct Peripherals {
Andrew Walbran1a289d12025-02-11 14:55:39 +000058 pub uart0: PhysicalInstance<PL011Registers>,
59 pub uart1: PhysicalInstance<PL011Registers>,
60 pub uart2: PhysicalInstance<PL011Registers>,
61 pub uart3: PhysicalInstance<PL011Registers>,
62 pub watchdog: PhysicalInstance<SP805Registers>,
63 pub gicd: PhysicalInstance<GICDRegisters>,
Imre Kis9c084c02024-08-14 15:53:45 +020064}
65
66impl Peripherals {
67 /// Take the peripherals once
68 pub fn take() -> Option<Self> {
69 if !*PERIPHERALS_TAKEN.lock() {
Imre Kis75a43542024-10-02 14:11:25 +020070 // SAFETY: PERIPHERALS_TAKEN ensures that this is only called once.
Imre Kis9c084c02024-08-14 15:53:45 +020071 Some(unsafe { Self::steal() })
72 } else {
73 None
74 }
75 }
76
77 /// Unsafe version of take()
78 ///
79 /// # Safety
Andrew Walbran1a289d12025-02-11 14:55:39 +000080 ///
81 /// The caller must ensure that each peripheral is only used once.
Imre Kis9c084c02024-08-14 15:53:45 +020082 pub unsafe fn steal() -> Self {
83 *PERIPHERALS_TAKEN.lock() = true;
84
85 Peripherals {
Andrew Walbran1a289d12025-02-11 14:55:39 +000086 uart0: PhysicalInstance::new(0x1c09_0000),
87 uart1: PhysicalInstance::new(0x1c0a_0000),
88 uart2: PhysicalInstance::new(0x1c0b_0000),
89 uart3: PhysicalInstance::new(0x1c0c_0000),
90 watchdog: PhysicalInstance::new(0x1c0f_0000),
91 gicd: PhysicalInstance::new(0x2f00_0000),
Imre Kis9c084c02024-08-14 15:53:45 +020092 }
93 }
94}