zynq::ddr, main: parameters, memtest

This commit is contained in:
Astro 2019-10-25 23:19:34 +02:00
parent e61d1268ac
commit 9b4f07f37c
3 changed files with 119 additions and 13 deletions

View File

@ -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");

View File

@ -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)),
];

View File

@ -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);
}
}
} }