Skip to main content

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