1#![allow(dead_code, reason = "Clock functions called from generated macro code")]
11#![allow(
12 missing_docs,
13 reason = "Clock-tree types come from a generated macro that does not emit doc strings"
14)]
15#![allow(
16 clippy::enum_variant_names,
17 reason = "CPU frequency variant names follow the chip-spec MHz convention"
18)]
19
20use core::sync::atomic::{AtomicBool, Ordering};
21
22use esp_rom_sys::rom::ets_update_cpu_frequency_rom;
23
24use crate::{
25 peripherals::{HP_SYS_CLKRST, LP_AON_CLKRST, PMU},
26 soc::regi2c,
27 time::Rate,
28};
29
30define_clock_tree_types!();
31
32#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35#[non_exhaustive]
36pub enum CpuClock {
37 _400MHz = 400,
40
41 _200MHz = 200,
44
45 #[default]
48 _100MHz = 100,
49}
50
51impl CpuClock {
52 const PRESET_400: ClockConfig = ClockConfig {
54 cpu_root_clk: Some(CpuRootClkConfig::Cpll),
55 cpll_clk: Some(CpllClkConfig::_400),
56 mpll_clk: Some(MpllClkConfig::_500),
57 cpu_clk: Some(CpuClkConfig::new(0)), mem_clk: Some(MemClkConfig::new(1)), sys_clk: Some(SysClkConfig::new(0)), apb_clk: Some(ApbClkConfig::new(1)), iomux_function_clock: Some(IomuxFunctionClockConfig::new(
62 IomuxFunctionClockSource::PllF80m,
63 0,
64 )),
65 lp_fast_clk: Some(LpFastClkConfig::RcFast),
66 lp_slow_clk: Some(LpSlowClkConfig::RcSlow),
67 timg_calibration_clock: None,
68 };
69
70 const PRESET_200: ClockConfig = ClockConfig {
73 cpu_root_clk: Some(CpuRootClkConfig::Cpll),
74 cpll_clk: Some(CpllClkConfig::_400),
75 mpll_clk: Some(MpllClkConfig::_500),
76 cpu_clk: Some(CpuClkConfig::new(1)), mem_clk: Some(MemClkConfig::new(0)), sys_clk: Some(SysClkConfig::new(0)), apb_clk: Some(ApbClkConfig::new(1)), iomux_function_clock: Some(IomuxFunctionClockConfig::new(
81 IomuxFunctionClockSource::PllF80m,
82 0,
83 )),
84 lp_fast_clk: Some(LpFastClkConfig::RcFast),
85 lp_slow_clk: Some(LpSlowClkConfig::RcSlow),
86 timg_calibration_clock: None,
87 };
88
89 const PRESET_100: ClockConfig = ClockConfig {
90 cpu_root_clk: Some(CpuRootClkConfig::Cpll),
91 cpll_clk: Some(CpllClkConfig::_400),
92 mpll_clk: Some(MpllClkConfig::_500),
93 cpu_clk: Some(CpuClkConfig::new(3)), mem_clk: Some(MemClkConfig::new(0)), sys_clk: Some(SysClkConfig::new(0)), apb_clk: Some(ApbClkConfig::new(0)), iomux_function_clock: Some(IomuxFunctionClockConfig::new(
98 IomuxFunctionClockSource::PllF80m,
99 0,
100 )),
101 lp_fast_clk: Some(LpFastClkConfig::RcFast),
102 lp_slow_clk: Some(LpSlowClkConfig::RcSlow),
103 timg_calibration_clock: None,
104 };
105}
106
107impl From<CpuClock> for ClockConfig {
108 fn from(value: CpuClock) -> ClockConfig {
109 match value {
110 CpuClock::_400MHz => CpuClock::PRESET_400,
111 CpuClock::_200MHz => CpuClock::PRESET_200,
112 CpuClock::_100MHz => CpuClock::PRESET_100,
113 }
114 }
115}
116
117impl Default for ClockConfig {
118 fn default() -> Self {
119 Self::from(CpuClock::default())
120 }
121}
122
123impl ClockConfig {
124 pub(crate) fn try_get_preset(self) -> Option<CpuClock> {
125 match self {
126 v if v == CpuClock::PRESET_400 => Some(CpuClock::_400MHz),
127 v if v == CpuClock::PRESET_200 => Some(CpuClock::_200MHz),
128 v if v == CpuClock::PRESET_100 => Some(CpuClock::_100MHz),
129 _ => None,
130 }
131 }
132
133 pub(crate) fn configure(self, clocks: &mut ClockTree) {
134 DIVIDER_UPDATE_DEFERRED.store(true, Ordering::Relaxed);
138 self.apply(clocks);
139 DIVIDER_UPDATE_DEFERRED.store(false, Ordering::Relaxed);
140
141 update_divider();
142 ets_update_cpu_frequency_rom(Rate::from_hz(cpu_clk_frequency()).as_mhz());
143 }
144}
145
146fn enable_cpll_clk_impl(_clocks: &mut ClockTree, _en: bool) {
149 }
151
152fn configure_cpll_clk_impl(
153 _clocks: &mut ClockTree,
154 _old_config: Option<CpllClkConfig>,
155 new_config: CpllClkConfig,
156) {
157 HP_SYS_CLKRST::regs()
161 .ana_pll_ctrl0()
162 .modify(|_, w| w.cpu_pll_cal_stop().clear_bit());
163
164 let div7_0: u8 = match new_config {
166 CpllClkConfig::_360 => 9,
167 CpllClkConfig::_400 => 10,
168 };
169
170 let lref: u8 = 0x50; let dcur: u8 = 0x73; regi2c::I2C_CPLL_OC_REF_DIV.write_reg(lref);
174 regi2c::I2C_CPLL_OC_DIV_7_0.write_reg(div7_0);
175 regi2c::I2C_CPLL_OC_DCUR.write_reg(dcur);
176
177 while !HP_SYS_CLKRST::regs()
179 .ana_pll_ctrl0()
180 .read()
181 .cpu_pll_cal_end()
182 .bit_is_set()
183 {
184 core::hint::spin_loop();
185 }
186
187 crate::rom::ets_delay_us(10);
189
190 HP_SYS_CLKRST::regs()
191 .ana_pll_ctrl0()
192 .modify(|_, w| w.cpu_pll_cal_stop().set_bit());
193}
194
195fn enable_spll_clk_impl(_clocks: &mut ClockTree, _en: bool) {
198 }
200
201fn enable_mpll_clk_impl(clocks: &mut ClockTree, en: bool) {
204 PMU::regs().rf_pwc().modify(|_, w| w.mspi_phy_xpd().bit(en));
205 LP_AON_CLKRST::regs()
206 .lp_aonclkrst_hp_clk_ctrl()
207 .modify(|_, w| w.lp_aonclkrst_hp_mpll_500m_clk_en().bit(en));
208
209 if !en {
210 return;
211 }
212
213 HP_SYS_CLKRST::regs()
217 .ana_pll_ctrl0()
218 .modify(|_, w| w.mspi_cal_stop().clear_bit());
219
220 regi2c::I2C_MPLL_DHREF_DHREF.write_field(3);
221
222 let rstb = regi2c::I2C_MPLL_IR_CAL_RSTB.read();
223 regi2c::I2C_MPLL_IR_CAL_RSTB.write_reg(rstb & 0xDF);
224 regi2c::I2C_MPLL_IR_CAL_RSTB.write_reg(rstb | (1 << 5));
225
226 let ref_div: u8 = 1;
228 let div: u8 = match unwrap!(clocks.mpll_clk) {
229 MpllClkConfig::_320 => 15,
230 MpllClkConfig::_400 => 19,
231 MpllClkConfig::_500 => 24,
232 };
233 let div_val: u8 = (div << 3) | ref_div;
234 regi2c::I2C_MPLL_DIV_REG_ADDR.write_reg(div_val);
235
236 while HP_SYS_CLKRST::regs()
237 .ana_pll_ctrl0()
238 .read()
239 .mspi_cal_end()
240 .bit_is_clear()
241 {
242 core::hint::spin_loop();
243 }
244 HP_SYS_CLKRST::regs()
245 .ana_pll_ctrl0()
246 .modify(|_, w| w.mspi_cal_stop().set_bit());
247
248 crate::rom::ets_delay_us(10);
249}
250
251fn configure_mpll_clk_impl(
252 _clocks: &mut ClockTree,
253 _old_config: Option<MpllClkConfig>,
254 _new_config: MpllClkConfig,
255) {
256 }
258
259fn configure_cpu_root_clk_impl(
261 _clocks: &mut ClockTree,
262 _old_selector: Option<CpuRootClkConfig>,
263 new_selector: CpuRootClkConfig,
264) {
265 let sel = match new_selector {
267 CpuRootClkConfig::Xtal => 0,
268 CpuRootClkConfig::Cpll => 1,
269 CpuRootClkConfig::RcFast => 2,
270 };
271 LP_AON_CLKRST::regs()
272 .lp_aonclkrst_hp_clk_ctrl()
273 .modify(|_, w| unsafe { w.lp_aonclkrst_hp_root_clk_src_sel().bits(sel) });
274}
275
276fn enable_cpu_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
278fn configure_cpu_clk_impl(
279 _clocks: &mut ClockTree,
280 _old_config: Option<CpuClkConfig>,
281 new_config: CpuClkConfig,
282) {
283 HP_SYS_CLKRST::regs()
284 .root_clk_ctrl0()
285 .modify(|_, w| unsafe {
286 w.cpu_clk_div_num().bits(new_config.divisor as u8);
287 w.cpu_clk_div_numerator().bits(0);
288 w.cpu_clk_div_denominator().bits(0)
289 });
290
291 update_divider();
293
294 if !DIVIDER_UPDATE_DEFERRED.load(Ordering::Relaxed) {
295 ets_update_cpu_frequency_rom(Rate::from_hz(cpu_clk_frequency()).as_mhz());
296 }
297}
298
299static DIVIDER_UPDATE_DEFERRED: AtomicBool = AtomicBool::new(false);
300
301fn update_divider() {
302 if DIVIDER_UPDATE_DEFERRED.load(Ordering::Relaxed) {
303 return;
304 }
305
306 HP_SYS_CLKRST::regs()
307 .root_clk_ctrl0()
308 .modify(|_, w| w.soc_clk_div_update().set_bit());
309 while HP_SYS_CLKRST::regs()
310 .root_clk_ctrl0()
311 .read()
312 .soc_clk_div_update()
313 .bit_is_set()
314 {
315 core::hint::spin_loop();
316 }
317}
318
319fn enable_mem_clk_impl(_clocks: &mut ClockTree, _en: bool) {
322 }
324
325fn configure_mem_clk_impl(
326 _clocks: &mut ClockTree,
327 _old_config: Option<MemClkConfig>,
328 new_config: MemClkConfig,
329) {
330 HP_SYS_CLKRST::regs()
331 .root_clk_ctrl1()
332 .modify(|_, w| unsafe {
333 w.mem_clk_div_num().bits(new_config.divisor as u8);
334 w.mem_clk_div_numerator().bits(0);
335 w.mem_clk_div_denominator().bits(0)
336 });
337
338 update_divider();
340}
341
342fn enable_sys_clk_impl(_clocks: &mut ClockTree, _en: bool) {
345 }
347
348fn configure_sys_clk_impl(
349 _clocks: &mut ClockTree,
350 _old_config: Option<SysClkConfig>,
351 new_config: SysClkConfig,
352) {
353 HP_SYS_CLKRST::regs()
354 .root_clk_ctrl1()
355 .modify(|_, w| unsafe { w.sys_clk_div_num().bits(new_config.divisor as u8) });
356 HP_SYS_CLKRST::regs()
357 .root_clk_ctrl2()
358 .modify(|_, w| unsafe {
359 w.sys_clk_div_numerator().bits(0);
360 w.sys_clk_div_denominator().bits(0)
361 });
362
363 update_divider();
365}
366
367fn enable_apb_clk_impl(_clocks: &mut ClockTree, _en: bool) {
370 }
372
373fn configure_apb_clk_impl(
374 _clocks: &mut ClockTree,
375 _old_config: Option<ApbClkConfig>,
376 new_config: ApbClkConfig,
377) {
378 HP_SYS_CLKRST::regs()
379 .root_clk_ctrl2()
380 .modify(|_, w| unsafe {
381 w.apb_clk_div_num().bits(new_config.divisor as u8);
382 w.apb_clk_div_numerator().bits(0)
383 });
384 HP_SYS_CLKRST::regs()
385 .root_clk_ctrl3()
386 .modify(|_, w| unsafe { w.apb_clk_div_denominator().bits(0) });
387
388 update_divider();
390}
391
392fn configure_iomux_function_clock_impl(
395 _clocks: &mut ClockTree,
396 _old_config: Option<IomuxFunctionClockConfig>,
397 new_config: IomuxFunctionClockConfig,
398) {
399 HP_SYS_CLKRST::regs()
400 .peri_clk_ctrl26()
401 .modify(|_, w| unsafe {
402 w.iomux_clk_src_sel().bit(matches!(
403 new_config.source,
404 IomuxFunctionClockSource::PllF80m
405 ));
406 w.iomux_clk_div_num().bits(new_config.div_num as u8)
407 });
408}
409
410fn configure_lp_fast_clk_impl(
412 _clocks: &mut ClockTree,
413 _old_selector: Option<LpFastClkConfig>,
414 new_selector: LpFastClkConfig,
415) {
416 LP_AON_CLKRST::regs()
417 .lp_aonclkrst_lp_clk_conf()
418 .modify(|_, w| unsafe {
419 w.lp_aonclkrst_fast_clk_sel().bits(match new_selector {
420 LpFastClkConfig::RcFast => 0,
421 LpFastClkConfig::XtalD2 => 1,
422 })
423 });
424}
425
426fn configure_lp_slow_clk_impl(
428 _clocks: &mut ClockTree,
429 _old_selector: Option<LpSlowClkConfig>,
430 new_selector: LpSlowClkConfig,
431) {
432 LP_AON_CLKRST::regs()
433 .lp_aonclkrst_lp_clk_conf()
434 .modify(|_, w| unsafe {
435 w.lp_aonclkrst_slow_clk_sel().bits(match new_selector {
436 LpSlowClkConfig::RcSlow => 0,
437 #[cfg(use_xtal32k)]
438 LpSlowClkConfig::Xtal32k => 1,
439 LpSlowClkConfig::OscSlow => 3,
441 })
442 });
443}
444
445impl SdmInstance {
448 fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
451 crate::peripherals::GPIO_SD::regs()
452 .sigmadelta_misc()
453 .modify(|_, w| w.function_clk_en().bit(en));
454 }
455}
456impl TimgInstance {
457 fn enable_function_clock_impl(self, _clocks: &mut ClockTree, _en: bool) {
458 }
460
461 fn configure_function_clock_impl(
462 self,
463 _clocks: &mut ClockTree,
464 _old_config: Option<TimgFunctionClockConfig>,
465 _new_config: TimgFunctionClockConfig,
466 ) {
467 }
470
471 fn enable_wdt_clock_impl(self, _clocks: &mut ClockTree, _en: bool) {}
472
473 fn configure_wdt_clock_impl(
474 self,
475 _clocks: &mut ClockTree,
476 _old_config: Option<TimgWdtClockConfig>,
477 _new_config: TimgWdtClockConfig,
478 ) {
479 }
481}
482
483impl RmtInstance {
484 fn enable_sclk_impl(self, _clocks: &mut ClockTree, en: bool) {
487 HP_SYS_CLKRST::regs()
488 .peri_clk_ctrl22()
489 .modify(|_, w| w.rmt_clk_en().bit(en));
490 }
491
492 fn configure_sclk_impl(
493 self,
494 _clocks: &mut ClockTree,
495 _old_config: Option<RmtSclkConfig>,
496 new_config: RmtSclkConfig,
497 ) {
498 HP_SYS_CLKRST::regs()
500 .peri_clk_ctrl22()
501 .modify(|_, w| unsafe {
502 w.rmt_clk_src_sel().bits(match new_config {
503 RmtSclkConfig::XtalClk => 0,
504 RmtSclkConfig::RcFastClk => 1,
505 RmtSclkConfig::PllF80m => 2,
506 })
507 });
508 }
509}
510
511fn enable_cpu_root_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
515fn enable_lp_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
516fn enable_lp_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
517
518fn enable_rc_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
520#[cfg(use_xtal32k)]
521fn enable_xtal32k_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
522fn enable_osc_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
523fn enable_rc_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
524fn enable_rc32k_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
525fn enable_pll_f20m_impl(_clocks: &mut ClockTree, _en: bool) {}
526fn enable_pll_f80m_impl(_clocks: &mut ClockTree, _en: bool) {}
527fn enable_pll_f120m_impl(_clocks: &mut ClockTree, _en: bool) {}
528fn enable_pll_f160m_impl(_clocks: &mut ClockTree, _en: bool) {}
529fn enable_pll_f240m_impl(_clocks: &mut ClockTree, _en: bool) {}
530fn enable_pll_f25m_impl(_clocks: &mut ClockTree, _en: bool) {}
531fn enable_pll_f50m_impl(_clocks: &mut ClockTree, _en: bool) {}
532fn enable_xtal_d2_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
533fn enable_spll_d3_clock_impl(_clocks: &mut ClockTree, _en: bool) {}
534
535fn enable_timg_calibration_clock_impl(_clocks: &mut ClockTree, _en: bool) {
538 }
540
541impl MipiDsiInstance {
542 fn enable_dpi_clk_impl(self, _clocks: &mut ClockTree, en: bool) {
546 HP_SYS_CLKRST::regs()
547 .peri_clk_ctrl03()
548 .modify(|_, w| w.mipi_dsi_dpiclk_en().bit(en));
549 }
550
551 fn configure_dpi_clk_impl(
552 self,
553 _clocks: &mut ClockTree,
554 _old_config: Option<MipiDsiDpiClkConfig>,
555 new_config: MipiDsiDpiClkConfig,
556 ) {
557 let src_sel = match new_config.sclk() {
559 MipiDsiDpiClkSclk::Xtal => 0,
560 MipiDsiDpiClkSclk::PllF240m => 1,
561 MipiDsiDpiClkSclk::PllF160m => 2,
562 };
563 HP_SYS_CLKRST::regs()
564 .peri_clk_ctrl03()
565 .modify(|_, w| unsafe {
566 w.mipi_dsi_dpiclk_src_sel().bits(src_sel);
567 w.mipi_dsi_dpiclk_div_num().bits(new_config.div_num() as u8)
568 });
569 }
570
571 fn enable_phy_pll_refclk_impl(self, _clocks: &mut ClockTree, en: bool) {
575 HP_SYS_CLKRST::regs()
576 .peri_clk_ctrl03()
577 .modify(|_, w| w.mipi_dsi_dphy_pll_refclk_en().bit(en));
578 }
579
580 fn configure_phy_pll_refclk_impl(
581 self,
582 _clocks: &mut ClockTree,
583 _old_config: Option<MipiDsiPhyPllRefclkConfig>,
584 new_config: MipiDsiPhyPllRefclkConfig,
585 ) {
586 let src_sel = match new_config.sclk() {
588 MipiDsiPhyPllRefclkSclk::Xtal => 0u8,
589 MipiDsiPhyPllRefclkSclk::Cpll => 2,
590 MipiDsiPhyPllRefclkSclk::Spll => 3,
591 MipiDsiPhyPllRefclkSclk::Mpll => 4,
592 };
593 HP_SYS_CLKRST::regs()
594 .peri_clk_ctrl03()
595 .modify(|_, w| unsafe {
596 w.mipi_dsi_dphy_pll_refclk_src_sel().bits(src_sel);
597 w.mipi_dsi_dphy_pll_refclk_div_num()
598 .bits(new_config.div_num() as u8)
599 });
600 }
601
602 fn enable_phy_cfg_clk_impl(self, _clocks: &mut ClockTree, en: bool) {
607 HP_SYS_CLKRST::regs()
608 .peri_clk_ctrl03()
609 .modify(|_, w| w.mipi_dsi_dphy_cfg_clk_en().bit(en));
610 }
611
612 fn configure_phy_cfg_clk_impl(
613 self,
614 _clocks: &mut ClockTree,
615 _old_config: Option<MipiDsiPhyCfgClkConfig>,
616 new_config: MipiDsiPhyCfgClkConfig,
617 ) {
618 let src_sel = match new_config {
620 MipiDsiPhyCfgClkConfig::PllF20m => 0,
621 MipiDsiPhyCfgClkConfig::RcFast => 1,
622 MipiDsiPhyCfgClkConfig::PllF25m => 2,
623 };
624 HP_SYS_CLKRST::regs()
625 .peri_clk_ctrl02()
626 .modify(|_, w| unsafe { w.mipi_dsi_dphy_clk_src_sel().bits(src_sel) });
627 }
628}
629
630fn configure_timg_calibration_clock_impl(
631 _clocks: &mut ClockTree,
632 _old_config: Option<TimgCalibrationClockConfig>,
633 new_config: TimgCalibrationClockConfig,
634) {
635 HP_SYS_CLKRST::regs()
636 .peri_clk_ctrl21()
637 .modify(|_, w| unsafe {
638 w.timergrp0_tgrt_clk_src_sel().bits(match new_config {
639 TimgCalibrationClockConfig::MpllClk => 0,
640 TimgCalibrationClockConfig::SpllClk => 1,
641 TimgCalibrationClockConfig::CpllClk => 2,
642 TimgCalibrationClockConfig::RcFastDivClk => 7,
643 TimgCalibrationClockConfig::RcSlowClk => 8,
644 #[cfg(use_xtal32k)]
645 TimgCalibrationClockConfig::Xtal32kClk => 10,
646 })
647 });
648}
649
650impl PsramInstance {
651 fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
654 HP_SYS_CLKRST::regs().peri_clk_ctrl00().modify(|_, w| {
655 w.psram_pll_clk_en().bit(en);
656 w.psram_core_clk_en().bit(en)
657 });
658 }
659
660 fn configure_function_clock_impl(
661 self,
662 _clocks: &mut ClockTree,
663 _old_config: Option<PsramFunctionClockConfig>,
664 new_config: PsramFunctionClockConfig,
665 ) {
666 HP_SYS_CLKRST::regs()
667 .peri_clk_ctrl00()
668 .modify(|_, w| unsafe {
669 w.psram_clk_src_sel().bits(match new_config {
670 PsramFunctionClockConfig::Xtal => 0,
671 PsramFunctionClockConfig::Mpll => 1,
672 PsramFunctionClockConfig::Spll => 2,
673 PsramFunctionClockConfig::Cpll => 3,
674 })
675 });
676 }
677}