use core::{
ops::Not,
sync::atomic::{AtomicBool, Ordering},
};
use crate::{
peripherals::{HP_SYS_CLKRST, LP_AON_CLKRST, PMU, USB_DEVICE},
private::DropGuard,
rtc_cntl::{
Rtc,
rtc::{HpAnalog, HpSysCntlReg, HpSysPower, LpAnalog, LpSysPower},
sleep::{SleepKind, pmu_common::SleepTimeConfig},
},
soc::clocks::{self, ClockTree, CpuRootClkConfig},
};
static USJ_CLOCK_WAS_ENABLED: AtomicBool = AtomicBool::new(false);
static USJ_PAD_WAS_ENABLED: AtomicBool = AtomicBool::new(false);
fn usj_module_is_enabled() -> bool {
let clkrst = HP_SYS_CLKRST::regs();
let aon = LP_AON_CLKRST::regs();
clkrst
.soc_clk_ctrl2()
.read()
.usb_device_apb_clk_en()
.bit_is_set()
&& aon
.lp_aonclkrst_hp_usb_clkrst_ctrl1()
.read()
.lp_aonclkrst_rst_en_usb_device()
.bit_is_clear()
}
fn usj_enable_bus_clock(enable: bool) {
HP_SYS_CLKRST::regs()
.soc_clk_ctrl2()
.modify(|_, w| w.usb_device_apb_clk_en().bit(enable));
LP_AON_CLKRST::regs()
.lp_aonclkrst_hp_usb_clkrst_ctrl0()
.modify(|_, w| w.lp_aonclkrst_usb_device_48m_clk_en().bit(enable));
}
fn usj_reset_register() {
let aon = LP_AON_CLKRST::regs();
aon.lp_aonclkrst_hp_usb_clkrst_ctrl1()
.modify(|_, w| w.lp_aonclkrst_rst_en_usb_device().set_bit());
aon.lp_aonclkrst_hp_usb_clkrst_ctrl1()
.modify(|_, w| w.lp_aonclkrst_rst_en_usb_device().clear_bit());
}
fn usj_set_pad_enable(enable: bool) {
USB_DEVICE::regs()
.conf0()
.modify(|_, w| w.usb_pad_enable().bit(enable));
}
fn usj_pad_is_enabled() -> bool {
USB_DEVICE::regs()
.conf0()
.read()
.usb_pad_enable()
.bit_is_set()
}
fn usj_pad_backup_and_disable() {
let clock_enabled = usj_module_is_enabled();
let pad_enabled = if clock_enabled {
usj_pad_is_enabled()
} else {
usj_enable_bus_clock(true);
usj_reset_register();
false
};
usj_set_pad_enable(false);
usj_enable_bus_clock(false);
USJ_CLOCK_WAS_ENABLED.store(clock_enabled, Ordering::Relaxed);
USJ_PAD_WAS_ENABLED.store(pad_enabled, Ordering::Relaxed);
}
fn usj_pad_restore() {
usj_enable_bus_clock(true);
usj_set_pad_enable(USJ_PAD_WAS_ENABLED.load(Ordering::Relaxed));
if !USJ_CLOCK_WAS_ENABLED.load(Ordering::Relaxed) {
usj_enable_bus_clock(false);
}
}
const P4_LP_RAM_BOOT_ADDR: usize = 0x5010_8000;
fn is_rev3_mspi_workaround_needed() -> bool {
crate::efuse::chip_revision() == crate::efuse::ChipRevision::from_combined(300)
}
core::arch::global_asm!(
".pushsection .rodata.p4_rev3_mspi_wa, \"a\"",
".option push",
".option norelax",
".option norvc",
".balign 4",
".global _p4_rev3_mspi_wa_start",
".global _p4_rev3_mspi_wa_end",
"_p4_rev3_mspi_wa_start:",
"li a0, 0x50111014",
"li a1, 0x8000",
"lw a2, 0(a0)",
"or a2, a2, a1",
"sw a2, 0(a0)",
"li a0, 0x5008C03C",
"li a1, 0x80000000",
"not a1, a1",
"lw a2, 0(a0)",
"and a2, a2, a1",
"sw a2, 0(a0)",
"li a1, 0x1",
"lw a2, 0(a0)",
"or a2, a2, a1",
"sw a2, 0(a0)",
"li a0, 0x5008C380", "sw zero, 0(a0)",
"li a0, 0x5008C37C", "li a1, 0x1000",
"sw a1, 0(a0)",
"li a0, 0x500E51A4",
"li a1, 0x7",
"sw a1, 0(a0)",
"li a0, 0x80000000",
"lw a1, 0(a0)",
"li a0, 0x80000080",
"lw a1, 0(a0)",
"li t3, 40",
"csrr t0, cycle",
"add t1, t0, t3",
"100:",
"csrr t2, cycle",
"blt t2, t1, 100b",
"li a0, 0x500E51A4",
"sw zero, 0(a0)",
"li a0, 0x500E60C0",
"li a1, 0x400000", "lw a2, 0(a0)",
"or a2, a2, a1",
"sw a2, 0(a0)",
"li a1, 0x1000000", "lw a2, 0(a0)",
"or a2, a2, a1",
"sw a2, 0(a0)",
"li a1, 0x400000",
"not a1, a1",
"lw a2, 0(a0)",
"and a2, a2, a1",
"sw a2, 0(a0)",
"li a1, 0x1000000",
"not a1, a1",
"lw a2, 0(a0)",
"and a2, a2, a1",
"sw a2, 0(a0)",
"li a5, 0x4FC00000",
"jr a5",
"_p4_rev3_mspi_wa_end:",
".option pop",
".popsection",
);
fn install_mspi_workaround_stub() {
unsafe extern "C" {
static _p4_rev3_mspi_wa_start: u8;
static _p4_rev3_mspi_wa_end: u8;
}
let src = &raw const _p4_rev3_mspi_wa_start;
let end = &raw const _p4_rev3_mspi_wa_end;
let len = end as usize - src as usize;
let words = len.div_ceil(4);
let src = src as *const u32;
let dst = P4_LP_RAM_BOOT_ADDR as *mut u32;
for i in 0..words {
unsafe { dst.add(i).write_volatile(src.add(i).read_volatile()) };
}
}
fn set_boot_from_lp_ram(boot_from_lp_ram: bool) {
LP_AON_CLKRST::regs()
.lp_aonclkrst_hpcpu_reset_ctrl0()
.modify(|_, w| {
w.lp_aonclkrst_hpcore0_stat_vector_sel()
.bit(!boot_from_lp_ram)
});
}
fn pmu_sleep_dcdc_to_ldo_handover() {
const LDO_TAKEOVER_PREPARATION_TIME_US: u32 = 185;
const HP_CALI_ACTIVE_DBIAS: u8 = 24;
const LDO_TAKEOVER_DBIAS: u8 = 30;
const LDO_TAKEOVER_DCM_VSET: u8 = 24;
PMU::regs()
.hp_active_hp_regulator0()
.modify(|_, w| unsafe { w.hp_active_hp_regulator_dbias().bits(LDO_TAKEOVER_DBIAS) });
PMU::regs()
.hp_active_hp_regulator0()
.modify(|_, w| w.hp_active_hp_regulator_xpd().set_bit());
PMU::regs()
.hp_active_bias()
.modify(|_, w| unsafe { w.hp_active_dcm_vset().bits(LDO_TAKEOVER_DCM_VSET) });
crate::rom::ets_delay_us(LDO_TAKEOVER_PREPARATION_TIME_US);
PMU::regs().dcm_ctrl().modify(|_, w| {
w.dcdc_off_req().set_bit();
w.dcdc_done_force().set_bit()
});
PMU::regs()
.hp_active_hp_regulator0()
.modify(|_, w| unsafe { w.hp_active_hp_regulator_dbias().bits(HP_CALI_ACTIVE_DBIAS) });
}
#[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_dcm_mode(0);
cfg.bias.set_pd_cur(true); cfg.bias.set_bias_sleep(true); 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.bias.set_dcm_mode(1);
cfg.bias.set_dcm_vset(DCM_VSET_IN_SLEEP);
cfg.regulator1.set_drv_b(0); cfg.bias.set_pd_cur(true); cfg.bias.set_bias_sleep(true); cfg.regulator0.set_xpd(false); 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.bias.set_dbg_atten(0);
this.hp_sys.regulator0.set_dbias(HP_CALI_ACTIVE_DBIAS);
this.lp_sys_sleep.bias.set_pd_cur(false);
this.lp_sys_sleep.bias.set_bias_sleep(false);
this.lp_sys_sleep.bias.set_dbg_atten(0);
}
this
}
fn apply(&self, dslp: bool) {
PMU::regs()
.hp_active_bias()
.modify(|_, w| unsafe { w.hp_active_dcm_mode().bits(if dslp { 0 } else { 1 }) });
PMU::regs().hp_sleep_bias().modify(|_, w| unsafe {
w.hp_sleep_dcm_mode().bits(self.hp_sys.bias.dcm_mode());
w.hp_sleep_dcm_vset().bits(self.hp_sys.bias.dcm_vset());
w.hp_sleep_dbg_atten().bits(self.hp_sys.bias.dbg_atten());
w.hp_sleep_pd_cur().bit(self.hp_sys.bias.pd_cur());
w.sleep().bit(self.hp_sys.bias.bias_sleep())
});
PMU::regs().hp_sleep_hp_regulator0().modify(|_, w| unsafe {
w.hp_sleep_hp_regulator_slp_mem_xpd()
.bit(self.hp_sys.regulator0.slp_mem_xpd());
w.hp_sleep_hp_regulator_slp_logic_xpd()
.bit(self.hp_sys.regulator0.slp_logic_xpd());
w.hp_sleep_hp_regulator_xpd()
.bit(self.hp_sys.regulator0.xpd());
w.hp_sleep_hp_regulator_slp_logic_dbias()
.bits(self.hp_sys.regulator0.slp_logic_dbias());
w.hp_sleep_hp_regulator_dbias()
.bits(self.hp_sys.regulator0.dbias())
});
PMU::regs().hp_sleep_hp_regulator1().modify(|_, w| unsafe {
w.hp_sleep_hp_regulator_drv_b()
.bits(self.hp_sys.regulator1.drv_b())
});
PMU::regs().lp_sleep_bias().modify(|_, w| unsafe {
w.lp_sleep_dbg_atten()
.bits(self.lp_sys_sleep.bias.dbg_atten());
w.lp_sleep_pd_cur().bit(self.lp_sys_sleep.bias.pd_cur());
w.sleep().bit(self.lp_sys_sleep.bias.bias_sleep())
});
PMU::regs().lp_sleep_lp_regulator0().modify(|_, w| unsafe {
w.lp_sleep_lp_regulator_slp_xpd()
.bit(self.lp_sys_sleep.regulator0.slp_xpd());
w.lp_sleep_lp_regulator_xpd()
.bit(self.lp_sys_sleep.regulator0.xpd());
w.lp_sleep_lp_regulator_slp_dbias()
.bits(self.lp_sys_sleep.regulator0.slp_dbias());
w.lp_sleep_lp_regulator_dbias()
.bits(self.lp_sys_sleep.regulator0.dbias())
});
PMU::regs().lp_sleep_lp_regulator1().modify(|_, w| unsafe {
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_deep_sleep(pd_flags: PowerDownFlags) -> Self {
let mut syscntl = HpSysCntlReg::default();
syscntl.set_dig_pad_slp_sel(false);
syscntl.set_lp_pad_hold_all(pd_flags.pd_lp_periph());
Self { syscntl }
}
fn defaults_light_sleep(pd_flags: PowerDownFlags) -> Self {
Self {
syscntl: {
let mut cfg = HpSysCntlReg::default();
cfg.set_dig_pad_slp_sel(false);
cfg.set_lp_pad_hold_all(pd_flags.pd_lp_periph());
cfg.set_dig_pause_wdt(true);
cfg
},
}
}
fn apply(&self) {
PMU::regs().hp_sleep_hp_sys_cntl().modify(|_, w| {
w.hp_sleep_dig_pad_slp_sel()
.bit(self.syscntl.dig_pad_slp_sel());
w.hp_sleep_lp_pad_hold_all()
.bit(self.syscntl.lp_pad_hold_all());
w.hp_sleep_dig_pause_wdt().bit(self.syscntl.dig_pause_wdt());
w.hp_sleep_dig_cpu_stall().bit(true)
});
}
}
#[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_dcdc_switch_pd_en(pd_flags.pd_vddsdio());
self.hp_sys.dig_power.set_cnnt_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_top_pd_en(pd_flags.pd_top());
self.hp_sys.dig_power.set_mem_pd_en(pd_flags.pd_mem());
self.hp_sys.clk.set_i2c_iso_en(true);
self.hp_sys.clk.set_i2c_retention(true);
self.hp_sys.clk.set_xpd_pll_i2c(0);
self.hp_sys.clk.set_xpd_pll(0);
self.hp_sys.xtal.set_xpd_xtal(pd_flags.pd_xtal().not());
self.lp_sys_active.clk_power.set_xpd_lppll(true);
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
.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) {
PMU::regs()
.hp_sleep_dig_power()
.modify(|_, w| unsafe { w.bits(self.hp_sys.dig_power.0) });
PMU::regs()
.hp_sleep_hp_ck_power()
.modify(|_, w| unsafe { w.bits(self.hp_sys.clk.0) });
PMU::regs()
.hp_sleep_xtal()
.modify(|_, w| w.hp_sleep_xpd_xtal().bit(self.hp_sys.xtal.xpd_xtal()));
PMU::regs()
.hp_sleep_lp_dig_power()
.modify(|_, w| unsafe { w.bits(self.lp_sys_active.dig_power.0) });
PMU::regs()
.hp_sleep_lp_ck_power()
.modify(|_, w| unsafe { w.bits(self.lp_sys_active.clk_power.0) });
PMU::regs()
.lp_sleep_lp_dig_power()
.modify(|_, w| unsafe { w.bits(self.lp_sys_sleep.dig_power.0) });
PMU::regs()
.lp_sleep_lp_ck_power()
.modify(|_, w| unsafe { w.bits(self.lp_sys_sleep.clk_power.0) });
PMU::regs()
.lp_sleep_xtal()
.modify(|_, w| w.lp_sleep_xpd_xtal().bit(self.lp_sys_sleep.xtal.xpd_xtal()));
}
}
#[derive(Clone, Copy, Default)]
pub struct HpParam {
analog_wait_target_cycle: u16,
digital_power_supply_wait_cycle: u16,
digital_power_up_wait_cycle: u16,
pll_stable_wait_cycle: u16,
min_slp_slow_clk_cycle: u8,
}
#[derive(Clone, Copy, Default)]
pub struct LpParam {
digital_power_supply_wait_cycle: u16,
min_slp_slow_clk_cycle: u8,
analog_wait_target_cycle: u8,
digital_power_up_wait_cycle: u16,
}
#[derive(Clone, Copy, Default)]
pub struct HpLpParam {
xtal_stable_wait_cycle: u16,
}
#[derive(Clone, Copy)]
pub struct ParamSleepConfig {
hp_sys: HpParam,
lp_sys: LpParam,
hp_lp: HpLpParam,
}
impl ParamSleepConfig {
fn apply(&self) {
PMU::regs().slp_wakeup_cntl3().modify(|_, w| unsafe {
w.hp_min_slp_val().bits(self.hp_sys.min_slp_slow_clk_cycle);
w.lp_min_slp_val().bits(self.lp_sys.min_slp_slow_clk_cycle)
});
PMU::regs().slp_wakeup_cntl7().modify(|_, w| unsafe {
w.ana_wait_target()
.bits(self.hp_sys.analog_wait_target_cycle)
});
PMU::regs().power_wait_timer0().modify(|_, w| unsafe {
w.dg_hp_wait_timer()
.bits(self.hp_sys.digital_power_supply_wait_cycle);
w.dg_hp_powerup_timer()
.bits(self.hp_sys.digital_power_up_wait_cycle)
});
PMU::regs().power_wait_timer1().modify(|_, w| unsafe {
w.dg_lp_wait_timer()
.bits(self.lp_sys.digital_power_supply_wait_cycle);
w.dg_lp_powerup_timer()
.bits(self.lp_sys.digital_power_up_wait_cycle)
});
PMU::regs().slp_wakeup_cntl5().modify(|_, w| unsafe {
w.lp_ana_wait_target()
.bits(self.lp_sys.analog_wait_target_cycle)
});
PMU::regs().power_ck_wait_cntl().modify(|_, w| unsafe {
w.pmu_wait_xtl_stable()
.bits(self.hp_lp.xtal_stable_wait_cycle);
w.pmu_wait_pll_stable()
.bits(self.hp_sys.pll_stable_wait_cycle)
});
}
fn defaults(config: SleepTimeConfig, pd_flags: PowerDownFlags, pd_xtal: bool) -> Self {
let hp_analog_wait_time_us = if pd_flags.pd_top() {
MachineConstants::HP_ANA_WAIT_TIME_PD_TOP_US
} else {
MachineConstants::HP_ANA_WAIT_TIME_PU_TOP_US
};
let hp_sys = HpParam {
min_slp_slow_clk_cycle: config.us_to_slowclk(MachineConstants::HP_MIN_SLP_TIME_US)
as u8,
analog_wait_target_cycle: config.us_to_slowclk(hp_analog_wait_time_us) as u16,
digital_power_supply_wait_cycle: config
.us_to_fastclk(MachineConstants::HP_POWER_SUPPLY_WAIT_TIME_US)
as u16,
digital_power_up_wait_cycle: config
.us_to_fastclk(MachineConstants::HP_POWER_UP_WAIT_TIME_US)
as u16,
pll_stable_wait_cycle: config
.us_to_fastclk(MachineConstants::HP_PLL_WAIT_STABLE_TIME_US)
as u16,
};
let lp_sys = LpParam {
min_slp_slow_clk_cycle: config.us_to_slowclk(MachineConstants::LP_MIN_SLP_TIME_US)
as u8,
analog_wait_target_cycle: config.us_to_slowclk(MachineConstants::LP_ANALOG_WAIT_TIME_US)
as u8,
digital_power_supply_wait_cycle: config
.us_to_fastclk(MachineConstants::LP_POWER_SUPPLY_WAIT_TIME_US)
as u16,
digital_power_up_wait_cycle: config
.us_to_fastclk(MachineConstants::LP_POWER_UP_WAIT_TIME_US)
as u16,
};
let 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
};
Self {
hp_sys,
lp_sys,
hp_lp: HpLpParam {
xtal_stable_wait_cycle,
},
}
}
}
impl SleepTimeConfig {
pub(crate) const CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ: u32 = 360;
pub(crate) const LIGHT_SLEEP_TIME_OVERHEAD_US: u32 = 56;
pub(crate) 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 =
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_analog_wait_time_us = if pd_flags.pd_top() {
MachineConstants::HP_ANA_WAIT_TIME_PD_TOP_US
} else {
MachineConstants::HP_ANA_WAIT_TIME_PU_TOP_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 = 0;
let hp_clock_wait_time_us = if pd_flags.pd_xtal() {
MachineConstants::HP_XTAL_WAIT_STABLE_TIME_US
+ MachineConstants::HP_PLL_WAIT_STABLE_TIME_US
} else {
MachineConstants::HP_PLL_WAIT_STABLE_TIME_US
};
let hp_hw_wait_time_us = hp_analog_wait_time_us
+ hp_digital_power_up_wait_time_us
+ hp_regdma_wait_time_us
+ hp_clock_wait_time_us;
lp_hw_wait_time_us + hp_hw_wait_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),
}
}
}
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);
}
}
const DCM_VSET_IN_SLEEP: u8 = 14;
const HP_CALI_ACTIVE_DBIAS: u8 = 24;
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_ANA_WAIT_TIME_PD_TOP_US: u32 = 260;
const HP_REGDMA_S2A_WORK_TIME_US: u32 = 685;
const HP_ANA_WAIT_TIME_PU_TOP_US: u32 =
Self::HP_ANA_WAIT_TIME_PD_TOP_US + Self::HP_REGDMA_S2A_WORK_TIME_US;
const HP_POWER_SUPPLY_WAIT_TIME_US: u32 = 2;
const HP_POWER_UP_WAIT_TIME_US: u32 = 26;
const HP_XTAL_WAIT_STABLE_TIME_US: u32 = 250;
const HP_PLL_WAIT_STABLE_TIME_US: u32 = 50;
}
impl RtcSleepConfig {
pub fn deep_slp(&self) -> bool {
self.deep
}
pub fn deep() -> Self {
Self {
deep: true,
..Self::default()
}
}
pub(crate) fn is_deep_sleep(&self) -> bool {
self.deep_slp()
}
pub(crate) fn set_sleep_kind(&mut self, kind: SleepKind) {
self.deep = kind == SleepKind::Deep;
}
pub(crate) fn base_settings(_rtc: &Rtc<'_>) {}
pub(crate) fn apply(&mut self) {
let lp_slow_uses_xtal32k = cfg_select! {
use_xtal32k => ClockTree::with(|clocks| {
matches!(
clocks::lp_slow_clk_config(clocks),
Some(clocks::LpSlowClkConfig::Xtal32k)
)
}),
_ => false,
};
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(!lp_slow_uses_xtal32k);
self.pd_flags.set_pd_rc32k(true);
self.pd_flags.set_pd_rc_fast(true);
} else {
self.pd_flags.set_pd_xtal(true);
self.pd_flags.set_pd_rc_fast(true);
self.pd_flags.set_pd_xtal32k(!lp_slow_uses_xtal32k);
}
}
#[crate::ram]
pub(crate) fn start_sleep(&self, wakeup_mask: u32, reject_mask: u32) -> impl Sized {
let restore_clock_config = ClockTree::with(|clocks| {
let old_cpu_root_clk = clocks.cpu_root_clk();
clocks::configure_cpu_root_clk(clocks, CpuRootClkConfig::Xtal);
DropGuard::new((), move |_| {
ClockTree::with(|clocks| {
if let Some(old) = old_cpu_root_clk {
clocks::configure_cpu_root_clk(clocks, old);
}
});
})
});
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, self.pd_flags.pd_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;
DigitalSleepConfig::defaults_deep_sleep(self.pd_flags).apply();
AnalogSleepConfig::defaults_deep_sleep().apply(true);
} else {
AnalogSleepConfig::defaults_light_sleep(self.pd_flags).apply(false);
DigitalSleepConfig::defaults_light_sleep(self.pd_flags).apply();
}
param.apply();
let mspi_workaround = self.deep && is_rev3_mspi_workaround_needed();
if mspi_workaround {
install_mspi_workaround_stub();
set_boot_from_lp_ram(true);
}
let restore_boot_vector = DropGuard::new((), move |_| {
if mspi_workaround {
set_boot_from_lp_ram(false);
}
});
crate::peripherals::LP_AON::regs()
.lp_store8()
.modify(|r, w| unsafe { w.bits(r.bits() & !0x01 | self.deep as u32) });
PMU::regs()
.slp_wakeup_cntl2()
.write(|w| unsafe { w.bits(wakeup_mask) });
PMU::regs().slp_wakeup_cntl1().modify(|_, w| unsafe {
w.slp_reject_en().bit(reject_mask != 0);
w.sleep_reject_ena().bits(reject_mask)
});
PMU::regs()
.slp_wakeup_cntl4()
.write(|w| w.slp_reject_cause_clr().bit(true));
PMU::regs().int_clr().write(|w| {
w.sw().clear_bit_by_one();
w.soc_sleep_reject().clear_bit_by_one();
w.soc_wakeup().clear_bit_by_one()
});
if self.deep {
pmu_sleep_dcdc_to_ldo_handover();
}
if !self.deep {
usj_pad_backup_and_disable();
}
PMU::regs()
.imm_pad_hold_all()
.write(|w| w.tie_high_pad_slp_sel().set_bit());
PMU::regs()
.slp_wakeup_cntl0()
.write(|w| w.sleep_req().bit(true));
(restore_clock_config, restore_boot_vector)
}
#[crate::ram]
pub(crate) fn finish_sleep(&self) {
PMU::regs()
.imm_pad_hold_all()
.write(|w| w.tie_low_pad_slp_sel().set_bit());
if !self.deep {
usj_pad_restore();
}
}
}