1#![allow(dead_code, reason = "Some of this is bound to be unused")]
13#![allow(missing_docs, reason = "Experimental")]
14
15use esp_rom_sys::rom::{ets_delay_us, ets_update_cpu_frequency_rom};
18
19use crate::{
20 peripherals::{APB_CTRL, I2C_ANA_MST, LPWR, SYSTEM, TIMG0, TIMG1},
21 soc::regi2c,
22 time::Rate,
23};
24
25define_clock_tree_types!();
26
27#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30#[allow(
31 clippy::enum_variant_names,
32 reason = "MHz suffix indicates physical unit."
33)]
34#[non_exhaustive]
35pub enum CpuClock {
36 #[default]
38 _80MHz = 80,
39
40 _160MHz = 160,
42}
43
44impl CpuClock {
45 const PRESET_80: ClockConfig = ClockConfig {
48 xtal_clk: None,
49 system_pre_div: None,
50 pll_clk: Some(PllClkConfig::_480),
51 cpu_pll_div_out: Some(CpuPllDivOutConfig::_80),
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_160: ClockConfig = ClockConfig {
60 xtal_clk: None,
61 system_pre_div: None,
62 pll_clk: Some(PllClkConfig::_480),
63 cpu_pll_div_out: Some(CpuPllDivOutConfig::_160),
64 cpu_clk: Some(CpuClkConfig::Pll),
65 rc_fast_clk_div_n: Some(RcFastClkDivNConfig::new(0)),
66 rtc_slow_clk: Some(RtcSlowClkConfig::RcSlow),
67 rtc_fast_clk: Some(RtcFastClkConfig::Rc),
68 low_power_clk: Some(LowPowerClkConfig::RtcSlow),
69 timg_calibration_clock: None,
70 };
71}
72
73impl From<CpuClock> for ClockConfig {
74 fn from(value: CpuClock) -> ClockConfig {
75 match value {
76 CpuClock::_80MHz => CpuClock::PRESET_80,
77 CpuClock::_160MHz => CpuClock::PRESET_160,
78 }
79 }
80}
81
82impl Default for ClockConfig {
83 fn default() -> Self {
84 Self::from(CpuClock::default())
85 }
86}
87
88impl ClockConfig {
89 pub(crate) fn try_get_preset(self) -> Option<CpuClock> {
90 match self {
91 v if v == CpuClock::PRESET_80 => Some(CpuClock::_80MHz),
92 v if v == CpuClock::PRESET_160 => Some(CpuClock::_160MHz),
93 _ => None,
94 }
95 }
96
97 pub(crate) fn configure(mut self, clocks: &mut ClockTree) {
98 if self.xtal_clk.is_none() {
99 self.xtal_clk = Some(XtalClkConfig::_40);
101 }
102
103 configure_xtal_clk(clocks, XtalClkConfig::_40);
105 configure_system_pre_div(clocks, SystemPreDivConfig::new(0));
106 configure_cpu_clk(clocks, CpuClkConfig::Xtal);
107
108 self.apply(clocks);
109 }
110}
111
112fn configure_xtal_clk_impl(
115 _clocks: &mut ClockTree,
116 _old_config: Option<XtalClkConfig>,
117 _config: XtalClkConfig,
118) {
119 }
121
122fn enable_pll_clk_impl(clocks: &mut ClockTree, en: bool) {
125 I2C_ANA_MST::regs()
127 .ana_config()
128 .modify(|_, w| w.bbpll_pd().bit(!en));
129
130 LPWR::regs().options0().modify(|_, w| {
131 let power_down = !en;
132 w.bb_i2c_force_pd().bit(power_down);
133 w.bbpll_force_pd().bit(power_down);
134 w.bbpll_i2c_force_pd().bit(power_down)
135 });
136
137 if !en {
138 return;
139 }
140
141 let pll_freq = unwrap!(clocks.pll_clk);
143 let xtal_freq = unwrap!(clocks.xtal_clk);
144 SYSTEM::regs()
145 .cpu_per_conf()
146 .modify(|_, w| w.pll_freq_sel().bit(pll_freq == PllClkConfig::_480));
147
148 I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
152 w.bbpll_stop_force_high().clear_bit();
153 w.bbpll_stop_force_low().set_bit()
154 });
155
156 let div_ref: u8;
157 let div7_0: u8;
158 let dr1: u8;
159 let dr3: u8;
160 let dchgp: u8;
161 let dcur: u8;
162 let dbias: u8;
163 match pll_freq {
164 PllClkConfig::_480 => {
165 match xtal_freq {
167 XtalClkConfig::_40 => {
168 div_ref = 0;
169 div7_0 = 8;
171 dr1 = 0;
172 dr3 = 0;
173 dchgp = 5;
174 dcur = 3;
175 dbias = 2;
176 }
177 }
178
179 regi2c::I2C_BBPLL_REG4.write_reg(0x6b);
181 }
182 PllClkConfig::_320 => {
183 match xtal_freq {
185 XtalClkConfig::_40 => {
186 div_ref = 0;
187 div7_0 = 4;
189 dr1 = 0;
190 dr3 = 0;
191 dchgp = 5;
192 dcur = 3;
193 dbias = 2;
194 }
195 }
196
197 regi2c::I2C_BBPLL_REG4.write_reg(0x69);
199 }
200 }
201
202 const I2C_BBPLL_OC_DCHGP_LSB: u32 = 4;
203 const I2C_BBPLL_OC_DLREF_SEL_LSB: u32 = 6;
204 const I2C_BBPLL_OC_DHREF_SEL_LSB: u32 = 4;
205
206 let i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | div_ref;
207
208 let i2c_bbpll_dcur =
210 (2 << I2C_BBPLL_OC_DLREF_SEL_LSB) | (1 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
211
212 regi2c::I2C_BBPLL_OC_REF.write_reg(i2c_bbpll_lref);
213 regi2c::I2C_BBPLL_OC_DIV_REG.write_reg(div7_0);
214 regi2c::I2C_BBPLL_OC_DR1.write_field(dr1);
215 regi2c::I2C_BBPLL_OC_DR3.write_field(dr3);
216 regi2c::I2C_BBPLL_REG6.write_reg(i2c_bbpll_dcur);
217 regi2c::I2C_BBPLL_OC_VCO_DBIAS.write_field(dbias);
218 regi2c::I2C_BBPLL_OC_DHREF_SEL.write_field(2);
219 regi2c::I2C_BBPLL_OC_DLREF_SEL.write_field(1);
220}
221
222fn configure_pll_clk_impl(
223 _clocks: &mut ClockTree,
224 _old_config: Option<PllClkConfig>,
225 _config: PllClkConfig,
226) {
227 }
230
231fn enable_rc_fast_clk_impl(_clocks: &mut ClockTree, en: bool) {
234 const RTC_CNTL_FOSC_DFREQ_DEFAULT: u8 = 172;
236 LPWR::regs().clk_conf().modify(|_, w| {
237 unsafe { w.ck8m_dfreq().bits(RTC_CNTL_FOSC_DFREQ_DEFAULT) };
241
242 w.enb_ck8m().bit(!en);
243 w.dig_clk8m_en().bit(en); w.ck8m_force_pd().clear_bit();
246 w.ck8m_force_pu().clear_bit()
247 });
248 LPWR::regs()
249 .timer1()
250 .modify(|_, w| unsafe { w.ck8m_wait().bits(if en { 5 } else { 20 }) });
251}
252
253#[cfg(use_xtal32k)]
256fn enable_xtal32k_clk_impl(_clocks: &mut ClockTree, en: bool) {
257 const CLK_LL_XTAL_32K_DAC_VAL: u8 = 3;
261 const CLK_LL_XTAL_32K_DRES_VAL: u8 = 3;
262 const CLK_LL_XTAL_32K_DGM_VAL: u8 = 3;
263 const CLK_LL_XTAL_32K_DBUF_VAL: bool = true; LPWR::regs().ext_xtl_conf().modify(|_, w| unsafe {
265 w.xtal32k_gpio_sel().bit(false);
266
267 w.dac_xtal_32k().bits(CLK_LL_XTAL_32K_DAC_VAL);
268 w.dres_xtal_32k().bits(CLK_LL_XTAL_32K_DRES_VAL);
269 w.dgm_xtal_32k().bits(CLK_LL_XTAL_32K_DGM_VAL);
270 w.dbuf_xtal_32k().bit(CLK_LL_XTAL_32K_DBUF_VAL);
271
272 w.xpd_xtal_32k().bit(en)
273 });
274
275 LPWR::regs()
277 .clk_conf()
278 .modify(|_, w| w.dig_xtal32k_en().bit(en));
279}
280
281fn enable_rc_slow_clk_impl(_clocks: &mut ClockTree, en: bool) {
284 if en {
285 const RTC_CNTL_SCK_DCAP_DEFAULT: u8 = 255;
288 LPWR::regs()
289 .rtc_cntl()
290 .modify(|_, w| unsafe { w.sck_dcap().bits(RTC_CNTL_SCK_DCAP_DEFAULT) });
291
292 let slow_clk_conf = LPWR::regs().slow_clk_conf();
296 let new_value = slow_clk_conf.modify(|_, w| w.ana_clk_div_vld().clear_bit());
298 let new_value = slow_clk_conf.write(|w| unsafe {
300 w.bits(new_value);
301 w.ana_clk_div().bits(0)
302 });
303 slow_clk_conf.write(|w| {
305 unsafe { w.bits(new_value) };
306 w.ana_clk_div_vld().set_bit()
307 });
308 }
309}
310
311fn enable_rc_fast_div_clk_impl(_clocks: &mut ClockTree, en: bool) {
314 LPWR::regs()
315 .clk_conf()
316 .modify(|_, w| w.enb_ck8m_div().bit(!en));
317}
318
319fn enable_system_pre_div_in_impl(_clocks: &mut ClockTree, _en: bool) {
322 }
324
325fn configure_system_pre_div_in_impl(
326 _clocks: &mut ClockTree,
327 _old_config: Option<SystemPreDivInConfig>,
328 _new_config: SystemPreDivInConfig,
329) {
330 }
332
333fn enable_system_pre_div_impl(_clocks: &mut ClockTree, _en: bool) {
336 }
338
339fn configure_system_pre_div_impl(
340 _clocks: &mut ClockTree,
341 _old_config: Option<SystemPreDivConfig>,
342 new_config: SystemPreDivConfig,
343) {
344 APB_CTRL::regs()
345 .sysclk_conf()
346 .modify(|_, w| unsafe { w.pre_div_cnt().bits(new_config.divisor() as u16 & 0x3FF) });
347}
348
349fn enable_cpu_pll_div_out_impl(_clocks: &mut ClockTree, _en: bool) {
352 }
354
355fn configure_cpu_pll_div_out_impl(
356 _clocks: &mut ClockTree,
357 _old_config: Option<CpuPllDivOutConfig>,
358 _config: CpuPllDivOutConfig,
359) {
360 }
362
363fn enable_apb_clk_impl(_clocks: &mut ClockTree, _en: bool) {
366 }
368
369fn configure_apb_clk_impl(
370 _clocks: &mut ClockTree,
371 _old_config: Option<ApbClkConfig>,
372 _new_config: ApbClkConfig,
373) {
374 }
376
377fn enable_crypto_clk_impl(_clocks: &mut ClockTree, _en: bool) {
380 }
382
383fn configure_crypto_clk_impl(
384 _clocks: &mut ClockTree,
385 _old_config: Option<CryptoClkConfig>,
386 _new_config: CryptoClkConfig,
387) {
388 }
390
391fn configure_cpu_clk_impl(
394 clocks: &mut ClockTree,
395 _old_config: Option<CpuClkConfig>,
396 new_config: CpuClkConfig,
397) {
398 if new_config == CpuClkConfig::Pll {
400 SYSTEM::regs().cpu_per_conf().modify(|_, w| unsafe {
401 w.cpuperiod_sel()
402 .bits(match unwrap!(clocks.cpu_pll_div_out) {
403 CpuPllDivOutConfig::_80 => 0,
404 CpuPllDivOutConfig::_160 => 1,
405 })
406 });
407 }
408
409 SYSTEM::regs().sysclk_conf().modify(|_, w| unsafe {
410 w.pre_div_cnt().bits(0);
411 w.soc_clk_sel().bits(match new_config {
412 CpuClkConfig::Xtal => 0,
413 CpuClkConfig::RcFast => 2,
414 CpuClkConfig::Pll => 1,
415 })
416 });
417
418 let apb_freq = Rate::from_hz(apb_clk_frequency());
419 update_apb_frequency(apb_freq);
420
421 let cpu_freq = Rate::from_hz(cpu_clk_frequency());
422 ets_update_cpu_frequency_rom(cpu_freq.as_mhz());
423}
424
425fn update_apb_frequency(freq: Rate) {
426 let freq_shifted = (freq.as_hz() >> 12) & 0xFFFF;
427 let value = freq_shifted | (freq_shifted << 16);
428 LPWR::regs()
429 .store5()
430 .modify(|_, w| unsafe { w.data().bits(value) });
431}
432
433fn enable_pll_80m_impl(_clocks: &mut ClockTree, _en: bool) {
436 }
438
439fn enable_pll_160m_impl(_clocks: &mut ClockTree, _en: bool) {
442 }
444
445fn enable_rc_fast_clk_div_n_impl(_clocks: &mut ClockTree, _en: bool) {
448 }
450
451fn configure_rc_fast_clk_div_n_impl(
452 _clocks: &mut ClockTree,
453 _old_config: Option<RcFastClkDivNConfig>,
454 new_config: RcFastClkDivNConfig,
455) {
456 let clk_conf = LPWR::regs().clk_conf();
457 let new_value = clk_conf.modify(|_, w| w.ck8m_div_sel_vld().clear_bit());
459 let new_value = clk_conf.write(|w| unsafe {
461 w.bits(new_value);
462 w.ck8m_div_sel().bits(new_config.divisor() as u8)
463 });
464 clk_conf.write(|w| {
466 unsafe { w.bits(new_value) };
467 w.ck8m_div_sel_vld().set_bit()
468 });
469}
470
471fn enable_xtal_div_clk_impl(_clocks: &mut ClockTree, _en: bool) {
474 }
476
477fn enable_rtc_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {
480 }
482
483fn configure_rtc_slow_clk_impl(
484 _clocks: &mut ClockTree,
485 _old_config: Option<RtcSlowClkConfig>,
486 new_config: RtcSlowClkConfig,
487) {
488 LPWR::regs().clk_conf().modify(|_, w| unsafe {
489 w.ana_clk_rtc_sel().bits(match new_config {
491 #[cfg(use_xtal32k)]
492 RtcSlowClkConfig::Xtal32k => 1,
493 RtcSlowClkConfig::RcSlow => 0,
494 RtcSlowClkConfig::RcFast => 2,
495 })
496 });
497 ets_delay_us(300);
498}
499
500fn enable_rtc_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {
503 }
505
506fn configure_rtc_fast_clk_impl(
507 _clocks: &mut ClockTree,
508 _old_config: Option<RtcFastClkConfig>,
509 new_config: RtcFastClkConfig,
510) {
511 LPWR::regs().clk_conf().modify(|_, w| match new_config {
513 RtcFastClkConfig::Xtal => w.fast_clk_rtc_sel().clear_bit(),
514 RtcFastClkConfig::Rc => w.fast_clk_rtc_sel().set_bit(),
515 });
516 ets_delay_us(3);
517}
518
519fn enable_low_power_clk_impl(_clocks: &mut ClockTree, _en: bool) {
522 }
527
528fn configure_low_power_clk_impl(
529 _clocks: &mut ClockTree,
530 _old_config: Option<LowPowerClkConfig>,
531 new_config: LowPowerClkConfig,
532) {
533 SYSTEM::regs().bt_lpck_div_frac().modify(|_, w| {
534 w.lpclk_sel_8m()
535 .bit(new_config == LowPowerClkConfig::RcFast);
536 w.lpclk_sel_rtc_slow()
537 .bit(new_config == LowPowerClkConfig::RtcSlow);
538 w.lpclk_sel_xtal()
539 .bit(new_config == LowPowerClkConfig::Xtal);
540 w.lpclk_sel_xtal32k().bit({
541 cfg_select! {
542 use_xtal32k => new_config == LowPowerClkConfig::Xtal32k,
543 _ => false,
544 }
545 })
546 });
547}
548
549fn enable_uart_mem_clk_impl(_clocks: &mut ClockTree, en: bool) {
552 let regs = SYSTEM::regs();
556
557 if en {
558 regs.perip_rst_en0()
559 .modify(|_, w| w.uart_mem_rst().bit(true));
560 regs.perip_rst_en0()
561 .modify(|_, w| w.uart_mem_rst().bit(false));
562 }
563
564 regs.perip_clk_en0()
565 .modify(|_, w| w.uart_mem_clk_en().bit(en));
566}
567
568fn enable_timg_calibration_clock_impl(_clocks: &mut ClockTree, _en: bool) {
571 }
574
575fn configure_timg_calibration_clock_impl(
576 _clocks: &mut ClockTree,
577 _old_config: Option<TimgCalibrationClockConfig>,
578 new_config: TimgCalibrationClockConfig,
579) {
580 TIMG0::regs().rtccalicfg().modify(|_, w| unsafe {
581 w.rtc_cali_clk_sel().bits(match new_config {
582 TimgCalibrationClockConfig::RcSlowClk => 0,
583 TimgCalibrationClockConfig::RcFastDivClk => 1,
584 #[cfg(use_xtal32k)]
585 TimgCalibrationClockConfig::Xtal32kClk => 2,
586 })
587 });
588}
589
590impl SdmInstance {
591 fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
594 crate::peripherals::GPIO_SD::regs()
595 .sigmadelta_misc()
596 .modify(|_, w| w.function_clk_en().bit(en));
597 }
598}
599impl RmtInstance {
600 fn enable_sclk_impl(self, _clocks: &mut ClockTree, en: bool) {
603 crate::peripherals::RMT::regs()
604 .sys_conf()
605 .modify(|_, w| w.sclk_active().bit(en));
606 }
607
608 fn configure_sclk_impl(
609 self,
610 _clocks: &mut ClockTree,
611 _old_config: Option<RmtSclkConfig>,
612 new_config: RmtSclkConfig,
613 ) {
614 crate::peripherals::RMT::regs()
615 .sys_conf()
616 .modify(|_, w| unsafe {
617 w.clk_en().clear_bit();
618 w.sclk_sel().bits(match new_config {
619 RmtSclkConfig::ApbClk => 1,
620 RmtSclkConfig::RcFastClk => 2,
621 RmtSclkConfig::XtalClk => 3,
622 })
623 });
624 }
625}
626
627impl TimgInstance {
628 fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
633 let regs = match self {
634 TimgInstance::Timg0 => TIMG0::regs(),
635 TimgInstance::Timg1 => TIMG1::regs(),
636 };
637 regs.regclk().modify(|_, w| {
638 w.timer_clk_is_active().bit(en);
639 w.clk_en().bit(en)
640 });
641 }
642
643 fn configure_function_clock_impl(
644 self,
645 _clocks: &mut ClockTree,
646 _old_config: Option<TimgFunctionClockConfig>,
647 new_config: TimgFunctionClockConfig,
648 ) {
649 let regs = match self {
650 TimgInstance::Timg0 => TIMG0::regs(),
651 TimgInstance::Timg1 => TIMG1::regs(),
652 };
653 regs.t(0).config().modify(|_, w| {
654 w.use_xtal()
655 .bit(new_config == TimgFunctionClockConfig::XtalClk)
656 });
657 }
658
659 fn enable_wdt_clock_impl(self, _clocks: &mut ClockTree, _en: bool) {
662 }
664
665 fn configure_wdt_clock_impl(
666 self,
667 _clocks: &mut ClockTree,
668 _old_config: Option<TimgWdtClockConfig>,
669 new_config: TimgWdtClockConfig,
670 ) {
671 let regs = match self {
672 TimgInstance::Timg0 => TIMG0::regs(),
673 TimgInstance::Timg1 => TIMG1::regs(),
674 };
675 regs.wdtconfig0().modify(|_, w| {
676 w.wdt_use_xtal()
677 .bit(new_config == TimgWdtClockConfig::XtalClk)
678 });
679 }
680}