zynq::ddr, main: parameters, memtest
This commit is contained in:
parent
e61d1268ac
commit
9b4f07f37c
|
@ -87,6 +87,9 @@ const HWADDR: [u8; 6] = [0, 0x23, 0xde, 0xea, 0xbe, 0xef];
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Main.");
|
println!("Main.");
|
||||||
|
|
||||||
|
zynq::clocks::CpuClocks::enable_ddr(1_066_000_000);
|
||||||
|
let pll_status = zynq::slcr::RegisterBlock::new().pll_status.read();
|
||||||
|
println!("PLLs: {}", pll_status);
|
||||||
let clocks = zynq::clocks::CpuClocks::get();
|
let clocks = zynq::clocks::CpuClocks::get();
|
||||||
println!("Clocks: {:?}", clocks);
|
println!("Clocks: {:?}", clocks);
|
||||||
println!("CPU speeds: {}/{}/{}/{} MHz",
|
println!("CPU speeds: {}/{}/{}/{} MHz",
|
||||||
|
@ -94,7 +97,9 @@ fn main() {
|
||||||
clocks.cpu_3x2x() / 1_000_000,
|
clocks.cpu_3x2x() / 1_000_000,
|
||||||
clocks.cpu_2x() / 1_000_000,
|
clocks.cpu_2x() / 1_000_000,
|
||||||
clocks.cpu_1x() / 1_000_000);
|
clocks.cpu_1x() / 1_000_000);
|
||||||
let ddr = zynq::ddr::DdrRam::new();
|
let mut ddr = zynq::ddr::DdrRam::new();
|
||||||
|
println!("DDR: {:?}", ddr.status());
|
||||||
|
ddr.memtest();
|
||||||
|
|
||||||
let eth = zynq::eth::Eth::default(HWADDR.clone());
|
let eth = zynq::eth::Eth::default(HWADDR.clone());
|
||||||
println!("Eth on");
|
println!("Eth on");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::regs::{RegisterR, RegisterRW};
|
use crate::regs::{RegisterR, RegisterW, RegisterRW};
|
||||||
use super::slcr;
|
use super::slcr;
|
||||||
|
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
|
@ -90,19 +90,33 @@ impl CpuClocks {
|
||||||
pll / u32::from(uart_clk_ctrl.divisor())
|
pll / u32::from(uart_clk_ctrl.divisor())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Zynq-7000 AP SoC Technical Reference Manual:
|
||||||
|
/// 25.10.4 PLLs
|
||||||
pub fn enable_ddr(target_clock: u32) {
|
pub fn enable_ddr(target_clock: u32) {
|
||||||
|
let fdiv = (target_clock / PS_CLK).min(66) as u16;
|
||||||
let regs = slcr::RegisterBlock::new();
|
let regs = slcr::RegisterBlock::new();
|
||||||
regs.ddr_pll_ctrl.modify(|_, w| w
|
regs.ddr_pll_ctrl.modify(|_, w| w
|
||||||
.pll_pwrdwn(false)
|
.pll_pwrdwn(false)
|
||||||
.pll_reset(true)
|
|
||||||
.pll_bypass_force(true)
|
.pll_bypass_force(true)
|
||||||
);
|
|
||||||
let fdiv = (target_clock / PS_CLK).max(127) as u16;
|
|
||||||
regs.ddr_pll_ctrl.modify(|_, w| w
|
|
||||||
.pll_pwrdwn(false)
|
|
||||||
.pll_reset(false)
|
|
||||||
.pll_fdiv(fdiv)
|
.pll_fdiv(fdiv)
|
||||||
);
|
);
|
||||||
|
let (pll_res, pll_cp, lock_cnt) = PLL_FDIV_LOCK_PARAM.iter()
|
||||||
|
.filter(|(fdiv_max, _)| fdiv <= *fdiv_max)
|
||||||
|
.last()
|
||||||
|
.expect("PLL_FDIV_LOCK_PARAM")
|
||||||
|
.1.clone();
|
||||||
|
regs.ddr_pll_cfg.write(
|
||||||
|
slcr::PllCfg::zeroed()
|
||||||
|
.pll_res(pll_res)
|
||||||
|
.pll_cp(pll_cp)
|
||||||
|
.lock_cnt(lock_cnt)
|
||||||
|
);
|
||||||
|
regs.ddr_pll_ctrl.modify(|_, w| w
|
||||||
|
.pll_reset(true)
|
||||||
|
);
|
||||||
|
regs.ddr_pll_ctrl.modify(|_, w| w
|
||||||
|
.pll_reset(false)
|
||||||
|
);
|
||||||
while ! regs.pll_status.read().ddr_pll_lock() {}
|
while ! regs.pll_status.read().ddr_pll_lock() {}
|
||||||
regs.ddr_pll_ctrl.modify(|_, w| w
|
regs.ddr_pll_ctrl.modify(|_, w| w
|
||||||
.pll_bypass_force(false)
|
.pll_bypass_force(false)
|
||||||
|
@ -110,3 +124,27 @@ impl CpuClocks {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// (pll_fdiv_max, (pll_cp, pll_res, lock_cnt))
|
||||||
|
const PLL_FDIV_LOCK_PARAM: &[(u16, (u8, u8, u16))] = &[
|
||||||
|
(13, (2, 6, 750)),
|
||||||
|
(14, (2, 6, 700)),
|
||||||
|
(15, (2, 6, 650)),
|
||||||
|
(16, (2, 10, 625)),
|
||||||
|
(17, (2, 10, 575)),
|
||||||
|
(18, (2, 10, 550)),
|
||||||
|
(19, (2, 10, 525)),
|
||||||
|
(20, (2, 12, 500)),
|
||||||
|
(21, (2, 12, 475)),
|
||||||
|
(22, (2, 12, 450)),
|
||||||
|
(23, (2, 12, 425)),
|
||||||
|
(25, (2, 12, 400)),
|
||||||
|
(26, (2, 12, 375)),
|
||||||
|
(28, (2, 12, 350)),
|
||||||
|
(30, (2, 12, 325)),
|
||||||
|
(33, (2, 2, 300)),
|
||||||
|
(36, (2, 2, 275)),
|
||||||
|
(40, (2, 2, 250)),
|
||||||
|
(47, (3, 12, 250)),
|
||||||
|
(66, (2, 4, 250)),
|
||||||
|
];
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
use crate::regs::{RegisterR, RegisterW, RegisterRW};
|
use crate::regs::{RegisterR, RegisterW, RegisterRW};
|
||||||
|
use crate::println;
|
||||||
use super::slcr;
|
use super::slcr;
|
||||||
use super::clocks::CpuClocks;
|
use super::clocks::CpuClocks;
|
||||||
|
|
||||||
mod regs;
|
mod regs;
|
||||||
|
|
||||||
|
#[cfg(feature = "target_zc706")]
|
||||||
/// Micron MT41J256M8HX-15E: 667 MHz DDR3
|
/// Micron MT41J256M8HX-15E: 667 MHz DDR3
|
||||||
const DDR_FREQ: u32 = 666_666_666;
|
const DDR_FREQ: u32 = 666_666_666;
|
||||||
|
|
||||||
|
#[cfg(feature = "target_cora_z7_10")]
|
||||||
|
/// Micron MT41K256M16HA-125: 800 MHz DDR3L
|
||||||
|
const DDR_FREQ: u32 = 800_000_000;
|
||||||
|
|
||||||
|
/// MT41K256M16HA-125
|
||||||
const DCI_FREQ: u32 = 10_000_000;
|
const DCI_FREQ: u32 = 10_000_000;
|
||||||
|
|
||||||
pub struct DdrRam {
|
pub struct DdrRam {
|
||||||
|
@ -131,12 +139,24 @@ impl DdrRam {
|
||||||
slcr.ddriob_drive_slew_clock.write(0x00F9861C);
|
slcr.ddriob_drive_slew_clock.write(0x00F9861C);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable internal V[REF]
|
#[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
|
slcr.ddriob_ddr_ctrl.modify(|_, w| w
|
||||||
.vref_ext_en_lower(false)
|
.vref_ext_en_lower(true)
|
||||||
.vref_ext_en_upper(false)
|
.vref_ext_en_upper(true)
|
||||||
.vref_sel(slcr::DdriobVrefSel::Vref0_75V)
|
.vref_sel(vref_sel)
|
||||||
.vref_int_en(true)
|
.vref_int_en(false)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -158,4 +178,47 @@ impl DdrRam {
|
||||||
pub fn status(&self) -> regs::ControllerStatus {
|
pub fn status(&self) -> regs::ControllerStatus {
|
||||||
self.regs.mode_sts_reg.read().operating_mode()
|
self.regs.mode_sts_reg.read().operating_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move into trait
|
||||||
|
pub fn ptr(&mut self) -> *mut u8 {
|
||||||
|
// 0x0010_0000 as *mut _
|
||||||
|
0x0020_0000 as *mut _
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
// #[cfg(feature = "target_zc706")]
|
||||||
|
// 1024 * 1024 * 1024
|
||||||
|
4 * 1024 * 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn memtest(&mut self) {
|
||||||
|
let slice = unsafe {
|
||||||
|
core::slice::from_raw_parts_mut(self.ptr(), self.size())
|
||||||
|
};
|
||||||
|
let patterns: &'static [u8] = &[0, 0xff, 0x55, 0xaa, 0];
|
||||||
|
let mut expected = None;
|
||||||
|
for (i, pattern) in patterns.iter().enumerate() {
|
||||||
|
println!("memtest phase {} (status: {:?})", i, self.status());
|
||||||
|
|
||||||
|
let slice_len = slice.len();
|
||||||
|
let mut progress = 0;
|
||||||
|
for (j, b) in slice.iter_mut().enumerate() {
|
||||||
|
expected.map(|expected| {
|
||||||
|
let read: u8 = *b;
|
||||||
|
if read != expected {
|
||||||
|
println!("{:08X}: expected {:02X}, read {:02X}", b as *mut u8 as usize, expected, read);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*b = *pattern;
|
||||||
|
// println!("{:08X}", b as *mut u8 as usize);
|
||||||
|
let new_progress = 100 * j / slice_len;
|
||||||
|
if new_progress > progress {
|
||||||
|
progress = new_progress;
|
||||||
|
println!("{}%", progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = Some(*pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue