From 9b4f07f37c100c5b303e6bec631bdeb719c8f97e Mon Sep 17 00:00:00 2001 From: Astro Date: Fri, 25 Oct 2019 23:19:34 +0200 Subject: [PATCH] zynq::ddr, main: parameters, memtest --- src/main.rs | 7 ++++- src/zynq/clocks.rs | 52 +++++++++++++++++++++++++++----- src/zynq/ddr/mod.rs | 73 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 119 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 95815602..49a4e6ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -87,6 +87,9 @@ const HWADDR: [u8; 6] = [0, 0x23, 0xde, 0xea, 0xbe, 0xef]; fn 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(); println!("Clocks: {:?}", clocks); println!("CPU speeds: {}/{}/{}/{} MHz", @@ -94,7 +97,9 @@ fn main() { clocks.cpu_3x2x() / 1_000_000, clocks.cpu_2x() / 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()); println!("Eth on"); diff --git a/src/zynq/clocks.rs b/src/zynq/clocks.rs index daa041f1..0d33cb6f 100644 --- a/src/zynq/clocks.rs +++ b/src/zynq/clocks.rs @@ -1,4 +1,4 @@ -use crate::regs::{RegisterR, RegisterRW}; +use crate::regs::{RegisterR, RegisterW, RegisterRW}; use super::slcr; #[cfg(feature = "target_zc706")] @@ -90,19 +90,33 @@ impl CpuClocks { 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) { + let fdiv = (target_clock / PS_CLK).min(66) as u16; let regs = slcr::RegisterBlock::new(); regs.ddr_pll_ctrl.modify(|_, w| w .pll_pwrdwn(false) - .pll_reset(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) ); + 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() {} regs.ddr_pll_ctrl.modify(|_, w| w .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)), +]; diff --git a/src/zynq/ddr/mod.rs b/src/zynq/ddr/mod.rs index fbbe1db3..5cd83d90 100644 --- a/src/zynq/ddr/mod.rs +++ b/src/zynq/ddr/mod.rs @@ -1,11 +1,19 @@ use crate::regs::{RegisterR, RegisterW, RegisterRW}; +use crate::println; use super::slcr; use super::clocks::CpuClocks; mod regs; +#[cfg(feature = "target_zc706")] /// Micron MT41J256M8HX-15E: 667 MHz DDR3 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; pub struct DdrRam { @@ -131,12 +139,24 @@ impl DdrRam { 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 - .vref_ext_en_lower(false) - .vref_ext_en_upper(false) - .vref_sel(slcr::DdriobVrefSel::Vref0_75V) - .vref_int_en(true) + .vref_ext_en_lower(true) + .vref_ext_en_upper(true) + .vref_sel(vref_sel) + .vref_int_en(false) ); }); } @@ -158,4 +178,47 @@ impl DdrRam { pub fn status(&self) -> regs::ControllerStatus { 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); + } + } }