Skip to main content

arm_fvp_base_pac/
lib.rs

1// SPDX-FileCopyrightText: Copyright The arm-fvp-base-pac Contributors.
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4#![no_std]
5#![doc = include_str!("../README.md")]
6#![deny(clippy::undocumented_unsafe_blocks)]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8
9#[cfg(all(feature = "base-revc", feature = "base-r"))]
10compile_error!("must only choose one of these Cargo features: `base-revc`; `base-r`");
11
12pub mod power_controller;
13pub mod system;
14
15// Re-export peripheral drivers and common safe-mmio types
16#[cfg(feature = "base-revc")]
17pub use arm_cci;
18pub use arm_generic_timer;
19pub use arm_gic;
20pub use arm_pl011_uart;
21pub use arm_sp805;
22pub use arm_tzc;
23
24pub use safe_mmio::{PhysicalInstance, UniqueMmioPointer};
25
26#[cfg(feature = "base-revc")]
27use arm_cci::Cci5x0Registers;
28use arm_generic_timer::memory_mapped::{CntBase, CntControlBase, CntCtlBase, CntReadBase};
29use arm_gic::{
30    IntId,
31    gicv3::registers::{Gicd, GicrSgi},
32};
33use arm_pl011_uart::PL011Registers;
34use arm_sp805::SP805Registers;
35use arm_tzc::TzcRegisters;
36use core::{fmt::Debug, ops::RangeInclusive};
37use power_controller::FvpPowerControllerRegisters;
38use spin::mutex::Mutex;
39use system::FvpSystemRegisters;
40
41static PERIPHERALS_TAKEN: Mutex<bool> = Mutex::new(false);
42
43/// Memory map based on 'Table 6-5: Base Platform memory map' of 'Fast Models Version 11.28
44/// Reference Guide'. The ranges for normal memory regions are public, however the peripheral
45/// regions are private and they should be accessed through the `Peripherals` structure.
46pub struct MemoryMap;
47
48#[allow(unused)]
49impl MemoryMap {
50    pub const TRUSTED_BOOT_ROM: RangeInclusive<usize> = flip(0x00_0000_0000..=0x00_03FF_FFFF);
51    pub const TRUSTED_SRAM: RangeInclusive<usize> = flip(0x00_0400_0000..=0x00_0407_FFFF);
52    pub const TRUSTED_DRAM: RangeInclusive<usize> = flip(0x00_0600_0000..=0x00_07FF_FFFF);
53    pub const NOR_FLASH0: RangeInclusive<usize> = flip(0x00_0800_0000..=0x00_0BFF_FFFF);
54    pub const NOR_FLASH1: RangeInclusive<usize> = flip(0x00_0C00_0000..=0x00_0FFF_FFFF);
55    pub const PSRAM: RangeInclusive<usize> = flip(0x00_1400_0000..=0x00_17FF_FFFF);
56    pub const VRAM: RangeInclusive<usize> = flip(0x00_1800_0000..=0x00_19FF_FFFF);
57    pub const ETHERNET: RangeInclusive<usize> = flip(0x00_1A00_0000..=0x00_1AFF_FFFF);
58    pub const USB: RangeInclusive<usize> = flip(0x00_1B00_0000..=0x00_1BFF_FFFF);
59    pub const VE_SYSTEM: RangeInclusive<usize> = flip(0x00_1C01_0000..=0x00_1C01_FFFF);
60    pub const SYSTEM_CONTROLLER: RangeInclusive<usize> = flip(0x00_1C02_0000..=0x00_1C02_FFFF);
61    pub const AACI: RangeInclusive<usize> = flip(0x00_1C04_0000..=0x00_1C04_FFFF);
62    pub const MCI: RangeInclusive<usize> = flip(0x00_1C05_0000..=0x00_1C05_FFFF);
63    pub const KMI_KEYBOARD: RangeInclusive<usize> = flip(0x00_1C06_0000..=0x00_1C06_FFFF);
64    pub const KMI_MOUSE: RangeInclusive<usize> = flip(0x00_1C07_0000..=0x00_1C07_FFFF);
65    pub const UART0: RangeInclusive<usize> = flip(0x00_1C09_0000..=0x00_1C09_FFFF);
66    pub const UART1: RangeInclusive<usize> = flip(0x00_1C0A_0000..=0x00_1C0A_FFFF);
67    pub const UART2: RangeInclusive<usize> = flip(0x00_1C0B_0000..=0x00_1C0B_FFFF);
68    pub const UART3: RangeInclusive<usize> = flip(0x00_1C0C_0000..=0x00_1C0C_FFFF);
69    pub const VFS2: RangeInclusive<usize> = flip(0x00_1C0D_0000..=0x00_1C0D_FFFF);
70    pub const WATCHDOG: RangeInclusive<usize> = flip(0x00_1C0F_0000..=0x00_1C0F_FFFF);
71    pub const POWER_CONTROLLER: RangeInclusive<usize> = flip(0x00_1C10_0000..=0x00_1C10_FFFF);
72    pub const DUAL_TIMER0: RangeInclusive<usize> = flip(0x00_1C11_0000..=0x00_1C11_FFFF);
73    pub const DUAL_TIMER1: RangeInclusive<usize> = flip(0x00_1C12_0000..=0x00_1C12_FFFF);
74    pub const VIRTIO_BLOCK_DEVICE: RangeInclusive<usize> = flip(0x00_1C13_0000..=0x00_1C13_FFFF);
75    pub const VIRTIO_PLAN9_DEVICE: RangeInclusive<usize> = flip(0x00_1C14_0000..=0x00_1C14_FFFF);
76    pub const VIRTIO_NET_DEVICE: RangeInclusive<usize> = flip(0x00_1C15_0000..=0x00_1C15_FFFF);
77    pub const RTC: RangeInclusive<usize> = flip(0x00_1C17_0000..=0x00_1C17_FFFF);
78    pub const CF_CARD: RangeInclusive<usize> = flip(0x00_1C1A_0000..=0x00_1C1A_FFFF);
79    pub const CLCD_CONTROLLER: RangeInclusive<usize> = flip(0x00_1C1F_0000..=0x00_1C1F_FFFF);
80    pub const VIRTIO_RNG: RangeInclusive<usize> = flip(0x00_1C20_0000..=0x00_1C20_FFFF);
81    pub const LS64_TESTING_FIFO: RangeInclusive<usize> = flip(0x00_1D00_0000..=0x00_1D00_FFFF);
82    pub const UTILITY_BUS: RangeInclusive<usize> = flip(0x00_1E00_0000..=0x00_1EFF_FFFF);
83    pub const NON_TRUSTED_ROM: RangeInclusive<usize> = flip(0x00_1F00_0000..=0x00_1F00_0FFF);
84    pub const CORESIGHT: RangeInclusive<usize> = flip(0x00_2000_0000..=0x00_27FF_FFFF);
85    #[cfg(feature = "base-revc")]
86    pub const CCI_550: RangeInclusive<usize> = flip(0x00_2A00_0000..=0x00_2A09_FFFF);
87    pub const REFCLK_CNTCONTROL: RangeInclusive<usize> = flip(0x00_2A43_0000..=0x00_2A43_FFFF);
88    pub const EL2_WATCHDOG_CONTROL: RangeInclusive<usize> = flip(0x00_2A44_0000..=0x00_2A44_FFFF);
89    pub const EL2_WATCHDOG_REFRESH: RangeInclusive<usize> = flip(0x00_2A45_0000..=0x00_2A45_FFFF);
90    pub const TRUSTED_WATCHDOG: RangeInclusive<usize> = flip(0x00_2A49_0000..=0x00_2A49_FFFF);
91    pub const TRUSTZONE_CONTROLLER: RangeInclusive<usize> = flip(0x00_2A4A_0000..=0x00_2A4A_FFFF);
92    pub const REFCLK_CNTREAD: RangeInclusive<usize> = flip(0x00_2A80_0000..=0x00_2A80_FFFF);
93    pub const AP_REFCLK_CNTCTL: RangeInclusive<usize> = flip(0x00_2A81_0000..=0x00_2A81_FFFF);
94    pub const AP_REFCLK_CNTBASE0: RangeInclusive<usize> = flip(0x00_2A82_0000..=0x00_2A82_FFFF);
95    pub const AP_REFCLK_CNTBASE1: RangeInclusive<usize> = flip(0x00_2A83_0000..=0x00_2A83_FFFF);
96    pub const DMC_400_CFG: RangeInclusive<usize> = flip(0x00_2B0A_0000..=0x00_2B0A_FFFF);
97    #[cfg(feature = "base-revc")]
98    pub const SMMUV3_AEM: RangeInclusive<usize> = flip(0x00_2B40_0000..=0x00_2B4F_FFFF);
99    #[cfg(feature = "base-revc")]
100    pub const DMA330X4: RangeInclusive<usize> = flip(0x00_2B50_0000..=0x00_2B5F_FFFF);
101    pub const GICC: RangeInclusive<usize> = flip(0x00_2C00_0000..=0x00_2C00_1FFF);
102    pub const GICH: RangeInclusive<usize> = flip(0x00_2C01_0000..=0x00_2C01_0FFF);
103    pub const GICV: RangeInclusive<usize> = flip(0x00_2C02_F000..=0x00_2C03_0FFF);
104    #[cfg(not(feature = "base-revc"))]
105    pub const CCI_400: RangeInclusive<usize> = flip(0x00_2C09_0000..=0x00_2C09_FFFF);
106    #[cfg(feature = "base-revc")]
107    pub const MALI_G76: RangeInclusive<usize> = flip(0x00_2D00_0000..=0x00_2DFF_0000);
108    pub const NON_TRUSTED_SRAM: RangeInclusive<usize> = flip(0x00_2E00_0000..=0x00_2E00_FFFF);
109    pub const GICD: RangeInclusive<usize> = flip(0x00_2F00_0000..=0x00_2F00_FFFF);
110    pub const GITS: RangeInclusive<usize> = flip(0x00_2F02_0000..=0x00_2F03_FFFF);
111    pub const GICR: RangeInclusive<usize> = flip(0x00_2F10_0000..=0x00_2F1F_FFFF);
112    #[cfg(feature = "base-revc")]
113    pub const PCIE_CONFIG_REGION: RangeInclusive<usize> = flip(0x00_4000_0000..=0x00_4FFF_FFFF);
114    #[cfg(feature = "base-revc")]
115    pub const PCIE_MEMORY_REGION1: RangeInclusive<usize> = flip(0x00_5000_0000..=0x00_5FFF_FFFF);
116    pub const TRUSTED_RNG: RangeInclusive<usize> = flip(0x00_7FE6_0000..=0x00_7FE6_0FFF);
117    pub const TRUSTED_NV_COUNTERS: RangeInclusive<usize> = flip(0x00_7FE7_0000..=0x00_7FE7_0FFF);
118    pub const TRUSTED_ROOT_KEY_STORAGE: RangeInclusive<usize> =
119        flip(0x00_7FE8_0000..=0x00_7FE8_0FFF);
120    pub const DDR3_PHY: RangeInclusive<usize> = flip(0x00_7FEF_0000..=0x00_7FEF_FFFF);
121    pub const HDLCD_CONTROLLER: RangeInclusive<usize> = flip(0x00_7FF6_0000..=0x00_7FF6_FFFF);
122    pub const DRAM0: RangeInclusive<usize> = flip(0x00_8000_0000..=0x00_FFFF_FFFF);
123    pub const DRAM1: RangeInclusive<usize> = flip(0x08_8000_0000..=0x0F_FFFF_FFFF);
124    #[cfg(feature = "base-revc")]
125    pub const PCIE_MEMORY_REGION2: RangeInclusive<usize> = flip(0x40_0000_0000..=0x7F_FFFF_FFFF);
126    pub const DRAM2: RangeInclusive<usize> = flip(0x88_0000_0000..=0xFF_FFFF_FFFF);
127    pub const DRAM3: RangeInclusive<usize> = flip(0x00_0880_0000_0000..=0x00_0FFF_FFFF_FFFF);
128    pub const DRAM4: RangeInclusive<usize> = flip(0x00_8800_0000_0000..=0x00_FFFF_FFFF_FFFF);
129    pub const DRAM5: RangeInclusive<usize> = flip(0x08_8000_0000_0000..=0x0F_FFFF_FFFF_FFFF);
130    pub const DRAM6: RangeInclusive<usize> = flip(0x88_0000_0000_0000..=0x8F_FFFF_FFFF_FFFF);
131}
132
133/// FVP peripherals
134#[derive(Debug)]
135pub struct Peripherals {
136    pub system: PhysicalInstance<FvpSystemRegisters>,
137    pub uart0: PhysicalInstance<PL011Registers>,
138    pub uart1: PhysicalInstance<PL011Registers>,
139    pub uart2: PhysicalInstance<PL011Registers>,
140    pub uart3: PhysicalInstance<PL011Registers>,
141    pub watchdog: PhysicalInstance<SP805Registers>,
142    pub power_controller: PhysicalInstance<FvpPowerControllerRegisters>,
143    /// CCI-550 is only available on the FVP Base RevC platform when the cluster count is 1 or 2.
144    #[cfg(feature = "base-revc")]
145    pub cci_550: PhysicalInstance<Cci5x0Registers>,
146    pub refclk_cntcontrol: PhysicalInstance<CntControlBase>,
147    pub trusted_watchdog: PhysicalInstance<SP805Registers>,
148    pub trustzone_controller: PhysicalInstance<TzcRegisters>,
149    pub refclk_cntread: PhysicalInstance<CntReadBase>,
150    pub ap_refclk_cntctl: PhysicalInstance<CntCtlBase>,
151    pub ap_refclk_cntbase0: PhysicalInstance<CntBase>,
152    pub ap_refclk_cntbase1: PhysicalInstance<CntBase>,
153    pub gicd: PhysicalInstance<Gicd>,
154    pub gicr: PhysicalInstance<GicrSgi>,
155}
156
157impl Peripherals {
158    /// Take the peripherals once
159    pub fn take() -> Option<Self> {
160        if !*PERIPHERALS_TAKEN.lock() {
161            // SAFETY: PERIPHERALS_TAKEN ensures that this is only called once.
162            Some(unsafe { Self::steal() })
163        } else {
164            None
165        }
166    }
167
168    /// Unsafe version of take()
169    ///
170    /// # Safety
171    ///
172    /// This must not be called while any other instance of this type or the peripherals it contains
173    /// exists.
174    pub unsafe fn steal() -> Self {
175        *PERIPHERALS_TAKEN.lock() = true;
176
177        // SAFETY: The caller guarantees that no other instance exists.
178        unsafe {
179            Peripherals {
180                system: PhysicalInstance::new(*MemoryMap::VE_SYSTEM.start()),
181                uart0: PhysicalInstance::new(*MemoryMap::UART0.start()),
182                uart1: PhysicalInstance::new(*MemoryMap::UART1.start()),
183                uart2: PhysicalInstance::new(*MemoryMap::UART2.start()),
184                uart3: PhysicalInstance::new(*MemoryMap::UART3.start()),
185                watchdog: PhysicalInstance::new(*MemoryMap::WATCHDOG.start()),
186                power_controller: PhysicalInstance::new(*MemoryMap::POWER_CONTROLLER.start()),
187                #[cfg(feature = "base-revc")]
188                cci_550: PhysicalInstance::new(*MemoryMap::CCI_550.start()),
189                refclk_cntcontrol: PhysicalInstance::new(*MemoryMap::REFCLK_CNTCONTROL.start()),
190                trusted_watchdog: PhysicalInstance::new(*MemoryMap::TRUSTED_WATCHDOG.start()),
191                trustzone_controller: PhysicalInstance::new(
192                    *MemoryMap::TRUSTZONE_CONTROLLER.start(),
193                ),
194                refclk_cntread: PhysicalInstance::new(*MemoryMap::REFCLK_CNTREAD.start()),
195                ap_refclk_cntctl: PhysicalInstance::new(*MemoryMap::AP_REFCLK_CNTCTL.start()),
196                ap_refclk_cntbase0: PhysicalInstance::new(*MemoryMap::AP_REFCLK_CNTBASE0.start()),
197                ap_refclk_cntbase1: PhysicalInstance::new(*MemoryMap::AP_REFCLK_CNTBASE1.start()),
198                gicd: PhysicalInstance::new(*MemoryMap::GICD.start()),
199                gicr: PhysicalInstance::new(*MemoryMap::GICR.start()),
200            }
201        }
202    }
203}
204
205/// CCI-550 index assignment of internal components.
206#[cfg(feature = "base-revc")]
207pub struct Cci550Map;
208
209#[cfg(feature = "base-revc")]
210impl Cci550Map {
211    /// Index of cluster 0.
212    pub const CLUSTER0: usize = 5;
213    /// Index of cluster 1.
214    pub const CLUSTER1: usize = 6;
215}
216
217/// Filter unit assignment in the TrustZone Controller.
218pub struct TzcFilter;
219
220impl TzcFilter {
221    /// Default filter index.
222    pub const DEFAULT: usize = 0;
223    /// Filter of PL111_CLCD and HDLCD0.
224    pub const LCD: usize = 2;
225}
226
227/// Non-Secure Access Identity (NSAID) assignment in the TrustZone Controller.
228pub struct TzcNsaid;
229
230impl TzcNsaid {
231    /// Default NSAID.
232    pub const DEFAULT: usize = 0;
233    // Cluster0 and Cluster 1 application processors and VirtioNetMMIO.
234    pub const APPLICATION_PROCESSORS: usize = 9;
235    /// VirtioP9Device, VirtioBlockDevice.
236    pub const VIRTIO: usize = 8;
237    /// PCI bus.
238    pub const PCI: usize = 1;
239    /// PL111_CLCD.
240    pub const CLCD: usize = 7;
241    /// HDLCD0.
242    pub const HDLCD0: usize = 2;
243}
244
245/// Private Peripheral Interrupt assignments for the Base Platform.
246pub struct PrivatePeripheralInterrupts;
247
248impl PrivatePeripheralInterrupts {
249    pub const SECURE_HYPERVISOR_VIRTUAL_TIMER: IntId = IntId::ppi(3);
250    pub const SECURE_HYPERVISOR_PHYSICAL_TIMER: IntId = IntId::ppi(4);
251    pub const SPU: IntId = IntId::ppi(5);
252    pub const DCC_COMMS_CHANNEL: IntId = IntId::ppi(6);
253    pub const PMU_OVERFLOW: IntId = IntId::ppi(7);
254    pub const CTI: IntId = IntId::ppi(8);
255    pub const VIRTUAL_CPU_INTERFACE_MAINTENANCE: IntId = IntId::ppi(9);
256    pub const HYPERVISOR_TIMER: IntId = IntId::ppi(10);
257    pub const VIRTUAL_TIMER: IntId = IntId::ppi(11);
258    pub const HYPERVISOR_VIRTUAL_TIMER: IntId = IntId::ppi(12);
259    pub const SECURE_PHYSICAL_TIMER: IntId = IntId::ppi(13);
260    pub const NONSECURE_PHYSICAL_TIMER: IntId = IntId::ppi(14);
261    pub const TRBU: IntId = IntId::ppi(15);
262}
263
264/// Shared Peripheral Interrupt assignments for the Base Platform.
265pub struct SharedPeripheralInterrupts;
266
267impl SharedPeripheralInterrupts {
268    pub const WATCHDOG: IntId = IntId::spi(0);
269    pub const DUAL_TIMER0: IntId = IntId::spi(2);
270    pub const DUAL_TIMER1: IntId = IntId::spi(3);
271    pub const RTC: IntId = IntId::spi(4);
272    pub const UART0: IntId = IntId::spi(5);
273    pub const UART1: IntId = IntId::spi(6);
274    pub const UART2: IntId = IntId::spi(7);
275    pub const UART3: IntId = IntId::spi(8);
276    pub const MCIINTR0: IntId = IntId::spi(9);
277    pub const MCIINTR1: IntId = IntId::spi(10);
278    pub const AACI: IntId = IntId::spi(11);
279    pub const KMI_KEYBOARD: IntId = IntId::spi(12);
280    pub const KMI_MOUSE: IntId = IntId::spi(13);
281    pub const CLCD: IntId = IntId::spi(14);
282    pub const CLCD_CONTROLLER: IntId = Self::CLCD;
283    pub const ETHERNET: IntId = IntId::spi(15);
284    pub const TRUSTED_WATCHDOG: IntId = IntId::spi(24);
285    pub const CNTPSIRQ: IntId = IntId::spi(25);
286    pub const CNTPSIRQ1: IntId = IntId::spi(26);
287    pub const EL2_WATCHDOG_WS0: IntId = IntId::spi(27);
288    pub const EL2_WATCHDOG_WS1: IntId = IntId::spi(28);
289    pub const VIRTIO_BLOCK_DEVICE: IntId = IntId::spi(42);
290    pub const VIRTIO_PLAN9_DEVICE: IntId = IntId::spi(43);
291    pub const VIRTIO_NET_DEVICE: IntId = IntId::spi(44);
292    pub const VIRTIO_RNG: IntId = IntId::spi(46);
293    pub const TRUSTZONE_CONTROLLER: IntId = IntId::spi(48);
294    pub const PMUIRQ_CL0_CPU0: IntId = IntId::spi(60);
295    pub const PMUIRQ_CL0_CPU1: IntId = IntId::spi(61);
296    pub const PMUIRQ_CL0_CPU2: IntId = IntId::spi(62);
297    pub const PMUIRQ_CL0_CPU3: IntId = IntId::spi(63);
298    pub const PMUIRQ_CL1_CPU0: IntId = IntId::spi(64);
299    pub const PMUIRQ_CL1_CPU1: IntId = IntId::spi(65);
300    pub const PMUIRQ_CL1_CPU2: IntId = IntId::spi(66);
301    pub const PMUIRQ_CL1_CPU3: IntId = IntId::spi(67);
302    pub const HDLCD_CONTROLLER: IntId = IntId::spi(85);
303    pub const TRUSTED_RNG: IntId = IntId::spi(107);
304}
305
306#[cfg(feature = "base-revc")]
307impl SharedPeripheralInterrupts {
308    pub const SMMUV3_NONSECURE_COMBINED: IntId = IntId::spi(71);
309    pub const SMMUV3_SECURE_COMBINED: IntId = IntId::spi(72);
310    pub const SMMUV3_SECURE_EVENT_QUEUE: IntId = IntId::spi(73);
311    pub const SMMUV3_NONSECURE_EVENT_QUEUE: IntId = IntId::spi(74);
312    pub const SMMUV3_PRI_QUEUE: IntId = IntId::spi(75);
313    pub const SMMUV3_SECURE_COMMAND_QUEUE_SYNC: IntId = IntId::spi(76);
314    pub const SMMUV3_NONSECURE_COMMAND_QUEUE_SYNC: IntId = IntId::spi(77);
315    pub const SMMUV3_SECURE_GERROR: IntId = IntId::spi(78);
316    pub const SMMUV3_NONSECURE_GERROR: IntId = IntId::spi(79);
317    pub const MALI_G76_GPU: IntId = IntId::spi(160);
318    pub const MALI_G76_GPU_JOB: IntId = IntId::spi(161);
319    pub const MALI_G76_GPU_MMU: IntId = IntId::spi(162);
320    pub const PCIE_INTA: IntId = IntId::spi(168);
321    pub const PCIE_INTB: IntId = IntId::spi(169);
322    pub const PCIE_INTC: IntId = IntId::spi(170);
323    pub const PCIE_INTD: IntId = IntId::spi(171);
324    pub const PCIE_SERR: IntId = IntId::spi(175);
325}
326
327/// For `base-r` platforms, flips the lower 2 GiB and upper 2 GiB regions.
328///
329/// This is a no-op if the `base-r` feature is not set.
330const fn flip(range: RangeInclusive<usize>) -> RangeInclusive<usize> {
331    const LIMIT_4GB: usize = 0x1_0000_0000;
332    #[cfg(feature = "base-r")]
333    const FLIP_BIT: usize = 0x8000_0000;
334    #[cfg(not(feature = "base-r"))]
335    const FLIP_BIT: usize = 0x0000_0000;
336
337    let mut start = *range.start();
338    let mut end = *range.end();
339    if start < LIMIT_4GB && end < LIMIT_4GB {
340        start ^= FLIP_BIT;
341        end ^= FLIP_BIT;
342    };
343    start..=end
344}