diff --git a/examples/embassy/Cargo.toml b/examples/embassy/Cargo.toml index c17151b..b2aaa27 100644 --- a/examples/embassy/Cargo.toml +++ b/examples/embassy/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"] categories = ["embedded", "no-std", "hardware-support"] [dependencies] -cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", rev = "79dba7000d2090d13823bfb783d9d64be8b778d2", features = ["critical-section-single-core"] } +cortex-ar = "0.3" zynq7000-rt = { path = "../../zynq7000-rt" } zynq7000 = { path = "../../zynq7000" } zynq7000-hal = { path = "../../zynq7000-hal" } @@ -20,7 +20,7 @@ dht-sensor = { git = "https://github.com/michaelbeaumont/dht-sensor.git", rev = static_cell = "2" critical-section = "1" heapless = "0.9" -embedded-io = "0.6" +embedded-io = "0.7" embedded-hal = "1" fugit = "0.3" log = "0.4" diff --git a/examples/embassy/src/main.rs b/examples/embassy/src/main.rs index afbdfe4..1047373 100644 --- a/examples/embassy/src/main.rs +++ b/examples/embassy/src/main.rs @@ -8,7 +8,7 @@ use embassy_time::{Duration, Ticker}; use embedded_hal::digital::StatefulOutputPin; use embedded_io::Write; use log::{error, info}; -use zynq7000_hal::{clocks, gic, gpio, gtc, time::Hertz, uart, BootMode, InteruptConfig}; +use zynq7000_hal::{BootMode, InteruptConfig, clocks, gic, gpio, gtc, time::Hertz, uart}; use zynq7000_rt as _; diff --git a/examples/simple/Cargo.toml b/examples/simple/Cargo.toml index 64354b6..fdec76d 100644 --- a/examples/simple/Cargo.toml +++ b/examples/simple/Cargo.toml @@ -9,11 +9,11 @@ repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" license = "MIT OR Apache-2.0" [dependencies] -cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", rev = "79dba7000d2090d13823bfb783d9d64be8b778d2", features = ["critical-section-single-core"] } +cortex-ar = "0.3" zynq7000-rt = { path = "../../zynq7000-rt" } zynq7000 = { path = "../../zynq7000" } zynq7000-hal = { path = "../../zynq7000-hal" } -embedded-io = "0.6" +embedded-io = "0.7" embedded-hal = "1" fugit = "0.3" log = "0.4" diff --git a/examples/zedboard/Cargo.toml b/examples/zedboard/Cargo.toml index 279562c..34cd460 100644 --- a/examples/zedboard/Cargo.toml +++ b/examples/zedboard/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"] categories = ["embedded", "no-std", "hardware-support"] [dependencies] -cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", rev = "79dba7000d2090d13823bfb783d9d64be8b778d2", features = ["critical-section-single-core"] } +cortex-ar = "0.3" zynq7000-rt = { path = "../../zynq7000-rt" } zynq7000 = { path = "../../zynq7000" } zynq7000-hal = { path = "../../zynq7000-hal" } @@ -19,7 +19,7 @@ zynq7000-embassy = { path = "../../zynq7000-embassy" } zedboard-bsp = { path = "../../zedboard-bsp" } num_enum = { version = "0.7", default-features = false } l3gd20 = { git = "https://github.com/us-irs/l3gd20.git", branch = "add-async-if" } -embedded-io = "0.6" +embedded-io = "0.7" bitbybit = "1.4" arbitrary-int = "2" embedded-io-async = "0.6" diff --git a/examples/zedboard/src/bin/qspi.rs b/examples/zedboard/src/bin/qspi.rs index 7c1e30f..89fd2e8 100644 --- a/examples/zedboard/src/bin/qspi.rs +++ b/examples/zedboard/src/bin/qspi.rs @@ -10,7 +10,7 @@ use embedded_io::Write; use log::{error, info}; use zedboard::PS_CLOCK_FREQUENCY; use zedboard_bsp::qspi_spansion; -use zynq7000_hal::{clocks, gic, gpio, gtc, prelude::*, qspi, uart, BootMode}; +use zynq7000_hal::{BootMode, clocks, gic, gpio, gtc, prelude::*, qspi, uart}; use zynq7000_rt as _; diff --git a/examples/zedboard/src/main.rs b/examples/zedboard/src/main.rs index b08c435..59c4962 100644 --- a/examples/zedboard/src/main.rs +++ b/examples/zedboard/src/main.rs @@ -9,7 +9,7 @@ use embedded_hal::digital::StatefulOutputPin; use embedded_io::Write; use log::{error, info}; use zedboard::PS_CLOCK_FREQUENCY; -use zynq7000_hal::{clocks, gic, gpio, gtc, uart, BootMode}; +use zynq7000_hal::{BootMode, clocks, gic, gpio, gtc, uart}; use zynq7000_rt as _; diff --git a/zedboard-bsp/src/qspi_spansion.rs b/zedboard-bsp/src/qspi_spansion.rs index 31258d6..9eafd3b 100644 --- a/zedboard-bsp/src/qspi_spansion.rs +++ b/zedboard-bsp/src/qspi_spansion.rs @@ -64,6 +64,8 @@ pub enum SectorArchictecture { Hybrid = 0x01, } +pub const PAGE_SIZE: usize = 256; + #[derive(Debug, Clone, Copy)] pub struct BaseDeviceId { manufacturer_id: u8, @@ -221,6 +223,8 @@ pub enum ProgramPageError { ProgrammingErrorBitSet, #[error("address error: {0}")] Addr(#[from] AddrError), + #[error("data is larger than page size {PAGE_SIZE}")] + DataLargerThanPage, } pub struct QspiSpansionS25Fl256SIoMode(RefCell); @@ -428,14 +432,17 @@ impl QspiSpansionS25Fl256SIoMode { /// This function also takes care of enabling writes before programming the page. /// This function will block until the operation has completed. /// - /// TODO: Allow smaller write size - pub fn program_page(&mut self, addr: u32, data: &[u8; 256]) -> Result<(), ProgramPageError> { + /// The data length max not exceed the page size [PAGE_SIZE]. + pub fn program_page(&mut self, addr: u32, data: &[u8]) -> Result<(), ProgramPageError> { if addr + data.len() as u32 > u24::MAX.as_u32() { return Err(AddrError::OutOfRange.into()); } if !addr.is_multiple_of(0x100) { return Err(AddrError::Alignment.into()); } + if data.len() > PAGE_SIZE { + return Err(ProgramPageError::DataLargerThanPage); + } self.write_enable(); let qspi = self.0.get_mut(); let mut transfer = qspi.transfer_guard(); @@ -448,8 +455,9 @@ impl QspiSpansionS25Fl256SIoMode { transfer.write_word_txd_00(u32::from_ne_bytes(raw_word)); let mut read_index: u32 = 0; let mut current_byte_index = 0; + let fifo_writes = data.len().div_ceil(4); // Fill the FIFO until it is full. - for _ in 0..FIFO_DEPTH - 1 { + for _ in 0..core::cmp::min(fifo_writes, FIFO_DEPTH - 1) { transfer.write_word_txd_00(u32::from_ne_bytes( data[current_byte_index..current_byte_index + 4] .try_into() @@ -470,25 +478,38 @@ impl QspiSpansionS25Fl256SIoMode { } }; - // Immediately fill the FIFO again with the remaining 8 bytes. - wait_for_tx_slot(&mut transfer); + while current_byte_index < data.len() { + // Immediately fill the FIFO again with the remaining 8 bytes. + wait_for_tx_slot(&mut transfer); - transfer.write_word_txd_00(u32::from_ne_bytes( - data[current_byte_index..current_byte_index + 4] - .try_into() - .unwrap(), - )); - current_byte_index += 4; + let word = match core::cmp::min(4, data.len() - current_byte_index) { + 1 => { + let mut bytes = [0; 4]; + bytes[0] = data[current_byte_index]; + u32::from_ne_bytes(bytes) + } + 2 => { + let mut bytes = [0; 4]; + bytes[0..2].copy_from_slice(&data[current_byte_index..current_byte_index + 2]); + u32::from_ne_bytes(bytes) + } + 3 => { + let mut bytes = [0; 4]; + bytes[0..3].copy_from_slice(&data[current_byte_index..current_byte_index + 3]); + u32::from_ne_bytes(bytes) + } + 4 => u32::from_ne_bytes( + data[current_byte_index..current_byte_index + 4] + .try_into() + .unwrap(), + ), + _ => unreachable!(), + }; + transfer.write_word_txd_00(word); + current_byte_index += 4; + } - wait_for_tx_slot(&mut transfer); - - transfer.write_word_txd_00(u32::from_ne_bytes( - data[current_byte_index..current_byte_index + 4] - .try_into() - .unwrap(), - )); - - while read_index < 256 { + while read_index < data.len() as u32 { if transfer.read_status().rx_above_threshold() { transfer.read_rx_data(); read_index = read_index.wrapping_add(4); @@ -528,11 +549,7 @@ impl QspiSpansionS25Fl256SIoMode { if dummy_byte { bytes_to_write += 1; } - let fifo_writes = if bytes_to_write.is_multiple_of(4) { - bytes_to_write / 4 - } else { - (bytes_to_write / 4) + 1 - }; + let fifo_writes = bytes_to_write.div_ceil(4); // Fill the FIFO until it is full or all 0 bytes have been written. for _ in 0..core::cmp::min(fifo_writes, FIFO_DEPTH - 1) { transfer.write_word_txd_00(0); diff --git a/zedboard-fpga-design/README.md b/zedboard-fpga-design/README.md index 2e4d5f6..2533876 100644 --- a/zedboard-fpga-design/README.md +++ b/zedboard-fpga-design/README.md @@ -38,3 +38,25 @@ vivado zedboard-rust.xpr You can perform all the steps specified in the Vivado GUI as well using `Execute TCL script` and `Load Project`. + +# Generating the SDT folder from a hardware description + +You can generate a hardware description by building the block design by using `Generate Bitstream` +inside the Vivado GUI and then exporting the hardware description via +`File -> Export -> Export Hardware`. This allows to generate a `*.xsa` file which describes the +hardware. + +After that, you can generate the SDT output folder which contains various useful files like +the `ps7_init.tcl` script. The provided ` sdtgen.tcl` and `stdgen.py` script simplify this process. + +For example, the following command generates the SDT output folder inside a folder +named `sdt_out` for a hardware description files `zedboard-rust/zedboard-rust.xsa`, +assuming that the Vitis tool suite is installed at `/tools/Xilinx/Vitis/2024.1`: + +```sh +export AMD_TOOLS="/tools/Xilinx/Vitis/2024.1" +./sdtgen.py -x ./zedboard-rust/zedboard-rust.xsa +``` + +Run `stdgen.py -h` for more information and configuration options. The `stdgen.py` is a helper +script which will invoke `sdtgen.tcl` to generate the SDT. diff --git a/zedboard-fsbl/Cargo.toml b/zedboard-fsbl/Cargo.toml index 00a44e2..1f635d6 100644 --- a/zedboard-fsbl/Cargo.toml +++ b/zedboard-fsbl/Cargo.toml @@ -9,13 +9,13 @@ repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" license = "MIT OR Apache-2.0" [dependencies] -cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", rev = "79dba7000d2090d13823bfb783d9d64be8b778d2", features = ["critical-section-single-core"] } +cortex-ar = "0.3" zynq7000-rt = { path = "../zynq7000-rt" } zynq7000 = { path = "../zynq7000" } zynq7000-hal = { path = "../zynq7000-hal" } zedboard-bsp = { path = "../zedboard-bsp" } zynq-boot-image = { path = "../zynq-boot-image" } -embedded-io = "0.6" +embedded-io = "0.7" embedded-hal = "1" fugit = "0.3" log = "0.4" diff --git a/zedboard-fsbl/src/main.rs b/zedboard-fsbl/src/main.rs index a7e1d68..ce9fdad 100644 --- a/zedboard-fsbl/src/main.rs +++ b/zedboard-fsbl/src/main.rs @@ -16,9 +16,9 @@ use zynq7000_hal::{ pll::{PllConfig, configure_arm_pll, configure_io_pll}, }, ddr::{DdrClockSetupConfig, configure_ddr_for_ddr3, memtest}, - gic, gpio, l2_cache, + devcfg, gic, gpio, l2_cache, prelude::*, - qspi, + qspi::{self, QSPI_START_ADDRESS}, time::Hertz, uart::{ClockConfig, Config, Uart}, }; @@ -225,7 +225,19 @@ fn qspi_boot(mut qspi: QspiSpansionS25Fl256SLinearMode) -> ! { match dest_dev { DestinationDevice::Pl => { info!("Loading image '{name}' to PL (FPGA).."); - // TODO: Load the bitstream. + // Load the bitstream directly from linear mapped QSPI memory. + let boot_bin_slice = unsafe { + core::slice::from_raw_parts( + (QSPI_START_ADDRESS + + partition + .data_offset() + .expect("invalid PL partition data offset")) + as *const _, + partition.total_partition_length().unwrap(), + ) + }; + devcfg::configure_bitstream_non_secure(true, boot_bin_slice) + .expect("unexpected unaligned address"); } DestinationDevice::Ps => { // TODO: Load the binary into DDR. Jump at lowest load address after all diff --git a/zedboard-qspi-flasher/Cargo.toml b/zedboard-qspi-flasher/Cargo.toml index 77d7669..aa9a498 100644 --- a/zedboard-qspi-flasher/Cargo.toml +++ b/zedboard-qspi-flasher/Cargo.toml @@ -4,11 +4,12 @@ version = "0.1.0" edition = "2024" [dependencies] -cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", branch = "main" } +cortex-ar = { version = "0.3" } zynq7000-rt = { path = "../zynq7000-rt" } zynq7000 = { path = "../zynq7000" } zynq7000-hal = { path = "../zynq7000-hal" } +zynq-boot-image = { path = "../zynq-boot-image" } zedboard-bsp = { path = "../zedboard-bsp" } -embedded-io = "0.6" +embedded-io = "0.7" embedded-hal = "1" log = "0.4" diff --git a/zedboard-qspi-flasher/build.rs b/zedboard-qspi-flasher/build.rs new file mode 100644 index 0000000..d534cc3 --- /dev/null +++ b/zedboard-qspi-flasher/build.rs @@ -0,0 +1,31 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); +} diff --git a/zedboard-qspi-flasher/memory.x b/zedboard-qspi-flasher/memory.x new file mode 100644 index 0000000..11faa59 --- /dev/null +++ b/zedboard-qspi-flasher/memory.x @@ -0,0 +1,22 @@ +MEMORY +{ + /* Zedboard: 512 MB DDR3. Only use 63 MB for now, should be plenty for a bare-metal app. + Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This is + recommended for something like DMA descriptors. */ + CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M + UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M +} + +REGION_ALIAS("DATA", CODE); + +SECTIONS +{ + /* Uncached memory */ + .uncached (NOLOAD) : ALIGN(4) { + . = ALIGN(4); + _sbss_uncached = .; + *(.uncached .uncached.*); + . = ALIGN(4); + _ebss_uncached = .; + } > UNCACHED +} diff --git a/zedboard-qspi-flasher/qspi-flasher.tcl b/zedboard-qspi-flasher/qspi-flasher.tcl new file mode 100644 index 0000000..6004dd9 --- /dev/null +++ b/zedboard-qspi-flasher/qspi-flasher.tcl @@ -0,0 +1,151 @@ +if {[info exists env(ip_address_hw_server)]} { + set ip $env(ip_address_hw_server) +} else { + set ip "localhost" +} + +# absolute directory that contains *this* script +set script_dir [file dirname [info script]] + +# Defaults +set boot_bin_addr 0x10000000 +set boot_bin_size_addr 0x900000 +set init_tcl "" +set bin "" +set bitstream "" + +# Usage helper +proc usage {} { + puts "Usage: xsct qspi-flasher.tcl \[-b|--bin \]" + puts "Options:" + puts " -b, --bin Path to boot binary to flash" + puts " -h, --help Show this help" +} + +# Compact, robust parser +set expecting "" +set endopts 0 +foreach arg $argv { + # If previous option expects a value, take this arg + if {$expecting ne ""} { + set $expecting $arg + set expecting "" + continue + } + + # Option handling (until we see --) + if {!$endopts && [string match "-*" $arg]} { + if {$arg eq "--"} { set endopts 1; continue } + if {$arg eq "-h" || $arg eq "--help"} { usage; exit 0 } + if {$arg eq "-b" || $arg eq "--bin"} { set expecting app; continue } + puts "error: unknown option: $arg"; usage; exit 1 + } + + # Positional: expect only + if {$init_tcl eq ""} { + set init_tcl $arg + } else { + puts "error: unexpected positional argument: $arg" + usage + exit 1 + } +} + +# Check that QSPI flasher app exists. +set flasher_app [file join $script_dir .. target armv7a-none-eabihf release zedboard-qspi-flasher] +if {![file exists $flasher_app]} { + error "QSPI flasher application not found at path: $flasher_app" +} +set flasher_app [file normalize $flasher_app] + +# Validate required init script +if {$init_tcl eq ""} { + puts "error: missing required first argument pointing to initialization TCL script" + usage + exit 1 +} +if {![file exists $init_tcl]} { + puts "error: the PS init tcl script '$init_tcl' does not exist" + exit 1 +} + +# Resolve app: CLI takes precedence over env(APP) +if {$bin ne ""} { + if {![file exists $bin]} { + puts "error: the boot binary file '$bin' does not exist" + exit 1 + } +} elseif {[info exists env(BOOTBIN)]} { + if {[file exists $env(BOOTBIN)]} { + set bin $env(BOOTBIN) + } else { + puts "warning: BOOTBIN environment variable is set but file does not exist: $env(BOOTBIN)" + } +} + +if {$bin eq ""} { + puts "error: boot.bin binary required as BOOTBIN environment" + usage + exit 1 +} + +# Validate bitstream if provided +if {$bitstream ne "" && ![file exists $bitstream]} { + puts "error: the bitstream file '$bitstream' does not exist" + exit 1 +} + +puts "Hardware server IP address: $ip" +connect -url tcp:$ip:3121 + +set devices [targets] + +set apu_line [string trim [targets -nocase -filter {name =~ "APU"}]] +set arm_core_0_line [string trim [targets -nocase -filter {name =~ "ARM Cortex-A9 MPCore #0"}]] +set fpga_line [string trim [targets -nocase -filter {name =~ "xc7z020"}]] + +set apu_device_num [string index $apu_line 0] +set arm_core_0_num [string index $arm_core_0_line 0] +set fpga_device_num [string index $fpga_line 0] + +puts "Select ps target with number: $apu_device_num" + +# Select the target +target $apu_device_num + +# Resetting the target involved problems when an image is stored on the flash. +# It has turned out that it is not essential to reset the system before loading +# the software components into the device. +puts "Reset target" +# TODO: Make the reset optional/configurable via input argument. +# Reset the target +rst + +puts "Set ps target with device number: $arm_core_0_num" +targets $arm_core_0_num + +puts "Initialize processing system" +# Init processing system +source $init_tcl + +ps7_init +ps7_post_config + +puts "Set arm core 0 target with number: $arm_core_0_num" +target $arm_core_0_num + +puts "Download boot.bin $bin to target DDR at address $boot_bin_addr" +dow -data $bin $boot_bin_addr + +# Write boot.bin binary size to specific address. +set boot_bin_size [file size $bin] +puts "Writing boot.bin size $boot_bin_size to target DDR at address $boot_bin_size_addr" +mwr ${boot_bin_size_addr} ${boot_bin_size} + +puts "Flashing QSPI flasher app" +dow $flasher_app + +puts "Starting QSPI flasher app" +con + +puts "Success" diff --git a/zedboard-qspi-flasher/src/main.rs b/zedboard-qspi-flasher/src/main.rs index e43c3f7..f063de4 100644 --- a/zedboard-qspi-flasher/src/main.rs +++ b/zedboard-qspi-flasher/src/main.rs @@ -7,10 +7,11 @@ use core::panic::PanicInfo; use cortex_ar::asm::nop; use embedded_hal::{delay::DelayNs as _, digital::StatefulOutputPin as _}; use embedded_io::Write as _; -use log::info; +use log::{error, info}; use zedboard_bsp::qspi_spansion; +use zynq_boot_image::BootHeader; use zynq7000_hal::{ - clocks, gpio, prelude::*, priv_tim, qspi, time::Hertz, uart, BootMode, LevelShifterConfig, + BootMode, LevelShifterConfig, clocks, gpio, prelude::*, priv_tim, qspi, time::Hertz, uart, }; use zynq7000_rt as _; @@ -19,6 +20,15 @@ use zynq7000_rt as _; // Not required for the PAC mode, is required for clean delays in HAL mode. const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_333); +// TODO: Make this configurable somehow? +const BOOT_BIN_BASE_ADDR: usize = 0x1000_0000; +const BOOT_BIN_SIZE_ADDR: usize = 0x900_000; + +// Maximum of 16 MB is allowed for now. +const MAX_BOOT_BIN_SIZE: usize = 16 * 1024 * 1024; + +const VERIFY_PROGRAMMING: bool = true; + #[allow(dead_code)] const QSPI_DEV_COMBINATION: qspi::QspiDeviceCombination = qspi::QspiDeviceCombination { vendor: qspi::QspiVendor::WinbondAndSpansion, @@ -75,6 +85,7 @@ pub fn main() -> ! { let boot_mode = BootMode::new_from_regs(); info!("Boot mode: {:?}", boot_mode); + /* let qspi_clock_config = qspi::ClockConfig::calculate_with_loopback(qspi::SrcSelIo::IoPll, &clocks, 100.MHz()) .expect("QSPI clock calculation failed"); @@ -96,7 +107,78 @@ pub fn main() -> ! { let qspi_io_mode = qspi.into_io_mode(false); - let _spansion_qspi = qspi_spansion::QspiSpansionS25Fl256SIoMode::new(qspi_io_mode, true); + let mut spansion_qspi = qspi_spansion::QspiSpansionS25Fl256SIoMode::new(qspi_io_mode, true); + + let mut boot_bin_slice = unsafe { + core::slice::from_raw_parts(BOOT_BIN_BASE_ADDR as *const _, BootHeader::FIXED_SIZED_PART) + }; + // This perform some basic validity checks. + let _boot_header = BootHeader::new(&boot_bin_slice[0..BootHeader::FIXED_SIZED_PART]) + .expect("failed to parse boot header"); + let boot_bin_size = + unsafe { core::ptr::read_volatile(BOOT_BIN_SIZE_ADDR as *const u32) as usize }; + if boot_bin_size == 0 || boot_bin_size > MAX_BOOT_BIN_SIZE { + panic!( + "boot binary size read at address {:#x} is invalid: found {}, must be in range [0, {}]", + BOOT_BIN_SIZE_ADDR, boot_bin_size, MAX_BOOT_BIN_SIZE + ); + } + boot_bin_slice = + unsafe { core::slice::from_raw_parts(BOOT_BIN_BASE_ADDR as *const _, boot_bin_size) }; + info!( + "flashing boot binary with {} bytes to QSPI address 0x0", + boot_bin_size + ); + + let mut current_addr = 0; + let mut read_buf = [0u8; 256]; + while current_addr < boot_bin_size { + if current_addr % 0x10000 == 0 { + info!("Erasing sector at address {:#x}", current_addr); + match spansion_qspi.erase_sector(current_addr as u32) { + Ok(()) => {} + Err(e) => { + error!( + "failed to erase sector at address {:#x}: {:?}", + current_addr, e + ); + panic!("QSPI erase failed"); + } + } + } + let write_size = core::cmp::min(256, boot_bin_size - current_addr); + let write_slice = &boot_bin_slice[current_addr..current_addr + write_size]; + info!("Programming address {:#x}", current_addr); + match spansion_qspi.program_page(current_addr as u32, write_slice) { + Ok(()) => {} + Err(e) => { + error!( + "failed to write data to QSPI at address {:#x}: {:?}", + current_addr, e + ); + panic!("QSPI write failed"); + } + } + if VERIFY_PROGRAMMING { + spansion_qspi.read_page_fast_read( + current_addr as u32, + &mut read_buf[0..write_size], + true, + ); + if &read_buf[0..write_size] != write_slice { + error!( + "data verification failed at address {:#x}: wrote {:x?}, read {:x?}", + current_addr, + &write_slice[0..core::cmp::min(16, write_size)], + &read_buf[0..core::cmp::min(16, write_size)] + ); + panic!("QSPI data verification failed"); + } + } + current_addr += write_size; + } + info!("flashing done"); + */ let mut mio_led = gpio::Output::new_for_mio(gpio_pins.mio.mio7, gpio::PinState::Low); loop { diff --git a/zynq-mmu/Cargo.toml b/zynq-mmu/Cargo.toml index 7bf07b0..785bf7a 100644 --- a/zynq-mmu/Cargo.toml +++ b/zynq-mmu/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] thiserror = { version = "2", default-features = false } -cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", branch = "bump-arbitrary-int" } +cortex-ar = { version = "0.3" } [features] tools = [] diff --git a/zynq7000-hal/Cargo.toml b/zynq7000-hal/Cargo.toml index 8e8e74d..6ffc9a4 100644 --- a/zynq7000-hal/Cargo.toml +++ b/zynq7000-hal/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["no-std", "hal", "amd", "zynq7000", "xilinx", "bare-metal"] categories = ["embedded", "no-std", "hardware-support"] [dependencies] -cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", branch = "bump-arbitrary-int" } +cortex-ar = { version = "0.3" } zynq7000 = { path = "../zynq7000" } zynq-mmu = { path = "../zynq-mmu", version = "0.1.0" } @@ -22,7 +22,7 @@ thiserror = { version = "2", default-features = false } num_enum = { version = "0.7", default-features = false } ringbuf = { version = "0.4.8", default-features = false } embedded-hal-nb = "1" -embedded-io = "0.6" +embedded-io = "0.7" embedded-hal = "1" embedded-hal-async = "1" heapless = "0.9" @@ -39,7 +39,7 @@ embassy-net-driver = "0.2" smoltcp = { version = "0.12", default-features = false, features = ["proto-ipv4", "medium-ethernet", "socket-raw"] } vcell = "0.1" raw-slicee = "0.1" -embedded-io-async = "0.6" +embedded-io-async = "0.7" [features] std = ["thiserror/std", "alloc"] diff --git a/zynq7000-hal/src/lib.rs b/zynq7000-hal/src/lib.rs index c04ea6e..56390bf 100644 --- a/zynq7000-hal/src/lib.rs +++ b/zynq7000-hal/src/lib.rs @@ -14,8 +14,8 @@ extern crate alloc; use slcr::Slcr; use zynq7000::{ - slcr::{BootModeRegister, BootPllConfig, LevelShifterRegister}, SpiClockPhase, SpiClockPolarity, + slcr::{BootModeRegister, BootPllConfig, LevelShifterRegister}, }; pub mod cache; diff --git a/zynq7000-hal/src/uart/tx_async.rs b/zynq7000-hal/src/uart/tx_async.rs index f349e71..3033123 100644 --- a/zynq7000-hal/src/uart/tx_async.rs +++ b/zynq7000-hal/src/uart/tx_async.rs @@ -202,4 +202,9 @@ impl embedded_io_async::Write for TxAsync { async fn write(&mut self, buf: &[u8]) -> Result { Ok(self.write(buf).await) } + + /// This implementation does not do anything. + async fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } } diff --git a/zynq7000-rt/Cargo.toml b/zynq7000-rt/Cargo.toml index fd2df97..2e2f73c 100644 --- a/zynq7000-rt/Cargo.toml +++ b/zynq7000-rt/Cargo.toml @@ -12,7 +12,7 @@ categories = ["embedded", "no-std", "hardware-support"] [dependencies] cortex-a-rt = { version = "0.1", optional = true, features = ["vfp-dp"] } -cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", branch = "bump-arbitrary-int" } +cortex-ar = { version = "0.3" } arbitrary-int = "2" zynq-mmu = { path = "../zynq-mmu", version = "0.1.0" }