1#![allow(dead_code, reason = "Some of this is bound to be unused")]
14#![allow(missing_docs, reason = "Experimental")]
15
16use crate::{
17 peripherals::{I2C_ANA_MST, LP_CLKRST, MODEM_LPCON, PCR, PMU},
18 soc::{regi2c, xtal32k},
19};
20
21define_clock_tree_types!();
22
23#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26#[allow(
27 clippy::enum_variant_names,
28 reason = "MHz suffix indicates physical unit."
29)]
30#[non_exhaustive]
31pub enum CpuClock {
32 #[default]
34 _80MHz = 80,
35
36 _160MHz = 160,
38}
39
40impl CpuClock {
41 const PRESET_80: ClockConfig = ClockConfig {
42 xtal_clk: None,
43 hp_root_clk: Some(HpRootClkConfig::PllF160m),
44 cpu_clk: Some(CpuClkConfig::new(1)),
45 ahb_clk: Some(AhbClkConfig::new(3)),
46 apb_clk: Some(ApbClkConfig::new(0)),
47 lp_fast_clk: Some(LpFastClkConfig::RcFast),
48 lp_slow_clk: Some(xtal32k::default_lp_slow_clk()),
49 ble_lp_clk: Some(BleLpClkConfig::Xtal),
50 crypto_clk: Some(CryptoClkConfig::PllF480m),
51 timg_calibration_clock: None,
52 };
53 const PRESET_160: ClockConfig = ClockConfig {
54 xtal_clk: None,
55 hp_root_clk: Some(HpRootClkConfig::PllF160m),
56 cpu_clk: Some(CpuClkConfig::new(0)),
57 ahb_clk: Some(AhbClkConfig::new(3)),
58 apb_clk: Some(ApbClkConfig::new(0)),
59 lp_fast_clk: Some(LpFastClkConfig::RcFast),
60 lp_slow_clk: Some(xtal32k::default_lp_slow_clk()),
61 ble_lp_clk: Some(BleLpClkConfig::Xtal),
62 crypto_clk: Some(CryptoClkConfig::PllF480m),
63 timg_calibration_clock: None,
64 };
65}
66
67impl From<CpuClock> for ClockConfig {
68 fn from(value: CpuClock) -> ClockConfig {
69 match value {
70 CpuClock::_80MHz => CpuClock::PRESET_80,
71 CpuClock::_160MHz => CpuClock::PRESET_160,
72 }
73 }
74}
75
76impl Default for ClockConfig {
77 fn default() -> Self {
78 Self::from(CpuClock::default())
79 }
80}
81
82impl ClockConfig {
83 pub(crate) fn try_get_preset(self) -> Option<CpuClock> {
84 match self {
85 v if v == CpuClock::PRESET_80 => Some(CpuClock::_80MHz),
86 v if v == CpuClock::PRESET_160 => Some(CpuClock::_160MHz),
87 _ => None,
88 }
89 }
90
91 pub(crate) fn configure(mut self, clocks: &mut ClockTree) {
92 if self.xtal_clk.is_none() {
93 self.xtal_clk = Some(XtalClkConfig::_40);
94 }
95
96 self.apply(clocks);
97 }
98}
99
100fn configure_xtal_clk_impl(
103 _clocks: &mut ClockTree,
104 _old_config: Option<XtalClkConfig>,
105 _config: XtalClkConfig,
106) {
107 }
109
110pub(crate) fn reconfigure_pll(clocks: &mut ClockTree) {
115 if clocks.pll_clk_refcount > 0 {
116 enable_pll_clk_impl(clocks, true);
117 }
118}
119
120fn enable_pll_clk_impl(_clocks: &mut ClockTree, en: bool) {
121 if en {
122 PMU::regs().imm_hp_ck_power().write(|w| {
123 w.tie_high_xpd_bb_i2c().set_bit();
124 w.tie_high_xpd_bbpll().set_bit();
125 w.tie_high_xpd_bbpll_i2c().set_bit()
126 });
127 PMU::regs()
128 .imm_hp_ck_power()
129 .write(|w| w.tie_high_global_bbpll_icg().set_bit());
130 } else {
131 PMU::regs()
132 .imm_hp_ck_power()
133 .write(|w| w.tie_low_global_bbpll_icg().set_bit());
134 PMU::regs().imm_hp_ck_power().write(|w| {
135 w.tie_low_xpd_bb_i2c().set_bit();
136 w.tie_low_xpd_bbpll().set_bit();
137 w.tie_low_xpd_bbpll_i2c().set_bit()
138 });
139
140 return;
141 }
142
143 I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
147 w.bbpll_stop_force_high().clear_bit();
148 w.bbpll_stop_force_low().set_bit()
149 });
150
151 const DIV7_0: u8 = 8;
152 const DIV_REF: u8 = 0; const DCHGP: u8 = 5;
154 const DBIAS: u8 = 3;
155 const HREF: u8 = 3;
156 const LREF: u8 = 1;
157
158 const I2C_BBPLL_OC_DCHGP_LSB: u32 = 4;
159 const I2C_BBPLL_LREF: u8 = (DCHGP << I2C_BBPLL_OC_DCHGP_LSB) | DIV_REF;
163
164 regi2c::I2C_BBPLL_OC_REF.write_reg(I2C_BBPLL_LREF);
165 regi2c::I2C_BBPLL_OC_DIV_REG.write_reg(DIV7_0);
166 regi2c::I2C_BBPLL_OC_DLREF_SEL.write_field(LREF);
167 regi2c::I2C_BBPLL_OC_DHREF_SEL.write_field(HREF);
168 regi2c::I2C_BBPLL_OC_VCO_DBIAS.write_field(DBIAS);
169
170 while I2C_ANA_MST::regs()
172 .ana_conf0()
173 .read()
174 .cal_done()
175 .bit_is_clear()
176 {}
177 crate::rom::ets_delay_us(10);
178
179 I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
181 w.bbpll_stop_force_high().set_bit();
182 w.bbpll_stop_force_low().clear_bit()
183 });
184}
185
186fn enable_rc_fast_clk_impl(_clocks: &mut ClockTree, en: bool) {
189 LP_CLKRST::regs()
190 .clk_to_hp()
191 .modify(|_, w| w.icg_hp_fosc().bit(en));
192}
193
194#[cfg(use_xtal32k)]
197fn enable_xtal32k_clk_impl(_clocks: &mut ClockTree, en: bool) {
198 LP_CLKRST::regs()
199 .clk_to_hp()
200 .modify(|_, w| w.icg_hp_xtal32k().bit(en));
201}
202
203fn enable_osc_slow_clk_impl(_clocks: &mut ClockTree, en: bool) {
206 LP_CLKRST::regs()
207 .clk_to_hp()
208 .modify(|_, w| w.icg_hp_osc32k().bit(en));
209}
210
211fn enable_rc_slow_clk_impl(_clocks: &mut ClockTree, en: bool) {
214 LP_CLKRST::regs()
215 .clk_to_hp()
216 .modify(|_, w| w.icg_hp_sosc().bit(en));
217}
218
219fn enable_pll_f20m_impl(_clocks: &mut ClockTree, en: bool) {
222 PCR::regs()
223 .pll_div_clk_en()
224 .modify(|_, w| w.pll_20m_clk_en().bit(en));
225}
226
227fn enable_pll_f40m_impl(_clocks: &mut ClockTree, en: bool) {
230 PCR::regs()
231 .pll_div_clk_en()
232 .modify(|_, w| w.pll_40m_clk_en().bit(en));
233}
234
235fn enable_pll_f48m_impl(_clocks: &mut ClockTree, en: bool) {
238 PCR::regs()
239 .pll_div_clk_en()
240 .modify(|_, w| w.pll_48m_clk_en().bit(en));
241}
242
243fn enable_pll_f60m_impl(_clocks: &mut ClockTree, en: bool) {
246 PCR::regs()
247 .pll_div_clk_en()
248 .modify(|_, w| w.pll_60m_clk_en().bit(en));
249}
250
251fn enable_pll_f80m_impl(_clocks: &mut ClockTree, en: bool) {
254 PCR::regs()
255 .pll_div_clk_en()
256 .modify(|_, w| w.pll_80m_clk_en().bit(en));
257}
258
259fn enable_pll_f120m_impl(_clocks: &mut ClockTree, en: bool) {
262 PCR::regs()
263 .pll_div_clk_en()
264 .modify(|_, w| w.pll_120m_clk_en().bit(en));
265}
266
267fn enable_pll_f160m_impl(_clocks: &mut ClockTree, en: bool) {
270 PCR::regs()
271 .pll_div_clk_en()
272 .modify(|_, w| w.pll_160m_clk_en().bit(en));
273}
274
275fn enable_hp_root_clk_impl(_clocks: &mut ClockTree, _en: bool) {
278 }
280
281fn configure_hp_root_clk_impl(
282 _clocks: &mut ClockTree,
283 _old_config: Option<HpRootClkConfig>,
284 new_config: HpRootClkConfig,
285) {
286 PCR::regs().sysclk_conf().modify(|_, w| unsafe {
289 w.soc_clk_sel().bits(match new_config {
290 HpRootClkConfig::Xtal => 0,
291 HpRootClkConfig::RcFast => 1,
292 HpRootClkConfig::PllF160m => 2,
293 })
294 });
295
296 bus_clock_update();
297}
298
299fn bus_clock_update() {
301 PCR::regs()
302 .bus_clk_update()
303 .write(|w| w.bus_clock_update().set_bit());
304 while PCR::regs()
305 .bus_clk_update()
306 .read()
307 .bus_clock_update()
308 .bit_is_set()
309 {}
310}
311
312fn enable_cpu_clk_impl(_clocks: &mut ClockTree, _en: bool) {
315 }
317
318fn configure_cpu_clk_impl(
319 _clocks: &mut ClockTree,
320 _old_config: Option<CpuClkConfig>,
321 new_config: CpuClkConfig,
322) {
323 PCR::regs()
324 .cpu_freq_conf()
325 .modify(|_, w| unsafe { w.cpu_div_num().bits(new_config.divisor() as u8) });
326
327 bus_clock_update();
328}
329
330fn enable_ahb_clk_impl(_clocks: &mut ClockTree, _en: bool) {
333 }
335
336fn configure_ahb_clk_impl(
337 _clocks: &mut ClockTree,
338 _old_config: Option<AhbClkConfig>,
339 new_config: AhbClkConfig,
340) {
341 PCR::regs()
342 .ahb_freq_conf()
343 .modify(|_, w| unsafe { w.ahb_div_num().bits(new_config.divisor() as u8) });
344
345 bus_clock_update();
346}
347
348fn enable_apb_clk_impl(_clocks: &mut ClockTree, _en: bool) {
351 }
353
354fn configure_apb_clk_impl(
355 _clocks: &mut ClockTree,
356 _old_config: Option<ApbClkConfig>,
357 new_config: ApbClkConfig,
358) {
359 PCR::regs()
360 .apb_freq_conf()
361 .modify(|_, w| unsafe { w.apb_div_num().bits(new_config.divisor() as u8) });
362}
363
364fn enable_xtal_d2_clk_impl(_clocks: &mut ClockTree, _en: bool) {
367 }
369
370fn enable_lp_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {
373 }
375
376fn configure_lp_fast_clk_impl(
377 _clocks: &mut ClockTree,
378 _old_config: Option<LpFastClkConfig>,
379 new_config: LpFastClkConfig,
380) {
381 LP_CLKRST::regs().lp_clk_conf().modify(|_, w| unsafe {
382 w.fast_clk_sel().bits(match new_config {
383 LpFastClkConfig::RcFast => 0,
384 LpFastClkConfig::XtalD2 => 1,
385 LpFastClkConfig::Xtal => 2,
386 })
387 });
388}
389
390fn enable_lp_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {
393 }
395
396fn configure_lp_slow_clk_impl(
397 _clocks: &mut ClockTree,
398 _old_config: Option<LpSlowClkConfig>,
399 new_config: LpSlowClkConfig,
400) {
401 LP_CLKRST::regs().lp_clk_conf().modify(|_, w| unsafe {
402 w.slow_clk_sel().bits(match new_config {
403 LpSlowClkConfig::RcSlow => 0,
404 #[cfg(use_xtal32k)]
405 LpSlowClkConfig::Xtal32k => 1,
406 LpSlowClkConfig::OscSlow => 3,
408 })
409 });
410}
411
412fn enable_crypto_pll_div_impl(_clocks: &mut ClockTree, _en: bool) {
415 }
417
418fn enable_crypto_clk_impl(_clocks: &mut ClockTree, _en: bool) {
421 }
423
424fn configure_crypto_clk_impl(
425 _clocks: &mut ClockTree,
426 _old_config: Option<CryptoClkConfig>,
427 new_config: CryptoClkConfig,
428) {
429 PCR::regs().sec_conf().modify(|_, w| unsafe {
430 w.sec_clk_sel().bits(match new_config {
431 CryptoClkConfig::Xtal => 0,
432 CryptoClkConfig::RcFast => 1,
433 CryptoClkConfig::PllF480m => 2,
434 })
435 });
436}
437
438fn enable_timg_calibration_clock_impl(_clocks: &mut ClockTree, _en: bool) {
441 }
443
444fn configure_timg_calibration_clock_impl(
445 _clocks: &mut ClockTree,
446 _old_config: Option<TimgCalibrationClockConfig>,
447 new_config: TimgCalibrationClockConfig,
448) {
449 PCR::regs().ctrl_32k_conf().modify(|_, w| unsafe {
450 w._32k_sel().bits(match new_config {
451 TimgCalibrationClockConfig::OscSlowClk => 0,
452 #[cfg(use_xtal32k)]
453 TimgCalibrationClockConfig::Xtal32kClk => 1,
454 TimgCalibrationClockConfig::RcSlowClk => 3,
456 TimgCalibrationClockConfig::RcFastDivClk => 4,
457 })
458 });
459}
460
461impl AdcInstance {
462 fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
465 PCR::regs()
466 .saradc_clkm_conf()
467 .modify(|_, w| w.saradc_clkm_en().bit(en));
468 }
469
470 fn configure_function_clock_impl(
471 self,
472 _clocks: &mut ClockTree,
473 _old_config: Option<AdcFunctionClockConfig>,
474 new_config: AdcFunctionClockConfig,
475 ) {
476 PCR::regs().saradc_clkm_conf().modify(|_, w| unsafe {
477 w.saradc_clkm_sel().bits(match new_config {
478 AdcFunctionClockConfig::Xtal => 0,
479 AdcFunctionClockConfig::RcFast => 1,
480 AdcFunctionClockConfig::PllF80m => 2,
481 })
482 });
483 }
484}
485
486impl TimgInstance {
487 fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
492 let timg = match self {
493 TimgInstance::Timg0 => 0,
494 TimgInstance::Timg1 => 1,
495 };
496 PCR::regs()
497 .timergroup(timg)
498 .timer_clk_conf()
499 .modify(|_, w| w.timer_clk_en().bit(en));
500 }
501
502 fn configure_function_clock_impl(
503 self,
504 _clocks: &mut ClockTree,
505 _old_config: Option<TimgFunctionClockConfig>,
506 new_config: TimgFunctionClockConfig,
507 ) {
508 let timg = match self {
510 TimgInstance::Timg0 => 0,
511 TimgInstance::Timg1 => 1,
512 };
513 PCR::regs()
514 .timergroup(timg)
515 .timer_clk_conf()
516 .modify(|_, w| unsafe {
517 w.timer_clk_sel().bits(match new_config {
518 TimgFunctionClockConfig::XtalClk => 0,
519 TimgFunctionClockConfig::RcFastClk => 1,
520 TimgFunctionClockConfig::PllF80m => 2,
521 })
522 });
523 }
524
525 fn enable_wdt_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
528 let timg = match self {
529 TimgInstance::Timg0 => 0,
530 TimgInstance::Timg1 => 1,
531 };
532 PCR::regs()
533 .timergroup(timg)
534 .wdt_clk_conf()
535 .modify(|_, w| w.wdt_clk_en().bit(en));
536 }
537
538 fn configure_wdt_clock_impl(
539 self,
540 _clocks: &mut ClockTree,
541 _old_config: Option<TimgWdtClockConfig>,
542 new_config: TimgWdtClockConfig,
543 ) {
544 let timg = match self {
545 TimgInstance::Timg0 => 0,
546 TimgInstance::Timg1 => 1,
547 };
548 PCR::regs()
549 .timergroup(timg)
550 .wdt_clk_conf()
551 .modify(|_, w| unsafe {
552 w.wdt_clk_sel().bits(match new_config {
553 TimgWdtClockConfig::XtalClk => 0,
554 TimgWdtClockConfig::RcFastClk => 1,
555 TimgWdtClockConfig::PllF80m => 2,
556 })
557 });
558 }
559}
560
561fn enable_ble_lp_xtal_clk_impl(_clocks: &mut ClockTree, _en: bool) {
564 }
566
567fn enable_ble_lp_rc_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {
570 }
573
574fn enable_ble_lp_clk_impl(_clocks: &mut ClockTree, en: bool) {
577 MODEM_LPCON::regs()
578 .clk_conf()
579 .modify(|_, w| w.clk_lp_timer_en().bit(en));
580}
581
582fn configure_ble_lp_clk_impl(
583 _clocks: &mut ClockTree,
584 _old_config: Option<BleLpClkConfig>,
585 new_config: BleLpClkConfig,
586) {
587 let divisor = match new_config {
588 BleLpClkConfig::Xtal => xtal_clk_frequency() / ble_lp_xtal_clk_frequency() - 1,
589 BleLpClkConfig::RcSlow => rc_slow_clk_frequency() / ble_lp_rc_slow_clk_frequency() - 1,
591 #[cfg(use_xtal32k)]
592 BleLpClkConfig::Xtal32k => 0,
593 };
594 let sel_xtal32k = cfg_select! {
595 use_xtal32k => new_config == BleLpClkConfig::Xtal32k,
596 _ => false,
597 };
598
599 MODEM_LPCON::regs()
600 .test_conf()
601 .modify(|_, w| w.clk_en().set_bit());
602
603 MODEM_LPCON::regs().lp_timer_conf().modify(|_, w| unsafe {
604 w.clk_lp_timer_sel_osc_slow()
605 .bit(new_config == BleLpClkConfig::RcSlow);
606 w.clk_lp_timer_sel_osc_fast().clear_bit();
607 w.clk_lp_timer_sel_xtal()
608 .bit(new_config == BleLpClkConfig::Xtal);
609 w.clk_lp_timer_sel_xtal32k().bit(sel_xtal32k);
610 w.clk_lp_timer_div_num().bits(divisor as u16)
611 });
612
613 if sel_xtal32k {
614 MODEM_LPCON::regs()
616 .modem_32k_clk_conf()
617 .modify(|_, w| unsafe { w.clk_modem_32k_sel().bits(0) });
618 }
619}