2019-10-22 07:25:35 +08:00
|
|
|
use crate::regs::{RegisterR, RegisterW, RegisterRW};
|
2019-10-22 04:19:03 +08:00
|
|
|
use super::slcr;
|
|
|
|
use super::clocks::CpuClocks;
|
2019-10-22 04:12:10 +08:00
|
|
|
|
|
|
|
/// Micron MT41J256M8HX-15E: 667 MHz
|
|
|
|
const DDR_FREQ: u32 = 666_666_666;
|
2019-10-22 07:25:35 +08:00
|
|
|
const DCI_FREQ: u32 = 10_000_000;
|
2019-10-22 04:12:10 +08:00
|
|
|
|
|
|
|
pub struct DdrRam {
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DdrRam {
|
|
|
|
pub fn new() -> Self {
|
2019-10-22 07:25:35 +08:00
|
|
|
let clocks = CpuClocks::get();
|
|
|
|
Self::clock_setup(&clocks);
|
|
|
|
Self::calibrate_iob_impedance(&clocks);
|
|
|
|
|
2019-10-22 04:12:10 +08:00
|
|
|
let ram = DdrRam {};
|
|
|
|
ram
|
|
|
|
}
|
|
|
|
|
2019-10-22 07:25:35 +08:00
|
|
|
fn clock_setup(clocks: &CpuClocks) {
|
2019-10-22 04:12:10 +08:00
|
|
|
let ddr3x_clk_divisor = ((clocks.ddr - 1) / DDR_FREQ + 1).min(255) as u8;
|
|
|
|
let ddr2x_clk_divisor = 3 * ddr3x_clk_divisor / 2;
|
2019-10-22 07:25:35 +08:00
|
|
|
|
2019-10-22 04:12:10 +08:00
|
|
|
slcr::RegisterBlock::unlocked(|slcr| {
|
|
|
|
slcr.ddr_pll_ctrl.write(
|
|
|
|
slcr::PllCtrl::zeroed()
|
|
|
|
);
|
|
|
|
|
|
|
|
slcr.ddr_clk_ctrl.write(
|
|
|
|
slcr::DdrClkCtrl::zeroed()
|
|
|
|
.ddr_2xclkact(true)
|
|
|
|
.ddr_3xclkact(true)
|
|
|
|
.ddr_2xclk_divisor(ddr2x_clk_divisor)
|
|
|
|
.ddr_3xclk_divisor(ddr3x_clk_divisor)
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2019-10-22 07:25:35 +08:00
|
|
|
|
|
|
|
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() {}
|
|
|
|
});
|
|
|
|
}
|
2019-10-22 04:12:10 +08:00
|
|
|
}
|