l2 cache init now done in user app #7

Merged
muellerr merged 1 commits from l2-cache-init-opt into main 2025-07-28 11:02:17 +02:00
19 changed files with 304 additions and 83 deletions

View File

@@ -15,6 +15,7 @@ use zynq7000_hal::{
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{Flex, Output, PinState, mio}, gpio::{Flex, Output, PinState, mio},
gtc::Gtc, gtc::Gtc,
l2_cache,
time::Hertz, time::Hertz,
uart::{ClkConfigRaw, Uart, UartConfig}, uart::{ClkConfigRaw, Uart, UartConfig},
}; };
@@ -43,7 +44,9 @@ const OPEN_DRAIN_PINS_MIO9_TO_MIO14: bool = false;
#[embassy_executor::main] #[embassy_executor::main]
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! { async fn main(_spawner: Spawner) -> ! {
let dp = PsPeripherals::take().unwrap(); let mut dp = PsPeripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller. // Set up the global interrupt controller.

View File

@@ -16,6 +16,7 @@ use zynq7000_hal::{
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{Output, PinState, mio}, gpio::{Output, PinState, mio},
gtc::Gtc, gtc::Gtc,
l2_cache,
time::Hertz, time::Hertz,
uart::{ClkConfigRaw, TxAsync, Uart, UartConfig, on_interrupt_tx}, uart::{ClkConfigRaw, TxAsync, Uart, UartConfig, on_interrupt_tx},
}; };
@@ -37,7 +38,9 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! {
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
#[embassy_executor::main] #[embassy_executor::main]
async fn main(spawner: Spawner) -> ! { async fn main(spawner: Spawner) -> ! {
let dp = PsPeripherals::take().unwrap(); let mut dp = PsPeripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller. // Set up the global interrupt controller.

View File

@@ -21,6 +21,7 @@ use zynq7000_hal::{
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{Output, PinState, mio}, gpio::{Output, PinState, mio},
gtc::Gtc, gtc::Gtc,
l2_cache,
time::Hertz, time::Hertz,
uart::{ClkConfigRaw, Uart, UartConfig}, uart::{ClkConfigRaw, Uart, UartConfig},
}; };
@@ -43,7 +44,9 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! {
#[embassy_executor::main] #[embassy_executor::main]
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! { async fn main(_spawner: Spawner) -> ! {
let dp = PsPeripherals::take().unwrap(); let mut dp = PsPeripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller. // Set up the global interrupt controller.

View File

@@ -14,6 +14,7 @@ use zynq7000_hal::{
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{Output, PinState, mio}, gpio::{Output, PinState, mio},
gtc::Gtc, gtc::Gtc,
l2_cache,
time::Hertz, time::Hertz,
uart::{ClkConfigRaw, Uart, UartConfig}, uart::{ClkConfigRaw, Uart, UartConfig},
}; };
@@ -33,11 +34,12 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! {
main(); main();
} }
// TODO: The export name is ignored..
#[embassy_executor::main] #[embassy_executor::main]
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! { async fn main(_spawner: Spawner) -> ! {
let dp = PsPeripherals::take().unwrap(); let mut dp = PsPeripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller. // Set up the global interrupt controller.

View File

@@ -12,6 +12,7 @@ use zynq7000_hal::{
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{Output, PinState, mio}, gpio::{Output, PinState, mio},
gtc::Gtc, gtc::Gtc,
l2_cache,
prelude::*, prelude::*,
time::Hertz, time::Hertz,
uart::{ClkConfigRaw, Uart, UartConfig}, uart::{ClkConfigRaw, Uart, UartConfig},
@@ -35,7 +36,9 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! {
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
pub fn main() -> ! { pub fn main() -> ! {
let dp = zynq7000::PsPeripherals::take().unwrap(); let mut dp = zynq7000::PsPeripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller. // Set up the global interrupt controller.

View File

@@ -13,6 +13,7 @@ use zynq7000_hal::{
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{Output, PinState, mio}, gpio::{Output, PinState, mio},
gtc::Gtc, gtc::Gtc,
l2_cache,
prelude::*, prelude::*,
time::Hertz, time::Hertz,
uart::{ClkConfigRaw, Uart, UartConfig}, uart::{ClkConfigRaw, Uart, UartConfig},
@@ -36,7 +37,9 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! {
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
pub fn main() -> ! { pub fn main() -> ! {
let dp = zynq7000::PsPeripherals::take().unwrap(); let mut dp = zynq7000::PsPeripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller. // Set up the global interrupt controller.

View File

@@ -6,7 +6,10 @@ use core::panic::PanicInfo;
use cortex_ar::asm::nop; use cortex_ar::asm::nop;
use embedded_hal::digital::StatefulOutputPin; use embedded_hal::digital::StatefulOutputPin;
use zynq7000::PsPeripherals; use zynq7000::PsPeripherals;
use zynq7000_hal::gpio::{Output, PinState, mio}; use zynq7000_hal::{
gpio::{Output, PinState, mio},
l2_cache,
};
use zynq7000_rt as _; use zynq7000_rt as _;
/// One user LED is MIO7 /// One user LED is MIO7
@@ -31,6 +34,7 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! {
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
pub fn main() -> ! { pub fn main() -> ! {
l2_cache::init_with_defaults(&mut unsafe { zynq7000::l2_cache::L2Cache::new_mmio_fixed() });
match LIB { match LIB {
Lib::Pac => { Lib::Pac => {
let mut gpio = unsafe { zynq7000::gpio::Gpio::new_mmio_fixed() }; let mut gpio = unsafe { zynq7000::gpio::Gpio::new_mmio_fixed() };

View File

@@ -48,6 +48,7 @@ use zynq7000_hal::{
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{GpioPins, Output, PinState}, gpio::{GpioPins, Output, PinState},
gtc::Gtc, gtc::Gtc,
l2_cache,
uart::{ClkConfigRaw, Uart, UartConfig}, uart::{ClkConfigRaw, Uart, UartConfig},
}; };
@@ -208,14 +209,17 @@ async fn tcp_task(mut tcp: TcpSocket<'static>) -> ! {
#[embassy_executor::main] #[embassy_executor::main]
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
async fn main(spawner: Spawner) -> ! { async fn main(spawner: Spawner) -> ! {
let mut dp = PsPeripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);
// Enable PS-PL level shifters.
configure_level_shifter(LevelShifterConfig::EnableAll);
// Configure the uncached memory region using the MMU. // Configure the uncached memory region using the MMU.
mmu_l1_table_mut() mmu_l1_table_mut()
.update(UNCACHED_ADDR, SHAREABLE_DEVICE) .update(UNCACHED_ADDR, SHAREABLE_DEVICE)
.expect("configuring uncached memory section failed"); .expect("configuring uncached memory section failed");
// Enable PS-PL level shifters.
configure_level_shifter(LevelShifterConfig::EnableAll);
let dp = PsPeripherals::take().unwrap();
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller. // Set up the global interrupt controller.

View File

@@ -24,7 +24,7 @@ use zynq7000_hal::{
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{GpioPins, Output, PinState}, gpio::{GpioPins, Output, PinState},
gtc::Gtc, gtc::Gtc,
i2c, i2c, l2_cache,
time::Hertz, time::Hertz,
uart, uart,
}; };
@@ -48,9 +48,12 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! {
#[embassy_executor::main] #[embassy_executor::main]
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! { async fn main(_spawner: Spawner) -> ! {
let mut dp = PsPeripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);
// Enable PS-PL level shifters. // Enable PS-PL level shifters.
configure_level_shifter(LevelShifterConfig::EnableAll); configure_level_shifter(LevelShifterConfig::EnableAll);
let dp = PsPeripherals::take().unwrap();
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();

View File

@@ -24,6 +24,7 @@ use zynq7000_hal::{
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{GpioPins, Output, PinState}, gpio::{GpioPins, Output, PinState},
gtc::Gtc, gtc::Gtc,
l2_cache,
spi::{self, SpiAsync, SpiId, SpiWithHwCs, SpiWithHwCsAsync, on_interrupt}, spi::{self, SpiAsync, SpiId, SpiWithHwCs, SpiWithHwCsAsync, on_interrupt},
time::Hertz, time::Hertz,
uart::{self, TxAsync, on_interrupt_tx}, uart::{self, TxAsync, on_interrupt_tx},
@@ -50,9 +51,12 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! {
#[embassy_executor::main] #[embassy_executor::main]
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
async fn main(spawner: Spawner) -> ! { async fn main(spawner: Spawner) -> ! {
let mut dp = PsPeripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);
// Enable PS-PL level shifters. // Enable PS-PL level shifters.
configure_level_shifter(LevelShifterConfig::EnableAll); configure_level_shifter(LevelShifterConfig::EnableAll);
let dp = PsPeripherals::take().unwrap();
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let mut clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); let mut clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();

View File

@@ -19,6 +19,7 @@ use zynq7000_hal::{
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{GpioPins, Output, PinState}, gpio::{GpioPins, Output, PinState},
gtc::Gtc, gtc::Gtc,
l2_cache,
uart::{ClkConfigRaw, Uart, UartConfig}, uart::{ClkConfigRaw, Uart, UartConfig},
}; };
@@ -100,9 +101,11 @@ impl UartMultiplexer {
#[embassy_executor::main] #[embassy_executor::main]
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! { async fn main(_spawner: Spawner) -> ! {
let mut dp = PsPeripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);
// Enable PS-PL level shifters. // Enable PS-PL level shifters.
configure_level_shifter(LevelShifterConfig::EnableAll); configure_level_shifter(LevelShifterConfig::EnableAll);
let dp = PsPeripherals::take().unwrap();
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller. // Set up the global interrupt controller.

View File

@@ -45,6 +45,7 @@ use zynq7000_hal::{
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{GpioPins, Output, PinState}, gpio::{GpioPins, Output, PinState},
gtc::Gtc, gtc::Gtc,
l2_cache,
time::Hertz, time::Hertz,
uart::{ClkConfigRaw, Uart, UartConfig}, uart::{ClkConfigRaw, Uart, UartConfig},
}; };
@@ -165,9 +166,12 @@ impl UartMultiplexer {
#[embassy_executor::main] #[embassy_executor::main]
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
async fn main(spawner: Spawner) -> ! { async fn main(spawner: Spawner) -> ! {
let mut dp = PsPeripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);
// Enable PS-PL level shifters. // Enable PS-PL level shifters.
configure_level_shifter(LevelShifterConfig::EnableAll); configure_level_shifter(LevelShifterConfig::EnableAll);
let dp = PsPeripherals::take().unwrap();
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller. // Set up the global interrupt controller.

View File

@@ -16,6 +16,7 @@ use zynq7000_hal::{
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{GpioPins, Output, PinState}, gpio::{GpioPins, Output, PinState},
gtc::Gtc, gtc::Gtc,
l2_cache,
uart::{ClkConfigRaw, Uart, UartConfig}, uart::{ClkConfigRaw, Uart, UartConfig},
}; };
@@ -36,9 +37,12 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! {
#[embassy_executor::main] #[embassy_executor::main]
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! { async fn main(_spawner: Spawner) -> ! {
let mut dp = PsPeripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);
// Enable PS-PL level shifters. // Enable PS-PL level shifters.
configure_level_shifter(LevelShifterConfig::EnableAll); configure_level_shifter(LevelShifterConfig::EnableAll);
let dp = PsPeripherals::take().unwrap();
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller. // Set up the global interrupt controller.

View File

@@ -29,7 +29,7 @@ pub fn clean_and_invalidate_data_cache() {
// Clean all ways in L2 cache. // Clean all ways in L2 cache.
let mut l2c = unsafe { L2Cache::new_mmio_fixed() }; let mut l2c = unsafe { L2Cache::new_mmio_fixed() };
l2c.write_clean_invalidate_by_way(0xff); l2c.write_clean_invalidate_by_way(0xffff);
while l2c.read_cache_sync().busy() {} while l2c.read_cache_sync().busy() {}
compiler_fence(core::sync::atomic::Ordering::SeqCst); compiler_fence(core::sync::atomic::Ordering::SeqCst);

View File

@@ -0,0 +1,81 @@
use core::sync::atomic::compiler_fence;
use arbitrary_int::{u2, u3};
pub use zynq7000::l2_cache::LatencyConfig;
use zynq7000::l2_cache::{
Associativity, AuxControl, Control, InterruptControl, MmioL2Cache, ReplacementPolicy, WaySize,
};
use crate::slcr::Slcr;
/// This is the default configuration used by Xilinx/AMD.
pub const AUX_CTRL_DEFAULT: AuxControl = AuxControl::builder()
.with_early_bresp_enable(true)
.with_isntruction_prefetch_enable(true)
.with_data_prefetch_enable(true)
.with_nonsec_interrupt_access_control(false)
.with_nonsec_lockdown_enable(false)
.with_cache_replace_policy(ReplacementPolicy::RoundRobin)
.with_force_write_alloc(u2::new(0))
.with_shared_attr_override(false)
.with_parity_enable(true)
.with_event_monitor_bus_enable(true)
.with_way_size(WaySize::_64kB)
.with_associativity(Associativity::_8Way)
.with_shared_attribute_invalidate(false)
.with_exclusive_cache_config(false)
.with_store_buff_device_limitation_enable(false)
.with_high_priority_so_dev_reads(false)
.with_full_line_zero_enable(false)
.build();
/// Xilinx/AMD default configuration. 2 cycles for setup, write and read.
pub const DEFAULT_TAG_RAM_LATENCY: LatencyConfig = LatencyConfig::builder()
.with_write_access_latency(u3::new(0b001))
.with_read_access_latency(u3::new(0b001))
.with_setup_latency(u3::new(0b001))
.build();
/// Xilinx/AMD default configuration. 2 cycles for setup and write, 3 cycles for read.
pub const DEFAULT_DATA_RAM_LATENCY: LatencyConfig = LatencyConfig::builder()
.with_write_access_latency(u3::new(0b001))
.with_read_access_latency(u3::new(0b010))
.with_setup_latency(u3::new(0b001))
.build();
// SLCR L2C ram configuration.
pub const SLCR_L2C_CONFIG_MAGIC_VALUE: u32 = 0x00020202;
/// Similar to [init], but uses Xilinx/AMD defaults for the latency configurations.
pub fn init_with_defaults(l2c_mmio: &mut MmioL2Cache<'static>) {
init(l2c_mmio, DEFAULT_TAG_RAM_LATENCY, DEFAULT_DATA_RAM_LATENCY);
}
/// Generic intializer function for the L2 cache.
///
/// This function is based on the initialization sequence specified in the TRM p.94 and on
/// the runtime initialization provided by Xilinx/AMD.
pub fn init(
l2c_mmio: &mut MmioL2Cache<'static>,
tag_ram_latency: LatencyConfig,
data_ram_latency: LatencyConfig,
) {
l2c_mmio.write_control(Control::new_disabled());
l2c_mmio.write_aux_control(AUX_CTRL_DEFAULT);
l2c_mmio.write_tag_ram_latency(tag_ram_latency);
l2c_mmio.write_data_ram_latency(data_ram_latency);
// Invalidate the whole cache.
l2c_mmio.write_clean_invalidate_by_way(0xffff);
while l2c_mmio.read_cache_sync().busy() {}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let pending = l2c_mmio.read_interrupt_raw_status();
l2c_mmio.write_interrupt_clear(InterruptControl::new_with_raw_value(pending.raw_value()));
unsafe {
Slcr::with(|slcr| {
slcr.write_magic_l2c_register(SLCR_L2C_CONFIG_MAGIC_VALUE);
});
}
l2c_mmio.write_control(Control::new_enabled());
}

View File

@@ -19,6 +19,7 @@ pub mod gic;
pub mod gpio; pub mod gpio;
pub mod gtc; pub mod gtc;
pub mod i2c; pub mod i2c;
pub mod l2_cache;
pub mod log; pub mod log;
pub mod prelude; pub mod prelude;
pub mod slcr; pub mod slcr;

View File

@@ -1,8 +1,10 @@
//! Start-up code for Zynq 7000 //! Start-up code for Zynq 7000
//! //!
//! The bootup routine was kepts as similar to the one //! The bootup routine was is based on the one
//! [provided by Xilinx](https://github.com/Xilinx/embeddedsw/blob/master/lib/bsp/standalone/src/arm/cortexa9/gcc/boot.S) //! [provided by Xilinx](https://github.com/Xilinx/embeddedsw/blob/master/lib/bsp/standalone/src/arm/cortexa9/gcc/boot.S)
//! as possible. The boot routine includes stack, MMU, cache and .bss/.data section initialization. //! but does NOT provide the L2 cache initialization.
//!
//! The boot routine includes stack, MMU and .bss/.data section initialization.
use cortex_a_rt as _; use cortex_a_rt as _;
use cortex_ar::register::{Cpsr, cpsr::ProcessorMode}; use cortex_ar::register::{Cpsr, cpsr::ProcessorMode};
@@ -196,61 +198,6 @@ initialize:
orr r0, r0, #(0x01 ) /* Cache/TLB maintenance broadcast */ orr r0, r0, #(0x01 ) /* Cache/TLB maintenance broadcast */
mcr p15, 0, r0, c1, c0, 1 /* Write ACTLR*/ mcr p15, 0, r0, c1, c0, 1 /* Write ACTLR*/
/* Invalidate L2 Cache and enable L2 Cache*/
/* For AMP, assume running on CPU1. Don't initialize L2 Cache (up to Linux) */
ldr r0,=L2CCCrtl /* Load L2CC base address base + control register */
mov r1, #0 /* force the disable bit */
str r1, [r0] /* disable the L2 Caches */
ldr r0,=L2CCAuxCrtl /* Load L2CC base address base + Aux control register */
ldr r1,[r0] /* read the register */
ldr r2,=L2CCAuxControl /* set the default bits */
orr r1,r1,r2
str r1, [r0] /* store the Aux Control Register */
ldr r0,=L2CCTAGLatReg /* Load L2CC base address base + TAG Latency address */
ldr r1,=L2CCTAGLatency /* set the latencies for the TAG*/
str r1, [r0] /* store the TAG Latency register Register */
ldr r0,=L2CCDataLatReg /* Load L2CC base address base + Data Latency address */
ldr r1,=L2CCDataLatency /* set the latencies for the Data*/
str r1, [r0] /* store the Data Latency register Register */
ldr r0,=L2CCWay /* Load L2CC base address base + way register*/
ldr r2, =0xFFFF
str r2, [r0] /* force invalidate */
ldr r0,=L2CCSync /* need to poll 0x730, PSS_L2CC_CACHE_SYNC_OFFSET */
/* Load L2CC base address base + sync register*/
/* poll for completion */
Sync:
ldr r1, [r0]
cmp r1, #0
bne Sync
ldr r0,=L2CCIntRaw /* clear pending interrupts */
ldr r1,[r0]
ldr r0,=L2CCIntClear
str r1,[r0]
ldr r0,=SLCRUnlockReg /* Load SLCR base address base + unlock register */
ldr r1,=SLCRUnlockKey /* set unlock key */
str r1, [r0] /* Unlock SLCR */
ldr r0,=SLCRL2cRamReg /* Load SLCR base address base + l2c Ram Control register */
ldr r1,=SLCRL2cRamConfig /* set the configuration value */
str r1, [r0] /* store the L2c Ram Control Register */
ldr r0,=SLCRlockReg /* Load SLCR base address base + lock register */
ldr r1,=SLCRlockKey /* set lock key */
str r1, [r0] /* lock SLCR */
ldr r0,=L2CCCrtl /* Load L2CC base address base + control register */
ldr r1,[r0] /* read the register */
mov r2, #L2CCControl /* set the enable bit */
orr r1,r1,r2
str r1, [r0] /* enable the L2 Caches */
mov r0, r0 mov r0, r0
mrc p15, 0, r1, c1, c0, 2 /* read cp access control register (CACR) into r1 */ mrc p15, 0, r1, c1, c0, 2 /* read cp access control register (CACR) into r1 */
orr r1, r1, #(0xf << 20) /* enable full access for p10 & p11 */ orr r1, r1, #(0xf << 20) /* enable full access for p10 & p11 */

View File

@@ -1,4 +1,4 @@
use arbitrary_int::{u4, u6}; use arbitrary_int::{u2, u3, u4, u6};
pub const L2C_BASE_ADDR: usize = 0xF8F0_2000; pub const L2C_BASE_ADDR: usize = 0xF8F0_2000;
@@ -40,6 +40,153 @@ pub struct CacheId {
rtl_release: u6, 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)]
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)]
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)]
#[derive(Debug, 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)]
#[derive(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,
}
#[derive(derive_mmio::Mmio)] #[derive(derive_mmio::Mmio)]
#[repr(C)] #[repr(C)]
pub struct L2Cache { pub struct L2Cache {
@@ -50,10 +197,10 @@ pub struct L2Cache {
_reserved: [u32; 0x3E], _reserved: [u32; 0x3E],
control: u32, control: Control,
aux_control: u32, aux_control: AuxControl,
tag_ram_control: u32, tag_ram_latency: LatencyConfig,
data_ram_control: u32, data_ram_latency: LatencyConfig,
_reserved2: [u32; 0x3C], _reserved2: [u32; 0x3C],
@@ -64,11 +211,11 @@ pub struct L2Cache {
event_counter_0: u32, event_counter_0: u32,
interrupt_mask: u32, interrupt_mask: u32,
#[mmio(PureRead)] #[mmio(PureRead)]
interrupt_mask_status: u32, interrupt_mask_status: InterruptStatus,
#[mmio(PureRead)] #[mmio(PureRead)]
interrupt_raw_status: u32, interrupt_raw_status: InterruptStatus,
#[mmio(Write)] #[mmio(Write)]
interrupt_clear: u32, interrupt_clear: InterruptControl,
_reserved3: [u32; 0x143], _reserved3: [u32; 0x143],

View File

@@ -39,6 +39,7 @@ static PERIPHERALS_TAKEN: AtomicBool = AtomicBool::new(false);
pub struct PsPeripherals { pub struct PsPeripherals {
pub gicc: gic::MmioGicc<'static>, pub gicc: gic::MmioGicc<'static>,
pub gicd: gic::MmioGicd<'static>, pub gicd: gic::MmioGicd<'static>,
pub l2c: l2_cache::MmioL2Cache<'static>,
pub uart_0: uart::MmioUart<'static>, pub uart_0: uart::MmioUart<'static>,
pub uart_1: uart::MmioUart<'static>, pub uart_1: uart::MmioUart<'static>,
pub spi_0: spi::MmioSpi<'static>, pub spi_0: spi::MmioSpi<'static>,
@@ -74,6 +75,7 @@ impl PsPeripherals {
Self { Self {
gicc: gic::Gicc::new_mmio_fixed(), gicc: gic::Gicc::new_mmio_fixed(),
gicd: gic::Gicd::new_mmio_fixed(), gicd: gic::Gicd::new_mmio_fixed(),
l2c: l2_cache::L2Cache::new_mmio_fixed(),
uart_0: uart::Uart::new_mmio_fixed_0(), uart_0: uart::Uart::new_mmio_fixed_0(),
uart_1: uart::Uart::new_mmio_fixed_1(), uart_1: uart::Uart::new_mmio_fixed_1(),
gtc: gtc::Gtc::new_mmio_fixed(), gtc: gtc::Gtc::new_mmio_fixed(),