forked from M-Labs/zynq-rs
zynq::ddr: implement configure_iob()
This commit is contained in:
parent
afda48e3fe
commit
a8886de067
@ -35,9 +35,11 @@ macro_rules! register_common {
|
||||
}
|
||||
|
||||
pub mod $mod_name {
|
||||
#[derive(Clone)]
|
||||
pub struct Read {
|
||||
pub inner: $inner,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct Write {
|
||||
pub inner: $inner,
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::regs::{RegisterR, RegisterW, RegisterRW};
|
||||
use super::slcr;
|
||||
use super::clocks::CpuClocks;
|
||||
|
||||
/// Micron MT41J256M8HX-15E: 667 MHz
|
||||
/// Micron MT41J256M8HX-15E: 667 MHz DDR3
|
||||
const DDR_FREQ: u32 = 666_666_666;
|
||||
const DCI_FREQ: u32 = 10_000_000;
|
||||
|
||||
@ -14,11 +14,14 @@ impl DdrRam {
|
||||
let clocks = CpuClocks::get();
|
||||
Self::clock_setup(&clocks);
|
||||
Self::calibrate_iob_impedance(&clocks);
|
||||
Self::configure_iob();
|
||||
|
||||
let ram = DdrRam {};
|
||||
ram
|
||||
}
|
||||
|
||||
/// Zynq-7000 AP SoC Technical Reference Manual:
|
||||
/// 10.6.1 DDR Clock Initialization
|
||||
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;
|
||||
@ -38,6 +41,8 @@ impl DdrRam {
|
||||
});
|
||||
}
|
||||
|
||||
/// Zynq-7000 AP SoC Technical Reference Manual:
|
||||
/// 10.6.2 DDR IOB Impedance Calibration
|
||||
fn calibrate_iob_impedance(clocks: &CpuClocks) {
|
||||
let divisor0 = (clocks.ddr / DCI_FREQ)
|
||||
.max(1).min(63) as u8;
|
||||
@ -80,4 +85,49 @@ impl DdrRam {
|
||||
while ! slcr.ddriob_dci_status.read().done() {}
|
||||
});
|
||||
}
|
||||
|
||||
/// Zynq-7000 AP SoC Technical Reference Manual:
|
||||
/// 10.6.3 DDR IOB Configuration
|
||||
fn configure_iob() {
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
let addr_config = slcr::DdriobConfig::zeroed()
|
||||
.output_en(slcr::DdriobOutputEn::Obuf);
|
||||
slcr.ddriob_addr0.write(addr_config.clone());
|
||||
slcr.ddriob_addr1.write(addr_config);
|
||||
let data_config = slcr::DdriobConfig::zeroed()
|
||||
.inp_type(slcr::DdriobInputType::VrefDifferential)
|
||||
.term_en(true)
|
||||
.dci_type(slcr::DdriobDciType::Termination)
|
||||
.output_en(slcr::DdriobOutputEn::Obuf);
|
||||
slcr.ddriob_data0.write(data_config.clone());
|
||||
slcr.ddriob_data1.write(data_config);
|
||||
let diff_config = slcr::DdriobConfig::zeroed()
|
||||
.inp_type(slcr::DdriobInputType::Differential)
|
||||
.term_en(true)
|
||||
.dci_type(slcr::DdriobDciType::Termination)
|
||||
.output_en(slcr::DdriobOutputEn::Obuf);
|
||||
slcr.ddriob_diff0.write(diff_config.clone());
|
||||
slcr.ddriob_diff1.write(diff_config);
|
||||
slcr.ddriob_clock.write(
|
||||
slcr::DdriobConfig::zeroed()
|
||||
.output_en(slcr::DdriobOutputEn::Obuf)
|
||||
);
|
||||
|
||||
unsafe {
|
||||
// Not documented in Technical Reference Manual
|
||||
slcr.ddriob_drive_slew_addr.write(0x0018C61C);
|
||||
slcr.ddriob_drive_slew_data.write(0x00F9861C);
|
||||
slcr.ddriob_drive_slew_diff.write(0x00F9861C);
|
||||
slcr.ddriob_drive_slew_clock.write(0x00F9861C);
|
||||
}
|
||||
|
||||
// Enable internal 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)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,45 @@ pub enum ArmPllSource {
|
||||
IoPll = 0b11,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum DdriobInputType {
|
||||
Off = 0b00,
|
||||
/// For SSTL, HSTL
|
||||
VrefDifferential = 0b01,
|
||||
Differential = 0b10,
|
||||
Lvcmos = 0b11,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum DdriobDciType {
|
||||
/// DDR2/3L Addr and Clock
|
||||
Disabled = 0b00,
|
||||
/// LPDDR2
|
||||
Drive = 0b01,
|
||||
/// DDR2/3/3L Data and Diff
|
||||
Termination = 0b11,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum DdriobOutputEn {
|
||||
Ibuf = 0b00,
|
||||
Obuf = 0b11,
|
||||
}
|
||||
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum DdriobVrefSel {
|
||||
/// For LPDDR2 with 1.2V IO
|
||||
Vref0_6V,
|
||||
/// For DDR3L with 1.35V IO
|
||||
Vref0_675V,
|
||||
/// For DDR3 with 1.5V IO
|
||||
Vref0_75V,
|
||||
/// For DDR2 with 1.8V IO
|
||||
Vref0_9V,
|
||||
}
|
||||
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RegisterBlock {
|
||||
pub scl: RW<u32>,
|
||||
@ -190,17 +229,18 @@ pub struct RegisterBlock {
|
||||
pub gpiob_cfg_hstl: RW<u32>,
|
||||
pub gpiob_drvr_bias_ctrl: RW<u32>,
|
||||
reserved21: [u32; 9],
|
||||
pub ddriob_addr1: RW<u32>,
|
||||
pub ddriob_data0: RW<u32>,
|
||||
pub ddriob_data1: RW<u32>,
|
||||
pub ddriob_diff0: RW<u32>,
|
||||
pub ddriob_diff1: RW<u32>,
|
||||
pub ddriob_clock: RW<u32>,
|
||||
pub w_addr: RW<u32>,
|
||||
pub w_data: RW<u32>,
|
||||
pub w_diff: RW<u32>,
|
||||
pub w_clock: RW<u32>,
|
||||
pub ddriob_ddr_ctrl: RW<u32>,
|
||||
pub ddriob_addr0: DdriobConfig,
|
||||
pub ddriob_addr1: DdriobConfig,
|
||||
pub ddriob_data0: DdriobConfig,
|
||||
pub ddriob_data1: DdriobConfig,
|
||||
pub ddriob_diff0: DdriobConfig,
|
||||
pub ddriob_diff1: DdriobConfig,
|
||||
pub ddriob_clock: DdriobConfig,
|
||||
pub ddriob_drive_slew_addr: RW<u32>,
|
||||
pub ddriob_drive_slew_data: RW<u32>,
|
||||
pub ddriob_drive_slew_diff: RW<u32>,
|
||||
pub ddriob_drive_slew_clock: RW<u32>,
|
||||
pub ddriob_ddr_ctrl: DdriobDdrCtrl,
|
||||
pub ddriob_dci_ctrl: DdriobDciCtrl,
|
||||
pub ddriob_dci_status: DdriobDciStatus,
|
||||
}
|
||||
@ -463,6 +503,23 @@ mio_pin_register!(mio_pin_53, MioPin53);
|
||||
register!(gpiob_ctrl, GpiobCtrl, RW, u32);
|
||||
register_bit!(gpiob_ctrl, vref_en, 0);
|
||||
|
||||
register!(ddriob_config, DdriobConfig, RW, u32);
|
||||
register_bits_typed!(ddriob_config, inp_type, u8, DdriobInputType, 1, 2);
|
||||
register_bit!(ddriob_config, dci_update_b, 3);
|
||||
register_bit!(ddriob_config, term_en, 4);
|
||||
register_bits_typed!(ddriob_config, dci_type, u8, DdriobDciType, 5, 6);
|
||||
register_bit!(ddriob_config, ibuf_disable_mode, 7);
|
||||
register_bit!(ddriob_config, term_disable_mode, 8);
|
||||
register_bits_typed!(ddriob_config, output_en, u8, DdriobOutputEn, 9, 10);
|
||||
register_bit!(ddriob_config, pullup_en, 11);
|
||||
|
||||
register!(ddriob_ddr_ctrl, DdriobDdrCtrl, RW, u32);
|
||||
register_bit!(ddriob_ddr_ctrl, vref_int_en, 1);
|
||||
register_bits_typed!(ddriob_ddr_ctrl, vref_sel, u8, DdriobVrefSel, 1, 4);
|
||||
register_bit!(ddriob_ddr_ctrl, vref_ext_en_lower, 5);
|
||||
register_bit!(ddriob_ddr_ctrl, vref_ext_en_upper, 6);
|
||||
register_bit!(ddriob_ddr_ctrl, refio_en, 9);
|
||||
|
||||
register!(ddriob_dci_ctrl, DdriobDciCtrl, RW, u32);
|
||||
register_bit!(ddriob_dci_ctrl, reset, 0);
|
||||
register_bit!(ddriob_dci_ctrl, enable, 0);
|
||||
|
Loading…
Reference in New Issue
Block a user