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