1use arbitrary_int::u6;
7use zynq7000::ddrc::MmioDdrController;
8
9use crate::{
10 BootMode,
11 clocks::pll::{PllConfig, configure_ddr_pll},
12 time::Hertz,
13};
14
15pub mod ll;
16
17pub use ll::{DdrcConfigSet, DdriobConfigSet};
18
19#[derive(Debug, Clone, Copy)]
20pub struct DdrClockSetupConfig {
21 pub ps_clk: Hertz,
22 pub ddr_clk: Hertz,
23 pub ddr_3x_div: u6,
24 pub ddr_2x_div: u6,
25}
26
27impl DdrClockSetupConfig {
28 pub const fn new(ps_clk: Hertz, ddr_clk: Hertz, ddr_3x_div: u6, ddr_2x_div: u6) -> Self {
29 Self {
30 ps_clk,
31 ddr_clk,
32 ddr_3x_div,
33 ddr_2x_div,
34 }
35 }
36}
37
38pub fn configure_ddr_for_ddr3(
51 mut ddrc_regs: MmioDdrController<'static>,
52 boot_mode: BootMode,
53 clk_setup_cfg: DdrClockSetupConfig,
54 ddriob_cfg: &DdriobConfigSet,
55 ddr_cfg: &DdrcConfigSet,
56) {
57 configure_ddr_pll(
60 boot_mode,
61 PllConfig::new_from_target_clock(clk_setup_cfg.ps_clk, clk_setup_cfg.ddr_clk).unwrap(),
62 );
63 let ddr_clks = unsafe {
65 crate::clocks::DdrClocks::new_with_2x_3x_init(
66 clk_setup_cfg.ddr_clk,
67 clk_setup_cfg.ddr_3x_div,
68 clk_setup_cfg.ddr_2x_div,
69 )
70 };
71 let dci_clk_cfg = ll::calculate_dci_divisors(&ddr_clks);
72
73 ddrc_regs.modify_ddrc_ctrl(|mut val| {
74 val.set_soft_reset(zynq7000::ddrc::regs::SoftReset::Reset);
75 val
76 });
77
78 unsafe {
80 ll::configure_iob(ddriob_cfg);
81 ll::calibrate_iob_impedance_for_ddr3(dci_clk_cfg, false);
84 }
85 ll::configure_ddr_config(&mut ddrc_regs, ddr_cfg);
86 let slcr = unsafe { crate::slcr::Slcr::steal() };
89 let ddriob_shared = slcr.regs().ddriob_shared();
90 while !ddriob_shared.read_dci_status().done() {
92 cortex_ar::asm::nop();
93 }
94 log::debug!("DDR IOB impedance calib done");
95
96 ddrc_regs.modify_ddrc_ctrl(|mut val| {
98 val.set_soft_reset(zynq7000::ddrc::regs::SoftReset::Active);
99 val
100 });
101 while ddrc_regs.read_mode_status().operating_mode()
103 != zynq7000::ddrc::regs::OperatingMode::NormalOperation
104 {
105 cortex_ar::asm::nop();
107 }
108}
109
110pub mod memtest {
111 #[derive(Debug, thiserror::Error)]
112 pub enum MemTestError {
113 #[error("memory address is not aligned to 4 bytes")]
114 AddrNotAligned,
115 #[error("memory test error")]
116 Memory {
117 addr: usize,
118 expected: u32,
119 found: u32,
120 },
121 }
122
123 pub unsafe fn walking_zero_test(base_addr: usize, words: usize) -> Result<(), MemTestError> {
128 unsafe { walking_value_test(true, base_addr, words) }
129 }
130
131 pub unsafe fn walking_one_test(base_addr: usize, words: usize) -> Result<(), MemTestError> {
136 unsafe { walking_value_test(true, base_addr, words) }
137 }
138
139 pub unsafe fn walking_value_test(
144 walking_zero: bool,
145 base_addr: usize,
146 words: usize,
147 ) -> Result<(), MemTestError> {
148 if words == 0 {
149 return Ok(());
150 }
151 if !base_addr.is_multiple_of(4) {
152 return Err(MemTestError::AddrNotAligned);
153 }
154 let base_ptr = base_addr as *mut u32;
155
156 for bit in 0..32 {
158 let pattern = if walking_zero {
159 !(1u32 << bit)
160 } else {
161 1u32 << bit
162 };
163
164 for i in 0..words {
166 unsafe {
167 let p = base_ptr.add(i);
168 core::ptr::write_volatile(p, pattern);
169 }
170 }
171
172 for i in 0..words {
174 let val;
175 unsafe {
176 let p = base_ptr.add(i) as *const u32;
177 val = core::ptr::read_volatile(p);
178 }
179 if val != pattern {
180 return Err(MemTestError::Memory {
181 addr: base_addr + i * 4,
182 expected: pattern,
183 found: val,
184 });
185 }
186 }
187 }
188 Ok(())
189 }
190
191 pub unsafe fn checkerboard_test(base_addr: usize, words: usize) -> Result<(), MemTestError> {
196 if words == 0 {
197 return Ok(());
198 }
199 if !base_addr.is_multiple_of(4) {
200 return Err(MemTestError::AddrNotAligned);
201 }
202
203 let base_ptr = base_addr as *mut u32;
204 let patterns = [0xAAAAAAAAu32, 0x55555555u32];
205
206 for &pattern in &patterns {
207 for i in 0..words {
209 let value = if i % 2 == 0 { pattern } else { !pattern };
210 unsafe {
211 core::ptr::write_volatile(base_ptr.add(i), value);
212 }
213 }
214
215 for i in 0..words {
217 let expected = if i % 2 == 0 { pattern } else { !pattern };
218 let val = unsafe { core::ptr::read_volatile(base_ptr.add(i)) };
219
220 if val != expected {
221 return Err(MemTestError::Memory {
222 addr: base_addr + i * 4,
223 expected,
224 found: val,
225 });
226 }
227 }
228 }
229
230 Ok(())
231 }
232}