use fugit::HertzU32;
use strum::FromRepr;
use crate::{
clock::{
clocks_ll::{
esp32c6_bbpll_get_freq_mhz,
esp32c6_cpu_get_hs_divider,
esp32c6_cpu_get_ls_divider,
esp32c6_rtc_bbpll_configure_raw,
esp32c6_rtc_freq_to_pll_mhz_raw,
esp32c6_rtc_update_to_8m,
esp32c6_rtc_update_to_xtal_raw,
regi2c_write_mask,
},
Clock,
XtalClock,
},
peripherals::TIMG0,
rtc_cntl::RtcClock,
soc::efuse::Efuse,
system::RadioPeripherals,
};
const I2C_DIG_REG: u8 = 0x6d;
const I2C_DIG_REG_HOSTID: u8 = 0;
const I2C_DIG_REG_XPD_RTC_REG: u8 = 13;
const I2C_DIG_REG_XPD_RTC_REG_MSB: u8 = 2;
const I2C_DIG_REG_XPD_RTC_REG_LSB: u8 = 2;
const I2C_DIG_REG_XPD_DIG_REG: u8 = 13;
const I2C_DIG_REG_XPD_DIG_REG_MSB: u8 = 3;
const I2C_DIG_REG_XPD_DIG_REG_LSB: u8 = 3;
const I2C_DIG_REG_ENIF_RTC_DREG: u8 = 5;
const I2C_DIG_REG_ENIF_RTC_DREG_MSB: u8 = 7;
const I2C_DIG_REG_ENIF_RTC_DREG_LSB: u8 = 7;
const I2C_DIG_REG_ENIF_DIG_DREG: u8 = 7;
const I2C_DIG_REG_ENIF_DIG_DREG_MSB: u8 = 7;
const I2C_DIG_REG_ENIF_DIG_DREG_LSB: u8 = 7;
const I2C_DIG_REG_SCK_DCAP: u8 = 14;
const I2C_DIG_REG_SCK_DCAP_MSB: u8 = 7;
const I2C_DIG_REG_SCK_DCAP_LSB: u8 = 0;
unsafe fn pmu<'a>() -> &'a esp32c6::pmu::RegisterBlock {
&*esp32c6::PMU::ptr()
}
unsafe fn modem_lpcon<'a>() -> &'a esp32c6::modem_lpcon::RegisterBlock {
&*esp32c6::MODEM_LPCON::ptr()
}
unsafe fn modem_syscon<'a>() -> &'a esp32c6::modem_syscon::RegisterBlock {
&*esp32c6::MODEM_SYSCON::ptr()
}
unsafe fn lp_clkrst<'a>() -> &'a esp32c6::lp_clkrst::RegisterBlock {
&*esp32c6::LP_CLKRST::ptr()
}
unsafe fn pcr<'a>() -> &'a esp32c6::pcr::RegisterBlock {
&*esp32c6::PCR::ptr()
}
unsafe fn lp_aon<'a>() -> &'a esp32c6::lp_aon::RegisterBlock {
&*esp32c6::LP_AON::ptr()
}
fn pmu_power_domain_force_default() {
unsafe {
pmu().power_pd_top_cntl().modify(|_, w| {
w.force_top_reset() .bit(false)
.force_top_iso() .bit(false)
.force_top_pu() .bit(false)
.force_top_no_reset() .bit(false)
.force_top_no_iso() .bit(false)
.force_top_pd() .bit(false)
});
pmu().power_pd_hpaon_cntl().modify(|_, w| {
w.force_hp_aon_reset() .bit(false)
.force_hp_aon_iso() .bit(false)
.force_hp_aon_pu() .bit(false)
.force_hp_aon_no_reset() .bit(false)
.force_hp_aon_no_iso() .bit(false)
.force_hp_aon_pd() .bit(false)
});
pmu().power_pd_hpcpu_cntl().modify(|_, w| {
w.force_hp_cpu_reset() .bit(false)
.force_hp_cpu_iso() .bit(false)
.force_hp_cpu_pu() .bit(false)
.force_hp_cpu_no_reset() .bit(false)
.force_hp_cpu_no_iso() .bit(false)
.force_hp_cpu_pd() .bit(false)
});
pmu().power_pd_hpwifi_cntl().modify(|_, w| {
w.force_hp_wifi_reset() .bit(false)
.force_hp_wifi_iso() .bit(false)
.force_hp_wifi_pu() .bit(false)
.force_hp_wifi_no_reset() .bit(false)
.force_hp_wifi_no_iso() .bit(false)
.force_hp_wifi_pd() .bit(false)
});
pmu().power_pd_mem_cntl().modify(|_, w| {
w.force_hp_mem_no_iso() .bits(0)
});
pmu().power_pd_lpperi_cntl().modify(|_, w| {
w.force_lp_peri_reset() .bit(false)
.force_lp_peri_iso() .bit(false)
.force_lp_peri_pu() .bit(false)
.force_lp_peri_no_reset() .bit(false)
.force_lp_peri_no_iso() .bit(false)
.force_lp_peri_pd() .bit(false)
});
};
}
fn modem_clock_domain_power_state_icg_map_init() {
const ICG_NOGATING_MODEM: u8 = 1 << 1;
const ICG_NOGATING_ACTIVE: u8 = 1 << 2;
unsafe {
modem_syscon().clk_conf_power_st().modify(|_, w| {
w.clk_modem_apb_st_map() .bits(ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM)
.clk_modem_peri_st_map() .bits(ICG_NOGATING_ACTIVE)
.clk_wifi_st_map() .bits(ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM)
.clk_bt_st_map() .bits(ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM)
.clk_fe_st_map() .bits(ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM)
.clk_zb_st_map() .bits(ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM)
});
modem_lpcon().clk_conf_power_st().modify(|_, w| {
w.clk_lp_apb_st_map() .bits(ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM)
.clk_i2c_mst_st_map() .bits(ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM)
.clk_coex_st_map() .bits(ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM)
.clk_wifipwr_st_map() .bits(ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM)
});
}
}
enum RtcSlowClockSource {
RcSlow = 0,
XTAL32K = 1,
RC32K = 2,
OscSlow = 3,
Invalid,
}
impl RtcSlowClockSource {
fn current() -> Self {
let lp_clkrst = unsafe { lp_clkrst() };
match lp_clkrst.lp_clk_conf().read().slow_clk_sel().bits() {
0 => Self::RcSlow,
1 => Self::XTAL32K,
2 => Self::RC32K,
3 => Self::OscSlow,
_ => Self::Invalid,
}
}
}
#[allow(unused)]
enum ModemClockLpclkSource {
RcSlow = 0,
RcFast,
MainXtal,
RC32K,
XTAL32K,
EXT32K,
}
impl From<RtcSlowClockSource> for ModemClockLpclkSource {
fn from(src: RtcSlowClockSource) -> Self {
match src {
RtcSlowClockSource::RcSlow => Self::RcSlow,
RtcSlowClockSource::XTAL32K => Self::XTAL32K,
RtcSlowClockSource::RC32K => Self::RC32K,
RtcSlowClockSource::OscSlow => Self::EXT32K,
_ => Self::RcSlow,
}
}
}
fn modem_clock_hal_deselect_all_wifi_lpclk_source() {
unsafe {
modem_lpcon().wifi_lp_clk_conf().modify(|_, w| {
w.clk_wifipwr_lp_sel_osc_slow()
.clear_bit()
.clk_wifipwr_lp_sel_osc_fast()
.clear_bit()
.clk_wifipwr_lp_sel_xtal32k()
.clear_bit()
.clk_wifipwr_lp_sel_xtal()
.clear_bit()
});
}
}
fn modem_clock_hal_select_wifi_lpclk_source(src: ModemClockLpclkSource) {
unsafe {
modem_lpcon().wifi_lp_clk_conf().modify(|_, w| match src {
ModemClockLpclkSource::RcSlow => w.clk_wifipwr_lp_sel_osc_slow().set_bit(),
ModemClockLpclkSource::RcFast => w.clk_wifipwr_lp_sel_osc_fast().set_bit(),
ModemClockLpclkSource::MainXtal => w.clk_wifipwr_lp_sel_xtal().set_bit(),
ModemClockLpclkSource::RC32K
| ModemClockLpclkSource::XTAL32K
| ModemClockLpclkSource::EXT32K => w.clk_wifipwr_lp_sel_xtal32k().set_bit(),
});
modem_lpcon().modem_32k_clk_conf().modify(|_, w| match src {
ModemClockLpclkSource::RcSlow
| ModemClockLpclkSource::RcFast
| ModemClockLpclkSource::MainXtal => w,
ModemClockLpclkSource::RC32K => w.clk_modem_32k_sel().bits(1),
ModemClockLpclkSource::XTAL32K => w.clk_modem_32k_sel().bits(0),
ModemClockLpclkSource::EXT32K => w.clk_modem_32k_sel().bits(2),
});
}
}
fn modem_lpcon_ll_set_wifi_lpclk_divisor_value(divider: u16) {
unsafe {
modem_lpcon()
.wifi_lp_clk_conf()
.modify(|_, w| w.clk_wifipwr_lp_div_num().bits(divider));
}
}
fn modem_clock_hal_enable_wifipwr_clock(enable: bool) {
unsafe {
modem_lpcon()
.clk_conf()
.modify(|_, w| w.clk_wifipwr_en().bit(enable));
}
}
fn modem_clock_select_lp_clock_source(
periph: RadioPeripherals,
src: ModemClockLpclkSource,
divider: u16,
) {
match periph {
RadioPeripherals::Wifi => {
modem_clock_hal_deselect_all_wifi_lpclk_source();
modem_clock_hal_select_wifi_lpclk_source(src);
modem_lpcon_ll_set_wifi_lpclk_divisor_value(divider);
modem_clock_hal_enable_wifipwr_clock(true);
}
RadioPeripherals::Phy | RadioPeripherals::Bt | RadioPeripherals::Ieee802154 => {
todo!("unused by setup code")
}
}
}
const fn hp_retention_regdma_config(dir: u8, entry: u8) -> u8 {
(((dir) << 2) | (entry & 0x3)) & 0x7
}
const HP_CALI_DBIAS: u8 = 25;
const LP_CALI_DBIAS: u8 = 26;
const ICG_MODEM_CODE_SLEEP: u8 = 0;
const ICG_MODEM_CODE_MODEM: u8 = 1;
const ICG_MODEM_CODE_ACTIVE: u8 = 2;
const HP_SYSCLK_XTAL: u8 = 0;
const HP_SYSCLK_PLL: u8 = 1;
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct HpDigPower(u32);
pub bool, vdd_spi_pd_en, set_vdd_spi_pd_en: 21;
pub bool, mem_dslp , set_mem_dslp : 22;
pub u8, mem_pd_en , set_mem_pd_en : 26, 23;
pub bool, wifi_pd_en , set_wifi_pd_en : 27;
pub bool, cpu_pd_en , set_cpu_pd_en : 29;
pub bool, aon_pd_en , set_aon_pd_en : 30;
pub bool, top_pd_en , set_top_pd_en : 31;
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct HpClkPower(u32);
pub bool, i2c_iso_en , set_i2c_iso_en : 26;
pub bool, i2c_retention, set_i2c_retention: 27;
pub bool, xpd_bb_i2c , set_xpd_bb_i2c : 28;
pub bool, xpd_bbpll_i2c, set_xpd_bbpll_i2c: 29;
pub bool, xpd_bbpll , set_xpd_bbpll : 30;
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct HpXtalPower(u32);
pub bool, xpd_xtal , set_xpd_xtal : 31;
}
#[derive(Clone, Copy, Default)]
pub struct HpSysPower {
pub dig_power: HpDigPower,
pub clk: HpClkPower,
pub xtal: HpXtalPower,
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct HpSysCntlReg(u32);
pub bool, uart_wakeup_en , set_uart_wakeup_en : 24;
pub bool, lp_pad_hold_all, set_lp_pad_hold_all: 25;
pub bool, hp_pad_hold_all, set_hp_pad_hold_all: 26;
pub bool, dig_pad_slp_sel, set_dig_pad_slp_sel: 27;
pub bool, dig_pause_wdt , set_dig_pause_wdt : 28;
pub bool, dig_cpu_stall , set_dig_cpu_stall : 29;
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct HpIcgModem(u32);
pub u8, code, set_code: 31, 30;
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct HpSysclk(u32);
pub bool, dig_sysclk_nodiv , set_dig_sysclk_nodiv : 26;
pub bool, icg_sysclk_en , set_icg_sysclk_en : 27;
pub bool, sysclk_slp_sel , set_sysclk_slp_sel : 28;
pub bool, icg_slp_sel , set_icg_slp_sel : 29;
pub u8, dig_sysclk_sel , set_dig_sysclk_sel : 31, 30;
}
#[derive(Clone, Copy, Default)]
struct SystemClockParam {
icg_func: u32,
icg_apb: u32,
icg_modem: HpIcgModem,
sysclk: HpSysclk,
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct HpAnalogBias(u32);
pub bool, xpd_bias , set_xpd_bias : 25;
pub u8, dbg_atten , set_dbg_atten : 29, 26;
pub bool, pd_cur , set_pd_cur : 30;
pub bool, bias_sleep, set_bias_sleep: 31;
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct HpAnalogRegulator0(u32);
pub u8, lp_dbias_vol , set_lp_dbias_vol : 8, 4;
pub u8, hp_dbias_vol , set_hp_dbias_vol : 13, 9;
pub bool, dbias_sel , set_dbias_sel : 14;
pub bool, dbias_init , set_dbias_init : 15;
pub bool, slp_mem_xpd , set_slp_mem_xpd : 16;
pub bool, slp_logic_xpd , set_slp_logic_xpd : 17;
pub bool, xpd , set_xpd : 18;
pub u8, slp_mem_dbias , set_slp_mem_dbias : 22, 19;
pub u8, slp_logic_dbias, set_slp_logic_dbias: 26, 23;
pub u8, dbias , set_dbias : 31, 27;
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct HpAnalogRegulator1(u32);
pub u32, drv_b , set_drv_b : 31, 8;
}
#[derive(Clone, Copy, Default)]
pub struct HpAnalog {
pub bias: HpAnalogBias,
pub regulator0: HpAnalogRegulator0,
pub regulator1: HpAnalogRegulator1,
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct HpActiveBackup(u32);
pub u8, hp_sleep2active_backup_modem_clk_code, set_hp_sleep2active_backup_modem_clk_code: 5, 4;
pub u8, hp_modem2active_backup_modem_clk_code, set_hp_modem2active_backup_modem_clk_code: 7, 6;
pub bool, hp_active_retention_mode , set_hp_active_retention_mode : 10;
pub bool, hp_sleep2active_retention_en , set_hp_sleep2active_retention_en : 11;
pub bool, hp_modem2active_retention_en , set_hp_modem2active_retention_en : 12;
pub u8, hp_sleep2active_backup_clk_sel , set_hp_sleep2active_backup_clk_sel : 15, 14;
pub u8, hp_modem2active_backup_clk_sel , set_hp_modem2active_backup_clk_sel : 17, 16;
pub u8, hp_sleep2active_backup_mode , set_hp_sleep2active_backup_mode : 22, 20;
pub u8, hp_modem2active_backup_mode , set_hp_modem2active_backup_mode : 25, 23;
pub bool, hp_sleep2active_backup_en , set_hp_sleep2active_backup_en : 29;
pub bool, hp_modem2active_backup_en , set_hp_modem2active_backup_en : 30;
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct HpModemBackup(u32);
pub u8, hp_sleep2modem_backup_modem_clk_code , set_hp_sleep2modem_backup_modem_clk_code : 5, 4;
pub bool, hp_modem_retention_mode , set_hp_modem_retention_mode : 10;
pub bool, hp_sleep2modem_retention_en , set_hp_sleep2modem_retention_en : 11;
pub u8, hp_sleep2modem_backup_clk_sel , set_hp_sleep2modem_backup_clk_sel : 15, 14;
pub u8, hp_sleep2modem_backup_mode , set_hp_sleep2modem_backup_mode : 22, 20;
pub bool, hp_sleep2modem_backup_en , set_hp_sleep2modem_backup_en : 29;
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct HpSleepBackup(u32);
pub u8, hp_modem2sleep_backup_modem_clk_code , set_hp_modem2sleep_backup_modem_clk_code : 7, 6;
pub u8, hp_active2sleep_backup_modem_clk_code, set_hp_active2sleep_backup_modem_clk_code: 9, 8;
pub bool, hp_sleep_retention_mode , set_hp_sleep_retention_mode : 10;
pub bool, hp_modem2sleep_retention_en , set_hp_modem2sleep_retention_en : 12;
pub bool, hp_active2sleep_retention_en , set_hp_active2sleep_retention_en : 13;
pub u8, hp_modem2sleep_backup_clk_sel , set_hp_modem2sleep_backup_clk_sel : 17, 16;
pub u8, hp_active2sleep_backup_clk_sel , set_hp_active2sleep_backup_clk_sel : 19, 18;
pub u8, hp_modem2sleep_backup_mode , set_hp_modem2sleep_backup_mode : 25, 23;
pub u8, hp_active2sleep_backup_mode , set_hp_active2sleep_backup_mode : 28, 26;
pub bool, hp_modem2sleep_backup_en , set_hp_modem2sleep_backup_en : 30;
pub bool, hp_active2sleep_backup_en , set_hp_active2sleep_backup_en : 31;
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct HpBackupClk(u32);
pub bool, gdma , set_gdma : 0;
pub bool, spi2 , set_spi2 : 1;
pub bool, i2s_rx , set_i2s_rx : 2;
pub bool, uart0 , set_uart0 : 3;
pub bool, uart1 , set_uart1 : 4;
pub bool, uhci , set_uhci : 5;
pub bool, usb_device , set_usb_device : 6;
pub bool, i2s_tx , set_i2s_tx : 7;
pub bool, regdma , set_regdma : 8;
pub bool, retention , set_retention : 9;
pub bool, mem_monitor , set_mem_monitor : 10;
pub bool, sdio_slave , set_sdio_slave : 11;
pub bool, tsens , set_tsens : 12;
pub bool, tg1 , set_tg1 : 13;
pub bool, tg0 , set_tg0 : 14;
pub bool, hpbus , set_hpbus : 15;
pub bool, soc_etm , set_soc_etm : 16;
pub bool, hpcore , set_hpcore : 17;
pub bool, systimer , set_systimer : 18;
pub bool, sec , set_sec : 19;
pub bool, saradc , set_saradc : 20;
pub bool, rmt , set_rmt : 21;
pub bool, pwm , set_pwm : 22;
pub bool, pvt_monitor , set_pvt_monitor : 23;
pub bool, parl_tx , set_parl_tx : 24;
pub bool, parl_rx , set_parl_rx : 25;
pub bool, mspi , set_mspi : 26;
pub bool, ledc , set_ledc : 27;
pub bool, iomux , set_iomux : 28;
pub bool, i2c , set_i2c : 29;
pub bool, can1 , set_can1 : 30;
pub bool, can0 , set_can0 : 31;
}
macro_rules! hp_system_init {
($state:ident => $s:ident) => {
paste::paste! {
unsafe {
pmu().[<$state _dig_power >]().modify(|_, w| w.bits($s.power.dig_power.0));
pmu().[<$state _hp_ck_power >]().modify(|_, w| w.bits($s.power.clk.0));
pmu().[<$state _xtal >]().modify(|_, w| w
.[<$state _xpd_xtal >]().bit($s.power.xtal.xpd_xtal())
);
pmu().[<$state _icg_hp_func >]().write(|w| w.bits($s.clock.icg_func));
pmu().[<$state _icg_hp_apb >]().write(|w| w.bits($s.clock.icg_apb));
pmu().[<$state _icg_modem >]().write(|w| w
.[<$state _dig_icg_modem_code >]().bits($s.clock.icg_modem.code())
);
pmu().[<$state _sysclk >]().modify(|_, w| w
.[<$state _dig_sys_clk_no_div >]().bit($s.clock.sysclk.dig_sysclk_nodiv())
.[<$state _icg_sys_clock_en >]().bit($s.clock.sysclk.icg_sysclk_en())
.[<$state _sys_clk_slp_sel >]().bit($s.clock.sysclk.sysclk_slp_sel())
.[<$state _icg_slp_sel >]().bit($s.clock.sysclk.icg_slp_sel())
.[<$state _dig_sys_clk_sel >]().bits($s.clock.sysclk.dig_sysclk_sel())
);
pmu().[<$state _hp_sys_cntl >]().modify(|_, w| w
.[<$state _uart_wakeup_en >]().bit($s.syscntl.uart_wakeup_en())
.[<$state _lp_pad_hold_all >]().bit($s.syscntl.lp_pad_hold_all())
.[<$state _hp_pad_hold_all >]().bit($s.syscntl.hp_pad_hold_all())
.[<$state _dig_pad_slp_sel >]().bit($s.syscntl.dig_pad_slp_sel())
.[<$state _dig_pause_wdt >]().bit($s.syscntl.dig_pause_wdt())
.[<$state _dig_cpu_stall >]().bit($s.syscntl.dig_cpu_stall())
);
pmu().[<$state _bias >]().modify(|_, w| w
.[<$state _xpd_bias >]().bit($s.anlg.bias.xpd_bias())
.[<$state _dbg_atten >]().bits($s.anlg.bias.dbg_atten())
.[<$state _pd_cur >]().bit($s.anlg.bias.pd_cur())
.sleep().bit($s.anlg.bias.bias_sleep())
);
pmu().[<$state _hp_regulator0 >]().modify(|_, w| w
.[<$state _hp_regulator_slp_mem_xpd >]().bit($s.anlg.regulator0.slp_mem_xpd())
.[<$state _hp_regulator_slp_logic_xpd >]().bit($s.anlg.regulator0.slp_logic_xpd())
.[<$state _hp_regulator_xpd >]().bit($s.anlg.regulator0.xpd())
.[<$state _hp_regulator_slp_mem_dbias >]().bits($s.anlg.regulator0.slp_mem_dbias())
.[<$state _hp_regulator_slp_logic_dbias >]().bits($s.anlg.regulator0.slp_logic_dbias())
.[<$state _hp_regulator_dbias >]().bits($s.anlg.regulator0.dbias())
);
pmu().[<$state _hp_regulator1 >]().modify(|_, w| w
.[<$state _hp_regulator_drv_b >]().bits($s.anlg.regulator1.drv_b())
);
pmu().[<$state _backup >]().write(|w| w.bits($s.retention));
pmu().[<$state _backup_clk >]().write(|w| w.bits($s.backup_clk));
}
}
};
}
struct HpSystemInit {
power: HpSysPower,
clock: SystemClockParam,
syscntl: HpSysCntlReg,
anlg: HpAnalog,
retention: u32,
backup_clk: u32,
}
impl HpSystemInit {
fn active() -> Self {
let mut power = HpSysPower::default();
power.dig_power.set_vdd_spi_pd_en(false);
power.dig_power.set_wifi_pd_en(false);
power.dig_power.set_cpu_pd_en(false);
power.dig_power.set_aon_pd_en(false);
power.dig_power.set_top_pd_en(false);
power.dig_power.set_mem_pd_en(0);
power.dig_power.set_mem_dslp(false);
power.clk.set_i2c_iso_en(false);
power.clk.set_i2c_retention(false);
power.clk.set_xpd_bb_i2c(true);
power.clk.set_xpd_bbpll_i2c(true);
power.clk.set_xpd_bbpll(true);
power.xtal.set_xpd_xtal(true);
let mut clock = SystemClockParam {
icg_func: 0xffffffff,
icg_apb: 0xffffffff,
..SystemClockParam::default()
};
clock.icg_modem.set_code(ICG_MODEM_CODE_ACTIVE);
clock.sysclk.set_dig_sysclk_nodiv(false);
clock.sysclk.set_icg_sysclk_en(true);
clock.sysclk.set_sysclk_slp_sel(false);
clock.sysclk.set_icg_slp_sel(false);
clock.sysclk.set_dig_sysclk_sel(HP_SYSCLK_XTAL);
let mut syscntl = HpSysCntlReg::default();
syscntl.set_uart_wakeup_en(false);
syscntl.set_lp_pad_hold_all(false);
syscntl.set_hp_pad_hold_all(false);
syscntl.set_dig_pad_slp_sel(false);
syscntl.set_dig_pause_wdt(false);
syscntl.set_dig_cpu_stall(false);
let mut anlg = HpAnalog::default();
anlg.bias.set_xpd_bias(true);
anlg.bias.set_dbg_atten(0x0);
anlg.bias.set_pd_cur(false);
anlg.bias.set_bias_sleep(false);
anlg.regulator0.set_lp_dbias_vol(0xD);
anlg.regulator0.set_hp_dbias_vol(0x1C);
anlg.regulator0.set_dbias_sel(true);
anlg.regulator0.set_dbias_init(true);
anlg.regulator0.set_slp_mem_xpd(false);
anlg.regulator0.set_slp_logic_xpd(false);
anlg.regulator0.set_xpd(true);
anlg.regulator0.set_slp_mem_dbias(0);
anlg.regulator0.set_slp_logic_dbias(0);
anlg.regulator0.set_dbias(HP_CALI_DBIAS);
anlg.regulator1.set_drv_b(0);
let mut retention = HpActiveBackup::default();
retention.set_hp_sleep2active_backup_modem_clk_code(2);
retention.set_hp_modem2active_backup_modem_clk_code(2);
retention.set_hp_active_retention_mode(false);
retention.set_hp_sleep2active_retention_en(false);
retention.set_hp_modem2active_retention_en(false);
retention.set_hp_sleep2active_backup_clk_sel(0);
retention.set_hp_modem2active_backup_clk_sel(1);
retention.set_hp_sleep2active_backup_mode(hp_retention_regdma_config(0, 0));
retention.set_hp_modem2active_backup_mode(hp_retention_regdma_config(0, 2));
retention.set_hp_sleep2active_backup_en(false);
retention.set_hp_modem2active_backup_en(false);
let mut backup_clk = HpBackupClk::default();
backup_clk.set_regdma(true);
backup_clk.set_tg0(true);
backup_clk.set_tg1(true);
backup_clk.set_hpbus(true);
backup_clk.set_mspi(true);
backup_clk.set_iomux(true);
backup_clk.set_spi2(true);
backup_clk.set_uart0(true);
backup_clk.set_systimer(true);
Self {
power,
clock,
syscntl,
anlg,
retention: retention.0,
backup_clk: backup_clk.0,
}
}
fn modem() -> Self {
let mut power = HpSysPower::default();
power.dig_power.set_vdd_spi_pd_en(false);
power.dig_power.set_wifi_pd_en(false);
power.dig_power.set_cpu_pd_en(true);
power.dig_power.set_aon_pd_en(false);
power.dig_power.set_top_pd_en(false);
power.dig_power.set_mem_pd_en(0);
power.dig_power.set_mem_dslp(false);
power.clk.set_xpd_bb_i2c(true);
power.clk.set_xpd_bbpll_i2c(true);
power.clk.set_xpd_bbpll(true);
power.clk.set_i2c_iso_en(false);
power.clk.set_i2c_retention(false);
power.xtal.set_xpd_xtal(true);
let mut clock = SystemClockParam {
icg_func: 0,
icg_apb: 0,
..SystemClockParam::default()
};
clock.icg_modem.set_code(ICG_MODEM_CODE_MODEM);
clock.sysclk.set_dig_sysclk_nodiv(false);
clock.sysclk.set_icg_sysclk_en(true);
clock.sysclk.set_sysclk_slp_sel(true);
clock.sysclk.set_icg_slp_sel(true);
clock.sysclk.set_dig_sysclk_sel(HP_SYSCLK_PLL);
let mut syscntl = HpSysCntlReg::default();
syscntl.set_uart_wakeup_en(true);
syscntl.set_lp_pad_hold_all(false);
syscntl.set_hp_pad_hold_all(false);
syscntl.set_dig_pad_slp_sel(false);
syscntl.set_dig_pause_wdt(true);
syscntl.set_dig_cpu_stall(true);
let mut anlg = HpAnalog::default();
anlg.bias.set_xpd_bias(false);
anlg.bias.set_dbg_atten(0x0);
anlg.bias.set_pd_cur(false);
anlg.bias.set_bias_sleep(false);
anlg.regulator0.set_slp_mem_xpd(false);
anlg.regulator0.set_slp_logic_xpd(false);
anlg.regulator0.set_xpd(true);
anlg.regulator0.set_slp_mem_dbias(0);
anlg.regulator0.set_slp_logic_dbias(0);
anlg.regulator0.set_dbias(HP_CALI_DBIAS);
anlg.regulator1.set_drv_b(0);
let mut retention = HpModemBackup::default();
retention.set_hp_sleep2modem_backup_modem_clk_code(1);
retention.set_hp_modem_retention_mode(false);
retention.set_hp_sleep2modem_retention_en(false);
retention.set_hp_sleep2modem_backup_clk_sel(0);
retention.set_hp_sleep2modem_backup_mode(hp_retention_regdma_config(0, 1));
retention.set_hp_sleep2modem_backup_en(false);
let mut backup_clk = HpBackupClk::default();
backup_clk.set_regdma(true);
backup_clk.set_tg0(true);
backup_clk.set_tg1(true);
backup_clk.set_hpbus(true);
backup_clk.set_mspi(true);
backup_clk.set_iomux(true);
backup_clk.set_spi2(true);
backup_clk.set_uart0(true);
backup_clk.set_systimer(true);
Self {
power,
clock,
syscntl,
anlg,
retention: retention.0,
backup_clk: backup_clk.0,
}
}
fn sleep() -> Self {
let mut power = HpSysPower::default();
power.dig_power.set_vdd_spi_pd_en(true);
power.dig_power.set_mem_dslp(false);
power.dig_power.set_mem_pd_en(0);
power.dig_power.set_wifi_pd_en(true);
power.dig_power.set_cpu_pd_en(false);
power.dig_power.set_aon_pd_en(false);
power.dig_power.set_top_pd_en(false);
power.clk.set_i2c_iso_en(true);
power.clk.set_i2c_retention(true);
power.clk.set_xpd_bb_i2c(true);
power.clk.set_xpd_bbpll_i2c(false);
power.clk.set_xpd_bbpll(false);
power.xtal.set_xpd_xtal(false);
let mut clock = SystemClockParam {
icg_func: 0,
icg_apb: 0,
..SystemClockParam::default()
};
clock.icg_modem.set_code(ICG_MODEM_CODE_SLEEP);
clock.sysclk.set_dig_sysclk_nodiv(false);
clock.sysclk.set_icg_sysclk_en(false);
clock.sysclk.set_sysclk_slp_sel(true);
clock.sysclk.set_icg_slp_sel(true);
clock.sysclk.set_dig_sysclk_sel(HP_SYSCLK_XTAL);
let mut anlg = HpAnalog::default();
anlg.bias.set_xpd_bias(false);
anlg.bias.set_dbg_atten(0x0);
anlg.bias.set_pd_cur(false);
anlg.bias.set_bias_sleep(false);
anlg.regulator0.set_slp_mem_xpd(false);
anlg.regulator0.set_slp_logic_xpd(false);
anlg.regulator0.set_xpd(true);
anlg.regulator0.set_slp_mem_dbias(0);
anlg.regulator0.set_slp_logic_dbias(0);
anlg.regulator0.set_dbias(1);
anlg.regulator1.set_drv_b(0);
let mut retention = HpSleepBackup::default();
retention.set_hp_modem2sleep_backup_modem_clk_code(0);
retention.set_hp_active2sleep_backup_modem_clk_code(2);
retention.set_hp_sleep_retention_mode(false);
retention.set_hp_modem2sleep_retention_en(false);
retention.set_hp_active2sleep_retention_en(false);
retention.set_hp_modem2sleep_backup_clk_sel(0);
retention.set_hp_active2sleep_backup_clk_sel(0);
retention.set_hp_modem2sleep_backup_mode(hp_retention_regdma_config(1, 1));
retention.set_hp_active2sleep_backup_mode(hp_retention_regdma_config(1, 0));
retention.set_hp_modem2sleep_backup_en(false);
retention.set_hp_active2sleep_backup_en(false);
let mut backup_clk = HpBackupClk::default();
backup_clk.set_regdma(true);
backup_clk.set_tg0(true);
backup_clk.set_tg1(true);
backup_clk.set_hpbus(true);
backup_clk.set_mspi(true);
backup_clk.set_iomux(true);
backup_clk.set_spi2(true);
backup_clk.set_uart0(true);
backup_clk.set_systimer(true);
let mut syscntl = HpSysCntlReg::default();
syscntl.set_uart_wakeup_en(true);
syscntl.set_lp_pad_hold_all(false);
syscntl.set_hp_pad_hold_all(false);
syscntl.set_dig_pad_slp_sel(true);
syscntl.set_dig_pause_wdt(true);
syscntl.set_dig_cpu_stall(true);
Self {
power,
clock,
syscntl,
anlg,
retention: retention.0,
backup_clk: backup_clk.0,
}
}
fn init_default() {
let active = Self::active();
let modem = Self::modem();
let sleep = Self::sleep();
hp_system_init!(hp_active => active);
hp_system_init!(hp_modem => modem);
hp_system_init!(hp_sleep => sleep);
unsafe {
pmu()
.imm_modem_icg()
.write(|w| w.update_dig_icg_modem_en().bit(true));
pmu()
.imm_sleep_sysclk()
.write(|w| w.update_dig_icg_switch().bit(true));
const PMU_SLEEP_PROTECT_HP_LP_SLEEP: u8 = 2;
pmu()
.slp_wakeup_cntl3()
.modify(|_, w| w.sleep_prt_sel().bits(PMU_SLEEP_PROTECT_HP_LP_SLEEP));
}
}
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct LpDigPower(u32);
pub u32, mem_dslp , set_mem_dslp : 30;
pub u32, peri_pd_en, set_peri_pd_en: 31;
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct LpClkPower(u32);
pub u32, xpd_xtal32k, set_xpd_xtal32k: 28;
pub u32, xpd_rc32k , set_xpd_rc32k : 29;
pub u32, xpd_fosc , set_xpd_fosc : 30;
pub u32, pd_osc , set_pd_osc : 31;
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct LpXtalPower(u32);
pub bool, xpd_xtal , set_xpd_xtal : 31;
}
#[derive(Clone, Copy, Default)]
pub struct LpSysPower {
pub dig_power: LpDigPower,
pub clk_power: LpClkPower,
pub xtal: LpXtalPower,
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct LpAnalogBias(u32);
pub bool, xpd_bias , set_xpd_bias : 25;
pub u8, dbg_atten , set_dbg_atten : 29, 26;
pub bool, pd_cur , set_pd_cur : 30;
pub bool, bias_sleep, set_bias_sleep: 31;
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct LpAnalogRegulator0(u32);
pub bool, slp_xpd , set_slp_xpd : 21;
pub bool, xpd , set_xpd : 22;
pub u8, slp_dbias, set_slp_dbias: 26, 23;
pub u8, dbias , set_dbias : 31, 27;
}
bitfield::bitfield! {
#[derive(Clone, Copy, Default)]
pub struct LpAnalogRegulator1(u32);
pub u8, drv_b , set_drv_b : 31, 28;
}
#[derive(Clone, Copy, Default)]
pub struct LpAnalog {
pub bias: LpAnalogBias,
pub regulator0: LpAnalogRegulator0,
pub regulator1: LpAnalogRegulator1,
}
macro_rules! lp_system_init {
($state:ident => $s:ident) => {
paste::paste! {
unsafe {
pmu().[< $state _dig_power >]().modify(|_, w| w.bits($s.dig_power.0));
pmu().[< $state _ck_power >]().modify(|_, w| w.bits($s.clk_power.0));
pmu().[< $state _regulator0 >]().modify(|_, w| w
.[< $state _regulator_slp_xpd >]().bit($s.analog_regulator0.slp_xpd())
.[< $state _regulator_xpd >]().bit($s.analog_regulator0.xpd())
.[< $state _regulator_slp_dbias >]().bits($s.analog_regulator0.slp_dbias())
.[< $state _regulator_dbias >]().bits($s.analog_regulator0.dbias())
);
pmu().[< $state _regulator1 >]().modify(|_, w| w
.[< $state _regulator_drv_b >]().bits($s.analog_regulator1.drv_b())
);
}
}
};
}
struct LpSystemInit {
dig_power: LpDigPower,
clk_power: LpClkPower,
xtal: LpXtalPower,
bias: LpAnalogBias,
analog_regulator0: LpAnalogRegulator0,
analog_regulator1: LpAnalogRegulator1,
}
impl LpSystemInit {
fn active() -> Self {
let mut dig_power = LpDigPower::default();
dig_power.set_peri_pd_en(false);
dig_power.set_mem_dslp(false);
let mut clk_power = LpClkPower::default();
clk_power.set_xpd_xtal32k(true);
clk_power.set_xpd_rc32k(true);
clk_power.set_xpd_fosc(true);
let mut analog_regulator0 = LpAnalogRegulator0::default();
analog_regulator0.set_slp_xpd(false);
analog_regulator0.set_xpd(true);
analog_regulator0.set_slp_dbias(0);
analog_regulator0.set_dbias(26);
let mut analog_regulator1 = LpAnalogRegulator1::default();
analog_regulator1.set_drv_b(0);
Self {
dig_power,
clk_power,
xtal: LpXtalPower::default(),
bias: LpAnalogBias::default(),
analog_regulator0,
analog_regulator1,
}
}
fn sleep() -> Self {
let mut dig_power = LpDigPower::default();
dig_power.set_mem_dslp(true);
dig_power.set_peri_pd_en(false);
let mut clk_power = LpClkPower::default();
clk_power.set_xpd_xtal32k(false);
clk_power.set_xpd_rc32k(false);
clk_power.set_xpd_fosc(false);
clk_power.set_pd_osc(false);
let mut xtal = LpXtalPower::default();
xtal.set_xpd_xtal(false);
let mut analog_bias = LpAnalogBias::default();
analog_bias.set_xpd_bias(false);
analog_bias.set_dbg_atten(0);
analog_bias.set_pd_cur(true);
analog_bias.set_bias_sleep(true);
let mut analog_regulator0 = LpAnalogRegulator0::default();
analog_regulator0.set_slp_xpd(false);
analog_regulator0.set_xpd(true);
analog_regulator0.set_slp_dbias(0);
analog_regulator0.set_dbias(12);
let mut analog_regulator1 = LpAnalogRegulator1::default();
analog_regulator1.set_drv_b(0);
Self {
dig_power,
clk_power,
xtal,
bias: analog_bias,
analog_regulator0,
analog_regulator1,
}
}
fn init_default() {
let active = Self::active();
let sleep = Self::sleep();
lp_system_init!(hp_sleep_lp => active);
lp_system_init!(lp_sleep_lp => sleep);
unsafe {
pmu()
.lp_sleep_xtal()
.modify(|_, w| w.lp_sleep_xpd_xtal().bit(sleep.xtal.xpd_xtal()));
pmu().lp_sleep_bias().modify(|_, w| {
w.lp_sleep_xpd_bias() .bit(sleep.bias.xpd_bias())
.lp_sleep_dbg_atten() .bits(sleep.bias.dbg_atten())
.lp_sleep_pd_cur() .bit(sleep.bias.pd_cur())
.sleep() .bit(sleep.bias.bias_sleep())
});
}
}
}
pub(crate) fn init() {
let pmu = unsafe { pmu() };
pmu.rf_pwc()
.modify(|_, w| w.perif_i2c_rstb().set_bit().xpd_perif_i2c().set_bit());
regi2c_write_mask(
I2C_DIG_REG,
I2C_DIG_REG_HOSTID,
I2C_DIG_REG_ENIF_RTC_DREG,
I2C_DIG_REG_ENIF_RTC_DREG_MSB,
I2C_DIG_REG_ENIF_RTC_DREG_LSB,
1,
);
regi2c_write_mask(
I2C_DIG_REG,
I2C_DIG_REG_HOSTID,
I2C_DIG_REG_ENIF_DIG_DREG,
I2C_DIG_REG_ENIF_DIG_DREG_MSB,
I2C_DIG_REG_ENIF_DIG_DREG_LSB,
1,
);
regi2c_write_mask(
I2C_DIG_REG,
I2C_DIG_REG_HOSTID,
I2C_DIG_REG_XPD_RTC_REG,
I2C_DIG_REG_XPD_RTC_REG_MSB,
I2C_DIG_REG_XPD_RTC_REG_LSB,
0,
);
regi2c_write_mask(
I2C_DIG_REG,
I2C_DIG_REG_HOSTID,
I2C_DIG_REG_XPD_DIG_REG,
I2C_DIG_REG_XPD_DIG_REG_MSB,
I2C_DIG_REG_XPD_DIG_REG_LSB,
0,
);
HpSystemInit::init_default();
LpSystemInit::init_default();
pmu_power_domain_force_default();
modem_clock_domain_power_state_icg_map_init();
let modem_lpclk_src = ModemClockLpclkSource::from(RtcSlowClockSource::current());
modem_clock_select_lp_clock_source(RadioPeripherals::Wifi, modem_lpclk_src, 0);
}
pub(crate) fn configure_clock() {
assert!(matches!(RtcClock::xtal_freq(), XtalClock::RtcXtalFreq40M));
RtcClock::set_fast_freq(RtcFastClock::RtcFastClockRcFast);
let cal_val = loop {
RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRcSlow);
let res = RtcClock::calibrate(RtcCalSel::RtcCalRtcMux, 1024);
if res != 0 {
break res;
}
};
unsafe {
lp_aon().store1().modify(|_, w| w.bits(cal_val));
}
modem_clk_domain_active_state_icg_map_preinit();
}
fn modem_clk_domain_active_state_icg_map_preinit() {
unsafe {
pmu()
.hp_active_icg_modem()
.modify(|_, w| w.hp_active_dig_icg_modem_code().bits(ICG_MODEM_CODE_ACTIVE));
modem_syscon()
.clk_conf_power_st()
.modify(|_, w| w.clk_modem_apb_st_map().bits(1 << ICG_MODEM_CODE_ACTIVE));
modem_lpcon().clk_conf_power_st().modify(|_, w| {
w.clk_i2c_mst_st_map()
.bits(1 << ICG_MODEM_CODE_ACTIVE)
.clk_lp_apb_st_map()
.bits(1 << ICG_MODEM_CODE_ACTIVE)
});
pmu()
.imm_modem_icg()
.write(|w| w.update_dig_icg_modem_en().set_bit());
pmu()
.imm_sleep_sysclk()
.write(|w| w.update_dig_icg_switch().set_bit());
lp_clkrst()
.fosc_cntl()
.modify(|_, w| w.fosc_dfreq().bits(100));
regi2c_write_mask(
I2C_DIG_REG,
I2C_DIG_REG_HOSTID,
I2C_DIG_REG_SCK_DCAP,
I2C_DIG_REG_SCK_DCAP_MSB,
I2C_DIG_REG_SCK_DCAP_LSB,
128,
);
lp_clkrst()
.rc32k_cntl()
.modify(|_, w| w.rc32k_dfreq().bits(700));
regi2c_write_mask(
I2C_DIG_REG,
I2C_DIG_REG_HOSTID,
I2C_DIG_REG_ENIF_RTC_DREG,
I2C_DIG_REG_ENIF_RTC_DREG_MSB,
I2C_DIG_REG_ENIF_RTC_DREG_LSB,
1,
);
regi2c_write_mask(
I2C_DIG_REG,
I2C_DIG_REG_HOSTID,
I2C_DIG_REG_ENIF_DIG_DREG,
I2C_DIG_REG_ENIF_DIG_DREG_MSB,
I2C_DIG_REG_ENIF_DIG_DREG_LSB,
1,
);
pmu()
.hp_active_hp_regulator0()
.modify(|_, w| w.hp_active_hp_regulator_dbias().bits(HP_CALI_DBIAS));
pmu()
.hp_sleep_lp_regulator0()
.modify(|_, w| w.hp_sleep_lp_regulator_dbias().bits(LP_CALI_DBIAS));
pcr()
.ctrl_tick_conf()
.modify(|_, w| w.fosc_tick_num().bits(255));
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromRepr)]
pub enum SocResetReason {
ChipPowerOn = 0x01,
CoreSw = 0x03,
CoreDeepSleep = 0x05,
CoreSDIO = 0x06,
CoreMwdt0 = 0x07,
CoreMwdt1 = 0x08,
CoreRtcWdt = 0x09,
Cpu0Mwdt0 = 0x0B,
Cpu0Sw = 0x0C,
Cpu0RtcWdt = 0x0D,
SysBrownOut = 0x0F,
SysRtcWdt = 0x10,
Cpu0Mwdt1 = 0x11,
SysSuperWdt = 0x12,
CoreEfuseCrc = 0x14,
CoreUsbUart = 0x15,
CoreUsbJtag = 0x16,
Cpu0JtagCpu = 0x18,
}
#[allow(unused)]
#[derive(Debug, Clone, Copy)]
pub(crate) enum RtcFastClock {
RtcFastClockRcFast = 0,
RtcFastClockXtalD2 = 1,
}
impl Clock for RtcFastClock {
fn frequency(&self) -> HertzU32 {
match self {
RtcFastClock::RtcFastClockXtalD2 => HertzU32::Hz(40_000_000 / 2), RtcFastClock::RtcFastClockRcFast => HertzU32::Hz(17_500_000),
}
}
}
#[allow(clippy::enum_variant_names)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum RtcSlowClock {
RtcSlowClockRcSlow = 0,
RtcSlowClock32kXtal = 1,
RtcSlowClock32kRc = 2,
RtcSlowOscSlow = 3,
}
impl Clock for RtcSlowClock {
fn frequency(&self) -> HertzU32 {
match self {
RtcSlowClock::RtcSlowClockRcSlow => HertzU32::Hz(136_000),
RtcSlowClock::RtcSlowClock32kXtal => HertzU32::Hz(32_768),
RtcSlowClock::RtcSlowClock32kRc => HertzU32::Hz(32_768),
RtcSlowClock::RtcSlowOscSlow => HertzU32::Hz(32_768),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) enum RtcCalSel {
RtcCalRtcMux = -1,
RtcCalRcSlow = 0,
RtcCal32kXtal = 1,
RtcCal32kRc = 2,
RtcCal32kOscSlow = 3,
RtcCalRcFast,
}
#[derive(Clone)]
pub(crate) enum RtcCaliClkSel {
CaliClkRcSlow = 0,
CaliClkRcFast = 1,
CaliClk32k = 2,
}
impl RtcClock {
pub(crate) fn xtal_freq_mhz() -> u32 {
Self::read_xtal_freq_mhz().unwrap_or(40)
}
pub fn xtal_freq() -> XtalClock {
match Self::xtal_freq_mhz() {
40 => XtalClock::RtcXtalFreq40M,
other => XtalClock::RtcXtalFreqOther(other),
}
}
pub fn slow_freq() -> RtcSlowClock {
let lp_clrst = unsafe { lp_clkrst() };
let slow_freq = lp_clrst.lp_clk_conf().read().slow_clk_sel().bits();
match slow_freq {
0 => RtcSlowClock::RtcSlowClockRcSlow,
1 => RtcSlowClock::RtcSlowClock32kXtal,
2 => RtcSlowClock::RtcSlowClock32kRc,
3 => RtcSlowClock::RtcSlowOscSlow,
_ => unreachable!(),
}
}
fn set_slow_freq(slow_freq: RtcSlowClock) {
unsafe {
lp_clkrst()
.lp_clk_conf()
.modify(|_, w| w.slow_clk_sel().bits(slow_freq as u8));
lp_clkrst().clk_to_hp().modify(|_, w| {
w.icg_hp_xtal32k()
.bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kXtal))
.icg_hp_xtal32k()
.bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kXtal))
});
}
}
fn set_fast_freq(fast_freq: RtcFastClock) {
unsafe {
lp_clkrst().lp_clk_conf().modify(|_, w| {
w.fast_clk_sel().bit(match fast_freq {
RtcFastClock::RtcFastClockRcFast => false,
RtcFastClock::RtcFastClockXtalD2 => true,
})
});
}
crate::rom::ets_delay_us(3);
}
pub(crate) fn calibrate_internal(mut cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
const SOC_CLK_RC_FAST_FREQ_APPROX: u32 = 17_500_000;
const SOC_CLK_RC_SLOW_FREQ_APPROX: u32 = 136_000;
const SOC_CLK_XTAL32K_FREQ_APPROX: u32 = 32768;
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match cal_clk {
RtcCalSel::RtcCalRtcMux => match RtcClock::slow_freq() {
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
_ => cal_clk,
},
RtcCalSel::RtcCal32kOscSlow => RtcCalSel::RtcCalRtcMux,
_ => cal_clk,
};
}
let lp_clkrst = unsafe { lp_clkrst() };
let pcr = unsafe { pcr() };
let pmu = unsafe { pmu() };
let clk_src = RtcClock::slow_freq();
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match clk_src {
RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCal32kOscSlow,
};
}
let cali_clk_sel;
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match clk_src {
RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCalRcSlow,
}
}
if cal_clk == RtcCalSel::RtcCalRcFast {
cali_clk_sel = RtcCaliClkSel::CaliClkRcFast;
} else if cal_clk == RtcCalSel::RtcCalRcSlow {
cali_clk_sel = RtcCaliClkSel::CaliClkRcSlow;
} else {
cali_clk_sel = RtcCaliClkSel::CaliClk32k;
match cal_clk {
RtcCalSel::RtcCalRtcMux | RtcCalSel::RtcCalRcSlow | RtcCalSel::RtcCalRcFast => {}
RtcCalSel::RtcCal32kRc => {
pcr.ctrl_32k_conf()
.modify(|_, w| unsafe { w.clk_32k_sel().bits(0) });
}
RtcCalSel::RtcCal32kXtal => {
pcr.ctrl_32k_conf()
.modify(|_, w| unsafe { w.clk_32k_sel().bits(1) });
}
RtcCalSel::RtcCal32kOscSlow => {
pcr.ctrl_32k_conf()
.modify(|_, w| unsafe { w.clk_32k_sel().bits(2) });
}
}
}
let dig_32k_xtal_enabled = lp_clkrst.clk_to_hp().read().icg_hp_xtal32k().bit_is_set();
if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
lp_clkrst
.clk_to_hp()
.modify(|_, w| w.icg_hp_xtal32k().set_bit());
}
lp_clkrst
.clk_to_hp()
.modify(|_, w| w.icg_hp_xtal32k().set_bit());
pmu.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_xtal32k().set_bit());
pmu.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
let rc_fast_enabled = pmu
.hp_sleep_lp_ck_power()
.read()
.hp_sleep_xpd_fosc_clk()
.bit_is_set();
let dig_rc_fast_enabled = lp_clkrst.clk_to_hp().read().icg_hp_fosc().bit_is_set();
if cal_clk == RtcCalSel::RtcCalRcFast {
if !rc_fast_enabled {
pmu.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
crate::rom::ets_delay_us(50);
}
if !dig_rc_fast_enabled {
lp_clkrst
.clk_to_hp()
.modify(|_, w| w.icg_hp_fosc().set_bit());
crate::rom::ets_delay_us(5);
}
}
let rc32k_enabled = pmu
.hp_sleep_lp_ck_power()
.read()
.hp_sleep_xpd_rc32k()
.bit_is_set();
let dig_rc32k_enabled = lp_clkrst.clk_to_hp().read().icg_hp_osc32k().bit_is_set();
if cal_clk == RtcCalSel::RtcCal32kRc {
if !rc32k_enabled {
pmu.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
crate::rom::ets_delay_us(300);
}
if !dig_rc32k_enabled {
lp_clkrst
.clk_to_hp()
.modify(|_, w| w.icg_hp_osc32k().set_bit());
}
}
let timg0 = unsafe { &*TIMG0::ptr() };
if timg0
.rtccalicfg()
.read()
.rtc_cali_start_cycling()
.bit_is_set()
{
timg0
.rtccalicfg2()
.modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(1) });
while !timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_set()
&& !timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_set()
{}
}
timg0
.rtccalicfg()
.modify(|_, w| unsafe { w.rtc_cali_clk_sel().bits(cali_clk_sel.clone() as u8) });
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start_cycling().clear_bit());
timg0
.rtccalicfg()
.modify(|_, w| unsafe { w.rtc_cali_max().bits(slowclk_cycles as u16) });
let expected_freq = match cali_clk_sel {
RtcCaliClkSel::CaliClk32k => {
timg0.rtccalicfg2().modify(|_, w| unsafe {
w.rtc_cali_timeout_thres().bits(slowclk_cycles << 12)
});
SOC_CLK_XTAL32K_FREQ_APPROX
}
RtcCaliClkSel::CaliClkRcFast => {
timg0
.rtccalicfg2()
.modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(0x01FFFFFF) });
SOC_CLK_RC_FAST_FREQ_APPROX
}
_ => {
timg0.rtccalicfg2().modify(|_, w| unsafe {
w.rtc_cali_timeout_thres().bits(slowclk_cycles << 10)
});
SOC_CLK_RC_SLOW_FREQ_APPROX
}
};
let us_time_estimate = (HertzU32::MHz(slowclk_cycles) / expected_freq).to_Hz();
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start().clear_bit());
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start().set_bit());
crate::rom::ets_delay_us(us_time_estimate);
let cal_val = loop {
if timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_set() {
if Efuse::chip_revision() > 0 {
if cal_clk == RtcCalSel::RtcCalRcFast {
break timg0.rtccalicfg1().read().rtc_cali_value().bits() >> 5;
}
break timg0.rtccalicfg1().read().rtc_cali_value().bits();
} else {
break timg0.rtccalicfg1().read().rtc_cali_value().bits();
}
}
if timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_set() {
break 0;
}
};
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start().clear_bit());
if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
lp_clkrst
.clk_to_hp()
.modify(|_, w| w.icg_hp_xtal32k().clear_bit());
}
if cal_clk == RtcCalSel::RtcCalRcFast {
if rc_fast_enabled {
pmu.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
crate::rom::ets_delay_us(50);
}
if dig_rc_fast_enabled {
lp_clkrst
.clk_to_hp()
.modify(|_, w| w.icg_hp_fosc().set_bit());
crate::rom::ets_delay_us(5);
}
}
if cal_clk == RtcCalSel::RtcCal32kRc {
if rc32k_enabled {
pmu.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
crate::rom::ets_delay_us(300);
}
if dig_rc32k_enabled {
lp_clkrst
.clk_to_hp()
.modify(|_, w| w.icg_hp_osc32k().set_bit());
}
}
cal_val
}
fn calibrate(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
let xtal_freq = RtcClock::xtal_freq();
let mut slowclk_cycles = slowclk_cycles;
if Efuse::chip_revision() > 0 && cal_clk == RtcCalSel::RtcCalRcFast {
slowclk_cycles >>= 5;
}
let xtal_cycles = RtcClock::calibrate_internal(cal_clk, slowclk_cycles) as u64;
let divider = xtal_freq.mhz() as u64 * slowclk_cycles as u64;
let period_64 = ((xtal_cycles << RtcClock::CAL_FRACT) + divider / 2u64 - 1u64) / divider;
(period_64 & u32::MAX as u64) as u32
}
pub(crate) fn cycles_to_1ms() -> u16 {
let period_13q19 = RtcClock::calibrate(
match RtcClock::slow_freq() {
RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRtcMux,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCal32kOscSlow,
},
1024,
);
let period = (100_000_000 * period_13q19 as u64) / (1 << RtcClock::CAL_FRACT);
(100_000_000 * 1000 / period) as u16
}
pub(crate) fn estimate_xtal_frequency() -> u32 {
let timg0 = unsafe { crate::peripherals::TIMG0::steal() };
while timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_clear() {}
timg0.rtccalicfg().modify(|_, w| unsafe {
w.rtc_cali_clk_sel()
.bits(0) .rtc_cali_max()
.bits(100)
.rtc_cali_start_cycling()
.clear_bit()
.rtc_cali_start()
.set_bit()
});
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start().set_bit());
while timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_clear() {}
(timg0.rtccalicfg1().read().rtc_cali_value().bits()
* (RtcSlowClock::RtcSlowClockRcSlow.frequency().to_Hz() / 100))
/ 1_000_000
}
}
pub(crate) fn rtc_clk_cpu_freq_set_xtal() {
let freq = RtcClock::xtal_freq_mhz();
esp32c6_rtc_update_to_xtal_raw(freq, 1);
rtc_clk_bbpll_disable();
}
#[derive(Clone, Copy, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub(crate) struct UnsupportedClockSource;
#[derive(Clone, Copy, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub(crate) enum CpuClockSource {
Xtal,
Pll,
RcFast,
}
impl CpuClockSource {
pub(crate) fn current() -> Result<Self, UnsupportedClockSource> {
let source = match unsafe { pcr().sysclk_conf().read().soc_clk_sel().bits() } {
0 => CpuClockSource::Xtal,
1 => CpuClockSource::Pll,
2 => CpuClockSource::RcFast,
_ => return Err(UnsupportedClockSource),
};
Ok(source)
}
pub(crate) fn select(self) {
unsafe {
pcr().sysclk_conf().modify(|_, w| {
w.soc_clk_sel().bits(match self {
CpuClockSource::Xtal => 0,
CpuClockSource::Pll => 1,
CpuClockSource::RcFast => 2,
})
});
}
}
}
#[derive(Clone, Copy)]
pub(crate) struct SavedClockConfig {
pub source: CpuClockSource,
pub source_freq_mhz: u32,
pub div: u8,
}
impl SavedClockConfig {
pub(crate) fn save() -> Self {
let source = unwrap!(CpuClockSource::current());
let div;
let source_freq_mhz;
match source {
CpuClockSource::Xtal => {
div = esp32c6_cpu_get_ls_divider();
source_freq_mhz = RtcClock::xtal_freq_mhz();
}
CpuClockSource::Pll => {
div = esp32c6_cpu_get_hs_divider();
source_freq_mhz = esp32c6_bbpll_get_freq_mhz();
}
CpuClockSource::RcFast => {
div = esp32c6_cpu_get_ls_divider();
source_freq_mhz = 20;
}
}
SavedClockConfig {
source,
source_freq_mhz,
div,
}
}
fn freq_mhz(&self) -> u32 {
self.source_freq_mhz / self.div as u32
}
pub(crate) fn restore(self) {
let old_source = unwrap!(CpuClockSource::current());
match self.source {
CpuClockSource::Xtal => esp32c6_rtc_update_to_xtal_raw(self.freq_mhz(), self.div),
CpuClockSource::RcFast => esp32c6_rtc_update_to_8m(),
CpuClockSource::Pll => {
if old_source != CpuClockSource::Pll {
rtc_clk_bbpll_enable();
esp32c6_rtc_bbpll_configure_raw(
RtcClock::xtal_freq_mhz(),
self.source_freq_mhz,
);
}
esp32c6_rtc_freq_to_pll_mhz_raw(self.freq_mhz());
}
}
if old_source == CpuClockSource::Pll && self.source != CpuClockSource::Pll
{
rtc_clk_bbpll_disable();
}
}
}
fn rtc_clk_bbpll_enable() {
unsafe {
pmu().imm_hp_ck_power().modify(|_, w| {
w.tie_high_xpd_bb_i2c()
.set_bit()
.tie_high_xpd_bbpll()
.set_bit()
.tie_high_xpd_bbpll_i2c()
.set_bit()
});
pmu()
.imm_hp_ck_power()
.modify(|_, w| w.tie_high_global_bbpll_icg().set_bit());
}
}
fn rtc_clk_bbpll_disable() {
unsafe {
pmu()
.imm_hp_ck_power()
.modify(|_, w| w.tie_low_global_bbpll_icg().set_bit());
pmu().imm_hp_ck_power().modify(|_, w| {
w.tie_low_xpd_bbpll()
.set_bit()
.tie_low_xpd_bbpll_i2c()
.set_bit()
});
}
}