#![allow(dead_code, reason = "Clock functions called from generated macro code")]
#![allow(
missing_docs,
reason = "Clock-tree types come from a generated macro that does not emit doc strings"
)]
#![allow(
clippy::enum_variant_names,
reason = "CPU frequency variant names follow the chip-spec MHz convention"
)]
use core::sync::atomic::{AtomicBool, Ordering};
use esp_rom_sys::rom::ets_update_cpu_frequency_rom;
use crate::{
peripherals::{HP_SYS_CLKRST, LP_AON_CLKRST, PMU},
soc::regi2c,
time::Rate,
};
define_clock_tree_types!();
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum CpuClock {
_400MHz = 400,
_200MHz = 200,
#[default]
_100MHz = 100,
}
impl CpuClock {
const PRESET_400: ClockConfig = ClockConfig {
cpu_root_clk: Some(CpuRootClkConfig::Cpll),
cpll_clk: Some(CpllClkConfig::_400),
mpll_clk: Some(MpllClkConfig::_500),
cpu_clk: Some(CpuClkConfig::new(0)), mem_clk: Some(MemClkConfig::new(1)), sys_clk: Some(SysClkConfig::new(0)), apb_clk: Some(ApbClkConfig::new(1)), iomux_function_clock: Some(IomuxFunctionClockConfig::new(
IomuxFunctionClockSource::PllF80m,
0,
)),
lp_fast_clk: Some(LpFastClkConfig::RcFast),
lp_slow_clk: Some(LpSlowClkConfig::RcSlow),
timg_calibration_clock: None,
};
const PRESET_200: ClockConfig = ClockConfig {
cpu_root_clk: Some(CpuRootClkConfig::Cpll),
cpll_clk: Some(CpllClkConfig::_400),
mpll_clk: Some(MpllClkConfig::_500),
cpu_clk: Some(CpuClkConfig::new(1)), mem_clk: Some(MemClkConfig::new(0)), sys_clk: Some(SysClkConfig::new(0)), apb_clk: Some(ApbClkConfig::new(1)), iomux_function_clock: Some(IomuxFunctionClockConfig::new(
IomuxFunctionClockSource::PllF80m,
0,
)),
lp_fast_clk: Some(LpFastClkConfig::RcFast),
lp_slow_clk: Some(LpSlowClkConfig::RcSlow),
timg_calibration_clock: None,
};
const PRESET_100: ClockConfig = ClockConfig {
cpu_root_clk: Some(CpuRootClkConfig::Cpll),
cpll_clk: Some(CpllClkConfig::_400),
mpll_clk: Some(MpllClkConfig::_500),
cpu_clk: Some(CpuClkConfig::new(3)), mem_clk: Some(MemClkConfig::new(0)), sys_clk: Some(SysClkConfig::new(0)), apb_clk: Some(ApbClkConfig::new(0)), iomux_function_clock: Some(IomuxFunctionClockConfig::new(
IomuxFunctionClockSource::PllF80m,
0,
)),
lp_fast_clk: Some(LpFastClkConfig::RcFast),
lp_slow_clk: Some(LpSlowClkConfig::RcSlow),
timg_calibration_clock: None,
};
}
impl From<CpuClock> for ClockConfig {
fn from(value: CpuClock) -> ClockConfig {
match value {
CpuClock::_400MHz => CpuClock::PRESET_400,
CpuClock::_200MHz => CpuClock::PRESET_200,
CpuClock::_100MHz => CpuClock::PRESET_100,
}
}
}
impl Default for ClockConfig {
fn default() -> Self {
Self::from(CpuClock::default())
}
}
impl ClockConfig {
pub(crate) fn try_get_preset(self) -> Option<CpuClock> {
match self {
v if v == CpuClock::PRESET_400 => Some(CpuClock::_400MHz),
v if v == CpuClock::PRESET_200 => Some(CpuClock::_200MHz),
v if v == CpuClock::PRESET_100 => Some(CpuClock::_100MHz),
_ => None,
}
}
pub(crate) fn configure(self, clocks: &mut ClockTree) {
DIVIDER_UPDATE_DEFERRED.store(true, Ordering::Relaxed);
self.apply(clocks);
DIVIDER_UPDATE_DEFERRED.store(false, Ordering::Relaxed);
update_divider();
ets_update_cpu_frequency_rom(Rate::from_hz(cpu_clk_frequency()).as_mhz());
}
}
fn enable_cpll_clk_impl(_clocks: &mut ClockTree, _en: bool) {
}
fn configure_cpll_clk_impl(
_clocks: &mut ClockTree,
_old_config: Option<CpllClkConfig>,
new_config: CpllClkConfig,
) {
HP_SYS_CLKRST::regs()
.ana_pll_ctrl0()
.modify(|_, w| w.cpu_pll_cal_stop().clear_bit());
let div7_0: u8 = match new_config {
CpllClkConfig::_360 => 9,
CpllClkConfig::_400 => 10,
};
let lref: u8 = 0x50; let dcur: u8 = 0x73;
regi2c::I2C_CPLL_OC_REF_DIV.write_reg(lref);
regi2c::I2C_CPLL_OC_DIV_7_0.write_reg(div7_0);
regi2c::I2C_CPLL_OC_DCUR.write_reg(dcur);
while !HP_SYS_CLKRST::regs()
.ana_pll_ctrl0()
.read()
.cpu_pll_cal_end()
.bit_is_set()
{
core::hint::spin_loop();
}
crate::rom::ets_delay_us(10);
HP_SYS_CLKRST::regs()
.ana_pll_ctrl0()
.modify(|_, w| w.cpu_pll_cal_stop().set_bit());
}
fn enable_spll_clk_impl(_clocks: &mut ClockTree, _en: bool) {
}
fn enable_mpll_clk_impl(clocks: &mut ClockTree, en: bool) {
PMU::regs().rf_pwc().modify(|_, w| w.mspi_phy_xpd().bit(en));
LP_AON_CLKRST::regs()
.lp_aonclkrst_hp_clk_ctrl()
.modify(|_, w| w.lp_aonclkrst_hp_mpll_500m_clk_en().bit(en));
if !en {
return;
}
HP_SYS_CLKRST::regs()
.ana_pll_ctrl0()
.modify(|_, w| w.mspi_cal_stop().clear_bit());
regi2c::I2C_MPLL_DHREF_DHREF.write_field(3);
let rstb = regi2c::I2C_MPLL_IR_CAL_RSTB.read();
regi2c::I2C_MPLL_IR_CAL_RSTB.write_reg(rstb & 0xDF);
regi2c::I2C_MPLL_IR_CAL_RSTB.write_reg(rstb | (1 << 5));
let ref_div: u8 = 1;
let div: u8 = match unwrap!(clocks.mpll_clk) {
MpllClkConfig::_320 => 15,
MpllClkConfig::_400 => 19,
MpllClkConfig::_500 => 24,
};
let div_val: u8 = (div << 3) | ref_div;
regi2c::I2C_MPLL_DIV_REG_ADDR.write_reg(div_val);
while HP_SYS_CLKRST::regs()
.ana_pll_ctrl0()
.read()
.mspi_cal_end()
.bit_is_clear()
{
core::hint::spin_loop();
}
HP_SYS_CLKRST::regs()
.ana_pll_ctrl0()
.modify(|_, w| w.mspi_cal_stop().set_bit());
crate::rom::ets_delay_us(10);
}
fn configure_mpll_clk_impl(
_clocks: &mut ClockTree,
_old_config: Option<MpllClkConfig>,
_new_config: MpllClkConfig,
) {
}
fn configure_cpu_root_clk_impl(
_clocks: &mut ClockTree,
_old_selector: Option<CpuRootClkConfig>,
new_selector: CpuRootClkConfig,
) {
let sel = match new_selector {
CpuRootClkConfig::Xtal => 0,
CpuRootClkConfig::Cpll => 1,
CpuRootClkConfig::RcFast => 2,
};
LP_AON_CLKRST::regs()
.lp_aonclkrst_hp_clk_ctrl()
.modify(|_, w| unsafe { w.lp_aonclkrst_hp_root_clk_src_sel().bits(sel) });
}
fn enable_cpu_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
fn configure_cpu_clk_impl(
_clocks: &mut ClockTree,
_old_config: Option<CpuClkConfig>,
new_config: CpuClkConfig,
) {
HP_SYS_CLKRST::regs()
.root_clk_ctrl0()
.modify(|_, w| unsafe {
w.cpu_clk_div_num().bits(new_config.divisor as u8);
w.cpu_clk_div_numerator().bits(0);
w.cpu_clk_div_denominator().bits(0)
});
update_divider();
if !DIVIDER_UPDATE_DEFERRED.load(Ordering::Relaxed) {
ets_update_cpu_frequency_rom(Rate::from_hz(cpu_clk_frequency()).as_mhz());
}
}
static DIVIDER_UPDATE_DEFERRED: AtomicBool = AtomicBool::new(false);
fn update_divider() {
if DIVIDER_UPDATE_DEFERRED.load(Ordering::Relaxed) {
return;
}
HP_SYS_CLKRST::regs()
.root_clk_ctrl0()
.modify(|_, w| w.soc_clk_div_update().set_bit());
while HP_SYS_CLKRST::regs()
.root_clk_ctrl0()
.read()
.soc_clk_div_update()
.bit_is_set()
{
core::hint::spin_loop();
}
}
fn enable_mem_clk_impl(_clocks: &mut ClockTree, _en: bool) {
}
fn configure_mem_clk_impl(
_clocks: &mut ClockTree,
_old_config: Option<MemClkConfig>,
new_config: MemClkConfig,
) {
HP_SYS_CLKRST::regs()
.root_clk_ctrl1()
.modify(|_, w| unsafe {
w.mem_clk_div_num().bits(new_config.divisor as u8);
w.mem_clk_div_numerator().bits(0);
w.mem_clk_div_denominator().bits(0)
});
update_divider();
}
fn enable_sys_clk_impl(_clocks: &mut ClockTree, _en: bool) {
}
fn configure_sys_clk_impl(
_clocks: &mut ClockTree,
_old_config: Option<SysClkConfig>,
new_config: SysClkConfig,
) {
HP_SYS_CLKRST::regs()
.root_clk_ctrl1()
.modify(|_, w| unsafe { w.sys_clk_div_num().bits(new_config.divisor as u8) });
HP_SYS_CLKRST::regs()
.root_clk_ctrl2()
.modify(|_, w| unsafe {
w.sys_clk_div_numerator().bits(0);
w.sys_clk_div_denominator().bits(0)
});
update_divider();
}
fn enable_apb_clk_impl(_clocks: &mut ClockTree, _en: bool) {
}
fn configure_apb_clk_impl(
_clocks: &mut ClockTree,
_old_config: Option<ApbClkConfig>,
new_config: ApbClkConfig,
) {
HP_SYS_CLKRST::regs()
.root_clk_ctrl2()
.modify(|_, w| unsafe {
w.apb_clk_div_num().bits(new_config.divisor as u8);
w.apb_clk_div_numerator().bits(0)
});
HP_SYS_CLKRST::regs()
.root_clk_ctrl3()
.modify(|_, w| unsafe { w.apb_clk_div_denominator().bits(0) });
update_divider();
}
fn configure_iomux_function_clock_impl(
_clocks: &mut ClockTree,
_old_config: Option<IomuxFunctionClockConfig>,
new_config: IomuxFunctionClockConfig,
) {
HP_SYS_CLKRST::regs()
.peri_clk_ctrl26()
.modify(|_, w| unsafe {
w.iomux_clk_src_sel().bit(matches!(
new_config.source,
IomuxFunctionClockSource::PllF80m
));
w.iomux_clk_div_num().bits(new_config.div_num as u8)
});
}
fn configure_lp_fast_clk_impl(
_clocks: &mut ClockTree,
_old_selector: Option<LpFastClkConfig>,
new_selector: LpFastClkConfig,
) {
LP_AON_CLKRST::regs()
.lp_aonclkrst_lp_clk_conf()
.modify(|_, w| unsafe {
w.lp_aonclkrst_fast_clk_sel().bits(match new_selector {
LpFastClkConfig::RcFast => 0,
LpFastClkConfig::XtalD2 => 1,
})
});
}
fn configure_lp_slow_clk_impl(
_clocks: &mut ClockTree,
_old_selector: Option<LpSlowClkConfig>,
new_selector: LpSlowClkConfig,
) {
LP_AON_CLKRST::regs()
.lp_aonclkrst_lp_clk_conf()
.modify(|_, w| unsafe {
w.lp_aonclkrst_slow_clk_sel().bits(match new_selector {
LpSlowClkConfig::RcSlow => 0,
#[cfg(use_xtal32k)]
LpSlowClkConfig::Xtal32k => 1,
LpSlowClkConfig::OscSlow => 3,
})
});
}
impl SdmInstance {
fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
crate::peripherals::GPIO_SD::regs()
.sigmadelta_misc()
.modify(|_, w| w.function_clk_en().bit(en));
}
}
impl TimgInstance {
fn enable_function_clock_impl(self, _clocks: &mut ClockTree, _en: bool) {
}
fn configure_function_clock_impl(
self,
_clocks: &mut ClockTree,
_old_config: Option<TimgFunctionClockConfig>,
_new_config: TimgFunctionClockConfig,
) {
}
fn enable_wdt_clock_impl(self, _clocks: &mut ClockTree, _en: bool) {}
fn configure_wdt_clock_impl(
self,
_clocks: &mut ClockTree,
_old_config: Option<TimgWdtClockConfig>,
_new_config: TimgWdtClockConfig,
) {
}
}
impl RmtInstance {
fn enable_sclk_impl(self, _clocks: &mut ClockTree, en: bool) {
HP_SYS_CLKRST::regs()
.peri_clk_ctrl22()
.modify(|_, w| w.rmt_clk_en().bit(en));
}
fn configure_sclk_impl(
self,
_clocks: &mut ClockTree,
_old_config: Option<RmtSclkConfig>,
new_config: RmtSclkConfig,
) {
HP_SYS_CLKRST::regs()
.peri_clk_ctrl22()
.modify(|_, w| unsafe {
w.rmt_clk_src_sel().bits(match new_config {
RmtSclkConfig::XtalClk => 0,
RmtSclkConfig::RcFastClk => 1,
RmtSclkConfig::PllF80m => 2,
})
});
}
}
fn enable_cpu_root_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_lp_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_lp_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_rc_fast_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
#[cfg(use_xtal32k)]
fn enable_xtal32k_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_osc_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_rc_slow_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_rc32k_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_pll_f20m_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_pll_f80m_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_pll_f120m_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_pll_f160m_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_pll_f240m_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_pll_f25m_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_pll_f50m_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_xtal_d2_clk_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_spll_d3_clock_impl(_clocks: &mut ClockTree, _en: bool) {}
fn enable_timg_calibration_clock_impl(_clocks: &mut ClockTree, _en: bool) {
}
impl MipiDsiInstance {
fn enable_dpi_clk_impl(self, _clocks: &mut ClockTree, en: bool) {
HP_SYS_CLKRST::regs()
.peri_clk_ctrl03()
.modify(|_, w| w.mipi_dsi_dpiclk_en().bit(en));
}
fn configure_dpi_clk_impl(
self,
_clocks: &mut ClockTree,
_old_config: Option<MipiDsiDpiClkConfig>,
new_config: MipiDsiDpiClkConfig,
) {
let src_sel = match new_config.sclk() {
MipiDsiDpiClkSclk::Xtal => 0,
MipiDsiDpiClkSclk::PllF240m => 1,
MipiDsiDpiClkSclk::PllF160m => 2,
};
HP_SYS_CLKRST::regs()
.peri_clk_ctrl03()
.modify(|_, w| unsafe {
w.mipi_dsi_dpiclk_src_sel().bits(src_sel);
w.mipi_dsi_dpiclk_div_num().bits(new_config.div_num() as u8)
});
}
fn enable_phy_pll_refclk_impl(self, _clocks: &mut ClockTree, en: bool) {
HP_SYS_CLKRST::regs()
.peri_clk_ctrl03()
.modify(|_, w| w.mipi_dsi_dphy_pll_refclk_en().bit(en));
}
fn configure_phy_pll_refclk_impl(
self,
_clocks: &mut ClockTree,
_old_config: Option<MipiDsiPhyPllRefclkConfig>,
new_config: MipiDsiPhyPllRefclkConfig,
) {
let src_sel = match new_config.sclk() {
MipiDsiPhyPllRefclkSclk::Xtal => 0u8,
MipiDsiPhyPllRefclkSclk::Cpll => 2,
MipiDsiPhyPllRefclkSclk::Spll => 3,
MipiDsiPhyPllRefclkSclk::Mpll => 4,
};
HP_SYS_CLKRST::regs()
.peri_clk_ctrl03()
.modify(|_, w| unsafe {
w.mipi_dsi_dphy_pll_refclk_src_sel().bits(src_sel);
w.mipi_dsi_dphy_pll_refclk_div_num()
.bits(new_config.div_num() as u8)
});
}
fn enable_phy_cfg_clk_impl(self, _clocks: &mut ClockTree, en: bool) {
HP_SYS_CLKRST::regs()
.peri_clk_ctrl03()
.modify(|_, w| w.mipi_dsi_dphy_cfg_clk_en().bit(en));
}
fn configure_phy_cfg_clk_impl(
self,
_clocks: &mut ClockTree,
_old_config: Option<MipiDsiPhyCfgClkConfig>,
new_config: MipiDsiPhyCfgClkConfig,
) {
let src_sel = match new_config {
MipiDsiPhyCfgClkConfig::PllF20m => 0,
MipiDsiPhyCfgClkConfig::RcFast => 1,
MipiDsiPhyCfgClkConfig::PllF25m => 2,
};
HP_SYS_CLKRST::regs()
.peri_clk_ctrl02()
.modify(|_, w| unsafe { w.mipi_dsi_dphy_clk_src_sel().bits(src_sel) });
}
}
fn configure_timg_calibration_clock_impl(
_clocks: &mut ClockTree,
_old_config: Option<TimgCalibrationClockConfig>,
new_config: TimgCalibrationClockConfig,
) {
HP_SYS_CLKRST::regs()
.peri_clk_ctrl21()
.modify(|_, w| unsafe {
w.timergrp0_tgrt_clk_src_sel().bits(match new_config {
TimgCalibrationClockConfig::MpllClk => 0,
TimgCalibrationClockConfig::SpllClk => 1,
TimgCalibrationClockConfig::CpllClk => 2,
TimgCalibrationClockConfig::RcFastDivClk => 7,
TimgCalibrationClockConfig::RcSlowClk => 8,
#[cfg(use_xtal32k)]
TimgCalibrationClockConfig::Xtal32kClk => 10,
})
});
}
impl PsramInstance {
fn enable_function_clock_impl(self, _clocks: &mut ClockTree, en: bool) {
HP_SYS_CLKRST::regs().peri_clk_ctrl00().modify(|_, w| {
w.psram_pll_clk_en().bit(en);
w.psram_core_clk_en().bit(en)
});
}
fn configure_function_clock_impl(
self,
_clocks: &mut ClockTree,
_old_config: Option<PsramFunctionClockConfig>,
new_config: PsramFunctionClockConfig,
) {
HP_SYS_CLKRST::regs()
.peri_clk_ctrl00()
.modify(|_, w| unsafe {
w.psram_clk_src_sel().bits(match new_config {
PsramFunctionClockConfig::Xtal => 0,
PsramFunctionClockConfig::Mpll => 1,
PsramFunctionClockConfig::Spll => 2,
PsramFunctionClockConfig::Cpll => 3,
})
});
}
}