1use strum::FromRepr;
2
3use crate::{
4 clock::{clocks_ll::regi2c_write_mask, Clock, XtalClock},
5 peripherals::{LPWR, LP_AON, PCR, PMU, TIMG0},
6 rtc_cntl::RtcClock,
7 time::Rate,
8};
9
10const I2C_PMU: u8 = 0x6d;
11const I2C_PMU_HOSTID: u8 = 0;
12
13const I2C_PMU_EN_I2C_RTC_DREG: u8 = 8;
14const I2C_PMU_EN_I2C_RTC_DREG_MSB: u8 = 0;
15const I2C_PMU_EN_I2C_RTC_DREG_LSB: u8 = 0;
16
17const I2C_PMU_EN_I2C_DIG_DREG: u8 = 8;
18const I2C_PMU_EN_I2C_DIG_DREG_MSB: u8 = 1;
19const I2C_PMU_EN_I2C_DIG_DREG_LSB: u8 = 1;
20
21const I2C_PMU_EN_I2C_RTC_DREG_SLP: u8 = 8;
22const I2C_PMU_EN_I2C_RTC_DREG_SLP_MSB: u8 = 2;
23const I2C_PMU_EN_I2C_RTC_DREG_SLP_LSB: u8 = 2;
24
25const I2C_PMU_EN_I2C_DIG_DREG_SLP: u8 = 8;
26const I2C_PMU_EN_I2C_DIG_DREG_SLP_MSB: u8 = 3;
27const I2C_PMU_EN_I2C_DIG_DREG_SLP_LSB: u8 = 3;
28
29const I2C_PMU_OR_XPD_RTC_REG: u8 = 8;
30const I2C_PMU_OR_XPD_RTC_REG_MSB: u8 = 4;
31const I2C_PMU_OR_XPD_RTC_REG_LSB: u8 = 4;
32
33const I2C_PMU_OR_XPD_DIG_REG: u8 = 8;
34const I2C_PMU_OR_XPD_DIG_REG_MSB: u8 = 5;
35const I2C_PMU_OR_XPD_DIG_REG_LSB: u8 = 5;
36
37const I2C_PMU_OR_XPD_TRX: u8 = 15;
38const I2C_PMU_OR_XPD_TRX_MSB: u8 = 2;
39const I2C_PMU_OR_XPD_TRX_LSB: u8 = 2;
40
41pub(crate) fn init() {
42 unsafe {
44 regi2c_write_mask(
45 I2C_PMU,
46 I2C_PMU_HOSTID,
47 I2C_PMU_EN_I2C_RTC_DREG,
48 I2C_PMU_EN_I2C_RTC_DREG_MSB,
49 I2C_PMU_EN_I2C_RTC_DREG_LSB,
50 0,
51 );
52 regi2c_write_mask(
53 I2C_PMU,
54 I2C_PMU_HOSTID,
55 I2C_PMU_EN_I2C_DIG_DREG,
56 I2C_PMU_EN_I2C_DIG_DREG_MSB,
57 I2C_PMU_EN_I2C_DIG_DREG_LSB,
58 0,
59 );
60 regi2c_write_mask(
61 I2C_PMU,
62 I2C_PMU_HOSTID,
63 I2C_PMU_EN_I2C_RTC_DREG_SLP,
64 I2C_PMU_EN_I2C_RTC_DREG_SLP_MSB,
65 I2C_PMU_EN_I2C_RTC_DREG_SLP_LSB,
66 0,
67 );
68 regi2c_write_mask(
69 I2C_PMU,
70 I2C_PMU_HOSTID,
71 I2C_PMU_EN_I2C_DIG_DREG_SLP,
72 I2C_PMU_EN_I2C_DIG_DREG_SLP_MSB,
73 I2C_PMU_EN_I2C_DIG_DREG_SLP_LSB,
74 0,
75 );
76 regi2c_write_mask(
77 I2C_PMU,
78 I2C_PMU_HOSTID,
79 I2C_PMU_OR_XPD_RTC_REG,
80 I2C_PMU_OR_XPD_RTC_REG_MSB,
81 I2C_PMU_OR_XPD_RTC_REG_LSB,
82 0,
83 );
84 regi2c_write_mask(
85 I2C_PMU,
86 I2C_PMU_HOSTID,
87 I2C_PMU_OR_XPD_DIG_REG,
88 I2C_PMU_OR_XPD_DIG_REG_MSB,
89 I2C_PMU_OR_XPD_DIG_REG_LSB,
90 0,
91 );
92 regi2c_write_mask(
93 I2C_PMU,
94 I2C_PMU_HOSTID,
95 I2C_PMU_OR_XPD_TRX,
96 I2C_PMU_OR_XPD_TRX_MSB,
97 I2C_PMU_OR_XPD_TRX_LSB,
98 0,
99 );
100
101 let pmu = PMU::regs();
102
103 pmu.power_pd_top_cntl().write(|w| w.bits(0));
104 pmu.power_pd_hpaon_cntl().write(|w| w.bits(0));
105 pmu.power_pd_hpcpu_cntl().write(|w| w.bits(0));
106 pmu.power_pd_hpperi_reserve().write(|w| w.bits(0));
107 pmu.power_pd_hpwifi_cntl().write(|w| w.bits(0));
108 pmu.power_pd_lpperi_cntl().write(|w| w.bits(0));
109
110 pmu.hp_active_hp_regulator0()
111 .modify(|_, w| w.hp_active_hp_regulator_dbias().bits(25));
112 pmu.hp_sleep_lp_regulator0()
113 .modify(|_, w| w.hp_sleep_lp_regulator_dbias().bits(26));
114
115 pmu.slp_wakeup_cntl5()
116 .modify(|_, w| w.lp_ana_wait_target().bits(15));
117 pmu.slp_wakeup_cntl7()
118 .modify(|_, w| w.ana_wait_target().bits(1700));
119 }
120}
121
122pub(crate) fn configure_clock() {
123 assert!(matches!(RtcClock::xtal_freq(), XtalClock::_32M));
124
125 RtcClock::set_fast_freq(RtcFastClock::RtcFastClockRcFast);
126
127 let cal_val = loop {
128 RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRcSlow);
129
130 let res = RtcClock::calibrate(RtcCalSel::RtcCalRtcMux, 1024);
131 if res != 0 {
132 break res;
133 }
134 };
135
136 LP_AON::regs()
137 .store1()
138 .modify(|_, w| unsafe { w.bits(cal_val) });
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, FromRepr)]
151pub enum SocResetReason {
152 ChipPowerOn = 0x01,
158 CoreSw = 0x03,
160 CoreDeepSleep = 0x05,
162 CoreMwdt0 = 0x07,
164 CoreMwdt1 = 0x08,
166 CoreRtcWdt = 0x09,
168 Cpu0Mwdt0 = 0x0B,
170 Cpu0Sw = 0x0C,
172 Cpu0RtcWdt = 0x0D,
174 SysBrownOut = 0x0F,
176 SysRtcWdt = 0x10,
178 Cpu0Mwdt1 = 0x11,
180 SysSuperWdt = 0x12,
182 SysClkGlitch = 0x13,
184 CoreEfuseCrc = 0x14,
186 CoreUsbUart = 0x15,
188 CoreUsbJtag = 0x16,
190 CorePwrGlitch = 0x17,
192}
193
194#[derive(Debug, Clone, Copy)]
196pub(crate) enum RtcFastClock {
197 RtcFastClockRcFast = 0,
199 #[allow(dead_code)]
200 RtcFastClockXtalD2 = 1,
202}
203
204impl Clock for RtcFastClock {
205 fn frequency(&self) -> Rate {
206 match self {
207 RtcFastClock::RtcFastClockXtalD2 => Rate::from_hz(16_000_000),
208 RtcFastClock::RtcFastClockRcFast => Rate::from_hz(8_000_000),
209 }
210 }
211}
212
213#[allow(clippy::enum_variant_names)]
215#[derive(Debug, Clone, Copy)]
216#[non_exhaustive]
217pub enum RtcSlowClock {
218 RtcSlowClockRcSlow = 0,
220 RtcSlowClock32kXtal = 1,
222 RtcSlowClock32kRc = 2,
224 RtcSlowOscSlow = 3,
226}
227
228impl Clock for RtcSlowClock {
229 fn frequency(&self) -> Rate {
230 match self {
231 RtcSlowClock::RtcSlowClockRcSlow => Rate::from_hz(150_000),
232 RtcSlowClock::RtcSlowClock32kXtal => Rate::from_hz(32_768),
233 RtcSlowClock::RtcSlowClock32kRc => Rate::from_hz(32_768),
234 RtcSlowClock::RtcSlowOscSlow => Rate::from_hz(32_768),
235 }
236 }
237}
238
239#[derive(Debug, Clone, Copy, PartialEq)]
240pub(crate) enum RtcCalSel {
242 RtcCalRtcMux = -1,
244 RtcCalRcSlow = 0,
246 RtcCal32kXtal = 1,
248 RtcCal32kRc = 2,
250 RtcCal32kOscSlow = 3,
253 RtcCalRcFast,
255}
256
257#[derive(Clone)]
258pub(crate) enum RtcCaliClkSel {
259 CaliClkRcSlow = 0,
260 CaliClkRcFast = 1,
261 CaliClk32k = 2,
262}
263
264impl RtcClock {
266 pub fn xtal_freq() -> XtalClock {
270 match Self::read_xtal_freq_mhz() {
271 None | Some(32) => XtalClock::_32M,
272 Some(other) => XtalClock::Other(other),
273 }
274 }
275
276 fn set_fast_freq(fast_freq: RtcFastClock) {
277 unsafe {
279 let lp_clkrst = LPWR::regs();
280 lp_clkrst.lp_clk_conf().modify(|_, w| {
281 w.fast_clk_sel().bits(match fast_freq {
282 RtcFastClock::RtcFastClockRcFast => 0b00,
283 RtcFastClock::RtcFastClockXtalD2 => 0b01,
284 })
285 });
286 }
287
288 crate::rom::ets_delay_us(3);
289 }
290
291 fn set_slow_freq(slow_freq: RtcSlowClock) {
292 unsafe {
293 let lp_clkrst = LPWR::regs();
294
295 lp_clkrst
296 .lp_clk_conf()
297 .modify(|_, w| w.slow_clk_sel().bits(slow_freq as u8));
298 lp_clkrst.clk_to_hp().modify(|_, w| {
299 w.icg_hp_xtal32k()
300 .bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kXtal))
301 .icg_hp_xtal32k()
302 .bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kXtal))
303 });
304 }
305 }
306
307 pub fn slow_freq() -> RtcSlowClock {
309 let lp_clrst = LPWR::regs();
310
311 let slow_freq = lp_clrst.lp_clk_conf().read().slow_clk_sel().bits();
312 match slow_freq {
313 0 => RtcSlowClock::RtcSlowClockRcSlow,
314 1 => RtcSlowClock::RtcSlowClock32kXtal,
315 2 => RtcSlowClock::RtcSlowClock32kRc,
316 3 => RtcSlowClock::RtcSlowOscSlow,
317 _ => unreachable!(),
318 }
319 }
320
321 fn calibrate(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
322 let xtal_freq = RtcClock::xtal_freq();
323 let xtal_cycles = RtcClock::calibrate_internal(cal_clk, slowclk_cycles) as u64;
324 let divider = xtal_freq.mhz() as u64 * slowclk_cycles as u64;
325 let period_64 = ((xtal_cycles << RtcClock::CAL_FRACT) + divider / 2u64 - 1u64) / divider;
326
327 (period_64 & u32::MAX as u64) as u32
328 }
329
330 fn calibrate_internal(mut cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
334 const SOC_CLK_RC_FAST_FREQ_APPROX: u32 = 17_500_000;
335 const SOC_CLK_RC_SLOW_FREQ_APPROX: u32 = 136_000;
336 const SOC_CLK_XTAL32K_FREQ_APPROX: u32 = 32768;
337
338 if cal_clk == RtcCalSel::RtcCalRtcMux {
339 cal_clk = match cal_clk {
340 RtcCalSel::RtcCalRtcMux => match RtcClock::slow_freq() {
341 RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
342 RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
343 _ => cal_clk,
344 },
345 RtcCalSel::RtcCal32kOscSlow => RtcCalSel::RtcCalRtcMux,
346 _ => cal_clk,
347 };
348 }
349
350 let lp_clkrst = LPWR::regs();
351 let pcr = PCR::regs();
352 let pmu = PMU::regs();
353
354 let clk_src = RtcClock::slow_freq();
355
356 if cal_clk == RtcCalSel::RtcCalRtcMux {
357 cal_clk = match clk_src {
358 RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
359 RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
360 RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
361 RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCal32kOscSlow,
362 };
363 }
364
365 let cali_clk_sel;
366 if cal_clk == RtcCalSel::RtcCalRtcMux {
367 cal_clk = match clk_src {
368 RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
369 RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
370 RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
371 RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCalRcSlow,
372 }
373 }
374
375 if cal_clk == RtcCalSel::RtcCalRcFast {
376 cali_clk_sel = RtcCaliClkSel::CaliClkRcFast;
377 } else if cal_clk == RtcCalSel::RtcCalRcSlow {
378 cali_clk_sel = RtcCaliClkSel::CaliClkRcSlow;
379 } else {
380 cali_clk_sel = RtcCaliClkSel::CaliClk32k;
381 match cal_clk {
382 RtcCalSel::RtcCalRtcMux | RtcCalSel::RtcCalRcSlow | RtcCalSel::RtcCalRcFast => {}
383 RtcCalSel::RtcCal32kRc => {
384 pcr.ctrl_32k_conf()
385 .modify(|_, w| unsafe { w.clk_32k_sel().bits(0) });
386 }
387 RtcCalSel::RtcCal32kXtal => {
388 pcr.ctrl_32k_conf()
389 .modify(|_, w| unsafe { w.clk_32k_sel().bits(1) });
390 }
391 RtcCalSel::RtcCal32kOscSlow => {
392 pcr.ctrl_32k_conf()
393 .modify(|_, w| unsafe { w.clk_32k_sel().bits(2) });
394 }
395 }
396 }
397
398 let dig_32k_xtal_enabled = lp_clkrst.clk_to_hp().read().icg_hp_xtal32k().bit_is_set();
404
405 if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
406 lp_clkrst
407 .clk_to_hp()
408 .modify(|_, w| w.icg_hp_xtal32k().set_bit());
409 }
410
411 lp_clkrst
414 .clk_to_hp()
415 .modify(|_, w| w.icg_hp_xtal32k().set_bit());
416 pmu.hp_sleep_lp_ck_power()
417 .modify(|_, w| w.hp_sleep_xpd_xtal32k().set_bit());
418
419 pmu.hp_sleep_lp_ck_power()
420 .modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
421
422 let rc_fast_enabled = pmu
423 .hp_sleep_lp_ck_power()
424 .read()
425 .hp_sleep_xpd_fosc_clk()
426 .bit_is_set();
427 let dig_rc_fast_enabled = lp_clkrst.clk_to_hp().read().icg_hp_fosc().bit_is_set();
428
429 if cal_clk == RtcCalSel::RtcCalRcFast {
430 if !rc_fast_enabled {
431 pmu.hp_sleep_lp_ck_power()
432 .modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
433 crate::rom::ets_delay_us(50);
434 }
435
436 if !dig_rc_fast_enabled {
437 lp_clkrst
438 .clk_to_hp()
439 .modify(|_, w| w.icg_hp_fosc().set_bit());
440 crate::rom::ets_delay_us(5);
441 }
442 }
443
444 let rc32k_enabled = pmu
445 .hp_sleep_lp_ck_power()
446 .read()
447 .hp_sleep_xpd_rc32k()
448 .bit_is_set();
449 let dig_rc32k_enabled = lp_clkrst.clk_to_hp().read().icg_hp_osc32k().bit_is_set();
450
451 if cal_clk == RtcCalSel::RtcCal32kRc {
452 if !rc32k_enabled {
453 pmu.hp_sleep_lp_ck_power()
454 .modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
455 crate::rom::ets_delay_us(300);
456 }
457
458 if !dig_rc32k_enabled {
459 lp_clkrst
460 .clk_to_hp()
461 .modify(|_, w| w.icg_hp_osc32k().set_bit());
462 }
463 }
464
465 let timg0 = TIMG0::regs();
468
469 if timg0
470 .rtccalicfg()
471 .read()
472 .rtc_cali_start_cycling()
473 .bit_is_set()
474 {
475 timg0
476 .rtccalicfg2()
477 .modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(1) });
478
479 while !timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_set()
483 && !timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_set()
484 {}
485 }
486
487 timg0
489 .rtccalicfg()
490 .modify(|_, w| unsafe { w.rtc_cali_clk_sel().bits(cali_clk_sel.clone() as u8) });
491 timg0
492 .rtccalicfg()
493 .modify(|_, w| w.rtc_cali_start_cycling().clear_bit());
494 timg0
495 .rtccalicfg()
496 .modify(|_, w| unsafe { w.rtc_cali_max().bits(slowclk_cycles as u16) });
497
498 let expected_freq = match cali_clk_sel {
499 RtcCaliClkSel::CaliClk32k => {
500 timg0.rtccalicfg2().modify(|_, w| unsafe {
501 w.rtc_cali_timeout_thres().bits(slowclk_cycles << 12)
502 });
503 SOC_CLK_XTAL32K_FREQ_APPROX
504 }
505 RtcCaliClkSel::CaliClkRcFast => {
506 timg0
507 .rtccalicfg2()
508 .modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(0x01FFFFFF) });
509 SOC_CLK_RC_FAST_FREQ_APPROX
510 }
511 _ => {
512 timg0.rtccalicfg2().modify(|_, w| unsafe {
513 w.rtc_cali_timeout_thres().bits(slowclk_cycles << 10)
514 });
515 SOC_CLK_RC_SLOW_FREQ_APPROX
516 }
517 };
518
519 let us_time_estimate = (Rate::from_mhz(slowclk_cycles) / expected_freq).as_hz();
520
521 timg0
523 .rtccalicfg()
524 .modify(|_, w| w.rtc_cali_start().clear_bit());
525 timg0
526 .rtccalicfg()
527 .modify(|_, w| w.rtc_cali_start().set_bit());
528
529 crate::rom::ets_delay_us(us_time_estimate);
531
532 let cal_val = loop {
533 if timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_set() {
534 break timg0.rtccalicfg1().read().rtc_cali_value().bits();
535 }
536
537 if timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_set() {
538 break 0;
540 }
541 };
542
543 timg0
544 .rtccalicfg()
545 .modify(|_, w| w.rtc_cali_start().clear_bit());
546
547 if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
548 lp_clkrst
549 .clk_to_hp()
550 .modify(|_, w| w.icg_hp_xtal32k().clear_bit());
551 }
552
553 if cal_clk == RtcCalSel::RtcCalRcFast {
554 if rc_fast_enabled {
555 pmu.hp_sleep_lp_ck_power()
556 .modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
557 crate::rom::ets_delay_us(50);
558 }
559
560 if dig_rc_fast_enabled {
561 lp_clkrst
562 .clk_to_hp()
563 .modify(|_, w| w.icg_hp_fosc().set_bit());
564 crate::rom::ets_delay_us(5);
565 }
566 }
567
568 if cal_clk == RtcCalSel::RtcCal32kRc {
569 if rc32k_enabled {
570 pmu.hp_sleep_lp_ck_power()
571 .modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
572 crate::rom::ets_delay_us(300);
573 }
574 if dig_rc32k_enabled {
575 lp_clkrst
576 .clk_to_hp()
577 .modify(|_, w| w.icg_hp_osc32k().set_bit());
578 }
579 }
580
581 cal_val
582 }
583
584 pub(crate) fn cycles_to_1ms() -> u16 {
585 let period_13q19 = RtcClock::calibrate(
586 match RtcClock::slow_freq() {
587 RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRtcMux,
588 RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
589 RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
590 RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCal32kOscSlow,
591 },
593 1024,
594 );
595
596 let period = (100_000_000 * period_13q19 as u64) / (1 << RtcClock::CAL_FRACT);
598
599 (100_000_000 * 1000 / period) as u16
600 }
601
602 pub(crate) fn estimate_xtal_frequency() -> u32 {
603 let timg0 = TIMG0::regs();
604 while timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_clear() {}
605
606 timg0.rtccalicfg().modify(|_, w| unsafe {
607 w.rtc_cali_clk_sel()
608 .bits(0) .rtc_cali_max()
610 .bits(100)
611 .rtc_cali_start_cycling()
612 .clear_bit()
613 .rtc_cali_start()
614 .set_bit()
615 });
616
617 timg0
618 .rtccalicfg()
619 .modify(|_, w| w.rtc_cali_start().set_bit());
620
621 while timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_clear() {}
622
623 (timg0.rtccalicfg1().read().rtc_cali_value().bits()
624 * (RtcSlowClock::RtcSlowClockRcSlow.frequency().as_hz() / 100))
625 / 1_000_000
626 }
627}