arm_cci/
lib.rs

1// SPDX-FileCopyrightText: Copyright The arm-cci 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#![deny(unsafe_op_in_unsafe_fn)]
8
9use bitflags::bitflags;
10pub use safe_mmio::UniqueMmioPointer;
11use safe_mmio::{
12    field, field_shared,
13    fields::{ReadPure, ReadPureWrite},
14};
15use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
16
17/// Control Override Register
18#[repr(transparent)]
19#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
20pub struct ControlOverrideRegister(u32);
21
22/// Secure Access Register
23#[repr(transparent)]
24#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
25pub struct SecureAccessRegister(u32);
26
27/// Status Register
28#[repr(transparent)]
29#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
30pub struct StatusRegister(u32);
31
32/// Snoop Control Register
33#[repr(transparent)]
34#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
35pub struct SnoopControlRegister(u32);
36
37bitflags! {
38    impl ControlOverrideRegister: u32 {
39        /// CCI-550 only, Enable both snoop data layers for data transfer between ACE masters.
40        const CD_LAYER2_ACE_ENABLE = 1 << 4;
41        /// Disable regional clock gating
42        const DISABLE_CLOCK_GATING = 1 << 3;
43        /// Disable the snoop filter
44        const DISABLE_SNOOP_FILTER = 1 << 2;
45        /// DVM message disable
46        const DVM_MESSAGE_DISABLE = 1 << 1;
47        /// Snoop disable
48        const SNOOP_DISABLE = 1 << 0;
49    }
50
51    impl SecureAccessRegister: u32 {
52        /// Enable the PMU to count both Secure and Non-secure events.
53        const SECURE_OBSERVATION_OVERRIDE = 1 << 2;
54        /// Disable Non-secure access to the PMU and Interface Monitor Registers, unless overridden
55        /// by `NON_SECURE_REGISTER_ACCESS_OVERRIDE`.
56        const DEBUG_MONITOR_SECURITY_OVERRIDE = 1 << 1;
57        /// Enable Non-secure access to the CCI-550 registers.
58        const NON_SECURE_REGISTER_ACCESS_OVERRIDE = 1 << 0;
59    }
60
61    impl StatusRegister: u32 {
62        /// Snoop filter RAM power state change pending.
63        const SF_RAM_STATE_CHANGE_PENDING = 1 << 8;
64        /// Indicates when the snoop filter RAM is initialized.
65        const SF_RAM_INITIALIZATION = 1 << 1;
66        /// Indicates whether any changes to the Snoop Control Registers or the Control Override
67        /// Register are pending:
68        const CHANGE_PENDING = 1 << 0;
69    }
70
71    impl SnoopControlRegister: u32 {
72        /// Indicates whether the slave interface supports DVM messages.
73        const SUPPORT_DVMS = 1 << 31;
74        /// Indicates whether the slave interface supports snoop requests.
75        const SUPPORT_SNOOPS = 1 << 30;
76        /// CCI-550 only, Indicates whether the slave interface has a system coherency interface to
77        /// provide hardware snoop enable control.
78        const HARDWARE_SNOOP_ENABLE_CONTROL = 1 << 29;
79        /// Enables issuing of DVM message requests from the slave interface.
80        const ENABLE_DVMS = 1 << 1;
81        /// Enables issuing of snoop requests from the slave interface.
82        const ENABLE_SNOOP = 1 << 0;
83    }
84}
85
86/// CCI base registers
87#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
88#[repr(C, align(4))]
89pub struct CciBaseRegisters {
90    /// 0x000: Control Override Register
91    ctrl_ovr: ReadPureWrite<ControlOverrideRegister>,
92    /// 0x004
93    reserved_004: u32,
94    /// 0x008: Secure Access Register
95    secr_acc: ReadPureWrite<SecureAccessRegister>,
96    /// 0x00C: Status Register
97    status: ReadPure<StatusRegister>,
98    /// 0x010: Imprecise Error Register
99    impr_error: ReadPureWrite<u32>,
100    /// 0x014: QoS Threshold Register
101    qos_threshold: ReadPureWrite<u32>,
102    /// 0x018 - 0x0FC
103    reserved_018: [u32; 58],
104    /// 0x0100: Performance Monitor Control Register
105    pmu_ctrl: ReadPure<u32>,
106    /// 0x0104: Interface Monitor Control Register
107    debug_ctrl: ReadPureWrite<u32>,
108    /// 0x108 - 0xFCC
109    reserved_108: [u32; 946],
110    /// 0xFD0: Peripheral ID4
111    peripheral_id4: ReadPure<u32>,
112    /// 0xFD4: Peripheral ID5
113    peripheral_id5: ReadPure<u32>,
114    /// 0xFD8: Peripheral ID6
115    peripheral_id6: ReadPure<u32>,
116    /// 0xFDC: Peripheral ID7
117    peripheral_id7: ReadPure<u32>,
118    /// 0xFE0: Peripheral ID0
119    peripheral_id0: ReadPure<u32>,
120    /// 0xFE4: Peripheral ID1
121    peripheral_id1: ReadPure<u32>,
122    /// 0xFE8: Peripheral ID2
123    peripheral_id2: ReadPure<u32>,
124    /// 0xFEC: Peripheral ID3
125    peripheral_id3: ReadPure<u32>,
126    /// 0xFF0: Component ID0
127    component_id0: ReadPure<u32>,
128    /// 0xFF4: Component ID1
129    component_id1: ReadPure<u32>,
130    /// 0xFF8: Component ID2
131    component_id2: ReadPure<u32>,
132    /// 0xFFC: Component ID3
133    component_id3: ReadPure<u32>,
134}
135
136/// Slave interface registers
137#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
138#[repr(C, align(4))]
139pub struct CciSlaveRegisters {
140    /// 0x000: Snoop Control Register
141    snoop_ctrl: ReadPureWrite<SnoopControlRegister>,
142    /// 0x004: Shareable Override Register
143    share_ovr: ReadPureWrite<u32>,
144    /// 0x008 - 0x0FC
145    reserved_008: [u32; 62],
146    /// 0x100: Read Channel QoS Value Override Register
147    arqos_ovr: ReadPureWrite<u32>,
148    /// 0x104: Write Channel QoS Value Override Register
149    awqos_ovr: ReadPureWrite<u32>,
150    reserved_108: [u32; 2],
151    /// 0x110: Max OT Register
152    qos_max_ot: ReadPureWrite<u32>,
153    /// 0x114 - 0xFFC
154    reserved_13c: [u32; 955],
155}
156
157/// Performance counter registers
158#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
159#[repr(C, align(4))]
160pub struct CciPerformanceCounterRegisters {
161    /// 0x000: Event Select Register
162    evnt_sel: ReadPureWrite<u32>,
163    /// 0x004: Event Count Register
164    ecnt_data: ReadPureWrite<u32>,
165    /// 0x008: Count Control Register
166    ecnt_ctlr: ReadPureWrite<u32>,
167    /// 0x00c: Overflow Flag Status Register
168    ecnt_clr_ovfl: ReadPureWrite<u32>,
169    /// 0x010 - 0xFFC
170    reserved_10: [u32; 16380],
171}
172
173/// Slave Interface Monitor Registers
174#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
175#[repr(C, align(4))]
176pub struct CciSlaveInterfaceMonitorRegisters {
177    /// 0x000 - Slave Interface Monitor Registers
178    slave_debug: [ReadPureWrite<u32>; 7],
179    reserved: [u32; 57],
180}
181
182/// Master Interface Monitor Registers
183#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
184#[repr(C, align(4))]
185pub struct CciMasterInterfaceMonitorRegisters {
186    /// Master Interface Monitor Registers
187    master_debug: [ReadPureWrite<u32>; 6],
188    reserved: [u32; 58],
189}
190
191/// CCI-500/CCI-550 registers
192#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
193#[repr(C, align(4))]
194pub struct Cci5x0Registers {
195    /// 0x00000: Base registers
196    base_regs: CciBaseRegisters,
197    /// 0x01000 - 0x07FFC: Slave interface 0-6 registers
198    slaves: [CciSlaveRegisters; 7],
199    /// 0x08000 - 0x0FFFC
200    reserved_8000: [u32; 8192],
201    /// 0x10000 - 0x8FFFC: Performance counter 0-7 registers
202    performance_counters: [CciPerformanceCounterRegisters; 8],
203    /// 0x90000 - 0x900FC: Slave Interface Monitor Registers
204    slave_interface_monitor: CciSlaveInterfaceMonitorRegisters,
205    /// 0x90100 - 0x901FC: Master Interface Monitor Registers
206    master_interface_monitor: CciMasterInterfaceMonitorRegisters,
207    // 0x90200 - 0xA0000
208    reserved_90200: [u32; 16256],
209}
210
211/// CCI-500/CCI-550 driver.
212#[derive(Eq, Debug, PartialEq)]
213pub struct Cci5x0<'a> {
214    regs: UniqueMmioPointer<'a, Cci5x0Registers>,
215}
216
217impl<'a> Cci5x0<'a> {
218    pub fn new(regs: UniqueMmioPointer<'a, Cci5x0Registers>) -> Self {
219        Self { regs }
220    }
221
222    /// Adds master to cache coherency domain.
223    ///
224    /// # Safety
225    ///
226    /// The caller must ensure that the master only enables allocating shareable data into its cache
227    /// after this function completes.
228    pub unsafe fn add_master_to_coherency(&mut self, index: usize) {
229        // Safety: Enabling DVM and snoop propagates the same requirements to the caller of this
230        // function. The function waits until the transaction completes by calling
231        // wait_pending_change.
232        unsafe {
233            self.write_snoop_control(
234                index,
235                SnoopControlRegister::ENABLE_DVMS | SnoopControlRegister::ENABLE_SNOOP,
236            );
237        }
238
239        self.wait_pending_change();
240    }
241
242    /// Removes master from cache coherency domain.
243    ///
244    /// # Safety
245    ///
246    /// The caller must ensure that the master is configured so that it does not allocate shareable
247    /// data into its cache, for example by disabling the data cache. The caller also has to clean
248    /// and invalidate all shareable data from the caches in the master prior calling this function.
249    pub unsafe fn remove_master_from_coherency(&mut self, index: usize) {
250        // Safety: Disabling DVM and snoop propagates the same requirements to the caller of this
251        // function.
252        unsafe {
253            self.write_snoop_control(index, SnoopControlRegister::empty());
254        }
255        self.wait_pending_change();
256    }
257
258    /// Writes the snoop control register of the slave interface.
259    ///
260    /// # Safety
261    ///
262    /// When disabling snoop or DVM messages the caller must ensure that the master is configured so
263    /// that it does not allocate shareable data into its cache, for example by disabling the data
264    /// cache. The caller also has to clean and invalidate all shareable data from the caches in the
265    /// master prior calling this function.
266    /// When enabling snoop or DVM messages, the caller must ensure that the master only enables
267    /// allocating shareable data into its cache after this transaction completes.
268    unsafe fn write_snoop_control(&mut self, index: usize, snoop_control: SnoopControlRegister) {
269        let mut slaves = field!(self.regs, slaves);
270        let mut slave = slaves.get(index).unwrap();
271
272        field!(slave, snoop_ctrl).write(snoop_control);
273
274        // Execute a barrier instruction to ensure that the previous step is complete.
275        // Safety: Synchronization barrier only.
276        #[cfg(target_arch = "aarch64")]
277        unsafe {
278            core::arch::asm!(
279                "isb
280                dsb sy",
281                options(nomem, nostack)
282            );
283        }
284    }
285
286    /// Wait until there are any pending changes to the Snoop Control Registers or the Control
287    /// Override Register
288    fn wait_pending_change(&self) {
289        let base_regs = field_shared!(self.regs, base_regs);
290        while field_shared!(base_regs, status)
291            .read()
292            .contains(StatusRegister::CHANGE_PENDING)
293        {
294            core::hint::spin_loop();
295        }
296    }
297}
298
299#[cfg(test)]
300mod tests {
301    use super::*;
302
303    #[test]
304    fn size() {
305        assert_eq!(0x1000, core::mem::size_of::<CciBaseRegisters>());
306        assert_eq!(0x1000, core::mem::size_of::<CciSlaveRegisters>());
307        assert_eq!(
308            0x10000,
309            core::mem::size_of::<CciPerformanceCounterRegisters>()
310        );
311        assert_eq!(
312            0x100,
313            core::mem::size_of::<CciSlaveInterfaceMonitorRegisters>()
314        );
315        assert_eq!(
316            0x100,
317            core::mem::size_of::<CciMasterInterfaceMonitorRegisters>()
318        );
319        assert_eq!(0xa0000, core::mem::size_of::<Cci5x0Registers>());
320    }
321}