Skip to main content

esp_hal/rtc_cntl/sleep/
esp32s31.rs

1//! Light- and deep-sleep support for the ESP32-S31.
2use core::ops::Not;
3
4use crate::{
5    peripherals::{LP_SYS as LP_AON, PMU},
6    private::DropGuard,
7    rtc_cntl::{
8        Rtc,
9        rtc::{HpAnalog, HpSysCntlReg, HpSysPower, LpAnalog, LpSysPower},
10        sleep::{
11            SleepKind,
12            pmu_common::{SleepTimeConfig, request_sleep},
13        },
14    },
15    soc::{
16        clocks::{self, ClockTree, CpuRootClkConfig},
17        xtal32k,
18    },
19};
20
21const HP_CALI_DBIAS: u8 = 26;
22const LP_CALI_DBIAS: u8 = 26;
23
24/// Configuration for controlling analog behavior during sleep.
25#[derive(Clone, Copy)]
26pub struct AnalogSleepConfig {
27    /// High-power system analog configuration.
28    pub hp_sys: HpAnalog,
29    /// Low-power system analog configuration.
30    pub lp_sys_sleep: LpAnalog,
31}
32
33impl AnalogSleepConfig {
34    fn defaults_deep_sleep() -> Self {
35        // PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT
36        Self {
37            hp_sys: {
38                let mut cfg = HpAnalog::default();
39                cfg.bias.set_pd_cur(true);
40                cfg.bias.set_bias_sleep(true);
41                cfg.regulator0.set_xpd(false);
42                cfg.bias.set_dbg_atten(0);
43                cfg
44            },
45            lp_sys_sleep: {
46                let mut cfg = LpAnalog::default();
47                cfg.regulator1.set_drv_b(0);
48                cfg.bias.set_pd_cur(true);
49                cfg.bias.set_bias_sleep(true);
50                cfg.regulator0.set_slp_xpd(false);
51                cfg.regulator0.set_slp_dbias(0);
52                cfg.regulator0.set_xpd(true);
53                cfg.bias.set_dbg_atten(12);
54                cfg.regulator0.set_dbias(23);
55                cfg
56            },
57        }
58    }
59
60    fn defaults_light_sleep(pd_flags: PowerDownFlags) -> Self {
61        let mut this = Self {
62            hp_sys: {
63                let mut cfg = HpAnalog::default();
64                cfg.regulator1.set_drv_b(0);
65                cfg.bias.set_pd_cur(true);
66                cfg.bias.set_bias_sleep(true);
67                cfg.regulator0.set_xpd(true);
68                cfg.bias.set_dbg_atten(0);
69                cfg.regulator0.set_dbias(1);
70                cfg
71            },
72            lp_sys_sleep: {
73                let mut cfg = LpAnalog::default();
74                cfg.regulator1.set_drv_b(0);
75                cfg.bias.set_pd_cur(true);
76                cfg.bias.set_bias_sleep(true);
77                cfg.regulator0.set_slp_xpd(false);
78                cfg.regulator0.set_slp_dbias(0);
79                cfg.regulator0.set_xpd(true);
80                cfg.bias.set_dbg_atten(0);
81                cfg.regulator0.set_dbias(12);
82                cfg
83            },
84        };
85
86        if !pd_flags.pd_xtal() {
87            this.hp_sys.bias.set_pd_cur(false);
88            this.lp_sys_sleep.bias.set_pd_cur(false);
89        }
90
91        if !pd_flags.pd_xtal() || !pd_flags.pd_rc_fast() {
92            this.hp_sys.bias.set_dbg_atten(0);
93            this.hp_sys.regulator0.set_dbias(HP_CALI_DBIAS);
94            this.lp_sys_sleep.bias.set_dbg_atten(0);
95            this.lp_sys_sleep.regulator0.set_dbias(LP_CALI_DBIAS);
96        }
97
98        this
99    }
100
101    fn apply(&self) {
102        // pmu_sleep_analog_init
103        PMU::regs().hp_sleep_bias().modify(|_, w| unsafe {
104            w.hp_sleep_dbg_atten().bits(self.hp_sys.bias.dbg_atten());
105            w.hp_sleep_pd_cur().bit(self.hp_sys.bias.pd_cur());
106            w.sleep().bit(self.hp_sys.bias.bias_sleep())
107        });
108        PMU::regs().hp_sleep_hp_regulator0().modify(|_, w| unsafe {
109            w.hp_sleep_hp_regulator_slp_mem_xpd()
110                .bit(self.hp_sys.regulator0.slp_mem_xpd());
111            w.hp_sleep_hp_regulator_slp_logic_xpd()
112                .bit(self.hp_sys.regulator0.slp_logic_xpd());
113            w.hp_sleep_hp_regulator_xpd()
114                .bit(self.hp_sys.regulator0.xpd());
115            w.hp_sleep_hp_regulator_slp_logic_dbias()
116                .bits(self.hp_sys.regulator0.slp_logic_dbias());
117            w.hp_sleep_hp_regulator_dbias()
118                .bits(self.hp_sys.regulator0.dbias())
119        });
120        PMU::regs().hp_sleep_hp_regulator1().modify(|_, w| unsafe {
121            w.hp_sleep_hp_regulator_drv_b()
122                .bits(self.hp_sys.regulator1.drv_b())
123        });
124
125        PMU::regs().lp_sleep_bias().modify(|_, w| unsafe {
126            w.lp_sleep_dbg_atten()
127                .bits(self.lp_sys_sleep.bias.dbg_atten());
128            w.lp_sleep_pd_cur().bit(self.lp_sys_sleep.bias.pd_cur());
129            w.sleep().bit(self.lp_sys_sleep.bias.bias_sleep())
130        });
131        PMU::regs().lp_sleep_lp_regulator0().modify(|_, w| unsafe {
132            w.lp_sleep_lp_regulator_slp_xpd()
133                .bit(self.lp_sys_sleep.regulator0.slp_xpd());
134            w.lp_sleep_lp_regulator_xpd()
135                .bit(self.lp_sys_sleep.regulator0.xpd());
136            w.lp_sleep_lp_regulator_slp_dbias()
137                .bits(self.lp_sys_sleep.regulator0.slp_dbias());
138            w.lp_sleep_lp_regulator_dbias()
139                .bits(self.lp_sys_sleep.regulator0.dbias())
140        });
141        PMU::regs().lp_sleep_lp_regulator1().modify(|_, w| unsafe {
142            w.lp_sleep_lp_regulator_drv_b()
143                .bits(self.lp_sys_sleep.regulator1.drv_b())
144        });
145    }
146}
147
148/// Configuration for digital peripherals during sleep.
149#[derive(Clone, Copy)]
150pub struct DigitalSleepConfig {
151    /// High-power system control register configuration.
152    pub syscntl: HpSysCntlReg,
153}
154
155impl DigitalSleepConfig {
156    fn defaults_deep_sleep(pd_flags: PowerDownFlags) -> Self {
157        let mut syscntl = HpSysCntlReg::default();
158        syscntl.set_dig_pad_slp_sel(false);
159        syscntl.set_lp_pad_hold_all(true);
160        syscntl.set_hp_pad_hold_all(true);
161        syscntl.set_dig_pause_wdt(true);
162        syscntl.set_c_channel(!pd_flags.pd_top());
163        Self { syscntl }
164    }
165
166    fn defaults_light_sleep(pd_flags: PowerDownFlags) -> Self {
167        let mut syscntl = HpSysCntlReg::default();
168        syscntl.set_dig_pad_slp_sel(!pd_flags.pd_top());
169        syscntl.set_lp_pad_hold_all(pd_flags.pd_top());
170        syscntl.set_hp_pad_hold_all(pd_flags.pd_top());
171        syscntl.set_dig_pause_wdt(true);
172        syscntl.set_c_channel(!pd_flags.pd_top());
173        Self { syscntl }
174    }
175
176    fn apply(&self) {
177        PMU::regs().hp_sleep_hp_sys_cntl().modify(|_, w| {
178            w.hp_sleep_c_channel().bit(self.syscntl.c_channel());
179            w.hp_sleep_dig_pad_slp_sel()
180                .bit(self.syscntl.dig_pad_slp_sel());
181            w.hp_sleep_lp_pad_hold_all()
182                .bit(self.syscntl.lp_pad_hold_all());
183            w.hp_sleep_hp_pad_hold_all()
184                .bit(self.syscntl.hp_pad_hold_all());
185            w.hp_sleep_dig_pause_wdt().bit(self.syscntl.dig_pause_wdt());
186            w.hp_sleep_dig_cpu_stall().bit(true)
187        });
188    }
189}
190
191/// Configuration of HP and LP power domains during sleep.
192#[derive(Clone, Copy)]
193pub struct PowerSleepConfig {
194    /// Power configuration for the high-power system during sleep.
195    pub hp_sys: HpSysPower,
196    /// Power configuration for the low-power system when it is active.
197    pub lp_sys_active: LpSysPower,
198    /// Power configuration for the low-power system when it is in sleep mode.
199    pub lp_sys_sleep: LpSysPower,
200}
201
202impl PowerSleepConfig {
203    fn defaults(pd_flags: PowerDownFlags) -> Self {
204        let mut this = Self {
205            hp_sys: HpSysPower::default(),
206            lp_sys_active: LpSysPower::default(),
207            lp_sys_sleep: LpSysPower::default(),
208        };
209        this.apply_flags(pd_flags);
210        this
211    }
212
213    fn apply_flags(&mut self, pd_flags: PowerDownFlags) {
214        // PMU_SLEEP_POWER_CONFIG_DEFAULT
215        self.hp_sys
216            .dig_power
217            .set_vdd_spi_pd_en(pd_flags.pd_vddsdio());
218        self.hp_sys
219            .dig_power
220            .set_hp_alive_pd_en(pd_flags.pd_mem() || pd_flags.pd_hp_aon());
221        self.hp_sys
222            .dig_power
223            .set_modem_top_pd_en(pd_flags.pd_modem());
224        self.hp_sys.dig_power.set_hp_cnnt_pd_en(pd_flags.pd_modem());
225        self.hp_sys.dig_power.set_hp_cpu_pd_en(pd_flags.pd_cpu());
226        self.hp_sys.dig_power.set_modem_pwr_pd_en(pd_flags.pd_mem());
227        self.hp_sys.dig_power.set_top_pd_en(pd_flags.pd_top());
228
229        self.hp_sys.clk.set_i2c_iso_en(true);
230        self.hp_sys.clk.set_i2c_retention(true);
231
232        self.hp_sys.xtal.set_xpd_xtal(pd_flags.pd_xtal().not());
233
234        self.lp_sys_active
235            .clk_power
236            .set_xpd_xtal32k(pd_flags.pd_xtal32k().not());
237        self.lp_sys_active
238            .clk_power
239            .set_xpd_rc32k(pd_flags.pd_rc32k().not());
240        self.lp_sys_active.clk_power.set_xpd_fosc(true);
241
242        self.lp_sys_sleep
243            .dig_power
244            .set_peri_pd_en(pd_flags.pd_lp_periph());
245
246        self.lp_sys_sleep
247            .clk_power
248            .set_xpd_xtal32k(pd_flags.pd_xtal32k().not());
249        self.lp_sys_sleep
250            .clk_power
251            .set_xpd_rc32k(pd_flags.pd_rc32k().not());
252        self.lp_sys_sleep
253            .clk_power
254            .set_xpd_fosc(pd_flags.pd_rc_fast().not());
255
256        self.lp_sys_sleep
257            .xtal
258            .set_xpd_xtal(pd_flags.pd_xtal().not());
259    }
260
261    fn apply(&self, dslp: bool) {
262        // pmu_sleep_power_init
263        PMU::regs()
264            .hp_sleep_dig_power()
265            .modify(|_, w| unsafe { w.bits(self.hp_sys.dig_power.0) });
266        PMU::regs()
267            .hp_sleep_hp_ck_power()
268            .modify(|_, w| unsafe { w.bits(self.hp_sys.clk.0) });
269        PMU::regs()
270            .hp_sleep_xtal()
271            .modify(|_, w| w.hp_sleep_xpd_xtal().bit(self.hp_sys.xtal.xpd_xtal()));
272
273        set_memory_power_on_mask(!dslp);
274
275        PMU::regs()
276            .hp_sleep_lp_dig_power()
277            .modify(|_, w| unsafe { w.bits(self.lp_sys_active.dig_power.0) });
278        PMU::regs()
279            .hp_sleep_lp_ck_power()
280            .modify(|_, w| unsafe { w.bits(self.lp_sys_active.clk_power.0) });
281
282        PMU::regs()
283            .lp_sleep_lp_dig_power()
284            .modify(|_, w| unsafe { w.bits(self.lp_sys_sleep.dig_power.0) });
285        PMU::regs()
286            .lp_sleep_lp_ck_power()
287            .modify(|_, w| unsafe { w.bits(self.lp_sys_sleep.clk_power.0) });
288        PMU::regs()
289            .lp_sleep_xtal()
290            .modify(|_, w| w.lp_sleep_xpd_xtal().bit(self.lp_sys_sleep.xtal.xpd_xtal()));
291    }
292}
293
294fn set_memory_power_on_mask(keep_on: bool) {
295    // pmu_ll_hp_set_memory_power_on_mask: 0 in deep sleep, 0xf in light sleep.
296    let mask = if keep_on { 0x1f } else { 0 };
297    PMU::regs().power_pd_mem_mask().modify(|_, w| unsafe {
298        w.pd_hp_mem0_mask().bits(mask);
299        w.pd_hp_mem1_mask().bits(mask);
300        w.pd_hp_mem2_mask().bits(mask)
301    });
302    PMU::regs().power_pd_mem_cntl().modify(|r, w| unsafe {
303        let mut pu = r.force_hp_mem_pu().bits();
304        if keep_on {
305            pu |= 1 << 3;
306        } else {
307            pu &= !(1 << 3);
308        }
309        w.force_hp_mem_pu().bits(pu)
310    });
311}
312
313/// High-power system sleep timing parameters.
314#[derive(Clone, Copy, Default)]
315pub struct HpParam {
316    analog_wait_target_cycle: u16,
317    digital_power_supply_wait_cycle: u16,
318    digital_power_up_wait_cycle: u16,
319    pll_stable_wait_cycle: u16,
320    modem_wakeup_wait_cycle: u32,
321    isolate_wait_cycle: u8,
322    reset_wait_cycle: u8,
323    min_slp_slow_clk_cycle: u8,
324}
325
326/// Low-power system sleep timing parameters.
327#[derive(Clone, Copy, Default)]
328pub struct LpParam {
329    digital_power_supply_wait_cycle: u16,
330    min_slp_slow_clk_cycle: u8,
331    analog_wait_target_cycle: u8,
332    digital_power_up_wait_cycle: u8,
333    isolate_wait_cycle: u8,
334    reset_wait_cycle: u8,
335}
336
337/// Shared HP/LP sleep timing parameters.
338#[derive(Clone, Copy, Default)]
339pub struct HpLpParam {
340    xtal_stable_wait_cycle: u16,
341}
342
343/// Sleep timing parameter configuration.
344#[derive(Clone, Copy)]
345pub struct ParamSleepConfig {
346    hp_sys: HpParam,
347    lp_sys: LpParam,
348    hp_lp: HpLpParam,
349}
350
351impl ParamSleepConfig {
352    fn apply(&self) {
353        // pmu_sleep_param_init
354        PMU::regs().slp_wakeup_cntl3().modify(|_, w| unsafe {
355            w.hp_min_slp_val().bits(self.hp_sys.min_slp_slow_clk_cycle);
356            w.lp_min_slp_val().bits(self.lp_sys.min_slp_slow_clk_cycle)
357        });
358
359        PMU::regs().slp_wakeup_cntl7().modify(|_, w| unsafe {
360            w.ana_wait_target()
361                .bits(self.hp_sys.analog_wait_target_cycle)
362        });
363
364        PMU::regs().power_wait_timer0().modify(|_, w| unsafe {
365            w.dg_hp_pd_wait_timer()
366                .bits(self.hp_sys.digital_power_supply_wait_cycle);
367            w.dg_hp_powerup_timer()
368                .bits(self.hp_sys.digital_power_up_wait_cycle)
369        });
370
371        PMU::regs().power_wait_timer1().modify(|_, w| unsafe {
372            w.dg_lp_pd_wait_timer()
373                .bits(self.lp_sys.digital_power_supply_wait_cycle);
374            w.dg_lp_powerup_timer()
375                .bits(self.lp_sys.digital_power_up_wait_cycle)
376        });
377
378        PMU::regs().power_wait_timer2().modify(|_, w| unsafe {
379            w.dg_hp_iso_wait_timer()
380                .bits(self.hp_sys.isolate_wait_cycle);
381            w.dg_hp_rst_wait_timer().bits(self.hp_sys.reset_wait_cycle);
382            w.dg_lp_iso_wait_timer()
383                .bits(self.lp_sys.isolate_wait_cycle);
384            w.dg_lp_rst_wait_timer().bits(self.lp_sys.reset_wait_cycle)
385        });
386
387        PMU::regs().slp_wakeup_cntl5().modify(|_, w| unsafe {
388            w.lp_ana_wait_target()
389                .bits(self.lp_sys.analog_wait_target_cycle);
390            w.modem_wait_target()
391                .bits(self.hp_sys.modem_wakeup_wait_cycle)
392        });
393
394        PMU::regs().power_ck_wait_cntl().modify(|_, w| unsafe {
395            w.pmu_wait_xtl_stable()
396                .bits(self.hp_lp.xtal_stable_wait_cycle);
397            w.pmu_wait_pll_stable()
398                .bits(self.hp_sys.pll_stable_wait_cycle)
399        });
400    }
401
402    fn defaults(config: SleepTimeConfig, pd_flags: PowerDownFlags, xpd_xtal: bool) -> Self {
403        let hw_wait_time_us = config.pmu_sleep_calculate_hw_wait_time(pd_flags);
404        let modem_wakeup_wait_time_us = (config.sleep_time_adjustment
405            + MachineConstants::MODEM_STATE_SKIP_TIME_US
406            + MachineConstants::HP_REGDMA_RF_ON_WORK_TIME_US)
407            .saturating_sub(hw_wait_time_us);
408
409        let hp_sys = HpParam {
410            min_slp_slow_clk_cycle: config.us_to_slowclk(MachineConstants::HP_MIN_SLP_TIME_US)
411                as u8,
412            analog_wait_target_cycle: config.us_to_fastclk(MachineConstants::HP_ANALOG_WAIT_TIME_US)
413                as u16,
414            digital_power_supply_wait_cycle: config
415                .us_to_fastclk(MachineConstants::HP_POWER_SUPPLY_WAIT_TIME_US)
416                as u16,
417            digital_power_up_wait_cycle: config
418                .us_to_fastclk(MachineConstants::HP_POWER_UP_WAIT_TIME_US)
419                as u16,
420            pll_stable_wait_cycle: config
421                .us_to_fastclk(MachineConstants::HP_PLL_WAIT_STABLE_TIME_US)
422                as u16,
423            modem_wakeup_wait_cycle: config.us_to_fastclk(modem_wakeup_wait_time_us),
424            isolate_wait_cycle: config.us_to_fastclk(MachineConstants::HP_ISOLATE_WAIT_TIME_US)
425                as u8,
426            reset_wait_cycle: config.us_to_fastclk(MachineConstants::HP_RESET_WAIT_TIME_US) as u8,
427        };
428
429        let lp_sys = LpParam {
430            min_slp_slow_clk_cycle: config.us_to_slowclk(MachineConstants::LP_MIN_SLP_TIME_US)
431                as u8,
432            analog_wait_target_cycle: config.us_to_slowclk(MachineConstants::LP_ANALOG_WAIT_TIME_US)
433                as u8,
434            digital_power_supply_wait_cycle: config
435                .us_to_fastclk(MachineConstants::LP_POWER_SUPPLY_WAIT_TIME_US)
436                as u16,
437            digital_power_up_wait_cycle: config
438                .us_to_fastclk(MachineConstants::LP_POWER_UP_WAIT_TIME_US)
439                as u8,
440            isolate_wait_cycle: config.us_to_fastclk(MachineConstants::LP_ISOLATE_WAIT_TIME_US)
441                as u8,
442            reset_wait_cycle: config.us_to_fastclk(MachineConstants::LP_RESET_WAIT_TIME_US) as u8,
443        };
444
445        let xtal_stable_wait_cycle = if xpd_xtal {
446            config.us_to_slowclk(MachineConstants::LP_XTAL_WAIT_STABLE_TIME_US) as u16
447        } else {
448            config.us_to_fastclk(MachineConstants::HP_XTAL_WAIT_STABLE_TIME_US) as u16
449        };
450
451        Self {
452            hp_sys,
453            lp_sys,
454            hp_lp: HpLpParam {
455                xtal_stable_wait_cycle,
456            },
457        }
458    }
459}
460
461impl SleepTimeConfig {
462    pub(crate) const CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ: u32 = 160;
463    pub(crate) const LIGHT_SLEEP_TIME_OVERHEAD_US: u32 = 780;
464
465    pub(crate) fn pmu_sleep_calculate_hw_wait_time(&self, pd_flags: PowerDownFlags) -> u32 {
466        let lp_wakeup_wait_time_us = self.slowclk_to_us(MachineConstants::LP_WAKEUP_WAIT_CYCLE);
467        let lp_clk_switch_time_us = self.slowclk_to_us(MachineConstants::LP_CLK_SWITCH_CYCLE);
468        let lp_clk_power_on_wait_time_us =
469            self.slowclk_to_us(MachineConstants::LP_CLK_POWER_ON_WAIT_CYCLE);
470        let lp_control_wait_time_us =
471            MachineConstants::LP_ISOLATE_WAIT_TIME_US + MachineConstants::LP_RESET_WAIT_TIME_US;
472
473        let lp_hw_wait_time_us = MachineConstants::LP_MIN_SLP_TIME_US
474            + MachineConstants::LP_ANALOG_WAIT_TIME_US
475            + lp_clk_power_on_wait_time_us
476            + lp_wakeup_wait_time_us
477            + lp_clk_switch_time_us
478            + MachineConstants::LP_POWER_SUPPLY_WAIT_TIME_US
479            + MachineConstants::LP_POWER_UP_WAIT_TIME_US
480            + lp_control_wait_time_us;
481
482        let hp_digital_power_up_wait_time_us = MachineConstants::HP_POWER_SUPPLY_WAIT_TIME_US
483            + MachineConstants::HP_POWER_UP_WAIT_TIME_US;
484        let hp_control_wait_time_us =
485            MachineConstants::HP_ISOLATE_WAIT_TIME_US + MachineConstants::HP_RESET_WAIT_TIME_US;
486        // The sleep backs up no register with REGDMA, so the wake needs no restore time.
487        let hp_regdma_wait_time_us = 0;
488        let hp_clock_wait_time_us = if pd_flags.pd_xtal() {
489            MachineConstants::HP_XTAL_WAIT_STABLE_TIME_US
490                + MachineConstants::HP_PLL_WAIT_STABLE_TIME_US
491        } else {
492            MachineConstants::HP_PLL_WAIT_STABLE_TIME_US
493        };
494
495        let hp_hw_wait_time_us = MachineConstants::HP_ANALOG_WAIT_TIME_US
496            + hp_digital_power_up_wait_time_us
497            + hp_regdma_wait_time_us
498            + hp_clock_wait_time_us
499            + hp_control_wait_time_us;
500
501        lp_hw_wait_time_us + hp_hw_wait_time_us
502    }
503}
504
505/// Configuration for the RTC sleep behavior.
506#[derive(Clone, Copy)]
507pub struct RtcSleepConfig {
508    /// Deep sleep flag.
509    pub deep: bool,
510    /// Power-down flags.
511    pub pd_flags: PowerDownFlags,
512}
513
514impl Default for RtcSleepConfig {
515    fn default() -> Self {
516        Self {
517            deep: false,
518            pd_flags: PowerDownFlags(0),
519        }
520    }
521}
522
523bitfield::bitfield! {
524    #[derive(Clone, Copy)]
525    /// Power domains to be powered down during sleep.
526    pub struct PowerDownFlags(u32);
527
528    /// Controls the power-down status of the top power domain.
529    pub u32, pd_top      , set_pd_top      : 0;
530    /// Controls the power-down status of the VDD_SDIO power domain.
531    pub u32, pd_vddsdio  , set_pd_vddsdio  : 1;
532    /// Controls the power-down status of the modem / connectivity power domain.
533    pub u32, pd_modem    , set_pd_modem    : 2;
534    /// Controls the power-down status of the high-performance peripheral power domain.
535    pub u32, pd_hp_periph, set_pd_hp_periph: 3;
536    /// Controls the power-down status of the CPU power domain.
537    ///
538    /// Crate-private, because a light sleep needs CPU retention to power this domain down. A
539    /// power-down without retention loses the CPU state.
540    pub(crate) u32, pd_cpu, set_pd_cpu: 4;
541    /// Controls the power-down status of the high-performance always-on domain.
542    pub u32, pd_hp_aon   , set_pd_hp_aon   : 5;
543    /// Controls the power-down status of memory group 0.
544    pub u32, pd_mem_g0   , set_pd_mem_g0   : 6;
545    /// Controls the power-down status of memory group 1.
546    pub u32, pd_mem_g1   , set_pd_mem_g1   : 7;
547    /// Controls the power-down status of memory group 2.
548    pub u32, pd_mem_g2   , set_pd_mem_g2   : 8;
549    /// Controls the power-down status of memory group 3.
550    pub u32, pd_mem_g3   , set_pd_mem_g3   : 9;
551    /// Controls the power-down status of the crystal oscillator.
552    pub u32, pd_xtal     , set_pd_xtal     : 10;
553    /// Controls the power-down status of the fast RC oscillator.
554    pub u32, pd_rc_fast  , set_pd_rc_fast  : 11;
555    /// Controls the power-down status of the 32 kHz crystal oscillator.
556    pub u32, pd_xtal32k  , set_pd_xtal32k  : 12;
557    /// Controls the power-down status of the 32 kHz RC oscillator.
558    pub u32, pd_rc32k    , set_pd_rc32k    : 13;
559    /// Controls the power-down status of the low-power peripheral domain.
560    pub u32, pd_lp_periph, set_pd_lp_periph: 14;
561}
562
563impl PowerDownFlags {
564    /// Returns whether all memory groups are powered down.
565    pub fn pd_mem(self) -> bool {
566        self.pd_mem_g0() && self.pd_mem_g1() && self.pd_mem_g2() && self.pd_mem_g3()
567    }
568
569    /// Sets the power-down status for all memory groups at once.
570    pub fn set_pd_mem(&mut self, value: bool) {
571        self.set_pd_mem_g0(value);
572        self.set_pd_mem_g1(value);
573        self.set_pd_mem_g2(value);
574        self.set_pd_mem_g3(value);
575    }
576}
577
578// Constants from `PMU_SLEEP_MC_DEFAULT()` in esp-idf pmu_param.h.
579struct MachineConstants;
580impl MachineConstants {
581    const LP_MIN_SLP_TIME_US: u32 = 450;
582    const LP_WAKEUP_WAIT_CYCLE: u32 = 4;
583    const LP_ANALOG_WAIT_TIME_US: u32 = 154;
584    const LP_XTAL_WAIT_STABLE_TIME_US: u32 = 250;
585    const LP_CLK_SWITCH_CYCLE: u32 = 1;
586    const LP_CLK_POWER_ON_WAIT_CYCLE: u32 = 1;
587    const LP_ISOLATE_WAIT_TIME_US: u32 = 1;
588    const LP_RESET_WAIT_TIME_US: u32 = 1;
589    const LP_POWER_SUPPLY_WAIT_TIME_US: u32 = 2;
590    const LP_POWER_UP_WAIT_TIME_US: u32 = 2;
591
592    const HP_MIN_SLP_TIME_US: u32 = 450;
593    const HP_ANALOG_WAIT_TIME_US: u32 = 154;
594    const HP_ISOLATE_WAIT_TIME_US: u32 = 1;
595    const HP_RESET_WAIT_TIME_US: u32 = 1;
596    const HP_POWER_SUPPLY_WAIT_TIME_US: u32 = 2;
597    const HP_POWER_UP_WAIT_TIME_US: u32 = 2;
598    const HP_REGDMA_M2A_WORK_TIME_US: u32 = 278;
599    const HP_REGDMA_RF_ON_WORK_TIME_US: u32 = 70;
600    const HP_SYSTEM_DFS_UP_WORK_TIME_US: u32 = 124;
601    const HP_XTAL_WAIT_STABLE_TIME_US: u32 = 250;
602    const HP_PLL_WAIT_STABLE_TIME_US: u32 = 50;
603
604    const MODEM_STATE_SKIP_TIME_US: u32 = Self::HP_REGDMA_M2A_WORK_TIME_US
605        + Self::HP_SYSTEM_DFS_UP_WORK_TIME_US
606        + Self::LP_MIN_SLP_TIME_US;
607}
608
609impl RtcSleepConfig {
610    /// Returns whether the device is in deep sleep mode.
611    pub fn deep_slp(&self) -> bool {
612        self.deep
613    }
614
615    /// Configures the device for deep sleep mode.
616    pub fn deep() -> Self {
617        Self {
618            deep: true,
619            ..Self::default()
620        }
621    }
622
623    pub(crate) fn is_deep_sleep(&self) -> bool {
624        self.deep
625    }
626
627    pub(crate) fn base_settings(_rtc: &Rtc<'_>) {}
628
629    /// Selects the kind of the sleep, and what the sleep powers down.
630    ///
631    /// Sleep entry calls this before the hooks of the wakeup sources, so that a source can keep
632    /// powered what it needs.
633    pub(crate) fn set_sleep_kind(&mut self, kind: SleepKind) {
634        self.deep = kind == SleepKind::Deep;
635
636        let lp_slow_uses_xtal32k = cfg_select! {
637            use_xtal32k => ClockTree::with(|clocks| {
638                matches!(
639                    clocks::lp_slow_clk_config(clocks),
640                    Some(clocks::LpSlowClkConfig::Xtal32k)
641                )
642            }),
643            _ => false,
644        };
645
646        if self.deep {
647            self.pd_flags.set_pd_top(true);
648            self.pd_flags.set_pd_vddsdio(true);
649            self.pd_flags.set_pd_modem(true);
650            self.pd_flags.set_pd_hp_periph(true);
651            self.pd_flags.set_pd_cpu(true);
652            self.pd_flags.set_pd_mem(true);
653            self.pd_flags.set_pd_xtal(true);
654            self.pd_flags.set_pd_hp_aon(true);
655            self.pd_flags.set_pd_lp_periph(true);
656            self.pd_flags.set_pd_xtal32k(!lp_slow_uses_xtal32k);
657            self.pd_flags.set_pd_rc32k(true);
658            self.pd_flags.set_pd_rc_fast(true);
659        } else {
660            self.pd_flags.set_pd_xtal(true);
661            self.pd_flags.set_pd_rc_fast(true);
662            self.pd_flags
663                .set_pd_xtal32k(!lp_slow_uses_xtal32k && !xtal32k::use_xtal32k());
664        }
665    }
666
667    /// Configures the wakeup and reject sources of the sleep.
668    ///
669    /// [`Self::enter_sleep`] requests the sleep after this call. The return value is a guard that
670    /// restores what sleep entry changed for the sleep only, so the caller keeps it until the
671    /// sleep ends.
672    #[crate::ram]
673    pub(crate) fn start_sleep(&self, wakeup_mask: u32, reject_mask: u32) -> impl Sized {
674        let restore_clock_config = ClockTree::with(|clocks| {
675            let old_cpu_root_clk = clocks.cpu_root_clk();
676
677            clocks::configure_cpu_root_clk(clocks, CpuRootClkConfig::Xtal);
678
679            DropGuard::new((), move |_| {
680                ClockTree::with(|clocks| {
681                    if let Some(old) = old_cpu_root_clk {
682                        clocks::configure_cpu_root_clk(clocks, old);
683                    }
684                });
685            })
686        });
687
688        let power = PowerSleepConfig::defaults(self.pd_flags);
689        power.apply(self.deep);
690
691        let config = if self.deep {
692            SleepTimeConfig::deep_sleep()
693        } else {
694            SleepTimeConfig::light_sleep(self.pd_flags)
695        };
696
697        let mut param =
698            ParamSleepConfig::defaults(config, self.pd_flags, power.hp_sys.xtal.xpd_xtal());
699
700        if self.deep {
701            const PMU_LP_ANALOG_WAIT_TARGET_TIME_DSLP_US: u32 = 500;
702            param.lp_sys.analog_wait_target_cycle =
703                config.us_to_slowclk(PMU_LP_ANALOG_WAIT_TARGET_TIME_DSLP_US) as u8;
704
705            DigitalSleepConfig::defaults_deep_sleep(self.pd_flags).apply();
706            AnalogSleepConfig::defaults_deep_sleep().apply();
707        } else {
708            AnalogSleepConfig::defaults_light_sleep(self.pd_flags).apply();
709            DigitalSleepConfig::defaults_light_sleep(self.pd_flags).apply();
710        }
711
712        param.apply();
713
714        // lp_aon_hal_inform_wakeup_type: RTC_SLEEP_MODE_REG is LP_STORE8.
715        LP_AON::regs()
716            .lp_store(8)
717            .modify(|r, w| unsafe { w.bits(r.bits() & !0x01 | self.deep as u32) });
718
719        PMU::regs()
720            .slp_wakeup_cntl2()
721            .write(|w| unsafe { w.bits(wakeup_mask) });
722
723        PMU::regs()
724            .slp_wakeup_cntl1()
725            .write(|w| unsafe { w.sleep_reject_ena().bits(reject_mask) });
726
727        PMU::regs()
728            .slp_wakeup_cntl4()
729            .write(|w| w.slp_reject_cause_clr().bit(true));
730
731        PMU::regs().int_clr().write(|w| {
732            w.sw().clear_bit_by_one();
733            w.soc_sleep_reject().clear_bit_by_one();
734            w.soc_wakeup().clear_bit_by_one()
735        });
736
737        PMU::regs()
738            .slp_wakeup_cntl0()
739            .write(|w| w.slp_reject_en().bit(reject_mask != 0));
740
741        restore_clock_config
742    }
743
744    /// Requests the sleep.
745    ///
746    /// The caller waits for the result of the request.
747    #[inline(always)]
748    pub(crate) fn enter_sleep(&self) -> bool {
749        request_sleep()
750    }
751
752    /// Cleans up after sleep.
753    #[inline(always)]
754    pub(crate) fn finish_sleep(&self) {}
755}