improve FSBL #61

Merged
muellerr merged 1 commits from improve-fsbl into main 2026-03-31 20:12:51 +02:00
8 changed files with 140 additions and 16 deletions
+33
View File
@@ -16,6 +16,7 @@ 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,
@@ -75,6 +76,16 @@ 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),
);
}
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLK).unwrap();
@@ -102,6 +113,7 @@ fn main() -> ! {
false,
)
};
//log::info!("clocks: {:?}", clocks);
// Set up the global interrupt controller.
let mut gic = gic::GicConfigurator::new_with_init(periphs.gicc, periphs.gicd);
@@ -323,6 +335,7 @@ 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();
@@ -333,6 +346,26 @@ 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 {
+3 -1
View File
@@ -20,7 +20,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Added
Method to de-assert PL reset.
- 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
+1 -1
View File
@@ -48,7 +48,7 @@ bytemuck = "1.25"
[features]
std = ["thiserror/std", "alloc"]
alloc = []
defmt = ["dep:defmt", "fugit/defmt"]
defmt = ["dep:defmt", "fugit/defmt", "zynq7000/defmt"]
# These devices have a lower pin count.
7z010-7z007s-clg225 = []
+68 -5
View File
@@ -3,11 +3,12 @@ use arbitrary_int::{prelude::*, u6};
pub mod pll;
pub use zynq7000::slcr::clocks::CpuClockRatio;
use zynq7000::slcr::{
ClockControlRegisters,
clocks::{
ClockkRatioSelect, DualCommonPeriphIoClockControl, FpgaClockControl, GigEthClockControl,
SingleCommonPeriphIoClockControl,
ArmClockControl, ClockRatioSelectReg, DualCommonPeriphIoClockControl, FpgaClockControl,
GigEthClockControl, SingleCommonPeriphIoClockControl,
},
};
@@ -17,6 +18,7 @@ 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,
@@ -24,23 +26,82 @@ 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
}
@@ -278,25 +339,27 @@ 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_621_true();
let clk_sel = clk_regs.read_clk_ratio_select();
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() {
ClockkRatioSelect::FourToTwoToOne => ArmClocks {
CpuClockRatio::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(),
},
ClockkRatioSelect::SixToTwoToOne => ArmClocks {
CpuClockRatio::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(),
},
};
+7
View File
@@ -81,3 +81,10 @@ 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());
}
+2 -1
View File
@@ -13,11 +13,12 @@ categories = ["embedded", "no-std", "hardware-support"]
[dependencies]
static_assertions = "1.1"
derive-mmio = { version = "0.6", default-features = false }
bitbybit = "1.4"
bitbybit = "2"
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 }
[dev-dependencies]
approx = "0.5"
+12 -5
View File
@@ -128,7 +128,7 @@ pub enum SrcSelArm {
IoPll = 0b11,
}
#[bitbybit::bitfield(u32, debug)]
#[bitbybit::bitfield(u32, debug, default = 0x0)]
pub struct ArmClockControl {
#[bit(28, rw)]
cpu_peri_clk_act: bool,
@@ -178,19 +178,26 @@ pub struct DciClockControl {
clk_act: bool,
}
#[bitbybit::bitfield(u32, debug)]
#[bitbybit::bitfield(u32, debug, default = 0x0)]
pub struct ClockRatioSelectReg {
/// Reset value: 0x1 (6:2:1 clock)
#[bit(0, rw)]
sel: ClockkRatioSelect,
sel: CpuClockRatio,
}
#[bitbybit::bitenum(u1, exhaustive = true)]
#[derive(Debug)]
pub enum ClockkRatioSelect {
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CpuClockRatio {
/// 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,
}
@@ -399,7 +406,7 @@ pub struct ClockControlRegisters {
#[mmio(Inner)]
fpga_3_clk_ctrl: FpgaClockControlRegisters,
_gap1: [u32; 5],
clk_621_true: ClockRatioSelectReg,
clk_ratio_select: ClockRatioSelectReg,
}
impl ClockControlRegisters {
+14 -3
View File
@@ -10,7 +10,7 @@ checksum = "1417bbf608824a44cb2fa2ad74b5ec28c0ae4c83df62a4bd2b532bf04c241ade"
dependencies = [
"arbitrary-int 2.0.0",
"arm-targets",
"bitbybit",
"bitbybit 1.4.0",
"num_enum",
"thiserror",
]
@@ -104,6 +104,17 @@ 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"
@@ -683,7 +694,7 @@ name = "zynq7000"
version = "0.1.1"
dependencies = [
"arbitrary-int 2.0.0",
"bitbybit",
"bitbybit 2.0.0",
"derive-mmio",
"once_cell",
"rustversion",
@@ -696,7 +707,7 @@ name = "zynq7000-boot-image"
version = "0.1.0"
dependencies = [
"arbitrary-int 2.0.0",
"bitbybit",
"bitbybit 1.4.0",
"thiserror",
]