Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2267dd0bab | |||
| fbf741e589 | |||
| ee41d245c8 | |||
| d32e99f6a5 | |||
| 55c815fa5e |
@@ -10,4 +10,3 @@
|
||||
# running the application. You only need to do this once for unchanged bitstream as long as you
|
||||
# do not reset the whole board.
|
||||
# ZYNQ_BITSTREAM = "/home/$user/$project/$sdt_dir/bitstream.bit"
|
||||
# HW_SERVER_IP = "localhost"
|
||||
|
||||
@@ -11,8 +11,8 @@ jobs:
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: "armv7a-none-eabihf"
|
||||
- run: just check-dir firmware
|
||||
- run: just check-dir host
|
||||
- run: just check firmware
|
||||
- run: just check host
|
||||
|
||||
build:
|
||||
name: Check build
|
||||
@@ -24,8 +24,8 @@ jobs:
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: "armv7a-none-eabihf"
|
||||
- run: just build-zynq
|
||||
- run: just build-dir host
|
||||
- run: just check firmware
|
||||
- run: just check host
|
||||
|
||||
fmt:
|
||||
name: Check formatting
|
||||
@@ -37,8 +37,8 @@ jobs:
|
||||
with:
|
||||
components: rustfmt
|
||||
targets: "armv7a-none-eabihf"
|
||||
- run: just check-fmt-dir firmware
|
||||
- run: just check-fmt-dir host
|
||||
- run: just check-fmt firmware
|
||||
- run: just check-fmt host
|
||||
|
||||
docs:
|
||||
name: Check Documentation Build
|
||||
@@ -62,9 +62,9 @@ jobs:
|
||||
with:
|
||||
components: clippy, rust-src
|
||||
targets: "armv7a-none-eabihf"
|
||||
- run: just clippy-dir firmware
|
||||
- run: just clippy firmware
|
||||
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy
|
||||
- run: just clippy-dir host
|
||||
- run: just clippy host
|
||||
|
||||
@@ -8,47 +8,48 @@ family of SoCs.
|
||||
|
||||
This project contains the following crates:
|
||||
|
||||
## [Firmware Workspace](./firmware)
|
||||
## [Firmware Workspace](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware)
|
||||
|
||||
This workspace contains libraries and application which can only be run on the target system.
|
||||
|
||||
- The [`zynq7000-rt`](./firmware/zynq7000-rt)
|
||||
- The [`zynq7000-rt`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zynq7000-rt)
|
||||
run-time crate containing basic low-level startup code necessary to boot a Rust app on the
|
||||
Zynq7000.
|
||||
- The [`zynq7000`](./firmware/zynq7000) PAC crate containing basic low-level register access API.
|
||||
- The [`zynq7000-mmu`](./firmware/zynq7000-mmu)
|
||||
- The [`zynq7000`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zynq7000) PAC
|
||||
crate containing basic low-level register definitions.
|
||||
- The [`zynq7000-mmu`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zynq7000-hal)
|
||||
crate containing common MMU abstractions used by both the HAL and the run-time crate.
|
||||
- The [`zynq7000-hal`](./firmware/zynq7000-hal) HAL crate containing higher-level abstractions on
|
||||
top of the PAC register crate.
|
||||
- The [`zynq7000-embassy`](./firmware/zynq7000-embassy) crate containing an embassy-rs time driver
|
||||
using the global timer counter peripheral.
|
||||
- The [`zynq7000-hal`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zynq7000-hal)
|
||||
HAL crate containing higher-level abstractions on top of the PAC register crate.
|
||||
- The [`zynq7000-embassy`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zynq7000-embassy)
|
||||
crate containing support for running the embassy-rs asynchronous run-time.
|
||||
|
||||
This project was developed using a Zedboard, so there are several crates available targeted towards
|
||||
this board:
|
||||
|
||||
- The [`zedboard-bsp`](./firmware/zedboard-bsp)
|
||||
- The [`zedboard-bsp`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zedboard-bsp)
|
||||
crate containing board specific components for the Zedboard.
|
||||
- The [`zedboard-fsbl`](./firmware/zedboard-fsbl)
|
||||
- The [`zedboard-fsbl`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zedboard-fsbl)
|
||||
contains a simple first-stage bootloader application for the Zedboard.
|
||||
- The [`zedboard-qspi-flasher`](./firmware/zedboard-qspi-flasher)
|
||||
- The [`zedboard-qspi-flasher`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zedboard-qspi-flasher)
|
||||
contains an application which is able to flash a boot binary from DDR to the QSPI.
|
||||
|
||||
It also contains the following helper crates:
|
||||
|
||||
- The [`examples`](./firmware/examples)
|
||||
- The [`examples`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/examples)
|
||||
folder contains various example applications crates using the HAL and the PAC.
|
||||
This folder also contains dedicated example applications using the
|
||||
[`embassy`](https://github.com/embassy-rs/embassy) native Rust RTOS.
|
||||
|
||||
## Other libraries and tools
|
||||
|
||||
- The [`zedboard-fpga-design`](./zedboard-fpga-design)
|
||||
- The [`zedboard-fpga-design`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zedboard-fpga-design)
|
||||
folder contains a sample FPGA design and block design which was used in some of the provided software examples. The project was created with Vivado version 2024.1.
|
||||
The folder contains a README with all the steps required to load this project from a TCL script.
|
||||
- The [`zynq7000-boot-image`](./host/zynq7000-boot-image)
|
||||
- The [`zynq7000-boot-image`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/host/zynq7000-boot-image)
|
||||
library contains generic helpers to interface with the AMD
|
||||
[boot binary](https://docs.amd.com/r/en-US/ug1283-bootgen-user-guide).
|
||||
- The [`zynq7000-ps7init-extract`](./host/zynq7000-ps7init-extract)
|
||||
- The [`tools/zynq7000-ps7init-extract`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/host/zynq7000-ps7init-extract)
|
||||
tool allows extracting configuration from the AMD generated `ps7init.tcl` file which contains
|
||||
static configuration parameters for DDR initialization.
|
||||
|
||||
@@ -156,7 +157,7 @@ Zedboard are configured for JTAG boot.
|
||||
|
||||
You can use the `-tui` argument to also have a terminal UI.
|
||||
This repository provides a `scripts/runner.sh` which performs all the steps specified above.
|
||||
The `.cargo/config.toml.template` script contains the runner and some template environmental
|
||||
The `.cargo/def-config.toml` script contains the runner and some template environmental
|
||||
variables that need to be set for this to work. The command above also loaded the app, but
|
||||
this task can be performed by the `zynq7000-init.py` wrapper as well.
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ rustflags = [
|
||||
# If this is not enabled, debugging / stepping can become problematic.
|
||||
"-Cforce-frame-pointers=yes",
|
||||
# Can be useful for debugging.
|
||||
# "-Clink-args=-Map=app.map"
|
||||
"-Clink-args=-Map=app.map"
|
||||
]
|
||||
|
||||
[build]
|
||||
|
||||
@@ -9,7 +9,7 @@ repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.2" }
|
||||
aarch32-cpu = { version = "0.1", features = ["critical-section-single-core"] }
|
||||
zynq7000-rt = { path = "../../zynq7000-rt" }
|
||||
zynq7000 = { path = "../../zynq7000" }
|
||||
zynq7000-hal = { path = "../../zynq7000-hal", features = ["defmt"] }
|
||||
|
||||
@@ -3,18 +3,13 @@ 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*/
|
||||
/* CODE(rx) : ORIGIN = 0x00100000, LENGTH = 62M */
|
||||
CODE(rx) : ORIGIN = 0x00000000, LENGTH = 192K
|
||||
/* STACK: ORIGIN = 0x3F00000, LENGTH = 1M */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M
|
||||
/*CODE(rx) : ORIGIN = 0x00000000, LENGTH = 192K*/
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
}
|
||||
|
||||
REGION_ALIAS("VECTORS", CODE);
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
/* Use the upper OCM as the stack */
|
||||
REGION_ALIAS("STACKS", OCM_UPPER);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
@@ -45,6 +45,7 @@ fn main() -> ! {
|
||||
let mut led = Output::new_for_mio(mio_pins.mio7, PinState::High);
|
||||
loop {
|
||||
defmt::info!("toggling LED!");
|
||||
zynq7000_hal::cache::clean_and_invalidate_data_cache();
|
||||
led.toggle().unwrap();
|
||||
cpu_tim.delay_ms(1000);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"]
|
||||
categories = ["embedded", "no-std", "hardware-support"]
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.2", features = ["critical-section-single-core"] }
|
||||
aarch32-cpu = { version = "0.1", features = ["critical-section-single-core"] }
|
||||
zynq7000-rt = { path = "../../zynq7000-rt" }
|
||||
zynq7000 = { path = "../../zynq7000" }
|
||||
zynq7000-hal = { path = "../../zynq7000-hal" }
|
||||
@@ -25,8 +25,9 @@ embedded-hal = "1"
|
||||
fugit = "0.3"
|
||||
log = "0.4"
|
||||
|
||||
embassy-executor = { version = "0.10", features = [
|
||||
"platform-cortex-ar",
|
||||
embassy-executor = { version = "0.9", features = [
|
||||
"arch-cortex-ar",
|
||||
"executor-thread",
|
||||
]}
|
||||
embassy-time = { version = "0.5", features = ["tick-hz-1_000_000"] }
|
||||
# TODO: Remove generic-queue-16 feature as soon as upstream executor is used again.
|
||||
embassy-time = { version = "0.5", features = ["tick-hz-1_000_000", "generic-queue-16"] }
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 62 MB for now, should be plenty for a bare-metal app.
|
||||
1 MB stack memory and 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 = 62M
|
||||
STACKS : ORIGIN = 0x3F00000, LENGTH = 1M
|
||||
/* 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
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
}
|
||||
|
||||
REGION_ALIAS("VECTORS", CODE);
|
||||
|
||||
@@ -76,7 +76,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
let led = Output::new_for_mio(mio_pins.mio7, PinState::Low);
|
||||
spawner.spawn(led_task(led).unwrap());
|
||||
spawner.spawn(led_task(led)).unwrap();
|
||||
let mut log_buf: [u8; 2048] = [0; 2048];
|
||||
let frame_queue = zynq7000_hal::log::rb::get_frame_queue();
|
||||
loop {
|
||||
|
||||
@@ -9,7 +9,7 @@ repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.2" }
|
||||
aarch32-cpu = { version = "0.1" }
|
||||
zynq7000-rt = { path = "../../zynq7000-rt" }
|
||||
zynq7000 = { path = "../../zynq7000" }
|
||||
zynq7000-hal = { path = "../../zynq7000-hal" }
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 62 MB for now, should be plenty for a bare-metal app.
|
||||
1 MB stack memory and 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 = 62M
|
||||
STACKS : ORIGIN = 0x3F00000, LENGTH = 1M
|
||||
/* 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
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
}
|
||||
|
||||
REGION_ALIAS("VECTORS", CODE);
|
||||
|
||||
@@ -11,7 +11,7 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"]
|
||||
categories = ["embedded", "no-std", "hardware-support"]
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.2", features = ["critical-section-single-core"] }
|
||||
aarch32-cpu = { version = "0.1" }
|
||||
zynq7000-rt = { path = "../../zynq7000-rt" }
|
||||
zynq7000 = { path = "../../zynq7000" }
|
||||
zynq7000-hal = { path = "../../zynq7000-hal" }
|
||||
@@ -20,23 +20,27 @@ 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.7"
|
||||
bitbybit = "2"
|
||||
bitbybit = "1.4"
|
||||
arbitrary-int = "2"
|
||||
embedded-io-async = "0.7"
|
||||
embedded-io-async = "0.6"
|
||||
critical-section = "1"
|
||||
static_cell = "2"
|
||||
embedded-alloc = "0.7"
|
||||
embedded-alloc = "0.6"
|
||||
embedded-hal = "1"
|
||||
embedded-hal-async = "1"
|
||||
fugit = "0.3"
|
||||
log = "0.4"
|
||||
rand = { version = "0.10", default-features = false }
|
||||
rand = { version = "0.9", default-features = false, features = ["small_rng"] }
|
||||
|
||||
embassy-executor = { version = "0.10", features = ["platform-cortex-ar", "executor-thread"] }
|
||||
embassy-time = { version = "0.5", features = ["tick-hz-1_000_000"] }
|
||||
embassy-net = { version = "0.9", features = ["dhcpv4", "packet-trace", "medium-ethernet", "icmp", "tcp", "udp"] }
|
||||
embedded-sdmmc = { git = "https://github.com/robamu/embedded-sdmmc-rs.git", branch = "all-features" }
|
||||
embassy-sync = { version = "0.8" }
|
||||
heapless = "0.9"
|
||||
embassy-executor = { git = "https://github.com/us-irs/embassy.git", branch = "cortex-ar-update", features = [
|
||||
"arch-cortex-ar",
|
||||
"executor-thread",
|
||||
]}
|
||||
# TODO: Remove generic-queue-16 feature as soon as upstream executor is used again.
|
||||
embassy-time = { version = "0.5", features = ["tick-hz-1_000_000", "generic-queue-16"] }
|
||||
embassy-net = { version = "0.7", features = ["dhcpv4", "packet-trace", "medium-ethernet", "icmp", "tcp", "udp"] }
|
||||
embassy-sync = { version = "0.7" }
|
||||
# TODO: Bump as soon as new compatible smoltcp/embassy-net version is released.
|
||||
heapless = "0.8"
|
||||
axi-uartlite = { version = "0.1" }
|
||||
axi-uart16550 = { version = "0.1" }
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 62 MB for now, should be plenty for a bare-metal app.
|
||||
1 MB stack memory and 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 = 62M
|
||||
STACKS : ORIGIN = 0x3F00000, LENGTH = 1M
|
||||
/* 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
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
}
|
||||
|
||||
REGION_ALIAS("VECTORS", CODE);
|
||||
|
||||
@@ -32,7 +32,7 @@ use embassy_time::{Duration, Timer};
|
||||
use embedded_io::Write;
|
||||
use embedded_io_async::Write as _;
|
||||
use log::{LevelFilter, debug, error, info, warn};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand::{RngCore, SeedableRng};
|
||||
use zedboard::PS_CLOCK_FREQUENCY;
|
||||
use zedboard_bsp::phy_marvell;
|
||||
use zynq7000_hal::{
|
||||
@@ -373,9 +373,9 @@ async fn main(spawner: Spawner) -> ! {
|
||||
let tcp_socket = TcpSocket::new(stack, RX_TCP_BUFS.take(), TX_TCP_BUFS.take());
|
||||
|
||||
// Spawn all embassy tasks.
|
||||
spawner.spawn(embassy_net_task(runner).unwrap());
|
||||
spawner.spawn(udp_task(udp_socket).unwrap());
|
||||
spawner.spawn(tcp_task(tcp_socket).unwrap());
|
||||
spawner.spawn(embassy_net_task(runner)).unwrap();
|
||||
spawner.spawn(udp_task(udp_socket)).unwrap();
|
||||
spawner.spawn(tcp_task(tcp_socket)).unwrap();
|
||||
|
||||
let mut mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low);
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
spawner.spawn(logger_task(uart).unwrap());
|
||||
spawner.spawn(logger_task(uart)).unwrap();
|
||||
if BLOCKING {
|
||||
blocking_application(mio_led, emio_leds, spi).await;
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#![no_main]
|
||||
|
||||
use aarch32_cpu::asm::nop;
|
||||
use arbitrary_int::{traits::Integer as _, u2};
|
||||
use core::panic::PanicInfo;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_time::{Duration, Ticker};
|
||||
@@ -15,7 +14,6 @@ use zynq7000_hal::{BootMode, clocks, gic, gpio, gtc, prelude::*, qspi, uart};
|
||||
|
||||
use zynq7000_rt as _;
|
||||
|
||||
const DISPLAY_CLOCK_CONFIG: bool = false;
|
||||
const INIT_STRING: &str = "-- Zynq 7000 Zedboard QSPI example --\n\r";
|
||||
const QSPI_DEV_COMBINATION: qspi::QspiDeviceCombination = qspi::QspiDeviceCombination {
|
||||
vendor: qspi::QspiVendor::WinbondAndSpansion,
|
||||
@@ -30,7 +28,6 @@ fn entry_point() -> ! {
|
||||
}
|
||||
|
||||
const ERASE_PROGRAM_READ_TEST: bool = false;
|
||||
const TEST_QSPI_BASE: u32 = 0x20000;
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
@@ -71,9 +68,6 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
if DISPLAY_CLOCK_CONFIG {
|
||||
log::debug!("clock config: {:?}", clocks);
|
||||
}
|
||||
|
||||
let qspi_clock_config =
|
||||
qspi::ClockConfig::calculate_with_loopback(qspi::SrcSelIo::IoPll, &clocks, 100.MHz())
|
||||
@@ -96,14 +90,7 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
|
||||
let qspi_io_mode = qspi.into_io_mode(false);
|
||||
|
||||
let mut spansion_qspi = qspi_spansion::QspiSpansionS25Fl256SIoMode::new(
|
||||
qspi_io_mode,
|
||||
qspi_spansion::Config {
|
||||
set_quad_bit_if_necessary: true,
|
||||
latency_config: Some(u2::ZERO),
|
||||
clear_write_protection: true,
|
||||
},
|
||||
);
|
||||
let mut spansion_qspi = qspi_spansion::QspiSpansionS25Fl256SIoMode::new(qspi_io_mode, true);
|
||||
|
||||
let rdid = spansion_qspi.read_rdid_extended();
|
||||
info!(
|
||||
@@ -116,48 +103,27 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
);
|
||||
let cr1 = spansion_qspi.read_configuration_register();
|
||||
info!("QSPI Configuration Register 1: {:?}", cr1);
|
||||
let sr = spansion_qspi.read_status_register_1();
|
||||
info!("QSPI Status Register: {:?}", sr);
|
||||
|
||||
let mut write_buf: [u8; 100 * qspi_spansion::PAGE_SIZE] = [0x0; 100 * qspi_spansion::PAGE_SIZE];
|
||||
let mut write_buf: [u8; u8::MAX as usize + 1] = [0x0; u8::MAX as usize + 1];
|
||||
for (idx, byte) in write_buf.iter_mut().enumerate() {
|
||||
*byte = (idx % u8::MAX as usize) as u8;
|
||||
*byte = idx as u8;
|
||||
}
|
||||
let mut read_buf = [0u8; 100 * qspi_spansion::PAGE_SIZE];
|
||||
let mut read_buf = [0u8; 256];
|
||||
|
||||
if ERASE_PROGRAM_READ_TEST {
|
||||
info!("performing erase, program, read test");
|
||||
spansion_qspi
|
||||
.erase_sector(TEST_QSPI_BASE)
|
||||
.erase_sector(0x10000)
|
||||
.expect("erasing sector failed");
|
||||
spansion_qspi.read_fast_read(TEST_QSPI_BASE, &mut read_buf, true);
|
||||
spansion_qspi.read_page_fast_read(0x10000, &mut read_buf, true);
|
||||
for read in read_buf.iter() {
|
||||
assert_eq!(*read, 0xFF);
|
||||
}
|
||||
read_buf.fill(0);
|
||||
let mut current_offset = 0_usize;
|
||||
let mut current_qspi_offset = TEST_QSPI_BASE;
|
||||
for (idx, chunk) in write_buf
|
||||
.chunks(qspi_spansion::RECOMMENDED_PROGRAM_PAGE_SIZE)
|
||||
.enumerate()
|
||||
{
|
||||
spansion_qspi
|
||||
.program(current_qspi_offset, chunk)
|
||||
.expect("programming failed");
|
||||
spansion_qspi.read_fast_read(
|
||||
current_qspi_offset,
|
||||
&mut read_buf[current_offset..current_offset + chunk.len()],
|
||||
true,
|
||||
);
|
||||
assert_eq!(
|
||||
chunk,
|
||||
&read_buf[current_offset..current_offset + chunk.len()],
|
||||
"read and write missmatch at chunk index {}, data offset {}",
|
||||
idx,
|
||||
current_offset
|
||||
);
|
||||
current_offset += chunk.len();
|
||||
current_qspi_offset += chunk.len() as u32;
|
||||
spansion_qspi.program_page(0x10000, &write_buf).unwrap();
|
||||
spansion_qspi.read_page_fast_read(0x10000, &mut read_buf, true);
|
||||
for (read, written) in read_buf.iter().zip(write_buf.iter()) {
|
||||
assert_eq!(read, written);
|
||||
}
|
||||
info!("test successful");
|
||||
}
|
||||
@@ -167,7 +133,7 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
let guard = spansion_lqspi.read_guard();
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(
|
||||
(qspi::QSPI_START_ADDRESS + TEST_QSPI_BASE as usize) as *const u8,
|
||||
(qspi::QSPI_START_ADDRESS + 0x10000) as *const u8,
|
||||
read_buf.as_mut_ptr(),
|
||||
256,
|
||||
);
|
||||
|
||||
@@ -1,275 +0,0 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use aarch32_cpu::asm::nop;
|
||||
use core::panic::PanicInfo;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_time::{Duration, Ticker};
|
||||
use embedded_hal::digital::StatefulOutputPin;
|
||||
use embedded_io::Write;
|
||||
use log::error;
|
||||
use zedboard::PS_CLOCK_FREQUENCY;
|
||||
use zynq7000_hal::gpio::Input;
|
||||
use zynq7000_hal::prelude::*;
|
||||
use zynq7000_hal::sd::SdClockConfig;
|
||||
use zynq7000_hal::{BootMode, clocks, gic, gpio, gtc, sd::SdCardUninit, uart};
|
||||
|
||||
use zynq7000_rt as _;
|
||||
|
||||
const INIT_STRING: &str = "-- Zynq 7000 Zedboard SDIO example --\n\r";
|
||||
|
||||
// These are off by default because they write to the SD card as well.
|
||||
const LOW_LEVEL_TESTS: bool = false;
|
||||
const SDMMC_RS_TESTS: bool = false;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct DummyTimeSource;
|
||||
|
||||
impl embedded_sdmmc::TimeSource for DummyTimeSource {
|
||||
fn get_timestamp(&self) -> embedded_sdmmc::Timestamp {
|
||||
embedded_sdmmc::Timestamp::from_calendar(1970, 1, 1, 0, 0, 0).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Entry point which calls the embassy main method.
|
||||
#[zynq7000_rt::entry]
|
||||
fn entry_point() -> ! {
|
||||
main();
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
#[unsafe(export_name = "main")]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
let periphs = zynq7000_hal::init(zynq7000_hal::Config {
|
||||
init_l2_cache: true,
|
||||
level_shifter_config: Some(zynq7000_hal::LevelShifterConfig::EnableAll),
|
||||
interrupt_config: Some(zynq7000_hal::InteruptConfig::AllInterruptsToCpu0),
|
||||
})
|
||||
.unwrap();
|
||||
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
|
||||
let clocks = clocks::Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
|
||||
|
||||
let gpio_pins = gpio::GpioPins::new(periphs.gpio);
|
||||
|
||||
// Set up global timer counter and embassy time driver.
|
||||
let gtc = gtc::GlobalTimerCounter::new(periphs.gtc, clocks.arm_clocks());
|
||||
zynq7000_embassy::init(clocks.arm_clocks(), gtc);
|
||||
|
||||
// Set up the UART, we are logging with it.
|
||||
let uart_clk_config = uart::ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200)
|
||||
.unwrap()
|
||||
.0;
|
||||
let mut uart = uart::Uart::new_with_mio_for_uart_1(
|
||||
periphs.uart_1,
|
||||
uart::Config::new_with_clk_config(uart_clk_config),
|
||||
(gpio_pins.mio.mio48, gpio_pins.mio.mio49),
|
||||
)
|
||||
.unwrap();
|
||||
uart.write_all(INIT_STRING.as_bytes()).unwrap();
|
||||
// Safety: We are not multi-threaded yet.
|
||||
unsafe {
|
||||
zynq7000_hal::log::uart_blocking::init_unsafe_single_core(
|
||||
uart,
|
||||
log::LevelFilter::Trace,
|
||||
false,
|
||||
)
|
||||
};
|
||||
|
||||
let sdio_clock_config =
|
||||
SdClockConfig::calculate_for_io_clock(clocks.io_clocks(), 100.MHz(), 10.MHz()).unwrap();
|
||||
log::info!("SDIO clock config: {:?}", sdio_clock_config);
|
||||
let sd_card_uninit = SdCardUninit::new_for_sdio_0(
|
||||
periphs.sdio_0,
|
||||
sdio_clock_config,
|
||||
// On the zedboard, the bank has a 1.8 V voltage which is shifted up to 3.3 V by a
|
||||
// level shifter.
|
||||
zynq7000_hal::sd::IoType::LvCmos18,
|
||||
gpio_pins.mio.mio40,
|
||||
gpio_pins.mio.mio41,
|
||||
(
|
||||
gpio_pins.mio.mio42,
|
||||
gpio_pins.mio.mio43,
|
||||
gpio_pins.mio.mio44,
|
||||
gpio_pins.mio.mio45,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
let card_detect = Input::new_for_mio(gpio_pins.mio.mio47).unwrap();
|
||||
let write_protect = Input::new_for_mio(gpio_pins.mio.mio46).unwrap();
|
||||
// The card detect being active low makes sense according to the Zedboard docs. Not sure
|
||||
// about write-protect though.. It seems that write protect on means that the
|
||||
// the pin is pulled high.
|
||||
log::info!("Card detect state: {:?}", card_detect.is_low());
|
||||
log::info!("Write protect state: {:?}", write_protect.is_high());
|
||||
|
||||
let capabilities = sd_card_uninit.ll().capabilities();
|
||||
log::debug!("SDIO Capabilities: {:?}", capabilities);
|
||||
|
||||
let present_state = sd_card_uninit.ll().read_present_state();
|
||||
log::debug!("SD present state: {:?}", present_state);
|
||||
|
||||
let boot_mode = BootMode::new_from_regs();
|
||||
log::info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
let mut ticker = Ticker::every(Duration::from_millis(200));
|
||||
|
||||
let mut mio_led = gpio::Output::new_for_mio(gpio_pins.mio.mio7, gpio::PinState::Low);
|
||||
|
||||
let sd_result = sd_card_uninit.initialize();
|
||||
let sd_card = match sd_result {
|
||||
Ok(card) => {
|
||||
log::info!("SD card info: {:?}", card.card_info());
|
||||
card
|
||||
}
|
||||
Err(e) => {
|
||||
panic!("SDIO init error: {e:?}");
|
||||
}
|
||||
};
|
||||
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
|
||||
if LOW_LEVEL_TESTS {
|
||||
log::info!("doing SD card low-level tests");
|
||||
|
||||
let mut cache_buf: [u8; 4096] = [0; 4096];
|
||||
|
||||
// cache the data, will be written back later..
|
||||
sd_card
|
||||
.read_multiple_blocks(&mut cache_buf, 0x1000)
|
||||
.unwrap();
|
||||
|
||||
let mut write_data: [u8; 4096] = [0; 4096];
|
||||
for chunk in write_data.chunks_mut(u8::MAX as usize) {
|
||||
for (idx, byte) in chunk.iter_mut().enumerate() {
|
||||
*byte = idx as u8;
|
||||
}
|
||||
}
|
||||
sd_card.write_multiple_blocks(&write_data, 0x1000).unwrap();
|
||||
|
||||
sd_card.read_multiple_blocks(&mut buf, 0x1000).unwrap();
|
||||
for chunk in buf.chunks(u8::MAX as usize) {
|
||||
for (idx, byte) in chunk.iter().enumerate() {
|
||||
assert_eq!(idx as u8, *byte);
|
||||
}
|
||||
}
|
||||
|
||||
sd_card.write_multiple_blocks(&cache_buf, 0x1000).unwrap();
|
||||
|
||||
log::info!("SD card low-level tests success");
|
||||
}
|
||||
|
||||
buf.fill(0);
|
||||
|
||||
if SDMMC_RS_TESTS {
|
||||
log::info!("doing SD card embedded-sdmmc-rs tests");
|
||||
|
||||
// Now let's look for volumes (also known as partitions) on our block device.
|
||||
// To do this we need a Volume Manager. It will take ownership of the block device.
|
||||
let volume_mgr = embedded_sdmmc::VolumeManager::new(sd_card, DummyTimeSource);
|
||||
// Try and access Volume 0 (i.e. the first partition).
|
||||
// The volume object holds information about the filesystem on that volume.
|
||||
let volume0 = volume_mgr
|
||||
.open_volume(embedded_sdmmc::VolumeIdx(0))
|
||||
.unwrap();
|
||||
|
||||
// Open the root directory (mutably borrows from the volume).
|
||||
let mut current_dir = volume0.open_root_dir().unwrap();
|
||||
log::info!("iterating root directory");
|
||||
current_dir
|
||||
.iterate_dir(|entry| {
|
||||
log::info!("{:?}", entry);
|
||||
core::ops::ControlFlow::Continue(())
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let new_file = current_dir
|
||||
.open_file_in_dir("__T.TXT", embedded_sdmmc::Mode::ReadWriteCreateOrTruncate)
|
||||
.unwrap();
|
||||
let string = "test string\n";
|
||||
new_file.write(string.as_bytes()).unwrap();
|
||||
new_file.close().unwrap();
|
||||
|
||||
let read_new = current_dir
|
||||
.open_file_in_dir("__T.TXT", embedded_sdmmc::Mode::ReadOnly)
|
||||
.unwrap();
|
||||
assert_eq!(read_new.length(), string.len() as u32);
|
||||
read_new.read(&mut buf).unwrap();
|
||||
let buf_as_str = core::str::from_utf8(&buf[0..string.len()]).unwrap();
|
||||
assert_eq!(buf_as_str, string);
|
||||
read_new.close().unwrap();
|
||||
|
||||
current_dir.delete_entry_in_dir("__T.TXT").unwrap();
|
||||
|
||||
assert_eq!(
|
||||
current_dir.find_directory_entry("__T.TXT").unwrap_err(),
|
||||
embedded_sdmmc::Error::NotFound
|
||||
);
|
||||
|
||||
if current_dir.find_directory_entry("_TDIR").is_ok() {
|
||||
current_dir.delete_entry_in_dir("_TDIR").unwrap();
|
||||
}
|
||||
|
||||
current_dir.make_dir_in_dir("_TDIR").unwrap();
|
||||
current_dir.change_dir("_TDIR").unwrap();
|
||||
current_dir.change_dir("..").unwrap();
|
||||
current_dir.delete_entry_in_dir("_TDIR").unwrap();
|
||||
|
||||
current_dir.close().unwrap();
|
||||
|
||||
log::info!("SD card embedded-sdmmc-rs success");
|
||||
}
|
||||
|
||||
loop {
|
||||
mio_led.toggle().unwrap();
|
||||
|
||||
ticker.next().await; // Wait for the next cycle of the ticker
|
||||
}
|
||||
}
|
||||
|
||||
#[zynq7000_rt::irq]
|
||||
fn irq_handler() {
|
||||
let mut gic_helper = gic::GicInterruptHelper::new();
|
||||
let irq_info = gic_helper.acknowledge_interrupt();
|
||||
match irq_info.interrupt() {
|
||||
gic::Interrupt::Sgi(_) => (),
|
||||
gic::Interrupt::Ppi(ppi_interrupt) => {
|
||||
if ppi_interrupt == gic::PpiInterrupt::GlobalTimer {
|
||||
unsafe {
|
||||
zynq7000_embassy::on_interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
gic::Interrupt::Spi(_spi_interrupt) => (),
|
||||
gic::Interrupt::Invalid(_) => (),
|
||||
gic::Interrupt::Spurious => (),
|
||||
}
|
||||
gic_helper.end_of_interrupt(irq_info);
|
||||
}
|
||||
|
||||
#[zynq7000_rt::exception(DataAbort)]
|
||||
fn data_abort_handler(_faulting_addr: usize) -> ! {
|
||||
loop {
|
||||
nop();
|
||||
}
|
||||
}
|
||||
|
||||
#[zynq7000_rt::exception(Undefined)]
|
||||
fn undefined_handler(_faulting_addr: usize) -> ! {
|
||||
loop {
|
||||
nop();
|
||||
}
|
||||
}
|
||||
|
||||
#[zynq7000_rt::exception(PrefetchAbort)]
|
||||
fn prefetch_handler(_faulting_addr: usize) -> ! {
|
||||
loop {
|
||||
nop();
|
||||
}
|
||||
}
|
||||
|
||||
/// Panic handler
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
error!("Panic: {info:?}");
|
||||
loop {}
|
||||
}
|
||||
@@ -88,11 +88,11 @@ static QUEUE_UART16550: static_cell::ConstStaticCell<heapless::spsc::Queue<u8, R
|
||||
// Those are all used by the interrupt handler, so we have to do the Mutex dance.
|
||||
static RX_UART_0: Mutex<RefCell<Option<zynq7000_hal::uart::Rx>>> = Mutex::new(RefCell::new(None));
|
||||
|
||||
static UART_0_PROD: Mutex<RefCell<Option<heapless::spsc::Producer<'static, u8>>>> =
|
||||
static UART_0_PROD: Mutex<RefCell<Option<heapless::spsc::Producer<'static, u8, RB_SIZE>>>> =
|
||||
Mutex::new(RefCell::new(None));
|
||||
static UARTLITE_PROD: Mutex<RefCell<Option<heapless::spsc::Producer<'static, u8>>>> =
|
||||
static UARTLITE_PROD: Mutex<RefCell<Option<heapless::spsc::Producer<'static, u8, RB_SIZE>>>> =
|
||||
Mutex::new(RefCell::new(None));
|
||||
static UART16550_PROD: Mutex<RefCell<Option<heapless::spsc::Producer<'static, u8>>>> =
|
||||
static UART16550_PROD: Mutex<RefCell<Option<heapless::spsc::Producer<'static, u8, RB_SIZE>>>> =
|
||||
Mutex::new(RefCell::new(None));
|
||||
|
||||
/// Entry point which calls the embassy main method.
|
||||
@@ -284,20 +284,20 @@ async fn main(spawner: Spawner) -> ! {
|
||||
.replace(uart16550_prod);
|
||||
RX_UART_0.borrow(cs).borrow_mut().replace(uart_0_rx);
|
||||
});
|
||||
spawner.spawn(led_task(mio_led, emio_leds).unwrap());
|
||||
spawner.spawn(led_task(mio_led, emio_leds)).unwrap();
|
||||
|
||||
match UART_MODE {
|
||||
UartMode::Uart0ToUartlite => {
|
||||
spawner.spawn(uartlite_task(uartlite_tx).unwrap());
|
||||
spawner.spawn(uart_0_task(uart_0_tx).unwrap());
|
||||
spawner.spawn(uartlite_task(uartlite_tx)).unwrap();
|
||||
spawner.spawn(uart_0_task(uart_0_tx)).unwrap();
|
||||
}
|
||||
UartMode::Uart0ToUart16550 => {
|
||||
spawner.spawn(uart_0_task(uart_0_tx).unwrap());
|
||||
spawner.spawn(uart_16550_task(uart_16550_tx).unwrap());
|
||||
spawner.spawn(uart_0_task(uart_0_tx)).unwrap();
|
||||
spawner.spawn(uart_16550_task(uart_16550_tx)).unwrap();
|
||||
}
|
||||
UartMode::UartliteToUart16550 => {
|
||||
spawner.spawn(uartlite_task(uartlite_tx).unwrap());
|
||||
spawner.spawn(uart_16550_task(uart_16550_tx).unwrap());
|
||||
spawner.spawn(uartlite_task(uartlite_tx)).unwrap();
|
||||
spawner.spawn(uart_16550_task(uart_16550_tx)).unwrap();
|
||||
}
|
||||
}
|
||||
let mut read_buf: [u8; RB_SIZE] = [0; RB_SIZE];
|
||||
|
||||
@@ -8,19 +8,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
## Fixed
|
||||
|
||||
- QSPI robustness fixes. Read, fast-read and write operations are now chunked according to the 252
|
||||
byte limit specified in the TRM.
|
||||
|
||||
## Added
|
||||
|
||||
- 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
|
||||
|
||||
@@ -10,14 +10,9 @@ keywords = ["no-std", "zedboard", "bare-metal", "amd", "zynq7000"]
|
||||
categories = ["embedded", "no-std", "hardware-support"]
|
||||
|
||||
[dependencies]
|
||||
zynq7000 = { path = "../zynq7000", version = "0.2" }
|
||||
zynq7000 = { path = "../zynq7000", version = "0.1" }
|
||||
zynq7000-hal = { path = "../zynq7000-hal", version = "0.1" }
|
||||
bitbybit = "2"
|
||||
log = "0.4"
|
||||
bitbybit = "1.4"
|
||||
arbitrary-int = "2"
|
||||
num_enum = { version = "0.7", default-features = false }
|
||||
thiserror = { version = "2", default-features = false }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["armv7a-none-eabihf"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# program."]
|
||||
# program."]
|
||||
#![doc = r""]
|
||||
#![doc = r"This configuration file contains static DDR configuration parameters extracted from the"]
|
||||
#![doc = r"AMD ps7init.tcl file. It was generated for the MT41K128M16JT-125 DDR chip."]
|
||||
@@ -34,7 +34,7 @@ pub const DDRC_CONFIG_ZEDBOARD: DdrcConfigSet = DdrcConfigSet {
|
||||
ctrl_reg5: regs::CtrlReg5::new_with_raw_value(0x00466111),
|
||||
ctrl_reg6: regs::CtrlReg6::new_with_raw_value(0x00032222),
|
||||
che_t_zq: regs::CheTZq::new_with_raw_value(0x10200802),
|
||||
che_t_zq_short_interval_reg: regs::CheTZqShortInterval::new_with_raw_value(0x0690cb73),
|
||||
che_t_zq_short_interval_reg: regs::CheTZqShortInterval::new_with_raw_value(0x10200802),
|
||||
deep_powerdown: regs::DeepPowerdown::new_with_raw_value(0x000001fe),
|
||||
reg_2c: regs::Reg2c::new_with_raw_value(0x1cffffff),
|
||||
reg_2d: regs::Reg2d::new_with_raw_value(0x00000200),
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
# program."]
|
||||
# program."]
|
||||
#![doc = r""]
|
||||
#![doc = r"This configuration file contains static DDRIOB configuration parameters extracted from the"]
|
||||
#![doc = r"AMD ps7init.tcl file. It was generated for the MT41K128M16JT-125 DDR chip."]
|
||||
use zynq7000::ddrc::regs;
|
||||
use zynq7000_hal::ddr::DdriobConfigSet;
|
||||
pub const DDRIOB_CONFIG_SET_ZEDBOARD: DdriobConfigSet = DdriobConfigSet {
|
||||
ddr_control: zynq7000::slcr::ddriob::DdrControl::new_with_raw_value(0x00000260),
|
||||
addr0: regs::DdriobConfig::new_with_raw_value(0x00000600),
|
||||
addr1: regs::DdriobConfig::new_with_raw_value(0x00000600),
|
||||
data0: regs::DdriobConfig::new_with_raw_value(0x00000672),
|
||||
|
||||
@@ -2,17 +2,10 @@ use core::cell::RefCell;
|
||||
|
||||
use arbitrary_int::{prelude::*, u24};
|
||||
use zynq7000_hal::qspi::{
|
||||
FIFO_DEPTH, LinearQspiConfig, MAX_BYTES_PER_TRANSFER_IO_MODE, QspiIoMode, QspiLinearAddressing,
|
||||
FIFO_DEPTH, LinearQspiConfig, QspiIoMode, QspiIoTransferGuard, QspiLinearAddressing,
|
||||
QspiLinearReadGuard,
|
||||
};
|
||||
|
||||
/// 4 bytes are reserved for command byte and address. Rounded down at a 16 byte boundary,
|
||||
/// recommended by flash memory datasheet.
|
||||
pub const MAX_DATA_BYTES_PER_WRITE: usize = 240;
|
||||
/// Probably the most performant chunk/program size to program the chip without crossing page
|
||||
/// boundaries without exceeding the FIFO size.
|
||||
pub const RECOMMENDED_PROGRAM_PAGE_SIZE: usize = 128;
|
||||
|
||||
pub const QSPI_DEV_COMBINATION_REV_F: zynq7000_hal::qspi::QspiDeviceCombination =
|
||||
zynq7000_hal::qspi::QspiDeviceCombination {
|
||||
vendor: zynq7000_hal::qspi::QspiVendor::WinbondAndSpansion,
|
||||
@@ -20,8 +13,7 @@ pub const QSPI_DEV_COMBINATION_REV_F: zynq7000_hal::qspi::QspiDeviceCombination
|
||||
two_devices: false,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum RegisterId {
|
||||
/// WRR
|
||||
WriteRegisters = 0x01,
|
||||
@@ -72,8 +64,7 @@ pub enum SectorArchictecture {
|
||||
Hybrid = 0x01,
|
||||
}
|
||||
|
||||
pub const PAGE_SIZE: usize = 0x100;
|
||||
pub const SECTOR_SIZE: usize = 0x10000;
|
||||
pub const PAGE_SIZE: usize = 256;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BaseDeviceId {
|
||||
@@ -168,7 +159,8 @@ impl ExtendedDeviceId {
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u8, debug, forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u8)]
|
||||
#[derive(Debug)]
|
||||
pub struct StatusRegister1 {
|
||||
#[bit(7, rw)]
|
||||
status_register_write_disable: bool,
|
||||
@@ -176,18 +168,25 @@ pub struct StatusRegister1 {
|
||||
programming_error: bool,
|
||||
#[bit(5, r)]
|
||||
erase_error: bool,
|
||||
#[bits(2..=4, rw)]
|
||||
block_protection: u3,
|
||||
#[bit(4, r)]
|
||||
bp_2: bool,
|
||||
#[bit(3, r)]
|
||||
bp_1: bool,
|
||||
#[bit(2, r)]
|
||||
bp_0: bool,
|
||||
#[bit(1, r)]
|
||||
write_enable_latch: bool,
|
||||
#[bit(0, r)]
|
||||
write_in_progress: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u8, debug, forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u8)]
|
||||
#[derive(Debug)]
|
||||
pub struct ConfigRegister1 {
|
||||
#[bits(6..=7, rw)]
|
||||
latency_code: u2,
|
||||
#[bit(7, rw)]
|
||||
latency_code_1: bool,
|
||||
#[bit(6, rw)]
|
||||
latency_code_0: bool,
|
||||
/// This is an OTP bit. It can not be set back to 0 once it has been set to 1!
|
||||
#[bit(5, rw)]
|
||||
tbprot: bool,
|
||||
@@ -224,60 +223,27 @@ pub enum ProgramPageError {
|
||||
ProgrammingErrorBitSet,
|
||||
#[error("address error: {0}")]
|
||||
Addr(#[from] AddrError),
|
||||
#[error("program data is larger than page size {PAGE_SIZE}")]
|
||||
DataTooLarge,
|
||||
#[error("program data is not aligned to 4 bytes")]
|
||||
NotAligned,
|
||||
#[error("program data crosses page boundary")]
|
||||
CrossesPageBoundary,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub struct Config {
|
||||
pub set_quad_bit_if_necessary: bool,
|
||||
pub latency_config: Option<u2>,
|
||||
pub clear_write_protection: bool,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn sr_or_cr_update_possibly_required(&self) -> bool {
|
||||
self.set_quad_bit_if_necessary
|
||||
|| self.latency_config.is_some()
|
||||
|| self.clear_write_protection
|
||||
}
|
||||
#[error("data is larger than page size {PAGE_SIZE}")]
|
||||
DataLargerThanPage,
|
||||
}
|
||||
|
||||
pub struct QspiSpansionS25Fl256SIoMode(RefCell<QspiIoMode>);
|
||||
|
||||
impl QspiSpansionS25Fl256SIoMode {
|
||||
pub fn new(qspi: QspiIoMode, config: Config) -> Self {
|
||||
pub fn new(qspi: QspiIoMode, set_quad_bit_if_necessary: bool) -> Self {
|
||||
let mut spansion_qspi = QspiSpansionS25Fl256SIoMode(RefCell::new(qspi));
|
||||
spansion_qspi.clear_status();
|
||||
let mut write_required = false;
|
||||
if config.sr_or_cr_update_possibly_required() {
|
||||
if set_quad_bit_if_necessary {
|
||||
let mut cr1 = spansion_qspi.read_configuration_register();
|
||||
if config.set_quad_bit_if_necessary && !cr1.quad() {
|
||||
cr1.set_quad(true);
|
||||
write_required = true;
|
||||
}
|
||||
if let Some(latency_config) = config.latency_config
|
||||
&& cr1.latency_code() != latency_config
|
||||
{
|
||||
cr1.set_latency_code(latency_config);
|
||||
write_required = true;
|
||||
if cr1.quad() {
|
||||
// Quad bit is already set.
|
||||
return spansion_qspi;
|
||||
}
|
||||
cr1.set_quad(true);
|
||||
// Preserve the status register by reading it first.
|
||||
let mut sr1 = spansion_qspi.read_status_register_1();
|
||||
if config.clear_write_protection && sr1.block_protection() != u3::ZERO {
|
||||
sr1.set_status_register_write_disable(false);
|
||||
sr1.set_block_protection(u3::ZERO);
|
||||
write_required = true;
|
||||
}
|
||||
if write_required {
|
||||
// Safety: Only the QUAD bit was set while all other bits are preserved.
|
||||
unsafe {
|
||||
spansion_qspi.write_status_and_config_register(sr1, cr1);
|
||||
}
|
||||
let sr1 = spansion_qspi.read_status_register_1();
|
||||
// Safety: Only the QUAD bit was set while all other bits are preserved.
|
||||
unsafe {
|
||||
spansion_qspi.write_status_and_config_register(sr1, cr1);
|
||||
}
|
||||
}
|
||||
spansion_qspi
|
||||
@@ -291,16 +257,6 @@ impl QspiSpansionS25Fl256SIoMode {
|
||||
QspiSpansionS25Fl256SLinearMode(qspi)
|
||||
}
|
||||
|
||||
pub fn set_write_protection(&mut self, write_protection: u3) {
|
||||
unsafe {
|
||||
self.modify_status_and_config_register(|mut sr, cr| {
|
||||
sr.set_status_register_write_disable(false);
|
||||
sr.set_block_protection(write_protection);
|
||||
(sr, cr)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_enable(&mut self) {
|
||||
let qspi = self.0.get_mut();
|
||||
let mut transfer = qspi.transfer_guard();
|
||||
@@ -345,38 +301,7 @@ impl QspiSpansionS25Fl256SIoMode {
|
||||
/// # Safety
|
||||
///
|
||||
/// Misuse of this API does not lead to undefined behavior. However, it writes the
|
||||
/// configuration register, which is OTP bits. Changing these bits from 0 to 1 is an
|
||||
/// irreversible operation.
|
||||
pub unsafe fn modify_status_and_config_register(
|
||||
&mut self,
|
||||
f: impl FnOnce(StatusRegister1, ConfigRegister1) -> (StatusRegister1, ConfigRegister1),
|
||||
) {
|
||||
self.write_enable();
|
||||
let mut qspi = self.0.borrow_mut();
|
||||
let mut transfer = qspi.transfer_guard();
|
||||
let sr1 = self.read_status_register_1();
|
||||
let cr1 = self.read_configuration_register();
|
||||
let (sr1, cr1) = f(sr1, cr1);
|
||||
transfer.write_word_txd_11(u32::from_ne_bytes([
|
||||
RegisterId::WriteRegisters as u8,
|
||||
sr1.raw_value(),
|
||||
cr1.raw_value(),
|
||||
0x00,
|
||||
]));
|
||||
transfer.start();
|
||||
while !transfer.read_status().rx_above_threshold() {}
|
||||
transfer.read_rx_data();
|
||||
}
|
||||
|
||||
/// Write a new value for the status register. It is strongly recommended to read both
|
||||
/// the status and config register first and preserve all unchanged bits.
|
||||
///
|
||||
/// This API must be used if the QUAD bit (CR1\[1\]) is set.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Misuse of this API does not lead to undefined behavior. However, it writes the
|
||||
/// configuration register, which is OTP bits. Changing these bits from 0 to 1 is an
|
||||
/// configuration register, which as OTP bits. Changing these bits from 0 to 1 is an
|
||||
/// irreversible operation.
|
||||
pub unsafe fn write_status_and_config_register(
|
||||
&mut self,
|
||||
@@ -463,10 +388,10 @@ impl QspiSpansionS25Fl256SIoMode {
|
||||
|
||||
/// This function will block until the operation has completed.
|
||||
pub fn erase_sector(&mut self, addr: u32) -> Result<(), EraseError> {
|
||||
if addr + SECTOR_SIZE as u32 > u24::MAX.as_u32() {
|
||||
if addr + 0x10000 > u24::MAX.as_u32() {
|
||||
return Err(AddrError::OutOfRange.into());
|
||||
}
|
||||
if !addr.is_multiple_of(SECTOR_SIZE as u32) {
|
||||
if !addr.is_multiple_of(0x10000) {
|
||||
return Err(AddrError::Alignment.into());
|
||||
}
|
||||
self.write_enable();
|
||||
@@ -504,35 +429,19 @@ impl QspiSpansionS25Fl256SIoMode {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_pages(&mut self, mut addr: u32, data: &[u8]) -> Result<(), ProgramPageError> {
|
||||
if addr + data.len() as u32 > u24::MAX.as_u32() {
|
||||
return Err(AddrError::OutOfRange.into());
|
||||
}
|
||||
for chunk in data.chunks(RECOMMENDED_PROGRAM_PAGE_SIZE) {
|
||||
self.program(addr, chunk)?;
|
||||
addr += chunk.len() as u32;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This function also takes care of enabling writes before programming the page.
|
||||
/// 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 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> {
|
||||
/// 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 data.len() > MAX_DATA_BYTES_PER_WRITE {
|
||||
return Err(ProgramPageError::DataTooLarge);
|
||||
if !addr.is_multiple_of(0x100) {
|
||||
return Err(AddrError::Alignment.into());
|
||||
}
|
||||
if !data.len().is_multiple_of(4) {
|
||||
return Err(ProgramPageError::NotAligned);
|
||||
}
|
||||
if (addr as usize % PAGE_SIZE) + data.len() > PAGE_SIZE {
|
||||
return Err(ProgramPageError::CrossesPageBoundary);
|
||||
if data.len() > PAGE_SIZE {
|
||||
return Err(ProgramPageError::DataLargerThanPage);
|
||||
}
|
||||
self.write_enable();
|
||||
let qspi = self.0.get_mut();
|
||||
@@ -546,8 +455,7 @@ 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;
|
||||
// Full four byte writes.
|
||||
let fifo_writes = data.len() / 4;
|
||||
let fifo_writes = data.len().div_ceil(4);
|
||||
// Fill the FIFO until it is full.
|
||||
for _ in 0..core::cmp::min(fifo_writes, FIFO_DEPTH - 1) {
|
||||
transfer.write_word_txd_00(u32::from_ne_bytes(
|
||||
@@ -557,14 +465,52 @@ impl QspiSpansionS25Fl256SIoMode {
|
||||
));
|
||||
current_byte_index += 4;
|
||||
}
|
||||
|
||||
transfer.start();
|
||||
|
||||
// Wait until the transfer is done by waiting until all RX bytes have been received.
|
||||
let mut wait_for_tx_slot = |transfer: &mut QspiIoTransferGuard| loop {
|
||||
let status = transfer.read_status();
|
||||
if status.rx_above_threshold() {
|
||||
transfer.read_rx_data();
|
||||
read_index = read_index.wrapping_add(4);
|
||||
}
|
||||
if !status.tx_full() {
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
while current_byte_index < data.len() {
|
||||
// Immediately fill the FIFO again with the remaining 8 bytes.
|
||||
wait_for_tx_slot(&mut transfer);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
while read_index < data.len() as u32 {
|
||||
// Double read to avoid RX underflows as specified in TRM.
|
||||
let status_read = transfer.read_status();
|
||||
if status_read.rx_above_threshold() && transfer.read_status().rx_above_threshold() {
|
||||
if transfer.read_status().rx_above_threshold() {
|
||||
transfer.read_rx_data();
|
||||
read_index = read_index.wrapping_add(4);
|
||||
}
|
||||
@@ -587,134 +533,84 @@ impl QspiSpansionS25Fl256SIoMode {
|
||||
}
|
||||
}
|
||||
|
||||
fn generic_read(&self, addr: u32, buf: &mut [u8], dummy_byte: bool, fast_read: bool) {
|
||||
let mut offset = 0;
|
||||
let reg_id = if fast_read {
|
||||
RegisterId::FastRead
|
||||
} else {
|
||||
RegisterId::Read
|
||||
};
|
||||
pub fn read_page_fast_read(&self, addr: u32, buf: &mut [u8], dummy_byte: bool) {
|
||||
let mut qspi = self.0.borrow_mut();
|
||||
let mut max_chunk_size = MAX_BYTES_PER_TRANSFER_IO_MODE - 4;
|
||||
let mut transfer = qspi.transfer_guard();
|
||||
let raw_word: [u8; 4] = [
|
||||
RegisterId::FastRead as u8,
|
||||
((addr >> 16) & 0xff) as u8,
|
||||
((addr >> 8) & 0xff) as u8,
|
||||
(addr & 0xff) as u8,
|
||||
];
|
||||
transfer.write_word_txd_00(u32::from_ne_bytes(raw_word));
|
||||
let mut read_index = 0;
|
||||
let mut written_words = 0;
|
||||
let mut bytes_to_write = buf.len();
|
||||
if dummy_byte {
|
||||
max_chunk_size -= 1;
|
||||
bytes_to_write += 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);
|
||||
written_words += 1;
|
||||
}
|
||||
|
||||
while offset < buf.len() {
|
||||
// Calculate the size of the current chunk (max 248 bytes)
|
||||
let chunk_size = core::cmp::min(max_chunk_size, buf.len() - offset);
|
||||
let current_addr = addr + offset as u32;
|
||||
transfer.start();
|
||||
let mut reply_word_index = 0;
|
||||
|
||||
// Create a mutable slice for the current chunk
|
||||
let chunk_slice = &mut buf[offset..offset + chunk_size];
|
||||
|
||||
// This ensures the hardware transaction (Chip Select, etc.) restarts for each chunk.
|
||||
{
|
||||
let mut transfer = qspi.transfer_guard();
|
||||
|
||||
let raw_word: [u8; 4] = [
|
||||
reg_id as u8,
|
||||
((current_addr >> 16) & 0xff) as u8,
|
||||
((current_addr >> 8) & 0xff) as u8,
|
||||
(current_addr & 0xff) as u8,
|
||||
];
|
||||
transfer.write_word_txd_00(u32::from_ne_bytes(raw_word));
|
||||
|
||||
let mut read_index = 0;
|
||||
let mut written_words = 0;
|
||||
// Use chunk_size instead of the full buffer length
|
||||
let mut bytes_to_write = chunk_size;
|
||||
|
||||
if dummy_byte {
|
||||
bytes_to_write += 1;
|
||||
while read_index < buf.len() {
|
||||
if transfer.read_status().rx_above_threshold() {
|
||||
let reply = transfer.read_rx_data();
|
||||
if reply_word_index == 0 {
|
||||
reply_word_index += 1;
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
written_words += 1;
|
||||
}
|
||||
|
||||
transfer.start();
|
||||
let mut reply_word_index = 0;
|
||||
|
||||
// Loop based on the current chunk's size
|
||||
while read_index < chunk_size {
|
||||
let rx_is_above_threshold = transfer.read_status().rx_above_threshold();
|
||||
|
||||
// See p.374 of the TRM: Do a double read to ensure this is correct information.
|
||||
if rx_is_above_threshold && transfer.read_status().rx_above_threshold() {
|
||||
let reply = transfer.read_rx_data();
|
||||
if reply_word_index == 0 {
|
||||
reply_word_index += 1;
|
||||
continue;
|
||||
}
|
||||
let reply_as_bytes = reply.to_ne_bytes();
|
||||
// Calculate remaining bytes in this specific chunk
|
||||
let reply_size = core::cmp::min(chunk_size - read_index, 4);
|
||||
read_index += match (reply_size, reply_word_index == 1 && dummy_byte) {
|
||||
(1, false) => {
|
||||
chunk_slice[read_index] = reply_as_bytes[0];
|
||||
1
|
||||
}
|
||||
(1, true) => {
|
||||
chunk_slice[read_index] = reply_as_bytes[1];
|
||||
1
|
||||
}
|
||||
(2, false) => {
|
||||
chunk_slice[read_index..read_index + 2]
|
||||
.copy_from_slice(&reply_as_bytes[0..2]);
|
||||
2
|
||||
}
|
||||
(2, true) => {
|
||||
chunk_slice[read_index..read_index + 2]
|
||||
.copy_from_slice(&reply_as_bytes[1..3]);
|
||||
2
|
||||
}
|
||||
(3, false) => {
|
||||
chunk_slice[read_index..read_index + 3]
|
||||
.copy_from_slice(&reply_as_bytes[0..3]);
|
||||
3
|
||||
}
|
||||
(3, true) => {
|
||||
chunk_slice[read_index..read_index + 3]
|
||||
.copy_from_slice(&reply_as_bytes[1..4]);
|
||||
3
|
||||
}
|
||||
(4, false) => {
|
||||
chunk_slice[read_index..read_index + 4]
|
||||
.copy_from_slice(&reply_as_bytes[0..4]);
|
||||
4
|
||||
}
|
||||
(4, true) => {
|
||||
chunk_slice[read_index..read_index + 3]
|
||||
.copy_from_slice(&reply_as_bytes[1..4]);
|
||||
3
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
reply_word_index += 1;
|
||||
let reply_as_bytes = reply.to_ne_bytes();
|
||||
let reply_size = core::cmp::min(buf.len() - read_index, 4);
|
||||
read_index += match (reply_size, reply_word_index == 1 && dummy_byte) {
|
||||
(1, false) => {
|
||||
buf[read_index] = reply_as_bytes[0];
|
||||
1
|
||||
}
|
||||
if written_words < fifo_writes && !transfer.read_status().tx_full() {
|
||||
transfer.write_word_txd_00(0);
|
||||
written_words += 1;
|
||||
(1, true) => {
|
||||
buf[read_index] = reply_as_bytes[1];
|
||||
1
|
||||
}
|
||||
}
|
||||
(2, false) => {
|
||||
buf[read_index..read_index + 2].copy_from_slice(&reply_as_bytes[0..2]);
|
||||
2
|
||||
}
|
||||
(2, true) => {
|
||||
buf[read_index..read_index + 2].copy_from_slice(&reply_as_bytes[1..3]);
|
||||
2
|
||||
}
|
||||
(3, false) => {
|
||||
buf[read_index..read_index + 3].copy_from_slice(&reply_as_bytes[0..3]);
|
||||
3
|
||||
}
|
||||
(3, true) => {
|
||||
buf[read_index..read_index + 3].copy_from_slice(&reply_as_bytes[1..4]);
|
||||
3
|
||||
}
|
||||
(4, false) => {
|
||||
buf[read_index..read_index + 4].copy_from_slice(&reply_as_bytes[0..4]);
|
||||
4
|
||||
}
|
||||
(4, true) => {
|
||||
buf[read_index..read_index + 3].copy_from_slice(&reply_as_bytes[1..4]);
|
||||
3
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
reply_word_index += 1;
|
||||
}
|
||||
if written_words < fifo_writes && !transfer.read_status().tx_full() {
|
||||
transfer.write_word_txd_00(0);
|
||||
written_words += 1;
|
||||
}
|
||||
|
||||
offset += chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_fast_read(&self, addr: u32, buf: &mut [u8], dummy_byte: bool) {
|
||||
self.generic_read(addr, buf, dummy_byte, true)
|
||||
}
|
||||
|
||||
/// Only works if the clock speed is slower than 50 MHz according to datasheet.
|
||||
pub fn read_page_read(&self, addr: u32, buf: &mut [u8]) {
|
||||
self.generic_read(addr, buf, false, false)
|
||||
}
|
||||
}
|
||||
|
||||
/// If the Spansion QSPI is used in linear addressed mode, no IO operations are allowed.
|
||||
@@ -722,12 +618,10 @@ pub struct QspiSpansionS25Fl256SLinearMode(QspiLinearAddressing);
|
||||
|
||||
impl QspiSpansionS25Fl256SLinearMode {
|
||||
pub const BASE_ADDR: usize = QspiLinearAddressing::BASE_ADDRESS;
|
||||
pub const PAGE_SIZE: usize = PAGE_SIZE;
|
||||
pub const SECTOR_SIZE: usize = SECTOR_SIZE;
|
||||
|
||||
pub fn into_io_mode(self, dual_flash: bool) -> QspiSpansionS25Fl256SIoMode {
|
||||
let qspi = self.0.into_io_mode(dual_flash);
|
||||
QspiSpansionS25Fl256SIoMode::new(qspi, Config::default())
|
||||
QspiSpansionS25Fl256SIoMode::new(qspi, false)
|
||||
}
|
||||
|
||||
pub fn read_guard(&mut self) -> QspiLinearReadGuard<'_> {
|
||||
|
||||
@@ -9,7 +9,7 @@ repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.2", features = ["critical-section-single-core"] }
|
||||
aarch32-cpu = { version = "0.1", features = ["critical-section-single-core"] }
|
||||
zynq7000-rt = { path = "../zynq7000-rt" }
|
||||
zynq7000 = { path = "../zynq7000" }
|
||||
zynq7000-hal = { path = "../zynq7000-hal" }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
MEMORY
|
||||
{
|
||||
/* The Zynq7000 has 256 kB of OCM memory of which 196 kB can be used for the FSBL */
|
||||
CODE(rx) : ORIGIN = 0x00000000, LENGTH = 196K
|
||||
/* The Zynq7000 has 192 kB of OCM memory which can be used for the FSBL */
|
||||
CODE(rx) : ORIGIN = 0x00000000, LENGTH = 192K
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
/* Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This can
|
||||
be used for something like DMA descriptors, but the DDR needs to be set up first in addition
|
||||
@@ -11,8 +11,6 @@ MEMORY
|
||||
|
||||
REGION_ALIAS("VECTORS", CODE);
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
/* Use the upper OCM as the stack */
|
||||
REGION_ALIAS("STACKS", OCM_UPPER);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
@@ -8,15 +8,13 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use aarch32_cpu::asm::nop;
|
||||
use arbitrary_int::traits::Integer as _;
|
||||
use arbitrary_int::{u2, u6};
|
||||
use arbitrary_int::u6;
|
||||
use core::panic::PanicInfo;
|
||||
use aarch32_cpu::asm::nop;
|
||||
use embedded_io::Write as _;
|
||||
use log::{error, info};
|
||||
use zedboard_bsp::qspi_spansion::{self, QspiSpansionS25Fl256SLinearMode};
|
||||
use zynq7000_boot_image::DestinationDevice;
|
||||
use zynq7000_hal::clocks::ArmClocks;
|
||||
use zynq7000_hal::priv_tim;
|
||||
use zynq7000_hal::{
|
||||
BootMode,
|
||||
@@ -25,7 +23,7 @@ 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::{self, QSPI_START_ADDRESS},
|
||||
time::Hertz,
|
||||
@@ -76,20 +74,6 @@ fn main() -> ! {
|
||||
);
|
||||
|
||||
let mut periphs = zynq7000::Peripherals::take().unwrap();
|
||||
l2_cache::disable();
|
||||
|
||||
// Initialize the ARM clock. Safety: We only run this once.
|
||||
unsafe {
|
||||
ArmClocks::new_with_cpu_clock_init(
|
||||
ARM_CLK,
|
||||
zynq7000_hal::clocks::CpuClockRatio::SixToTwoToOne,
|
||||
u6::new(2),
|
||||
);
|
||||
// This is done by the AMD FSBL.
|
||||
zynq7000_hal::Slcr::with(|val| {
|
||||
val.gpiob().modify_ctrl(|val| val.with_vref_en(true));
|
||||
});
|
||||
}
|
||||
|
||||
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
|
||||
let clocks = Clocks::new_from_regs(PS_CLK).unwrap();
|
||||
@@ -178,19 +162,11 @@ fn main() -> ! {
|
||||
);
|
||||
|
||||
let qspi_io_mode = qspi.into_io_mode(false);
|
||||
let spansion_qspi = qspi_spansion::QspiSpansionS25Fl256SIoMode::new(
|
||||
qspi_io_mode,
|
||||
qspi_spansion::Config {
|
||||
set_quad_bit_if_necessary: true,
|
||||
latency_config: Some(u2::ZERO),
|
||||
clear_write_protection: true,
|
||||
},
|
||||
);
|
||||
let spansion_qspi = qspi_spansion::QspiSpansionS25Fl256SIoMode::new(qspi_io_mode, true);
|
||||
let spansion_lqspi =
|
||||
spansion_qspi.into_linear_addressed(qspi_spansion::QSPI_DEV_COMBINATION_REV_F.into());
|
||||
qspi_boot(spansion_lqspi, priv_tim);
|
||||
}
|
||||
|
||||
loop {
|
||||
aarch32_cpu::asm::nop();
|
||||
}
|
||||
@@ -280,7 +256,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!
|
||||
zynq7000_hal::pl::configure_bitstream_non_secure(true, boot_bin_slice)
|
||||
devcfg::configure_bitstream_non_secure(true, boot_bin_slice)
|
||||
.expect("unexpected unaligned address");
|
||||
log::info!("loaded bitstream successfully");
|
||||
}
|
||||
@@ -328,10 +304,6 @@ fn qspi_boot(mut qspi: QspiSpansionS25Fl256SLinearMode, _priv_tim: priv_tim::Cpu
|
||||
}
|
||||
}
|
||||
|
||||
// The PL is in reset state after power-up. This method needs to be called in the first-stage
|
||||
// bootloader to put it out of reset.
|
||||
zynq7000_hal::pl::deassert_reset();
|
||||
|
||||
match opt_jump_addr {
|
||||
Some(jump_addr) => {
|
||||
log::info!("jumping to address {}", jump_addr);
|
||||
@@ -341,7 +313,6 @@ fn qspi_boot(mut qspi: QspiSpansionS25Fl256SLinearMode, _priv_tim: priv_tim::Cpu
|
||||
zynq7000_hal::cache::clean_and_invalidate_data_cache();
|
||||
aarch32_cpu::register::TlbIAll::write();
|
||||
aarch32_cpu::register::BpIAll::write();
|
||||
l2_cache::disable();
|
||||
aarch32_cpu::asm::dsb();
|
||||
aarch32_cpu::asm::isb();
|
||||
|
||||
@@ -352,26 +323,6 @@ fn qspi_boot(mut qspi: QspiSpansionS25Fl256SLinearMode, _priv_tim: priv_tim::Cpu
|
||||
}
|
||||
}
|
||||
|
||||
#[zynq7000_rt::irq]
|
||||
fn interrupt_handler() {
|
||||
let mut gic_helper = gic::GicInterruptHelper::new();
|
||||
let irq_info = gic_helper.acknowledge_interrupt();
|
||||
match irq_info.interrupt() {
|
||||
gic::Interrupt::Sgi(_) => (),
|
||||
gic::Interrupt::Ppi(ppi_interrupt) => {
|
||||
log::warn!("unexpected PPI interrupt: {:?}", ppi_interrupt);
|
||||
}
|
||||
gic::Interrupt::Spi(spi_interrupt) => {
|
||||
log::warn!("unexpected SPI interrupt: {:?}", spi_interrupt);
|
||||
}
|
||||
gic::Interrupt::Invalid(_) => (),
|
||||
gic::Interrupt::Spurious => {
|
||||
log::warn!("spurious interrupt");
|
||||
}
|
||||
}
|
||||
gic_helper.end_of_interrupt(irq_info);
|
||||
}
|
||||
|
||||
#[zynq7000_rt::exception(DataAbort)]
|
||||
fn data_abort_handler(_faulting_addr: usize) -> ! {
|
||||
loop {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/boot.bin
|
||||
@@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.2", features = ["critical-section-single-core"] }
|
||||
aarch32-cpu = { version = "0.1", features = ["critical-section-single-core"] }
|
||||
zynq7000-rt = { path = "../zynq7000-rt" }
|
||||
zynq7000 = { path = "../zynq7000" }
|
||||
zynq7000-hal = { path = "../zynq7000-hal" }
|
||||
@@ -12,6 +12,5 @@ zynq7000-boot-image = { path = "../../host/zynq7000-boot-image" }
|
||||
zedboard-bsp = { path = "../zedboard-bsp" }
|
||||
embedded-io = "0.7"
|
||||
embedded-hal = "1"
|
||||
arbitrary-int = "2"
|
||||
log = "0.4"
|
||||
libm = "0.2"
|
||||
|
||||
@@ -3,17 +3,4 @@ Zedboard QSPI flasher
|
||||
|
||||
This application flashes a boot binary generated by the AMD `bootgen` utility from DDR
|
||||
to the Zedboard QSPI. This project contains a `qspi-flasher.tcl` script which can be invoked
|
||||
with `xsct` to flash a `boot.bin` and the QSPI flasher to DDR and then run the application.
|
||||
|
||||
The main `justfile` provides a convenience runner:
|
||||
|
||||
```sh
|
||||
just flash-nor-zedboard <path to my boot.bin>
|
||||
```
|
||||
|
||||
Please note that `xsct` must be callable for this to be usable which is part of a Xilinx Vitis installation.
|
||||
|
||||
If the hardware server is running on a remote target the IP address can be specified by setting the environment variable ip_address_hw_server.
|
||||
````sh
|
||||
$ export ip_address_hw_server=<ip-address>
|
||||
````
|
||||
with `xsct` to flash a `boot.bin` and the QSPI flasher to DDR adn then run the application.
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 62 MB for now, should be plenty for a bare-metal app.
|
||||
1 MB stack memory and 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 = 62M
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
STACKS : ORIGIN = 0x3F00000, LENGTH = 1M
|
||||
/* 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
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#![no_main]
|
||||
|
||||
use aarch32_cpu::asm::nop;
|
||||
use arbitrary_int::{traits::Integer as _, u2};
|
||||
use core::panic::PanicInfo;
|
||||
use embedded_hal::{delay::DelayNs as _, digital::StatefulOutputPin as _};
|
||||
use embedded_io::Write as _;
|
||||
@@ -98,14 +97,7 @@ fn main() -> ! {
|
||||
|
||||
let qspi_io_mode = qspi.into_io_mode(false);
|
||||
|
||||
let mut spansion_qspi = qspi_spansion::QspiSpansionS25Fl256SIoMode::new(
|
||||
qspi_io_mode,
|
||||
qspi_spansion::Config {
|
||||
set_quad_bit_if_necessary: true,
|
||||
latency_config: Some(u2::ZERO),
|
||||
clear_write_protection: 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)
|
||||
@@ -129,7 +121,7 @@ fn main() -> ! {
|
||||
);
|
||||
|
||||
let mut current_addr = 0;
|
||||
let mut read_buf = [0u8; qspi_spansion::PAGE_SIZE];
|
||||
let mut read_buf = [0u8; 256];
|
||||
let mut next_checkpoint = 0.05;
|
||||
while current_addr < boot_bin_size {
|
||||
if current_addr % 0x10000 == 0 {
|
||||
@@ -145,13 +137,10 @@ fn main() -> ! {
|
||||
}
|
||||
}
|
||||
}
|
||||
let write_size = core::cmp::min(
|
||||
qspi_spansion::RECOMMENDED_PROGRAM_PAGE_SIZE,
|
||||
boot_bin_size - current_addr,
|
||||
);
|
||||
let write_size = core::cmp::min(256, boot_bin_size - current_addr);
|
||||
let write_slice = &boot_bin_slice[current_addr..current_addr + write_size];
|
||||
log::debug!("Programming address {:#x}", current_addr);
|
||||
match spansion_qspi.program(current_addr as u32, write_slice) {
|
||||
match spansion_qspi.program_page(current_addr as u32, write_slice) {
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
log::error!(
|
||||
@@ -163,7 +152,11 @@ fn main() -> ! {
|
||||
}
|
||||
}
|
||||
if VERIFY_PROGRAMMING {
|
||||
spansion_qspi.read_fast_read(current_addr as u32, &mut read_buf[0..write_size], true);
|
||||
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?}",
|
||||
|
||||
@@ -8,14 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v0.1.1] 2026-03-13
|
||||
|
||||
- Try to fix docs build for docs.rs
|
||||
|
||||
# [v0.1.0] 2026-02-14
|
||||
# [v0.1.0] 2025-10-09
|
||||
|
||||
Initial release
|
||||
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-embassy-v0.1.0...HEAD
|
||||
[v0.1.1]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-embassy-v0.1.0...zynq7000-embassy-v0.1.1
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/v0.1.0...HEAD
|
||||
[v0.1.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/tag/zynq7000-embassy-v0.1.0
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
[package]
|
||||
name = "zynq7000-embassy"
|
||||
version = "0.1.1"
|
||||
version = "0.1.0"
|
||||
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||
edition = "2024"
|
||||
description = "Embassy time support for the Zynq7000 family of SoCs"
|
||||
description = "Embassy-rs support for the Zynq7000 family of SoCs"
|
||||
homepage = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
|
||||
repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
|
||||
license = "MIT OR Apache-2.0"
|
||||
@@ -17,7 +17,3 @@ zynq7000-hal = { path = "../zynq7000-hal", version = "0.1" }
|
||||
|
||||
embassy-time-driver = "0.2"
|
||||
embassy-time-queue-utils = "0.3"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["armv7a-none-eabihf"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
[](https://docs.rs/zynq7000-embassy)
|
||||
[](https://github.com/us-irs/zynq7000-rs/actions/workflows/ci.yml)
|
||||
|
||||
# Embassy time support for the AMD Zynq7000 SoC family
|
||||
# Embassy-rs support for the AMD Zynq7000 SoC family
|
||||
|
||||
This repository contains the [embassy-rs](https://github.com/embassy-rs/embassy) time support for
|
||||
the AMD Zynq7000 SoC family. It currently provides one driver using the global timer peripheral
|
||||
provided by the Zynq7000 PS for this purpose.
|
||||
This repository contains the [embassy-rs](https://github.com/embassy-rs/embassy) support for the
|
||||
AMD Zynq7000 SoC family. Currently, it contains the time driver to allow using embassy-rs. It
|
||||
currently provides one driver using the global timer peripheral provided by the Zynq7000 PS for
|
||||
this purpose.
|
||||
|
||||
The documentation contains more information on how to use this crate.
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
//! # Embassy time support for the AMD Zynq7000 SoC family
|
||||
//!
|
||||
//! This project contains the [embassy-rs](https://github.com/embassy-rs/embassy) time support for
|
||||
//! the AMD Zynq7000 SoC family. It currently provides one driver using the global timer peripheral
|
||||
//! provided by the Zynq7000 PS for this purpose.
|
||||
//!
|
||||
//! The [crate::init] method must be called once for the time driver to work properly.
|
||||
#![no_std]
|
||||
use core::cell::{Cell, RefCell};
|
||||
|
||||
|
||||
@@ -8,28 +8,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
## Fixed
|
||||
## Changed
|
||||
|
||||
- Bugfix for DDR initialization: `calibrate_iob_impedance_for_ddr3` and `calibrate_iob_impedance`
|
||||
now expect a `zynq7000::slcr::ddriob::DdrControl` input argument. This register write was
|
||||
missing
|
||||
- Increased UART type safety by providing dedicated MIO constructors for UART 0 and UART 1
|
||||
respectively.
|
||||
- Several bugfixes and improvements for GIC module. Some of the registers previously were
|
||||
completely overwritten instead of only modifying their own bit portions. Also allow targeting
|
||||
interrupts without clearing other CPU target.
|
||||
|
||||
## 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.
|
||||
|
||||
## Added
|
||||
|
||||
- Method to de-assert PL reset.
|
||||
- ARM clock initialization for the `ArmClocks` structure
|
||||
- The `ArmClocks` structure now caches the CPU clock ratio
|
||||
|
||||
# [v0.1.1] 2025-10-10
|
||||
|
||||
Documentation fixes.
|
||||
|
||||
@@ -11,11 +11,12 @@ keywords = ["no-std", "hal", "amd", "zynq7000", "bare-metal"]
|
||||
categories = ["embedded", "no-std", "hardware-support"]
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.2" }
|
||||
zynq7000 = { path = "../zynq7000", version = "0.2" }
|
||||
aarch32-cpu = { version = "0.1" }
|
||||
zynq7000 = { path = "../zynq7000", version = "0.1" }
|
||||
zynq7000-mmu = { path = "../zynq7000-mmu", version = "0.1" }
|
||||
|
||||
static_assertions = "1.1"
|
||||
bitbybit = "2"
|
||||
bitbybit = "1.4"
|
||||
arbitrary-int = "2"
|
||||
thiserror = { version = "2", default-features = false }
|
||||
num_enum = { version = "0.7", default-features = false }
|
||||
@@ -28,27 +29,25 @@ embedded-hal-async = "1"
|
||||
heapless = "0.9"
|
||||
static_cell = "2"
|
||||
delegate = "0.13"
|
||||
pastey = "0.2.1"
|
||||
paste = "1"
|
||||
nb = "1"
|
||||
fugit = "0.3"
|
||||
critical-section = "1"
|
||||
libm = "0.2"
|
||||
log = "0.4"
|
||||
embassy-sync = "0.8"
|
||||
embassy-sync = "0.7"
|
||||
embassy-net-driver = "0.2"
|
||||
smoltcp = { version = "0.13", default-features = false, features = ["proto-ipv4", "medium-ethernet", "socket-raw"] }
|
||||
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.7"
|
||||
serde = { version = "1", optional = true, features = ["derive"] }
|
||||
defmt = { version = "1", optional = true }
|
||||
embedded-sdmmc = { git = "https://github.com/robamu/embedded-sdmmc-rs.git", branch = "all-features" }
|
||||
bytemuck = "1.25"
|
||||
|
||||
[features]
|
||||
std = ["thiserror/std", "alloc"]
|
||||
alloc = []
|
||||
defmt = ["dep:defmt", "fugit/defmt", "zynq7000/defmt"]
|
||||
defmt = ["dep:defmt", "fugit/defmt"]
|
||||
# These devices have a lower pin count.
|
||||
7z010-7z007s-clg225 = []
|
||||
|
||||
@@ -58,4 +57,5 @@ approx = "0.5"
|
||||
[package.metadata.docs.rs]
|
||||
features = ["alloc"]
|
||||
targets = ["armv7a-none-eabihf"]
|
||||
cargo-args = ["-Z", "build-std=core,alloc"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
# HAL for the AMD Zynq 7000 SoC family
|
||||
|
||||
This repository contains the **H**ardware **A**bstraction **L**ayer (HAL), which is an additional
|
||||
hardware abstraction on top of the [peripheral access API](../zynq7000).
|
||||
hardware abstraction on top of the [peripheral access API](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000).
|
||||
|
||||
It is the result of reading the datasheet for the device and encoding a type-safe layer over the
|
||||
raw PAC. This crate also implements traits specified by the
|
||||
[embedded-hal](https://github.com/rust-embedded/embedded-hal) project, making it compatible with
|
||||
various drivers in the embedded rust ecosystem.
|
||||
|
||||
The [top-level README](../../README.md) and the documentation
|
||||
The [top-level README](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs) and the documentation
|
||||
contain more information on how to use this crate.
|
||||
|
||||
@@ -3,12 +3,11 @@ use arbitrary_int::{prelude::*, u6};
|
||||
|
||||
pub mod pll;
|
||||
|
||||
pub use zynq7000::slcr::clocks::CpuClockRatio;
|
||||
use zynq7000::slcr::{
|
||||
ClockControlRegisters,
|
||||
clocks::{
|
||||
ArmClockControl, ClockRatioSelectReg, DualCommonPeriphIoClockControl, FpgaClockControl,
|
||||
GigEthClockControl, SingleCommonPeriphIoClockControl,
|
||||
ClockkRatioSelect, DualCommonPeriphIoClockControl, FpgaClockControl, GigEthClockControl,
|
||||
SingleCommonPeriphIoClockControl,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -18,7 +17,6 @@ use super::time::Hertz;
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct ArmClocks {
|
||||
ref_clk: Hertz,
|
||||
ratio: CpuClockRatio,
|
||||
cpu_1x_clk: Hertz,
|
||||
cpu_2x_clk: Hertz,
|
||||
cpu_3x2x_clk: Hertz,
|
||||
@@ -26,82 +24,23 @@ pub struct ArmClocks {
|
||||
}
|
||||
|
||||
impl ArmClocks {
|
||||
/// Configure the ARM clocks based on the ARM PLL input clock.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This changes the CPU clock frequency. You must pass the ARM PLL clock frequency and
|
||||
/// you must ensure that this is only run once during system initialization, for example
|
||||
/// in the first-stage bootloader.
|
||||
pub unsafe fn new_with_cpu_clock_init(
|
||||
arm_pll_clk: Hertz,
|
||||
clock_ratio: CpuClockRatio,
|
||||
divisor: u6,
|
||||
) -> Self {
|
||||
unsafe {
|
||||
crate::slcr::Slcr::with(|slcr| {
|
||||
slcr.clk_ctrl().write_clk_ratio_select(
|
||||
ClockRatioSelectReg::builder().with_sel(clock_ratio).build(),
|
||||
);
|
||||
slcr.clk_ctrl().write_arm_clk_ctrl(
|
||||
ArmClockControl::builder()
|
||||
.with_cpu_peri_clk_act(true)
|
||||
.with_cpu_1x_clk_act(true)
|
||||
.with_cpu_2x_clk_act(true)
|
||||
.with_cpu_3or2x_clk_act(true)
|
||||
.with_cpu_6or4x_clk_act(true)
|
||||
.with_divisor(divisor)
|
||||
.with_srcsel(zynq7000::slcr::clocks::SrcSelArm::ArmPll)
|
||||
.build(),
|
||||
);
|
||||
});
|
||||
}
|
||||
let cpu_6x4x_clk = arm_pll_clk / divisor.as_u32();
|
||||
let cpu_1x_clk = match clock_ratio {
|
||||
CpuClockRatio::FourToTwoToOne => cpu_6x4x_clk / 4,
|
||||
CpuClockRatio::SixToTwoToOne => cpu_6x4x_clk / 6,
|
||||
};
|
||||
|
||||
Self {
|
||||
ref_clk: arm_pll_clk,
|
||||
ratio: clock_ratio,
|
||||
cpu_1x_clk,
|
||||
cpu_2x_clk: cpu_1x_clk * 2,
|
||||
cpu_3x2x_clk: match clock_ratio {
|
||||
CpuClockRatio::SixToTwoToOne => cpu_1x_clk * 3,
|
||||
CpuClockRatio::FourToTwoToOne => cpu_1x_clk * 2,
|
||||
},
|
||||
cpu_6x4x_clk,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn ratio(&self) -> CpuClockRatio {
|
||||
self.ratio
|
||||
}
|
||||
|
||||
/// Reference clock provided by ARM PLL which is used to calculate all other clock frequencies.
|
||||
#[inline]
|
||||
pub const fn ref_clk(&self) -> Hertz {
|
||||
self.ref_clk
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn cpu_1x_clk(&self) -> Hertz {
|
||||
self.cpu_1x_clk
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn cpu_2x_clk(&self) -> Hertz {
|
||||
self.cpu_2x_clk
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn cpu_3x2x_clk(&self) -> Hertz {
|
||||
self.cpu_3x2x_clk
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn cpu_6x4x_clk(&self) -> Hertz {
|
||||
self.cpu_6x4x_clk
|
||||
}
|
||||
@@ -258,7 +197,6 @@ impl IoClocks {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Display impl for clock config.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct Clocks {
|
||||
@@ -339,27 +277,25 @@ impl Clocks {
|
||||
zynq7000::slcr::clocks::SrcSelArm::DdrPll => ddr_pll_out,
|
||||
zynq7000::slcr::clocks::SrcSelArm::IoPll => io_pll_out,
|
||||
};
|
||||
let clk_sel = clk_regs.read_clk_ratio_select();
|
||||
let clk_sel = clk_regs.read_clk_621_true();
|
||||
if arm_clk_ctrl.divisor().as_u32() == 0 {
|
||||
return Err(ClockReadError::DivisorZero(DivisorZero(ClockModuleId::Arm)));
|
||||
}
|
||||
let arm_clk_divided = arm_base_clk / arm_clk_ctrl.divisor().as_u32();
|
||||
let arm_clks = match clk_sel.sel() {
|
||||
CpuClockRatio::FourToTwoToOne => ArmClocks {
|
||||
ClockkRatioSelect::FourToTwoToOne => ArmClocks {
|
||||
ref_clk: arm_pll_out,
|
||||
cpu_1x_clk: arm_clk_divided / 4,
|
||||
cpu_2x_clk: arm_clk_divided / 2,
|
||||
cpu_3x2x_clk: arm_clk_divided / 2,
|
||||
cpu_6x4x_clk: arm_clk_divided,
|
||||
ratio: clk_sel.sel(),
|
||||
},
|
||||
CpuClockRatio::SixToTwoToOne => ArmClocks {
|
||||
ClockkRatioSelect::SixToTwoToOne => ArmClocks {
|
||||
ref_clk: arm_pll_out,
|
||||
cpu_1x_clk: arm_clk_divided / 6,
|
||||
cpu_2x_clk: arm_clk_divided / 3,
|
||||
cpu_3x2x_clk: arm_clk_divided / 2,
|
||||
cpu_6x4x_clk: arm_clk_divided,
|
||||
ratio: clk_sel.sel(),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ impl PllConfig {
|
||||
|
||||
/// This function configures the ARM PLL based on the provided [PllConfig].
|
||||
pub fn configure_arm_pll(boot_mode: BootMode, pll_config: PllConfig) {
|
||||
if ARM_PLL_INIT.swap(true, core::sync::atomic::Ordering::Relaxed) {
|
||||
if ARM_PLL_INIT.swap(true, core::sync::atomic::Ordering::SeqCst) {
|
||||
return;
|
||||
}
|
||||
// Safety: This will only run at most once because of the atomic boolean check.
|
||||
@@ -205,20 +205,20 @@ pub fn configure_arm_pll(boot_mode: BootMode, pll_config: PllConfig) {
|
||||
|
||||
/// This function configures the IO PLL based on the provided [PllConfig].
|
||||
pub fn configure_io_pll(boot_mode: BootMode, pll_config: PllConfig) {
|
||||
if IO_PLL_INIT.swap(true, core::sync::atomic::Ordering::Relaxed) {
|
||||
if IO_PLL_INIT.swap(true, core::sync::atomic::Ordering::SeqCst) {
|
||||
return;
|
||||
}
|
||||
// Safety: This will only run at most once because of the atomic boolean check.
|
||||
unsafe { configure_io_pll_unchecked(boot_mode, pll_config) };
|
||||
unsafe { configure_arm_pll_unchecked(boot_mode, pll_config) };
|
||||
}
|
||||
|
||||
/// This function configures the DDR PLL based on the provided [PllConfig].
|
||||
pub fn configure_ddr_pll(boot_mode: BootMode, pll_config: PllConfig) {
|
||||
if DDR_PLL_INIT.swap(true, core::sync::atomic::Ordering::Relaxed) {
|
||||
if DDR_PLL_INIT.swap(true, core::sync::atomic::Ordering::SeqCst) {
|
||||
return;
|
||||
}
|
||||
// Safety: This will only run at most once because of the atomic boolean check.
|
||||
unsafe { configure_ddr_pll_unchecked(boot_mode, pll_config) };
|
||||
unsafe { configure_arm_pll_unchecked(boot_mode, pll_config) };
|
||||
}
|
||||
|
||||
/// This function configures the ARM PLL based on the provided [PllConfig].
|
||||
|
||||
@@ -86,42 +86,20 @@ pub unsafe fn configure_dci(ddr_clk: &DdrClocks) {
|
||||
///
|
||||
/// This function writes to the DDR IOB related registers. It should only be called once during
|
||||
/// DDR initialization.
|
||||
pub unsafe fn calibrate_iob_impedance_for_ddr3(
|
||||
ddr_control: zynq7000::slcr::ddriob::DdrControl,
|
||||
dci_clk_cfg: DciClkConfig,
|
||||
poll_for_done: bool,
|
||||
) {
|
||||
pub unsafe fn calibrate_iob_impedance_for_ddr3(dci_clk_cfg: DciClkConfig, poll_for_done: bool) {
|
||||
unsafe {
|
||||
calibrate_iob_impedance(
|
||||
ddr_control,
|
||||
dci_clk_cfg,
|
||||
CalibrationParams::new_ddr3(),
|
||||
u3::new(0),
|
||||
u2::new(0),
|
||||
u3::new(0b001),
|
||||
u3::new(0),
|
||||
u2::new(0),
|
||||
poll_for_done,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// DDR IOB impedance calibration parameters.
|
||||
pub struct CalibrationParams {
|
||||
pub pref_opt2: u3,
|
||||
pub pref_opt1: u2,
|
||||
pub nref_opt4: u3,
|
||||
pub nref_opt2: u3,
|
||||
pub nref_opt1: u2,
|
||||
}
|
||||
|
||||
impl CalibrationParams {
|
||||
pub const fn new_ddr3() -> Self {
|
||||
Self {
|
||||
pref_opt2: u3::new(0),
|
||||
pref_opt1: u2::new(0),
|
||||
nref_opt4: u3::new(0b001),
|
||||
nref_opt2: u3::new(0),
|
||||
nref_opt1: u2::new(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Calibrates the IOB impedance according to to TRM p.325, DDR IOB Impedance calibration.
|
||||
///
|
||||
/// This function will also enable the DCI clock with the provided clock configuration.
|
||||
@@ -137,9 +115,12 @@ impl CalibrationParams {
|
||||
/// This function writes to the DDR IOB related registers. It should only be called once during
|
||||
/// DDR initialization.
|
||||
pub unsafe fn calibrate_iob_impedance(
|
||||
ddr_control: zynq7000::slcr::ddriob::DdrControl,
|
||||
dci_clk_cfg: DciClkConfig,
|
||||
calibration_params: CalibrationParams,
|
||||
pref_opt2: u3,
|
||||
pref_opt1: u2,
|
||||
nref_opt4: u3,
|
||||
nref_opt2: u3,
|
||||
nref_opt1: u2,
|
||||
poll_for_done: bool,
|
||||
) {
|
||||
// Safety: Only writes to DDR IOB related registers.
|
||||
@@ -153,23 +134,31 @@ pub unsafe fn calibrate_iob_impedance(
|
||||
.build(),
|
||||
);
|
||||
let mut ddriob = slcr.ddriob();
|
||||
ddriob.write_ddr_control(ddr_control);
|
||||
ddriob.modify_dci_control(|val| val.with_reset(true));
|
||||
ddriob.modify_dci_control(|val| val.with_reset(false));
|
||||
ddriob.modify_dci_control(|val| val.with_reset(true));
|
||||
ddriob.modify_dci_control(|mut val| {
|
||||
val.set_pref_opt2(calibration_params.pref_opt2);
|
||||
val.set_pref_opt1(calibration_params.pref_opt1);
|
||||
val.set_nref_opt4(calibration_params.nref_opt4);
|
||||
val.set_nref_opt2(calibration_params.nref_opt2);
|
||||
val.set_nref_opt1(calibration_params.nref_opt1);
|
||||
ddriob.modify_dci_ctrl(|mut val| {
|
||||
val.set_reset(true);
|
||||
val
|
||||
});
|
||||
ddriob.modify_dci_control(|mut val| {
|
||||
ddriob.modify_dci_ctrl(|mut val| {
|
||||
val.set_reset(false);
|
||||
val
|
||||
});
|
||||
ddriob.modify_dci_ctrl(|mut val| {
|
||||
val.set_reset(true);
|
||||
val
|
||||
});
|
||||
ddriob.modify_dci_ctrl(|mut val| {
|
||||
val.set_pref_opt2(pref_opt2);
|
||||
val.set_pref_opt1(pref_opt1);
|
||||
val.set_nref_opt4(nref_opt4);
|
||||
val.set_nref_opt2(nref_opt2);
|
||||
val.set_nref_opt1(nref_opt1);
|
||||
val
|
||||
});
|
||||
ddriob.modify_dci_ctrl(|mut val| {
|
||||
val.set_update_control(false);
|
||||
val
|
||||
});
|
||||
ddriob.modify_dci_control(|mut val| {
|
||||
ddriob.modify_dci_ctrl(|mut val| {
|
||||
val.set_enable(true);
|
||||
val
|
||||
});
|
||||
@@ -181,7 +170,6 @@ pub unsafe fn calibrate_iob_impedance(
|
||||
|
||||
/// Static configuration for DDR IOBs.
|
||||
pub struct DdriobConfigSet {
|
||||
pub ddr_control: zynq7000::slcr::ddriob::DdrControl,
|
||||
pub addr0: DdriobConfig,
|
||||
pub addr1: DdriobConfig,
|
||||
pub data0: DdriobConfig,
|
||||
|
||||
@@ -76,7 +76,7 @@ pub fn configure_ddr_for_ddr3(
|
||||
ll::configure_iob(ddriob_cfg);
|
||||
// Do not wait for completion, it takes a bit of time. We can set all the DDR config registers
|
||||
// before polling for completion.
|
||||
ll::calibrate_iob_impedance_for_ddr3(ddriob_cfg.ddr_control, dci_clk_cfg, false);
|
||||
ll::calibrate_iob_impedance_for_ddr3(dci_clk_cfg, false);
|
||||
}
|
||||
ll::configure_ddr_config(&mut ddrc_regs, ddr_cfg);
|
||||
// Safety: This is only called once during DDR initialization, and we only modify DDR related
|
||||
@@ -129,7 +129,7 @@ pub mod memtest {
|
||||
/// This tests writes and reads on a memory block starting at the base address
|
||||
/// with the size `words` times 4.
|
||||
pub unsafe fn walking_one_test(base_addr: usize, words: usize) -> Result<(), MemTestError> {
|
||||
unsafe { walking_value_test(false, base_addr, words) }
|
||||
unsafe { walking_value_test(true, base_addr, words) }
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
|
||||
@@ -1,33 +1,4 @@
|
||||
//! # 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(),
|
||||
);
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
//! # Device Configuration Module
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("unaligned address: {0}")]
|
||||
pub struct UnalignedAddrError(usize);
|
||||
@@ -82,14 +53,10 @@ pub fn configure_bitstream_non_secure(
|
||||
val.set_pcap_rate_enable(false);
|
||||
val
|
||||
});
|
||||
|
||||
// As specified in the TMR,
|
||||
// Setting the two LSBs of the source and destination address to 2'b01 indicates to the DevC
|
||||
// DMA module the last DMA command of an overall transfer
|
||||
devcfg.write_dma_source_addr(bitstream.as_ptr() as u32 | 0b01);
|
||||
devcfg.write_dma_source_addr(bitstream.as_ptr() as u32);
|
||||
devcfg.write_dma_dest_addr(0xFFFF_FFFF);
|
||||
devcfg.write_dma_source_len(bitstream.len() as u32 / 4);
|
||||
devcfg.write_dma_dest_len(bitstream.len() as u32 / 4);
|
||||
devcfg.write_dma_source_len(bitstream.len() as u32);
|
||||
devcfg.write_dma_dest_len(bitstream.len() as u32);
|
||||
|
||||
while !devcfg.read_interrupt_status().dma_done() {}
|
||||
// TODO: Check for errors.
|
||||
@@ -8,6 +8,11 @@ use crate::{clocks::IoClocks, enable_amba_peripheral_clock, slcr::Slcr, time::He
|
||||
|
||||
use super::{EthernetId, PsEthernet as _};
|
||||
|
||||
pub struct EthernetLowLevel {
|
||||
id: EthernetId,
|
||||
pub regs: zynq7000::eth::MmioRegisters<'static>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Speed {
|
||||
Mbps10,
|
||||
@@ -47,10 +52,7 @@ impl ClockDivisors {
|
||||
|
||||
/// Calls [Self::calculate_for_rgmii], assuming that the IO clock is the reference clock,
|
||||
/// which is the default clock for the Ethernet module.
|
||||
pub fn calculate_for_rgmii_and_io_clock(
|
||||
io_clks: &IoClocks,
|
||||
target_speed: Speed,
|
||||
) -> (Self, u32) {
|
||||
pub fn calculate_for_rgmii_and_io_clock(io_clks: IoClocks, target_speed: Speed) -> (Self, u32) {
|
||||
Self::calculate_for_rgmii(io_clks.ref_clk(), target_speed)
|
||||
}
|
||||
|
||||
@@ -172,17 +174,8 @@ impl ClockDivSet {
|
||||
/// Ethernet low-level interface.
|
||||
///
|
||||
/// Basic building block for higher-level abstraction.
|
||||
pub struct EthernetLowLevel {
|
||||
id: EthernetId,
|
||||
/// Register block. Direct public access is allowed to allow low-level operations.
|
||||
pub regs: zynq7000::eth::MmioRegisters<'static>,
|
||||
}
|
||||
|
||||
impl EthernetLowLevel {
|
||||
/// Creates a new instance of the Ethernet low-level interface.
|
||||
///
|
||||
/// Returns [None] if the given registers block base address does not correspond to a valid
|
||||
/// Ethernet peripheral.
|
||||
#[inline]
|
||||
pub fn new(regs: zynq7000::eth::MmioRegisters<'static>) -> Option<Self> {
|
||||
regs.id()?;
|
||||
@@ -211,7 +204,33 @@ impl EthernetLowLevel {
|
||||
}
|
||||
|
||||
pub fn reset(&mut self, cycles: usize) {
|
||||
reset(self.id, cycles);
|
||||
let assert_reset = match self.id {
|
||||
EthernetId::Eth0 => EthernetReset::builder()
|
||||
.with_gem1_ref_rst(false)
|
||||
.with_gem0_ref_rst(true)
|
||||
.with_gem1_rx_rst(false)
|
||||
.with_gem0_rx_rst(true)
|
||||
.with_gem1_cpu1x_rst(false)
|
||||
.with_gem0_cpu1x_rst(true)
|
||||
.build(),
|
||||
EthernetId::Eth1 => EthernetReset::builder()
|
||||
.with_gem1_ref_rst(true)
|
||||
.with_gem0_ref_rst(false)
|
||||
.with_gem1_rx_rst(true)
|
||||
.with_gem0_rx_rst(false)
|
||||
.with_gem1_cpu1x_rst(true)
|
||||
.with_gem0_cpu1x_rst(false)
|
||||
.build(),
|
||||
};
|
||||
unsafe {
|
||||
Slcr::with(|regs| {
|
||||
regs.reset_ctrl().write_eth(assert_reset);
|
||||
for _ in 0..cycles {
|
||||
aarch32_cpu::asm::nop();
|
||||
}
|
||||
regs.reset_ctrl().write_eth(EthernetReset::DEFAULT);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -364,34 +383,3 @@ impl EthernetLowLevel {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
/// Resets the Ethernet peripheral with the given ID.
|
||||
pub fn reset(id: EthernetId, cycles: usize) {
|
||||
let assert_reset = match id {
|
||||
EthernetId::Eth0 => EthernetReset::builder()
|
||||
.with_gem1_ref_rst(false)
|
||||
.with_gem0_ref_rst(true)
|
||||
.with_gem1_rx_rst(false)
|
||||
.with_gem0_rx_rst(true)
|
||||
.with_gem1_cpu1x_rst(false)
|
||||
.with_gem0_cpu1x_rst(true)
|
||||
.build(),
|
||||
EthernetId::Eth1 => EthernetReset::builder()
|
||||
.with_gem1_ref_rst(true)
|
||||
.with_gem0_ref_rst(false)
|
||||
.with_gem1_rx_rst(true)
|
||||
.with_gem0_rx_rst(false)
|
||||
.with_gem1_cpu1x_rst(true)
|
||||
.with_gem0_cpu1x_rst(false)
|
||||
.build(),
|
||||
};
|
||||
unsafe {
|
||||
Slcr::with(|regs| {
|
||||
regs.reset_ctrl().write_eth(assert_reset);
|
||||
for _ in 0..cycles {
|
||||
aarch32_cpu::asm::nop();
|
||||
}
|
||||
regs.reset_ctrl().write_eth(EthernetReset::DEFAULT);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ pub trait PinId {
|
||||
macro_rules! pin_id {
|
||||
($Id:ident, $num:literal) => {
|
||||
// Need paste macro to use ident in doc attribute
|
||||
pastey::paste! {
|
||||
paste::paste! {
|
||||
#[doc = "Pin ID representing pin " $Id]
|
||||
#[derive(Debug)]
|
||||
pub enum $Id {}
|
||||
|
||||
@@ -18,11 +18,7 @@ unsafe impl Send for GlobalTimerCounter {}
|
||||
|
||||
/// Convert a frequency to GTC ticks given a clock frequency.
|
||||
pub const fn frequency_to_ticks(clock: Hertz, frequency: Hertz) -> u32 {
|
||||
if frequency.raw() != 0 {
|
||||
clock.raw().div_ceil(frequency.raw())
|
||||
} else {
|
||||
0
|
||||
}
|
||||
clock.raw().div_ceil(frequency.raw())
|
||||
}
|
||||
|
||||
impl GlobalTimerCounter {
|
||||
|
||||
@@ -81,10 +81,3 @@ pub fn init(
|
||||
}
|
||||
l2c_mmio.write_control(Control::new_enabled());
|
||||
}
|
||||
|
||||
/// Disable the L2 cache.
|
||||
#[inline]
|
||||
pub fn disable() {
|
||||
let mut l2c_mmio = unsafe { zynq7000::l2_cache::Registers::new_mmio_fixed() };
|
||||
l2c_mmio.write_control(Control::new_disabled());
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
pub use slcr::Slcr;
|
||||
use slcr::Slcr;
|
||||
use zynq7000::{
|
||||
SpiClockPhase, SpiClockPolarity,
|
||||
slcr::{BootModeRegister, BootPllConfig, LevelShifterRegister},
|
||||
@@ -27,6 +27,7 @@ use zynq7000::{
|
||||
pub mod cache;
|
||||
pub mod clocks;
|
||||
pub mod ddr;
|
||||
pub mod devcfg;
|
||||
pub mod eth;
|
||||
pub mod gic;
|
||||
pub mod gpio;
|
||||
@@ -34,11 +35,9 @@ 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;
|
||||
pub mod sd;
|
||||
pub mod slcr;
|
||||
pub mod spi;
|
||||
pub mod time;
|
||||
|
||||
@@ -8,7 +8,7 @@ use zynq7000::{
|
||||
BaudRateDivisor, Config, InstructionCode, InterruptStatus, LoopbackMasterClockDelay,
|
||||
SpiEnable,
|
||||
},
|
||||
slcr::{clocks::SingleCommonPeriphIoClockControl, mio::Speed, reset::ResetControlQspiSmc},
|
||||
slcr::{clocks::SingleCommonPeriphIoClockControl, mio::Speed, reset::QspiResetControl},
|
||||
};
|
||||
|
||||
pub use embedded_hal::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode};
|
||||
@@ -35,12 +35,6 @@ pub(crate) mod lqspi_configs;
|
||||
|
||||
pub const QSPI_MUX_CONFIG: MuxConfig = MuxConfig::new_with_l0();
|
||||
pub const FIFO_DEPTH: usize = 63;
|
||||
/// From the TRM:
|
||||
///
|
||||
/// > The maximum number of bytes per command sequence in this mode is limited by the depth of the
|
||||
/// > TxFIFO of 252 bytes.
|
||||
pub const MAX_BYTES_PER_TRANSFER_IO_MODE: usize = FIFO_DEPTH * 4;
|
||||
|
||||
/// In linear-addressed mode, the QSPI is memory-mapped, with the address starting here.
|
||||
pub const QSPI_START_ADDRESS: usize = 0xFC00_0000;
|
||||
|
||||
@@ -267,9 +261,7 @@ impl ClockConfig {
|
||||
if qspi_ref_clk < clocks.arm_clocks().cpu_1x_clk() {
|
||||
return Err(ClockCalculationError::RefClockSmallerThanCpu1xClock);
|
||||
}
|
||||
let qspi_baud_rate_div = qspi_ref_clk
|
||||
.raw()
|
||||
.div_ceil(target_qspi_interface_clock.raw());
|
||||
let qspi_baud_rate_div = qspi_ref_clk / target_qspi_interface_clock;
|
||||
let baud_rate_div = match qspi_baud_rate_div {
|
||||
0..=2 => BaudRateDivisor::_2,
|
||||
3..=4 => BaudRateDivisor::_4,
|
||||
@@ -417,7 +409,7 @@ impl Qspi {
|
||||
.with_disable_hstl_rcvr(false)
|
||||
.with_pullup(true)
|
||||
.with_io_type(voltage)
|
||||
.with_speed(Speed::FastCmosEdge)
|
||||
.with_speed(Speed::SlowCmosEdge)
|
||||
.with_l3_sel(QSPI_MUX_CONFIG.l3_sel())
|
||||
.with_l2_sel(QSPI_MUX_CONFIG.l2_sel())
|
||||
.with_l1_sel(QSPI_MUX_CONFIG.l1_sel())
|
||||
@@ -429,7 +421,7 @@ impl Qspi {
|
||||
.with_disable_hstl_rcvr(false)
|
||||
.with_pullup(false)
|
||||
.with_io_type(voltage)
|
||||
.with_speed(Speed::FastCmosEdge)
|
||||
.with_speed(Speed::SlowCmosEdge)
|
||||
.with_l3_sel(QSPI_MUX_CONFIG.l3_sel())
|
||||
.with_l2_sel(QSPI_MUX_CONFIG.l2_sel())
|
||||
.with_l1_sel(QSPI_MUX_CONFIG.l1_sel())
|
||||
@@ -471,7 +463,7 @@ impl Qspi {
|
||||
.with_disable_hstl_rcvr(false)
|
||||
.with_pullup(false)
|
||||
.with_io_type(voltage)
|
||||
.with_speed(Speed::FastCmosEdge)
|
||||
.with_speed(Speed::SlowCmosEdge)
|
||||
.with_l3_sel(QSPI_MUX_CONFIG.l3_sel())
|
||||
.with_l2_sel(QSPI_MUX_CONFIG.l2_sel())
|
||||
.with_l1_sel(QSPI_MUX_CONFIG.l1_sel())
|
||||
@@ -675,16 +667,16 @@ pub fn reset() {
|
||||
unsafe {
|
||||
Slcr::with(|regs| {
|
||||
regs.reset_ctrl().write_lqspi(
|
||||
ResetControlQspiSmc::builder()
|
||||
.with_ref_reset(true)
|
||||
QspiResetControl::builder()
|
||||
.with_qspi_ref_reset(true)
|
||||
.with_cpu_1x_reset(true)
|
||||
.build(),
|
||||
);
|
||||
// Keep it in reset for some cycles.
|
||||
for _ in 0..10 {
|
||||
for _ in 0..3 {
|
||||
aarch32_cpu::asm::nop();
|
||||
}
|
||||
regs.reset_ctrl().write_lqspi(ResetControlQspiSmc::DEFAULT);
|
||||
regs.reset_ctrl().write_lqspi(QspiResetControl::DEFAULT);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
use arbitrary_int::u6;
|
||||
use zynq7000::sdio::{BlockSelect, CommandRegister, ResponseType};
|
||||
|
||||
use embedded_sdmmc::sdcard::{AcmdId, CmdId};
|
||||
|
||||
pub struct CommandConfig {
|
||||
pub id: u6,
|
||||
pub response_type: ResponseType,
|
||||
pub index_check: bool,
|
||||
pub crc_check: bool,
|
||||
}
|
||||
|
||||
impl CommandConfig {
|
||||
pub const fn new_no_response(id: u6) -> Self {
|
||||
Self {
|
||||
id,
|
||||
response_type: ResponseType::None,
|
||||
index_check: false,
|
||||
crc_check: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn new_with_r1_response(id: u6) -> Self {
|
||||
Self {
|
||||
id,
|
||||
response_type: ResponseType::_48bits,
|
||||
index_check: true,
|
||||
crc_check: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn new_with_r2_response(id: u6) -> Self {
|
||||
Self {
|
||||
id,
|
||||
response_type: ResponseType::_136bits,
|
||||
index_check: false,
|
||||
crc_check: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn new_with_r3_response(id: u6) -> Self {
|
||||
Self {
|
||||
id,
|
||||
response_type: ResponseType::_48bits,
|
||||
index_check: false,
|
||||
crc_check: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn new_with_r6_response(id: u6) -> Self {
|
||||
Self {
|
||||
id,
|
||||
response_type: ResponseType::_48bitsWithCheck,
|
||||
index_check: false,
|
||||
crc_check: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn build_command_without_data(config: CommandConfig) -> CommandRegister {
|
||||
CommandRegister::builder()
|
||||
.with_command_index(config.id)
|
||||
.with_command_type(zynq7000::sdio::CommandType::Normal)
|
||||
.with_data_is_present(false)
|
||||
.with_command_index_check_enable(config.index_check)
|
||||
.with_command_crc_check_enable(config.crc_check)
|
||||
.with_response_type_select(config.response_type)
|
||||
.with_block_select(zynq7000::sdio::BlockSelect::SingleBlock)
|
||||
.with_data_transfer_direction(zynq7000::sdio::TransferDirection::Write)
|
||||
.with_auto_cmd12_enable(false)
|
||||
.with_block_count_enable(false)
|
||||
.with_dma_enable(false)
|
||||
.build()
|
||||
}
|
||||
|
||||
pub const CMD0_GO_IDLE_MODE: CommandRegister = build_command_without_data(
|
||||
CommandConfig::new_no_response(CmdId::CMD0_GoIdleState.raw_value()),
|
||||
);
|
||||
pub const CMD2_ALL_SEND_CID: CommandRegister = build_command_without_data(
|
||||
CommandConfig::new_with_r2_response(CmdId::CMD2_AllSendCid.raw_value()),
|
||||
);
|
||||
pub const CMD3_SEND_RELATIVE_ADDR: CommandRegister = build_command_without_data(
|
||||
CommandConfig::new_with_r6_response(CmdId::CMD3_SendRelativeAddr.raw_value()),
|
||||
);
|
||||
pub const CMD7_SELECT_SD_CARD: CommandRegister = build_command_without_data(
|
||||
CommandConfig::new_with_r1_response(CmdId::CMD7_SelectCard.raw_value()),
|
||||
);
|
||||
pub const CMD8_SEND_IF_COND: CommandRegister = build_command_without_data(
|
||||
CommandConfig::new_with_r1_response(CmdId::CMD8_SendIfCond.raw_value()),
|
||||
);
|
||||
pub const CMD9_SEND_CSD: CommandRegister = build_command_without_data(
|
||||
CommandConfig::new_with_r2_response(CmdId::CMD9_SendCsd.raw_value()),
|
||||
);
|
||||
pub const CMD13_SEND_STATUS: CommandRegister = build_command_without_data(
|
||||
CommandConfig::new_with_r1_response(CmdId::CMD13_SendStatus.raw_value()),
|
||||
);
|
||||
pub const CMD17_READ_SINGLE_BLOCK: CommandRegister = CommandRegister::builder()
|
||||
.with_command_index(CmdId::CMD17_ReadSingleBlock.raw_value())
|
||||
.with_command_type(zynq7000::sdio::CommandType::Normal)
|
||||
.with_data_is_present(true)
|
||||
.with_command_index_check_enable(true)
|
||||
.with_command_crc_check_enable(true)
|
||||
.with_response_type_select(ResponseType::_48bits)
|
||||
.with_block_select(BlockSelect::SingleBlock)
|
||||
.with_data_transfer_direction(zynq7000::sdio::TransferDirection::Read)
|
||||
.with_auto_cmd12_enable(false)
|
||||
.with_block_count_enable(false)
|
||||
.with_dma_enable(false)
|
||||
.build();
|
||||
pub const CMD24_WRITE_BLOCK: CommandRegister = CommandRegister::builder()
|
||||
.with_command_index(CmdId::CMD24_WriteBlock.raw_value())
|
||||
.with_command_type(zynq7000::sdio::CommandType::Normal)
|
||||
.with_data_is_present(true)
|
||||
.with_command_index_check_enable(true)
|
||||
.with_command_crc_check_enable(true)
|
||||
.with_response_type_select(ResponseType::_48bits)
|
||||
.with_block_select(BlockSelect::SingleBlock)
|
||||
.with_data_transfer_direction(zynq7000::sdio::TransferDirection::Write)
|
||||
.with_auto_cmd12_enable(false)
|
||||
.with_block_count_enable(false)
|
||||
.with_dma_enable(false)
|
||||
.build();
|
||||
|
||||
pub const CMD55_APP_CMD: CommandRegister = build_command_without_data(
|
||||
CommandConfig::new_with_r1_response(CmdId::CMD55_AppCmd.raw_value()),
|
||||
);
|
||||
pub const ACMD6_SET_BUS_WIDTH: CommandRegister = build_command_without_data(
|
||||
CommandConfig::new_with_r1_response(AcmdId::ACMD6_SetBusWidth.raw_value()),
|
||||
);
|
||||
pub const ACMD41_SEND_IF_COND: CommandRegister = build_command_without_data(
|
||||
CommandConfig::new_with_r3_response(AcmdId::ACMD41_SdSendOpCond.raw_value()),
|
||||
);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,99 +0,0 @@
|
||||
use crate::gpio::mio::{
|
||||
Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, Mio32, Mio33, Mio34,
|
||||
Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, MioPin, Pin,
|
||||
};
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
use crate::gpio::mio::{
|
||||
Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40,
|
||||
Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51,
|
||||
};
|
||||
|
||||
pub trait Sdio0ClockPin: MioPin {}
|
||||
pub trait Sdio0CommandPin: MioPin {}
|
||||
pub trait Sdio0Data0Pin: MioPin {}
|
||||
pub trait Sdio0Data1Pin: MioPin {}
|
||||
pub trait Sdio0Data2Pin: MioPin {}
|
||||
pub trait Sdio0Data3Pin: MioPin {}
|
||||
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0ClockPin for Pin<Mio16> {}
|
||||
impl Sdio0ClockPin for Pin<Mio28> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0ClockPin for Pin<Mio40> {}
|
||||
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0CommandPin for Pin<Mio17> {}
|
||||
impl Sdio0CommandPin for Pin<Mio29> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0CommandPin for Pin<Mio41> {}
|
||||
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0Data0Pin for Pin<Mio18> {}
|
||||
impl Sdio0Data0Pin for Pin<Mio30> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0Data0Pin for Pin<Mio42> {}
|
||||
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0Data1Pin for Pin<Mio19> {}
|
||||
impl Sdio0Data1Pin for Pin<Mio31> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0Data1Pin for Pin<Mio43> {}
|
||||
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0Data2Pin for Pin<Mio20> {}
|
||||
impl Sdio0Data2Pin for Pin<Mio32> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0Data2Pin for Pin<Mio44> {}
|
||||
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0Data3Pin for Pin<Mio21> {}
|
||||
impl Sdio0Data3Pin for Pin<Mio33> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0Data3Pin for Pin<Mio45> {}
|
||||
|
||||
pub trait Sdio1ClockPin: MioPin {}
|
||||
pub trait Sdio1CommandPin: MioPin {}
|
||||
pub trait Sdio1Data0Pin: MioPin {}
|
||||
pub trait Sdio1Data1Pin: MioPin {}
|
||||
pub trait Sdio1Data2Pin: MioPin {}
|
||||
pub trait Sdio1Data3Pin: MioPin {}
|
||||
|
||||
impl Sdio1ClockPin for Pin<Mio12> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio1ClockPin for Pin<Mio24> {}
|
||||
impl Sdio1ClockPin for Pin<Mio36> {}
|
||||
impl Sdio1ClockPin for Pin<Mio48> {}
|
||||
|
||||
impl Sdio1CommandPin for Pin<Mio11> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio1CommandPin for Pin<Mio23> {}
|
||||
impl Sdio1CommandPin for Pin<Mio35> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio1CommandPin for Pin<Mio47> {}
|
||||
|
||||
impl Sdio1Data0Pin for Pin<Mio10> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio1Data0Pin for Pin<Mio22> {}
|
||||
impl Sdio1Data0Pin for Pin<Mio34> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio1Data0Pin for Pin<Mio46> {}
|
||||
|
||||
impl Sdio1Data1Pin for Pin<Mio13> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio1Data1Pin for Pin<Mio25> {}
|
||||
impl Sdio1Data1Pin for Pin<Mio37> {}
|
||||
impl Sdio1Data1Pin for Pin<Mio49> {}
|
||||
|
||||
impl Sdio1Data2Pin for Pin<Mio14> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio1Data2Pin for Pin<Mio26> {}
|
||||
impl Sdio1Data2Pin for Pin<Mio38> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio1Data2Pin for Pin<Mio50> {}
|
||||
|
||||
impl Sdio1Data2Pin for Pin<Mio15> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio1Data3Pin for Pin<Mio27> {}
|
||||
impl Sdio1Data3Pin for Pin<Mio39> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio1Data3Pin for Pin<Mio51> {}
|
||||
@@ -18,7 +18,8 @@ use crate::{clocks::IoClocks, slcr::Slcr, time::Hertz};
|
||||
use arbitrary_int::{prelude::*, u3, u4, u6};
|
||||
use embedded_hal::delay::DelayNs;
|
||||
pub use embedded_hal::spi::Mode;
|
||||
use zynq7000::slcr::reset::DualRefAndClockResetSpiUart;
|
||||
use embedded_hal::spi::SpiBus as _;
|
||||
use zynq7000::slcr::reset::DualRefAndClockReset;
|
||||
use zynq7000::spi::{
|
||||
BaudDivSel, DelayControl, FifoWrite, InterruptControl, InterruptMask, InterruptStatus,
|
||||
MmioRegisters, SPI_0_BASE_ADDR, SPI_1_BASE_ADDR,
|
||||
@@ -873,7 +874,7 @@ impl Spi {
|
||||
fn prepare_generic_blocking_transfer(&mut self, words: &[u8]) -> usize {
|
||||
// We want to ensure the FIFO is empty for a new transfer. This is the simpler
|
||||
// implementation for now.
|
||||
self.flush();
|
||||
self.flush().unwrap();
|
||||
// Write this to 1 in any case to allow polling, defensive programming.
|
||||
self.inner.regs.write_rx_trig(1);
|
||||
|
||||
@@ -885,14 +886,20 @@ impl Spi {
|
||||
self.issue_manual_start_for_manual_cfg();
|
||||
written
|
||||
}
|
||||
}
|
||||
|
||||
fn read(&mut self, words: &mut [u8]) {
|
||||
impl embedded_hal::spi::ErrorType for Spi {
|
||||
type Error = Infallible;
|
||||
}
|
||||
|
||||
impl embedded_hal::spi::SpiBus for Spi {
|
||||
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
|
||||
if words.is_empty() {
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
// We want to ensure the FIFO is empty for a new transfer. This is the simpler
|
||||
// implementation for now.
|
||||
self.flush();
|
||||
self.flush()?;
|
||||
// Write this to 1 in any case to allow polling, defensive programming.
|
||||
self.regs().write_rx_trig(1);
|
||||
|
||||
@@ -919,11 +926,13 @@ impl Spi {
|
||||
write_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write(&mut self, words: &[u8]) {
|
||||
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
|
||||
if words.is_empty() {
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
let mut written = self.prepare_generic_blocking_transfer(words);
|
||||
let mut read_idx = 0;
|
||||
@@ -945,11 +954,12 @@ impl Spi {
|
||||
// We use the FIFO trigger mechanism to determine when we can read all the remaining bytes.
|
||||
self.regs().write_rx_trig((words.len() - read_idx) as u32);
|
||||
self.outstanding_rx = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn transfer(&mut self, read: &mut [u8], write: &[u8]) {
|
||||
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
|
||||
if read.is_empty() {
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
let mut write_idx = self.prepare_generic_blocking_transfer(write);
|
||||
let mut read_idx = 0;
|
||||
@@ -981,11 +991,13 @@ impl Spi {
|
||||
writes_finished = write_idx == max_idx;
|
||||
reads_finished = read_idx == max_idx;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn transfer_in_place(&mut self, words: &mut [u8]) {
|
||||
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
|
||||
if words.is_empty() {
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
let mut write_idx = self.prepare_generic_blocking_transfer(words);
|
||||
let mut read_idx = 0;
|
||||
@@ -1006,12 +1018,14 @@ impl Spi {
|
||||
writes_finished = write_idx == words.len();
|
||||
reads_finished = read_idx == words.len();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Blocking flush implementation.
|
||||
fn flush(&mut self) {
|
||||
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
if !self.outstanding_rx {
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
let rx_trig = self.inner.read_rx_not_empty_threshold();
|
||||
while !self.inner.read_isr().rx_not_empty() {}
|
||||
@@ -1020,37 +1034,6 @@ impl Spi {
|
||||
});
|
||||
self.inner.set_rx_fifo_trigger(1).unwrap();
|
||||
self.outstanding_rx = false;
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_hal::spi::ErrorType for Spi {
|
||||
type Error = Infallible;
|
||||
}
|
||||
|
||||
impl embedded_hal::spi::SpiBus for Spi {
|
||||
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
|
||||
Self::read(self, words);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
|
||||
Self::write(self, words);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
|
||||
Self::transfer(self, read, write);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
|
||||
Self::transfer_in_place(self, words);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Blocking flush implementation.
|
||||
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
Self::flush(self);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1084,23 +1067,23 @@ impl<Delay: DelayNs> embedded_hal::spi::SpiDevice for SpiWithHwCs<Delay> {
|
||||
for op in operations {
|
||||
match op {
|
||||
embedded_hal::spi::Operation::Read(items) => {
|
||||
self.spi.read(items);
|
||||
self.spi.read(items)?;
|
||||
}
|
||||
embedded_hal::spi::Operation::Write(items) => {
|
||||
self.spi.write(items);
|
||||
self.spi.write(items)?;
|
||||
}
|
||||
embedded_hal::spi::Operation::Transfer(read, write) => {
|
||||
self.spi.transfer(read, write);
|
||||
self.spi.transfer(read, write)?;
|
||||
}
|
||||
embedded_hal::spi::Operation::TransferInPlace(items) => {
|
||||
self.spi.transfer_in_place(items);
|
||||
self.spi.transfer_in_place(items)?;
|
||||
}
|
||||
embedded_hal::spi::Operation::DelayNs(delay) => {
|
||||
self.delay.delay_ns(*delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.spi.flush();
|
||||
self.spi.flush()?;
|
||||
self.spi.inner.no_hw_cs();
|
||||
Ok(())
|
||||
}
|
||||
@@ -1113,13 +1096,13 @@ impl<Delay: DelayNs> embedded_hal::spi::SpiDevice for SpiWithHwCs<Delay> {
|
||||
#[inline]
|
||||
pub fn reset(id: SpiId) {
|
||||
let assert_reset = match id {
|
||||
SpiId::Spi0 => DualRefAndClockResetSpiUart::builder()
|
||||
SpiId::Spi0 => DualRefAndClockReset::builder()
|
||||
.with_periph1_ref_rst(false)
|
||||
.with_periph0_ref_rst(true)
|
||||
.with_periph1_cpu1x_rst(false)
|
||||
.with_periph0_cpu1x_rst(true)
|
||||
.build(),
|
||||
SpiId::Spi1 => DualRefAndClockResetSpiUart::builder()
|
||||
SpiId::Spi1 => DualRefAndClockReset::builder()
|
||||
.with_periph1_ref_rst(true)
|
||||
.with_periph0_ref_rst(false)
|
||||
.with_periph1_cpu1x_rst(true)
|
||||
@@ -1131,11 +1114,10 @@ pub fn reset(id: SpiId) {
|
||||
regs.reset_ctrl().write_spi(assert_reset);
|
||||
// Keep it in reset for some cycles.. The TMR just mentions some small delay,
|
||||
// no idea what is meant with that.
|
||||
for _ in 0..5 {
|
||||
for _ in 0..3 {
|
||||
aarch32_cpu::asm::nop();
|
||||
}
|
||||
regs.reset_ctrl()
|
||||
.write_spi(DualRefAndClockResetSpiUart::ZERO);
|
||||
regs.reset_ctrl().write_spi(DualRefAndClockReset::DEFAULT);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use core::convert::Infallible;
|
||||
use arbitrary_int::u3;
|
||||
use libm::round;
|
||||
use zynq7000::{
|
||||
slcr::reset::DualRefAndClockResetSpiUart,
|
||||
slcr::reset::DualRefAndClockReset,
|
||||
uart::{
|
||||
BaudRateDivisor, Baudgen, ChMode, ClockSelect, FifoTrigger, InterruptControl,
|
||||
MmioRegisters, Mode, UART_0_BASE, UART_1_BASE,
|
||||
@@ -141,7 +141,7 @@ pub struct DivisorZero;
|
||||
macro_rules! pin_pairs {
|
||||
($index:literal, $UartPeriph:path, ($( [$(#[$meta:meta], )? $TxMio:ident, $RxMio:ident] ),+ $(,)? )) => {
|
||||
$(
|
||||
pastey::paste! {
|
||||
paste::paste! {
|
||||
$( #[$meta] )?
|
||||
impl [<TxPin $index>] for Pin<$TxMio> {}
|
||||
|
||||
@@ -720,13 +720,13 @@ impl embedded_io::Read for Uart {
|
||||
#[inline]
|
||||
pub fn reset(id: UartId) {
|
||||
let assert_reset = match id {
|
||||
UartId::Uart0 => DualRefAndClockResetSpiUart::builder()
|
||||
UartId::Uart0 => DualRefAndClockReset::builder()
|
||||
.with_periph1_ref_rst(false)
|
||||
.with_periph0_ref_rst(true)
|
||||
.with_periph1_cpu1x_rst(false)
|
||||
.with_periph0_cpu1x_rst(true)
|
||||
.build(),
|
||||
UartId::Uart1 => DualRefAndClockResetSpiUart::builder()
|
||||
UartId::Uart1 => DualRefAndClockReset::builder()
|
||||
.with_periph1_ref_rst(true)
|
||||
.with_periph0_ref_rst(false)
|
||||
.with_periph1_cpu1x_rst(true)
|
||||
@@ -736,12 +736,9 @@ pub fn reset(id: UartId) {
|
||||
unsafe {
|
||||
Slcr::with(|regs| {
|
||||
regs.reset_ctrl().write_uart(assert_reset);
|
||||
// Keep it in reset for a few cycles.. not sure if this is necessary.
|
||||
for _ in 0..5 {
|
||||
aarch32_cpu::asm::nop();
|
||||
}
|
||||
regs.reset_ctrl()
|
||||
.write_uart(DualRefAndClockResetSpiUart::ZERO);
|
||||
// Keep it in reset for one cycle.. not sure if this is necessary.
|
||||
aarch32_cpu::asm::nop();
|
||||
regs.reset_ctrl().write_uart(DualRefAndClockReset::DEFAULT);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v0.1.2] 2026-02-14
|
||||
|
||||
Bumped `aarch32-cpu` to v0.2
|
||||
|
||||
# [v0.1.1] 2025-10-10
|
||||
|
||||
Documentation fixes.
|
||||
@@ -20,7 +16,6 @@ Documentation fixes.
|
||||
|
||||
Initial release
|
||||
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-mmu-v0.1.2...HEAD
|
||||
[v0.1.2]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-mmu-v0.1.1...zynq7000-mmu-v0.1.2
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-mmu-v0.1.0...HEAD
|
||||
[v0.1.1]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-mmu-v0.1.0...zynq7000-mmu-v0.1.1
|
||||
[v0.1.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/tag/zynq7000-mmu-v0.1.0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "zynq7000-mmu"
|
||||
description = "Zynq7000 MMU structures"
|
||||
version = "0.1.2"
|
||||
version = "0.1.1"
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
homepage = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
|
||||
@@ -11,7 +11,7 @@ categories = ["embedded", "no-std", "hardware-support"]
|
||||
|
||||
[dependencies]
|
||||
thiserror = { version = "2", default-features = false }
|
||||
aarch32-cpu = { version = "0.2" }
|
||||
aarch32-cpu = { version = "0.1" }
|
||||
|
||||
[build-dependencies]
|
||||
arm-targets = { version = "0.4" }
|
||||
@@ -21,4 +21,5 @@ tools = []
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["armv7a-none-eabihf"]
|
||||
cargo-args = ["-Z", "build-std=core"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -8,8 +8,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v0.2.0] 2026-02-14
|
||||
|
||||
Bugfixes in startup assembler code.
|
||||
|
||||
## Changed
|
||||
@@ -19,7 +17,6 @@ Bugfixes in startup assembler code.
|
||||
- Runtime now calls a `kmain` method similar to the re-export `aarch32-rt` crate.
|
||||
Former `boot_core` method must be renamed to `kmain`, but it is recommended to use
|
||||
the `zynq7000-rt::entry` proc macro to annotate the main method.
|
||||
- Bumped `aarch32-rt` to v0.2 which now requires the `memory.x` file to place the `STACKS` segment
|
||||
|
||||
## Fixed
|
||||
|
||||
@@ -35,7 +32,6 @@ Documentation fixes.
|
||||
|
||||
Initial release
|
||||
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-rt-v0.2.0...HEAD
|
||||
[v0.2.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-rt-v0.1.1...zynq7000-rt-v0.2.0
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-rt-v0.1.0...HEAD
|
||||
[v0.1.1]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-rt-v0.1.0...zynq7000-rt-v0.1.1
|
||||
[v0.1.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/tag/zynq7000-rt-v0.1.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "zynq7000-rt"
|
||||
version = "0.2.0"
|
||||
version = "0.1.1"
|
||||
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||
edition = "2024"
|
||||
description = "Run-time support for the Zynq7000 family of SoCs for running bare-metal applications"
|
||||
@@ -11,8 +11,8 @@ keywords = ["no-std", "rt", "cortex-a", "amd", "zynq7000"]
|
||||
categories = ["embedded", "no-std", "hardware-support"]
|
||||
|
||||
[dependencies]
|
||||
aarch32-rt = { version = "0.2", optional = true, features = ["fpu-d32"] }
|
||||
aarch32-cpu = { version = "0.2" }
|
||||
aarch32-rt = { version = "0.1", optional = true, features = ["fpu-d32"] }
|
||||
aarch32-cpu = { version = "0.1" }
|
||||
arbitrary-int = "2"
|
||||
zynq7000-mmu = { path = "../zynq7000-mmu", version = "0.1" }
|
||||
|
||||
@@ -25,4 +25,5 @@ rt = ["dep:aarch32-rt"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["armv7a-none-eabihf"]
|
||||
cargo-args = ["-Z", "build-std=core"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
+194
-112
@@ -5,6 +5,7 @@
|
||||
//! but does NOT provide the L2 cache initialization.
|
||||
//!
|
||||
//! The boot routine includes stack, MMU and .bss/.data section initialization.
|
||||
use aarch32_cpu::register::{Cpsr, cpsr::ProcessorMode};
|
||||
use aarch32_rt as _;
|
||||
|
||||
// Start-up code for Armv7-A
|
||||
@@ -12,23 +13,23 @@ use aarch32_rt as _;
|
||||
// We set up our stacks and `kmain` in system mode.
|
||||
core::arch::global_asm!(
|
||||
r#"
|
||||
.set PSS_L2CC_BASE_ADDR, 0xF8F02000
|
||||
.set PSS_SLCR_BASE_ADDR, 0xF8000000
|
||||
.set PSS_L2CC_BASE_ADDR, 0xF8F02000
|
||||
.set PSS_SLCR_BASE_ADDR, 0xF8000000
|
||||
|
||||
.set SLCRlockReg, (PSS_SLCR_BASE_ADDR + 0x04) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_LOCK_OFFSET)*/
|
||||
.set SLCRUnlockReg, (PSS_SLCR_BASE_ADDR + 0x08) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_UNLOCK_OFFSET)*/
|
||||
.set SLCRL2cRamReg, (PSS_SLCR_BASE_ADDR + 0xA1C) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_L2C_RAM_OFFSET)*/
|
||||
.set SLCRCPURSTReg, (0xF8000000 + 0x244) /*(XPS_SYS_CTRL_BASEADDR + A9_CPU_RST_CTRL_OFFSET)*/
|
||||
.set EFUSEStatus, (0xF800D000 + 0x10) /*(XPS_EFUSE_BASEADDR + EFUSE_STATUS_OFFSET)*/
|
||||
.set SLCRlockReg, (PSS_SLCR_BASE_ADDR + 0x04) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_LOCK_OFFSET)*/
|
||||
.set SLCRUnlockReg, (PSS_SLCR_BASE_ADDR + 0x08) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_UNLOCK_OFFSET)*/
|
||||
.set SLCRL2cRamReg, (PSS_SLCR_BASE_ADDR + 0xA1C) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_L2C_RAM_OFFSET)*/
|
||||
.set SLCRCPURSTReg, (0xF8000000 + 0x244) /*(XPS_SYS_CTRL_BASEADDR + A9_CPU_RST_CTRL_OFFSET)*/
|
||||
.set EFUSEStatus, (0xF800D000 + 0x10) /*(XPS_EFUSE_BASEADDR + EFUSE_STATUS_OFFSET)*/
|
||||
|
||||
.set CRValMmuCac, 0b01000000000101 /* Enable IDC, and MMU */
|
||||
.set CRValHiVectorAddr, 0b10000000000000 /* Set the Vector address to high, 0xFFFF0000 */
|
||||
.set CRValMmuCac, 0b01000000000101 /* Enable IDC, and MMU */
|
||||
.set CRValHiVectorAddr, 0b10000000000000 /* Set the Vector address to high, 0xFFFF0000 */
|
||||
|
||||
.set SLCRlockKey, 0x767B /* SLCR lock key */
|
||||
.set SLCRUnlockKey, 0xDF0D /* SLCR unlock key */
|
||||
.set SLCRlockKey, 0x767B /* SLCR lock key */
|
||||
.set SLCRUnlockKey, 0xDF0D /* SLCR unlock key */
|
||||
.set SLCRL2cRamConfig, 0x00020202 /* SLCR L2C ram configuration */
|
||||
|
||||
.set FPEXC_EN, 0x40000000 /* FPU enable bit, (1 << 30) */
|
||||
.set FPEXC_EN, 0x40000000 /* FPU enable bit, (1 << 30) */
|
||||
|
||||
.section .text.startup
|
||||
.align 0
|
||||
@@ -38,98 +39,137 @@ core::arch::global_asm!(
|
||||
_start:
|
||||
// only allow cpu0 through
|
||||
// Read MPIDR
|
||||
mrc p15,0,r1,c0,c0,5
|
||||
mrc p15,0,r1,c0,c0,5
|
||||
// Extract CPU ID bits. For single-core systems, this should always be 0
|
||||
and r1, r1, #0x3
|
||||
cmp r1, #0
|
||||
beq check_efuse
|
||||
b initialize
|
||||
and r1, r1, #0x3
|
||||
cmp r1, #0
|
||||
beq check_efuse
|
||||
b initialize
|
||||
|
||||
// Zynq specific code. It is recommended to reset CPU1 according to page 160 of the datasheet
|
||||
check_efuse:
|
||||
ldr r0, =EFUSEStatus
|
||||
// Read eFuse setting
|
||||
ldr r1, [r0]
|
||||
// Check whether device is having single core
|
||||
ands r1,r1,#0x80
|
||||
beq initialize
|
||||
ldr r0,=EFUSEStatus
|
||||
ldr r1,[r0] /* Read eFuse setting */
|
||||
ands r1,r1,#0x80 /* Check whether device is having single core */
|
||||
beq initialize
|
||||
|
||||
/* single core device, reset cpu1 */
|
||||
ldr r0,=SLCRUnlockReg /* Load SLCR base address base + unlock register */
|
||||
ldr r1,=SLCRUnlockKey /* set unlock key */
|
||||
str r1, [r0] /* Unlock SLCR */
|
||||
|
||||
ldr r0,=SLCRCPURSTReg
|
||||
ldr r1,[r0] /* Read CPU Software Reset Control register */
|
||||
orr r1,r1,#0x22
|
||||
str r1,[r0] /* Reset CPU1 */
|
||||
ldr r0,=SLCRCPURSTReg
|
||||
ldr r1,[r0] /* Read CPU Software Reset Control register */
|
||||
orr r1,r1,#0x22
|
||||
str r1,[r0] /* Reset CPU1 */
|
||||
|
||||
ldr r0,=SLCRlockReg /* Load SLCR base address base + lock register */
|
||||
ldr r1,=SLCRlockKey /* set lock key */
|
||||
str r1, [r0] /* lock SLCR */
|
||||
ldr r0,=SLCRlockReg /* Load SLCR base address base + lock register */
|
||||
ldr r1,=SLCRlockKey /* set lock key */
|
||||
str r1, [r0] /* lock SLCR */
|
||||
initialize:
|
||||
mrc p15, 0, r0, c0, c0, 0 /* Get the revision */
|
||||
mrc p15, 0, r0, c0, c0, 0 /* Get the revision */
|
||||
and r5, r0, #0x00f00000
|
||||
and r6, r0, #0x0000000f
|
||||
orr r6, r6, r5, lsr #20-4
|
||||
|
||||
/* set VBAR to the _vector_table address in linker script */
|
||||
ldr r0, =_vector_table
|
||||
mcr p15, 0, r0, c12, c0, 0
|
||||
ldr r0, =_vector_table
|
||||
mcr p15, 0, r0, c12, c0, 0
|
||||
|
||||
/* Invalidate scu */
|
||||
ldr r7, =0xf8f0000c
|
||||
ldr r6, =0xffff
|
||||
str r6, [r7]
|
||||
ldr r7, =0xf8f0000c
|
||||
ldr r6, =0xffff
|
||||
str r6, [r7]
|
||||
|
||||
/* Invalidate caches and TLBs */
|
||||
mov r0,#0 /* r0 = 0 */
|
||||
mcr p15, 0, r0, c8, c7, 0 /* invalidate TLBs */
|
||||
mcr p15, 0, r0, c7, c5, 0 /* invalidate icache */
|
||||
mcr p15, 0, r0, c7, c5, 6 /* Invalidate branch predictor array */
|
||||
bl invalidate_dcache /* invalidate dcache */
|
||||
mov r0,#0 /* r0 = 0 */
|
||||
mcr p15, 0, r0, c8, c7, 0 /* invalidate TLBs */
|
||||
mcr p15, 0, r0, c7, c5, 0 /* invalidate icache */
|
||||
mcr p15, 0, r0, c7, c5, 6 /* Invalidate branch predictor array */
|
||||
bl invalidate_dcache /* invalidate dcache */
|
||||
|
||||
/* Disable MMU, if enabled */
|
||||
mrc p15, 0, r0, c1, c0, 0 /* read CP15 register 1 */
|
||||
bic r0, r0, #0x1 /* clear bit 0 */
|
||||
mcr p15, 0, r0, c1, c0, 0 /* write value back */
|
||||
mrc p15, 0, r0, c1, c0, 0 /* read CP15 register 1 */
|
||||
bic r0, r0, #0x1 /* clear bit 0 */
|
||||
mcr p15, 0, r0, c1, c0, 0 /* write value back */
|
||||
|
||||
bl _stack_setup_preallocated
|
||||
// Set up stacks first.
|
||||
ldr r3, =_stack_top
|
||||
|
||||
// Set stack pointer (right after) and mask interrupts for IRQ mode (Mode 0x12)
|
||||
msr cpsr_c, {irq_mode}
|
||||
// IRQ stack pointer
|
||||
mov sp, r3
|
||||
ldr r1, =_irq_stack_size
|
||||
sub r3, r3, r1
|
||||
|
||||
// Set stack pointer (right after) and mask interrupts for Supervisor/SVC mode (Mode 0x13)
|
||||
msr cpsr_c, {svc_mode}
|
||||
// Supervisor stack pointer
|
||||
mov sp, r3
|
||||
ldr r1, =_svc_stack_size
|
||||
sub r3, r3, r1
|
||||
|
||||
// Set stack pointer (right after) and mask interrupts for Abort/ABT mode (Mode 0x17)
|
||||
msr cpsr_c, {abt_mode}
|
||||
// Abort stack pointer
|
||||
mov sp, r3
|
||||
ldr r1, =_abt_stack_size
|
||||
sub r3, r3, r1
|
||||
|
||||
// Set stack pointer (right after) and mask interrupts for FIQ mode (Mode 0x11)
|
||||
msr cpsr_c, {fiq_mode}
|
||||
// FIQ stack pointer
|
||||
mov sp, r3
|
||||
ldr r1, =_fiq_stack_size
|
||||
sub r3, r3, r1
|
||||
|
||||
// Set stack pointer (right after) and mask interrupts for Undefined/UND mode (Mode 0x1B)
|
||||
msr cpsr_c, {und_mode}
|
||||
// Undefined stack pointer
|
||||
mov sp, r3
|
||||
ldr r1, =_und_stack_size
|
||||
sub r3, r3, r1
|
||||
|
||||
// Set stack pointer (right after) and mask interrupts for System/SYS mode (Mode 0x1F)
|
||||
msr cpsr_c, {sys_mode}
|
||||
// System stack pointer (main stack)
|
||||
mov sp, r3
|
||||
|
||||
// set scu enable bit in scu
|
||||
ldr r7, =0xf8f00000
|
||||
ldr r0, [r7]
|
||||
orr r0, r0, #0x1
|
||||
str r0, [r7]
|
||||
ldr r7, =0xf8f00000
|
||||
ldr r0, [r7]
|
||||
orr r0, r0, #0x1
|
||||
str r0, [r7]
|
||||
|
||||
/* Write to ACTLR */
|
||||
mrc p15, 0, r0, c1, c0, 1 /* Read ACTLR*/
|
||||
orr r0, r0, #(0x01 << 6) /* set SMP bit */
|
||||
orr r0, r0, #(0x01 ) /* Cache/TLB maintenance broadcast */
|
||||
mcr p15, 0, r0, c1, c0, 1 /* Write ACTLR*/
|
||||
mrc p15, 0, r0, c1, c0, 1 /* Read ACTLR*/
|
||||
orr r0, r0, #(0x01 << 6) /* set SMP bit */
|
||||
orr r0, r0, #(0x01 ) /* Cache/TLB maintenance broadcast */
|
||||
mcr p15, 0, r0, c1, c0, 1 /* Write ACTLR*/
|
||||
|
||||
mov r0, r0
|
||||
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 */
|
||||
mcr p15, 0, r1, c1, c0, 2 /* write back into CACR */
|
||||
mov r0, r0
|
||||
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 */
|
||||
mcr p15, 0, r1, c1, c0, 2 /* write back into CACR */
|
||||
|
||||
/* enable vfp */
|
||||
fmrx r1, FPEXC /* read the exception register */
|
||||
orr r1,r1, #FPEXC_EN /* set VFP enable bit, leave the others in orig state */
|
||||
fmxr FPEXC, r1 /* write back the exception register */
|
||||
fmrx r1, FPEXC /* read the exception register */
|
||||
orr r1,r1, #FPEXC_EN /* set VFP enable bit, leave the others in orig state */
|
||||
fmxr FPEXC, r1 /* write back the exception register */
|
||||
|
||||
mrc p15,0,r0,c1,c0,0 /* flow prediction enable */
|
||||
orr r0, r0, #(0x01 << 11) /* #0x8000 */
|
||||
mcr p15,0,r0,c1,c0,0
|
||||
mrc p15,0,r0,c1,c0,0 /* flow prediction enable */
|
||||
orr r0, r0, #(0x01 << 11) /* #0x8000 */
|
||||
mcr p15,0,r0,c1,c0,0
|
||||
|
||||
mrc p15,0,r0,c1,c0,1 /* read Auxiliary Control Register */
|
||||
orr r0, r0, #(0x1 << 2) /* enable Dside prefetch */
|
||||
orr r0, r0, #(0x1 << 1) /* enable L2 Prefetch hint */
|
||||
mcr p15,0,r0,c1,c0,1 /* write Auxiliary Control Register */
|
||||
mrc p15,0,r0,c1,c0,1 /* read Auxiliary Control Register */
|
||||
orr r0, r0, #(0x1 << 2) /* enable Dside prefetch */
|
||||
orr r0, r0, #(0x1 << 1) /* enable L2 Prefetch hint */
|
||||
mcr p15,0,r0,c1,c0,1 /* write Auxiliary Control Register */
|
||||
|
||||
mrs r0, cpsr /* get the current PSR */
|
||||
bic r0, r0, #0x100 /* enable asynchronous abort exception */
|
||||
msr cpsr_xsf, r0
|
||||
mrs r0, cpsr /* get the current PSR */
|
||||
bic r0, r0, #0x100 /* enable asynchronous abort exception */
|
||||
msr cpsr_xsf, r0
|
||||
|
||||
/* Zero BSS and initialize data before calling any function which might require them. */
|
||||
|
||||
@@ -159,20 +199,20 @@ data_init_done:
|
||||
/* enable MMU and cache */
|
||||
/* MMU Table is in .data, so this needs to be performed after .data is relocated */
|
||||
/* (Even if in most cases, .data is already in RAM and relocation is a no-op) */
|
||||
bl load_mmu_table
|
||||
bl load_mmu_table
|
||||
|
||||
mvn r0,#0 /* Load MMU domains -- all ones=manager */
|
||||
mcr p15,0,r0,c3,c0,0
|
||||
mvn r0,#0 /* Load MMU domains -- all ones=manager */
|
||||
mcr p15,0,r0,c3,c0,0
|
||||
|
||||
/* Enable mmu, icache and dcache */
|
||||
ldr r0,=CRValMmuCac
|
||||
mcr p15,0,r0,c1,c0,0 /* Enable cache and MMU */
|
||||
dsb /* dsb allow the MMU to start up */
|
||||
isb /* isb flush prefetch buffer */
|
||||
ldr r0,=CRValMmuCac
|
||||
mcr p15,0,r0,c1,c0,0 /* Enable cache and MMU */
|
||||
dsb /* dsb allow the MMU to start up */
|
||||
isb /* isb flush prefetch buffer */
|
||||
|
||||
// Jump to application
|
||||
// Load CPU ID 0, which will be used as a function argument to the boot_core function.
|
||||
mov r0, #0x0
|
||||
mov r0, #0x0
|
||||
bl kmain
|
||||
// In case the application returns, loop forever
|
||||
b .
|
||||
@@ -180,48 +220,90 @@ data_init_done:
|
||||
|
||||
.type _invalidate_dcache, %function
|
||||
invalidate_dcache:
|
||||
mrc p15, 1, r0, c0, c0, 1 /* read CLIDR */
|
||||
ands r3, r0, #0x7000000
|
||||
mov r3, r3, lsr #23 /* cache level value (naturally aligned) */
|
||||
beq finished
|
||||
mov r10, #0 /* start with level 0 */
|
||||
mrc p15, 1, r0, c0, c0, 1 /* read CLIDR */
|
||||
ands r3, r0, #0x7000000
|
||||
mov r3, r3, lsr #23 /* cache level value (naturally aligned) */
|
||||
beq finished
|
||||
mov r10, #0 /* start with level 0 */
|
||||
loop1:
|
||||
add r2, r10, r10, lsr #1 /* work out 3xcachelevel */
|
||||
mov r1, r0, lsr r2 /* bottom 3 bits are the Cache type for this level */
|
||||
and r1, r1, #7 /* get those 3 bits alone */
|
||||
cmp r1, #2
|
||||
blt skip /* no cache or only instruction cache at this level */
|
||||
mcr p15, 2, r10, c0, c0, 0 /* write the Cache Size selection register */
|
||||
isb /* isb to sync the change to the CacheSizeID reg */
|
||||
mrc p15, 1, r1, c0, c0, 0 /* reads current Cache Size ID register */
|
||||
and r2, r1, #7 /* extract the line length field */
|
||||
add r2, r2, #4 /* add 4 for the line length offset (log2 16 bytes) */
|
||||
ldr r4, =0x3ff
|
||||
ands r4, r4, r1, lsr #3 /* r4 is the max number on the way size (right aligned) */
|
||||
clz r5, r4 /* r5 is the bit position of the way size increment */
|
||||
ldr r7, =0x7fff
|
||||
ands r7, r7, r1, lsr #13 /* r7 is the max number of the index size (right aligned) */
|
||||
add r2, r10, r10, lsr #1 /* work out 3xcachelevel */
|
||||
mov r1, r0, lsr r2 /* bottom 3 bits are the Cache type for this level */
|
||||
and r1, r1, #7 /* get those 3 bits alone */
|
||||
cmp r1, #2
|
||||
blt skip /* no cache or only instruction cache at this level */
|
||||
mcr p15, 2, r10, c0, c0, 0 /* write the Cache Size selection register */
|
||||
isb /* isb to sync the change to the CacheSizeID reg */
|
||||
mrc p15, 1, r1, c0, c0, 0 /* reads current Cache Size ID register */
|
||||
and r2, r1, #7 /* extract the line length field */
|
||||
add r2, r2, #4 /* add 4 for the line length offset (log2 16 bytes) */
|
||||
ldr r4, =0x3ff
|
||||
ands r4, r4, r1, lsr #3 /* r4 is the max number on the way size (right aligned) */
|
||||
clz r5, r4 /* r5 is the bit position of the way size increment */
|
||||
ldr r7, =0x7fff
|
||||
ands r7, r7, r1, lsr #13 /* r7 is the max number of the index size (right aligned) */
|
||||
loop2:
|
||||
mov r9, r4 /* r9 working copy of the max way size (right aligned) */
|
||||
mov r9, r4 /* r9 working copy of the max way size (right aligned) */
|
||||
loop3:
|
||||
orr r11, r10, r9, lsl r5 /* factor in the way number and cache number into r11 */
|
||||
orr r11, r11, r7, lsl r2 /* factor in the index number */
|
||||
mcr p15, 0, r11, c7, c6, 2 /* invalidate by set/way */
|
||||
subs r9, r9, #1 /* decrement the way number */
|
||||
bge loop3
|
||||
subs r7, r7, #1 /* decrement the index */
|
||||
bge loop2
|
||||
orr r11, r10, r9, lsl r5 /* factor in the way number and cache number into r11 */
|
||||
orr r11, r11, r7, lsl r2 /* factor in the index number */
|
||||
mcr p15, 0, r11, c7, c6, 2 /* invalidate by set/way */
|
||||
subs r9, r9, #1 /* decrement the way number */
|
||||
bge loop3
|
||||
subs r7, r7, #1 /* decrement the index */
|
||||
bge loop2
|
||||
skip:
|
||||
add r10, r10, #2 /* increment the cache number */
|
||||
cmp r3, r10
|
||||
bgt loop1
|
||||
add r10, r10, #2 /* increment the cache number */
|
||||
cmp r3, r10
|
||||
bgt loop1
|
||||
|
||||
finished:
|
||||
mov r10, #0 /* switch back to cache level 0 */
|
||||
mcr p15, 2, r10, c0, c0, 0 /* select current cache level in cssr */
|
||||
mov r10, #0 /* switch back to cache level 0 */
|
||||
mcr p15, 2, r10, c0, c0, 0 /* select current cache level in cssr */
|
||||
dsb
|
||||
isb
|
||||
bx lr
|
||||
bx lr
|
||||
.size invalidate_dcache, . - invalidate_dcache
|
||||
"#,
|
||||
fiq_mode = const {
|
||||
Cpsr::new_with_raw_value(0)
|
||||
.with_mode(ProcessorMode::Fiq)
|
||||
.with_i(true)
|
||||
.with_f(true)
|
||||
.raw_value()
|
||||
},
|
||||
irq_mode = const {
|
||||
Cpsr::new_with_raw_value(0)
|
||||
.with_mode(ProcessorMode::Irq)
|
||||
.with_i(true)
|
||||
.with_f(true)
|
||||
.raw_value()
|
||||
},
|
||||
svc_mode = const {
|
||||
Cpsr::new_with_raw_value(0)
|
||||
.with_mode(ProcessorMode::Svc)
|
||||
.with_i(true)
|
||||
.with_f(true)
|
||||
.raw_value()
|
||||
},
|
||||
und_mode = const {
|
||||
Cpsr::new_with_raw_value(0)
|
||||
.with_mode(ProcessorMode::Und)
|
||||
.with_i(true)
|
||||
.with_f(true)
|
||||
.raw_value()
|
||||
},
|
||||
abt_mode = const {
|
||||
Cpsr::new_with_raw_value(0)
|
||||
.with_mode(ProcessorMode::Abt)
|
||||
.with_i(true)
|
||||
.with_f(true)
|
||||
.raw_value()
|
||||
},
|
||||
sys_mode = const {
|
||||
Cpsr::new_with_raw_value(0)
|
||||
.with_mode(ProcessorMode::Sys)
|
||||
.with_i(true)
|
||||
.with_f(true)
|
||||
.raw_value()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -8,15 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v0.2.0] 2026-04-01
|
||||
|
||||
- Renamed all register blocks to `Registers` to subblocks to `<Subblock>Registers`.
|
||||
- Updated IPTR registers in the GIC module to use a custom register type instead of a raw u32.
|
||||
- Added SDIO registers.
|
||||
- Fixed wrong position in QSPI reset register in SLCR Module
|
||||
- Added some missing reset register definitions.
|
||||
- Added `defmt` support
|
||||
- Some other minor renaming of registers (e.g. `ctrl` replaced by `control`)
|
||||
|
||||
# [v0.1.1] 2025-10-09
|
||||
|
||||
@@ -26,7 +20,6 @@ Documentation fix
|
||||
|
||||
Initial release
|
||||
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.2.0...HEAD
|
||||
[v0.2.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.1.0...zynq7000-v0.2.0
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.1.1...HEAD
|
||||
[v0.1.1]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.1.0...zynq7000-v0.1.1
|
||||
[v0.1.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/tag/zynq7000-v0.1.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "zynq7000"
|
||||
version = "0.2.0"
|
||||
version = "0.1.1"
|
||||
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||
edition = "2024"
|
||||
description = "Peripheral Access Crate (PAC) for the Zynq7000 family of SoCs"
|
||||
@@ -13,19 +13,16 @@ categories = ["embedded", "no-std", "hardware-support"]
|
||||
[dependencies]
|
||||
static_assertions = "1.1"
|
||||
derive-mmio = { version = "0.6", default-features = false }
|
||||
bitbybit = "2"
|
||||
bitbybit = "1.4"
|
||||
arbitrary-int = "2"
|
||||
rustversion = "1"
|
||||
thiserror = { version = "2", default-features = false }
|
||||
once_cell = { version = "1", default-features = false, features = ["critical-section"] }
|
||||
defmt = { version = "1", optional = true }
|
||||
|
||||
[features]
|
||||
defmt = ["dep:defmt", "arbitrary-int/defmt"]
|
||||
|
||||
[dev-dependencies]
|
||||
approx = "0.5"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["armv7a-none-eabihf"]
|
||||
cargo-args = ["-Z", "build-std=core"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
|
||||
This repository contains the Peripheral Access Crate (PAC) for the AMD Zynq7000 SoC family.
|
||||
|
||||
If you are interested in higher-level abstractions, it is recommended you visit the
|
||||
[`zynq7000-hal`](../zynq7000-hal) HAL crate which build on top of this PAC.
|
||||
If you are interested in higher-level abstractions, it is recommended you visit
|
||||
the [`zynq7000-hal`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000-hal)
|
||||
HAL crate which build on top of this PAC.
|
||||
|
||||
Check out the documentation for more details.
|
||||
|
||||
+55
-371
@@ -6,7 +6,6 @@ pub mod regs {
|
||||
|
||||
#[bitbybit::bitenum(u2)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum DataBusWidth {
|
||||
_32Bit = 0b00,
|
||||
_16Bit = 0b01,
|
||||
@@ -14,18 +13,11 @@ pub mod regs {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum SoftReset {
|
||||
Reset = 0,
|
||||
Active = 1,
|
||||
}
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DdrcControl {
|
||||
#[bit(16, rw)]
|
||||
disable_auto_refresh: bool,
|
||||
@@ -45,14 +37,7 @@ pub mod regs {
|
||||
soft_reset: SoftReset,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct TwoRankConfig {
|
||||
#[bits(14..=18, rw)]
|
||||
addrmap_cs_bit0: u5,
|
||||
@@ -65,13 +50,7 @@ pub mod regs {
|
||||
}
|
||||
|
||||
/// Queue control for the low priority and high priority read queues.
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct LprHprQueueControl {
|
||||
#[bits(22..=25, rw)]
|
||||
xact_run_length: u4,
|
||||
@@ -81,13 +60,7 @@ pub mod regs {
|
||||
min_non_critical_x32: u11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct WriteQueueControl {
|
||||
#[bits(15..=25, rw)]
|
||||
max_starve_x32: u11,
|
||||
@@ -97,13 +70,7 @@ pub mod regs {
|
||||
min_non_critical_x32: u11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DramParamReg0 {
|
||||
/// Minimum time to wait after coming out of self refresh before doing anything. This must be
|
||||
/// bigger than all the constraints that exist.
|
||||
@@ -118,13 +85,7 @@ pub mod regs {
|
||||
t_rc: u6,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DramParamReg1 {
|
||||
#[bits(28..=31, rw)]
|
||||
t_cke: u4,
|
||||
@@ -140,13 +101,7 @@ pub mod regs {
|
||||
wr2pre: u5,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DramParamReg2 {
|
||||
#[bits(28..=31, rw)]
|
||||
t_rcd: u4,
|
||||
@@ -166,19 +121,12 @@ pub mod regs {
|
||||
|
||||
/// Weird naming.
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum MobileSetting {
|
||||
Ddr2Ddr3 = 0,
|
||||
Lpddr2 = 1,
|
||||
}
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DramParamReg3 {
|
||||
#[bit(30, rw)]
|
||||
disable_pad_pd_feature: bool,
|
||||
@@ -206,19 +154,12 @@ pub mod regs {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ModeRegisterType {
|
||||
Write = 0,
|
||||
Read = 1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DramParamReg4 {
|
||||
#[bit(27, rw)]
|
||||
mr_rdata_valid: bool,
|
||||
@@ -238,13 +179,7 @@ pub mod regs {
|
||||
enable_2t_timing_mode: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DramInitParam {
|
||||
#[bits(11..=13, rw)]
|
||||
t_mrd: u3,
|
||||
@@ -254,13 +189,7 @@ pub mod regs {
|
||||
final_wait_x32: u7,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DramEmr {
|
||||
#[bits(16..=31, rw)]
|
||||
emr3: u16,
|
||||
@@ -268,13 +197,7 @@ pub mod regs {
|
||||
emr2: u16,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DramEmrMr {
|
||||
#[bits(16..=31, rw)]
|
||||
emr: u16,
|
||||
@@ -282,13 +205,7 @@ pub mod regs {
|
||||
mr: u16,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DramBurst8ReadWrite {
|
||||
#[bits(0..=3, rw)]
|
||||
burst_rdwr: u4,
|
||||
@@ -300,13 +217,7 @@ pub mod regs {
|
||||
burstchop: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DisableDq {
|
||||
#[bit(1, rw)]
|
||||
dis_dq: bool,
|
||||
@@ -314,13 +225,7 @@ pub mod regs {
|
||||
force_low_pri_n: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DramAddrMapBank {
|
||||
#[bits(16..=19, rw)]
|
||||
addrmap_bank_b6: u4,
|
||||
@@ -334,13 +239,7 @@ pub mod regs {
|
||||
addrmap_bank_b0: u4,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DramAddrMapColumn {
|
||||
#[bits(28..=31, rw)]
|
||||
addrmap_col_b11: u4,
|
||||
@@ -360,13 +259,7 @@ pub mod regs {
|
||||
addrmap_col_b2: u4,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DramAddrMapRow {
|
||||
#[bits(24..=27, rw)]
|
||||
addrmap_row_b15: u4,
|
||||
@@ -384,13 +277,7 @@ pub mod regs {
|
||||
addrmap_row_b0: u4,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DramOdt {
|
||||
#[bits(16..=17, rw)]
|
||||
phy_idle_local_odt: u2,
|
||||
@@ -404,13 +291,7 @@ pub mod regs {
|
||||
rank0_rd_odt: u3,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct PhyCmdTimeoutRdDataCpt {
|
||||
#[bits(28..=31, rw)]
|
||||
wrlvl_num_of_dq0: u4,
|
||||
@@ -433,32 +314,19 @@ pub mod regs {
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum DllCalibSel {
|
||||
Periodic = 0,
|
||||
Manual = 1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DllCalib {
|
||||
#[bit(16, rw)]
|
||||
sel: DllCalibSel,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct OdtDelayHold {
|
||||
#[bits(12..=15, rw)]
|
||||
wr_odt_hold: u4,
|
||||
@@ -470,13 +338,7 @@ pub mod regs {
|
||||
rd_odt_delay: u4,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct CtrlReg1 {
|
||||
#[bit(12, rw)]
|
||||
selfref_enable: bool,
|
||||
@@ -494,13 +356,7 @@ pub mod regs {
|
||||
pageclose: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct CtrlReg2 {
|
||||
#[bit(17, rw)]
|
||||
go_2_critcal_enable: bool,
|
||||
@@ -508,13 +364,7 @@ pub mod regs {
|
||||
go_2_critical_hysteresis: u8,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct CtrlReg3 {
|
||||
#[bits(16..=25, rw)]
|
||||
dfi_t_wlmrd: u10,
|
||||
@@ -524,13 +374,7 @@ pub mod regs {
|
||||
wrlvl_ww: u8,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct CtrlReg4 {
|
||||
#[bits(8..=15, rw)]
|
||||
dfi_t_ctrlupd_interval_max_x1024: u8,
|
||||
@@ -538,13 +382,7 @@ pub mod regs {
|
||||
dfi_t_ctrlupd_interval_min_x1024: u8,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct CtrlReg5 {
|
||||
#[bits(20..=25, rw)]
|
||||
t_ckesr: u6,
|
||||
@@ -560,13 +398,7 @@ pub mod regs {
|
||||
dfi_t_ctrl_delay: u4,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct CtrlReg6 {
|
||||
#[bits(16..=19, rw)]
|
||||
t_cksx: u4,
|
||||
@@ -580,13 +412,7 @@ pub mod regs {
|
||||
t_ckpde: u4,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct CheTZq {
|
||||
#[bits(22..=31, rw)]
|
||||
t_zq_short_nop: u10,
|
||||
@@ -600,13 +426,7 @@ pub mod regs {
|
||||
dis_auto_zq: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct CheTZqShortInterval {
|
||||
#[bits(20..=27, rw)]
|
||||
dram_rstn_x1024: u8,
|
||||
@@ -614,13 +434,7 @@ pub mod regs {
|
||||
t_zq_short_interval: u20,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DeepPowerdown {
|
||||
#[bits(1..=8, rw)]
|
||||
deep_powerdown_to_x1024: u8,
|
||||
@@ -628,13 +442,7 @@ pub mod regs {
|
||||
enable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct Reg2c {
|
||||
#[bit(28, rw)]
|
||||
dfi_rd_data_eye_train: bool,
|
||||
@@ -652,25 +460,13 @@ pub mod regs {
|
||||
dfi_wrlvl_max_x1024: u12,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct Reg2d {
|
||||
#[bit(9, rw)]
|
||||
skip_ocd: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DfiTiming {
|
||||
#[bits(15..=24, rw)]
|
||||
dfi_t_ctrlup_max: u10,
|
||||
@@ -680,13 +476,7 @@ pub mod regs {
|
||||
dfi_t_rddata_enable: u5,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct CheEccControl {
|
||||
#[bit(1, rw)]
|
||||
clear_correctable_errors: bool,
|
||||
@@ -695,20 +485,13 @@ pub mod regs {
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u3, exhaustive = false)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum EccMode {
|
||||
NoEcc = 0b000,
|
||||
SecDecOverOneBeat = 0b100,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct EccScrub {
|
||||
#[bit(3, rw)]
|
||||
disable_scrub: bool,
|
||||
@@ -716,13 +499,7 @@ pub mod regs {
|
||||
ecc_mode: Option<EccMode>,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct PhyReceiverEnable {
|
||||
#[bits(4..=7, rw)]
|
||||
phy_dif_off: u4,
|
||||
@@ -730,13 +507,7 @@ pub mod regs {
|
||||
phy_dif_on: u4,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct PhyConfig {
|
||||
#[bits(24..=30, rw)]
|
||||
dq_offset: u7,
|
||||
@@ -750,13 +521,7 @@ pub mod regs {
|
||||
data_slice_in_use: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct PhyInitRatio {
|
||||
#[bits(10..=19, rw)]
|
||||
gatelvl_init_ratio: u10,
|
||||
@@ -764,13 +529,7 @@ pub mod regs {
|
||||
wrlvl_init_ratio: u10,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct PhyDqsConfig {
|
||||
#[bits(11..=19, rw)]
|
||||
dqs_slave_delay: u9,
|
||||
@@ -780,13 +539,7 @@ pub mod regs {
|
||||
dqs_slave_ratio: u10,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct PhyWriteEnableConfig {
|
||||
#[bits(12..=20, rw)]
|
||||
fifo_we_in_delay: u9,
|
||||
@@ -796,13 +549,7 @@ pub mod regs {
|
||||
fifo_we_slave_ratio: u11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct PhyWriteDataSlaveConfig {
|
||||
#[bits(11..=19, rw)]
|
||||
wr_data_slave_delay: u9,
|
||||
@@ -812,13 +559,7 @@ pub mod regs {
|
||||
wr_data_slave_ratio: u10,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct Reg64 {
|
||||
#[bit(30, rw)]
|
||||
cmd_latency: bool,
|
||||
@@ -838,13 +579,7 @@ pub mod regs {
|
||||
bl2: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct Reg65 {
|
||||
#[bits(18..=19, rw)]
|
||||
ctrl_slave_delay: u2,
|
||||
@@ -864,13 +599,7 @@ pub mod regs {
|
||||
wr_rl_delay: u5,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct AxiPriorityWritePort {
|
||||
#[bit(18, rw)]
|
||||
disable_page_match: bool,
|
||||
@@ -882,13 +611,7 @@ pub mod regs {
|
||||
pri_wr_port: u10,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct AxiPriorityReadPort {
|
||||
#[bit(19, rw)]
|
||||
enable_hpr: bool,
|
||||
@@ -902,13 +625,7 @@ pub mod regs {
|
||||
pri_rd_port_n: u10,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct ExclusiveAccessConfig {
|
||||
#[bits(9..=17, rw)]
|
||||
access_id1_port: u9,
|
||||
@@ -917,20 +634,13 @@ pub mod regs {
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum LpddrBit {
|
||||
Ddr2Ddr3 = 0,
|
||||
Lpddr2 = 1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct LpddrControl0 {
|
||||
#[bits(4..=11, rw)]
|
||||
mr4_margin: u8,
|
||||
@@ -942,25 +652,13 @@ pub mod regs {
|
||||
lpddr2: LpddrBit,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct LpddrControl1 {
|
||||
#[bits(0..=31, rw)]
|
||||
mr4_read_interval: u32,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct LpddrControl2 {
|
||||
#[bits(12..=21, rw)]
|
||||
t_mrw: u10,
|
||||
@@ -970,13 +668,7 @@ pub mod regs {
|
||||
min_stable_clock_x1: u4,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct LpddrControl3 {
|
||||
#[bits(8..=17, rw)]
|
||||
dev_zqinit_x32: u10,
|
||||
@@ -986,7 +678,6 @@ pub mod regs {
|
||||
|
||||
#[bitbybit::bitenum(u3, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum OperatingMode {
|
||||
DdrcInit = 0,
|
||||
NormalOperation = 1,
|
||||
@@ -1012,19 +703,12 @@ pub mod regs {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum DebugStallBit {
|
||||
CommandsAccepted = 0,
|
||||
CommandsNotAccepted = 1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct ModeStatus {
|
||||
#[bits(16..=20, r)]
|
||||
dbg_hpr_queue_depth: u5,
|
||||
|
||||
@@ -4,7 +4,6 @@ pub const DEVCFG_BASE_ADDR: usize = 0xF8007000;
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum PlConfigAccess {
|
||||
/// Used for JTAG access
|
||||
TapController = 0,
|
||||
@@ -14,7 +13,6 @@ pub enum PlConfigAccess {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ConfigAccessPortSelect {
|
||||
/// Internal Configuration Access Port (ICAP), using PL or PS-based software.
|
||||
Icap = 0,
|
||||
@@ -24,7 +22,6 @@ pub enum ConfigAccessPortSelect {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum TimerSelect {
|
||||
_64kTimer = 0,
|
||||
_4kTimer = 1,
|
||||
@@ -32,7 +29,6 @@ pub enum TimerSelect {
|
||||
|
||||
#[bitbybit::bitenum(u3, exhaustive = false)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum AesEnable {
|
||||
Disable = 0b000,
|
||||
Enable = 0b111,
|
||||
@@ -40,7 +36,6 @@ pub enum AesEnable {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum PsBootMode {
|
||||
NonSecure = 0,
|
||||
Secure = 1,
|
||||
@@ -48,18 +43,11 @@ pub enum PsBootMode {
|
||||
|
||||
#[bitbybit::bitenum(u3, exhaustive = false)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ArmDapEnable {
|
||||
Enabled = 0b111,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Control {
|
||||
#[bit(31, rw)]
|
||||
force_reset: bool,
|
||||
@@ -107,7 +95,7 @@ pub struct Control {
|
||||
|
||||
/// The bits in this register and read/write, set-only, which means that only a PS_POR_B reset
|
||||
/// can clear the bits.
|
||||
#[bitbybit::bitfield(u32, debug, debug, defmt_fields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Lock {
|
||||
#[bit(4, rw)]
|
||||
aes_fuse: bool,
|
||||
@@ -125,7 +113,6 @@ pub struct Lock {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum EdgeConfig {
|
||||
Falling = 0,
|
||||
Rising = 1,
|
||||
@@ -134,7 +121,6 @@ pub enum EdgeConfig {
|
||||
/// Related to the full level for reads, and the empty level for writes.
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum FifoThresholdConfig {
|
||||
OneFourth = 0b00,
|
||||
HalfEmpty = 0b01,
|
||||
@@ -142,7 +128,7 @@ pub enum FifoThresholdConfig {
|
||||
EmptyOrFull = 0b11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_fields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Config {
|
||||
#[bits(10..=11, rw)]
|
||||
read_fifo_threshhold: FifoThresholdConfig,
|
||||
@@ -158,7 +144,7 @@ pub struct Config {
|
||||
disable_dst_incremenet: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_fields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Interrupt {
|
||||
/// Tri-state PL IO during HIZ.
|
||||
#[bit(31, rw)]
|
||||
@@ -213,7 +199,7 @@ pub struct Interrupt {
|
||||
negative_edge_pl_init: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct MiscControl {
|
||||
#[bits(28..=31, r)]
|
||||
ps_version: u4,
|
||||
@@ -227,7 +213,6 @@ pub struct MiscControl {
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum UnacknowledgedDmaTransfers {
|
||||
None = 0b00,
|
||||
One = 0b01,
|
||||
@@ -235,7 +220,7 @@ pub enum UnacknowledgedDmaTransfers {
|
||||
ThreeOrMore = 0b11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_fields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Status {
|
||||
#[bit(31, rw)]
|
||||
dma_command_queue_full: bool,
|
||||
|
||||
@@ -4,7 +4,8 @@ use arbitrary_int::{u2, u5};
|
||||
pub const GEM_0_BASE_ADDR: usize = 0xE000_B000;
|
||||
pub const GEM_1_BASE_ADDR: usize = 0xE000_C000;
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct NetworkControl {
|
||||
#[bit(18, w)]
|
||||
flush_next_rx_dpram_pkt: bool,
|
||||
@@ -40,7 +41,6 @@ pub struct NetworkControl {
|
||||
|
||||
/// The speed mode selects between 10 Mbps and 100 Mbps if the Gigabit enable bit is cleared.
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum SpeedMode {
|
||||
Low10Mbps = 0,
|
||||
@@ -49,7 +49,6 @@ pub enum SpeedMode {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum PcsSelect {
|
||||
GmiiMii = 0,
|
||||
Tbi = 1,
|
||||
@@ -57,7 +56,6 @@ pub enum PcsSelect {
|
||||
|
||||
#[bitbybit::bitenum(u3, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum MdcClockDivisor {
|
||||
Div8 = 0,
|
||||
Div16 = 1,
|
||||
@@ -84,13 +82,7 @@ impl MdcClockDivisor {
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
forbid_overlaps,
|
||||
defmt_fields(feature = "defmt")
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct NetworkConfig {
|
||||
#[bit(30, rw)]
|
||||
ignore_ipg_rx_error: bool,
|
||||
@@ -148,7 +140,7 @@ pub struct NetworkConfig {
|
||||
}
|
||||
|
||||
/// PHY management status information.
|
||||
#[bitbybit::bitfield(u32, debug, forbid_overlaps, defmt_fields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct NetworkStatus {
|
||||
#[bit(6, r)]
|
||||
pfc_pri_pause_neg: bool,
|
||||
@@ -167,7 +159,6 @@ pub struct NetworkStatus {
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum BurstLength {
|
||||
Single,
|
||||
#[default]
|
||||
@@ -189,14 +180,12 @@ impl BurstLength {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum AhbEndianess {
|
||||
Little = 0,
|
||||
Big = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct DmaRxBufSize(u8);
|
||||
|
||||
impl DmaRxBufSize {
|
||||
@@ -224,13 +213,7 @@ impl DmaRxBufSize {
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
forbid_overlaps,
|
||||
defmt_fields(feature = "defmt")
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct DmaConfig {
|
||||
#[bit(24, rw)]
|
||||
discard_when_ahb_full: bool,
|
||||
@@ -258,7 +241,7 @@ pub struct DmaConfig {
|
||||
burst_length: u5,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, forbid_overlaps, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct TxStatus {
|
||||
#[bit(8, rw)]
|
||||
hresp_not_ok: bool,
|
||||
@@ -289,7 +272,7 @@ impl TxStatus {
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, forbid_overlaps, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct RxStatus {
|
||||
#[bit(3, rw)]
|
||||
hresp_not_ok: bool,
|
||||
@@ -307,13 +290,7 @@ impl RxStatus {
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
forbid_overlaps,
|
||||
defmt_bitfields(feature = "defmt")
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct InterruptStatus {
|
||||
#[bit(26, rw)]
|
||||
tsu_sec_incr: bool,
|
||||
@@ -404,20 +381,13 @@ impl InterruptControl {
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = false)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum PhyOperation {
|
||||
Read = 0b10,
|
||||
Write = 0b01,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
forbid_overlaps,
|
||||
defmt_fields(feature = "defmt")
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct PhyMaintenance {
|
||||
/// Must be 1 for Clause 22 operations.
|
||||
#[bit(30, rw)]
|
||||
@@ -434,25 +404,13 @@ pub struct PhyMaintenance {
|
||||
data: u16,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
forbid_overlaps,
|
||||
defmt_bitfields(feature = "defmt")
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct PauseQuantum {
|
||||
#[bits(0..=15, rw)]
|
||||
value: u16,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
forbid_overlaps,
|
||||
defmt_bitfields(feature = "defmt")
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct MatchRegister {
|
||||
#[bit(31, rw)]
|
||||
copy_enable: bool,
|
||||
|
||||
@@ -4,13 +4,7 @@ use arbitrary_int::{u2, u3, u5, u10};
|
||||
use static_assertions::const_assert_eq;
|
||||
|
||||
/// Distributor Control Register
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DistributorControlRegister {
|
||||
#[bit(1, rw)]
|
||||
enable_non_secure: bool,
|
||||
@@ -19,7 +13,7 @@ pub struct DistributorControlRegister {
|
||||
}
|
||||
|
||||
/// Read only bit. This register only returns fixed constants.
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct TypeRegister {
|
||||
#[bits(11..=15, r)]
|
||||
lspi: u5,
|
||||
@@ -46,9 +40,10 @@ impl TypeRegister {
|
||||
|
||||
pub type Typer = TypeRegister;
|
||||
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
#[derive(PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
// TODO: Use bitbybit debug derive if new release was released.
|
||||
/// Interrupt processor target register (IPTR).
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct InterruptProcessorTargetRegister {
|
||||
/// Target array. Every register holds the information for 4 interrupts.
|
||||
#[bits(0..=1, rw, stride = 8)]
|
||||
@@ -146,13 +141,7 @@ impl DistributorRegisters {
|
||||
}
|
||||
|
||||
/// CPU interface control register.
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct InterfaceControl {
|
||||
#[bit(4, rw)]
|
||||
sbpr: bool,
|
||||
@@ -167,14 +156,14 @@ pub struct InterfaceControl {
|
||||
}
|
||||
|
||||
/// Priority Mask Register
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct PriorityRegister {
|
||||
#[bits(0..=7, rw)]
|
||||
priority: u8,
|
||||
}
|
||||
|
||||
/// Interrupt acknowledge register.
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct InterruptSignalRegister {
|
||||
#[bits(10..=12, rw)]
|
||||
cpu_id: u3,
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
//! # GPIO register module.
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct MaskedOutput {
|
||||
#[bits(16..=31, w)]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
pub const GTC_BASE_ADDR: usize = super::mpcore::MPCORE_BASE_ADDR + 0x0000_0200;
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, forbid_overlaps, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct GtcControl {
|
||||
#[bits(8..=15, rw)]
|
||||
prescaler: u8,
|
||||
@@ -16,7 +16,7 @@ pub struct GtcControl {
|
||||
enable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, forbid_overlaps, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct InterruptStatus {
|
||||
#[bit(0, rw)]
|
||||
event_flag: bool,
|
||||
|
||||
@@ -5,22 +5,20 @@ pub const I2C_0_BASE_ADDR: usize = 0xE000_4000;
|
||||
pub const I2C_1_BASE_ADDR: usize = 0xE000_5000;
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum Direction {
|
||||
Receiver = 0b1,
|
||||
Transmitter = 0b0,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum Mode {
|
||||
Slave = 0b0,
|
||||
Master = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_fields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct Control {
|
||||
/// Divides the input PCLK frequency by this value + 1
|
||||
#[bits(14..=15, rw)]
|
||||
@@ -49,7 +47,7 @@ pub struct Control {
|
||||
dir: Direction,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Status {
|
||||
#[bit(8, r)]
|
||||
bus_active: bool,
|
||||
@@ -67,19 +65,19 @@ pub struct Status {
|
||||
rx_rw: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Address {
|
||||
#[bits(0..=9, rw)]
|
||||
addr: u10,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Fifo {
|
||||
#[bits(0..=7, rw)]
|
||||
data: u8,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct InterruptStatus {
|
||||
#[bit(9, rw)]
|
||||
arbitration_lost: bool,
|
||||
@@ -101,7 +99,7 @@ pub struct InterruptStatus {
|
||||
complete: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct InterruptMask {
|
||||
#[bit(9, r)]
|
||||
arbitration_lost: bool,
|
||||
@@ -123,7 +121,7 @@ pub struct InterruptMask {
|
||||
complete: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32)]
|
||||
pub struct InterruptControl {
|
||||
#[bit(9, w)]
|
||||
arbitration_lost: bool,
|
||||
@@ -145,14 +143,14 @@ pub struct InterruptControl {
|
||||
complete: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Timeout {
|
||||
/// Reset value: 0x1F.
|
||||
#[bits(0..=7, rw)]
|
||||
timeout: u8,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct TransferSize {
|
||||
#[bits(0..=7, rw)]
|
||||
size: u8,
|
||||
|
||||
@@ -9,13 +9,13 @@ pub struct LockdownRegisters {
|
||||
instruction: u32,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct CacheSync {
|
||||
#[bit(0, r)]
|
||||
busy: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DebugControl {
|
||||
#[bit(2, rw)]
|
||||
spniden: bool,
|
||||
@@ -25,7 +25,7 @@ pub struct DebugControl {
|
||||
disable_cache_linefill: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct CacheId {
|
||||
#[bits(24..=31, r)]
|
||||
implementer: u8,
|
||||
@@ -56,16 +56,14 @@ impl Control {
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum ReplacementPolicy {
|
||||
PseudoRandomWithLfsr = 0,
|
||||
RoundRobin = 1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u3, exhaustive = true)]
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Default, Debug)]
|
||||
pub enum WaySize {
|
||||
__Reserved0 = 0b000,
|
||||
_16kB = 0b001,
|
||||
@@ -79,21 +77,14 @@ pub enum WaySize {
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Default, Debug)]
|
||||
pub enum Associativity {
|
||||
#[default]
|
||||
_8Way = 0,
|
||||
_16Way = 1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct AuxControl {
|
||||
#[bit(30, rw)]
|
||||
early_bresp_enable: bool,
|
||||
@@ -132,13 +123,7 @@ pub struct AuxControl {
|
||||
full_line_zero_enable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct LatencyConfig {
|
||||
/// Latency is the numerical value + 1 cycles.
|
||||
@@ -152,7 +137,7 @@ pub struct LatencyConfig {
|
||||
setup_latency: u3,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct InterruptStatus {
|
||||
#[bit(8, r)]
|
||||
dec_error_l3: bool,
|
||||
@@ -175,12 +160,7 @@ pub struct InterruptStatus {
|
||||
event_counter_overflow_increment: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct InterruptControl {
|
||||
#[bit(8, w)]
|
||||
|
||||
@@ -8,10 +8,6 @@
|
||||
//! on top of it.
|
||||
//! [The Zynq7000 HAL library](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000-hal)
|
||||
//! contains such a HAL which builds on this PAC.
|
||||
//!
|
||||
//! ## Features
|
||||
//!
|
||||
//! * `defmt` - Add support for the [`defmt`](https://github.com/knurling-rs/defmt) logging library.
|
||||
#![no_std]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
|
||||
@@ -33,7 +29,6 @@ pub mod l2_cache;
|
||||
pub mod mpcore;
|
||||
pub mod priv_tim;
|
||||
pub mod qspi;
|
||||
pub mod sdio;
|
||||
pub mod slcr;
|
||||
pub mod spi;
|
||||
pub mod ttc;
|
||||
@@ -68,8 +63,6 @@ pub struct Peripherals {
|
||||
pub qspi: qspi::MmioRegisters<'static>,
|
||||
pub devcfg: devcfg::MmioRegisters<'static>,
|
||||
pub xadc: xadc::MmioRegisters<'static>,
|
||||
pub sdio_0: sdio::MmioRegisters<'static>,
|
||||
pub sdio_1: sdio::MmioRegisters<'static>,
|
||||
}
|
||||
|
||||
impl Peripherals {
|
||||
@@ -110,8 +103,6 @@ impl Peripherals {
|
||||
qspi: qspi::Registers::new_mmio_fixed(),
|
||||
devcfg: devcfg::Registers::new_mmio_fixed(),
|
||||
xadc: xadc::Registers::new_mmio_fixed(),
|
||||
sdio_0: sdio::Registers::new_mmio_fixed_0(),
|
||||
sdio_1: sdio::Registers::new_mmio_fixed_1(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,7 +110,6 @@ impl Peripherals {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum SpiClockPhase {
|
||||
ActiveOutsideOfWord = 0,
|
||||
InactiveOutsideOfWord = 1,
|
||||
@@ -127,7 +117,6 @@ pub enum SpiClockPhase {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum SpiClockPolarity {
|
||||
QuiescentLow = 0,
|
||||
QuiescentHigh = 1,
|
||||
|
||||
@@ -19,7 +19,7 @@ pub const GICD_BASE_ADDR: usize = MPCORE_BASE_ADDR + 0x1000;
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct SnoopControlUnit {
|
||||
control: u32,
|
||||
ctrl: u32,
|
||||
config: u32,
|
||||
cpu_power_status: u32,
|
||||
invalidate_all_regs_in_secure_state: u32,
|
||||
|
||||
@@ -2,13 +2,7 @@
|
||||
|
||||
pub const CPU_PRIV_TIM_BASE_ADDR: usize = super::mpcore::MPCORE_BASE_ADDR + 0x0000_0600;
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct Control {
|
||||
#[bits(8..=15, rw)]
|
||||
prescaler: u8,
|
||||
@@ -20,13 +14,7 @@ pub struct Control {
|
||||
enable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct InterruptStatus {
|
||||
/// Cleared by writing a one.
|
||||
#[bit(0, rw)]
|
||||
|
||||
@@ -6,7 +6,6 @@ pub const QSPI_BASE_ADDR: usize = 0xE000D000;
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum InterfaceMode {
|
||||
LegacySpi = 0,
|
||||
FlashMemoryInterface = 1,
|
||||
@@ -14,7 +13,6 @@ pub enum InterfaceMode {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Endianness {
|
||||
Little = 0,
|
||||
Big = 1,
|
||||
@@ -23,7 +21,6 @@ pub enum Endianness {
|
||||
/// Baud rate divisor register values.
|
||||
#[bitbybit::bitenum(u3, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum BaudRateDivisor {
|
||||
_2 = 0b000,
|
||||
_4 = 0b001,
|
||||
@@ -51,13 +48,9 @@ impl BaudRateDivisor {
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
// TODO: Use bitbybit debug support as soon as support for write fields has been implemented.
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct Config {
|
||||
#[bit(31, rw)]
|
||||
interface_mode: InterfaceMode,
|
||||
@@ -244,7 +237,7 @@ pub struct Registers {
|
||||
/// Transmits 1-byte command and 3-byte data OR 4-byte data.
|
||||
#[mmio(Write)]
|
||||
tx_data_00: u32,
|
||||
#[mmio(Read)]
|
||||
#[mmio(PureRead)]
|
||||
rx_data: u32,
|
||||
slave_idle_count: u32,
|
||||
/// Defines the level at which the TX FIFO not full interrupt is generated.
|
||||
|
||||
@@ -1,542 +0,0 @@
|
||||
use arbitrary_int::{u2, u3, u4, u6, u12};
|
||||
|
||||
pub const SDIO_BASE_ADDR_0: usize = 0xE010_0000;
|
||||
pub const SDIO_BASE_ADDR_1: usize = 0xE010_1000;
|
||||
|
||||
#[bitbybit::bitenum(u3, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum BufferSize {
|
||||
_4kB = 0b000,
|
||||
_8kB = 0b001,
|
||||
_16kB = 0b010,
|
||||
_32kB = 0b011,
|
||||
_64kB = 0b100,
|
||||
_128kB = 0b101,
|
||||
_256kB = 0b110,
|
||||
_512kB = 0b111,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
debug,
|
||||
default = 0x0,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
pub struct BlockParams {
|
||||
#[bits(16..=31, rw)]
|
||||
blocks_count: u16,
|
||||
#[bits(12..=14, rw)]
|
||||
buffer_size: BufferSize,
|
||||
#[bits(0..=11, rw)]
|
||||
block_size: u12,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum CommandType {
|
||||
#[default]
|
||||
Normal = 0b00,
|
||||
Suspend = 0b01,
|
||||
Resume = 0b10,
|
||||
Abort = 0b11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ResponseType {
|
||||
// No response.
|
||||
None = 0b00,
|
||||
_136bits = 0b01,
|
||||
_48bits = 0b10,
|
||||
_48bitsWithCheck = 0b11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum BlockSelect {
|
||||
SingleBlock = 0,
|
||||
MultiBlock = 1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum TransferDirection {
|
||||
/// Host to card.
|
||||
Write = 0,
|
||||
/// Card to host.
|
||||
Read = 1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
pub struct CommandRegister {
|
||||
/// Set to command number (CMD0-63, ACMD0-63)
|
||||
#[bits(24..=29, rw)]
|
||||
command_index: u6,
|
||||
#[bits(22..=23, rw)]
|
||||
command_type: CommandType,
|
||||
/// Set to [false] for the following:
|
||||
///
|
||||
/// 1. Commands using only CMD line (ex. CMD52).
|
||||
/// 2. Commands with no data transfer but using busy signal on DAT\[0\].
|
||||
/// 3. Resume Command.
|
||||
#[bit(21, rw)]
|
||||
data_is_present: bool,
|
||||
/// When 1, the host controller checks the index field in the response to see if it has the
|
||||
/// same value as the command index.
|
||||
#[bit(20, rw)]
|
||||
command_index_check_enable: bool,
|
||||
/// When 1, the host controller checks the CRC field in the response.
|
||||
#[bit(18, rw)]
|
||||
command_crc_check_enable: bool,
|
||||
#[bits(16..=17, rw)]
|
||||
response_type_select: ResponseType,
|
||||
#[bit(5, rw)]
|
||||
block_select: BlockSelect,
|
||||
#[bit(4, rw)]
|
||||
data_transfer_direction: TransferDirection,
|
||||
/// Multiple block transfers for memory require CMD12 to stop the transaction. When this bit is
|
||||
/// 1, the host controller issues CMD12 automatically when completing the last block tranfer.
|
||||
#[bit(2, rw)]
|
||||
auto_cmd12_enable: bool,
|
||||
/// Enable block count register, which is only relevant for multiple block transfers.
|
||||
#[bit(1, rw)]
|
||||
block_count_enable: bool,
|
||||
#[bit(0, rw)]
|
||||
dma_enable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"), forbid_overlaps)]
|
||||
pub struct PresentState {
|
||||
#[bit(24, r)]
|
||||
cmd_line_signal_level: bool,
|
||||
#[bits(20..=23, r)]
|
||||
data_line_signal_level: u4,
|
||||
/// The Write Protect Switch is supported for memory and combo cards. This bit reflects the
|
||||
/// inversion of the SDx_WP pin.
|
||||
#[bit(19, r)]
|
||||
write_protect_switch_level: bool,
|
||||
/// This bit reflects the inverse value of the SDx_CDn pin.
|
||||
#[bit(18, r)]
|
||||
card_detect_pin_level: bool,
|
||||
/// This bit is used for testing. If it is 0, the Card Detect Pin Level is not stable. If this
|
||||
/// bit is set to 1, it means the Card Detect Pin Level is stable. The Software Reset For All
|
||||
/// in the Software Reset Register shall not affect this bit.
|
||||
#[bit(17, r)]
|
||||
card_state_stable: bool,
|
||||
/// This bit indicates whether a card has been inserted. Changing from 0 to 1 generates a Card
|
||||
/// Insertion interrupt in the Normal Interrupt Status register and changing from 1 to 0
|
||||
/// generates a Card Removal Interrupt in the Normal Interrupt Status register. The Software
|
||||
/// Reset For All in the Software Reset register shall not affect this bit. If a Card is
|
||||
/// removed while its power is on and its clock is oscillating, the HC shall clear SD Bus Power
|
||||
/// in the Power Control register and SD Clock Enable in the Clock control register. In
|
||||
/// addition the HD should clear the HC by the Software Reset For All in Software register. The
|
||||
/// card detect is active regardless of the SD Bus Power.
|
||||
#[bit(16, r)]
|
||||
card_inserted: bool,
|
||||
/// This status is used for non-DMA read transfers. This read only flag indicates that valid
|
||||
/// data exists in the host side buffer status. If this bit is 1, readable data exists in the
|
||||
/// buffer. A change of this bit from 1 to 0 occurs when all the block data is read from the
|
||||
/// buffer. A change of this bit from 0 to 1 occurs when all the block data is ready in the
|
||||
/// buffer and generates the Buffer Read Ready Interrupt.
|
||||
#[bit(11, r)]
|
||||
buffer_readable: bool,
|
||||
/// This status is used for non-DMA write transfers. This read only flag indicates if space is
|
||||
/// available for write data. If this bit is 1, data can be written to the buffer. A change of
|
||||
/// this bit from 1 to 0 occurs when all the block data is written to the buffer. A change of
|
||||
/// this bit from 0 to 1 occurs when top of block data can be written to the buffer and
|
||||
/// generates the Buffer Write Ready Interrupt.
|
||||
#[bit(10, r)]
|
||||
buffer_writable: bool,
|
||||
/// This status is used for detecting completion of a read transfer. This bit is set to 1 for
|
||||
/// either of the following conditions:
|
||||
///
|
||||
/// 1. After the end bit of the read command
|
||||
/// 2. When writing a 1 to continue Request in the Block Gap Control register to restart a read
|
||||
/// transfer.
|
||||
///
|
||||
/// This bit is cleared to 0 for either of the following conditions:
|
||||
///
|
||||
/// 1. When the last data block as specified by block length is transferred to the system.
|
||||
/// 2. When all valid data blocks have been transferred to the system and no current block
|
||||
/// transfers are being sent as a result of the Stop At Block Gap Request set to 1. A transfer
|
||||
/// complete interrupt is generated when this bit changes to 0.
|
||||
#[bit(9, r)]
|
||||
read_transfer_active: bool,
|
||||
/// This status indicates a write transfer is active. If this bit is 0, it means no valid write
|
||||
/// data exists in the HC. This bit is set in either of the following cases: 1. After the end
|
||||
/// bit of the write command. 2. When writing a 1 to Continue Request in the Block Gap Control
|
||||
/// register to restart a write transfer.
|
||||
///
|
||||
/// This bit is cleared in either of the following cases:
|
||||
///
|
||||
/// 1. After getting the CRC status of the last data block as specified by the transfer count
|
||||
/// (Single or Multiple)
|
||||
/// 2. After getting a CRC status of any block where data transmission is about to be stopped
|
||||
/// by a Stop At Block Gap Request.
|
||||
///
|
||||
/// During a write transaction, a Block Gap Event interrupt is generated when this bit is
|
||||
/// changed to 0, as a result of the Stop At Block Gap Request being set. This status is useful
|
||||
/// for the HD in determining when to issue commands during write busy.
|
||||
#[bit(8, r)]
|
||||
write_transfer_active: bool,
|
||||
#[bit(2, r)]
|
||||
dat_line_active: bool,
|
||||
/// This status bit is generated if either the DAT Line Active or the Read transfer Active is
|
||||
/// set to 1. If this bit is 0, it indicates the HC can issue the next SD command. Commands
|
||||
/// with busy signal belong to Command Inhibit (DAT) (ex. R1b, R5b type). Changing from 1 to 0
|
||||
/// generates a Transfer Complete interrupt in the Normal interrupt status register.
|
||||
#[bit(1, r)]
|
||||
command_inhibit_dat: bool,
|
||||
/// 0 indicates the CMD line is not in use and the host controller can issue a SD command
|
||||
/// using the CMD line. This bit is set immediately after the Command register (00Fh) is
|
||||
/// written. This bit is cleared when the command response is received. Even if the Command
|
||||
/// Inhibit (DAT) is set to 1, Commands using only the CMD line can be issued if this bit is 0.
|
||||
/// Changing from 1 to 0 generates a Command complete interrupt in the Normal Interrupt Status
|
||||
/// register. If the HC cannot issue the command because of a command conflict error or because
|
||||
/// of Command Not Issued By Auto CMD12 Error, this bit shall remain 1 and the Command Complete
|
||||
/// is not set. Status issuing Auto CMD12 is not read from this bit.
|
||||
#[bit(0, r)]
|
||||
command_inhibit_cmd: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum BusWidth {
|
||||
_1bit = 0,
|
||||
_4bits = 1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum DmaSelect {
|
||||
Sdma = 0b00,
|
||||
Adma1_32bits = 0b01,
|
||||
Adma2_32bits = 0b10,
|
||||
Adma2_64bits = 0b11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u3, exhaustive = false)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum SdBusVoltageSelect {
|
||||
Off = 0b000,
|
||||
_1_8V = 0b101,
|
||||
_3_0V = 0b110,
|
||||
_3_3V = 0b111,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
pub struct HostPowerBlockgapWakeupControl {
|
||||
#[bit(26, rw)]
|
||||
wakeup_event_enable_on_sd_card_removal: bool,
|
||||
#[bit(25, rw)]
|
||||
wakeup_event_enable_on_sd_card_insertion: bool,
|
||||
#[bit(24, rw)]
|
||||
wakeup_event_enable_on_card_interrupt: bool,
|
||||
#[bit(19, rw)]
|
||||
interrupt_at_block_gap: bool,
|
||||
#[bit(18, rw)]
|
||||
read_wait_control: bool,
|
||||
#[bit(17, rw)]
|
||||
continue_request: bool,
|
||||
#[bit(16, rw)]
|
||||
stop_as_block_gap_request: bool,
|
||||
#[bits(9..=11, rw)]
|
||||
sd_bus_voltage_select: Option<SdBusVoltageSelect>,
|
||||
#[bit(8, rw)]
|
||||
sd_bus_power: bool,
|
||||
#[bit(7, rw)]
|
||||
card_detect_signal_detection: bool,
|
||||
#[bit(6, rw)]
|
||||
card_detetect_test_level: bool,
|
||||
#[bits(3..=4, rw)]
|
||||
dma_select: DmaSelect,
|
||||
#[bit(2, rw)]
|
||||
high_speed_enable: bool,
|
||||
#[bit(1, rw)]
|
||||
bus_width: BusWidth,
|
||||
#[bit(0, rw)]
|
||||
led_control: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u8, exhaustive = false)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum SdClockDivisor {
|
||||
Div256 = 0x80,
|
||||
Div128 = 0x40,
|
||||
Div64 = 0x20,
|
||||
Div32 = 0x10,
|
||||
Div16 = 0x08,
|
||||
Div8 = 0x04,
|
||||
Div4 = 0x02,
|
||||
Div2 = 0x01,
|
||||
Div1 = 0x00,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
pub struct ClockAndTimeoutAndSwResetControl {
|
||||
#[bit(26, rw)]
|
||||
software_reset_for_dat_line: bool,
|
||||
#[bit(25, rw)]
|
||||
software_reset_for_cmd_line: bool,
|
||||
#[bit(24, rw)]
|
||||
software_reset_for_all: bool,
|
||||
/// Interval: TMCLK * 2^(13 + register value)
|
||||
///
|
||||
/// 0b1111 is reserved.
|
||||
#[bits(16..=19, rw)]
|
||||
data_timeout_counter_value: u4,
|
||||
#[bits(8..=15, rw)]
|
||||
sdclk_frequency_select: Option<SdClockDivisor>,
|
||||
#[bit(2, rw)]
|
||||
sd_clock_enable: bool,
|
||||
#[bit(1, r)]
|
||||
internal_clock_stable: bool,
|
||||
#[bit(0, rw)]
|
||||
internal_clock_enable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"), forbid_overlaps)]
|
||||
pub struct InterruptStatus {
|
||||
#[bit(29, rw)]
|
||||
ceata_error_status: bool,
|
||||
#[bit(28, rw)]
|
||||
target_response_error: bool,
|
||||
#[bit(25, rw)]
|
||||
adma_error: bool,
|
||||
#[bit(24, rw)]
|
||||
auto_cmd12_error: bool,
|
||||
#[bit(23, rw)]
|
||||
current_limit_error: bool,
|
||||
#[bit(22, rw)]
|
||||
data_end_bit_error: bool,
|
||||
#[bit(21, rw)]
|
||||
data_crc_error: bool,
|
||||
#[bit(20, rw)]
|
||||
data_timeout_error: bool,
|
||||
#[bit(19, rw)]
|
||||
command_index_error: bool,
|
||||
#[bit(18, rw)]
|
||||
command_end_bit_error: bool,
|
||||
#[bit(17, rw)]
|
||||
command_crc_error: bool,
|
||||
#[bit(16, rw)]
|
||||
command_timeout_error: bool,
|
||||
#[bit(15, r)]
|
||||
error_interrupt: bool,
|
||||
#[bit(10, rw)]
|
||||
boot_terminate: bool,
|
||||
#[bit(9, rw)]
|
||||
boot_ack_recv: bool,
|
||||
#[bit(8, r)]
|
||||
card_interrupt: bool,
|
||||
#[bit(7, rw)]
|
||||
card_removal: bool,
|
||||
#[bit(6, rw)]
|
||||
card_insertion: bool,
|
||||
#[bit(5, rw)]
|
||||
buffer_read_ready: bool,
|
||||
#[bit(4, rw)]
|
||||
buffer_write_ready: bool,
|
||||
#[bit(3, rw)]
|
||||
dma_interrupt: bool,
|
||||
#[bit(2, rw)]
|
||||
blockgap_event: bool,
|
||||
#[bit(1, rw)]
|
||||
transfer_complete: bool,
|
||||
#[bit(0, rw)]
|
||||
command_complete: bool,
|
||||
}
|
||||
|
||||
impl InterruptStatus {
|
||||
pub const ALL_BITS: u32 = 0x33FF06FF;
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
|
||||
pub struct InterruptMask {
|
||||
#[bit(29, rw)]
|
||||
ceata_error_status: bool,
|
||||
#[bit(28, rw)]
|
||||
target_response_error: bool,
|
||||
#[bit(25, rw)]
|
||||
adma_error: bool,
|
||||
#[bit(24, rw)]
|
||||
auto_cmd12_error: bool,
|
||||
#[bit(23, rw)]
|
||||
current_limit_error: bool,
|
||||
#[bit(22, rw)]
|
||||
data_end_bit_error: bool,
|
||||
#[bit(21, rw)]
|
||||
data_crc_error: bool,
|
||||
#[bit(20, rw)]
|
||||
data_timeout_error: bool,
|
||||
#[bit(19, rw)]
|
||||
command_index_error: bool,
|
||||
#[bit(18, rw)]
|
||||
command_end_bit_error: bool,
|
||||
#[bit(17, rw)]
|
||||
command_crc_error: bool,
|
||||
#[bit(16, rw)]
|
||||
command_timeout_error: bool,
|
||||
#[bit(15, rw)]
|
||||
error_interrupt: bool,
|
||||
#[bit(10, rw)]
|
||||
boot_terminate: bool,
|
||||
#[bit(9, rw)]
|
||||
boot_ack_recv: bool,
|
||||
#[bit(8, rw)]
|
||||
card_interrupt: bool,
|
||||
#[bit(7, rw)]
|
||||
card_removal: bool,
|
||||
#[bit(6, rw)]
|
||||
card_insertion: bool,
|
||||
#[bit(5, rw)]
|
||||
buffer_read_ready: bool,
|
||||
#[bit(4, rw)]
|
||||
buffer_write_ready: bool,
|
||||
#[bit(3, rw)]
|
||||
dma_interrupt: bool,
|
||||
#[bit(2, rw)]
|
||||
blockgap_event: bool,
|
||||
#[bit(1, rw)]
|
||||
transfer_complete: bool,
|
||||
#[bit(0, rw)]
|
||||
command_complete: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
|
||||
pub struct Capabilities {
|
||||
#[bit(30, rw)]
|
||||
spi_block_mode: bool,
|
||||
#[bit(29, rw)]
|
||||
spi_mode: bool,
|
||||
#[bit(28, rw)]
|
||||
_64_bit_system_bus_support: bool,
|
||||
#[bit(27, rw)]
|
||||
interrupt_mode: bool,
|
||||
#[bit(26, rw)]
|
||||
voltage_support_1_8v: bool,
|
||||
#[bit(25, rw)]
|
||||
voltage_support_3_0v: bool,
|
||||
#[bit(24, rw)]
|
||||
voltage_support_3_3v: bool,
|
||||
#[bit(23, rw)]
|
||||
suspend_resume_support: bool,
|
||||
#[bit(22, rw)]
|
||||
sdma_support: bool,
|
||||
#[bit(21, rw)]
|
||||
high_speed_support: bool,
|
||||
#[bit(19, rw)]
|
||||
adma2_support: bool,
|
||||
#[bit(18, rw)]
|
||||
extended_media_bus_support: bool,
|
||||
#[bits(16..=17, rw)]
|
||||
max_block_length: u2,
|
||||
#[bit(7, rw)]
|
||||
timeout_clock_unit: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
|
||||
pub struct BlockSizeRegister {
|
||||
/// Enabled when block count enable in the transfer mode register is set to 1 and only
|
||||
/// valid for multiple block transfers.
|
||||
#[bits(16..=31, rw)]
|
||||
block_counts_for_current_transfer: u16,
|
||||
#[bits(12..=14, rw)]
|
||||
host_sdma_buffer_size: u3,
|
||||
#[bits(0..=11, rw)]
|
||||
transfer_block_size: u12,
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct Registers {
|
||||
sdma_system_addr: u32,
|
||||
block_params: BlockSizeRegister,
|
||||
/// Bit 39-8 of Command-Format.
|
||||
argument: u32,
|
||||
command: CommandRegister,
|
||||
#[mmio(PureRead)]
|
||||
responses: [u32; 4],
|
||||
buffer_data_port: u32,
|
||||
#[mmio(PureRead)]
|
||||
present_state: PresentState,
|
||||
host_power_blockgap_wakeup_control: HostPowerBlockgapWakeupControl,
|
||||
clock_timeout_sw_reset_control: ClockAndTimeoutAndSwResetControl,
|
||||
interrupt_status: InterruptStatus,
|
||||
interrupt_status_enable: InterruptMask,
|
||||
interrupt_signal_enable: InterruptMask,
|
||||
#[mmio(PureRead)]
|
||||
auto_cmd12_error_status: u32,
|
||||
#[mmio(PureRead)]
|
||||
capabilities: Capabilities,
|
||||
_gap_0: u32,
|
||||
#[mmio(PureRead)]
|
||||
maximum_current_capabilities: u32,
|
||||
_gap_1: u32,
|
||||
force_event_register: u32,
|
||||
adma_error_status: u32,
|
||||
adma_system_address: u32,
|
||||
_gap_2: u32,
|
||||
boot_timeout_control: u32,
|
||||
debug_selection: u32,
|
||||
_gap_3: [u32; 0x22],
|
||||
spi_interrupt_support: u32,
|
||||
_gap_4: [u32; 0x2],
|
||||
slot_interrupt_status_host_controll_version: u32,
|
||||
}
|
||||
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<Registers>(), 0x100);
|
||||
|
||||
impl Registers {
|
||||
/// Create a new SDIO MMIO instance for SDIO 0 at address [SDIO_BASE_ADDR_0].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
#[inline]
|
||||
pub const unsafe fn new_mmio_fixed_0() -> MmioRegisters<'static> {
|
||||
unsafe { Self::new_mmio_at(SDIO_BASE_ADDR_0) }
|
||||
}
|
||||
|
||||
/// Create a new SDIO MMIO instance for SDIO 1 at address [SDIO_BASE_ADDR_1].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
#[inline]
|
||||
pub const unsafe fn new_mmio_fixed_1() -> MmioRegisters<'static> {
|
||||
unsafe { Self::new_mmio_at(SDIO_BASE_ADDR_1) }
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
use super::{CLOCK_CONTROL_OFFSET, SLCR_BASE_ADDR};
|
||||
use arbitrary_int::{u4, u6, u7, u10};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Bypass {
|
||||
NotBypassed = 0b00,
|
||||
/// This is the default reset value.
|
||||
@@ -13,13 +12,7 @@ pub enum Bypass {
|
||||
BypassedRegardlessOfPinStrapping = 0b11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct PllControl {
|
||||
/// Feedback divisor for the PLL.
|
||||
///
|
||||
@@ -75,7 +68,7 @@ impl PllControl {
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct PllConfig {
|
||||
#[bits(12..=21, rw)]
|
||||
lock_count: u10,
|
||||
@@ -87,7 +80,7 @@ pub struct PllConfig {
|
||||
loop_resistor: u4,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct PllStatus {
|
||||
#[bit(5, r)]
|
||||
io_pll_stable: bool,
|
||||
@@ -103,7 +96,7 @@ pub struct PllStatus {
|
||||
arm_pll_lock: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_fields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct FpgaClockControl {
|
||||
// Reset value 0x1
|
||||
#[bits(20..=25, rw)]
|
||||
@@ -135,7 +128,7 @@ pub enum SrcSelArm {
|
||||
IoPll = 0b11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, default = 0x0)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct ArmClockControl {
|
||||
#[bit(28, rw)]
|
||||
cpu_peri_clk_act: bool,
|
||||
@@ -185,32 +178,24 @@ pub struct DciClockControl {
|
||||
clk_act: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, default = 0x0)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct ClockRatioSelectReg {
|
||||
/// Reset value: 0x1 (6:2:1 clock)
|
||||
#[bit(0, rw)]
|
||||
sel: CpuClockRatio,
|
||||
sel: ClockkRatioSelect,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum CpuClockRatio {
|
||||
pub enum ClockkRatioSelect {
|
||||
/// 4:2:1 clock ratio, which is an abbreviation for 4:2:2:1.
|
||||
///
|
||||
/// The 4x clock is calculated by dividing the reference clock
|
||||
/// by the divisor, the rest by dividing by 2, 2 and 4 respectively.
|
||||
FourToTwoToOne = 0b0,
|
||||
/// 6:2:1 clock ratio, which is an abbreviation for 6:3:2:1.
|
||||
///
|
||||
/// The 6x clock is calculated by dividing the reference clock
|
||||
/// by the divisor, the rest by dividing by 2, 3 and 6 respectively.
|
||||
SixToTwoToOne = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Debug, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum SrcSelIo {
|
||||
IoPll = 0b00,
|
||||
IoPllAlt = 0b01,
|
||||
@@ -237,13 +222,7 @@ impl PartialEq for SrcSelIo {
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct GigEthClockControl {
|
||||
#[bits(20..=25, rw)]
|
||||
divisor_1: u6,
|
||||
@@ -258,20 +237,13 @@ pub struct GigEthClockControl {
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum SrcSelGigEthRclk {
|
||||
Mio = 0,
|
||||
Emio = 1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct GigEthRclkControl {
|
||||
#[bit(4, rw)]
|
||||
srcsel: SrcSelGigEthRclk,
|
||||
@@ -280,13 +252,8 @@ pub struct GigEthRclkControl {
|
||||
clk_enable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct CanClockControl {
|
||||
#[bits(20..=25, rw)]
|
||||
divisor_1: u6,
|
||||
@@ -300,13 +267,7 @@ pub struct CanClockControl {
|
||||
clk_0_act: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
pub struct SingleCommonPeriphIoClockControl {
|
||||
#[bits(8..=13, rw)]
|
||||
divisor: u6,
|
||||
@@ -316,13 +277,7 @@ pub struct SingleCommonPeriphIoClockControl {
|
||||
clk_act: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct DualCommonPeriphIoClockControl {
|
||||
#[bits(8..=13, rw)]
|
||||
divisor: u6,
|
||||
@@ -335,8 +290,7 @@ pub struct DualCommonPeriphIoClockControl {
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u3, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum SrcSelTpiu {
|
||||
IoPll = 0b000,
|
||||
IoPllAlt = 0b001,
|
||||
@@ -348,13 +302,7 @@ pub enum SrcSelTpiu {
|
||||
EmioTraceClkAlt2 = 0b111,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct TracePortClockControl {
|
||||
#[bits(8..=13, rw)]
|
||||
divisor: u6,
|
||||
@@ -369,13 +317,7 @@ pub struct TracePortClockControl {
|
||||
/// AMBA peripheral clock control.
|
||||
///
|
||||
/// These clocks must be enabled if you want to read from the peripheral register space.
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct AperClockControl {
|
||||
#[bit(24, rw)]
|
||||
smc_1x_clk_act: bool,
|
||||
@@ -457,7 +399,7 @@ pub struct ClockControlRegisters {
|
||||
#[mmio(Inner)]
|
||||
fpga_3_clk_ctrl: FpgaClockControlRegisters,
|
||||
_gap1: [u32; 5],
|
||||
clk_ratio_select: ClockRatioSelectReg,
|
||||
clk_621_true: ClockRatioSelectReg,
|
||||
}
|
||||
|
||||
impl ClockControlRegisters {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use arbitrary_int::{u2, u3};
|
||||
|
||||
#[bitbybit::bitenum(u4, exhaustive = false)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum VRefSel {
|
||||
/// VREF = 0.6 V
|
||||
Lpddr2 = 0b0001,
|
||||
@@ -14,13 +13,7 @@ pub enum VRefSel {
|
||||
Ddr2 = 0b1000,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct DdrControl {
|
||||
/// Enables VRP/VRN.
|
||||
#[bit(9, rw)]
|
||||
@@ -35,13 +28,7 @@ pub struct DdrControl {
|
||||
vref_int_en: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x00,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x00, debug)]
|
||||
pub struct DciControl {
|
||||
#[bit(20, rw)]
|
||||
update_control: bool,
|
||||
@@ -62,13 +49,7 @@ pub struct DciControl {
|
||||
reset: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct DciStatus {
|
||||
#[bit(13, rw)]
|
||||
done: bool,
|
||||
@@ -77,8 +58,7 @@ pub struct DciStatus {
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum OutputEnable {
|
||||
IBuf = 0b00,
|
||||
__Reserved0 = 0b01,
|
||||
@@ -87,8 +67,7 @@ pub enum OutputEnable {
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum InputType {
|
||||
Off = 0b00,
|
||||
VRefBasedDifferentialReceiverForSstlHstl = 0b01,
|
||||
@@ -97,8 +76,7 @@ pub enum InputType {
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum DciType {
|
||||
Disabled = 0b00,
|
||||
DciDrive = 0b01,
|
||||
@@ -106,13 +84,7 @@ pub enum DciType {
|
||||
DciTermination = 0b11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DdriobConfig {
|
||||
#[bit(11, rw)]
|
||||
pullup_enable: bool,
|
||||
@@ -146,8 +118,8 @@ pub struct DdrIobRegisters {
|
||||
ddriob_drive_slew_data: u32,
|
||||
ddriob_drive_slew_diff: u32,
|
||||
ddriob_drive_slew_clock: u32,
|
||||
ddr_control: DdrControl,
|
||||
dci_control: DciControl,
|
||||
ddr_ctrl: DdrControl,
|
||||
dci_ctrl: DciControl,
|
||||
dci_status: DciStatus,
|
||||
}
|
||||
|
||||
|
||||
@@ -4,16 +4,14 @@
|
||||
use arbitrary_int::{u2, u3};
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum Speed {
|
||||
SlowCmosEdge = 0b0,
|
||||
FastCmosEdge = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u3)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum IoType {
|
||||
LvCmos18 = 0b001,
|
||||
LvCmos25 = 0b010,
|
||||
@@ -21,7 +19,7 @@ pub enum IoType {
|
||||
Hstl = 0b100,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_fields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct Config {
|
||||
#[bit(13, rw)]
|
||||
|
||||
@@ -17,14 +17,14 @@ pub mod mio;
|
||||
pub mod reset;
|
||||
|
||||
#[bitbybit::bitenum(u3, exhaustive = false)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum VrefSel {
|
||||
Disabled = 0b000,
|
||||
Vref0_9V = 0b001,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0, debug, defmt_fields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct GpiobControl {
|
||||
#[bit(11, rw)]
|
||||
vref_sw_en: bool,
|
||||
@@ -62,14 +62,14 @@ impl GpiobRegisters {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum BootPllConfig {
|
||||
Enabled = 0,
|
||||
/// Disabled and bypassed.
|
||||
Bypassed = 1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0, debug, defmt_fields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct BootModeRegister {
|
||||
#[bit(4, r)]
|
||||
pll_config: BootPllConfig,
|
||||
@@ -79,20 +79,13 @@ pub struct BootModeRegister {
|
||||
|
||||
#[bitbybit::bitenum(u4)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum LevelShifterConfig {
|
||||
DisableAll = 0x00,
|
||||
EnablePsToPl = 0xA,
|
||||
EnableAll = 0xF,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct LevelShifterRegister {
|
||||
#[bits(0..=3, rw)]
|
||||
user_lvl_shftr_en: Option<LevelShifterConfig>,
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
use arbitrary_int::u17;
|
||||
|
||||
use super::{RESET_BLOCK_OFFSET, SLCR_BASE_ADDR};
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DualClockReset {
|
||||
/// Peripheral 1 AMBA software reset.
|
||||
#[bit(1, rw)]
|
||||
@@ -18,14 +10,8 @@ pub struct DualClockReset {
|
||||
periph0_cpu1x_rst: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
pub struct DualRefAndClockResetSpiUart {
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DualRefAndClockReset {
|
||||
/// Periperal 1 Reference software reset.
|
||||
#[bit(3, rw)]
|
||||
periph1_ref_rst: bool,
|
||||
@@ -40,47 +26,13 @@ pub struct DualRefAndClockResetSpiUart {
|
||||
periph0_cpu1x_rst: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
pub struct DualRefAndClockResetSdio {
|
||||
/// Periperal 1 Reference software reset.
|
||||
#[bit(5, rw)]
|
||||
periph1_ref_rst: bool,
|
||||
/// Peripheral 0 Reference software reset.
|
||||
#[bit(4, rw)]
|
||||
periph0_ref_rst: bool,
|
||||
/// Peripheral 1 AMBA software reset.
|
||||
#[bit(1, rw)]
|
||||
periph1_cpu1x_rst: bool,
|
||||
/// Peripheral 0 AMBA software reset.
|
||||
#[bit(0, rw)]
|
||||
periph0_cpu1x_rst: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct GpioClockReset {
|
||||
#[bit(0, rw)]
|
||||
gpio_cpu1x_rst: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct EthernetReset {
|
||||
#[bit(5, rw)]
|
||||
gem1_ref_rst: bool,
|
||||
@@ -96,152 +48,39 @@ pub struct EthernetReset {
|
||||
gem0_cpu1x_rst: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
pub struct ResetControlQspiSmc {
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct QspiResetControl {
|
||||
#[bit(2, rw)]
|
||||
qspi_ref_reset: bool,
|
||||
#[bit(1, rw)]
|
||||
ref_reset: bool,
|
||||
#[bit(0, rw)]
|
||||
cpu_1x_reset: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
pub struct FpgaResetControl {
|
||||
/// This block always needs to be written with 0. I think it contains some other hidden
|
||||
/// reset lines. This field makes this explicit.
|
||||
#[bits(8..=24, rw)]
|
||||
zero_block_0: u17,
|
||||
#[bit(3, rw)]
|
||||
fpga_3: bool,
|
||||
#[bit(2, rw)]
|
||||
fpga_2: bool,
|
||||
#[bit(1, rw)]
|
||||
fpga_1: bool,
|
||||
#[bit(0, rw)]
|
||||
fpga_0: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
pub struct CpuResetControl {
|
||||
#[bit(8, rw)]
|
||||
peripheral_reset: bool,
|
||||
#[bit(5, rw)]
|
||||
cpu1_clockstop: bool,
|
||||
#[bit(4, rw)]
|
||||
cpu0_clockstop: bool,
|
||||
#[bit(1, rw)]
|
||||
cpu1_reset: bool,
|
||||
#[bit(0, rw)]
|
||||
cpu0_reset: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
pub struct PsResetControl {
|
||||
#[bit(0, rw)]
|
||||
soft_reset: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
pub struct ResetControlSingleBit {
|
||||
#[bit(0, rw)]
|
||||
reset: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
pub struct ResetControlInterconnect {
|
||||
/// Care must be taken to ensure that the AXI
|
||||
/// interconnect does not have outstanding
|
||||
/// transactions and the bus is idle.
|
||||
#[bit(0, rw)]
|
||||
reset: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ApuWatchdogTarget {
|
||||
/// Same system level as PS_SRST_B.
|
||||
PsSrstB = 1,
|
||||
CpuAssociatedWithWdt = 0,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
pub struct WatchTimerResetControl {
|
||||
#[bit(1, rw)]
|
||||
apu_wdt_1_reset_target: ApuWatchdogTarget,
|
||||
#[bit(0, rw)]
|
||||
apu_wdt_0_reset_target: ApuWatchdogTarget,
|
||||
}
|
||||
|
||||
/// Reset control block.
|
||||
///
|
||||
/// All reset signal bits are active high, writing a 1 asserts the reset.
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct ResetControl {
|
||||
/// Processing System Software reset control
|
||||
pss: PsResetControl,
|
||||
ddr: ResetControlSingleBit,
|
||||
/// PS Software reset control
|
||||
pss: u32,
|
||||
ddr: u32,
|
||||
/// Central interconnect reset control
|
||||
topsw: ResetControlInterconnect,
|
||||
dmac: ResetControlSingleBit,
|
||||
usb: DualClockReset,
|
||||
topsw: u32,
|
||||
dmac: u32,
|
||||
usb: u32,
|
||||
eth: EthernetReset,
|
||||
sdio: DualRefAndClockResetSdio,
|
||||
spi: DualRefAndClockResetSpiUart,
|
||||
sdio: DualRefAndClockReset,
|
||||
spi: DualRefAndClockReset,
|
||||
can: DualClockReset,
|
||||
i2c: DualClockReset,
|
||||
uart: DualRefAndClockResetSpiUart,
|
||||
uart: DualRefAndClockReset,
|
||||
gpio: GpioClockReset,
|
||||
lqspi: ResetControlQspiSmc,
|
||||
smc: ResetControlQspiSmc,
|
||||
ocm: ResetControlSingleBit,
|
||||
lqspi: QspiResetControl,
|
||||
smc: u32,
|
||||
ocm: u32,
|
||||
_gap0: u32,
|
||||
fpga: FpgaResetControl,
|
||||
a9_cpu: CpuResetControl,
|
||||
fpga: u32,
|
||||
a9_cpu: u32,
|
||||
_gap1: u32,
|
||||
rs_awdt: WatchTimerResetControl,
|
||||
rs_awdt: u32,
|
||||
}
|
||||
|
||||
impl ResetControl {
|
||||
|
||||
@@ -9,7 +9,6 @@ pub const SPI_1_BASE_ADDR: usize = 0xE000_7000;
|
||||
/// The SPI reference block will be divided by a divisor value.
|
||||
#[bitbybit::bitenum(u3)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum BaudDivSel {
|
||||
By4 = 0b001,
|
||||
By8 = 0b010,
|
||||
@@ -34,13 +33,8 @@ impl BaudDivSel {
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
// TODO: Use bitbybit debug support as soon as it was added.
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
pub struct Config {
|
||||
#[bit(17, rw)]
|
||||
modefail_gen_en: bool,
|
||||
@@ -73,13 +67,7 @@ pub struct Config {
|
||||
master_ern: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct InterruptStatus {
|
||||
#[bit(6, rw)]
|
||||
tx_underflow: bool,
|
||||
@@ -98,12 +86,7 @@ pub struct InterruptStatus {
|
||||
rx_ovr: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct InterruptControl {
|
||||
#[bit(6, w)]
|
||||
@@ -123,7 +106,7 @@ pub struct InterruptControl {
|
||||
rx_ovr: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct InterruptMask {
|
||||
#[bit(6, r)]
|
||||
tx_underflow: bool,
|
||||
@@ -143,7 +126,6 @@ pub struct InterruptMask {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct FifoWrite(arbitrary_int::UInt<u32, 8>);
|
||||
|
||||
impl FifoWrite {
|
||||
@@ -164,7 +146,6 @@ impl FifoWrite {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct FifoRead(arbitrary_int::UInt<u32, 8>);
|
||||
|
||||
impl FifoRead {
|
||||
@@ -180,13 +161,7 @@ impl FifoRead {
|
||||
}
|
||||
|
||||
/// The numbers specified in the register fields are always specified in number of
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
forbid_overlaps,
|
||||
defmt_bitfields(feature = "defmt")
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct DelayControl {
|
||||
/// Number of cycles the chip select is de-asserted between words when CPHA = 0
|
||||
#[bits(24..=31, rw)]
|
||||
|
||||
@@ -4,9 +4,8 @@ use arbitrary_int::u4;
|
||||
pub const TTC_0_BASE_ADDR: usize = 0xF800_1000;
|
||||
pub const TTC_1_BASE_ADDR: usize = 0xF800_2000;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ClockSource {
|
||||
/// PS internal bus clock.
|
||||
#[default]
|
||||
@@ -14,13 +13,7 @@ pub enum ClockSource {
|
||||
External = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct ClockControl {
|
||||
/// When this bit is set and the external clock is selected, the counter clocks on the
|
||||
/// negative edge of the external clock input.
|
||||
@@ -35,16 +28,14 @@ pub struct ClockControl {
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum Mode {
|
||||
Overflow = 0b0,
|
||||
Interval = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug, Default)]
|
||||
pub enum WavePolarity {
|
||||
/// The waveform output goes from high to low on a match 0 interrupt and returns high on
|
||||
/// overflow or interval interrupt.
|
||||
@@ -56,20 +47,13 @@ pub enum WavePolarity {
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum WaveEnable {
|
||||
Enable = 0b0,
|
||||
Disable = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct CounterControl {
|
||||
#[bit(6, rw)]
|
||||
wave_polarity: WavePolarity,
|
||||
@@ -92,25 +76,19 @@ pub struct CounterControl {
|
||||
disable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_fields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Counter {
|
||||
#[bits(0..=15, r)]
|
||||
count: u16,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_fields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct RwValue {
|
||||
#[bits(0..=15, rw)]
|
||||
value: u16,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct InterruptStatus {
|
||||
/// Even timer overflow interrupt.
|
||||
#[bit(5, r)]
|
||||
@@ -127,13 +105,7 @@ pub struct InterruptStatus {
|
||||
interval: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct InterruptControl {
|
||||
/// Even timer overflow interrupt.
|
||||
#[bit(5, rw)]
|
||||
@@ -150,13 +122,7 @@ pub struct InterruptControl {
|
||||
interval: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct EventControl {
|
||||
/// E_Ov bit. When set to 0, the event timer is disabled and set to 0 when an event timer
|
||||
/// register overflow occurs. Otherwise, continue counting on overflow.
|
||||
@@ -170,7 +136,7 @@ pub struct EventControl {
|
||||
enable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"), forbid_overlaps)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct EventCount {
|
||||
#[bits(0..=15, r)]
|
||||
count: u16,
|
||||
|
||||
@@ -5,8 +5,7 @@ pub const UART_0_BASE: usize = 0xE000_0000;
|
||||
pub const UART_1_BASE: usize = 0xE000_1000;
|
||||
|
||||
#[bitbybit::bitenum(u3, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum Parity {
|
||||
Even = 0b000,
|
||||
Odd = 0b001,
|
||||
@@ -22,7 +21,6 @@ pub enum Parity {
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum CharLen {
|
||||
SixBits = 0b11,
|
||||
SevenBits = 0b10,
|
||||
@@ -33,7 +31,6 @@ pub enum CharLen {
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ClockSelect {
|
||||
#[default]
|
||||
UartRefClk = 0b0,
|
||||
@@ -42,7 +39,6 @@ pub enum ClockSelect {
|
||||
|
||||
#[bitbybit::bitenum(u2)]
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Stopbits {
|
||||
#[default]
|
||||
One = 0b00,
|
||||
@@ -52,7 +48,6 @@ pub enum Stopbits {
|
||||
|
||||
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||
#[derive(Debug, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ChMode {
|
||||
#[default]
|
||||
Normal = 0b00,
|
||||
@@ -61,13 +56,7 @@ pub enum ChMode {
|
||||
RemoteLoopback = 0b11,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
forbid_overlaps,
|
||||
defmt_bitfields(feature = "defmt")
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Control {
|
||||
/// Stop transmitter break.
|
||||
#[bit(8, rw)]
|
||||
@@ -98,13 +87,7 @@ pub struct Control {
|
||||
rx_rst: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
forbid_overlaps,
|
||||
defmt_fields(feature = "defmt")
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct Mode {
|
||||
#[bits(8..=9, rw)]
|
||||
chmode: ChMode,
|
||||
@@ -119,45 +102,32 @@ pub struct Mode {
|
||||
clksel: ClockSelect,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0,
|
||||
debug,
|
||||
forbid_overlaps,
|
||||
defmt_fields(feature = "defmt")
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0, debug)]
|
||||
pub struct Baudgen {
|
||||
#[bits(0..=15, rw)]
|
||||
cd: u16,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0,
|
||||
debug,
|
||||
forbid_overlaps,
|
||||
defmt_fields(feature = "defmt")
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0, debug)]
|
||||
pub struct BaudRateDivisor {
|
||||
#[bits(0..=7, rw)]
|
||||
bdiv: u8,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, forbid_overlaps, defmt_fields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Fifo {
|
||||
#[bits(0..=7, rw)]
|
||||
fifo: u8,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[derive(Debug)]
|
||||
pub enum Ttrig {
|
||||
LessThanTTrig = 0b0,
|
||||
GreaterEqualTTrig = 0b1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, forbid_overlaps, defmt_bitfields(feature = "defmt"))]
|
||||
#[bitbybit::bitfield(u32, debug)]
|
||||
pub struct Status {
|
||||
#[bit(14, r)]
|
||||
tx_near_full: bool,
|
||||
@@ -184,13 +154,8 @@ pub struct Status {
|
||||
rx_trg: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
forbid_overlaps,
|
||||
defmt_bitfields(feature = "defmt")
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct InterruptControl {
|
||||
#[bit(12, w)]
|
||||
tx_over: bool,
|
||||
@@ -223,14 +188,13 @@ pub struct InterruptControl {
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct FifoTrigger {
|
||||
#[bits(0..=5, rw)]
|
||||
trig: u6,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
|
||||
#[derive(PartialEq, Eq)]
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct InterruptMask {
|
||||
#[bit(12, r)]
|
||||
tx_over: bool,
|
||||
@@ -262,13 +226,7 @@ pub struct InterruptMask {
|
||||
rx_trg: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(
|
||||
u32,
|
||||
default = 0x0,
|
||||
debug,
|
||||
defmt_bitfields(feature = "defmt"),
|
||||
forbid_overlaps
|
||||
)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0, debug)]
|
||||
pub struct InterruptStatus {
|
||||
#[bit(12, rw)]
|
||||
tx_over: bool,
|
||||
|
||||
Generated
+8
-19
@@ -4,13 +4,13 @@ version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aarch32-cpu"
|
||||
version = "0.2.0"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1417bbf608824a44cb2fa2ad74b5ec28c0ae4c83df62a4bd2b532bf04c241ade"
|
||||
checksum = "5db6700cf01549520abec199376115e1ceb6fde1d1de30064f0f230be8a0c305"
|
||||
dependencies = [
|
||||
"arbitrary-int 2.0.0",
|
||||
"arm-targets",
|
||||
"bitbybit 1.4.0",
|
||||
"bitbybit",
|
||||
"num_enum",
|
||||
"thiserror",
|
||||
]
|
||||
@@ -104,17 +104,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitbybit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d2a3353d70ac1091a33cbf31fc7e77b19091538a7e306e3740712af19807ca"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "boot-image-test"
|
||||
version = "0.1.0"
|
||||
@@ -691,10 +680,10 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
|
||||
[[package]]
|
||||
name = "zynq7000"
|
||||
version = "0.2.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"arbitrary-int 2.0.0",
|
||||
"bitbybit 2.0.0",
|
||||
"bitbybit",
|
||||
"derive-mmio",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
@@ -707,13 +696,13 @@ name = "zynq7000-boot-image"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arbitrary-int 2.0.0",
|
||||
"bitbybit 1.4.0",
|
||||
"bitbybit",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zynq7000-mmu"
|
||||
version = "0.1.2"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"aarch32-cpu",
|
||||
"arm-targets",
|
||||
@@ -736,7 +725,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zynq7000-rt"
|
||||
version = "0.2.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"aarch32-cpu",
|
||||
"arbitrary-int 2.0.0",
|
||||
|
||||
@@ -4,7 +4,7 @@ use clap::Parser as _;
|
||||
use simple_logger::SimpleLogger;
|
||||
|
||||
const DDRC_ADDR_RANGE: RangeInclusive<u32> = 0xf800_6000..=0xf800_62b4;
|
||||
const DDRIOB_ADDR_RANGE: RangeInclusive<u32> = 0xf800_0b40..=0xf800_0b6c;
|
||||
const DDRIOB_ADDR_RANGE: RangeInclusive<u32> = 0xf800_0b40..=0xf800_0b68;
|
||||
|
||||
const DDRC_FILE_NAME: &str = "ddrc_config_autogen.rs";
|
||||
const DDRIOB_FILE_NAME: &str = "ddriob_config_autogen.rs";
|
||||
@@ -198,7 +198,7 @@ fn generate_ddrc_config(
|
||||
let lpddr_ctrl_3 = reg_to_values.val_as_token("LPDDR CTRL 3", 0xF800_62B4);
|
||||
|
||||
let generated = quote::quote! {
|
||||
//!This file was auto-generated by the [zynq7000-ps7init-extract](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/host/zynq7000-ps7init-extract) program.
|
||||
//!This file was auto-generated by the [zynq7000-ps7init-extract](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/tools/zynq7000-ps7init-extract) program.
|
||||
//!
|
||||
//!This configuration file contains static DDR configuration parameters extracted from the
|
||||
//!AMD ps7init.tcl file
|
||||
@@ -310,7 +310,6 @@ fn generate_ddriob_config(
|
||||
file_name: &str,
|
||||
) -> std::io::Result<()> {
|
||||
// Format as hex strings
|
||||
let ddr_control = reg_to_values.val_as_token("DDRIOB DDR Control", 0xF800_0B6C);
|
||||
let addr0 = reg_to_values.val_as_token("DDRIOB Addr 0", 0xF800_0B40);
|
||||
let addr1 = reg_to_values.val_as_token("DDRIOB Addr 1", 0xF800_0B44);
|
||||
let data0 = reg_to_values.val_as_token("DDRIOB Data 0", 0xF800_0B48);
|
||||
@@ -319,7 +318,7 @@ fn generate_ddriob_config(
|
||||
let diff1 = reg_to_values.val_as_token("DDRIOB Diff 1", 0xF800_0B54);
|
||||
let clock = reg_to_values.val_as_token("DDRIOB Clock", 0xF800_0B58);
|
||||
let generated = quote::quote! {
|
||||
//!This file was auto-generated by the [zynq7000-ps7init-extract](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/host/zynq7000-ps7init-extract) program.
|
||||
//!This file was auto-generated by the [zynq7000-ps7init-extract](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/tools/zynq7000-ps7init-extract) program.
|
||||
//!
|
||||
//!This configuration file contains static DDRIOB configuration parameters extracted from the
|
||||
//!AMD ps7init.tcl file
|
||||
@@ -327,7 +326,6 @@ fn generate_ddriob_config(
|
||||
use zynq7000_hal::ddr::DdriobConfigSet;
|
||||
|
||||
pub const DDRIOB_CONFIG_SET_ZEDBOARD: DdriobConfigSet = DdriobConfigSet {
|
||||
ddr_control: zynq7000::slcr::ddriob::DdrControl::new_with_raw_value(#ddr_control),
|
||||
addr0: regs::DdriobConfig::new_with_raw_value(#addr0),
|
||||
addr1: regs::DdriobConfig::new_with_raw_value(#addr1),
|
||||
data0: regs::DdriobConfig::new_with_raw_value(#data0),
|
||||
|
||||
@@ -1,33 +1,31 @@
|
||||
all: check build check-fmt clippy docs-zynq
|
||||
all: check-all build-all clean-all fmt-all clippy-all docs-zynq
|
||||
|
||||
check: (check-dir "firmware") (check-dir "host")
|
||||
clean: (clean-dir "firmware") (clean-dir "host")
|
||||
build: build-zynq (build-dir "host")
|
||||
fmt: (fmt-dir "firmware") (fmt-dir "host")
|
||||
check-fmt: (check-fmt-dir "firmware") (check-fmt-dir "host")
|
||||
clippy: (clippy-dir "firmware") (clippy-dir "host")
|
||||
check-all: (check "firmware") (check "host")
|
||||
clean-all: (clean "firmware") (clean "host")
|
||||
build-all: build-zynq (build "host")
|
||||
fmt-all: (fmt "firmware") (fmt "host")
|
||||
check-fmt-all: (check-fmt "firmware") (check-fmt "host")
|
||||
clippy-all: (clippy "firmware") (clippy "host")
|
||||
|
||||
check-dir target:
|
||||
check target:
|
||||
cd {{target}} && cargo check
|
||||
|
||||
build-dir target:
|
||||
build target:
|
||||
cd {{target}} && cargo build
|
||||
|
||||
[working-directory: 'firmware']
|
||||
build-zynq: (build-dir "firmware")
|
||||
cd "zynq7000" && cargo build --all-features
|
||||
cd "zedboard-fsbl" && cargo build --release
|
||||
build-zynq: (build "firmware")
|
||||
cd "firmware/zedboard-fsbl" && cargo build --release
|
||||
|
||||
clean-dir target:
|
||||
clean target:
|
||||
cd {{target}} && cargo clean
|
||||
|
||||
check-fmt-dir target:
|
||||
check-fmt target:
|
||||
cd {{target}} && cargo +stable fmt --all -- --check
|
||||
|
||||
fmt-dir target:
|
||||
fmt target:
|
||||
cd {{target}} && cargo +stable fmt
|
||||
|
||||
clippy-dir target:
|
||||
clippy target:
|
||||
cd {{target}} && cargo clippy -- -D warnings
|
||||
|
||||
[working-directory: 'firmware']
|
||||
@@ -58,8 +56,5 @@ run binary:
|
||||
python3 {{justfile_directory()}}/scripts/zynq7000-init.py
|
||||
|
||||
# Run the GDB debugger in GUI mode.
|
||||
gdb-multiarch -q -x {{justfile_directory()}}/firmware/gdb.gdb {{binary}} -tui
|
||||
|
||||
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 {{invocation_directory()}}/{{boot_binary}}
|
||||
# gdb-multiarch -q -x {{justfile_directory()}}/zynq/gdb.gdb {{binary}} -tui
|
||||
probe-rs run --chip X7Z --protocol jtag --verify --skip-reset {{binary}}
|
||||
|
||||
Generated
+2121
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "probe-rs-test"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
probe-rs = { path = "../../probe-rs/probe-rs" }
|
||||
defmt-decoder = { version = "1" }
|
||||
anyhow = { version = "1" }
|
||||
@@ -0,0 +1,20 @@
|
||||
source [find interface/ftdi/digilent_jtag_smt2.cfg]
|
||||
source [find target/zynq_7000.cfg]
|
||||
|
||||
init
|
||||
|
||||
# Halt the target
|
||||
halt
|
||||
|
||||
# Load the ELF file
|
||||
load_image ../firmware/target/armv7a-none-eabihf/release/defmt
|
||||
verify_image ../firmware/target/armv7a-none-eabihf/release/defmt
|
||||
|
||||
# Set PC to entrypoint
|
||||
reg pc 0x100000
|
||||
|
||||
# Resume
|
||||
resume
|
||||
|
||||
# Optional: Exit OpenOCD if running in batch mode
|
||||
shutdown
|
||||
@@ -0,0 +1,88 @@
|
||||
use std::{path::Path, time::Duration};
|
||||
|
||||
use probe_rs::{
|
||||
Permissions,
|
||||
architecture::arm::dp::DpAddress,
|
||||
flashing::{self, DownloadOptions, ElfOptions, Format},
|
||||
probe::{WireProtocol, list::Lister},
|
||||
rtt,
|
||||
};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
// Initialize the subscriber with an environment filter.
|
||||
// This allows you to control log levels using the `RUST_LOG` environment variable.
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
// Reads the RUST_LOG environment variable.
|
||||
// Defaults to "info" if not set.
|
||||
EnvFilter::from_default_env(),
|
||||
)
|
||||
.init();
|
||||
|
||||
let lister = Lister::new();
|
||||
let probes = lister.list_all();
|
||||
|
||||
let mut probe = probes[0].open()?;
|
||||
probe.select_protocol(WireProtocol::Jtag).unwrap();
|
||||
|
||||
let mut session = probe.attach("X7Z", Permissions::default()).unwrap();
|
||||
println!("target: {:?}", session.target().memory_ports);
|
||||
let arm_if = session.get_arm_interface()?;
|
||||
arm_if.select_debug_port(DpAddress::Default)?;
|
||||
let elf_path = Path::new("../firmware/target/armv7a-none-eabihf/release/defmt");
|
||||
let format = Format::Elf(ElfOptions::default());
|
||||
let mut download_opts = DownloadOptions::default();
|
||||
download_opts.verify = true;
|
||||
download_opts.skip_reset = true;
|
||||
|
||||
println!("flashing ELF file");
|
||||
let loader = flashing::build_loader(&mut session, elf_path, format.clone(), None)?;
|
||||
|
||||
let elf_file = std::fs::read(elf_path).unwrap();
|
||||
let rtt_addr = rtt::find_rtt_control_block_in_raw_file(&elf_file)?.unwrap();
|
||||
let vector_table_addr = loader.vector_table_addr().unwrap();
|
||||
|
||||
loader.commit(&mut session, download_opts)?;
|
||||
|
||||
println!("attaching RTT");
|
||||
|
||||
let mut memory = session.memory_access_port(0)?;
|
||||
let mut rtt = rtt::Rtt::attach_at(&mut memory, rtt_addr)?;
|
||||
drop(memory);
|
||||
session.prepare_running_on_ram(vector_table_addr, 0)?;
|
||||
let mut core = session.core(0)?;
|
||||
|
||||
println!("running core");
|
||||
core.run()?;
|
||||
|
||||
let defmt_table = defmt_decoder::Table::parse(&elf_file)?.unwrap();
|
||||
let mut stream_decoder = defmt_table.new_stream_decoder();
|
||||
drop(core);
|
||||
|
||||
// Read from a channel
|
||||
loop {
|
||||
let mut memory = session.memory_access_port(0)?;
|
||||
for channel in rtt.up_channels() {
|
||||
let mut buf = [0u8; 1024];
|
||||
let count = channel.read(&mut memory, &mut buf[..])?;
|
||||
|
||||
if count > 0 {
|
||||
stream_decoder.received(&buf[..count]);
|
||||
// decode the received data
|
||||
match stream_decoder.decode() {
|
||||
Ok(frame) => {
|
||||
println!("defmt frame: {}", frame.display_message())
|
||||
}
|
||||
Err(defmt_decoder::DecodeError::UnexpectedEof) => {
|
||||
println!("unexpected EOF");
|
||||
}
|
||||
Err(defmt_decoder::DecodeError::Malformed) => {
|
||||
println!("malformed defmt frame");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(100));
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 62 MB for now, should be plenty for a bare-metal app.
|
||||
1 MB stack memory and 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 = 62M
|
||||
STACKS : ORIGIN = 0x3F00000, LENGTH = 1M
|
||||
/* 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
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
}
|
||||
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
MEMORY
|
||||
{
|
||||
/* The Zynq7000 has 256 kB of OCM memory of which 196 kB can be used for the FSBL */
|
||||
CODE(rx) : ORIGIN = 0x00000000, LENGTH = 196K
|
||||
/* The Zynq7000 has 192 kB of OCM memory which can be used for the FSBL */
|
||||
CODE(rx) : ORIGIN = 0x00000000, LENGTH = 192K
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
/* Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This can
|
||||
be used for something like DMA descriptors, but the DDR needs to be set up first in addition
|
||||
@@ -9,10 +9,7 @@ MEMORY
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
}
|
||||
|
||||
REGION_ALIAS("VECTORS", CODE);
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
/* Use the upper OCM as the stack */
|
||||
REGION_ALIAS("STACKS", OCM_UPPER);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
+48
-48
@@ -84,26 +84,26 @@ proc ps7_ddr_init_data_3_0 {} {
|
||||
mask_write 0XF800611C 0x7FFFFFCF 0x40000001
|
||||
mask_write 0XF8006120 0x7FFFFFCF 0x40000001
|
||||
mask_write 0XF8006124 0x7FFFFFCF 0x40000001
|
||||
mask_write 0XF800612C 0x000FFFFF 0x00033C03
|
||||
mask_write 0XF8006130 0x000FFFFF 0x00034003
|
||||
mask_write 0XF8006134 0x000FFFFF 0x0002F400
|
||||
mask_write 0XF8006138 0x000FFFFF 0x00030400
|
||||
mask_write 0XF800612C 0x000FFFFF 0x00024000
|
||||
mask_write 0XF8006130 0x000FFFFF 0x00022C00
|
||||
mask_write 0XF8006134 0x000FFFFF 0x00023000
|
||||
mask_write 0XF8006138 0x000FFFFF 0x00024C00
|
||||
mask_write 0XF8006140 0x000FFFFF 0x00000035
|
||||
mask_write 0XF8006144 0x000FFFFF 0x00000035
|
||||
mask_write 0XF8006148 0x000FFFFF 0x00000035
|
||||
mask_write 0XF800614C 0x000FFFFF 0x00000035
|
||||
mask_write 0XF8006154 0x000FFFFF 0x00000083
|
||||
mask_write 0XF8006158 0x000FFFFF 0x00000083
|
||||
mask_write 0XF800615C 0x000FFFFF 0x0000007F
|
||||
mask_write 0XF8006160 0x000FFFFF 0x00000078
|
||||
mask_write 0XF8006168 0x001FFFFF 0x00000124
|
||||
mask_write 0XF800616C 0x001FFFFF 0x00000125
|
||||
mask_write 0XF8006170 0x001FFFFF 0x00000112
|
||||
mask_write 0XF8006174 0x001FFFFF 0x00000116
|
||||
mask_write 0XF800617C 0x000FFFFF 0x000000C3
|
||||
mask_write 0XF8006180 0x000FFFFF 0x000000C3
|
||||
mask_write 0XF8006184 0x000FFFFF 0x000000BF
|
||||
mask_write 0XF8006188 0x000FFFFF 0x000000B8
|
||||
mask_write 0XF8006154 0x000FFFFF 0x00000077
|
||||
mask_write 0XF8006158 0x000FFFFF 0x0000007C
|
||||
mask_write 0XF800615C 0x000FFFFF 0x0000007C
|
||||
mask_write 0XF8006160 0x000FFFFF 0x00000075
|
||||
mask_write 0XF8006168 0x001FFFFF 0x000000E5
|
||||
mask_write 0XF800616C 0x001FFFFF 0x000000E0
|
||||
mask_write 0XF8006170 0x001FFFFF 0x000000E1
|
||||
mask_write 0XF8006174 0x001FFFFF 0x000000E8
|
||||
mask_write 0XF800617C 0x000FFFFF 0x000000B7
|
||||
mask_write 0XF8006180 0x000FFFFF 0x000000BC
|
||||
mask_write 0XF8006184 0x000FFFFF 0x000000BC
|
||||
mask_write 0XF8006188 0x000FFFFF 0x000000B5
|
||||
mask_write 0XF8006190 0x6FFFFEFE 0x00040080
|
||||
mask_write 0XF8006194 0x000FFFFF 0x0001FC82
|
||||
mask_write 0XF8006204 0xFFFFFFFF 0x00000000
|
||||
@@ -320,26 +320,26 @@ proc ps7_ddr_init_data_2_0 {} {
|
||||
mask_write 0XF800611C 0x7FFFFFFF 0x40000001
|
||||
mask_write 0XF8006120 0x7FFFFFFF 0x40000001
|
||||
mask_write 0XF8006124 0x7FFFFFFF 0x40000001
|
||||
mask_write 0XF800612C 0x000FFFFF 0x00033C03
|
||||
mask_write 0XF8006130 0x000FFFFF 0x00034003
|
||||
mask_write 0XF8006134 0x000FFFFF 0x0002F400
|
||||
mask_write 0XF8006138 0x000FFFFF 0x00030400
|
||||
mask_write 0XF800612C 0x000FFFFF 0x00024000
|
||||
mask_write 0XF8006130 0x000FFFFF 0x00022C00
|
||||
mask_write 0XF8006134 0x000FFFFF 0x00023000
|
||||
mask_write 0XF8006138 0x000FFFFF 0x00024C00
|
||||
mask_write 0XF8006140 0x000FFFFF 0x00000035
|
||||
mask_write 0XF8006144 0x000FFFFF 0x00000035
|
||||
mask_write 0XF8006148 0x000FFFFF 0x00000035
|
||||
mask_write 0XF800614C 0x000FFFFF 0x00000035
|
||||
mask_write 0XF8006154 0x000FFFFF 0x00000083
|
||||
mask_write 0XF8006158 0x000FFFFF 0x00000083
|
||||
mask_write 0XF800615C 0x000FFFFF 0x0000007F
|
||||
mask_write 0XF8006160 0x000FFFFF 0x00000078
|
||||
mask_write 0XF8006168 0x001FFFFF 0x00000124
|
||||
mask_write 0XF800616C 0x001FFFFF 0x00000125
|
||||
mask_write 0XF8006170 0x001FFFFF 0x00000112
|
||||
mask_write 0XF8006174 0x001FFFFF 0x00000116
|
||||
mask_write 0XF800617C 0x000FFFFF 0x000000C3
|
||||
mask_write 0XF8006180 0x000FFFFF 0x000000C3
|
||||
mask_write 0XF8006184 0x000FFFFF 0x000000BF
|
||||
mask_write 0XF8006188 0x000FFFFF 0x000000B8
|
||||
mask_write 0XF8006154 0x000FFFFF 0x00000077
|
||||
mask_write 0XF8006158 0x000FFFFF 0x0000007C
|
||||
mask_write 0XF800615C 0x000FFFFF 0x0000007C
|
||||
mask_write 0XF8006160 0x000FFFFF 0x00000075
|
||||
mask_write 0XF8006168 0x001FFFFF 0x000000E5
|
||||
mask_write 0XF800616C 0x001FFFFF 0x000000E0
|
||||
mask_write 0XF8006170 0x001FFFFF 0x000000E1
|
||||
mask_write 0XF8006174 0x001FFFFF 0x000000E8
|
||||
mask_write 0XF800617C 0x000FFFFF 0x000000B7
|
||||
mask_write 0XF8006180 0x000FFFFF 0x000000BC
|
||||
mask_write 0XF8006184 0x000FFFFF 0x000000BC
|
||||
mask_write 0XF8006188 0x000FFFFF 0x000000B5
|
||||
mask_write 0XF8006190 0xFFFFFFFF 0x10040080
|
||||
mask_write 0XF8006194 0x000FFFFF 0x0001FC82
|
||||
mask_write 0XF8006204 0xFFFFFFFF 0x00000000
|
||||
@@ -554,26 +554,26 @@ proc ps7_ddr_init_data_1_0 {} {
|
||||
mask_write 0XF800611C 0x7FFFFFFF 0x40000001
|
||||
mask_write 0XF8006120 0x7FFFFFFF 0x40000001
|
||||
mask_write 0XF8006124 0x7FFFFFFF 0x40000001
|
||||
mask_write 0XF800612C 0x000FFFFF 0x00033C03
|
||||
mask_write 0XF8006130 0x000FFFFF 0x00034003
|
||||
mask_write 0XF8006134 0x000FFFFF 0x0002F400
|
||||
mask_write 0XF8006138 0x000FFFFF 0x00030400
|
||||
mask_write 0XF800612C 0x000FFFFF 0x00024000
|
||||
mask_write 0XF8006130 0x000FFFFF 0x00022C00
|
||||
mask_write 0XF8006134 0x000FFFFF 0x00023000
|
||||
mask_write 0XF8006138 0x000FFFFF 0x00024C00
|
||||
mask_write 0XF8006140 0x000FFFFF 0x00000035
|
||||
mask_write 0XF8006144 0x000FFFFF 0x00000035
|
||||
mask_write 0XF8006148 0x000FFFFF 0x00000035
|
||||
mask_write 0XF800614C 0x000FFFFF 0x00000035
|
||||
mask_write 0XF8006154 0x000FFFFF 0x00000083
|
||||
mask_write 0XF8006158 0x000FFFFF 0x00000083
|
||||
mask_write 0XF800615C 0x000FFFFF 0x0000007F
|
||||
mask_write 0XF8006160 0x000FFFFF 0x00000078
|
||||
mask_write 0XF8006168 0x001FFFFF 0x00000124
|
||||
mask_write 0XF800616C 0x001FFFFF 0x00000125
|
||||
mask_write 0XF8006170 0x001FFFFF 0x00000112
|
||||
mask_write 0XF8006174 0x001FFFFF 0x00000116
|
||||
mask_write 0XF800617C 0x000FFFFF 0x000000C3
|
||||
mask_write 0XF8006180 0x000FFFFF 0x000000C3
|
||||
mask_write 0XF8006184 0x000FFFFF 0x000000BF
|
||||
mask_write 0XF8006188 0x000FFFFF 0x000000B8
|
||||
mask_write 0XF8006154 0x000FFFFF 0x00000077
|
||||
mask_write 0XF8006158 0x000FFFFF 0x0000007C
|
||||
mask_write 0XF800615C 0x000FFFFF 0x0000007C
|
||||
mask_write 0XF8006160 0x000FFFFF 0x00000075
|
||||
mask_write 0XF8006168 0x001FFFFF 0x000000E5
|
||||
mask_write 0XF800616C 0x001FFFFF 0x000000E0
|
||||
mask_write 0XF8006170 0x001FFFFF 0x000000E1
|
||||
mask_write 0XF8006174 0x001FFFFF 0x000000E8
|
||||
mask_write 0XF800617C 0x000FFFFF 0x000000B7
|
||||
mask_write 0XF8006180 0x000FFFFF 0x000000BC
|
||||
mask_write 0XF8006184 0x000FFFFF 0x000000BC
|
||||
mask_write 0XF8006188 0x000FFFFF 0x000000B5
|
||||
mask_write 0XF8006190 0xFFFFFFFF 0x10040080
|
||||
mask_write 0XF8006194 0x000FFFFF 0x0001FC82
|
||||
mask_write 0XF8006204 0xFFFFFFFF 0x00000000
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
if {[info exists env(XSCT_HW_SERVER_IP)]} {
|
||||
set ip $env(XSCT_HW_SERVER_IP)
|
||||
if {[info exists env(ip_address_hw_server)]} {
|
||||
set ip $env(ip_address_hw_server)
|
||||
} else {
|
||||
set ip "localhost"
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ def main():
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--tools",
|
||||
# Required only if env var is not set
|
||||
required=not bool(os.getenv("AMD_TOOLS")),
|
||||
# Use env var if set
|
||||
default=os.getenv("AMD_TOOLS"),
|
||||
help="The path to the tool to use. Must point to a valid Vivado tools installation which"
|
||||
@@ -41,13 +43,10 @@ def main():
|
||||
help="No bitstream flashing for initialization with SDT.",
|
||||
)
|
||||
parser.add_argument("-a", "--app", dest="app", help="Path to the app to program")
|
||||
default_ip = os.getenv("HW_SERVER_IP")
|
||||
if not default_ip:
|
||||
default_ip = DEFAULT_IP_ADDRESS_HW_SERVER
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--ip",
|
||||
default=default_ip,
|
||||
default=DEFAULT_IP_ADDRESS_HW_SERVER,
|
||||
help="The IP address of the hardware server (default: localhost)",
|
||||
)
|
||||
parser.add_argument(
|
||||
@@ -92,7 +91,7 @@ def main():
|
||||
print(f"The app '{args.app}' does not exist")
|
||||
sys.exit(1)
|
||||
|
||||
os.environ["XSCT_HW_SERVER_IP"] = args.ip
|
||||
os.environ["IP_ADDRESS_HW_SERVER"] = args.ip
|
||||
init_tcl = None
|
||||
bitstream = None
|
||||
if args.bit:
|
||||
@@ -112,8 +111,8 @@ def main():
|
||||
init_script = sdt_path / "ps7_init.tcl"
|
||||
if not init_script.exists():
|
||||
sys.exit("Error: ps7_init.tcl file not found in the SDT folder.")
|
||||
if not args.init_tcl:
|
||||
init_tcl = str(init_script)
|
||||
|
||||
init_tcl = str(init_script)
|
||||
else:
|
||||
if not args.init_tcl:
|
||||
print("Error: No ps7_init.tcl file specified.")
|
||||
|
||||
Reference in New Issue
Block a user