1#![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#[repr(transparent)]
19#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
20pub struct ControlOverrideRegister(u32);
21
22#[repr(transparent)]
24#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
25pub struct SecureAccessRegister(u32);
26
27#[repr(transparent)]
29#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
30pub struct StatusRegister(u32);
31
32#[repr(transparent)]
34#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
35pub struct SnoopControlRegister(u32);
36
37bitflags! {
38 impl ControlOverrideRegister: u32 {
39 const CD_LAYER2_ACE_ENABLE = 1 << 4;
41 const DISABLE_CLOCK_GATING = 1 << 3;
43 const DISABLE_SNOOP_FILTER = 1 << 2;
45 const DVM_MESSAGE_DISABLE = 1 << 1;
47 const SNOOP_DISABLE = 1 << 0;
49 }
50
51 impl SecureAccessRegister: u32 {
52 const SECURE_OBSERVATION_OVERRIDE = 1 << 2;
54 const DEBUG_MONITOR_SECURITY_OVERRIDE = 1 << 1;
57 const NON_SECURE_REGISTER_ACCESS_OVERRIDE = 1 << 0;
59 }
60
61 impl StatusRegister: u32 {
62 const SF_RAM_STATE_CHANGE_PENDING = 1 << 8;
64 const SF_RAM_INITIALIZATION = 1 << 1;
66 const CHANGE_PENDING = 1 << 0;
69 }
70
71 impl SnoopControlRegister: u32 {
72 const SUPPORT_DVMS = 1 << 31;
74 const SUPPORT_SNOOPS = 1 << 30;
76 const HARDWARE_SNOOP_ENABLE_CONTROL = 1 << 29;
79 const ENABLE_DVMS = 1 << 1;
81 const ENABLE_SNOOP = 1 << 0;
83 }
84}
85
86#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
88#[repr(C, align(4))]
89pub struct CciBaseRegisters {
90 ctrl_ovr: ReadPureWrite<ControlOverrideRegister>,
92 reserved_004: u32,
94 secr_acc: ReadPureWrite<SecureAccessRegister>,
96 status: ReadPure<StatusRegister>,
98 impr_error: ReadPureWrite<u32>,
100 qos_threshold: ReadPureWrite<u32>,
102 reserved_018: [u32; 58],
104 pmu_ctrl: ReadPure<u32>,
106 debug_ctrl: ReadPureWrite<u32>,
108 reserved_108: [u32; 946],
110 peripheral_id4: ReadPure<u32>,
112 peripheral_id5: ReadPure<u32>,
114 peripheral_id6: ReadPure<u32>,
116 peripheral_id7: ReadPure<u32>,
118 peripheral_id0: ReadPure<u32>,
120 peripheral_id1: ReadPure<u32>,
122 peripheral_id2: ReadPure<u32>,
124 peripheral_id3: ReadPure<u32>,
126 component_id0: ReadPure<u32>,
128 component_id1: ReadPure<u32>,
130 component_id2: ReadPure<u32>,
132 component_id3: ReadPure<u32>,
134}
135
136#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
138#[repr(C, align(4))]
139pub struct CciSlaveRegisters {
140 snoop_ctrl: ReadPureWrite<SnoopControlRegister>,
142 share_ovr: ReadPureWrite<u32>,
144 reserved_008: [u32; 62],
146 arqos_ovr: ReadPureWrite<u32>,
148 awqos_ovr: ReadPureWrite<u32>,
150 reserved_108: [u32; 2],
151 qos_max_ot: ReadPureWrite<u32>,
153 reserved_13c: [u32; 955],
155}
156
157#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
159#[repr(C, align(4))]
160pub struct CciPerformanceCounterRegisters {
161 evnt_sel: ReadPureWrite<u32>,
163 ecnt_data: ReadPureWrite<u32>,
165 ecnt_ctlr: ReadPureWrite<u32>,
167 ecnt_clr_ovfl: ReadPureWrite<u32>,
169 reserved_10: [u32; 16380],
171}
172
173#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
175#[repr(C, align(4))]
176pub struct CciSlaveInterfaceMonitorRegisters {
177 slave_debug: [ReadPureWrite<u32>; 7],
179 reserved: [u32; 57],
180}
181
182#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
184#[repr(C, align(4))]
185pub struct CciMasterInterfaceMonitorRegisters {
186 master_debug: [ReadPureWrite<u32>; 6],
188 reserved: [u32; 58],
189}
190
191#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
193#[repr(C, align(4))]
194pub struct Cci5x0Registers {
195 base_regs: CciBaseRegisters,
197 slaves: [CciSlaveRegisters; 7],
199 reserved_8000: [u32; 8192],
201 performance_counters: [CciPerformanceCounterRegisters; 8],
203 slave_interface_monitor: CciSlaveInterfaceMonitorRegisters,
205 master_interface_monitor: CciMasterInterfaceMonitorRegisters,
207 reserved_90200: [u32; 16256],
209}
210
211#[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 pub unsafe fn add_master_to_coherency(&mut self, index: usize) {
229 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 pub unsafe fn remove_master_from_coherency(&mut self, index: usize) {
250 unsafe {
253 self.write_snoop_control(index, SnoopControlRegister::empty());
254 }
255 self.wait_pending_change();
256 }
257
258 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 #[cfg(target_arch = "aarch64")]
277 unsafe {
278 core::arch::asm!(
279 "isb
280 dsb sy",
281 options(nomem, nostack)
282 );
283 }
284 }
285
286 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}