1use arbitrary_int::{prelude::*, u6};
7
8pub mod pll;
9
10use zynq7000::slcr::{
11 ClockControl,
12 clocks::{
13 ClockkRatioSelect, DualCommonPeriphIoClockControl, FpgaClockControl, GigEthClockControl,
14 SingleCommonPeriphIoClockControl,
15 },
16};
17
18use super::time::Hertz;
19
20#[derive(Debug)]
21pub struct ArmClocks {
22 ref_clk: Hertz,
23 cpu_1x_clk: Hertz,
24 cpu_2x_clk: Hertz,
25 cpu_3x2x_clk: Hertz,
26 cpu_6x4x_clk: Hertz,
27}
28
29impl ArmClocks {
30 pub const fn ref_clk(&self) -> Hertz {
32 self.ref_clk
33 }
34
35 pub const fn cpu_1x_clk(&self) -> Hertz {
36 self.cpu_1x_clk
37 }
38
39 pub const fn cpu_2x_clk(&self) -> Hertz {
40 self.cpu_2x_clk
41 }
42
43 pub const fn cpu_3x2x_clk(&self) -> Hertz {
44 self.cpu_3x2x_clk
45 }
46
47 pub const fn cpu_6x4x_clk(&self) -> Hertz {
48 self.cpu_6x4x_clk
49 }
50}
51
52#[derive(Debug)]
53pub struct DdrClocks {
54 ref_clk: Hertz,
56 ddr_3x_clk: Hertz,
57 ddr_2x_clk: Hertz,
58}
59
60impl DdrClocks {
61 pub unsafe fn configure_2x_3x_clk(ddr_3x_div: u6, ddr_2x_div: u6) {
72 unsafe {
74 crate::slcr::Slcr::with(|slcr| {
75 slcr.clk_ctrl().modify_ddr_clk_ctrl(|mut val| {
76 val.set_div_3x_clk(ddr_3x_div);
77 val.set_div_2x_clk(ddr_2x_div);
78 val
79 });
80 });
81 }
82 }
83
84 pub unsafe fn new_with_2x_3x_init(ref_clk: Hertz, ddr_3x_div: u6, ddr_2x_div: u6) -> Self {
95 unsafe { Self::configure_2x_3x_clk(ddr_3x_div, ddr_2x_div) };
96 Self {
97 ref_clk,
98 ddr_3x_clk: ref_clk / ddr_3x_div.as_u32(),
99 ddr_2x_clk: ref_clk / ddr_2x_div.as_u32(),
100 }
101 }
102
103 pub const fn ref_clk(&self) -> Hertz {
105 self.ref_clk
106 }
107
108 pub fn ddr_3x_clk(&self) -> Hertz {
110 self.ddr_3x_clk
111 }
112
113 pub fn ddr_2x_clk(&self) -> Hertz {
116 self.ddr_2x_clk
117 }
118}
119
120#[derive(Debug)]
121pub struct IoClocks {
122 ref_clk: Hertz,
124 smc_clk: Hertz,
125 qspi_clk: Hertz,
126 sdio_clk: Hertz,
127 uart_clk: Hertz,
128 spi_clk: Hertz,
129 can_clk: Hertz,
130 pcap_2x_clk: Hertz,
131 trace_clk: Option<Hertz>,
132}
133
134impl IoClocks {
135 pub const fn ref_clk(&self) -> Hertz {
136 self.ref_clk
137 }
138
139 pub const fn smc_clk(&self) -> Hertz {
140 self.smc_clk
141 }
142
143 pub fn update_smc_clk(&mut self, clk: Hertz) {
144 self.smc_clk = clk
145 }
146
147 pub const fn qspi_clk(&self) -> Hertz {
148 self.qspi_clk
149 }
150
151 pub fn update_qspi_clk(&mut self, clk: Hertz) {
152 self.qspi_clk = clk
153 }
154
155 pub const fn sdio_clk(&self) -> Hertz {
156 self.sdio_clk
157 }
158
159 pub fn update_sdio_clk(&mut self, clk: Hertz) {
160 self.sdio_clk = clk
161 }
162
163 pub const fn uart_clk(&self) -> Hertz {
164 self.uart_clk
165 }
166
167 pub fn update_uart_clk(&mut self, clk: Hertz) {
168 self.uart_clk = clk
169 }
170
171 pub const fn spi_clk(&self) -> Hertz {
172 self.spi_clk
173 }
174
175 pub fn update_spi_clk(&mut self, clk: Hertz) {
176 self.spi_clk = clk
177 }
178
179 pub fn can_clk(&self) -> Hertz {
180 self.can_clk
181 }
182
183 pub fn update_can_clk(&mut self, clk: Hertz) {
184 self.can_clk = clk
185 }
186
187 pub fn pcap_2x_clk(&self) -> Hertz {
188 self.pcap_2x_clk
189 }
190
191 pub fn update_pcap_2x_clk(&mut self, clk: Hertz) {
192 self.pcap_2x_clk = clk
193 }
194
195 pub fn trace_clk(&self) -> Option<Hertz> {
197 self.trace_clk
198 }
199}
200
201#[derive(Debug)]
202pub struct Clocks {
203 ps_clk: Hertz,
204 arm_pll_out: Hertz,
205 io_pll_out: Hertz,
206 ddr_pll_out: Hertz,
207 arm: ArmClocks,
208 ddr: DdrClocks,
209 io: IoClocks,
210 pl: [Hertz; 4],
211}
212
213#[derive(Debug, Copy, Clone, PartialEq, Eq)]
214pub enum ClockModuleId {
215 Ddr,
216 Arm,
217 Smc,
218 Qspi,
219 Sdio,
220 Uart,
221 Spi,
222 Pcap,
223 Can,
224 Fpga,
225 Trace,
226 Gem0,
227 Gem1,
228}
229
230#[derive(Debug)]
231pub struct DivisorZero(pub ClockModuleId);
232
233#[derive(Debug, thiserror::Error)]
234pub enum ClockReadError {
235 #[error("PLL feedback divisor is zero")]
237 PllFeedbackZero,
238 #[error("divisor is zero")]
240 DivisorZero(DivisorZero),
241 #[error("divisor is not even")]
243 DivisorNotEven,
244}
245
246impl Clocks {
247 pub fn ps_clk(&self) -> Hertz {
249 self.ps_clk
250 }
251
252 pub fn new_from_regs(ps_clk_freq: Hertz) -> Result<Self, ClockReadError> {
257 let mut clk_regs = unsafe { ClockControl::new_mmio_fixed() };
258
259 let arm_pll_cfg = clk_regs.read_arm_pll_ctrl();
260 let io_pll_cfg = clk_regs.read_io_pll_ctrl();
261 let ddr_pll_cfg = clk_regs.read_ddr_pll_ctrl();
262
263 if arm_pll_cfg.fdiv().as_u32() == 0
264 || io_pll_cfg.fdiv().as_u32() == 0
265 || ddr_pll_cfg.fdiv().as_u32() == 0
266 {
267 return Err(ClockReadError::PllFeedbackZero);
268 }
269 let arm_pll_out = ps_clk_freq * arm_pll_cfg.fdiv().into();
270 let io_pll_out = ps_clk_freq * io_pll_cfg.fdiv().into();
271 let ddr_pll_out = ps_clk_freq * ddr_pll_cfg.fdiv().into();
272
273 let arm_clk_ctrl = clk_regs.read_arm_clk_ctrl();
274 let arm_base_clk = match arm_clk_ctrl.srcsel() {
275 zynq7000::slcr::clocks::SrcSelArm::ArmPll
276 | zynq7000::slcr::clocks::SrcSelArm::ArmPllAlt => arm_pll_out,
277 zynq7000::slcr::clocks::SrcSelArm::DdrPll => ddr_pll_out,
278 zynq7000::slcr::clocks::SrcSelArm::IoPll => io_pll_out,
279 };
280 let clk_sel = clk_regs.read_clk_621_true();
281 if arm_clk_ctrl.divisor().as_u32() == 0 {
282 return Err(ClockReadError::DivisorZero(DivisorZero(ClockModuleId::Arm)));
283 }
284 let arm_clk_divided = arm_base_clk / arm_clk_ctrl.divisor().as_u32();
285 let arm_clks = match clk_sel.sel() {
286 ClockkRatioSelect::FourToTwoToOne => ArmClocks {
287 ref_clk: arm_pll_out,
288 cpu_1x_clk: arm_clk_divided / 4,
289 cpu_2x_clk: arm_clk_divided / 2,
290 cpu_3x2x_clk: arm_clk_divided / 2,
291 cpu_6x4x_clk: arm_clk_divided,
292 },
293 ClockkRatioSelect::SixToTwoToOne => ArmClocks {
294 ref_clk: arm_pll_out,
295 cpu_1x_clk: arm_clk_divided / 6,
296 cpu_2x_clk: arm_clk_divided / 3,
297 cpu_3x2x_clk: arm_clk_divided / 2,
298 cpu_6x4x_clk: arm_clk_divided,
299 },
300 };
301
302 let ddr_clk_ctrl = clk_regs.read_ddr_clk_ctrl();
303 if ddr_clk_ctrl.div_3x_clk().as_u32() == 0 || ddr_clk_ctrl.div_2x_clk().as_u32() == 0 {
304 return Err(ClockReadError::DivisorZero(DivisorZero(ClockModuleId::Ddr)));
305 }
306 let ddr_clks = DdrClocks {
307 ref_clk: ddr_pll_out,
308 ddr_3x_clk: ddr_pll_out / ddr_clk_ctrl.div_3x_clk().as_u32(),
309 ddr_2x_clk: ddr_pll_out / ddr_clk_ctrl.div_2x_clk().as_u32(),
310 };
311
312 let handle_common_single_clock_config = |single_block: SingleCommonPeriphIoClockControl,
313 id: ClockModuleId|
314 -> Result<Hertz, ClockReadError> {
315 if single_block.divisor().as_u32() == 0 {
316 return Err(ClockReadError::DivisorZero(DivisorZero(id)));
317 }
318 Ok(match single_block.srcsel() {
319 zynq7000::slcr::clocks::SrcSelIo::IoPll
320 | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => {
321 io_pll_out / single_block.divisor().as_u32()
322 }
323 zynq7000::slcr::clocks::SrcSelIo::ArmPll => {
324 arm_pll_out / single_block.divisor().as_u32()
325 }
326 zynq7000::slcr::clocks::SrcSelIo::DdrPll => {
327 ddr_pll_out / single_block.divisor().as_u32()
328 }
329 })
330 };
331 let handle_common_dual_clock_config = |dual_block: DualCommonPeriphIoClockControl,
332 id: ClockModuleId|
333 -> Result<Hertz, ClockReadError> {
334 if dual_block.divisor().as_u32() == 0 {
335 return Err(ClockReadError::DivisorZero(DivisorZero(id)));
336 }
337 Ok(match dual_block.srcsel() {
338 zynq7000::slcr::clocks::SrcSelIo::IoPll
339 | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => {
340 io_pll_out / dual_block.divisor().as_u32()
341 }
342 zynq7000::slcr::clocks::SrcSelIo::ArmPll => {
343 arm_pll_out / dual_block.divisor().as_u32()
344 }
345 zynq7000::slcr::clocks::SrcSelIo::DdrPll => {
346 ddr_pll_out / dual_block.divisor().as_u32()
347 }
348 })
349 };
350
351 let smc_clk =
352 handle_common_single_clock_config(clk_regs.read_smc_clk_ctrl(), ClockModuleId::Smc)?;
353 let qspi_clk =
354 handle_common_single_clock_config(clk_regs.read_lqspi_clk_ctrl(), ClockModuleId::Qspi)?;
355 let sdio_clk =
356 handle_common_dual_clock_config(clk_regs.read_sdio_clk_ctrl(), ClockModuleId::Sdio)?;
357 let uart_clk =
358 handle_common_dual_clock_config(clk_regs.read_uart_clk_ctrl(), ClockModuleId::Uart)?;
359 let spi_clk =
360 handle_common_dual_clock_config(clk_regs.read_spi_clk_ctrl(), ClockModuleId::Spi)?;
361 let pcap_2x_clk =
362 handle_common_single_clock_config(clk_regs.read_pcap_clk_ctrl(), ClockModuleId::Pcap)?;
363 let can_clk_ctrl = clk_regs.read_can_clk_ctrl();
364 let can_clk_ref_clk = match can_clk_ctrl.srcsel() {
365 zynq7000::slcr::clocks::SrcSelIo::IoPll
366 | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => io_pll_out,
367 zynq7000::slcr::clocks::SrcSelIo::ArmPll => arm_pll_out,
368 zynq7000::slcr::clocks::SrcSelIo::DdrPll => ddr_pll_out,
369 };
370 if can_clk_ctrl.divisor_0().as_u32() == 0 || can_clk_ctrl.divisor_1().as_u32() == 0 {
371 return Err(ClockReadError::DivisorZero(DivisorZero(ClockModuleId::Can)));
372 }
373 let can_clk =
374 can_clk_ref_clk / can_clk_ctrl.divisor_0().as_u32() / can_clk_ctrl.divisor_1().as_u32();
375
376 let trace_clk_ctrl = clk_regs.read_dbg_clk_ctrl();
377 if trace_clk_ctrl.divisor().as_u32() == 0 {
378 return Err(ClockReadError::DivisorZero(DivisorZero(
379 ClockModuleId::Trace,
380 )));
381 }
382 let trace_clk = match trace_clk_ctrl.srcsel() {
383 zynq7000::slcr::clocks::SrcSelTpiu::IoPll
384 | zynq7000::slcr::clocks::SrcSelTpiu::IoPllAlt => {
385 Some(io_pll_out / trace_clk_ctrl.divisor().as_u32())
386 }
387 zynq7000::slcr::clocks::SrcSelTpiu::ArmPll => {
388 Some(arm_pll_out / trace_clk_ctrl.divisor().as_u32())
389 }
390 zynq7000::slcr::clocks::SrcSelTpiu::DdrPll => {
391 Some(ddr_pll_out / trace_clk_ctrl.divisor().as_u32())
392 }
393 zynq7000::slcr::clocks::SrcSelTpiu::EmioTraceClk
394 | zynq7000::slcr::clocks::SrcSelTpiu::EmioTraceClkAlt0
395 | zynq7000::slcr::clocks::SrcSelTpiu::EmioTraceClkAlt1
396 | zynq7000::slcr::clocks::SrcSelTpiu::EmioTraceClkAlt2 => None,
397 };
398 let calculate_fpga_clk =
399 |fpga_clk_ctrl: FpgaClockControl| -> Result<Hertz, ClockReadError> {
400 if fpga_clk_ctrl.divisor_0().as_u32() == 0
401 || fpga_clk_ctrl.divisor_1().as_u32() == 0
402 {
403 return Err(ClockReadError::DivisorZero(DivisorZero(
404 ClockModuleId::Fpga,
405 )));
406 }
407 Ok(match fpga_clk_ctrl.srcsel() {
408 zynq7000::slcr::clocks::SrcSelIo::IoPll
409 | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => {
410 io_pll_out
411 / fpga_clk_ctrl.divisor_0().as_u32()
412 / fpga_clk_ctrl.divisor_1().as_u32()
413 }
414 zynq7000::slcr::clocks::SrcSelIo::ArmPll => {
415 arm_pll_out
416 / fpga_clk_ctrl.divisor_0().as_u32()
417 / fpga_clk_ctrl.divisor_1().as_u32()
418 }
419 zynq7000::slcr::clocks::SrcSelIo::DdrPll => {
420 ddr_pll_out
421 / fpga_clk_ctrl.divisor_0().as_u32()
422 / fpga_clk_ctrl.divisor_1().as_u32()
423 }
424 })
425 };
426
427 Ok(Self {
428 ps_clk: ps_clk_freq,
429 io_pll_out,
430 ddr_pll_out,
431 arm_pll_out,
432 arm: arm_clks,
433 ddr: ddr_clks,
434 io: IoClocks {
435 ref_clk: io_pll_out,
436 smc_clk,
437 qspi_clk,
438 sdio_clk,
439 uart_clk,
440 spi_clk,
441 can_clk,
442 pcap_2x_clk,
443 trace_clk,
444 },
445 pl: [
448 calculate_fpga_clk(clk_regs.fpga_0_clk_ctrl().read_ctrl())?,
449 calculate_fpga_clk(clk_regs.fpga_1_clk_ctrl().read_ctrl())?,
450 calculate_fpga_clk(clk_regs.fpga_2_clk_ctrl().read_ctrl())?,
451 calculate_fpga_clk(clk_regs.fpga_3_clk_ctrl().read_ctrl())?,
452 ],
453 })
454 }
455
456 pub fn arm_clocks(&self) -> &ArmClocks {
457 &self.arm
458 }
459
460 pub fn ddr_clocks(&self) -> &DdrClocks {
461 &self.ddr
462 }
463
464 pub fn io_clocks(&self) -> &IoClocks {
465 &self.io
466 }
467
468 pub fn io_clocks_mut(&mut self) -> &mut IoClocks {
469 &mut self.io
470 }
471
472 pub fn pl_clocks(&self) -> &[Hertz; 4] {
474 &self.pl
475 }
476
477 fn calculate_gem_ref_clock(
478 &self,
479 reg: GigEthClockControl,
480 module: ClockModuleId,
481 ) -> Result<Hertz, DivisorZero> {
482 let source_clk = match reg.srcsel() {
483 zynq7000::slcr::clocks::SrcSelIo::IoPll
484 | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => self.io_pll_out,
485 zynq7000::slcr::clocks::SrcSelIo::ArmPll => self.arm_pll_out,
486 zynq7000::slcr::clocks::SrcSelIo::DdrPll => self.ddr_pll_out,
487 };
488 let div0 = reg.divisor_0().as_u32();
489 if div0 == 0 {
490 return Err(DivisorZero(module));
491 }
492 let div1 = reg.divisor_1().as_u32();
493 if div1 == 0 {
494 return Err(DivisorZero(module));
495 }
496 Ok(source_clk / reg.divisor_0().as_u32() / reg.divisor_1().as_u32())
497 }
498
499 pub fn calculate_gem_0_ref_clock(&self) -> Result<Hertz, DivisorZero> {
508 let clk_regs = unsafe { ClockControl::new_mmio_fixed() };
509 self.calculate_gem_ref_clock(clk_regs.read_gem_0_clk_ctrl(), ClockModuleId::Gem0)
510 }
511
512 pub fn calculate_gem_1_ref_clock(&self) -> Result<Hertz, DivisorZero> {
521 let clk_regs = unsafe { ClockControl::new_mmio_fixed() };
522 self.calculate_gem_ref_clock(clk_regs.read_gem_0_clk_ctrl(), ClockModuleId::Gem1)
523 }
524}