From afda48e3fe3e136a97f7254e28db6ec0aa5f4f9c Mon Sep 17 00:00:00 2001 From: Astro Date: Tue, 22 Oct 2019 01:25:35 +0200 Subject: [PATCH] zynq::ddr: add clock_setup(), calibrate_iob_impedance() --- src/zynq/ddr/mod.rs | 58 +++++++++++++++++++++++++++++++++++++++------ src/zynq/slcr.rs | 25 ++++++++++++++++--- 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/src/zynq/ddr/mod.rs b/src/zynq/ddr/mod.rs index bac5bcd..1663556 100644 --- a/src/zynq/ddr/mod.rs +++ b/src/zynq/ddr/mod.rs @@ -1,27 +1,28 @@ -use crate::regs::RegisterW; +use crate::regs::{RegisterR, RegisterW, RegisterRW}; use super::slcr; use super::clocks::CpuClocks; /// Micron MT41J256M8HX-15E: 667 MHz const DDR_FREQ: u32 = 666_666_666; +const DCI_FREQ: u32 = 10_000_000; pub struct DdrRam { } impl DdrRam { pub fn new() -> Self { - Self::clock_setup(); - + let clocks = CpuClocks::get(); + Self::clock_setup(&clocks); + Self::calibrate_iob_impedance(&clocks); + let ram = DdrRam {}; - // TODO: ram. ram } - fn clock_setup() { - let clocks = CpuClocks::get(); + fn clock_setup(clocks: &CpuClocks) { let ddr3x_clk_divisor = ((clocks.ddr - 1) / DDR_FREQ + 1).min(255) as u8; let ddr2x_clk_divisor = 3 * ddr3x_clk_divisor / 2; - + slcr::RegisterBlock::unlocked(|slcr| { slcr.ddr_pll_ctrl.write( slcr::PllCtrl::zeroed() @@ -36,4 +37,47 @@ impl DdrRam { ); }); } + + fn calibrate_iob_impedance(clocks: &CpuClocks) { + let divisor0 = (clocks.ddr / DCI_FREQ) + .max(1).min(63) as u8; + let divisor1 = (clocks.ddr / DCI_FREQ / u32::from(divisor0)) + .max(1).min(63) as u8; + + 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 + 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() {} + }); + } } diff --git a/src/zynq/slcr.rs b/src/zynq/slcr.rs index b12dacf..5795e28 100644 --- a/src/zynq/slcr.rs +++ b/src/zynq/slcr.rs @@ -36,7 +36,7 @@ pub struct RegisterBlock { reserved1: [u32; 1], pub arm_clk_ctrl: ArmClkCtrl, pub ddr_clk_ctrl: DdrClkCtrl, - pub dci_clk_ctrl: RW, + pub dci_clk_ctrl: DciClkCtrl, pub aper_clk_ctrl: AperClkCtrl, pub usb0_clk_ctrl: RW, pub usb1_clk_ctrl: RW, @@ -201,8 +201,8 @@ pub struct RegisterBlock { pub w_diff: RW, pub w_clock: RW, pub ddriob_ddr_ctrl: RW, - pub ddriob_dci_ctrl: RW, - pub ddriob_dci_status: RW, + pub ddriob_dci_ctrl: DdriobDciCtrl, + pub ddriob_dci_status: DdriobDciStatus, } register_at!(RegisterBlock, 0xF8000000, new); @@ -275,6 +275,11 @@ register_bit!(ddr_clk_ctrl, ddr_2xclkact, 1); register_bits!(ddr_clk_ctrl, ddr_3xclk_divisor, u8, 20, 25); register_bits!(ddr_clk_ctrl, ddr_2xclk_divisor, u8, 26, 31); +register!(dci_clk_ctrl, DciClkCtrl, RW, u32); +register_bit!(dci_clk_ctrl, clkact, 0); +register_bits!(dci_clk_ctrl, divisor0, u8, 8, 13); +register_bits!(dci_clk_ctrl, divisor1, u8, 20, 25); + register!(clk_621_true, Clk621True, RW, u32); register_bit!(clk_621_true, clk_621_true, 0); @@ -457,3 +462,17 @@ mio_pin_register!(mio_pin_53, MioPin53); register!(gpiob_ctrl, GpiobCtrl, RW, u32); register_bit!(gpiob_ctrl, vref_en, 0); + +register!(ddriob_dci_ctrl, DdriobDciCtrl, RW, u32); +register_bit!(ddriob_dci_ctrl, reset, 0); +register_bit!(ddriob_dci_ctrl, enable, 0); +register_bits!(ddriob_dci_ctrl, nref_opt1, u8, 6, 7); +register_bits!(ddriob_dci_ctrl, nref_opt2, u8, 8, 10); +register_bits!(ddriob_dci_ctrl, nref_opt4, u8, 11, 13); +register_bits!(ddriob_dci_ctrl, pref_opt1, u8, 14, 15); +register_bits!(ddriob_dci_ctrl, pref_opt2, u8, 17, 19); +register_bit!(ddriob_dci_ctrl, update_control, 20); + +register!(ddriob_dci_status, DdriobDciStatus, RW, u32); +register_bit!(ddriob_dci_status, done, 0); +register_bit!(ddriob_dci_status, lock, 13);