Skip to main content

esp_hal/rtc_cntl/sleep/
esp32h4.rs

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