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 LpSlowClkConfig::Xtal32k => 1,
438 LpSlowClkConfig::OscSlow => 3,
440 })
441 });
442}
443
444impl SdmInstance {
447 fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
450 crate::peripherals::GPIO_SD::regs()
451 .sigmadelta_misc()
452 .modify(|_, w| w.function_clk_en().bit(en));
453 }
454}
455impl TimgInstance {
456 fn enable_function_clock_impl(self, _clocks: &mut ClockTree, _en: bool) {
457 }
459
460 fn configure_function_clock_impl(
461 self,
462 _clocks: &mut ClockTree,
463 _old_config: Option<TimgFunctionClockConfig>,
464 _new_config: TimgFunctionClockConfig,
465 ) {
466 }
469
470 fn enable_wdt_clock_impl(self, _clocks: &mut ClockTree, _en: bool) {}
471
472 fn configure_wdt_clock_impl(
473 self,
474 _clocks: &mut ClockTree,
475 _old_config: Option<TimgWdtClockConfig>,
476 _new_config: TimgWdtClockConfig,
477 ) {
478 }
480}
481
482impl RmtInstance {
483 fn enable_sclk_impl(self, _clocks: &mut ClockTree, en: bool) {
486 HP_SYS_CLKRST::regs()
487 .peri_clk_ctrl22()
488 .modify(|_, w| w.rmt_clk_en().bit(en));
489 }
490
491 fn configure_sclk_impl(
492 self,
493 _clocks: &mut ClockTree,
494 _old_config: Option<RmtSclkConfig>,
495 new_config: RmtSclkConfig,
496 ) {
497 HP_SYS_CLKRST::regs()
499 .peri_clk_ctrl22()
500 .modify(|_, w| unsafe {
501 w.rmt_clk_src_sel().bits(match new_config {
502 RmtSclkConfig::XtalClk => 0,
503 RmtSclkConfig::RcFastClk => 1,
504 RmtSclkConfig::PllF80m => 2,
505 })
506 });
507 }
508}
509
510fn enable_cpu_root_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
514fn enable_lp_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
515fn enable_lp_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
516
517fn enable_rc_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
519fn enable_xtal32k_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
520fn enable_osc_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
521fn enable_rc_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
522fn enable_rc32k_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
523fn enable_pll_f20m_impl(_clocks: &mut ClockTree, _en: bool) {}
524fn enable_pll_f80m_impl(_clocks: &mut ClockTree, _en: bool) {}
525fn enable_pll_f120m_impl(_clocks: &mut ClockTree, _en: bool) {}
526fn enable_pll_f160m_impl(_clocks: &mut ClockTree, _en: bool) {}
527fn enable_pll_f240m_impl(_clocks: &mut ClockTree, _en: bool) {}
528fn enable_pll_f25m_impl(_clocks: &mut ClockTree, _en: bool) {}
529fn enable_pll_f50m_impl(_clocks: &mut ClockTree, _en: bool) {}
530fn enable_xtal_d2_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
531
532fn enable_timg_calibration_clock_impl(_clocks: &mut ClockTree, _en: bool) {
535 }
537
538impl MipiDsiInstance {
539 fn enable_dpi_clk_impl(self, _clocks: &mut ClockTree, en: bool) {
543 HP_SYS_CLKRST::regs()
544 .peri_clk_ctrl03()
545 .modify(|_, w| w.mipi_dsi_dpiclk_en().bit(en));
546 }
547
548 fn configure_dpi_clk_impl(
549 self,
550 _clocks: &mut ClockTree,
551 _old_config: Option<MipiDsiDpiClkConfig>,
552 new_config: MipiDsiDpiClkConfig,
553 ) {
554 let src_sel = match new_config.sclk() {
556 MipiDsiDpiClkSclk::Xtal => 0,
557 MipiDsiDpiClkSclk::PllF240m => 1,
558 MipiDsiDpiClkSclk::PllF160m => 2,
559 };
560 HP_SYS_CLKRST::regs()
561 .peri_clk_ctrl03()
562 .modify(|_, w| unsafe {
563 w.mipi_dsi_dpiclk_src_sel().bits(src_sel);
564 w.mipi_dsi_dpiclk_div_num().bits(new_config.div_num() as u8)
565 });
566 }
567
568 fn enable_phy_pll_refclk_impl(self, _clocks: &mut ClockTree, en: bool) {
572 HP_SYS_CLKRST::regs()
573 .peri_clk_ctrl03()
574 .modify(|_, w| w.mipi_dsi_dphy_pll_refclk_en().bit(en));
575 }
576
577 fn configure_phy_pll_refclk_impl(
578 self,
579 _clocks: &mut ClockTree,
580 _old_config: Option<MipiDsiPhyPllRefclkConfig>,
581 new_config: MipiDsiPhyPllRefclkConfig,
582 ) {
583 let src_sel = match new_config.sclk() {
585 MipiDsiPhyPllRefclkSclk::Xtal => 0u8,
586 MipiDsiPhyPllRefclkSclk::Cpll => 2,
587 MipiDsiPhyPllRefclkSclk::Spll => 3,
588 MipiDsiPhyPllRefclkSclk::Mpll => 4,
589 };
590 HP_SYS_CLKRST::regs()
591 .peri_clk_ctrl03()
592 .modify(|_, w| unsafe {
593 w.mipi_dsi_dphy_pll_refclk_src_sel().bits(src_sel);
594 w.mipi_dsi_dphy_pll_refclk_div_num()
595 .bits(new_config.div_num() as u8)
596 });
597 }
598
599 fn enable_phy_cfg_clk_impl(self, _clocks: &mut ClockTree, en: bool) {
604 HP_SYS_CLKRST::regs()
605 .peri_clk_ctrl03()
606 .modify(|_, w| w.mipi_dsi_dphy_cfg_clk_en().bit(en));
607 }
608
609 fn configure_phy_cfg_clk_impl(
610 self,
611 _clocks: &mut ClockTree,
612 _old_config: Option<MipiDsiPhyCfgClkConfig>,
613 new_config: MipiDsiPhyCfgClkConfig,
614 ) {
615 let src_sel = match new_config {
617 MipiDsiPhyCfgClkConfig::PllF20m => 0,
618 MipiDsiPhyCfgClkConfig::RcFast => 1,
619 MipiDsiPhyCfgClkConfig::PllF25m => 2,
620 };
621 HP_SYS_CLKRST::regs()
622 .peri_clk_ctrl02()
623 .modify(|_, w| unsafe { w.mipi_dsi_dphy_clk_src_sel().bits(src_sel) });
624 }
625}
626
627fn configure_timg_calibration_clock_impl(
628 _clocks: &mut ClockTree,
629 _old_config: Option<TimgCalibrationClockConfig>,
630 new_config: TimgCalibrationClockConfig,
631) {
632 HP_SYS_CLKRST::regs()
633 .peri_clk_ctrl21()
634 .modify(|_, w| unsafe {
635 w.timergrp0_tgrt_clk_src_sel().bits(match new_config {
636 TimgCalibrationClockConfig::MpllClk => 0,
637 TimgCalibrationClockConfig::SpllClk => 1,
638 TimgCalibrationClockConfig::CpllClk => 2,
639 TimgCalibrationClockConfig::RcFastDivClk => 7,
640 TimgCalibrationClockConfig::RcSlowClk => 8,
641 TimgCalibrationClockConfig::Xtal32kClk => 10,
642 })
643 });
644}
645
646impl PsramInstance {
647 fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
650 HP_SYS_CLKRST::regs().peri_clk_ctrl00().modify(|_, w| {
651 w.psram_pll_clk_en().bit(en);
652 w.psram_core_clk_en().bit(en)
653 });
654 }
655
656 fn configure_function_clock_impl(
657 self,
658 _clocks: &mut ClockTree,
659 _old_config: Option<PsramFunctionClockConfig>,
660 new_config: PsramFunctionClockConfig,
661 ) {
662 HP_SYS_CLKRST::regs()
663 .peri_clk_ctrl00()
664 .modify(|_, w| unsafe {
665 w.psram_clk_src_sel().bits(match new_config {
666 PsramFunctionClockConfig::Xtal => 0,
667 PsramFunctionClockConfig::Mpll => 1,
668 PsramFunctionClockConfig::Spll => 2,
669 PsramFunctionClockConfig::Cpll => 3,
670 })
671 });
672 }
673}