bugfix for DDR init #62

Merged
muellerr merged 1 commits from bugfix-ddr-init into main 2026-04-01 11:01:18 +02:00
11 changed files with 124 additions and 97 deletions
@@ -1,4 +1,4 @@
#![doc = r"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."]
#![doc = r"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."]
#![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(0x10200802),
che_t_zq_short_interval_reg: regs::CheTZqShortInterval::new_with_raw_value(0x0690cb73),
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,10 +1,11 @@
#![doc = r"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."]
#![doc = r"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."]
#![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),
+8 -2
View File
@@ -85,6 +85,10 @@ fn main() -> ! {
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.
@@ -113,7 +117,6 @@ 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);
@@ -187,6 +190,7 @@ fn main() -> ! {
spansion_qspi.into_linear_addressed(qspi_spansion::QSPI_DEV_COMBINATION_REV_F.into());
qspi_boot(spansion_lqspi, priv_tim);
}
loop {
aarch32_cpu::asm::nop();
}
@@ -324,6 +328,8 @@ 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 {
@@ -361,7 +367,7 @@ fn interrupt_handler() {
gic::Interrupt::Invalid(_) => (),
gic::Interrupt::Spurious => {
log::warn!("spurious interrupt");
},
}
}
gic_helper.end_of_interrupt(irq_info);
}
+9 -3
View File
@@ -8,15 +8,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased]
## Fixed
- 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
- 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.
- 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.
## Added
+43 -31
View File
@@ -86,20 +86,42 @@ 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(dci_clk_cfg: DciClkConfig, poll_for_done: bool) {
pub unsafe fn calibrate_iob_impedance_for_ddr3(
ddr_control: zynq7000::slcr::ddriob::DdrControl,
dci_clk_cfg: DciClkConfig,
poll_for_done: bool,
) {
unsafe {
calibrate_iob_impedance(
ddr_control,
dci_clk_cfg,
u3::new(0),
u2::new(0),
u3::new(0b001),
u3::new(0),
u2::new(0),
CalibrationParams::new_ddr3(),
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.
@@ -115,12 +137,9 @@ pub unsafe fn calibrate_iob_impedance_for_ddr3(dci_clk_cfg: DciClkConfig, poll_f
/// 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,
pref_opt2: u3,
pref_opt1: u2,
nref_opt4: u3,
nref_opt2: u3,
nref_opt1: u2,
calibration_params: CalibrationParams,
poll_for_done: bool,
) {
// Safety: Only writes to DDR IOB related registers.
@@ -134,31 +153,23 @@ pub unsafe fn calibrate_iob_impedance(
.build(),
);
let mut ddriob = slcr.ddriob();
ddriob.modify_dci_ctrl(|mut val| {
val.set_reset(true);
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);
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| {
ddriob.modify_dci_control(|mut val| {
val.set_update_control(false);
val
});
ddriob.modify_dci_ctrl(|mut val| {
ddriob.modify_dci_control(|mut val| {
val.set_enable(true);
val
});
@@ -170,6 +181,7 @@ 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,
+1 -1
View File
@@ -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(dci_clk_cfg, false);
ll::calibrate_iob_impedance_for_ddr3(ddriob_cfg.ddr_control, 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
+1 -1
View File
@@ -18,7 +18,7 @@
#[cfg(feature = "alloc")]
extern crate alloc;
use slcr::Slcr;
pub use slcr::Slcr;
use zynq7000::{
SpiClockPhase, SpiClockPolarity,
slcr::{BootModeRegister, BootPllConfig, LevelShifterRegister},
+3 -3
View File
@@ -417,7 +417,7 @@ impl Qspi {
.with_disable_hstl_rcvr(false)
.with_pullup(true)
.with_io_type(voltage)
.with_speed(Speed::SlowCmosEdge)
.with_speed(Speed::FastCmosEdge)
.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 +429,7 @@ impl Qspi {
.with_disable_hstl_rcvr(false)
.with_pullup(false)
.with_io_type(voltage)
.with_speed(Speed::SlowCmosEdge)
.with_speed(Speed::FastCmosEdge)
.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 +471,7 @@ impl Qspi {
.with_disable_hstl_rcvr(false)
.with_pullup(false)
.with_io_type(voltage)
.with_speed(Speed::SlowCmosEdge)
.with_speed(Speed::FastCmosEdge)
.with_l3_sel(QSPI_MUX_CONFIG.l3_sel())
.with_l2_sel(QSPI_MUX_CONFIG.l2_sel())
.with_l1_sel(QSPI_MUX_CONFIG.l1_sel())
+2 -2
View File
@@ -118,8 +118,8 @@ pub struct DdrIobRegisters {
ddriob_drive_slew_data: u32,
ddriob_drive_slew_diff: u32,
ddriob_drive_slew_clock: u32,
ddr_ctrl: DdrControl,
dci_ctrl: DciControl,
ddr_control: DdrControl,
dci_control: DciControl,
dci_status: DciStatus,
}
+5 -3
View File
@@ -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_0b68;
const DDRIOB_ADDR_RANGE: RangeInclusive<u32> = 0xf800_0b40..=0xf800_0b6c;
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/tools/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/host/zynq7000-ps7init-extract) program.
//!
//!This configuration file contains static DDR configuration parameters extracted from the
//!AMD ps7init.tcl file
@@ -310,6 +310,7 @@ 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);
@@ -318,7 +319,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/tools/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/host/zynq7000-ps7init-extract) program.
//!
//!This configuration file contains static DDRIOB configuration parameters extracted from the
//!AMD ps7init.tcl file
@@ -326,6 +327,7 @@ 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),
+48 -48
View File
@@ -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 0x00024000
mask_write 0XF8006130 0x000FFFFF 0x00022C00
mask_write 0XF8006134 0x000FFFFF 0x00023000
mask_write 0XF8006138 0x000FFFFF 0x00024C00
mask_write 0XF800612C 0x000FFFFF 0x00033C03
mask_write 0XF8006130 0x000FFFFF 0x00034003
mask_write 0XF8006134 0x000FFFFF 0x0002F400
mask_write 0XF8006138 0x000FFFFF 0x00030400
mask_write 0XF8006140 0x000FFFFF 0x00000035
mask_write 0XF8006144 0x000FFFFF 0x00000035
mask_write 0XF8006148 0x000FFFFF 0x00000035
mask_write 0XF800614C 0x000FFFFF 0x00000035
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 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 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 0x00024000
mask_write 0XF8006130 0x000FFFFF 0x00022C00
mask_write 0XF8006134 0x000FFFFF 0x00023000
mask_write 0XF8006138 0x000FFFFF 0x00024C00
mask_write 0XF800612C 0x000FFFFF 0x00033C03
mask_write 0XF8006130 0x000FFFFF 0x00034003
mask_write 0XF8006134 0x000FFFFF 0x0002F400
mask_write 0XF8006138 0x000FFFFF 0x00030400
mask_write 0XF8006140 0x000FFFFF 0x00000035
mask_write 0XF8006144 0x000FFFFF 0x00000035
mask_write 0XF8006148 0x000FFFFF 0x00000035
mask_write 0XF800614C 0x000FFFFF 0x00000035
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 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 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 0x00024000
mask_write 0XF8006130 0x000FFFFF 0x00022C00
mask_write 0XF8006134 0x000FFFFF 0x00023000
mask_write 0XF8006138 0x000FFFFF 0x00024C00
mask_write 0XF800612C 0x000FFFFF 0x00033C03
mask_write 0XF8006130 0x000FFFFF 0x00034003
mask_write 0XF8006134 0x000FFFFF 0x0002F400
mask_write 0XF8006138 0x000FFFFF 0x00030400
mask_write 0XF8006140 0x000FFFFF 0x00000035
mask_write 0XF8006144 0x000FFFFF 0x00000035
mask_write 0XF8006148 0x000FFFFF 0x00000035
mask_write 0XF800614C 0x000FFFFF 0x00000035
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 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 0XF8006190 0xFFFFFFFF 0x10040080
mask_write 0XF8006194 0x000FFFFF 0x0001FC82
mask_write 0XF8006204 0xFFFFFFFF 0x00000000