use core::{fmt::Debug, marker::PhantomData, num::NonZeroU32, sync::atomic::AtomicU32};
use regs::srss::{clk_dsi_select::DsiMux, clk_path_select::PathMux};
use crate::regs;
#[cfg(any(mxs40srss, mxs40ssrss))]
pub mod fll;
#[cfg(mxs40ssrss)]
pub mod lpdpll;
static HF_CLOCK_FREQUENCIES: [AtomicU32; 16] = [const { AtomicU32::new(0) }; 16];
pub const CLOCK_HF_CPU: usize = 0;
pub fn current_cpu_frequency() -> u32 {
ClockHf::<CLOCK_HF_CPU>::frequency()
.map(NonZeroU32::get)
.unwrap_or(8_000_000)
}
#[derive(Debug)]
#[non_exhaustive]
pub struct SysClock;
impl SysClock {
pub const unsafe fn steal() -> Self {
SysClock
}
}
impl SysClock {
pub fn clock_path<const N: usize>(&mut self) -> &mut ClockPath<N>
where
ClockPath<N>: ClockPathPresent,
{
unsafe { ClockPath::steal() }
}
pub fn clock_hf<const N: usize>(&mut self) -> &mut ClockHf<N> {
const {
match N {
#[cfg(clock_hf_0)]
0 => {}
#[cfg(clock_hf_1)]
1 => {}
#[cfg(clock_hf_2)]
2 => {}
#[cfg(clock_hf_3)]
3 => {}
#[cfg(clock_hf_4)]
4 => {}
#[cfg(clock_hf_5)]
5 => {}
#[cfg(clock_hf_6)]
6 => {}
#[cfg(clock_hf_7)]
7 => {}
#[cfg(clock_hf_8)]
8 => {}
#[cfg(clock_hf_9)]
9 => {}
#[cfg(clock_hf_10)]
10 => {}
#[cfg(clock_hf_11)]
11 => {}
#[cfg(clock_hf_12)]
12 => {}
#[cfg(clock_hf_13)]
13 => {}
#[cfg(clock_hf_14)]
14 => {}
#[cfg(clock_hf_15)]
15 => {}
_ => panic!("Invalid high-frequency clock root index"),
}
}
unsafe { ClockHf::steal() }
}
pub fn clock_lf(&mut self) -> ClockLf<'_> {
unsafe { ClockLf::steal() }
}
pub fn ilo(&mut self) -> Ilo<'_> {
unsafe { Ilo::steal() }
}
pub fn wco(&mut self) -> Wco<'_> {
unsafe { Wco::steal() }
}
#[inline(always)]
pub fn configure(&mut self, config: &ClockConfig, old: Option<&ClockConfig>) {
macro_rules! for_each {
($thing:literal, $body:ident) => {
for_each!($thing, $body @ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
};
($thing:literal, $body:ident @ $($n:literal),*) => {$(
paste::paste! {
#[cfg([<$thing _ $n>])]
$body!([<$thing _ $n>], $n);
}
)*};
}
#[cfg(mxs40srss)]
self.set_wait_states(u32::MAX, false);
if config.ilo.is_some() && config.ilo.as_ref() != old.and_then(|c| c.ilo.as_ref()) {
self.ilo().configure(config.ilo.as_ref());
}
if config.wco.is_some() && config.wco.as_ref() != old.and_then(|c| c.wco.as_ref()) {
self.wco().configure(config.wco.as_ref());
}
macro_rules! bypass_multiplier {
($path:ident, $n:literal) => {
if config.$path.multiplier_config.is_none()
&& old.is_none_or(|c| c.$path.multiplier_config.is_some())
{
self.clock_path::<$n>().multiplier().configure(None);
}
};
}
for_each!("clock_path", bypass_multiplier);
macro_rules! set_path {
($path:ident, $n:literal) => {
if Some(config.$path.source) != old.map(|c| c.$path.source) {
self.clock_path::<$n>().set_source(config.$path.source);
}
};
}
for_each!("clock_path", set_path);
macro_rules! set_hf_root {
($hf:ident, 0) => {
if Some(config.$hf) != old.map(|c| c.$hf) {
self.clock_hf::<0>().configure(Some(&config.$hf));
}
};
($hf:ident, $n:literal) => {
if Some(config.$hf) != old.map(|c| c.$hf) {
self.clock_hf::<$n>().configure(config.$hf.as_ref());
}
};
}
for_each!("clock_hf", set_hf_root);
#[cfg(mxs40srss)]
self.set_wait_states(current_cpu_frequency(), config.is_ulp);
macro_rules! configure_multiplier {
($path:ident, $n:literal) => {
if config.$path.multiplier_config.as_ref().is_some()
&& config.$path.multiplier_config.as_ref()
!= old.and_then(|c| c.$path.multiplier_config.as_ref())
{
self.clock_path::<$n>()
.multiplier()
.configure(config.$path.multiplier_config.as_ref());
}
};
}
for_each!("clock_path", configure_multiplier);
if config.ilo.is_none() && old.and_then(|c| c.ilo.as_ref()).is_some() {
self.ilo().configure(None);
}
if config.wco.is_none() && old.and_then(|c| c.wco.as_ref()).is_some() {
self.wco().configure(None);
}
}
#[cfg(mxs40srss)]
pub fn set_wait_states(&mut self, cpu_freq: u32, is_ulp: bool) {
let ram_wait_states = match cpu_freq {
0..=25_000_000 => 0,
25_000_001..=100_000_000 if !is_ulp => 0,
25_000_001..=100_000_000 => 1,
100_000_001.. => 1,
};
let flash_wait_states = if is_ulp {
match cpu_freq {
0..=16_000_000 => 0,
16_000_001..=33_000_000 => 1,
33_000_001.. => 2,
}
} else {
match cpu_freq {
0..=29_000_000 => 0,
29_000_001..=58_000_000 => 1,
58_000_001..=87_000_000 => 2,
87_000_001..=120_000_000 => 3,
120_000_001.. => 4,
}
};
unsafe {
regs::CPUSS
.rom_ctl()
.modify(|r| r.fast_ws().set(0).slow_ws().set(ram_wait_states));
regs::CPUSS
.ram0_ctl0()
.modify(|r| r.fast_ws().set(0).slow_ws().set(ram_wait_states));
#[cfg(ramc1)]
regs::CPUSS
.ram1_ctl0()
.modify(|r| r.fast_ws().set(0).slow_ws().set(ram_wait_states));
#[cfg(ramc2)]
regs::CPUSS
.ram2_ctl0()
.modify(|r| r.fast_ws().set(0).slow_ws().set(ram_wait_states));
regs::FLASHC
.flash_ctl()
.modify(|r| r.main_ws().set(flash_wait_states));
}
}
}
#[derive(Debug, Clone)]
pub struct ClockConfig {
pub ilo: Option<IloConfig>,
pub wco: Option<WcoConfig>,
#[cfg(clock_path_0)]
pub clock_path_0: ClockPathConfig<0>,
#[cfg(clock_path_1)]
pub clock_path_1: ClockPathConfig<1>,
#[cfg(clock_path_2)]
pub clock_path_2: ClockPathConfig<2>,
#[cfg(clock_path_3)]
pub clock_path_3: ClockPathConfig<3>,
#[cfg(clock_path_4)]
pub clock_path_4: ClockPathConfig<4>,
#[cfg(clock_path_5)]
pub clock_path_5: ClockPathConfig<5>,
#[cfg(clock_path_6)]
pub clock_path_6: ClockPathConfig<6>,
#[cfg(clock_path_7)]
pub clock_path_7: ClockPathConfig<7>,
#[cfg(clock_path_8)]
pub clock_path_8: ClockPathConfig<8>,
#[cfg(clock_path_9)]
pub clock_path_9: ClockPathConfig<9>,
#[cfg(clock_path_10)]
pub clock_path_10: ClockPathConfig<10>,
#[cfg(clock_path_11)]
pub clock_path_11: ClockPathConfig<11>,
#[cfg(clock_path_12)]
pub clock_path_12: ClockPathConfig<12>,
#[cfg(clock_path_13)]
pub clock_path_13: ClockPathConfig<13>,
#[cfg(clock_path_14)]
pub clock_path_14: ClockPathConfig<14>,
#[cfg(clock_path_15)]
pub clock_path_15: ClockPathConfig<15>,
#[cfg(clock_hf_0)]
pub clock_hf_0: ClockHfConfig,
#[cfg(clock_hf_1)]
pub clock_hf_1: Option<ClockHfConfig>,
#[cfg(clock_hf_2)]
pub clock_hf_2: Option<ClockHfConfig>,
#[cfg(clock_hf_3)]
pub clock_hf_3: Option<ClockHfConfig>,
#[cfg(clock_hf_4)]
pub clock_hf_4: Option<ClockHfConfig>,
#[cfg(clock_hf_5)]
pub clock_hf_5: Option<ClockHfConfig>,
#[cfg(clock_hf_6)]
pub clock_hf_6: Option<ClockHfConfig>,
#[cfg(clock_hf_7)]
pub clock_hf_7: Option<ClockHfConfig>,
#[cfg(clock_hf_8)]
pub clock_hf_8: Option<ClockHfConfig>,
#[cfg(clock_hf_9)]
pub clock_hf_9: Option<ClockHfConfig>,
#[cfg(clock_hf_10)]
pub clock_hf_10: Option<ClockHfConfig>,
#[cfg(clock_hf_11)]
pub clock_hf_11: Option<ClockHfConfig>,
#[cfg(clock_hf_12)]
pub clock_hf_12: Option<ClockHfConfig>,
#[cfg(clock_hf_13)]
pub clock_hf_13: Option<ClockHfConfig>,
#[cfg(clock_hf_14)]
pub clock_hf_14: Option<ClockHfConfig>,
#[cfg(clock_hf_15)]
pub clock_hf_15: Option<ClockHfConfig>,
pub clock_lf: ClockLfIn,
#[cfg(mxs40srss)]
pub is_ulp: bool,
}
impl ClockConfig {
pub const DEFAULT: Self = cfg_select! {
die = "psc3" => { Self {
ilo: Some(IloConfig {
backup_domain: false,
}),
wco: None,
clock_path_0: ClockPathConfig {
source: ClockSource::Imo,
multiplier_config: Some(fll::FllConfig::from_frequency(8_000_000, 100_000_000)),
},
clock_path_1: ClockPathConfig {
source: ClockSource::Iho,
multiplier_config: Some(lpdpll::LpDpllConfig::from_frequency(
48_000_000,
180_000_000,
lpdpll::LpDllMode::Integer,
)),
},
clock_path_2: ClockPathConfig {
source: ClockSource::Iho,
multiplier_config: Some(lpdpll::LpDpllConfig::from_frequency(
48_000_000,
240_000_000,
lpdpll::LpDllMode::Integer,
)),
},
clock_path_3: ClockPathConfig {
source: ClockSource::Imo,
multiplier_config: None,
},
clock_path_4: ClockPathConfig {
source: ClockSource::Imo,
multiplier_config: None,
},
clock_path_5: ClockPathConfig {
source: ClockSource::Imo,
multiplier_config: None,
},
clock_hf_0: ClockHfConfig {
source_path: ClockHfIn::ClockPath0,
divider: 1,
frequency: 100_000_000,
},
clock_hf_1: Some(ClockHfConfig {
source_path: ClockHfIn::ClockPath1,
divider: 1,
frequency: 180_000_000,
}),
clock_hf_2: Some(ClockHfConfig {
source_path: ClockHfIn::ClockPath0,
divider: 1,
frequency: 100_000_000,
}),
clock_hf_3: Some(ClockHfConfig {
source_path: ClockHfIn::ClockPath2,
divider: 1,
frequency: 240_000_000,
}),
clock_hf_4: Some(ClockHfConfig {
source_path: ClockHfIn::ClockPath0,
divider: 1,
frequency: 100_000_000,
}),
clock_hf_5: None,
clock_hf_6: None,
clock_lf: ClockLfIn::Ilo,
}}
any(die = "psoc6_01", die = "psoc6_02", die = "psoc6_03", die = "psoc6_04") => { Self {
ilo: Some(IloConfig {
backup_domain: false,
}),
wco: None,
clock_path_0: ClockPathConfig {
source: ClockSource::Imo,
multiplier_config: Some(fll::FllConfig::from_frequency(8_000_000, 100_000_000)),
},
clock_path_1: ClockPathConfig {
source: ClockSource::Imo,
multiplier_config: None,
},
clock_path_2: ClockPathConfig {
source: ClockSource::Imo,
multiplier_config: None,
},
clock_path_3: ClockPathConfig {
source: ClockSource::Imo,
multiplier_config: None,
},
clock_path_4: ClockPathConfig {
source: ClockSource::Imo,
multiplier_config: None,
},
clock_path_5: ClockPathConfig {
source: ClockSource::Imo,
multiplier_config: None,
},
clock_hf_0: ClockHfConfig {
source_path: ClockHfIn::ClockPath0,
divider: 1,
frequency: 100_000_000,
},
clock_hf_1: None,
clock_hf_2: None,
clock_hf_3: None,
clock_hf_4: None,
clock_hf_5: None,
clock_lf: ClockLfIn::Ilo,
is_ulp: false,
}}
};
}
impl Default for ClockConfig {
fn default() -> Self {
Self::DEFAULT
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ClockSource {
Imo,
ExtClk,
Eco,
#[cfg(mxs40ssrss)]
Iho,
Ilo,
Wco,
}
impl ClockSource {
fn value(&self) -> (PathMux, Option<DsiMux>) {
match self {
ClockSource::Imo => (PathMux::IMO, None),
ClockSource::ExtClk => (PathMux::EXTCLK, None),
ClockSource::Eco => (PathMux::ECO, None),
#[cfg(mxs40ssrss)]
ClockSource::Iho => (PathMux::IHO, None),
ClockSource::Ilo => (PathMux::DSI_MUX, Some(DsiMux::ILO)),
ClockSource::Wco => (PathMux::DSI_MUX, Some(DsiMux::WCO)),
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct ClockPath<const N: usize>;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ClockPathConfig<const N: usize>
where
ClockPath<N>: ClockPathPresent,
{
pub source: ClockSource,
pub multiplier_config:
Option<<<ClockPath<N> as ClockPathPresent>::Multiplier as Multiplier>::Config>,
}
impl<const N: usize> ClockPath<N>
where
Self: ClockPathPresent,
{
pub const unsafe fn steal() -> &'static mut ClockPath<N> {
unsafe { &mut *core::ptr::dangling_mut() }
}
pub fn multiplier(&mut self) -> &mut <Self as ClockPathPresent>::Multiplier {
unsafe { <Self as ClockPathPresent>::Multiplier::steal() }
}
pub fn set_source(&mut self, source: ClockSource) {
let (path_select, dsi_select) = source.value();
unsafe {
if let Some(dsi_select) = dsi_select {
regs::SRSS.clk_dsi_select()[N].init(|r| r.dsi_mux().set(dsi_select));
}
regs::SRSS.clk_path_select()[N].init(|r| r.path_mux().set(path_select));
}
}
}
#[derive(Debug)]
pub struct ClockHf<const N: usize>;
#[allow(missing_docs)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u8)]
pub enum ClockHfIn {
#[cfg(clock_path_0)]
ClockPath0 = 0,
#[cfg(clock_path_1)]
ClockPath1,
#[cfg(clock_path_2)]
ClockPath2,
#[cfg(clock_path_3)]
ClockPath3,
#[cfg(clock_path_4)]
ClockPath4,
#[cfg(clock_path_5)]
ClockPath5,
#[cfg(clock_path_6)]
ClockPath6,
#[cfg(clock_path_7)]
ClockPath7,
#[cfg(clock_path_8)]
ClockPath8,
#[cfg(clock_path_9)]
ClockPath9,
#[cfg(clock_path_10)]
ClockPath10,
#[cfg(clock_path_11)]
ClockPath11,
#[cfg(clock_path_12)]
ClockPath12,
#[cfg(clock_path_13)]
ClockPath13,
#[cfg(clock_path_14)]
ClockPath14,
#[cfg(clock_path_15)]
ClockPath15,
#[cfg(mxs40ssrss)]
Imo,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ClockHfConfig {
pub source_path: ClockHfIn,
pub divider: u8,
pub frequency: u32,
}
impl<const N: usize> ClockHf<N> {
pub unsafe fn steal() -> &'static mut Self {
unsafe { &mut *core::ptr::dangling_mut() }
}
#[cfg_attr(
mxs40srss,
doc = "Configures this high-frequency clock root.
- `source_path` is the clock path to source from, or `None` to disable the clock.
- `divider` is the divider to apply to the selected clock path, and must be one of 1, 2, 4, or 8."
)]
#[cfg_attr(
mxs40ssrss,
doc = "Configures this high-frequency clock root.\n\n\
- `source_path` is the clock path to source from, or `None` to disable the clock.\n\
- `divider` is the divider to apply to the selected clock path, and must be in the range 1-16.
"
)]
pub fn configure(&mut self, config: Option<&ClockHfConfig>) {
if N == 0 {
debug_assert!(config.is_some(), "Can't disable HF0");
}
let value = config
.map(|config| {
let mut value = regs::srss::ClkRootSelect::default();
value = value.enable().set(true);
value = value.root_mux().set(
#[cfg(mxs40ssrss)]
if config.source_path == ClockHfIn::Imo {
0
} else {
config.source_path as u8
}
.into(),
#[cfg(mxs40srss)]
(config.source_path as u8).into(),
);
cfg_select! {
mxs40srss => {
value = value.root_div().set(Self::validate_divider(config.divider));
}
mxs40ssrss => {
value = value.root_div_int().set(Self::validate_divider(config.divider));
}
}
value
})
.unwrap_or_default();
unsafe {
#[cfg(mxs40ssrss)]
if config.is_some_and(|c| c.source_path == ClockHfIn::Imo) {
regs::SRSS.clk_direct_select()[N].init(|r| {
r.direct_mux()
.set(regs::srss::clk_direct_select::DirectMux::IMO)
});
}
regs::SRSS.clk_root_select()[N].write(value);
#[cfg(mxs40ssrss)]
if config.is_none_or(|c| c.source_path != ClockHfIn::Imo) {
regs::SRSS.clk_direct_select()[N].init(|r| {
r.direct_mux()
.set(regs::srss::clk_direct_select::DirectMux::ROOT_MUX)
});
}
}
HF_CLOCK_FREQUENCIES[N].store(
config.map_or(0, |c| c.frequency),
core::sync::atomic::Ordering::Release,
);
}
pub fn frequency() -> Option<NonZeroU32> {
HF_CLOCK_FREQUENCIES[N]
.load(core::sync::atomic::Ordering::Acquire)
.try_into()
.ok()
}
#[cfg(mxs40srss)]
fn validate_divider(divider: u8) -> regs::srss::clk_root_select::RootDiv {
match divider {
1 => regs::srss::clk_root_select::RootDiv::NO_DIV,
2 => regs::srss::clk_root_select::RootDiv::DIV_BY_2,
4 => regs::srss::clk_root_select::RootDiv::DIV_BY_4,
8 => regs::srss::clk_root_select::RootDiv::DIV_BY_8,
_ => panic!("Invalid divider value"),
}
}
#[cfg(mxs40ssrss)]
fn validate_divider(divider: u8) -> regs::srss::clk_root_select::RootDivInt {
debug_assert!(matches!(divider, 1..=16));
(divider - 1).into()
}
}
pub trait ClockPathPresent {
type Multiplier: Multiplier;
}
pub trait Multiplier: 'static {
type Config: Clone + Debug + Eq;
unsafe fn steal() -> &'static mut Self;
fn configure(&mut self, config: Option<&Self::Config>);
}
impl Multiplier for () {
type Config = ();
#[doc(hidden)]
unsafe fn steal() -> &'static mut Self {
unsafe { &mut *core::ptr::dangling_mut() }
}
#[doc(hidden)]
fn configure(&mut self, _config: Option<&Self::Config>) {}
}
#[repr(u8)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Bypass {
Auto,
LockedOrNothing,
ReferenceInputOnly,
MultiplierOutputOnly,
}
pub trait ClockHfPresent<const N: usize> {}
macro_rules! impl_clock_path {
($($n:literal),*) => {$( paste::paste! {
#[cfg([<clock_path _ $n>])]
impl ClockPathPresent for ClockPath<[<$n>]> {
type Multiplier = cfg_select! {
clock_path_fll = $n => { fll::Fll }
clock_path_pll0 = $n => { pll::Pll<0> }
clock_path_pll1 = $n => { pll::Pll<1> }
clock_path_dpll_lp0 = $n => { lpdpll::LpDpll<0> }
clock_path_dpll_lp1 = $n => { lpdpll::LpDpll<1> }
clock_path_dpll_hp0 = $n => { hpdpll::HpDpll<0> }
_ => { () }
};
}
})*};
}
macro_rules! impl_clock_hf {
($($n:literal),*) => {$( paste::paste! {
#[cfg([<clock_hf _ $n>])]
impl ClockHfPresent<[<$n>]> for ClockHf<[<$n>]> {}
})*};
}
impl_clock_path!(
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"
);
impl_clock_hf!(
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"
);
#[derive(Debug)]
pub struct ClockLf<'a>(PhantomData<&'a mut ()>);
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ClockLfIn {
Ilo,
Wco,
#[cfg(mxs40ssrss)]
Eco {
integer_divider: u16,
fractional_divider: u8,
},
}
impl ClockLf<'_> {
pub const unsafe fn steal() -> ClockLf<'static> {
ClockLf(PhantomData)
}
pub fn set_source(&mut self, source: ClockLfIn) {
use regs::srss::clk_select::LfclkSel;
use regs::srss::wdt_ctl::WdtLock;
unsafe {
#[cfg(mxs40ssrss)]
if let ClockLfIn::Eco {
integer_divider,
fractional_divider,
} = source
{
debug_assert!(matches!(integer_divider, 1..=1024));
regs::SRSS.clk_eco_prescale().init(|r| {
r.eco_int_div()
.set(integer_divider - 1)
.eco_frac_div()
.set(fractional_divider)
});
regs::SRSS
.clk_eco_config()
.modify(|r| r.eco_div_enable().set(true));
while !regs::SRSS.clk_eco_prescale().read().eco_div_enabled().get() {}
} else {
regs::SRSS
.clk_eco_config()
.modify(|r| r.eco_div_enable().set(false));
}
let source = match source {
ClockLfIn::Ilo => LfclkSel::ILO,
ClockLfIn::Wco => LfclkSel::WCO,
#[cfg(mxs40ssrss)]
ClockLfIn::Eco { .. } => LfclkSel::ECO_PRESCALER,
};
critical_section::with(|_cs| {
let wdt_ctl = regs::SRSS.wdt_ctl().read();
regs::SRSS
.wdt_ctl()
.write(wdt_ctl.wdt_lock().set(WdtLock::CLR_0));
regs::SRSS
.wdt_ctl()
.write(wdt_ctl.wdt_lock().set(WdtLock::CLR_1));
regs::SRSS
.clk_select()
.modify(|r| r.lfclk_sel().set(source));
if wdt_ctl.wdt_lock().get() != WdtLock::new(0) {
regs::SRSS
.wdt_ctl()
.write(wdt_ctl.wdt_lock().set(WdtLock::SET_01));
}
});
}
}
pub fn source(&self) -> ClockLfIn {
use regs::srss::clk_select::LfclkSel;
unsafe {
match regs::SRSS.clk_select().read().lfclk_sel().get() {
LfclkSel::ILO => ClockLfIn::Ilo,
LfclkSel::WCO => ClockLfIn::Wco,
#[cfg(mxs40ssrss)]
LfclkSel::ECO_PRESCALER => {
let prescale = regs::SRSS.clk_eco_prescale().read();
ClockLfIn::Eco {
integer_divider: prescale.eco_int_div().get() + 1,
fractional_divider: prescale.eco_frac_div().get(),
}
}
_ => unreachable!(),
}
}
}
}
#[derive(Debug)]
pub struct Ilo<'a>(PhantomData<&'a mut ()>);
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct IloConfig {
pub backup_domain: bool,
}
impl Ilo<'_> {
pub const unsafe fn steal() -> Ilo<'static> {
Ilo(PhantomData)
}
pub fn configure(&mut self, config: Option<&IloConfig>) {
use regs::srss::wdt_ctl::WdtLock;
unsafe {
critical_section::with(|_cs| {
let wdt_ctl = regs::SRSS.wdt_ctl().read();
regs::SRSS
.wdt_ctl()
.write(wdt_ctl.wdt_lock().set(WdtLock::CLR_0));
regs::SRSS
.wdt_ctl()
.write(wdt_ctl.wdt_lock().set(WdtLock::CLR_1));
regs::SRSS.clk_ilo_config().init(|r| {
r.enable()
.set(config.is_some())
.ilo_backup()
.set(config.is_some_and(|c| c.backup_domain))
});
if wdt_ctl.wdt_lock().get() != WdtLock::new(0) {
regs::SRSS
.wdt_ctl()
.write(wdt_ctl.wdt_lock().set(WdtLock::SET_01));
}
});
}
}
}
#[derive(Debug)]
pub struct Wco<'a>(PhantomData<&'a mut ()>);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WcoConfig {
bypass: bool,
}
impl Wco<'_> {
pub const unsafe fn steal() -> Wco<'static> {
Wco(PhantomData)
}
pub fn configure(&mut self, config: Option<&WcoConfig>) {
unsafe {
regs::BACKUP.ctl().modify(|r| {
r.wco_en()
.set(config.is_some())
.wco_bypass()
.set(config.is_some_and(|c| c.bypass))
});
if config.is_some() {
#[cfg(mxs40ssrss)]
while !regs::BACKUP.wco_status().read().wco_ok().get() {}
#[cfg(mxs40srss)]
while !regs::BACKUP.status().read().wco_ok().get() {}
}
}
}
}