290 lines
6.1 KiB
Rust
290 lines
6.1 KiB
Rust
use arbitrary_int::{u2, u3, u4, u6};
|
|
|
|
pub const L2C_BASE_ADDR: usize = 0xF8F0_2000;
|
|
|
|
#[derive(derive_mmio::Mmio)]
|
|
#[repr(C)]
|
|
pub struct LockdownRegisters {
|
|
data: u32,
|
|
instruction: u32,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32, debug)]
|
|
pub struct CacheSync {
|
|
#[bit(0, r)]
|
|
busy: bool,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
|
pub struct DebugControl {
|
|
#[bit(2, rw)]
|
|
spniden: bool,
|
|
#[bit(1, rw)]
|
|
disable_write_back: bool,
|
|
#[bit(0, rw)]
|
|
disable_cache_linefill: bool,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32, debug)]
|
|
pub struct CacheId {
|
|
#[bits(24..=31, r)]
|
|
implementer: u8,
|
|
#[bits(10..=15, r)]
|
|
cache_id: u6,
|
|
#[bits(6..=9, r)]
|
|
part_number: u4,
|
|
#[bits(0..=5, r)]
|
|
rtl_release: u6,
|
|
}
|
|
|
|
#[repr(transparent)]
|
|
pub struct Control(u32);
|
|
|
|
impl Control {
|
|
pub fn new_enabled() -> Self {
|
|
Self(0x1)
|
|
}
|
|
|
|
pub fn new_disabled() -> Self {
|
|
Self(0x0)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn enabled(&mut self) -> bool {
|
|
self.0 == 0x1
|
|
}
|
|
}
|
|
|
|
#[bitbybit::bitenum(u1, exhaustive = true)]
|
|
#[derive(Debug)]
|
|
pub enum ReplacementPolicy {
|
|
PseudoRandomWithLfsr = 0,
|
|
RoundRobin = 1,
|
|
}
|
|
|
|
#[bitbybit::bitenum(u3, exhaustive = true)]
|
|
#[derive(Default, Debug)]
|
|
pub enum WaySize {
|
|
__Reserved0 = 0b000,
|
|
_16kB = 0b001,
|
|
_32kB = 0b010,
|
|
#[default]
|
|
_64kB = 0b011,
|
|
_128kB = 0b100,
|
|
_256kB = 0b101,
|
|
_512kB = 0b110,
|
|
__Reserved1 = 0b111,
|
|
}
|
|
|
|
#[bitbybit::bitenum(u1, exhaustive = true)]
|
|
#[derive(Default, Debug)]
|
|
pub enum Associativity {
|
|
#[default]
|
|
_8Way = 0,
|
|
_16Way = 1,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
|
pub struct AuxControl {
|
|
#[bit(30, rw)]
|
|
early_bresp_enable: bool,
|
|
#[bit(29, rw)]
|
|
isntruction_prefetch_enable: bool,
|
|
#[bit(28, rw)]
|
|
data_prefetch_enable: bool,
|
|
#[bit(27, rw)]
|
|
nonsec_interrupt_access_control: bool,
|
|
#[bit(26, rw)]
|
|
nonsec_lockdown_enable: bool,
|
|
#[bit(25, rw)]
|
|
cache_replace_policy: ReplacementPolicy,
|
|
#[bits(23..=24, rw)]
|
|
force_write_alloc: u2,
|
|
#[bit(22, rw)]
|
|
shared_attr_override: bool,
|
|
#[bit(21, rw)]
|
|
parity_enable: bool,
|
|
#[bit(20, rw)]
|
|
event_monitor_bus_enable: bool,
|
|
#[bits(17..=19, rw)]
|
|
way_size: WaySize,
|
|
#[bit(16, rw)]
|
|
associativity: Associativity,
|
|
#[bit(13, rw)]
|
|
shared_attribute_invalidate: bool,
|
|
#[bit(12, rw)]
|
|
exclusive_cache_config: bool,
|
|
#[bit(11, rw)]
|
|
store_buff_device_limitation_enable: bool,
|
|
#[bit(10, rw)]
|
|
high_priority_so_dev_reads: bool,
|
|
/// Disabled by default.
|
|
#[bit(0, rw)]
|
|
full_line_zero_enable: bool,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
|
#[derive(PartialEq, Eq)]
|
|
pub struct LatencyConfig {
|
|
/// Latency is the numerical value + 1 cycles.
|
|
#[bits(8..=10, rw)]
|
|
write_access_latency: u3,
|
|
/// Latency is the numerical value + 1 cycles.
|
|
#[bits(4..=6, rw)]
|
|
read_access_latency: u3,
|
|
/// Latency is the numerical value + 1 cycles.
|
|
#[bits(0..=2, rw)]
|
|
setup_latency: u3,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32, debug)]
|
|
pub struct InterruptStatus {
|
|
#[bit(8, r)]
|
|
dec_error_l3: bool,
|
|
#[bit(7, r)]
|
|
slave_error_l3: bool,
|
|
#[bit(6, r)]
|
|
error_data_ram_read: bool,
|
|
#[bit(5, r)]
|
|
error_tag_ram_read: bool,
|
|
#[bit(4, r)]
|
|
error_data_ram_write: bool,
|
|
#[bit(3, r)]
|
|
error_tag_ram_write: bool,
|
|
#[bit(2, r)]
|
|
parity_error_data_ram_read: bool,
|
|
#[bit(1, r)]
|
|
parity_error_tag_ram_read: bool,
|
|
/// ECNTR
|
|
#[bit(0, r)]
|
|
event_counter_overflow_increment: bool,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32, default = 0x0)]
|
|
#[derive(Debug)]
|
|
pub struct InterruptControl {
|
|
#[bit(8, w)]
|
|
dec_error_l3: bool,
|
|
#[bit(7, w)]
|
|
slave_error_l3: bool,
|
|
#[bit(6, w)]
|
|
error_data_ram_read: bool,
|
|
#[bit(5, w)]
|
|
error_tag_ram_read: bool,
|
|
#[bit(4, w)]
|
|
error_data_ram_write: bool,
|
|
#[bit(3, w)]
|
|
error_tag_ram_write: bool,
|
|
#[bit(2, w)]
|
|
parity_error_data_ram_read: bool,
|
|
#[bit(1, w)]
|
|
parity_error_tag_ram_read: bool,
|
|
/// ECNTR
|
|
#[bit(0, w)]
|
|
event_counter_overflow_increment: bool,
|
|
}
|
|
|
|
/// L2 Cache register access.
|
|
#[derive(derive_mmio::Mmio)]
|
|
#[repr(C)]
|
|
pub struct Registers {
|
|
#[mmio(PureRead)]
|
|
cache_id: CacheId,
|
|
#[mmio(PureRead)]
|
|
cache_type: u32,
|
|
|
|
_reserved: [u32; 0x3E],
|
|
|
|
control: Control,
|
|
aux_control: AuxControl,
|
|
tag_ram_latency: LatencyConfig,
|
|
data_ram_latency: LatencyConfig,
|
|
|
|
_reserved2: [u32; 0x3C],
|
|
|
|
event_counter_control: u32,
|
|
event_counter_1_config: u32,
|
|
event_counter_0_config: u32,
|
|
event_counter_1: u32,
|
|
event_counter_0: u32,
|
|
interrupt_mask: u32,
|
|
#[mmio(PureRead)]
|
|
interrupt_mask_status: InterruptStatus,
|
|
#[mmio(PureRead)]
|
|
interrupt_raw_status: InterruptStatus,
|
|
#[mmio(Write)]
|
|
interrupt_clear: InterruptControl,
|
|
|
|
_reserved3: [u32; 0x143],
|
|
|
|
cache_sync: CacheSync,
|
|
|
|
_reserved4: [u32; 0xF],
|
|
|
|
invalidate_by_pa: u32,
|
|
|
|
_reserved5: [u32; 0x2],
|
|
|
|
invalidate_by_way: u32,
|
|
|
|
_reserved6: [u32; 0xC],
|
|
|
|
clean_by_pa: u32,
|
|
|
|
_reserved7: u32,
|
|
|
|
clean_by_index: u32,
|
|
clean_by_way: u32,
|
|
|
|
_reserved8: [u32; 0xC],
|
|
|
|
clean_invalidate_by_pa: u32,
|
|
|
|
_reserved9: u32,
|
|
|
|
clean_invalidate_by_index: u32,
|
|
clean_invalidate_by_way: u32,
|
|
|
|
_reserved10: [u32; 0x40],
|
|
|
|
#[mmio(Inner)]
|
|
lockdown_regs: [LockdownRegisters; 8],
|
|
|
|
_reserved11: [u32; 0x4],
|
|
|
|
lockdown_by_line_enable: u32,
|
|
unlock_way: u32,
|
|
|
|
_reserved12: [u32; 0xAA],
|
|
|
|
addr_filtering_start: u32,
|
|
addr_filtering_end: u32,
|
|
|
|
_reserved13: [u32; 0xCE],
|
|
|
|
debug_control: DebugControl,
|
|
|
|
_reserved14: [u32; 0x7],
|
|
|
|
prefetch_control: u32,
|
|
|
|
_reserved15: [u32; 0x7],
|
|
|
|
power_control: u32,
|
|
}
|
|
|
|
static_assertions::const_assert_eq!(core::mem::size_of::<Registers>(), 0xF84);
|
|
|
|
impl Registers {
|
|
/// Create a new L2C MMIO instance for for L2 Cache at address [L2C_BASE_ADDR].
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// This API can be used to potentially create a driver to the same peripheral structure
|
|
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
|
/// interfere with each other.
|
|
pub const unsafe fn new_mmio_fixed() -> MmioRegisters<'static> {
|
|
unsafe { Self::new_mmio_at(L2C_BASE_ADDR) }
|
|
}
|
|
}
|