aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2025-11-12 17:00:40 +0100
committerJames Munns <[email protected]>2025-11-12 17:00:40 +0100
commit1ec472aa864d8add5dd14246324d671217fab304 (patch)
treeeb4c5ec4f0d52332ce7806c409327532d3318ca8 /src
parent144c659fe278959736a1d391f1582dbbfc651646 (diff)
add frolf support
Diffstat (limited to 'src')
-rw-r--r--src/clocks.rs106
1 files changed, 103 insertions, 3 deletions
diff --git a/src/clocks.rs b/src/clocks.rs
index 74e0daeeb..a00b3e4c5 100644
--- a/src/clocks.rs
+++ b/src/clocks.rs
@@ -1,6 +1,9 @@
1//! Clock control helpers (no magic numbers, PAC field access only). 1//! Clock control helpers (no magic numbers, PAC field access only).
2//! Provides reusable gate abstractions for peripherals used by the examples. 2//! Provides reusable gate abstractions for peripherals used by the examples.
3use mcxa_pac::scg0::firccsr::{FircFclkPeriphEn, FircSclkPeriphEn, Fircsten}; 3use mcxa_pac::scg0::{
4 firccsr::{FircFclkPeriphEn, FircSclkPeriphEn, Fircsten},
5 sirccsr::{SircClkPeriphEn, Sircsten},
6};
4 7
5use crate::pac; 8use crate::pac;
6 9
@@ -249,10 +252,12 @@ pub enum PoweredClock {
249/// ───────────────▷│11 │ 252/// ───────────────▷│11 │
250/// └─────┘ 253/// └─────┘
251/// ``` 254/// ```
255#[non_exhaustive]
252pub struct ClocksConfig { 256pub struct ClocksConfig {
253 // FIRC, FRO180, 45/60/90/180M clock source 257 // FIRC, FRO180, 45/60/90/180M clock source
254 pub firc: Option<FircConfig>, 258 pub firc: Option<FircConfig>,
255 pub sirc: Option<SircConfig>, 259 // NOTE: I don't think we *can* disable the SIRC?
260 pub sirc: SircConfig,
256} 261}
257 262
258// FIRC/FRO180M 263// FIRC/FRO180M
@@ -264,6 +269,7 @@ pub struct ClocksConfig {
264/// │ │ └─────▷│GATE│──────────▷ 269/// │ │ └─────▷│GATE│──────────▷
265/// └───────────┘ └────┘ 270/// └───────────┘ └────┘
266/// ``` 271/// ```
272#[non_exhaustive]
267pub struct FircConfig { 273pub struct FircConfig {
268 pub frequency: FircFreqSel, 274 pub frequency: FircFreqSel,
269 pub power: PoweredClock, 275 pub power: PoweredClock,
@@ -291,6 +297,7 @@ pub enum FircFreqSel {
291/// │ │ └─────▷│1/12│──────────▷ 297/// │ │ └─────▷│1/12│──────────▷
292/// └───────────┘ └────┘ 298/// └───────────┘ └────┘
293/// ``` 299/// ```
300#[non_exhaustive]
294pub struct SircConfig { 301pub struct SircConfig {
295 pub power: PoweredClock, 302 pub power: PoweredClock,
296 // peripheral output, aka sirc_12mhz 303 // peripheral output, aka sirc_12mhz
@@ -300,6 +307,7 @@ pub struct SircConfig {
300} 307}
301 308
302#[derive(Default, Debug, Clone)] 309#[derive(Default, Debug, Clone)]
310#[non_exhaustive]
303pub struct Clocks { 311pub struct Clocks {
304 pub clk_in: Option<Clock>, 312 pub clk_in: Option<Clock>,
305 313
@@ -325,6 +333,7 @@ pub struct Clocks {
325 333
326static CLOCKS: critical_section::Mutex<Option<Clocks>> = critical_section::Mutex::new(None); 334static CLOCKS: critical_section::Mutex<Option<Clocks>> = critical_section::Mutex::new(None);
327 335
336#[non_exhaustive]
328pub enum ClockError { 337pub enum ClockError {
329 AlreadyInitialized, 338 AlreadyInitialized,
330 BadConfig { clock: &'static str, reason: &'static str }, 339 BadConfig { clock: &'static str, reason: &'static str },
@@ -475,6 +484,96 @@ impl ClockOperator<'_> {
475 484
476 Ok(()) 485 Ok(())
477 } 486 }
487
488 fn configure_sirc_clocks(&mut self) -> Result<(), ClockError> {
489 let SircConfig {
490 power,
491 fro_12m_enabled,
492 fro_lf_div,
493 } = &self.config.sirc;
494 let base_freq = 12_000_000;
495
496 // Allow writes
497 self.scg0.sirccsr().modify(|_r, w| w.lk().write_enabled());
498 self.clocks.fro_12m_root = Some(Clock {
499 frequency: base_freq,
500 power: *power,
501 });
502
503 let deep = match power {
504 PoweredClock::HighPowerOnly => Sircsten::Disabled,
505 PoweredClock::AlwaysEnabled => Sircsten::Enabled,
506 };
507 let pclk = if *fro_12m_enabled {
508 self.clocks.fro_12m = Some(Clock {
509 frequency: base_freq,
510 power: *power,
511 });
512 self.clocks.clk_1m = Some(Clock {
513 frequency: base_freq / 12,
514 power: *power,
515 });
516 SircClkPeriphEn::Enabled
517 } else {
518 SircClkPeriphEn::Disabled
519 };
520
521 // Set sleep/peripheral usage
522 self.scg0.sirccsr().modify(|_r, w| {
523 w.sircsten().variant(deep);
524 w.sirc_clk_periph_en().variant(pclk);
525 w
526 });
527
528 while self.scg0.sirccsr().read().sircvld().is_disabled_or_not_valid() {}
529 if self.scg0.sirccsr().read().sircerr().is_error_detected() {
530 return Err(ClockError::BadConfig {
531 clock: "sirc",
532 reason: "error set",
533 });
534 }
535
536 // reset lock
537 self.scg0.sirccsr().modify(|_r, w| w.lk().write_disabled());
538
539 // Do we enable the `fro_lf_div` output?
540 if let Some(d) = fro_lf_div.as_ref() {
541 // We need `fro_lf` to be enabled
542 if !*fro_12m_enabled {
543 return Err(ClockError::BadConfig {
544 clock: "fro_lf_div",
545 reason: "fro_12m not enabled",
546 });
547 }
548
549 // Halt and reset the div
550 self.syscon.frolfdiv().write(|w| {
551 w.halt().halt();
552 w.reset().asserted();
553 w
554 });
555 // Then change the div, unhalt it, and reset it
556 self.syscon.frolfdiv().write(|w| {
557 unsafe {
558 w.div().bits(d.into_bits());
559 }
560 w.halt().run();
561 w.reset().released();
562 w
563 });
564
565 // Wait for clock to stabilize
566 while self.syscon.frolfdiv().read().unstab().is_ongoing() {}
567
568 // Store off the clock info
569 self.clocks.fro_lf_div = Some(Clock {
570 frequency: base_freq / d.into_divisor(),
571 power: *power,
572 });
573 }
574
575 todo!()
576 }
478} 577}
479 578
480pub fn init(settings: ClocksConfig) -> Result<(), ClockError> { 579pub fn init(settings: ClocksConfig) -> Result<(), ClockError> {
@@ -497,7 +596,8 @@ pub fn init(settings: ClocksConfig) -> Result<(), ClockError> {
497 }; 596 };
498 597
499 operator.configure_firc_clocks()?; 598 operator.configure_firc_clocks()?;
500 // TODO, SIRC, and everything downstream 599 operator.configure_sirc_clocks()?;
600 // TODO, everything downstream
501 601
502 Ok(()) 602 Ok(())
503} 603}