Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions embassy-mcxa/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ embedded-storage = "0.3.1"
# Custom executor support
embassy-executor = { version = "0.10.0", path = "../embassy-executor" }

# USB device driver trait layer
embassy-usb-driver = { version = "0.2.2", path = "../embassy-usb-driver" }

# `time` dependencies
embassy-time = { version = "0.5.1", path = "../embassy-time" }
embassy-time-driver = { version = "0.2.2", path = "../embassy-time-driver", features = ["tick-hz-1_000_000"] }
Expand All @@ -59,15 +62,22 @@ grounded = { version = "0.2.1", features = ["cas", "critical-section"] }
heapless = "0.9"
maitake-sync = { version = "0.3.0", default-features = false, features = ["critical-section", "no-cache-pad"] }
nb = "1.1.0"
nxp-pac = { git = "https://github.com/embassy-rs/nxp-pac.git", rev = "a46946e7f5ba3b5d8136f2962400300d54a99d6c", features = ["rt"] }
# TEMPORARY: pinned to the fork branch carrying the MCXA577 USBHS/USBPHY register
# blocks (upstream PR embassy-rs/nxp-pac#108) plus the MCXA577 eSPI register block
# (mcxa577-espi-pac, to be PR'd on top of #108). Switch both nxp-pac entries back
# to a released/main rev of `https://github.com/embassy-rs/nxp-pac.git` once those
# merge.
nxp-pac = { git = "https://github.com/bogdan-petru/nxp-pac.git", rev = "4835d42036e706815c223654c0f85e5eeb974cdb", features = ["rt"] }
paste = "1.0.15"

rand-core-06 = { package = "rand_core", version = "0.6" }
rand-core-09 = { package = "rand_core", version = "0.9" }
rand-core-10 = { package = "rand_core", version = "0.10" }

[build-dependencies]
nxp-pac = { git = "https://github.com/embassy-rs/nxp-pac.git", rev = "a46946e7f5ba3b5d8136f2962400300d54a99d6c", default-features = false, features = ["metadata"] }
# TEMPORARY: see the note on the `[dependencies]` nxp-pac entry above. Switch back
# to `https://github.com/embassy-rs/nxp-pac.git` once the fork branches merge.
nxp-pac = { git = "https://github.com/bogdan-petru/nxp-pac.git", rev = "4835d42036e706815c223654c0f85e5eeb974cdb", default-features = false, features = ["metadata"] }
proc-macro2 = "1.0.106"
quote = "1.0.45"
regex = "1.12.3"
Expand Down
184 changes: 184 additions & 0 deletions embassy-mcxa/src/clocks/periph_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use crate::pac::mrcc::{
AdcClkselMux, ClkdivHalt, ClkdivReset, ClkdivUnstab, CtimerClkselMux, FclkClkselMux, Lpi2cClkselMux,
LpspiClkselMux, LpuartClkselMux, OstimerClkselMux,
};
#[cfg(feature = "mcxa5xx")]
use crate::pac::mrcc::{EspiClkselMux, PhyClkselMux, UsbClkselMux};

#[must_use]
pub struct PreEnableParts {
Expand Down Expand Up @@ -207,6 +209,188 @@ impl SPConfHelper for Clk1MConfig {
}
}

//
// USBHS
//

/// Clock configuration for the MCXA5xx USBHS controller and PHY.
#[cfg(feature = "mcxa5xx")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct UsbhsConfig {
/// Power state required for the SOSC reference clock.
pub power: PoweredClock,
/// USB PHY reference clock divider.
pub phy_div: Div4,
}

#[cfg(feature = "mcxa5xx")]
impl Default for UsbhsConfig {
fn default() -> Self {
Self {
power: PoweredClock::NormalEnabledDeepSleepDisabled,
phy_div: Div4::no_div(),
}
}
}

#[cfg(all(feature = "mcxa5xx", feature = "defmt"))]
impl defmt::Format for UsbhsConfig {
fn format(&self, f: defmt::Formatter) {
defmt::write!(
f,
"UsbhsConfig {{ power: {:?}, phy_div: {=u32} }}",
self.power,
self.phy_div.into_divisor()
)
}
}

#[cfg(feature = "mcxa5xx")]
impl SPConfHelper for UsbhsConfig {
fn pre_enable_config(&self, clocks: &Clocks) -> Result<PreEnableParts, ClockError> {
#[cfg(feature = "sosc-as-gpio")]
{
let _ = clocks;
return Err(ClockError::BadConfig {
clock: "usbhs phy",
reason: "requires SOSC pins",
});
}

#[cfg(not(feature = "sosc-as-gpio"))]
{
let freq = clocks.ensure_clk_in_active(&self.power)?;
if freq != 24_000_000 {
return Err(ClockError::BadConfig {
clock: "usbhs phy",
reason: "requires a 24 MHz SOSC reference",
});
}

let mrcc0 = crate::pac::MRCC0;
mrcc0
.mrcc_usb1_clksel()
.write(|w| w.set_mux(UsbClkselMux::I2ClkUsbhs0PhyClkXtal));
mrcc0
.mrcc_usb1_phy_clksel()
.write(|w| w.set_mux(PhyClkselMux::I2ClkrootSosc));

let clkdiv = mrcc0.mrcc_usb1_phy_clkdiv();
clkdiv.modify(|w| {
w.set_div(self.phy_div.into_bits());
w.set_halt(ClkdivHalt::Off);
w.set_reset(ClkdivReset::Off);
});
clkdiv.modify(|w| {
w.set_halt(ClkdivHalt::On);
w.set_reset(ClkdivReset::On);
});
while clkdiv.read().unstab() == ClkdivUnstab::Off {}

Ok(PreEnableParts {
freq: freq / self.phy_div.into_divisor(),
wake_guard: WakeGuard::for_power(&self.power),
})
}
}
}

//
// eSPI
//

/// Selectable functional clocks for the eSPI controller.
#[cfg(feature = "mcxa5xx")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum EspiClockSel {
/// Gated FRO_HF / FIRC clock (the FRDM-MCXA577 test-bench selection).
FroHf,
/// SOSC/XTAL/EXTAL clock source.
#[cfg(not(feature = "sosc-as-gpio"))]
ClkIn,
/// PLL1 clock after its divider.
Pll1ClkDiv,
/// Disabled.
None,
}

/// Clock configuration for the MCXA5xx eSPI controller.
#[cfg(feature = "mcxa5xx")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct EspiConfig {
/// Power state required for the selected source clock.
pub power: PoweredClock,
/// Selected clock source.
pub source: EspiClockSel,
/// Pre-divider applied to the source clock.
pub div: Div4,
}

#[cfg(all(feature = "mcxa5xx", feature = "defmt"))]
impl defmt::Format for EspiConfig {
fn format(&self, f: defmt::Formatter) {
defmt::write!(
f,
"EspiConfig {{ power: {:?}, source: {:?}, div: {=u32} }}",
self.power,
self.source,
self.div.into_divisor()
)
}
}

#[cfg(feature = "mcxa5xx")]
impl Default for EspiConfig {
fn default() -> Self {
Self {
power: PoweredClock::NormalEnabledDeepSleepDisabled,
source: EspiClockSel::FroHf,
div: Div4::no_div(),
}
}
}

#[cfg(feature = "mcxa5xx")]
impl SPConfHelper for EspiConfig {
fn pre_enable_config(&self, clocks: &Clocks) -> Result<PreEnableParts, ClockError> {
let mrcc0 = crate::pac::MRCC0;
let clksel = mrcc0.mrcc_espi0_clksel();
let clkdiv = mrcc0.mrcc_espi0_clkdiv();

// NOTE: the eSPI bus clock is host-driven; this functional clock only
// feeds the controller core, which auto-divides internally unless
// MCTRL.CLK_DIV_DISABLE is set, so no fmax check is applied here.
let (freq, variant) = match self.source {
EspiClockSel::FroHf => {
let freq = clocks.ensure_fro_hf_active(&self.power)?;
(freq, EspiClkselMux::I1ClkrootFircGated)
}
#[cfg(not(feature = "sosc-as-gpio"))]
EspiClockSel::ClkIn => {
let freq = clocks.ensure_clk_in_active(&self.power)?;
(freq, EspiClkselMux::I3ClkrootSosc)
}
EspiClockSel::Pll1ClkDiv => {
let freq = clocks.ensure_pll1_clk_div_active(&self.power)?;
(freq, EspiClkselMux::I6ClkrootSpllDiv)
}
EspiClockSel::None => {
clksel.write(|w| w.set_mux(EspiClkselMux::_RESERVED_7));
clkdiv.modify(|w| {
w.set_reset(ClkdivReset::On);
w.set_halt(ClkdivHalt::On);
});
return Ok(PreEnableParts::empty());
}
};

apply_div4!(self, clksel, clkdiv, variant, freq)
}
}

/// Placeholder configuration for the DAC peripheral.
///
/// The DAC HAL driver is not yet implemented, but the PAC metadata
Expand Down
Loading