Skip to main content

esp_hal/rtc_cntl/sleep/
esp32c6.rs

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