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