|
|
|
@ -42,14 +42,15 @@ impl DdrRam { |
|
|
|
|
let ddr3x_clk_divisor = ((clocks.ddr - 1) / DDR_FREQ + 1).min(255) as u8; |
|
|
|
|
let ddr2x_clk_divisor = 3 * ddr3x_clk_divisor / 2; |
|
|
|
|
|
|
|
|
|
let slcr = slcr::RegisterBlock::new(); |
|
|
|
|
slcr.ddr_clk_ctrl.write( |
|
|
|
|
slcr::DdrClkCtrl::zeroed() |
|
|
|
|
.ddr_2xclkact(true) |
|
|
|
|
.ddr_3xclkact(true) |
|
|
|
|
.ddr_2xclk_divisor(ddr2x_clk_divisor) |
|
|
|
|
.ddr_3xclk_divisor(ddr3x_clk_divisor) |
|
|
|
|
); |
|
|
|
|
slcr::RegisterBlock::unlocked(|slcr| { |
|
|
|
|
slcr.ddr_clk_ctrl.write( |
|
|
|
|
slcr::DdrClkCtrl::zeroed() |
|
|
|
|
.ddr_2xclkact(true) |
|
|
|
|
.ddr_3xclkact(true) |
|
|
|
|
.ddr_2xclk_divisor(ddr2x_clk_divisor) |
|
|
|
|
.ddr_3xclk_divisor(ddr3x_clk_divisor) |
|
|
|
|
); |
|
|
|
|
}); |
|
|
|
|
clocks |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -61,99 +62,101 @@ impl DdrRam { |
|
|
|
|
let divisor1 = (clocks.ddr / DCI_FREQ / u32::from(divisor0)) |
|
|
|
|
.max(1).min(63) as u8; |
|
|
|
|
|
|
|
|
|
let slcr = slcr::RegisterBlock::new(); |
|
|
|
|
// Step 1.
|
|
|
|
|
slcr.dci_clk_ctrl.write( |
|
|
|
|
slcr::DciClkCtrl::zeroed() |
|
|
|
|
.clkact(true) |
|
|
|
|
.divisor0(divisor0) |
|
|
|
|
.divisor1(divisor1) |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// Step 2.a.
|
|
|
|
|
slcr.ddriob_dci_ctrl.modify(|_, w| |
|
|
|
|
w.reset(false) |
|
|
|
|
); |
|
|
|
|
slcr.ddriob_dci_ctrl.modify(|_, w| |
|
|
|
|
w.reset(true) |
|
|
|
|
); |
|
|
|
|
// Step 3.b. for DDR3/DDR3L
|
|
|
|
|
slcr.ddriob_dci_ctrl.modify(|_, w| |
|
|
|
|
w.nref_opt1(0) |
|
|
|
|
.nref_opt2(0) |
|
|
|
|
.nref_opt4(1) |
|
|
|
|
.pref_opt1(0) |
|
|
|
|
.pref_opt2(0) |
|
|
|
|
); |
|
|
|
|
// Step 2.c.
|
|
|
|
|
slcr.ddriob_dci_ctrl.modify(|_, w| |
|
|
|
|
w.update_control(false) |
|
|
|
|
); |
|
|
|
|
// Step 2.d.
|
|
|
|
|
slcr.ddriob_dci_ctrl.modify(|_, w| |
|
|
|
|
w.enable(true) |
|
|
|
|
); |
|
|
|
|
// Step 2.e.
|
|
|
|
|
while ! slcr.ddriob_dci_status.read().done() {} |
|
|
|
|
slcr::RegisterBlock::unlocked(|slcr| { |
|
|
|
|
// Step 1.
|
|
|
|
|
slcr.dci_clk_ctrl.write( |
|
|
|
|
slcr::DciClkCtrl::zeroed() |
|
|
|
|
.clkact(true) |
|
|
|
|
.divisor0(divisor0) |
|
|
|
|
.divisor1(divisor1) |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// Step 2.a.
|
|
|
|
|
slcr.ddriob_dci_ctrl.modify(|_, w| |
|
|
|
|
w.reset(false) |
|
|
|
|
); |
|
|
|
|
slcr.ddriob_dci_ctrl.modify(|_, w| |
|
|
|
|
w.reset(true) |
|
|
|
|
); |
|
|
|
|
// Step 3.b. for DDR3/DDR3L
|
|
|
|
|
slcr.ddriob_dci_ctrl.modify(|_, w| |
|
|
|
|
w.nref_opt1(0) |
|
|
|
|
.nref_opt2(0) |
|
|
|
|
.nref_opt4(1) |
|
|
|
|
.pref_opt1(0) |
|
|
|
|
.pref_opt2(0) |
|
|
|
|
); |
|
|
|
|
// Step 2.c.
|
|
|
|
|
slcr.ddriob_dci_ctrl.modify(|_, w| |
|
|
|
|
w.update_control(false) |
|
|
|
|
); |
|
|
|
|
// Step 2.d.
|
|
|
|
|
slcr.ddriob_dci_ctrl.modify(|_, w| |
|
|
|
|
w.enable(true) |
|
|
|
|
); |
|
|
|
|
// Step 2.e.
|
|
|
|
|
while ! slcr.ddriob_dci_status.read().done() {} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Zynq-7000 AP SoC Technical Reference Manual:
|
|
|
|
|
/// 10.6.3 DDR IOB Configuration
|
|
|
|
|
fn configure_iob() { |
|
|
|
|
let slcr = slcr::RegisterBlock::new(); |
|
|
|
|
let addr_config = slcr::DdriobConfig::zeroed() |
|
|
|
|
.output_en(slcr::DdriobOutputEn::Obuf); |
|
|
|
|
slcr.ddriob_addr0.write(addr_config.clone()); |
|
|
|
|
slcr.ddriob_addr1.write(addr_config); |
|
|
|
|
|
|
|
|
|
let data_config = slcr::DdriobConfig::zeroed() |
|
|
|
|
.inp_type(slcr::DdriobInputType::VrefDifferential) |
|
|
|
|
.term_en(true) |
|
|
|
|
.dci_type(slcr::DdriobDciType::Termination) |
|
|
|
|
.output_en(slcr::DdriobOutputEn::Obuf); |
|
|
|
|
slcr.ddriob_data0.write(data_config.clone()); |
|
|
|
|
slcr.ddriob_data1.write(data_config); |
|
|
|
|
|
|
|
|
|
let diff_config = slcr::DdriobConfig::zeroed() |
|
|
|
|
.inp_type(slcr::DdriobInputType::Differential) |
|
|
|
|
.term_en(true) |
|
|
|
|
.dci_type(slcr::DdriobDciType::Termination) |
|
|
|
|
.output_en(slcr::DdriobOutputEn::Obuf); |
|
|
|
|
slcr.ddriob_diff0.write(diff_config.clone()); |
|
|
|
|
slcr.ddriob_diff1.write(diff_config); |
|
|
|
|
|
|
|
|
|
slcr.ddriob_clock.write( |
|
|
|
|
slcr::DdriobConfig::zeroed() |
|
|
|
|
.output_en(slcr::DdriobOutputEn::Obuf) |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
// Not documented in Technical Reference Manual
|
|
|
|
|
slcr.ddriob_drive_slew_addr.write(0x0018C61C); |
|
|
|
|
slcr.ddriob_drive_slew_data.write(0x00F9861C); |
|
|
|
|
slcr.ddriob_drive_slew_diff.write(0x00F9861C); |
|
|
|
|
slcr.ddriob_drive_slew_clock.write(0x00F9861C); |
|
|
|
|
} |
|
|
|
|
slcr::RegisterBlock::unlocked(|slcr| { |
|
|
|
|
let addr_config = slcr::DdriobConfig::zeroed() |
|
|
|
|
.output_en(slcr::DdriobOutputEn::Obuf); |
|
|
|
|
slcr.ddriob_addr0.write(addr_config.clone()); |
|
|
|
|
slcr.ddriob_addr1.write(addr_config); |
|
|
|
|
|
|
|
|
|
let data_config = slcr::DdriobConfig::zeroed() |
|
|
|
|
.inp_type(slcr::DdriobInputType::VrefDifferential) |
|
|
|
|
.term_en(true) |
|
|
|
|
.dci_type(slcr::DdriobDciType::Termination) |
|
|
|
|
.output_en(slcr::DdriobOutputEn::Obuf); |
|
|
|
|
slcr.ddriob_data0.write(data_config.clone()); |
|
|
|
|
slcr.ddriob_data1.write(data_config); |
|
|
|
|
|
|
|
|
|
let diff_config = slcr::DdriobConfig::zeroed() |
|
|
|
|
.inp_type(slcr::DdriobInputType::Differential) |
|
|
|
|
.term_en(true) |
|
|
|
|
.dci_type(slcr::DdriobDciType::Termination) |
|
|
|
|
.output_en(slcr::DdriobOutputEn::Obuf); |
|
|
|
|
slcr.ddriob_diff0.write(diff_config.clone()); |
|
|
|
|
slcr.ddriob_diff1.write(diff_config); |
|
|
|
|
|
|
|
|
|
slcr.ddriob_clock.write( |
|
|
|
|
slcr::DdriobConfig::zeroed() |
|
|
|
|
.output_en(slcr::DdriobOutputEn::Obuf) |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
// Not documented in Technical Reference Manual
|
|
|
|
|
slcr.ddriob_drive_slew_addr.write(0x0018C61C); |
|
|
|
|
slcr.ddriob_drive_slew_data.write(0x00F9861C); |
|
|
|
|
slcr.ddriob_drive_slew_diff.write(0x00F9861C); |
|
|
|
|
slcr.ddriob_drive_slew_clock.write(0x00F9861C); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[cfg(feature = "target_zc706")] |
|
|
|
|
let vref_sel = slcr::DdriobVrefSel::Vref0_75V; |
|
|
|
|
#[cfg(feature = "target_cora_z7_10")] |
|
|
|
|
let vref_sel = slcr::DdriobVrefSel::Vref0_675V; |
|
|
|
|
|
|
|
|
|
// // Enable internal V[REF]
|
|
|
|
|
// slcr.ddriob_ddr_ctrl.modify(|_, w| w
|
|
|
|
|
// .vref_ext_en_lower(false)
|
|
|
|
|
// .vref_ext_en_upper(false)
|
|
|
|
|
// .vref_sel(vref_sel)
|
|
|
|
|
// .vref_int_en(true)
|
|
|
|
|
// );
|
|
|
|
|
// Enable external V[REF]
|
|
|
|
|
slcr.ddriob_ddr_ctrl.modify(|_, w| w |
|
|
|
|
.vref_ext_en_lower(true) |
|
|
|
|
.vref_ext_en_upper(true) |
|
|
|
|
.vref_sel(vref_sel) |
|
|
|
|
.vref_int_en(false) |
|
|
|
|
); |
|
|
|
|
#[cfg(feature = "target_zc706")] |
|
|
|
|
let vref_sel = slcr::DdriobVrefSel::Vref0_75V; |
|
|
|
|
#[cfg(feature = "target_cora_z7_10")] |
|
|
|
|
let vref_sel = slcr::DdriobVrefSel::Vref0_675V; |
|
|
|
|
|
|
|
|
|
// // Enable internal V[REF]
|
|
|
|
|
// slcr.ddriob_ddr_ctrl.modify(|_, w| w
|
|
|
|
|
// .vref_ext_en_lower(false)
|
|
|
|
|
// .vref_ext_en_upper(false)
|
|
|
|
|
// .vref_sel(vref_sel)
|
|
|
|
|
// .vref_int_en(true)
|
|
|
|
|
// );
|
|
|
|
|
// Enable external V[REF]
|
|
|
|
|
slcr.ddriob_ddr_ctrl.modify(|_, w| w |
|
|
|
|
.vref_ext_en_lower(true) |
|
|
|
|
.vref_ext_en_upper(true) |
|
|
|
|
.vref_sel(vref_sel) |
|
|
|
|
.vref_int_en(false) |
|
|
|
|
); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Reset DDR controller
|
|
|
|
|