use core::ops::Not;
use crate::{
clock::RtcClock,
gpio::RtcFunction,
rtc_cntl::{
Rtc,
rtc::{HpAnalog, HpSysCntlReg, HpSysPower, LpAnalog, LpSysPower, SavedClockConfig},
sleep::{
Ext1WakeupSource,
TimerWakeupSource,
WakeFromLpCoreWakeupSource,
WakeSource,
WakeTriggers,
WakeupLevel,
},
},
soc::clocks::{ClockTree, TimgCalibrationClockConfig},
};
impl WakeSource for TimerWakeupSource {
fn apply(
&self,
rtc: &Rtc<'_>,
triggers: &mut WakeTriggers,
_sleep_config: &mut RtcSleepConfig,
) {
triggers.set_timer(true);
let lp_timer = unsafe { &*esp32c6::LP_TIMER::ptr() };
let ticks = crate::clock::us_to_rtc_ticks(self.duration.as_micros() as u64);
let now = rtc.time_since_boot_raw();
let time_in_ticks = now + ticks;
unsafe {
lp_timer.tar0_high().write(|w| {
w.main_timer_tar_high0()
.bits(((time_in_ticks >> 32) & 0xffff) as u16)
});
lp_timer.tar0_low().write(|w| {
w.main_timer_tar_low0()
.bits((time_in_ticks & 0xffffffff) as u32)
});
lp_timer
.int_clr()
.write(|w| w.soc_wakeup().clear_bit_by_one());
lp_timer
.tar0_high()
.modify(|_, w| w.main_timer_tar_en0().set_bit());
}
}
}
impl Ext1WakeupSource<'_, '_> {
fn wakeup_pins() -> u8 {
unsafe { lp_aon().ext_wakeup_cntl().read().ext_wakeup_sel().bits() }
}
fn wake_io_reset() {
use crate::gpio::RtcPin;
fn uninit_pin(pin: impl RtcPin, wakeup_pins: u8) {
if wakeup_pins & (1 << pin.number()) != 0 {
pin.rtcio_pad_hold(false);
pin.rtc_set_config(false, false, RtcFunction::Rtc);
}
}
let wakeup_pins = Ext1WakeupSource::wakeup_pins();
uninit_pin(unsafe { crate::peripherals::GPIO0::steal() }, wakeup_pins);
uninit_pin(unsafe { crate::peripherals::GPIO1::steal() }, wakeup_pins);
uninit_pin(unsafe { crate::peripherals::GPIO2::steal() }, wakeup_pins);
uninit_pin(unsafe { crate::peripherals::GPIO3::steal() }, wakeup_pins);
uninit_pin(unsafe { crate::peripherals::GPIO4::steal() }, wakeup_pins);
uninit_pin(unsafe { crate::peripherals::GPIO5::steal() }, wakeup_pins);
uninit_pin(unsafe { crate::peripherals::GPIO6::steal() }, wakeup_pins);
uninit_pin(unsafe { crate::peripherals::GPIO7::steal() }, wakeup_pins);
}
}
impl WakeSource for Ext1WakeupSource<'_, '_> {
fn apply(
&self,
_rtc: &Rtc<'_>,
triggers: &mut WakeTriggers,
_sleep_config: &mut RtcSleepConfig,
) {
triggers.set_ext1(true);
let mut pins = self.pins.borrow_mut();
let mut pin_mask = 0u8;
let mut level_mask = 0u8;
for (pin, level) in pins.iter_mut() {
pin_mask |= 1 << pin.number();
level_mask |= match level {
WakeupLevel::High => 1 << pin.number(),
WakeupLevel::Low => 0,
};
pin.rtc_set_config(true, true, RtcFunction::Rtc);
pin.rtcio_pad_hold(true);
}
unsafe {
lp_aon()
.ext_wakeup_cntl()
.modify(|_, w| w.ext_wakeup_status_clr().set_bit());
lp_aon().ext_wakeup_cntl().modify(|r, w| {
w.ext_wakeup_sel()
.bits(r.ext_wakeup_sel().bits() | pin_mask)
.ext_wakeup_lv()
.bits(r.ext_wakeup_lv().bits() & !pin_mask | level_mask)
});
}
}
}
impl Drop for Ext1WakeupSource<'_, '_> {
fn drop(&mut self) {
let mut pins = self.pins.borrow_mut();
for (pin, _level) in pins.iter_mut() {
pin.rtc_set_config(true, false, RtcFunction::Rtc);
}
}
}
impl WakeSource for WakeFromLpCoreWakeupSource {
fn apply(
&self,
_rtc: &Rtc<'_>,
triggers: &mut WakeTriggers,
_sleep_config: &mut RtcSleepConfig,
) {
triggers.set_lp_core(true);
}
}
#[derive(Clone, Copy)]
pub struct AnalogSleepConfig {
pub hp_sys: HpAnalog,
pub lp_sys_sleep: LpAnalog,
}
impl AnalogSleepConfig {
fn defaults_deep_sleep() -> Self {
Self {
hp_sys: {
let mut cfg = HpAnalog::default();
cfg.bias.set_pd_cur(false);
cfg.bias.set_bias_sleep(false);
cfg.regulator0.set_xpd(false);
cfg.bias.set_dbg_atten(0);
cfg
},
lp_sys_sleep: {
let mut cfg = LpAnalog::default();
cfg.regulator1.set_drv_b(0);
cfg.bias.set_pd_cur(true);
cfg.bias.set_bias_sleep(true);
cfg.regulator0.set_slp_xpd(false);
cfg.regulator0.set_slp_dbias(0);
cfg.regulator0.set_xpd(true);
cfg.bias.set_dbg_atten(12);
cfg.regulator0.set_dbias(23);
cfg
},
}
}
fn defaults_light_sleep(pd_flags: PowerDownFlags) -> Self {
let mut this = Self {
hp_sys: {
let mut cfg = HpAnalog::default();
cfg.regulator1.set_drv_b(0);
cfg.bias.set_pd_cur(true);
cfg.bias.set_bias_sleep(true);
cfg.regulator0.set_xpd(true);
cfg.bias.set_dbg_atten(0);
cfg.regulator0.set_dbias(1);
cfg
},
lp_sys_sleep: {
let mut cfg = LpAnalog::default();
cfg.regulator1.set_drv_b(0);
cfg.bias.set_pd_cur(true);
cfg.bias.set_bias_sleep(true);
cfg.regulator0.set_slp_xpd(false);
cfg.regulator0.set_slp_dbias(0);
cfg.regulator0.set_xpd(true);
cfg.bias.set_dbg_atten(0);
cfg.regulator0.set_dbias(12);
cfg
},
};
if !pd_flags.pd_xtal() {
this.hp_sys.bias.set_pd_cur(false);
this.hp_sys.bias.set_bias_sleep(false);
this.hp_sys.regulator0.set_dbias(25);
this.lp_sys_sleep.bias.set_pd_cur(false);
this.lp_sys_sleep.bias.set_bias_sleep(false);
this.lp_sys_sleep.regulator0.set_dbias(26);
}
this
}
fn apply(&self) {
unsafe {
pmu().hp_sleep_bias().modify(|_, w| {
w.hp_sleep_dbg_atten() .bits(self.hp_sys.bias.dbg_atten())
.hp_sleep_pd_cur() .bit(self.hp_sys.bias.pd_cur())
.sleep() .bit(self.hp_sys.bias.bias_sleep())
});
pmu().hp_sleep_hp_regulator0().modify(|_, w| {
w.hp_sleep_hp_regulator_xpd() .bit(self.hp_sys.regulator0.xpd())
.hp_sleep_hp_regulator_dbias() .bits(self.hp_sys.regulator0.dbias())
});
pmu().hp_sleep_hp_regulator1().modify(|_, w| {
w.hp_sleep_hp_regulator_drv_b() .bits(self.hp_sys.regulator1.drv_b())
});
pmu().lp_sleep_bias().modify(|_, w| {
w.lp_sleep_dbg_atten() .bits(self.lp_sys_sleep.bias.dbg_atten())
.lp_sleep_pd_cur() .bit(self.lp_sys_sleep.bias.pd_cur())
.sleep() .bit(self.lp_sys_sleep.bias.bias_sleep())
});
pmu().lp_sleep_lp_regulator0().modify(|_, w| {
w.lp_sleep_lp_regulator_slp_xpd() .bit(self.lp_sys_sleep.regulator0.slp_xpd())
.lp_sleep_lp_regulator_xpd() .bit(self.lp_sys_sleep.regulator0.xpd())
.lp_sleep_lp_regulator_slp_dbias() .bits(self.lp_sys_sleep.regulator0.slp_dbias())
.lp_sleep_lp_regulator_dbias() .bits(self.lp_sys_sleep.regulator0.dbias())
});
pmu().lp_sleep_lp_regulator1().modify(|_, w| {
w.lp_sleep_lp_regulator_drv_b() .bits(self.lp_sys_sleep.regulator1.drv_b())
});
}
}
}
#[derive(Clone, Copy)]
pub struct DigitalSleepConfig {
pub syscntl: HpSysCntlReg,
}
impl DigitalSleepConfig {
fn defaults_light_sleep(pd_flags: PowerDownFlags) -> Self {
Self {
syscntl: {
let mut cfg = HpSysCntlReg::default();
cfg.set_dig_pad_slp_sel(pd_flags.pd_top().not());
cfg
},
}
}
fn apply(&self) {
unsafe {
pmu().hp_sleep_hp_sys_cntl().modify(|_, w| {
w.hp_sleep_dig_pad_slp_sel()
.bit(self.syscntl.dig_pad_slp_sel())
})
};
}
}
#[derive(Clone, Copy)]
pub struct PowerSleepConfig {
pub hp_sys: HpSysPower,
pub lp_sys_active: LpSysPower,
pub lp_sys_sleep: LpSysPower,
}
impl PowerSleepConfig {
fn defaults(pd_flags: PowerDownFlags) -> Self {
let mut this = Self {
hp_sys: HpSysPower::default(),
lp_sys_active: LpSysPower::default(),
lp_sys_sleep: LpSysPower::default(),
};
this.apply_flags(pd_flags);
this
}
fn apply_flags(&mut self, pd_flags: PowerDownFlags) {
self.hp_sys
.dig_power
.set_vdd_spi_pd_en(pd_flags.pd_vddsdio());
self.hp_sys.dig_power.set_wifi_pd_en(pd_flags.pd_modem());
self.hp_sys.dig_power.set_cpu_pd_en(pd_flags.pd_cpu());
self.hp_sys.dig_power.set_aon_pd_en(pd_flags.pd_hp_aon());
self.hp_sys.dig_power.set_top_pd_en(pd_flags.pd_top());
self.hp_sys.clk.set_i2c_iso_en(true);
self.hp_sys.clk.set_i2c_retention(true);
self.hp_sys.xtal.set_xpd_xtal(pd_flags.pd_xtal().not());
self.lp_sys_active.clk_power.set_xpd_xtal32k(true);
self.lp_sys_active.clk_power.set_xpd_rc32k(true);
self.lp_sys_active.clk_power.set_xpd_fosc(true);
self.lp_sys_sleep
.dig_power
.set_peri_pd_en(pd_flags.pd_lp_periph());
self.lp_sys_sleep.dig_power.set_mem_dslp(true);
self.lp_sys_sleep
.clk_power
.set_xpd_xtal32k(pd_flags.pd_xtal32k().not());
self.lp_sys_sleep
.clk_power
.set_xpd_rc32k(pd_flags.pd_rc32k().not());
self.lp_sys_sleep
.clk_power
.set_xpd_fosc(pd_flags.pd_rc_fast().not());
self.lp_sys_sleep
.xtal
.set_xpd_xtal(pd_flags.pd_xtal().not());
}
fn apply(&self) {
unsafe {
pmu()
.hp_sleep_dig_power()
.modify(|_, w| w.bits(self.hp_sys.dig_power.0));
pmu()
.hp_sleep_hp_ck_power()
.modify(|_, w| w.bits(self.hp_sys.clk.0));
pmu()
.hp_sleep_xtal()
.modify(|_, w| w.hp_sleep_xpd_xtal().bit(self.hp_sys.xtal.xpd_xtal()));
pmu()
.hp_sleep_lp_dig_power()
.modify(|_, w| w.bits(self.lp_sys_active.dig_power.0));
pmu()
.hp_sleep_lp_ck_power()
.modify(|_, w| w.bits(self.lp_sys_active.clk_power.0));
pmu()
.lp_sleep_lp_dig_power()
.modify(|_, w| w.bits(self.lp_sys_sleep.dig_power.0));
pmu()
.lp_sleep_lp_ck_power()
.modify(|_, w| w.bits(self.lp_sys_sleep.clk_power.0));
pmu()
.lp_sleep_xtal()
.modify(|_, w| w.lp_sleep_xpd_xtal().bit(self.lp_sys_sleep.xtal.xpd_xtal()));
}
}
}
#[derive(Clone, Copy)]
pub struct HpParam {
pub modem_wakeup_wait_cycle: u32,
pub analog_wait_target_cycle: u16,
pub digital_power_down_wait_cycle: u16,
pub digital_power_supply_wait_cycle: u16,
pub digital_power_up_wait_cycle: u16,
pub pll_stable_wait_cycle: u16,
pub modify_icg_cntl_wait_cycle: u8,
pub switch_icg_cntl_wait_cycle: u8,
pub min_slp_slow_clk_cycle: u8,
}
#[derive(Clone, Copy)]
pub struct LpParam {
pub digital_power_supply_wait_cycle: u16,
pub min_slp_slow_clk_cycle: u8,
pub analog_wait_target_cycle: u8,
pub digital_power_down_wait_cycle: u8,
pub digital_power_up_wait_cycle: u8,
}
#[derive(Clone, Copy)]
pub struct HpLpParam {
pub xtal_stable_wait_cycle: u16,
}
#[derive(Clone, Copy)]
pub struct ParamSleepConfig {
pub hp_sys: HpParam,
pub lp_sys: LpParam,
pub hp_lp: HpLpParam,
}
impl ParamSleepConfig {
const PMU_SLEEP_PARAM_CONFIG_DEFAULT: Self = Self {
hp_sys: HpParam {
min_slp_slow_clk_cycle: 10,
analog_wait_target_cycle: 2419,
digital_power_supply_wait_cycle: 32,
digital_power_up_wait_cycle: 32,
modem_wakeup_wait_cycle: 20700,
pll_stable_wait_cycle: 2,
digital_power_down_wait_cycle: 0,
modify_icg_cntl_wait_cycle: 0,
switch_icg_cntl_wait_cycle: 0,
},
lp_sys: LpParam {
min_slp_slow_clk_cycle: 10,
analog_wait_target_cycle: 23,
digital_power_supply_wait_cycle: 32,
digital_power_up_wait_cycle: 32,
digital_power_down_wait_cycle: 0,
},
hp_lp: HpLpParam {
xtal_stable_wait_cycle: 30,
},
};
fn apply(&self) {
unsafe {
pmu().slp_wakeup_cntl3().modify(|_, w| {
w.hp_min_slp_val() .bits(self.hp_sys.min_slp_slow_clk_cycle)
.lp_min_slp_val() .bits(self.lp_sys.min_slp_slow_clk_cycle)
});
pmu().slp_wakeup_cntl7().modify(|_, w| {
w.ana_wait_target() .bits(self.hp_sys.analog_wait_target_cycle)
});
pmu().power_wait_timer0().modify(|_, w| {
w.dg_hp_wait_timer() .bits(self.hp_sys.digital_power_supply_wait_cycle)
.dg_hp_powerup_timer() .bits(self.hp_sys.digital_power_up_wait_cycle)
});
pmu().power_wait_timer1().modify(|_, w| {
w.dg_lp_wait_timer() .bits(self.lp_sys.digital_power_supply_wait_cycle)
.dg_lp_powerup_timer() .bits(self.lp_sys.digital_power_up_wait_cycle)
});
pmu().slp_wakeup_cntl5().modify(|_, w| {
w.lp_ana_wait_target() .bits(self.lp_sys.analog_wait_target_cycle)
.modem_wait_target() .bits(self.hp_sys.modem_wakeup_wait_cycle)
});
pmu().power_ck_wait_cntl().modify(|_, w| {
w.wait_xtl_stable() .bits(self.hp_lp.xtal_stable_wait_cycle)
.wait_pll_stable() .bits(self.hp_sys.pll_stable_wait_cycle)
});
}
}
fn defaults(config: SleepTimeConfig, pd_flags: PowerDownFlags, pd_xtal: bool) -> Self {
let mut param = Self::PMU_SLEEP_PARAM_CONFIG_DEFAULT;
param.hp_sys.min_slp_slow_clk_cycle =
config.us_to_slowclk(MachineConstants::HP_MIN_SLP_TIME_US) as u8;
param.hp_sys.analog_wait_target_cycle =
config.us_to_fastclk(MachineConstants::HP_ANALOG_WAIT_TIME_US) as u16;
param.hp_sys.digital_power_supply_wait_cycle =
config.us_to_fastclk(MachineConstants::HP_POWER_SUPPLY_WAIT_TIME_US) as u16;
param.hp_sys.digital_power_up_wait_cycle =
config.us_to_fastclk(MachineConstants::HP_POWER_UP_WAIT_TIME_US) as u16;
param.hp_sys.pll_stable_wait_cycle =
config.us_to_fastclk(MachineConstants::HP_PLL_WAIT_STABLE_TIME_US) as u16;
let hw_wait_time_us = config.pmu_sleep_calculate_hw_wait_time(pd_flags);
let modem_wakeup_wait_time_us = (config.sleep_time_adjustment
+ MachineConstants::MODEM_STATE_SKIP_TIME_US
+ MachineConstants::HP_REGDMA_RF_ON_WORK_TIME_US)
.saturating_sub(hw_wait_time_us);
param.hp_sys.modem_wakeup_wait_cycle = config.us_to_fastclk(modem_wakeup_wait_time_us);
param.lp_sys.min_slp_slow_clk_cycle =
config.us_to_slowclk(MachineConstants::LP_MIN_SLP_TIME_US) as u8;
param.lp_sys.analog_wait_target_cycle =
config.us_to_slowclk(MachineConstants::LP_ANALOG_WAIT_TIME_US) as u8;
param.lp_sys.digital_power_supply_wait_cycle =
config.us_to_fastclk(MachineConstants::LP_POWER_SUPPLY_WAIT_TIME_US) as u16;
param.lp_sys.digital_power_up_wait_cycle =
config.us_to_fastclk(MachineConstants::LP_POWER_UP_WAIT_TIME_US) as u8;
param.hp_lp.xtal_stable_wait_cycle = if pd_xtal {
config.us_to_slowclk(MachineConstants::LP_XTAL_WAIT_STABLE_TIME_US) as u16
} else {
config.us_to_fastclk(MachineConstants::HP_XTAL_WAIT_STABLE_TIME_US) as u16
};
param
}
}
#[derive(Clone, Copy)]
struct SleepTimeConfig {
sleep_time_adjustment: u32,
slowclk_period: u32,
fastclk_period: u32,
}
const CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ: u32 = 160;
impl SleepTimeConfig {
const RTC_CLK_CAL_FRACT: u32 = 19;
fn rtc_clk_cal_fast(slowclk_cycles: u32) -> u32 {
RtcClock::calibrate(TimgCalibrationClockConfig::RcFastDivClk, slowclk_cycles)
}
fn new(_deep: bool) -> Self {
let slowclk_period = unsafe { lp_aon().store1().read().data().bits() };
const FAST_CLK_SRC_CAL_CYCLES: u32 = 2048;
let fastclk_period = Self::rtc_clk_cal_fast(FAST_CLK_SRC_CAL_CYCLES);
Self {
sleep_time_adjustment: 0,
slowclk_period,
fastclk_period,
}
}
fn light_sleep(pd_flags: PowerDownFlags) -> Self {
const LIGHT_SLEEP_TIME_OVERHEAD_US: u32 = 56;
let mut this = Self::new(false);
let sw = LIGHT_SLEEP_TIME_OVERHEAD_US; let hw = this.pmu_sleep_calculate_hw_wait_time(pd_flags);
this.sleep_time_adjustment = sw + hw;
this
}
fn deep_sleep() -> Self {
let mut this = Self::new(true);
this.sleep_time_adjustment = 250 + 100 * 240 / CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ;
this
}
fn us_to_slowclk(&self, us: u32) -> u32 {
(us << Self::RTC_CLK_CAL_FRACT) / self.slowclk_period
}
fn slowclk_to_us(&self, rtc_cycles: u32) -> u32 {
(rtc_cycles * self.slowclk_period) >> Self::RTC_CLK_CAL_FRACT
}
fn us_to_fastclk(&self, us: u32) -> u32 {
(us << Self::RTC_CLK_CAL_FRACT) / self.fastclk_period
}
fn pmu_sleep_calculate_hw_wait_time(&self, pd_flags: PowerDownFlags) -> u32 {
let lp_wakeup_wait_time_us = self.slowclk_to_us(MachineConstants::LP_WAKEUP_WAIT_CYCLE);
let lp_clk_switch_time_us = self.slowclk_to_us(MachineConstants::LP_CLK_SWITCH_CYCLE);
let lp_clk_power_on_wait_time_us = if pd_flags.pd_xtal() {
MachineConstants::LP_XTAL_WAIT_STABLE_TIME_US
} else {
self.slowclk_to_us(MachineConstants::LP_CLK_POWER_ON_WAIT_CYCLE)
};
let lp_hw_wait_time_us = MachineConstants::LP_MIN_SLP_TIME_US
+ MachineConstants::LP_ANALOG_WAIT_TIME_US
+ lp_clk_power_on_wait_time_us
+ lp_wakeup_wait_time_us
+ lp_clk_switch_time_us
+ MachineConstants::LP_POWER_SUPPLY_WAIT_TIME_US
+ MachineConstants::LP_POWER_UP_WAIT_TIME_US;
let hp_digital_power_up_wait_time_us = MachineConstants::HP_POWER_SUPPLY_WAIT_TIME_US
+ MachineConstants::HP_POWER_UP_WAIT_TIME_US;
let hp_regdma_wait_time_us = u32::max(
MachineConstants::HP_REGDMA_S2M_WORK_TIME_US
+ MachineConstants::HP_REGDMA_M2A_WORK_TIME_US,
MachineConstants::HP_REGDMA_S2A_WORK_TIME_US,
);
let hp_clock_wait_time_us = MachineConstants::HP_XTAL_WAIT_STABLE_TIME_US
+ MachineConstants::HP_PLL_WAIT_STABLE_TIME_US;
let hp_hw_wait_time_us = MachineConstants::HP_ANALOG_WAIT_TIME_US
+ u32::max(
hp_digital_power_up_wait_time_us + hp_regdma_wait_time_us,
hp_clock_wait_time_us,
);
#[rustfmt::skip] const CONFIG_ESP_RADIO_ENHANCED_LIGHT_SLEEP: bool = true;
let (rf_on_protect_time_us, sync_time_us) = if CONFIG_ESP_RADIO_ENHANCED_LIGHT_SLEEP {
(
MachineConstants::HP_REGDMA_RF_ON_WORK_TIME_US,
MachineConstants::HP_CLOCK_DOMAIN_SYNC_TIME_US,
)
} else {
(0, 0)
};
lp_hw_wait_time_us + hp_hw_wait_time_us + sync_time_us + rf_on_protect_time_us
}
}
#[derive(Clone, Copy)]
pub struct RtcSleepConfig {
pub deep: bool,
pub pd_flags: PowerDownFlags,
}
impl Default for RtcSleepConfig {
fn default() -> Self {
Self {
deep: false,
pd_flags: PowerDownFlags(0),
}
}
}
unsafe fn pmu<'a>() -> &'a esp32c6::pmu::RegisterBlock {
unsafe { &*esp32c6::PMU::ptr() }
}
unsafe fn lp_aon<'a>() -> &'a esp32c6::lp_aon::RegisterBlock {
unsafe { &*esp32c6::LP_AON::ptr() }
}
bitfield::bitfield! {
#[derive(Clone, Copy)]
pub struct PowerDownFlags(u32);
pub u32, pd_top , set_pd_top : 0;
pub u32, pd_vddsdio , set_pd_vddsdio : 1;
pub u32, pd_modem , set_pd_modem : 2;
pub u32, pd_hp_periph, set_pd_hp_periph: 3;
pub u32, pd_cpu , set_pd_cpu : 4;
pub u32, pd_hp_aon , set_pd_hp_aon : 5;
pub u32, pd_mem_g0 , set_pd_mem_g0 : 6;
pub u32, pd_mem_g1 , set_pd_mem_g1 : 7;
pub u32, pd_mem_g2 , set_pd_mem_g2 : 8;
pub u32, pd_mem_g3 , set_pd_mem_g3 : 9;
pub u32, pd_xtal , set_pd_xtal : 10;
pub u32, pd_rc_fast , set_pd_rc_fast : 11;
pub u32, pd_xtal32k , set_pd_xtal32k : 12;
pub u32, pd_rc32k , set_pd_rc32k : 13;
pub u32, pd_lp_periph, set_pd_lp_periph: 14;
}
impl PowerDownFlags {
pub fn pd_mem(self) -> bool {
self.pd_mem_g0() && self.pd_mem_g1() && self.pd_mem_g2() && self.pd_mem_g3()
}
pub fn set_pd_mem(&mut self, value: bool) {
self.set_pd_mem_g0(value);
self.set_pd_mem_g1(value);
self.set_pd_mem_g2(value);
self.set_pd_mem_g3(value);
}
}
struct MachineConstants;
impl MachineConstants {
const LP_MIN_SLP_TIME_US: u32 = 450;
const LP_WAKEUP_WAIT_CYCLE: u32 = 4;
const LP_ANALOG_WAIT_TIME_US: u32 = 154;
const LP_XTAL_WAIT_STABLE_TIME_US: u32 = 250;
const LP_CLK_SWITCH_CYCLE: u32 = 1;
const LP_CLK_POWER_ON_WAIT_CYCLE: u32 = 1;
const LP_POWER_SUPPLY_WAIT_TIME_US: u32 = 2;
const LP_POWER_UP_WAIT_TIME_US: u32 = 2;
const HP_MIN_SLP_TIME_US: u32 = 450;
const HP_CLOCK_DOMAIN_SYNC_TIME_US: u32 = 150;
const HP_SYSTEM_DFS_UP_WORK_TIME_US: u32 = 124;
const HP_ANALOG_WAIT_TIME_US: u32 = 154;
const HP_POWER_SUPPLY_WAIT_TIME_US: u32 = 2;
const HP_POWER_UP_WAIT_TIME_US: u32 = 2;
const HP_REGDMA_S2M_WORK_TIME_US: u32 = 172;
const HP_REGDMA_S2A_WORK_TIME_US: u32 = 480;
const HP_REGDMA_M2A_WORK_TIME_US: u32 = 278;
const HP_REGDMA_RF_ON_WORK_TIME_US: u32 = 70;
const HP_XTAL_WAIT_STABLE_TIME_US: u32 = 250;
const HP_PLL_WAIT_STABLE_TIME_US: u32 = 1;
const MODEM_STATE_SKIP_TIME_US: u32 = Self::HP_REGDMA_M2A_WORK_TIME_US
+ Self::HP_SYSTEM_DFS_UP_WORK_TIME_US
+ Self::LP_MIN_SLP_TIME_US;
}
impl RtcSleepConfig {
pub fn deep_slp(&self) -> bool {
self.deep
}
pub fn deep() -> Self {
Self {
deep: true,
..Self::default()
}
}
pub(crate) fn base_settings(_rtc: &Rtc<'_>) {
Self::wake_io_reset();
}
fn wake_io_reset() {
Ext1WakeupSource::wake_io_reset();
}
pub(crate) fn apply(&mut self) {
if self.deep {
self.pd_flags.set_pd_top(true);
self.pd_flags.set_pd_vddsdio(true);
self.pd_flags.set_pd_modem(true);
self.pd_flags.set_pd_hp_periph(true);
self.pd_flags.set_pd_cpu(true);
self.pd_flags.set_pd_mem(true);
self.pd_flags.set_pd_xtal(true);
self.pd_flags.set_pd_hp_aon(true);
self.pd_flags.set_pd_lp_periph(true);
self.pd_flags.set_pd_xtal32k(true);
self.pd_flags.set_pd_rc32k(true);
self.pd_flags.set_pd_rc_fast(true);
}
}
pub(crate) fn start_sleep(&self, wakeup_triggers: WakeTriggers) {
const PMU_EXT0_WAKEUP_EN: u32 = 1 << 0;
const PMU_EXT1_WAKEUP_EN: u32 = 1 << 1;
const PMU_GPIO_WAKEUP_EN: u32 = 1 << 2;
const PMU_LP_TIMER_WAKEUP_EN: u32 = 1 << 4;
const PMU_WIFI_SOC_WAKEUP_EN: u32 = 1 << 5;
const PMU_UART0_WAKEUP_EN: u32 = 1 << 6;
const PMU_UART1_WAKEUP_EN: u32 = 1 << 7;
const PMU_SDIO_WAKEUP_EN: u32 = 1 << 8;
const PMU_BLE_SOC_WAKEUP_EN: u32 = 1 << 10;
const PMU_LP_CORE_WAKEUP_EN: u32 = 1 << 11;
const PMU_USB_WAKEUP_EN: u32 = 1 << 14;
const MODEM_REJECT: u32 = 1 << 16;
const RTC_SLEEP_REJECT_MASK: u32 = PMU_EXT0_WAKEUP_EN
| PMU_EXT1_WAKEUP_EN
| PMU_GPIO_WAKEUP_EN
| PMU_LP_TIMER_WAKEUP_EN
| PMU_WIFI_SOC_WAKEUP_EN
| PMU_UART0_WAKEUP_EN
| PMU_UART1_WAKEUP_EN
| PMU_SDIO_WAKEUP_EN
| PMU_BLE_SOC_WAKEUP_EN
| PMU_LP_CORE_WAKEUP_EN
| PMU_USB_WAKEUP_EN;
let wakeup_mask = wakeup_triggers.0 as u32;
let reject_mask = if self.deep {
0
} else {
let reject_mask = RTC_SLEEP_REJECT_MASK | MODEM_REJECT;
wakeup_mask & reject_mask
};
let cpu_freq_config = ClockTree::with(|clocks| {
let cpu_freq_config = SavedClockConfig::save(clocks);
crate::soc::clocks::configure_soc_root_clk(
clocks,
crate::soc::clocks::SocRootClkConfig::Xtal,
);
cpu_freq_config
});
let power = PowerSleepConfig::defaults(self.pd_flags);
power.apply();
let config = if self.deep {
SleepTimeConfig::deep_sleep()
} else {
SleepTimeConfig::light_sleep(self.pd_flags)
};
let mut param =
ParamSleepConfig::defaults(config, self.pd_flags, power.hp_sys.xtal.xpd_xtal());
if self.deep {
const PMU_LP_ANALOG_WAIT_TARGET_TIME_DSLP_US: u32 = 500;
param.lp_sys.analog_wait_target_cycle =
config.us_to_slowclk(PMU_LP_ANALOG_WAIT_TARGET_TIME_DSLP_US) as u8;
AnalogSleepConfig::defaults_deep_sleep().apply();
} else {
AnalogSleepConfig::defaults_light_sleep(self.pd_flags).apply();
DigitalSleepConfig::defaults_light_sleep(self.pd_flags).apply();
}
param.apply();
unsafe {
lp_aon()
.store9()
.modify(|r, w| w.bits(r.bits() & !0x01 | self.deep as u32));
pmu().slp_wakeup_cntl2().write(|w| w.bits(wakeup_mask));
pmu().slp_wakeup_cntl1().modify(|_, w| {
w.slp_reject_en()
.bit(true)
.sleep_reject_ena()
.bits(reject_mask)
});
pmu()
.slp_wakeup_cntl4()
.write(|w| w.slp_reject_cause_clr().bit(true));
pmu().int_clr().write(|w| {
w.sw() .clear_bit_by_one()
.soc_sleep_reject() .clear_bit_by_one()
.soc_wakeup() .clear_bit_by_one()
});
#[cfg(not(soc_has_pmu))]
if !(self.deep && wakeup_triggers.touch) {
APB_SARADC::regs()
.ctrl()
.modify(|_, w| w.saradc2_pwdet_drv().bit(false));
}
pmu().slp_wakeup_cntl0().write(|w| w.sleep_req().bit(true));
loop {
let int_raw = pmu().int_raw().read();
if int_raw.soc_wakeup().bit_is_set() || int_raw.soc_sleep_reject().bit_is_set() {
break;
}
}
}
ClockTree::with(|clocks| {
cpu_freq_config.restore(clocks);
});
}
pub(crate) fn finish_sleep(&self) {
Self::wake_io_reset();
}
}