diff --git a/firmware/examples/zedboard/Cargo.toml b/firmware/examples/zedboard/Cargo.toml index ff02140..650c039 100644 --- a/firmware/examples/zedboard/Cargo.toml +++ b/firmware/examples/zedboard/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"] categories = ["embedded", "no-std", "hardware-support"] [dependencies] -aarch32-cpu = { version = "0.2" } +aarch32-cpu = { version = "0.2", features = ["critical-section-single-core"] } zynq7000-rt = { path = "../../zynq7000-rt" } zynq7000 = { path = "../../zynq7000" } zynq7000-hal = { path = "../../zynq7000-hal" } diff --git a/firmware/zedboard-bsp/CHANGELOG.md b/firmware/zedboard-bsp/CHANGELOG.md index 7d42edb..313472a 100644 --- a/firmware/zedboard-bsp/CHANGELOG.md +++ b/firmware/zedboard-bsp/CHANGELOG.md @@ -17,6 +17,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - QSPI constructor can now optionally clear block protection and set latency configuration. +## Changed + +- Alignment rules of Spansion QSPI page program now only require 4 byte aligned size. + # [v0.1.0] Initial release diff --git a/firmware/zedboard-bsp/src/qspi_spansion.rs b/firmware/zedboard-bsp/src/qspi_spansion.rs index 3858c6f..90ea149 100644 --- a/firmware/zedboard-bsp/src/qspi_spansion.rs +++ b/firmware/zedboard-bsp/src/qspi_spansion.rs @@ -226,7 +226,7 @@ pub enum ProgramPageError { Addr(#[from] AddrError), #[error("program data is larger than page size {PAGE_SIZE}")] DataTooLarge, - #[error("program data is not aligned to 16 bytes")] + #[error("program data is not aligned to 4 bytes")] NotAligned, #[error("program data crosses page boundary")] CrossesPageBoundary, @@ -519,7 +519,7 @@ impl QspiSpansionS25Fl256SIoMode { /// This function will block until the operation has completed. /// /// The data length may not exceed [MAX_DATA_BYTES_PER_WRITE]. Furthermore, the data needs - /// to be aligned to 16 bytes and the programming operation is not allowed to cross a page. + /// to be aligned to 4 bytes and the programming operation is not allowed to cross a page. /// boundary. It is recommended to program in 128 byte chunks. pub fn program(&mut self, addr: u32, data: &[u8]) -> Result<(), ProgramPageError> { if addr + data.len() as u32 > u24::MAX.as_u32() { @@ -528,7 +528,7 @@ impl QspiSpansionS25Fl256SIoMode { if data.len() > MAX_DATA_BYTES_PER_WRITE { return Err(ProgramPageError::DataTooLarge); } - if !data.len().is_multiple_of(16) { + if !data.len().is_multiple_of(4) { return Err(ProgramPageError::NotAligned); } if (addr as usize % PAGE_SIZE) + data.len() > PAGE_SIZE { diff --git a/firmware/zedboard-fsbl/src/main.rs b/firmware/zedboard-fsbl/src/main.rs index 30cb760..4666654 100644 --- a/firmware/zedboard-fsbl/src/main.rs +++ b/firmware/zedboard-fsbl/src/main.rs @@ -24,7 +24,7 @@ use zynq7000_hal::{ pll::{PllConfig, configure_arm_pll, configure_io_pll}, }, ddr::{DdrClockSetupConfig, configure_ddr_for_ddr3, memtest}, - devcfg, gic, gpio, l2_cache, + gic, gpio, l2_cache, prelude::*, qspi::{self, QSPI_START_ADDRESS}, time::Hertz, @@ -264,7 +264,7 @@ fn qspi_boot(mut qspi: QspiSpansionS25Fl256SLinearMode, _priv_tim: priv_tim::Cpu }; // The DMA will read from the linear mapped QSPI directly, so it // has to be configured for reads using the guard! - devcfg::configure_bitstream_non_secure(true, boot_bin_slice) + zynq7000_hal::pl::configure_bitstream_non_secure(true, boot_bin_slice) .expect("unexpected unaligned address"); log::info!("loaded bitstream successfully"); } @@ -312,6 +312,8 @@ fn qspi_boot(mut qspi: QspiSpansionS25Fl256SLinearMode, _priv_tim: priv_tim::Cpu } } + zynq7000_hal::pl::deassert_reset(); + match opt_jump_addr { Some(jump_addr) => { log::info!("jumping to address {}", jump_addr); diff --git a/firmware/zynq7000-hal/CHANGELOG.md b/firmware/zynq7000-hal/CHANGELOG.md index dbb0cdb..4bf7da2 100644 --- a/firmware/zynq7000-hal/CHANGELOG.md +++ b/firmware/zynq7000-hal/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Changed +- `devcfg` moved to `pl` module - Added division by zero check in gtc frequency_to_ticks to avoid runtime panic - Increased UART type safety by providing dedicated MIO constructors for UART 0 and UART 1 respectively. @@ -17,6 +18,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). completely overwritten instead of only modifying their own bit portions. Also allow targeting interrupts without clearing other CPU target. +## Added + +Method to de-assert PL reset. + # [v0.1.1] 2025-10-10 Documentation fixes. diff --git a/firmware/zynq7000-hal/src/lib.rs b/firmware/zynq7000-hal/src/lib.rs index 756b9df..9376049 100644 --- a/firmware/zynq7000-hal/src/lib.rs +++ b/firmware/zynq7000-hal/src/lib.rs @@ -27,7 +27,6 @@ use zynq7000::{ pub mod cache; pub mod clocks; pub mod ddr; -pub mod devcfg; pub mod eth; pub mod gic; pub mod gpio; @@ -35,6 +34,7 @@ pub mod gtc; pub mod i2c; pub mod l2_cache; pub mod log; +pub mod pl; pub mod prelude; pub mod priv_tim; pub mod qspi; diff --git a/firmware/zynq7000-hal/src/devcfg.rs b/firmware/zynq7000-hal/src/pl.rs similarity index 71% rename from firmware/zynq7000-hal/src/devcfg.rs rename to firmware/zynq7000-hal/src/pl.rs index 563756c..743506c 100644 --- a/firmware/zynq7000-hal/src/devcfg.rs +++ b/firmware/zynq7000-hal/src/pl.rs @@ -1,4 +1,33 @@ -//! # Device Configuration Module +//! # Programmable Logic (PL) support module. +//! +//! Provides the [configure_bitstream_non_secure] method to program the PL using the device +//! configuration (`devcfg`) peripheral. +use arbitrary_int::{traits::Integer as _, u17}; +use zynq7000::slcr::reset::FpgaResetControl; + +use crate::slcr::Slcr; + +/// Put the PL out of reset. +/// +/// The PL is in reset state after power-up. This method should be called in the first-stage +/// bootloader to put it out of reset. +pub fn deassert_reset() { + // Safety: We only touch the PL reset register here. + unsafe { + Slcr::with(|slcr| { + slcr.reset_ctrl().write_fpga( + FpgaResetControl::builder() + .with_zero_block_0(u17::ZERO) + .with_fpga_3(false) + .with_fpga_2(false) + .with_fpga_1(false) + .with_fpga_0(false) + .build(), + ); + }) + }; +} + #[derive(Debug, thiserror::Error)] #[error("unaligned address: {0}")] pub struct UnalignedAddrError(usize); diff --git a/firmware/zynq7000/src/slcr/reset.rs b/firmware/zynq7000/src/slcr/reset.rs index c9f0d17..3368e55 100644 --- a/firmware/zynq7000/src/slcr/reset.rs +++ b/firmware/zynq7000/src/slcr/reset.rs @@ -77,7 +77,7 @@ pub struct ResetControlQspiSmc { #[bitbybit::bitfield(u32, default = 0x0, debug)] pub struct FpgaResetControl { /// This block always needs to be written with 0. I think it contains some other hidden - /// reset lines. + /// reset lines. This field makes this explicit. #[bits(8..=24, rw)] zero_block_0: u17, #[bit(3, rw)] diff --git a/justfile b/justfile index 88e784d..3528436 100644 --- a/justfile +++ b/justfile @@ -60,4 +60,4 @@ run binary: flash-nor-zedboard boot_binary: cd {{justfile_directory()}}/firmware/zedboard-qspi-flasher && cargo build --release - xsct firmware/zedboard-qspi-flasher/qspi-flasher.tcl scripts/ps7_init.tcl -b {{boot_binary}} + xsct firmware/zedboard-qspi-flasher/qspi-flasher.tcl scripts/ps7_init.tcl -b {{invocation_directory()}}/{{boot_binary}}