Skip to main content

esp_hal/rtc_cntl/sleep/
esp32c5.rs

1use core::ops::Not;
2
3use crate::{
4    peripherals::{LP_AON, PMU},
5    private::DropGuard,
6    rtc_cntl::{
7        Rtc,
8        rtc::{HpAnalog, HpSysCntlReg, HpSysPower, LpAnalog, LpSysPower},
9        sleep::{SleepKind, pmu_common::SleepTimeConfig},
10    },
11    soc::{
12        clocks::{self, ClockTree, HpRootClkConfig, LpSlowClkConfig},
13        xtal32k,
14    },
15};
16
17/// Configuration for controlling the behavior during sleep modes.
18#[derive(Clone, Copy)]
19// pmu_sleep_analog_config_t
20pub struct AnalogSleepConfig {
21    /// High-power system configuration.
22    pub hp_sys: HpAnalog,
23    // pub lp_sys_active: LpAnalog, // unused
24    /// Low-power system analog configuration.
25    pub lp_sys_sleep: LpAnalog,
26}
27
28impl AnalogSleepConfig {
29    fn defaults_deep_sleep() -> Self {
30        Self {
31            // PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT
32            hp_sys: {
33                let mut cfg = HpAnalog::default();
34
35                cfg.bias.set_pd_cur(false);
36                cfg.bias.set_bias_sleep(false);
37                cfg.regulator0.set_xpd(false);
38                cfg.bias.set_dbg_atten(0);
39
40                cfg
41            },
42            // lp_sys_active: LpAnalog::default(),
43            lp_sys_sleep: {
44                let mut cfg = LpAnalog::default();
45
46                cfg.regulator1.set_drv_b(0);
47                cfg.bias.set_pd_cur(true);
48                cfg.bias.set_bias_sleep(true);
49                cfg.regulator0.set_slp_xpd(false);
50                cfg.regulator0.set_slp_dbias(0);
51                cfg.regulator0.set_xpd(true);
52                cfg.bias.set_dbg_atten(9); // PMU_DBG_ATTEN_DEEPSLEEP_DEFAULT
53                cfg.regulator0.set_dbias(15); // PMU_LP_DBIAS_DEEPSLEEP_0V7_DEFAULT
54
55                cfg
56            },
57        }
58    }
59
60    fn defaults_light_sleep(pd_flags: PowerDownFlags) -> Self {
61        let mut this = Self {
62            // PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT
63            hp_sys: {
64                let mut cfg = HpAnalog::default();
65
66                cfg.regulator1.set_drv_b(0);
67                cfg.bias.set_pd_cur(true);
68                cfg.bias.set_bias_sleep(true);
69                cfg.regulator0.set_xpd(true);
70                cfg.bias.set_dbg_atten(1); // PMU_DBG_ATTEN_LIGHTSLEEP_DEFAULT
71                cfg.regulator0.set_dbias(0); // PMU_HP_DBIAS_LIGHTSLEEP_0V6_DEFAULT
72
73                cfg
74            },
75            // lp_sys_active: LpAnalog::default(),
76            lp_sys_sleep: {
77                let mut cfg = LpAnalog::default();
78
79                cfg.regulator1.set_drv_b(0);
80                cfg.bias.set_pd_cur(true);
81                cfg.bias.set_bias_sleep(true);
82                cfg.regulator0.set_slp_xpd(false);
83                cfg.regulator0.set_slp_dbias(0);
84                cfg.regulator0.set_xpd(true);
85                cfg.bias.set_dbg_atten(1); // PMU_DBG_ATTEN_LIGHTSLEEP_DEFAULT
86                cfg.regulator0.set_dbias(15); // PMU_LP_DBIAS_LIGHTSLEEP_0V7_DEFAULT
87
88                cfg
89            },
90        };
91
92        // When XTAL or RC_FAST stays on during sleep, raise the regulator
93        // voltage back to the active-mode calibration value.
94        if !pd_flags.pd_xtal() {
95            this.hp_sys.bias.set_pd_cur(false);
96            this.hp_sys.bias.set_bias_sleep(false);
97            this.hp_sys.bias.set_dbg_atten(0);
98            this.hp_sys.regulator0.set_dbias(28); // get_act_hp_dbias() ~ HP_CALI_DBIAS
99
100            this.lp_sys_sleep.bias.set_pd_cur(false);
101            this.lp_sys_sleep.bias.set_bias_sleep(false);
102            this.lp_sys_sleep.bias.set_dbg_atten(0);
103            this.lp_sys_sleep.regulator0.set_dbias(28); // get_act_lp_dbias() ~ LP_CALI_DBIAS
104        }
105
106        this
107    }
108
109    fn apply(&self) {
110        // pmu_sleep_analog_init
111
112        // HP SLEEP (hp_sleep_*)
113        PMU::regs().hp_sleep_bias().modify(|_, w| unsafe {
114            // pmu_ll_hp_set_dbg_atten
115            w.hp_sleep_dbg_atten().bits(self.hp_sys.bias.dbg_atten());
116            // pmu_ll_hp_set_current_power_off
117            w.hp_sleep_pd_cur().bit(self.hp_sys.bias.pd_cur());
118            // pmu_ll_hp_set_bias_sleep_enable
119            w.sleep().bit(self.hp_sys.bias.bias_sleep())
120        });
121        PMU::regs().hp_sleep_hp_regulator0().modify(|_, w| unsafe {
122            // pmu_ll_hp_set_regulator_xpd
123            w.hp_sleep_hp_regulator_xpd()
124                .bit(self.hp_sys.regulator0.xpd());
125            // pmu_ll_hp_set_regulator_dbias
126            w.hp_sleep_hp_regulator_dbias()
127                .bits(self.hp_sys.regulator0.dbias())
128        });
129        PMU::regs().hp_sleep_hp_regulator1().modify(|_, w| unsafe {
130            // pmu_ll_hp_set_regulator_driver_bar
131            w.hp_sleep_hp_regulator_drv_b()
132                .bits(self.hp_sys.regulator1.drv_b())
133        });
134
135        // LP SLEEP (lp_sleep_*)
136        PMU::regs().lp_sleep_bias().modify(|_, w| unsafe {
137            // pmu_ll_lp_set_dbg_atten
138            w.lp_sleep_dbg_atten()
139                .bits(self.lp_sys_sleep.bias.dbg_atten());
140            // pmu_ll_lp_set_current_power_off
141            w.lp_sleep_pd_cur().bit(self.lp_sys_sleep.bias.pd_cur());
142            // pmu_ll_lp_set_bias_sleep_enable
143            w.sleep().bit(self.lp_sys_sleep.bias.bias_sleep())
144        });
145
146        PMU::regs().lp_sleep_lp_regulator0().modify(|_, w| unsafe {
147            // pmu_ll_lp_set_regulator_slp_xpd
148            w.lp_sleep_lp_regulator_slp_xpd()
149                .bit(self.lp_sys_sleep.regulator0.slp_xpd());
150            // pmu_ll_lp_set_regulator_xpd
151            w.lp_sleep_lp_regulator_xpd()
152                .bit(self.lp_sys_sleep.regulator0.xpd());
153            // pmu_ll_lp_set_regulator_sleep_dbias
154            w.lp_sleep_lp_regulator_slp_dbias()
155                .bits(self.lp_sys_sleep.regulator0.slp_dbias());
156            // pmu_ll_lp_set_regulator_dbias
157            w.lp_sleep_lp_regulator_dbias()
158                .bits(self.lp_sys_sleep.regulator0.dbias())
159        });
160
161        PMU::regs().lp_sleep_lp_regulator1().modify(|_, w| unsafe {
162            // pmu_ll_lp_set_regulator_driver_bar
163            w.lp_sleep_lp_regulator_drv_b()
164                .bits(self.lp_sys_sleep.regulator1.drv_b())
165        });
166    }
167}
168
169/// Configuration for controlling the behavior of digital peripherals during
170/// sleep modes.
171#[derive(Clone, Copy)]
172// pmu_sleep_digital_config_t
173pub struct DigitalSleepConfig {
174    /// High-power system control register configuration.
175    pub syscntl: HpSysCntlReg,
176}
177
178impl DigitalSleepConfig {
179    fn defaults_light_sleep(pd_flags: PowerDownFlags) -> Self {
180        Self {
181            // PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT
182            syscntl: {
183                let mut cfg = HpSysCntlReg::default();
184
185                cfg.set_dig_pad_slp_sel(pd_flags.pd_top().not());
186
187                cfg
188            },
189        }
190    }
191
192    fn apply(&self) {
193        // pmu_sleep_digital_init
194        PMU::regs().hp_sleep_hp_sys_cntl().modify(|_, w| {
195            w.hp_sleep_dig_pad_slp_sel()
196                .bit(self.syscntl.dig_pad_slp_sel())
197        });
198    }
199}
200
201/// Configuration for controlling the power settings of high-power and low-power
202/// systems during sleep modes.
203#[derive(Clone, Copy)]
204// pmu_sleep_power_config_t
205pub struct PowerSleepConfig {
206    /// Power configuration for the high-power system during sleep.
207    pub hp_sys: HpSysPower,
208    /// Power configuration for the low-power system when it is active.
209    pub lp_sys_active: LpSysPower,
210    /// Power configuration for the low-power system when it is in sleep mode.
211    pub lp_sys_sleep: LpSysPower,
212}
213
214impl PowerSleepConfig {
215    fn defaults(pd_flags: PowerDownFlags) -> Self {
216        let mut this = Self {
217            hp_sys: HpSysPower::default(),
218            lp_sys_active: LpSysPower::default(),
219            lp_sys_sleep: LpSysPower::default(),
220        };
221        this.apply_flags(pd_flags);
222        this
223    }
224
225    fn apply_flags(&mut self, pd_flags: PowerDownFlags) {
226        // PMU_SLEEP_POWER_CONFIG_DEFAULT
227        self.hp_sys
228            .dig_power
229            .set_vdd_spi_pd_en(pd_flags.pd_vddsdio());
230        self.hp_sys.dig_power.set_wifi_pd_en(pd_flags.pd_modem());
231        self.hp_sys.dig_power.set_cpu_pd_en(pd_flags.pd_cpu());
232        self.hp_sys.dig_power.set_aon_pd_en(pd_flags.pd_hp_aon());
233        self.hp_sys.dig_power.set_top_pd_en(pd_flags.pd_top());
234
235        self.hp_sys.clk.set_i2c_iso_en(true);
236        self.hp_sys.clk.set_i2c_retention(true);
237
238        self.hp_sys.xtal.set_xpd_xtal(pd_flags.pd_xtal().not());
239
240        self.lp_sys_active
241            .clk_power
242            .set_xpd_xtal32k(xtal32k::use_xtal32k());
243        self.lp_sys_active.clk_power.set_xpd_rc32k(true);
244        self.lp_sys_active.clk_power.set_xpd_fosc(true);
245
246        self.lp_sys_sleep
247            .dig_power
248            .set_peri_pd_en(pd_flags.pd_lp_periph());
249        self.lp_sys_sleep.dig_power.set_mem_dslp(true);
250
251        self.lp_sys_sleep
252            .clk_power
253            .set_xpd_xtal32k(pd_flags.pd_xtal32k().not());
254        self.lp_sys_sleep
255            .clk_power
256            .set_xpd_rc32k(pd_flags.pd_rc32k().not());
257        self.lp_sys_sleep
258            .clk_power
259            .set_xpd_fosc(pd_flags.pd_rc_fast().not());
260
261        self.lp_sys_sleep
262            .xtal
263            .set_xpd_xtal(pd_flags.pd_xtal().not());
264    }
265
266    fn apply(&self) {
267        // pmu_sleep_power_init
268
269        // HP SLEEP (hp_sleep_*)
270        PMU::regs()
271            .hp_sleep_dig_power()
272            .modify(|_, w| unsafe { w.bits(self.hp_sys.dig_power.0) });
273        PMU::regs()
274            .hp_sleep_hp_ck_power()
275            .modify(|_, w| unsafe { w.bits(self.hp_sys.clk.0) });
276        PMU::regs()
277            .hp_sleep_xtal()
278            .modify(|_, w| w.hp_sleep_xpd_xtal().bit(self.hp_sys.xtal.xpd_xtal()));
279
280        // LP ACTIVE (hp_sleep_lp_*)
281        PMU::regs()
282            .hp_sleep_lp_dig_power()
283            .modify(|_, w| unsafe { w.bits(self.lp_sys_active.dig_power.0) });
284        PMU::regs()
285            .hp_sleep_lp_ck_power()
286            .modify(|_, w| unsafe { w.bits(self.lp_sys_active.clk_power.0) });
287
288        // LP SLEEP (lp_sleep_*)
289        PMU::regs()
290            .lp_sleep_lp_dig_power()
291            .modify(|_, w| unsafe { w.bits(self.lp_sys_sleep.dig_power.0) });
292        PMU::regs()
293            .lp_sleep_lp_ck_power()
294            .modify(|_, w| unsafe { w.bits(self.lp_sys_sleep.clk_power.0) });
295        PMU::regs()
296            .lp_sleep_xtal()
297            .modify(|_, w| w.lp_sleep_xpd_xtal().bit(self.lp_sys_sleep.xtal.xpd_xtal()));
298    }
299}
300
301/// Parameters for high-power system configurations during sleep modes.
302#[derive(Clone, Copy)]
303// pmu_hp_param_t
304pub struct HpParam {
305    /// Number of cycles to wait for the modem to wake up.
306    pub modem_wakeup_wait_cycle: u32,
307    /// Number of cycles to wait for the analog component stabilization.
308    pub analog_wait_target_cycle: u16,
309    /// Number of cycles to wait for the digital power-down sequence.
310    pub digital_power_down_wait_cycle: u16,
311    /// Number of cycles to wait for the digital power supply to stabilize.
312    pub digital_power_supply_wait_cycle: u16,
313    /// Number of cycles to wait for the digital power-up sequence.
314    pub digital_power_up_wait_cycle: u16,
315    /// Number of cycles to wait for the PLL to stabilize.
316    pub pll_stable_wait_cycle: u16,
317    /// Number of cycles to wait for modifying the ICG control.
318    pub modify_icg_cntl_wait_cycle: u8,
319    /// Number of cycles to wait for switching the ICG control.
320    pub switch_icg_cntl_wait_cycle: u8,
321    /// Minimum sleep time measured in slow clock cycles.
322    pub min_slp_slow_clk_cycle: u8,
323    /// Number of cycles to wait for all isolate signals to be ready.
324    pub isolate_wait_cycle: u8,
325    /// Number of cycles to wait for all reset signals to be ready.
326    pub reset_wait_cycle: u8,
327}
328
329/// Parameters for low-power system configurations during sleep modes.
330#[derive(Clone, Copy)]
331// pmu_lp_param_t
332pub struct LpParam {
333    /// Number of cycles to wait for the digital power supply to stabilize.
334    pub digital_power_supply_wait_cycle: u16,
335    /// Minimum sleep time measured in slow clock cycles.
336    pub min_slp_slow_clk_cycle: u8,
337    /// Number of cycles to wait for the analog component stabilization.
338    pub analog_wait_target_cycle: u8,
339    /// Number of cycles to wait for the digital power-down sequence.
340    pub digital_power_down_wait_cycle: u8,
341    /// Number of cycles to wait for the digital power-up sequence.
342    pub digital_power_up_wait_cycle: u8,
343    /// Number of cycles to wait for all isolate signals to be ready.
344    pub isolate_wait_cycle: u8,
345    /// Number of cycles to wait for all reset signals to be ready.
346    pub reset_wait_cycle: u8,
347}
348
349/// Parameters for high-power and low-power system configurations during sleep
350/// modes.
351#[derive(Clone, Copy)]
352// pmu_hp_lp_param_t
353pub struct HpLpParam {
354    /// Union of two u16 variants
355    pub xtal_stable_wait_cycle: u16,
356}
357
358/// Configuration of parameters for sleep modes
359#[derive(Clone, Copy)]
360// pmu_sleep_param_config_t
361pub struct ParamSleepConfig {
362    /// Configuration of high-power system parameters.
363    pub hp_sys: HpParam,
364    /// Configuration of low-power system parameters.
365    pub lp_sys: LpParam,
366    /// Shared configuration parameters for high-power and low-power systems.
367    pub hp_lp: HpLpParam,
368}
369impl ParamSleepConfig {
370    const PMU_SLEEP_PARAM_CONFIG_DEFAULT: Self = Self {
371        hp_sys: HpParam {
372            min_slp_slow_clk_cycle: 10,
373            analog_wait_target_cycle: 2419,
374            digital_power_supply_wait_cycle: 32,
375            digital_power_up_wait_cycle: 32,
376            modem_wakeup_wait_cycle: 20700,
377            pll_stable_wait_cycle: 2,
378
379            digital_power_down_wait_cycle: 0,
380            modify_icg_cntl_wait_cycle: 0,
381            switch_icg_cntl_wait_cycle: 0,
382            isolate_wait_cycle: 0,
383            reset_wait_cycle: 0,
384        },
385        lp_sys: LpParam {
386            min_slp_slow_clk_cycle: 10,
387            analog_wait_target_cycle: 23,
388            digital_power_supply_wait_cycle: 32,
389            digital_power_up_wait_cycle: 32,
390
391            digital_power_down_wait_cycle: 0,
392            isolate_wait_cycle: 0,
393            reset_wait_cycle: 0,
394        },
395        hp_lp: HpLpParam {
396            xtal_stable_wait_cycle: 30,
397        },
398    };
399
400    fn apply(&self) {
401        // pmu_sleep_param_init
402
403        PMU::regs().slp_wakeup_cntl3().modify(|_, w| unsafe {
404            // pmu_ll_hp_set_min_sleep_cycle
405            w.hp_min_slp_val().bits(self.hp_sys.min_slp_slow_clk_cycle);
406            // pmu_ll_lp_set_min_sleep_cycle
407            w.lp_min_slp_val().bits(self.lp_sys.min_slp_slow_clk_cycle)
408        });
409
410        PMU::regs().slp_wakeup_cntl7().modify(|_, w| unsafe {
411            // pmu_ll_hp_set_analog_wait_target_cycle
412            w.ana_wait_target()
413                .bits(self.hp_sys.analog_wait_target_cycle)
414        });
415
416        PMU::regs().power_wait_timer0().modify(|_, w| unsafe {
417            // pmu_ll_hp_set_digital_power_supply_wait_cycle
418            w.dg_hp_pd_wait_timer()
419                .bits(self.hp_sys.digital_power_supply_wait_cycle);
420            // pmu_ll_hp_set_digital_power_up_wait_cycle
421            w.dg_hp_powerup_timer()
422                .bits(self.hp_sys.digital_power_up_wait_cycle)
423        });
424
425        PMU::regs().power_wait_timer1().modify(|_, w| unsafe {
426            // pmu_ll_lp_set_digital_power_supply_wait_cycle
427            w.dg_lp_pd_wait_timer()
428                .bits(self.lp_sys.digital_power_supply_wait_cycle);
429            // pmu_ll_lp_set_digital_power_up_wait_cycle
430            w.dg_lp_powerup_timer()
431                .bits(self.lp_sys.digital_power_up_wait_cycle)
432        });
433
434        // pmu_hal_hp/lp_set_control_ready_wait_cycle (new on ESP32-C5)
435        PMU::regs().power_wait_timer2().modify(|_, w| unsafe {
436            w.dg_hp_iso_wait_timer()
437                .bits(self.hp_sys.isolate_wait_cycle);
438            w.dg_hp_rst_wait_timer().bits(self.hp_sys.reset_wait_cycle);
439            w.dg_lp_iso_wait_timer()
440                .bits(self.lp_sys.isolate_wait_cycle);
441            w.dg_lp_rst_wait_timer().bits(self.lp_sys.reset_wait_cycle)
442        });
443
444        PMU::regs().slp_wakeup_cntl5().modify(|_, w| unsafe {
445            // pmu_ll_lp_set_analog_wait_target_cycle
446            w.lp_ana_wait_target()
447                .bits(self.lp_sys.analog_wait_target_cycle);
448            // pmu_ll_hp_set_modem_wakeup_wait_cycle
449            w.modem_wait_target()
450                .bits(self.hp_sys.modem_wakeup_wait_cycle)
451        });
452        PMU::regs().power_ck_wait_cntl().modify(|_, w| unsafe {
453            // pmu_ll_hp_set_xtal_stable_wait_cycle
454            w.wait_xtl_stable().bits(self.hp_lp.xtal_stable_wait_cycle);
455            // pmu_ll_hp_set_pll_stable_wait_cycle
456            w.wait_pll_stable().bits(self.hp_sys.pll_stable_wait_cycle)
457        });
458    }
459
460    fn defaults(config: SleepTimeConfig, pd_flags: PowerDownFlags, pd_xtal: bool) -> Self {
461        let mut param = Self::PMU_SLEEP_PARAM_CONFIG_DEFAULT;
462
463        // pmu_sleep_param_config_default
464        param.hp_sys.min_slp_slow_clk_cycle =
465            config.us_to_slowclk(MachineConstants::HP_MIN_SLP_TIME_US) as u8;
466        param.hp_sys.analog_wait_target_cycle =
467            config.us_to_fastclk(MachineConstants::HP_ANALOG_WAIT_TIME_US) as u16;
468        param.hp_sys.digital_power_supply_wait_cycle =
469            config.us_to_fastclk(MachineConstants::HP_POWER_SUPPLY_WAIT_TIME_US) as u16;
470        param.hp_sys.digital_power_up_wait_cycle =
471            config.us_to_fastclk(MachineConstants::HP_POWER_UP_WAIT_TIME_US) as u16;
472        param.hp_sys.pll_stable_wait_cycle =
473            config.us_to_fastclk(MachineConstants::HP_PLL_WAIT_STABLE_TIME_US) as u16;
474        param.hp_sys.isolate_wait_cycle =
475            config.us_to_fastclk(MachineConstants::HP_ISOLATE_WAIT_TIME_US) as u8;
476        param.hp_sys.reset_wait_cycle =
477            config.us_to_fastclk(MachineConstants::HP_RESET_WAIT_TIME_US) as u8;
478
479        let hw_wait_time_us = config.pmu_sleep_calculate_hw_wait_time(pd_flags);
480
481        let modem_wakeup_wait_time_us = (config.sleep_time_adjustment
482            + MachineConstants::MODEM_STATE_SKIP_TIME_US
483            + MachineConstants::HP_REGDMA_RF_ON_WORK_TIME_US)
484            .saturating_sub(hw_wait_time_us);
485        param.hp_sys.modem_wakeup_wait_cycle = config.us_to_fastclk(modem_wakeup_wait_time_us);
486
487        param.lp_sys.min_slp_slow_clk_cycle =
488            config.us_to_slowclk(MachineConstants::LP_MIN_SLP_TIME_US) as u8;
489        param.lp_sys.analog_wait_target_cycle =
490            config.us_to_slowclk(MachineConstants::LP_ANALOG_WAIT_TIME_US) as u8;
491        param.lp_sys.digital_power_supply_wait_cycle =
492            config.us_to_fastclk(MachineConstants::LP_POWER_SUPPLY_WAIT_TIME_US) as u16;
493        param.lp_sys.digital_power_up_wait_cycle =
494            config.us_to_fastclk(MachineConstants::LP_POWER_UP_WAIT_TIME_US) as u8;
495        param.lp_sys.isolate_wait_cycle =
496            config.us_to_fastclk(MachineConstants::LP_ISOLATE_WAIT_TIME_US) as u8;
497        param.lp_sys.reset_wait_cycle =
498            config.us_to_fastclk(MachineConstants::LP_RESET_WAIT_TIME_US) as u8;
499
500        // This looks different from esp-idf but it is the same:
501        // Both `xtal_stable_wait_cycle` and `xtal_stable_wait_slow_clk_cycle` are
502        // u16 variants of the same union
503        param.hp_lp.xtal_stable_wait_cycle = if pd_xtal {
504            config.us_to_slowclk(MachineConstants::LP_XTAL_WAIT_STABLE_TIME_US) as u16
505        } else {
506            config.us_to_fastclk(MachineConstants::HP_XTAL_WAIT_STABLE_TIME_US) as u16
507        };
508
509        param
510    }
511}
512
513impl SleepTimeConfig {
514    pub(crate) const CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ: u32 = 160;
515    pub(crate) const LIGHT_SLEEP_TIME_OVERHEAD_US: u32 = 56;
516
517    pub(crate) fn pmu_sleep_calculate_hw_wait_time(&self, pd_flags: PowerDownFlags) -> u32 {
518        // LP core hardware wait time, microsecond
519        let lp_wakeup_wait_time_us = self.slowclk_to_us(MachineConstants::LP_WAKEUP_WAIT_CYCLE);
520        let lp_clk_switch_time_us = self.slowclk_to_us(MachineConstants::LP_CLK_SWITCH_CYCLE);
521        let lp_clk_power_on_wait_time_us = if pd_flags.pd_xtal() {
522            MachineConstants::LP_XTAL_WAIT_STABLE_TIME_US
523        } else {
524            self.slowclk_to_us(MachineConstants::LP_CLK_POWER_ON_WAIT_CYCLE)
525        };
526
527        // ESP32-C5 adds control (isolate + reset) wait time to both domains.
528        let lp_control_wait_time_us =
529            MachineConstants::LP_ISOLATE_WAIT_TIME_US + MachineConstants::LP_RESET_WAIT_TIME_US;
530        let lp_hw_wait_time_us = MachineConstants::LP_MIN_SLP_TIME_US
531            + MachineConstants::LP_ANALOG_WAIT_TIME_US
532            + lp_clk_power_on_wait_time_us
533            + lp_wakeup_wait_time_us
534            + lp_clk_switch_time_us
535            + MachineConstants::LP_POWER_SUPPLY_WAIT_TIME_US
536            + MachineConstants::LP_POWER_UP_WAIT_TIME_US
537            + lp_control_wait_time_us;
538
539        // HP core hardware wait time, microsecond
540        let hp_digital_power_up_wait_time_us = MachineConstants::HP_POWER_SUPPLY_WAIT_TIME_US
541            + MachineConstants::HP_POWER_UP_WAIT_TIME_US;
542        let hp_control_wait_time_us =
543            MachineConstants::HP_ISOLATE_WAIT_TIME_US + MachineConstants::HP_RESET_WAIT_TIME_US;
544        let hp_regdma_wait_time_us = u32::max(
545            MachineConstants::HP_REGDMA_S2M_WORK_TIME_US
546                + MachineConstants::HP_REGDMA_M2A_WORK_TIME_US,
547            MachineConstants::HP_REGDMA_S2A_WORK_TIME_US,
548        );
549        let hp_clock_wait_time_us = MachineConstants::HP_XTAL_WAIT_STABLE_TIME_US
550            + MachineConstants::HP_PLL_WAIT_STABLE_TIME_US;
551
552        let hp_hw_wait_time_us = MachineConstants::HP_ANALOG_WAIT_TIME_US
553            + u32::max(
554                hp_digital_power_up_wait_time_us + hp_regdma_wait_time_us,
555                hp_clock_wait_time_us,
556            )
557            + hp_control_wait_time_us;
558
559        #[rustfmt::skip] // ASCII art
560        //  When the SOC wakeup (lp timer or GPIO wakeup) and Modem wakeup (Beacon wakeup) complete,
561        // the soc wakeup will be delayed until the RF is turned on in Modem state.
562        //
563        //              modem wakeup                      TBTT, RF on by HW
564        //                   |                                    |
565        //                  \|/                                  \|/
566        // PMU_HP_ACTIVE                                                                         /------
567        // PMU_HP_MODEM                                           /------------//////////////////
568        // PMU_HP_SLEEP   ----------------------//////////////////
569        //                  /|\                /|\ /|\          /|\           /|\              /|\
570        //                   |<- some hw wait ->|   |            |             |<- M2A switch ->|
571        //                   |  slow cycles &   | soc wakeup     |                              |
572        //                   |   FOSC cycles    |<- S2M switch ->|                              |
573        //                   |                                                                  |
574        //                   |<--      PMU guard time, also the maximum time for the SOC     -->|
575        //                   |                           wake-up delay                          |
576        //
577        const CONFIG_ESP_RADIO_ENHANCED_LIGHT_SLEEP: bool = true;
578
579        let (rf_on_protect_time_us, sync_time_us) = if CONFIG_ESP_RADIO_ENHANCED_LIGHT_SLEEP {
580            (
581                MachineConstants::HP_REGDMA_RF_ON_WORK_TIME_US,
582                MachineConstants::HP_CLOCK_DOMAIN_SYNC_TIME_US,
583            )
584        } else {
585            (0, 0)
586        };
587
588        lp_hw_wait_time_us + hp_hw_wait_time_us + sync_time_us + rf_on_protect_time_us
589    }
590}
591
592/// Configuration for the RTC sleep behavior.
593#[derive(Clone, Copy)]
594// pmu_sleep_config_t + deep sleep flag + pd flags
595pub struct RtcSleepConfig {
596    /// Deep Sleep flag
597    pub deep: bool,
598    /// Power Down flags
599    pub pd_flags: PowerDownFlags,
600}
601
602impl Default for RtcSleepConfig {
603    fn default() -> Self {
604        // from pmu_sleep_param_config_default
605        // sleep flags will be applied by wakeup methods and apply
606
607        Self {
608            deep: false,
609            pd_flags: PowerDownFlags(0),
610        }
611    }
612}
613
614bitfield::bitfield! {
615    #[derive(Clone, Copy)]
616    /// Power domains to be powered down during sleep
617    pub struct PowerDownFlags(u32);
618
619    /// Controls the power-down status of the top power domain.
620    pub u32, pd_top      , set_pd_top      : 0;
621    /// Controls the power-down status of the VDD_SDIO power domain.
622    pub u32, pd_vddsdio  , set_pd_vddsdio  : 1;
623    /// Controls the power-down status of the modem power domain.
624    pub u32, pd_modem    , set_pd_modem    : 2;
625    /// Controls the power-down status of the high-performance peripheral power domain.
626    pub u32, pd_hp_periph, set_pd_hp_periph: 3;
627    /// Controls the power-down status of the CPU power domain.
628    pub u32, pd_cpu      , set_pd_cpu      : 4;
629    /// Controls the power-down status of the high-performance always-on domain.
630    pub u32, pd_hp_aon   , set_pd_hp_aon   : 5;
631    /// Controls the power-down status of memory group 0.
632    pub u32, pd_mem_g0   , set_pd_mem_g0   : 6;
633    /// Controls the power-down status of memory group 1.
634    pub u32, pd_mem_g1   , set_pd_mem_g1   : 7;
635    /// Controls the power-down status of memory group 2.
636    pub u32, pd_mem_g2   , set_pd_mem_g2   : 8;
637    /// Controls the power-down status of memory group 3.
638    pub u32, pd_mem_g3   , set_pd_mem_g3   : 9;
639    /// Controls the power-down status of the crystal oscillator.
640    pub u32, pd_xtal     , set_pd_xtal     : 10;
641    /// Controls the power-down status of the fast RC oscillator.
642    pub u32, pd_rc_fast  , set_pd_rc_fast  : 11;
643    /// Controls the power-down status of the 32kHz crystal oscillator.
644    pub u32, pd_xtal32k  , set_pd_xtal32k  : 12;
645    /// Controls the power-down status of the 32kHz RC oscillator.
646    pub u32, pd_rc32k    , set_pd_rc32k    : 13;
647    /// Controls the power-down status of the low-power peripheral domain.
648    pub u32, pd_lp_periph, set_pd_lp_periph: 14;
649}
650
651impl PowerDownFlags {
652    /// Checks whether all memory groups (G0, G1, G2, G3) are powered down.
653    pub fn pd_mem(self) -> bool {
654        self.pd_mem_g0() && self.pd_mem_g1() && self.pd_mem_g2() && self.pd_mem_g3()
655    }
656
657    /// Sets the power-down status for all memory groups (G0, G1, G2, G3) at
658    /// once.
659    pub fn set_pd_mem(&mut self, value: bool) {
660        self.set_pd_mem_g0(value);
661        self.set_pd_mem_g1(value);
662        self.set_pd_mem_g2(value);
663        self.set_pd_mem_g3(value);
664    }
665}
666
667// Constants defined in `PMU_SLEEP_MC_DEFAULT()` (ESP32-C5 values)
668struct MachineConstants;
669impl MachineConstants {
670    const LP_MIN_SLP_TIME_US: u32 = 450;
671    const LP_WAKEUP_WAIT_CYCLE: u32 = 4;
672    const LP_ANALOG_WAIT_TIME_US: u32 = 154;
673    const LP_XTAL_WAIT_STABLE_TIME_US: u32 = 250;
674    const LP_CLK_SWITCH_CYCLE: u32 = 1;
675    const LP_CLK_POWER_ON_WAIT_CYCLE: u32 = 1;
676    const LP_ISOLATE_WAIT_TIME_US: u32 = 1;
677    const LP_RESET_WAIT_TIME_US: u32 = 1;
678    const LP_POWER_SUPPLY_WAIT_TIME_US: u32 = 2;
679    const LP_POWER_UP_WAIT_TIME_US: u32 = 2;
680
681    const HP_MIN_SLP_TIME_US: u32 = 450;
682    const HP_CLOCK_DOMAIN_SYNC_TIME_US: u32 = 2;
683    const HP_SYSTEM_DFS_UP_WORK_TIME_US: u32 = 124;
684    const HP_ANALOG_WAIT_TIME_US: u32 = 154;
685    const HP_ISOLATE_WAIT_TIME_US: u32 = 1;
686    const HP_RESET_WAIT_TIME_US: u32 = 1;
687    const HP_POWER_SUPPLY_WAIT_TIME_US: u32 = 2;
688    const HP_POWER_UP_WAIT_TIME_US: u32 = 2;
689    const HP_REGDMA_S2M_WORK_TIME_US: u32 = 287;
690    const HP_REGDMA_S2A_WORK_TIME_US: u32 = 720;
691    const HP_REGDMA_M2A_WORK_TIME_US: u32 = 430;
692    // Unused, but defined in esp-idf. May be needed later.
693    // const HP_REGDMA_A2S_WORK_TIME_US: u32 = 433;
694    const HP_REGDMA_RF_ON_WORK_TIME_US: u32 = 68;
695    // Unused, but defined in esp-idf. May be needed later.
696    // const HP_REGDMA_RF_OFF_WORK_TIME_US: u32 = 25;
697    const HP_XTAL_WAIT_STABLE_TIME_US: u32 = 250;
698    const HP_PLL_WAIT_STABLE_TIME_US: u32 = 50;
699
700    const MODEM_STATE_SKIP_TIME_US: u32 = Self::HP_REGDMA_M2A_WORK_TIME_US
701        + Self::HP_SYSTEM_DFS_UP_WORK_TIME_US
702        + Self::LP_MIN_SLP_TIME_US;
703}
704
705impl RtcSleepConfig {
706    /// Returns whether the device is in deep sleep mode.
707    pub fn deep_slp(&self) -> bool {
708        self.deep
709    }
710
711    /// Configures the device for deep sleep mode with ultra-low power settings.
712    pub fn deep() -> Self {
713        // Set up for ultra-low power sleep. Wakeup sources may modify these settings.
714        Self {
715            deep: true,
716            ..Self::default()
717        }
718    }
719
720    pub(crate) fn is_deep_sleep(&self) -> bool {
721        self.deep
722    }
723
724    pub(crate) fn set_sleep_kind(&mut self, kind: SleepKind) {
725        self.deep = kind == SleepKind::Deep;
726    }
727
728    pub(crate) fn base_settings(_rtc: &Rtc<'_>) {}
729
730    /// Finalize power-down flags, apply configuration based on the flags.
731    pub(crate) fn apply(&mut self) {
732        let lp_slow_uses_xtal32k = ClockTree::with(|clocks| {
733            matches!(
734                clocks::lp_slow_clk_config(clocks),
735                Some(LpSlowClkConfig::Xtal32k)
736            )
737        });
738
739        if self.deep {
740            // force-disable certain power domains
741            self.pd_flags.set_pd_top(true);
742            self.pd_flags.set_pd_vddsdio(true);
743            self.pd_flags.set_pd_modem(true);
744            self.pd_flags.set_pd_hp_periph(true);
745            self.pd_flags.set_pd_cpu(true);
746            self.pd_flags.set_pd_mem(true);
747            self.pd_flags.set_pd_xtal(true);
748            self.pd_flags.set_pd_hp_aon(true);
749            self.pd_flags.set_pd_lp_periph(true);
750            self.pd_flags.set_pd_xtal32k(!lp_slow_uses_xtal32k);
751            self.pd_flags.set_pd_rc32k(true);
752            self.pd_flags.set_pd_rc_fast(true);
753        } else {
754            // Light sleep: the digital domain (CPU, RAM, peripherals) stays powered
755            // and only clock-gated, so execution resumes in place. To cut power we
756            // turn off the analog clock sources that nothing needs while the core is
757            // gated. Powering down XTAL also makes the analog config drop the HP
758            // regulator to the 0.6 V light-sleep voltage instead of holding it at the
759            // active calibration voltage (see `AnalogSleepConfig::defaults_light_sleep`),
760            // which is the dominant saving.
761            self.pd_flags.set_pd_xtal(true);
762            self.pd_flags.set_pd_rc_fast(true);
763            self.pd_flags.set_pd_xtal32k(!lp_slow_uses_xtal32k);
764        }
765    }
766
767    /// Configures the wakeup options and requests the sleep.
768    ///
769    /// The caller waits for the result of the request. The return value is a guard that restores
770    /// what sleep entry changed for the sleep only, so the caller keeps it until the sleep ends.
771    pub(crate) fn start_sleep(&self, wakeup_mask: u32, reject_mask: u32) -> impl Sized {
772        let restore_clock_config = ClockTree::with(|clocks| {
773            let old_root = clocks.hp_root_clk();
774
775            clocks::configure_hp_root_clk(clocks, HpRootClkConfig::Xtal);
776
777            // Restore the old clock settings when we return
778            DropGuard::new((), move |_| {
779                ClockTree::with(|clocks| {
780                    if let Some(old_root) = old_root {
781                        clocks::configure_hp_root_clk(clocks, old_root);
782                    }
783                });
784            })
785        });
786
787        // pmu_sleep_config_default + pmu_sleep_init.
788
789        let power = PowerSleepConfig::defaults(self.pd_flags);
790        power.apply();
791
792        // Needs to happen after rtc_clk_cpu_freq_set_xtal
793        let config = if self.deep {
794            SleepTimeConfig::deep_sleep()
795        } else {
796            SleepTimeConfig::light_sleep(self.pd_flags)
797        };
798
799        let mut param =
800            ParamSleepConfig::defaults(config, self.pd_flags, power.hp_sys.xtal.xpd_xtal());
801
802        if self.deep {
803            const PMU_LP_ANALOG_WAIT_TARGET_TIME_DSLP_US: u32 = 500;
804            param.lp_sys.analog_wait_target_cycle =
805                config.us_to_slowclk(PMU_LP_ANALOG_WAIT_TARGET_TIME_DSLP_US) as u8;
806
807            AnalogSleepConfig::defaults_deep_sleep().apply();
808        } else {
809            AnalogSleepConfig::defaults_light_sleep(self.pd_flags).apply();
810            DigitalSleepConfig::defaults_light_sleep(self.pd_flags).apply();
811        }
812
813        param.apply();
814
815        // like esp-idf pmu_sleep_start()
816
817        // lp_aon_hal_inform_wakeup_type - tells ROM which wakeup stub to run
818        LP_AON::regs()
819            .store9()
820            .modify(|r, w| unsafe { w.bits(r.bits() & !0x01 | self.deep as u32) });
821
822        // pmu_ll_hp_set_wakeup_enable
823        PMU::regs()
824            .slp_wakeup_cntl2()
825            .write(|w| unsafe { w.bits(wakeup_mask) });
826
827        // pmu_ll_hp_set_reject_enable
828        PMU::regs().slp_wakeup_cntl1().modify(|_, w| unsafe {
829            w.slp_reject_en().bit(reject_mask != 0);
830            w.sleep_reject_ena().bits(reject_mask)
831        });
832
833        // pmu_ll_hp_clear_reject_cause
834        PMU::regs()
835            .slp_wakeup_cntl4()
836            .write(|w| w.slp_reject_cause_clr().bit(true));
837
838        PMU::regs().int_clr().write(|w| {
839            // pmu_ll_hp_clear_sw_intr_status
840            w.sw().clear_bit_by_one();
841            // pmu_ll_hp_clear_reject_intr_status
842            w.soc_sleep_reject().clear_bit_by_one();
843            // pmu_ll_hp_clear_wakeup_intr_status
844            w.soc_wakeup().clear_bit_by_one()
845        });
846
847        // misc_modules_sleep_prepare
848
849        // Start entry into sleep mode
850
851        // pmu_ll_hp_set_sleep_enable
852        PMU::regs()
853            .slp_wakeup_cntl0()
854            .write(|w| w.sleep_req().bit(true));
855
856        restore_clock_config
857    }
858
859    /// Cleans up after sleep
860    pub(crate) fn finish_sleep(&self) {
861        // like esp-idf pmu_sleep_finish()
862        // In "pd_cpu lightsleep" and "deepsleep" modes we never get here
863
864        // The post-wake hook of the GPIO driver releases the pads that the sleep armed. Only that
865        // driver knows which pads it prepared.
866    }
867}