Add PL reset de-assert in FSBL #60

Merged
muellerr merged 1 commits from add-pl-deassert-in-fsbl into main 2026-03-31 18:29:06 +02:00
9 changed files with 50 additions and 10 deletions
+1 -1
View File
@@ -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" }
+4
View File
@@ -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
+3 -3
View File
@@ -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 {
+4 -2
View File
@@ -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);
+5
View File
@@ -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.
+1 -1
View File
@@ -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;
@@ -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);
+1 -1
View File
@@ -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)]
+1 -1
View File
@@ -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}}