2025-04-11 20:39:36 +02:00

192 lines
8.5 KiB
Rust

//! The overview of translation table memory attributes is described below.
//!
//!| | Memory Range | Definition in Translation Table |
//!|-----------------------|-------------------------|-----------------------------------|
//!| DDR | 0x00000000 - 0x3FFFFFFF | Normal write-back Cacheable |
//!| PL | 0x40000000 - 0xBFFFFFFF | Strongly Ordered |
//!| Reserved | 0xC0000000 - 0xDFFFFFFF | Unassigned |
//!| Memory mapped devices | 0xE0000000 - 0xE02FFFFF | Device Memory |
//!| Reserved | 0xE0300000 - 0xE0FFFFFF | Unassigned |
//!| NAND, NOR | 0xE1000000 - 0xE3FFFFFF | Device memory |
//!| SRAM | 0xE4000000 - 0xE5FFFFFF | Normal write-back Cacheable |
//!| Reserved | 0xE6000000 - 0xF7FFFFFF | Unassigned |
//!| AMBA APB Peripherals | 0xF8000000 - 0xF8FFFFFF | Device Memory |
//!| Reserved | 0xF9000000 - 0xFBFFFFFF | Unassigned |
//!| Linear QSPI - XIP | 0xFC000000 - 0xFDFFFFFF | Normal write-through cacheable |
//!| Reserved | 0xFE000000 - 0xFFEFFFFF | Unassigned |
//!| OCM | 0xFFF00000 - 0xFFFFFFFF | Normal inner write-back cacheable |
//!
//! For region 0x00000000 - 0x3FFFFFFF, a system where DDR is less than 1 GB,
//! region after DDR and before PL is marked as undefined/reserved in translation
//! table. In 0xF8000000 - 0xF8FFFFFF, 0xF8000C00 - 0xF8000FFF, 0xF8010000 -
//! 0xF88FFFFF and 0xF8F03000 to 0xF8FFFFFF are reserved but due to granual size
//! of 1 MB, it is not possible to define separate regions for them. For region
//! 0xFFF00000 - 0xFFFFFFFF, 0xFFF00000 to 0xFFFB0000 is reserved but due to 1MB
//! granual size, it is not possible to define separate region for it.
pub const MAX_DDR_SIZE: usize = 0x4000_0000;
pub const ONE_MB: usize = 0x10_0000;
pub mod offsets {
pub const OFFSET_DDR: usize = 0;
pub const OFFSET_DDR_ALL_ACCESSIBLE: usize = 0x10_0000;
pub const OFFSET_FPGA_SLAVE_0: usize = 0x4000_0000;
pub const OFFSET_FPGA_SLAVE_1_START: usize = 0x8000_0000;
pub const OFFSET_FPGA_SLAVE_1_END: usize = 0xC000_0000;
pub const OFFSET_IO_PERIPHERALS_START: usize = 0xE000_0000;
pub const OFFSET_IO_PERIPHERALS_END: usize = 0xE030_0000;
pub const OFFSET_NAND_MEMORY: usize = 0xE100_0000;
pub const OFFSET_NOR_MEMORY: usize = 0xE200_0000;
pub const OFFSET_SRAM_MEMORY: usize = 0xE400_0000;
pub const OFFSET_SMC_MEMORIES_END: usize = 0xE600_0000;
/// 0xf8000c00 to 0xf8000fff, 0xf8010000 to 0xf88fffff and
/// 0xf8f03000 to 0xf8ffffff are reserved but due to granual size of
/// 1MB, it is not possible to define separate regions for them.
pub const OFFSET_AMBA_APB_START: usize = 0xF800_0000;
pub const OFFSET_AMBA_APB_END: usize = 0xF900_0000;
pub const OFFSET_QSPI_XIP_START: usize = 0xFC00_0000;
pub const OFFSET_QSPI_XIP_END: usize = 0xFE00_0000;
/// 0xfff00000 to 0xfffb0000 is reserved but due to granual size of
/// 1MB, it is not possible to define separate region for it
pub const OFFSET_OCM_MAPPED_HIGH_START: usize = 0xFFF0_0000;
pub const OFFSET_OCM_MAPPED_HIGH_END: u64 = 0x1_0000_0000;
}
pub mod segments {
pub use super::offsets::*;
use super::{MAX_DDR_SIZE, ONE_MB};
/// First 1 MB of DDR has special treatment, access is dependant on SCU/OCM state.
/// Refer to Zynq TRM UG585 p.106 for more details.
pub const DDR_FULL_ACCESSIBLE: usize = (MAX_DDR_SIZE - ONE_MB) / ONE_MB;
pub const FPGA_SLAVE: usize = (OFFSET_FPGA_SLAVE_1_START - OFFSET_FPGA_SLAVE_0) / ONE_MB;
pub const UNASSIGNED_0: usize =
(OFFSET_IO_PERIPHERALS_START - OFFSET_FPGA_SLAVE_1_END) / ONE_MB;
pub const IO_PERIPHS: usize =
(OFFSET_IO_PERIPHERALS_END - OFFSET_IO_PERIPHERALS_START) / ONE_MB;
pub const UNASSIGNED_1: usize = (OFFSET_NAND_MEMORY - OFFSET_IO_PERIPHERALS_END) / ONE_MB;
pub const NAND: usize = (OFFSET_NOR_MEMORY - OFFSET_NAND_MEMORY) / ONE_MB;
pub const NOR: usize = (OFFSET_SRAM_MEMORY - OFFSET_NOR_MEMORY) / ONE_MB;
pub const SRAM: usize = (OFFSET_SMC_MEMORIES_END - OFFSET_SRAM_MEMORY) / ONE_MB;
pub const SEGMENTS_UNASSIGNED_2: usize =
(OFFSET_AMBA_APB_START - OFFSET_SMC_MEMORIES_END) / ONE_MB;
pub const AMBA_APB: usize = (OFFSET_AMBA_APB_END - OFFSET_AMBA_APB_START) / ONE_MB;
pub const UNASSIGNED_3: usize = (OFFSET_QSPI_XIP_START - OFFSET_AMBA_APB_END) / ONE_MB;
pub const QSPI_XIP: usize = (OFFSET_QSPI_XIP_END - OFFSET_QSPI_XIP_START) / ONE_MB;
pub const UNASSIGNED_4: usize = (OFFSET_OCM_MAPPED_HIGH_START - OFFSET_QSPI_XIP_END) / ONE_MB;
pub const OCM_MAPPED_HIGH: usize = ((OFFSET_OCM_MAPPED_HIGH_END
- OFFSET_OCM_MAPPED_HIGH_START as u64)
/ ONE_MB as u64) as usize;
}
pub mod section_attrs {
use cortex_ar::mmu::{
AccessPermissions, CacheableMemoryAttribute, MemoryRegionAttributes, SectionAttributes,
};
pub const DDR: SectionAttributes = SectionAttributes {
non_global: false,
p_bit: false,
shareable: true,
access: AccessPermissions::FullAccess,
// Manager domain
domain: 0b1111,
execute_never: false,
memory_attrs: MemoryRegionAttributes::CacheableMemory {
inner: CacheableMemoryAttribute::WriteBackWriteAlloc,
outer: CacheableMemoryAttribute::WriteBackWriteAlloc,
}
.as_raw(),
};
pub const FPGA_SLAVES: SectionAttributes = SectionAttributes {
non_global: false,
p_bit: false,
shareable: false,
access: AccessPermissions::FullAccess,
domain: 0b0000,
execute_never: false,
memory_attrs: MemoryRegionAttributes::StronglyOrdered.as_raw(),
};
pub const SHAREABLE_DEVICE: SectionAttributes = SectionAttributes {
non_global: false,
p_bit: false,
shareable: false,
access: AccessPermissions::FullAccess,
domain: 0b0000,
execute_never: false,
memory_attrs: MemoryRegionAttributes::ShareableDevice.as_raw(),
};
pub const SRAM: SectionAttributes = SectionAttributes {
non_global: false,
p_bit: false,
shareable: false,
access: AccessPermissions::FullAccess,
domain: 0b0000,
execute_never: false,
memory_attrs: MemoryRegionAttributes::OuterAndInnerWriteBackNoWriteAlloc.as_raw(),
};
pub const QSPI_XIP: SectionAttributes = SectionAttributes {
non_global: false,
p_bit: false,
shareable: false,
access: AccessPermissions::FullAccess,
domain: 0b0000,
execute_never: false,
memory_attrs: MemoryRegionAttributes::OuterAndInnerWriteThroughNoWriteAlloc.as_raw(),
};
pub const OCM_MAPPED_HIGH: SectionAttributes = SectionAttributes {
non_global: false,
p_bit: false,
shareable: false,
access: AccessPermissions::FullAccess,
domain: 0b0000,
execute_never: false,
memory_attrs: MemoryRegionAttributes::CacheableMemory {
inner: CacheableMemoryAttribute::WriteThroughNoWriteAlloc,
outer: CacheableMemoryAttribute::NonCacheable,
}
.as_raw(),
};
pub const UNASSIGNED_RESERVED: SectionAttributes = SectionAttributes {
non_global: false,
p_bit: false,
shareable: false,
access: AccessPermissions::PermissionFault,
domain: 0b0000,
execute_never: false,
memory_attrs: MemoryRegionAttributes::StronglyOrdered.as_raw(),
};
}
pub const NUM_L1_PAGE_TABLE_ENTRIES: usize = 4096;
#[repr(C, align(16384))]
#[cfg(feature = "rt")]
pub struct L1Table(pub(crate) [u32; NUM_L1_PAGE_TABLE_ENTRIES]);
/// Load the MMU translation table base address into the MMU.
///
/// # Safety
///
/// This function is unsafe because it directly writes to the MMU related registers. It has to be
/// called once in the boot code before enabling the MMU, and it should be called while the MMU is
/// disabled.
#[unsafe(no_mangle)]
#[cfg(feature = "rt")]
unsafe extern "C" fn load_mmu_table() {
let table_base = &crate::mmu_table::MMU_L1_PAGE_TABLE.0 as *const _ as u32;
unsafe {
core::arch::asm!(
"orr {0}, {0}, #0x5B", // Outer-cacheable, WB
"mcr p15, 0, {0}, c2, c0, 0", // Load table pointer
inout(reg) table_base => _,
options(nostack, preserves_flags)
);
}
}