From ef4fb598fb39604bde6478b45fe7c0ed7b9ca082 Mon Sep 17 00:00:00 2001 From: Astro Date: Tue, 28 Jul 2020 00:38:48 +0200 Subject: [PATCH] ddr: improve dci divisors calculation --- libboard_zynq/src/ddr/mod.rs | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/libboard_zynq/src/ddr/mod.rs b/libboard_zynq/src/ddr/mod.rs index b8ff935..b32e4ef 100644 --- a/libboard_zynq/src/ddr/mod.rs +++ b/libboard_zynq/src/ddr/mod.rs @@ -56,14 +56,35 @@ impl DdrRam { clocks } + fn calculate_dci_divisors(clocks: &Clocks) -> (u8, u8) { + let target = (DCI_FREQ - 1 + clocks.ddr) / DCI_FREQ; + + let mut best = None; + let mut best_error = 0; + for divisor0 in 1..63 { + for divisor1 in 1..63 { + let current = (divisor0 as u32) * (divisor1 as u32); + let error = if current > target { + current - target + } else { + target - current + }; + if best.is_none() || best_error > error { + best = Some((divisor0, divisor1)); + best_error = error; + } + } + } + best.unwrap() + } + /// Zynq-7000 AP SoC Technical Reference Manual: /// 10.6.2 DDR IOB Impedance Calibration fn calibrate_iob_impedance(clocks: &Clocks) { - let divisor0 = ((DCI_FREQ - 1 + clocks.ddr) / DCI_FREQ) - .max(1).min(63) as u8; - let divisor1 = ((DCI_FREQ - 1 + clocks.ddr) / DCI_FREQ / u32::from(divisor0)) - .max(1).min(63) as u8; - debug!("DDR DCI clock: {} Hz", clocks.ddr / u32::from(divisor0) / u32::from(divisor1)); + let (divisor0, divisor1) = Self::calculate_dci_divisors(clocks); + debug!("DDR DCI clock: {} Hz (divisors={}*{})", + clocks.ddr / u32::from(divisor0) / u32::from(divisor1), + divisor0, divisor1); slcr::RegisterBlock::unlocked(|slcr| { // Step 1.