1#![allow(dead_code, reason = "Some of this is bound to be unused")]
14#![allow(missing_docs, reason = "Experimental")]
15
16use esp_rom_sys::rom::{ets_delay_us, ets_update_cpu_frequency_rom};
19
20use crate::{
21 clock::RtcClock,
22 peripherals::{I2C_ANA_MST, LPWR, SYSTEM, TIMG0},
23 rtc_cntl::Rtc,
24 soc::regi2c,
25 time::Rate,
26};
27
28define_clock_tree_types!();
29
30#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
32#[cfg_attr(feature = "defmt", derive(defmt::Format))]
33#[allow(
34 clippy::enum_variant_names,
35 reason = "MHz suffix indicates physical unit."
36)]
37#[non_exhaustive]
38pub enum CpuClock {
39 #[default]
41 _80MHz = 80,
42
43 _120MHz = 120,
45}
46
47impl CpuClock {
48 const PRESET_80: ClockConfig = ClockConfig {
49 xtal_clk: None,
50 system_pre_div: None,
51 cpu_pll_div: Some(CpuPllDivConfig::new(CpuPllDivDivisor::_6)),
52 cpu_clk: Some(CpuClkConfig::Pll),
53 rc_fast_clk_div_n: Some(RcFastClkDivNConfig::new(0)),
54 rtc_slow_clk: Some(RtcSlowClkConfig::RcSlow),
55 rtc_fast_clk: Some(RtcFastClkConfig::Rc),
56 low_power_clk: Some(LowPowerClkConfig::RtcSlow),
57 timg_calibration_clock: None,
58 };
59 const PRESET_120: ClockConfig = ClockConfig {
60 xtal_clk: None,
61 system_pre_div: None,
62 cpu_pll_div: Some(CpuPllDivConfig::new(CpuPllDivDivisor::_4)),
63 cpu_clk: Some(CpuClkConfig::Pll),
64 rc_fast_clk_div_n: Some(RcFastClkDivNConfig::new(0)),
65 rtc_slow_clk: Some(RtcSlowClkConfig::RcSlow),
66 rtc_fast_clk: Some(RtcFastClkConfig::Rc),
67 low_power_clk: Some(LowPowerClkConfig::RtcSlow),
68 timg_calibration_clock: None,
69 };
70}
71
72impl From<CpuClock> for ClockConfig {
73 fn from(value: CpuClock) -> ClockConfig {
74 match value {
75 CpuClock::_80MHz => CpuClock::PRESET_80,
76 CpuClock::_120MHz => CpuClock::PRESET_120,
77 }
78 }
79}
80
81impl Default for ClockConfig {
82 fn default() -> Self {
83 Self::from(CpuClock::default())
84 }
85}
86
87impl ClockConfig {
88 pub(crate) fn try_get_preset(self) -> Option<CpuClock> {
89 match self {
90 v if v == CpuClock::PRESET_80 => Some(CpuClock::_80MHz),
91 v if v == CpuClock::PRESET_120 => Some(CpuClock::_120MHz),
92 _ => None,
93 }
94 }
95
96 pub(crate) fn configure(mut self, clocks: &mut ClockTree) {
97 configure_xtal_clk(clocks, XtalClkConfig::_40);
99 configure_system_pre_div(clocks, SystemPreDivConfig::new(0));
100 configure_cpu_clk(clocks, CpuClkConfig::Xtal);
101
102 if self.xtal_clk.is_none() {
106 let xtal = detect_xtal_freq(clocks);
110 debug!("Auto-detected XTAL frequency: {}", xtal.value());
111 self.xtal_clk = Some(xtal);
112 }
113
114 self.apply(clocks);
115 }
116}
117
118fn detect_xtal_freq(clocks: &mut ClockTree) -> XtalClkConfig {
119 const CALIBRATION_CYCLES: u32 = 10;
122
123 LPWR::regs()
125 .clk_conf()
126 .modify(|_, w| w.dig_clk8m_d256_en().set_bit());
127
128 let (xtal_cycles, calibration_clock_frequency) = RtcClock::measure_rtc_clock(
129 clocks,
130 TimgCalibrationClockConfig::RcFastDivClk,
131 TimgFunctionClockConfig::XtalClk,
132 CALIBRATION_CYCLES,
133 );
134
135 LPWR::regs()
136 .clk_conf()
137 .modify(|_, w| w.dig_clk8m_d256_en().clear_bit());
138
139 let mhz = (calibration_clock_frequency * xtal_cycles / CALIBRATION_CYCLES).as_mhz();
140
141 if mhz.abs_diff(40) < mhz.abs_diff(26) {
142 XtalClkConfig::_40
143 } else {
144 XtalClkConfig::_26
145 }
146}
147
148fn configure_xtal_clk_impl(
151 _clocks: &mut ClockTree,
152 _old_config: Option<XtalClkConfig>,
153 config: XtalClkConfig,
154) {
155 let freq_mhz = config.value() / 1_000_000;
161 LPWR::regs().store4().modify(|r, w| unsafe {
162 let disable_rom_log_bit = r.bits() & Rtc::RTC_DISABLE_ROM_LOG;
167 let half = (freq_mhz & (0xFFFF & !Rtc::RTC_DISABLE_ROM_LOG)) | disable_rom_log_bit;
168 w.data().bits(half | (half << 16))
169 });
170}
171
172fn enable_pll_clk_impl(clocks: &mut ClockTree, en: bool) {
175 const I2C_BBPLL_OC_DCHGP_LSB: u32 = 4;
176 const I2C_BBPLL_OC_DHREF_SEL_LSB: u32 = 4;
177 const I2C_BBPLL_OC_DLREF_SEL_LSB: u32 = 6;
178
179 I2C_ANA_MST::regs()
181 .ana_config()
182 .modify(|_, w| w.bbpll_pd().bit(!en));
183
184 LPWR::regs().options0().modify(|_, w| {
185 let power_down = !en;
186 w.bb_i2c_force_pd().bit(power_down);
187 w.bbpll_force_pd().bit(power_down);
188 w.bbpll_i2c_force_pd().bit(power_down)
189 });
190
191 if !en {
192 return;
193 }
194
195 SYSTEM::regs()
198 .cpu_per_conf()
199 .modify(|_, w| w.pll_freq_sel().set_bit()); I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
205 w.bbpll_stop_force_high().clear_bit();
206 w.bbpll_stop_force_low().set_bit()
207 });
208
209 let div_ref: u8;
210 let div7_0: u8;
211 let dr1: u8;
212 let dr3: u8;
213 let dchgp: u8;
214 let dcur: u8;
215 let dbias: u8;
216 match unwrap!(clocks.xtal_clk) {
218 XtalClkConfig::_26 => {
219 div_ref = 12;
221 div7_0 = 236;
223 dr1 = 4;
224 dr3 = 4;
225 dchgp = 0;
226 dcur = 0;
227 dbias = 2;
228 }
229 XtalClkConfig::_40 => {
230 div_ref = 0;
232 div7_0 = 8;
234 dr1 = 0;
235 dr3 = 0;
236 dchgp = 5;
237 dcur = 3;
238 dbias = 2;
239 }
240 }
241
242 regi2c::I2C_BBPLL_REG4.write_reg(0x6b);
243
244 let i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | div_ref;
245 let i2c_bbpll_dcur =
246 (1 << I2C_BBPLL_OC_DLREF_SEL_LSB) | (3 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
247
248 regi2c::I2C_BBPLL_OC_REF.write_reg(i2c_bbpll_lref);
249 regi2c::I2C_BBPLL_OC_DIV_REG.write_reg(div7_0);
250 regi2c::I2C_BBPLL_OC_DR1.write_field(dr1);
251 regi2c::I2C_BBPLL_OC_DR3.write_field(dr3);
252 regi2c::I2C_BBPLL_REG6.write_reg(i2c_bbpll_dcur);
253 regi2c::I2C_BBPLL_OC_VCO_DBIAS.write_field(dbias);
254
255 while I2C_ANA_MST::regs()
256 .ana_conf0()
257 .read()
258 .bbpll_cal_done()
259 .bit_is_clear()
260 {}
261
262 ets_delay_us(10);
263
264 I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
266 w.bbpll_stop_force_high().set_bit();
267 w.bbpll_stop_force_low().clear_bit()
268 });
269}
270
271fn enable_rc_fast_clk_impl(_clocks: &mut ClockTree, en: bool) {
274 const RTC_CNTL_FOSC_DFREQ_DEFAULT: u8 = 172;
276 LPWR::regs().clk_conf().modify(|_, w| {
277 unsafe { w.ck8m_dfreq().bits(RTC_CNTL_FOSC_DFREQ_DEFAULT) };
281
282 w.enb_ck8m().bit(!en);
283 w.dig_clk8m_en().bit(en); w.ck8m_force_pd().clear_bit();
286 w.ck8m_force_pu().clear_bit()
287 });
288 LPWR::regs()
289 .timer1()
290 .modify(|_, w| unsafe { w.ck8m_wait().bits(if en { 5 } else { 20 }) });
291}
292
293fn enable_osc_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {
296 }
298
299fn enable_rc_slow_clk_impl(_clocks: &mut ClockTree, en: bool) {
302 if !en {
303 return;
304 }
305
306 const RTC_CNTL_SCK_DCAP_DEFAULT: u8 = 255;
309 LPWR::regs()
310 .rtc_cntl()
311 .modify(|_, w| unsafe { w.sck_dcap().bits(RTC_CNTL_SCK_DCAP_DEFAULT) });
312
313 let slow_clk_conf = LPWR::regs().slow_clk_conf();
317 let new_value = slow_clk_conf.modify(|_, w| w.ana_clk_div_vld().clear_bit());
319 let new_value = slow_clk_conf.write(|w| unsafe {
321 w.bits(new_value);
322 w.ana_clk_div().bits(0)
323 });
324 slow_clk_conf.write(|w| {
326 unsafe { w.bits(new_value) };
327 w.ana_clk_div_vld().set_bit()
328 });
329}
330
331fn enable_rc_fast_div_clk_impl(_clocks: &mut ClockTree, en: bool) {
334 LPWR::regs()
335 .clk_conf()
336 .modify(|_, w| w.enb_ck8m_div().bit(!en));
337}
338
339fn enable_system_pre_div_in_impl(_clocks: &mut ClockTree, _en: bool) {
344 }
346
347fn configure_system_pre_div_in_impl(
348 _clocks: &mut ClockTree,
349 _old_config: Option<SystemPreDivInConfig>,
350 _new_config: SystemPreDivInConfig,
351) {
352 }
354
355fn enable_system_pre_div_impl(_clocks: &mut ClockTree, _en: bool) {
358 }
360
361fn configure_system_pre_div_impl(
362 _clocks: &mut ClockTree,
363 _old_config: Option<SystemPreDivConfig>,
364 new_config: SystemPreDivConfig,
365) {
366 SYSTEM::regs()
367 .sysclk_conf()
368 .modify(|_, w| unsafe { w.pre_div_cnt().bits(new_config.divisor() as u16 & 0x3FF) });
369}
370
371fn enable_cpu_pll_div_impl(_clocks: &mut ClockTree, _en: bool) {
374 }
376
377fn configure_cpu_pll_div_impl(
378 _clocks: &mut ClockTree,
379 _old_config: Option<CpuPllDivConfig>,
380 _new_config: CpuPllDivConfig,
381) {
382 }
384
385fn enable_apb_clk_impl(_clocks: &mut ClockTree, _en: bool) {
388 }
390
391fn configure_apb_clk_impl(
392 _clocks: &mut ClockTree,
393 _old_config: Option<ApbClkConfig>,
394 _new_config: ApbClkConfig,
395) {
396 }
398
399fn enable_crypto_clk_impl(_clocks: &mut ClockTree, _en: bool) {
402 }
404
405fn configure_crypto_clk_impl(
406 _clocks: &mut ClockTree,
407 _old_config: Option<CryptoClkConfig>,
408 _new_config: CryptoClkConfig,
409) {
410 }
412
413fn enable_mspi_clk_impl(_clocks: &mut ClockTree, _en: bool) {
416 }
418
419fn configure_mspi_clk_impl(
420 _clocks: &mut ClockTree,
421 _old_config: Option<MspiClkConfig>,
422 _new_config: MspiClkConfig,
423) {
424 }
426
427fn configure_cpu_clk_impl(
430 clocks: &mut ClockTree,
431 _old_config: Option<CpuClkConfig>,
432 new_config: CpuClkConfig,
433) {
434 if new_config == CpuClkConfig::Pll {
436 SYSTEM::regs().cpu_per_conf().modify(|_, w| unsafe {
437 w.cpuperiod_sel()
438 .bits(match unwrap!(clocks.cpu_pll_div).divisor {
439 CpuPllDivDivisor::_4 => 1,
440 CpuPllDivDivisor::_6 => 0,
441 })
442 });
443 }
444
445 SYSTEM::regs().sysclk_conf().modify(|_, w| unsafe {
446 w.soc_clk_sel().bits(match new_config {
447 CpuClkConfig::Xtal => 0,
448 CpuClkConfig::RcFast => 2,
449 CpuClkConfig::Pll => 1,
450 })
451 });
452
453 let apb_freq = Rate::from_hz(apb_clk_frequency());
454 update_apb_frequency(apb_freq);
455
456 let cpu_freq = Rate::from_hz(cpu_clk_frequency());
457 ets_update_cpu_frequency_rom(cpu_freq.as_mhz());
458}
459
460fn update_apb_frequency(freq: Rate) {
461 let freq_shifted = (freq.as_hz() >> 12) & 0xFFFF;
462 let value = freq_shifted | (freq_shifted << 16);
463 LPWR::regs()
464 .store5()
465 .modify(|_, w| unsafe { w.data().bits(value) });
466}
467
468fn enable_pll_40m_impl(_clocks: &mut ClockTree, _en: bool) {
471 }
473
474fn enable_pll_60m_impl(_clocks: &mut ClockTree, _en: bool) {
477 }
479
480fn enable_pll_80m_impl(_clocks: &mut ClockTree, _en: bool) {
483 }
485
486fn enable_cpu_div2_impl(_clocks: &mut ClockTree, _en: bool) {
489 }
491
492fn enable_rc_fast_clk_div_n_impl(_clocks: &mut ClockTree, _en: bool) {
495 }
497
498fn configure_rc_fast_clk_div_n_impl(
499 _clocks: &mut ClockTree,
500 _old_config: Option<RcFastClkDivNConfig>,
501 new_config: RcFastClkDivNConfig,
502) {
503 let clk_conf = LPWR::regs().clk_conf();
504 let new_value = clk_conf.modify(|_, w| w.ck8m_div_sel_vld().clear_bit());
506 let new_value = clk_conf.write(|w| unsafe {
508 w.bits(new_value);
509 w.ck8m_div_sel().bits(new_config.divisor() as u8)
510 });
511 clk_conf.write(|w| {
513 unsafe { w.bits(new_value) };
514 w.ck8m_div_sel_vld().set_bit()
515 });
516}
517
518fn enable_xtal_div_clk_impl(_clocks: &mut ClockTree, _en: bool) {
521 }
523
524fn enable_rtc_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {
527 }
529
530fn configure_rtc_slow_clk_impl(
531 _clocks: &mut ClockTree,
532 _old_config: Option<RtcSlowClkConfig>,
533 new_config: RtcSlowClkConfig,
534) {
535 LPWR::regs().clk_conf().modify(|_, w| unsafe {
536 w.ana_clk_rtc_sel().bits(match new_config {
538 RtcSlowClkConfig::OscSlow => 1,
539 RtcSlowClkConfig::RcSlow => 0,
540 RtcSlowClkConfig::RcFast => 2,
541 })
542 });
543
544 ets_delay_us(300);
545}
546
547fn enable_rtc_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {
550 }
552
553fn configure_rtc_fast_clk_impl(
554 _clocks: &mut ClockTree,
555 _old_config: Option<RtcFastClkConfig>,
556 new_config: RtcFastClkConfig,
557) {
558 LPWR::regs().clk_conf().modify(|_, w| match new_config {
560 RtcFastClkConfig::Xtal => w.fast_clk_rtc_sel().clear_bit(),
561 RtcFastClkConfig::Rc => w.fast_clk_rtc_sel().set_bit(),
562 });
563 ets_delay_us(3);
564}
565
566fn enable_low_power_clk_impl(_clocks: &mut ClockTree, _en: bool) {
569 }
574
575fn configure_low_power_clk_impl(
576 _clocks: &mut ClockTree,
577 _old_config: Option<LowPowerClkConfig>,
578 new_config: LowPowerClkConfig,
579) {
580 SYSTEM::regs().bt_lpck_div_frac().modify(|_, w| {
581 w.lpclk_sel_8m()
582 .bit(new_config == LowPowerClkConfig::RcFast);
583 w.lpclk_sel_rtc_slow()
584 .bit(new_config == LowPowerClkConfig::RtcSlow);
585 w.lpclk_sel_xtal()
586 .bit(new_config == LowPowerClkConfig::Xtal);
587 w.lpclk_sel_xtal32k()
588 .bit(new_config == LowPowerClkConfig::OscSlow)
589 });
590}
591
592fn enable_uart_mem_clk_impl(_clocks: &mut ClockTree, en: bool) {
595 let regs = SYSTEM::regs();
599
600 if en {
601 regs.perip_rst_en0()
602 .modify(|_, w| w.uart_mem_rst().bit(true));
603 regs.perip_rst_en0()
604 .modify(|_, w| w.uart_mem_rst().bit(false));
605 }
606
607 regs.perip_clk_en0()
608 .modify(|_, w| w.uart_mem_clk_en().bit(en));
609}
610
611fn enable_timg_calibration_clock_impl(_clocks: &mut ClockTree, _en: bool) {
614 }
617
618fn configure_timg_calibration_clock_impl(
619 _clocks: &mut ClockTree,
620 _old_config: Option<TimgCalibrationClockConfig>,
621 new_config: TimgCalibrationClockConfig,
622) {
623 TIMG0::regs().rtccalicfg().modify(|_, w| unsafe {
624 w.rtc_cali_clk_sel().bits(match new_config {
625 TimgCalibrationClockConfig::RcSlowClk => 0,
626 TimgCalibrationClockConfig::RcFastDivClk => 1,
627 TimgCalibrationClockConfig::Osc32kClk => 2,
628 })
629 });
630}
631
632impl TimgInstance {
633 fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
636 TIMG0::regs()
638 .regclk()
639 .modify(|_, w| w.timer_clk_is_active().bit(en));
640 }
641
642 fn configure_function_clock_impl(
643 self,
644 _clocks: &mut ClockTree,
645 _old_config: Option<TimgFunctionClockConfig>,
646 new_config: TimgFunctionClockConfig,
647 ) {
648 TIMG0::regs().t(0).config().modify(|_, w| {
649 w.use_xtal()
650 .bit(new_config == TimgFunctionClockConfig::XtalClk)
651 });
652 }
653
654 fn enable_wdt_clock_impl(self, _clocks: &mut ClockTree, _en: bool) {
657 }
659
660 fn configure_wdt_clock_impl(
661 self,
662 _clocks: &mut ClockTree,
663 _old_config: Option<TimgWdtClockConfig>,
664 new_config: TimgWdtClockConfig,
665 ) {
666 TIMG0::regs().wdtconfig0().modify(|_, w| {
667 w.wdt_use_xtal()
668 .bit(new_config == TimgWdtClockConfig::XtalClk)
669 });
670 }
671}