diff options
| author | James Munns <[email protected]> | 2025-11-12 17:00:40 +0100 |
|---|---|---|
| committer | James Munns <[email protected]> | 2025-11-12 17:00:40 +0100 |
| commit | 1ec472aa864d8add5dd14246324d671217fab304 (patch) | |
| tree | eb4c5ec4f0d52332ce7806c409327532d3318ca8 /src | |
| parent | 144c659fe278959736a1d391f1582dbbfc651646 (diff) | |
add frolf support
Diffstat (limited to 'src')
| -rw-r--r-- | src/clocks.rs | 106 |
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. |
| 3 | use mcxa_pac::scg0::firccsr::{FircFclkPeriphEn, FircSclkPeriphEn, Fircsten}; | 3 | use mcxa_pac::scg0::{ |
| 4 | firccsr::{FircFclkPeriphEn, FircSclkPeriphEn, Fircsten}, | ||
| 5 | sirccsr::{SircClkPeriphEn, Sircsten}, | ||
| 6 | }; | ||
| 4 | 7 | ||
| 5 | use crate::pac; | 8 | use crate::pac; |
| 6 | 9 | ||
| @@ -249,10 +252,12 @@ pub enum PoweredClock { | |||
| 249 | /// ───────────────▷│11 │ | 252 | /// ───────────────▷│11 │ |
| 250 | /// └─────┘ | 253 | /// └─────┘ |
| 251 | /// ``` | 254 | /// ``` |
| 255 | #[non_exhaustive] | ||
| 252 | pub struct ClocksConfig { | 256 | pub 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] | ||
| 267 | pub struct FircConfig { | 273 | pub 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] | ||
| 294 | pub struct SircConfig { | 301 | pub 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] | ||
| 303 | pub struct Clocks { | 311 | pub 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 | ||
| 326 | static CLOCKS: critical_section::Mutex<Option<Clocks>> = critical_section::Mutex::new(None); | 334 | static CLOCKS: critical_section::Mutex<Option<Clocks>> = critical_section::Mutex::new(None); |
| 327 | 335 | ||
| 336 | #[non_exhaustive] | ||
| 328 | pub enum ClockError { | 337 | pub 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 | ||
| 480 | pub fn init(settings: ClocksConfig) -> Result<(), ClockError> { | 579 | pub 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 | } |
