aboutsummaryrefslogtreecommitdiff
path: root/embassy-imxrt/src/clocks.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-imxrt/src/clocks.rs')
-rw-r--r--embassy-imxrt/src/clocks.rs1687
1 files changed, 1687 insertions, 0 deletions
diff --git a/embassy-imxrt/src/clocks.rs b/embassy-imxrt/src/clocks.rs
new file mode 100644
index 000000000..1d36fb142
--- /dev/null
+++ b/embassy-imxrt/src/clocks.rs
@@ -0,0 +1,1687 @@
1//! Clock configuration for the `RT6xx`
2use core::sync::atomic::{AtomicU32, AtomicU8, Ordering};
3
4#[cfg(feature = "defmt")]
5use defmt;
6use paste::paste;
7
8use crate::pac;
9
10/// Clock configuration;
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub enum Clocks {
14 /// Low power oscillator
15 Lposc,
16 /// System Frequency Resonance Oscillator (SFRO)
17 Sfro,
18 /// Real Time Clock
19 Rtc,
20 /// Feed-forward Ring Oscillator
21 Ffro, // This includes that div2 and div4 variations
22 /// External Clock Input
23 ClkIn,
24 /// AHB Clock
25 Hclk,
26 /// Main Clock
27 MainClk,
28 /// Main PLL Clock
29 MainPllClk, // also has aux0,aux1,dsp, and audio pll's downstream
30 /// System Clock
31 SysClk,
32 /// System Oscillator
33 SysOscClk,
34 /// ADC Clock
35 Adc,
36}
37
38/// Clock configuration.
39pub struct ClockConfig {
40 /// low-power oscillator config
41 pub lposc: LposcConfig,
42 /// 16Mhz internal oscillator config
43 pub sfro: SfroConfig,
44 /// Real Time Clock config
45 pub rtc: RtcClkConfig,
46 /// 48/60 Mhz internal oscillator config
47 pub ffro: FfroConfig,
48 // pub pll: Option<PllPfdConfig>, //potentially covered in main pll clk
49 /// External Clock-In config
50 pub clk_in: ClkInConfig,
51 /// AHB bus clock config
52 pub hclk: HclkConfig,
53 /// Main Clock config
54 pub main_clk: MainClkConfig,
55 /// Main Pll clock config
56 pub main_pll_clk: MainPllClkConfig,
57 /// Software concept to be used with systick, doesn't map to a register
58 pub sys_clk: SysClkConfig,
59 /// System Oscillator Config
60 pub sys_osc: SysOscConfig,
61 // todo: move ADC here
62}
63
64impl ClockConfig {
65 /// Clock configuration derived from external crystal.
66 #[must_use]
67 pub fn crystal() -> Self {
68 const CORE_CPU_FREQ: u32 = 500_000_000;
69 const PLL_CLK_FREQ: u32 = 528_000_000;
70 const SYS_CLK_FREQ: u32 = CORE_CPU_FREQ / 2;
71 Self {
72 lposc: LposcConfig {
73 state: State::Enabled,
74 freq: AtomicU32::new(Into::into(LposcFreq::Lp1m)),
75 },
76 sfro: SfroConfig { state: State::Enabled },
77 rtc: RtcClkConfig {
78 state: State::Enabled,
79 wake_alarm_state: State::Disabled,
80 sub_second_state: State::Disabled,
81 freq: AtomicU32::new(Into::into(RtcFreq::Default1Hz)),
82 rtc_int: RtcInterrupts::None,
83 },
84 ffro: FfroConfig {
85 state: State::Enabled,
86 freq: AtomicU32::new(Into::into(FfroFreq::Ffro48m)),
87 },
88 //pll: Some(PllConfig {}),//includes aux0 and aux1 pll
89 clk_in: ClkInConfig {
90 state: State::Disabled,
91 // This is an externally sourced clock
92 // Don't give it an initial frequency
93 freq: Some(AtomicU32::new(0)),
94 },
95 hclk: HclkConfig { state: State::Disabled },
96 main_clk: MainClkConfig {
97 state: State::Enabled,
98 //FFRO divided by 4 is reset values of Main Clk Sel A, Sel B
99 src: MainClkSrc::FFRO,
100 div_int: AtomicU32::new(4),
101 freq: AtomicU32::new(CORE_CPU_FREQ),
102 },
103 main_pll_clk: MainPllClkConfig {
104 state: State::Enabled,
105 src: MainPllClkSrc::SFRO,
106 freq: AtomicU32::new(PLL_CLK_FREQ),
107 mult: AtomicU8::new(16),
108 pfd0: 19, //
109 pfd1: 0, // future field
110 pfd2: 19, // 0x13
111 pfd3: 0, // future field
112 aux0_div: 0,
113 aux1_div: 0,
114 },
115 sys_clk: SysClkConfig {
116 sysclkfreq: AtomicU32::new(SYS_CLK_FREQ),
117 },
118 sys_osc: SysOscConfig { state: State::Enabled },
119 //adc: Some(AdcConfig {}), // TODO: add config
120 }
121 }
122}
123
124#[derive(Clone, Copy, Debug, PartialEq, Eq)]
125#[cfg_attr(feature = "defmt", derive(defmt::Format))]
126/// Clock state enum
127pub enum State {
128 /// Clock is enabled
129 Enabled,
130 /// Clock is disabled
131 Disabled,
132}
133
134#[derive(Clone, Copy, Debug, PartialEq, Eq)]
135#[cfg_attr(feature = "defmt", derive(defmt::Format))]
136/// Low Power Oscillator valid frequencies
137pub enum LposcFreq {
138 /// 1 `MHz` oscillator
139 Lp1m,
140 /// 32kHz oscillator
141 Lp32k,
142}
143
144impl From<LposcFreq> for u32 {
145 fn from(value: LposcFreq) -> Self {
146 match value {
147 LposcFreq::Lp1m => 1_000_000,
148 LposcFreq::Lp32k => 32_768,
149 }
150 }
151}
152
153impl TryFrom<u32> for LposcFreq {
154 type Error = ClockError;
155 fn try_from(value: u32) -> Result<Self, Self::Error> {
156 match value {
157 1_000_000 => Ok(LposcFreq::Lp1m),
158 32_768 => Ok(LposcFreq::Lp32k),
159 _ => Err(ClockError::InvalidFrequency),
160 }
161 }
162}
163
164/// Low power oscillator config
165pub struct LposcConfig {
166 state: State,
167 // low power osc
168 freq: AtomicU32,
169}
170
171const SFRO_FREQ: u32 = 16_000_000;
172/// SFRO config
173pub struct SfroConfig {
174 state: State,
175}
176
177/// Valid RTC frequencies
178pub enum RtcFreq {
179 /// "Alarm" aka 1Hz clock
180 Default1Hz,
181 /// "Wake" aka 1kHz clock
182 HighResolution1khz,
183 /// 32kHz clock
184 SubSecond32kHz,
185}
186
187impl From<RtcFreq> for u32 {
188 fn from(value: RtcFreq) -> Self {
189 match value {
190 RtcFreq::Default1Hz => 1,
191 RtcFreq::HighResolution1khz => 1_000,
192 RtcFreq::SubSecond32kHz => 32_768,
193 }
194 }
195}
196
197impl TryFrom<u32> for RtcFreq {
198 type Error = ClockError;
199 fn try_from(value: u32) -> Result<Self, Self::Error> {
200 match value {
201 1 => Ok(RtcFreq::Default1Hz),
202 1_000 => Ok(RtcFreq::HighResolution1khz),
203 32_768 => Ok(RtcFreq::SubSecond32kHz),
204 _ => Err(ClockError::InvalidFrequency),
205 }
206 }
207}
208
209/// RTC Interrupt options
210pub enum RtcInterrupts {
211 /// No interrupts are set
212 None,
213 /// 1Hz RTC clock aka Alarm interrupt set
214 Alarm,
215 /// 1kHz RTC clock aka Wake interrupt set
216 Wake,
217}
218
219impl From<RtcInterrupts> for u8 {
220 fn from(value: RtcInterrupts) -> Self {
221 match value {
222 RtcInterrupts::None => 0b00,
223 RtcInterrupts::Alarm => 0b01,
224 RtcInterrupts::Wake => 0b10,
225 }
226 }
227}
228/// RTC clock config.
229pub struct RtcClkConfig {
230 /// 1 Hz Clock state
231 pub state: State,
232 /// 1kHz Clock state
233 pub wake_alarm_state: State,
234 /// 32kHz Clock state
235 pub sub_second_state: State,
236 /// RTC clock source.
237 pub freq: AtomicU32,
238 /// RTC Interrupt
239 pub rtc_int: RtcInterrupts,
240}
241
242/// Valid FFRO Frequencies
243pub enum FfroFreq {
244 /// 48 Mhz Internal Oscillator
245 Ffro48m,
246 /// 60 `MHz` Internal Oscillator
247 Ffro60m,
248}
249
250/// FFRO Clock Config
251pub struct FfroConfig {
252 /// FFRO Clock state
253 state: State,
254 /// FFRO Frequency
255 freq: AtomicU32,
256}
257
258impl From<FfroFreq> for u32 {
259 fn from(value: FfroFreq) -> Self {
260 match value {
261 FfroFreq::Ffro48m => 48_000_000,
262 FfroFreq::Ffro60m => 60_000_000,
263 }
264 }
265}
266
267impl TryFrom<u32> for FfroFreq {
268 type Error = ClockError;
269 fn try_from(value: u32) -> Result<Self, Self::Error> {
270 match value {
271 48_000_000 => Ok(FfroFreq::Ffro48m),
272 60_000_000 => Ok(FfroFreq::Ffro60m),
273 _ => Err(ClockError::InvalidFrequency),
274 }
275 }
276}
277
278/// PLL clock source
279#[derive(Clone, Copy, Debug, PartialEq, Eq)]
280#[cfg_attr(feature = "defmt", derive(defmt::Format))]
281pub enum MainPllClkSrc {
282 /// SFRO
283 SFRO,
284 /// External Clock
285 ClkIn,
286 /// FFRO
287 FFRO,
288}
289
290/// Transform from Source Clock enum to Clocks
291impl From<MainPllClkSrc> for Clocks {
292 fn from(value: MainPllClkSrc) -> Self {
293 match value {
294 MainPllClkSrc::SFRO => Clocks::Sfro,
295 MainPllClkSrc::ClkIn => Clocks::ClkIn,
296 MainPllClkSrc::FFRO => Clocks::Ffro,
297 }
298 }
299}
300
301impl TryFrom<Clocks> for MainPllClkSrc {
302 type Error = ClockError;
303 fn try_from(value: Clocks) -> Result<Self, Self::Error> {
304 match value {
305 Clocks::Sfro => Ok(MainPllClkSrc::SFRO),
306 Clocks::Ffro => Ok(MainPllClkSrc::FFRO),
307 Clocks::ClkIn => Ok(MainPllClkSrc::ClkIn),
308 _ => Err(ClockError::ClockNotSupported),
309 }
310 }
311}
312
313/// PLL configuration.
314pub struct MainPllClkConfig {
315 /// Clock active state
316 pub state: State,
317 /// Main clock source.
318 pub src: MainPllClkSrc,
319 /// Main clock frequency
320 pub freq: AtomicU32,
321 //TODO: numerator and denominator not used but present in register
322 /// Multiplication factor.
323 pub mult: AtomicU8,
324 // the following are actually 6-bits not 8
325 /// Fractional divider 0, main pll clock
326 pub pfd0: u8,
327 /// Fractional divider 1
328 pub pfd1: u8,
329 /// Fractional divider 2
330 pub pfd2: u8,
331 /// Fractional divider 3
332 pub pfd3: u8,
333 // Aux dividers
334 /// aux divider 0
335 pub aux0_div: u8,
336 /// aux divider 1
337 pub aux1_div: u8,
338}
339/// External input clock config
340pub struct ClkInConfig {
341 /// External clock input state
342 state: State,
343 /// External clock input rate
344 freq: Option<AtomicU32>,
345}
346
347/// AHB clock config
348pub struct HclkConfig {
349 /// divider to turn main clk into hclk for AHB bus
350 pub state: State,
351}
352
353/// Main clock source.
354#[derive(Clone, Copy, Debug, PartialEq, Eq)]
355#[cfg_attr(feature = "defmt", derive(defmt::Format))]
356pub enum MainClkSrc {
357 /// FFRO divided by 4
358 FFROdiv4, // probably don't need since it'll be covered by div_int
359 /// External Clock
360 ClkIn,
361 /// Low Power Oscillator
362 Lposc,
363 /// FFRO
364 FFRO,
365 /// SFRO
366 SFRO,
367 /// Main PLL Clock
368 PllMain,
369 /// RTC 32kHz oscillator.
370 RTC32k,
371}
372
373impl From<MainClkSrc> for Clocks {
374 fn from(value: MainClkSrc) -> Self {
375 match value {
376 MainClkSrc::ClkIn => Clocks::ClkIn,
377 MainClkSrc::Lposc => Clocks::Lposc,
378 MainClkSrc::FFRO => Clocks::Ffro,
379 MainClkSrc::SFRO => Clocks::Sfro,
380 MainClkSrc::PllMain => Clocks::MainPllClk,
381 MainClkSrc::RTC32k => Clocks::Rtc,
382 MainClkSrc::FFROdiv4 => Clocks::Ffro,
383 }
384 }
385}
386
387impl TryFrom<Clocks> for MainClkSrc {
388 type Error = ClockError;
389 fn try_from(value: Clocks) -> Result<Self, Self::Error> {
390 match value {
391 Clocks::ClkIn => Ok(MainClkSrc::ClkIn),
392 Clocks::Lposc => Ok(MainClkSrc::Lposc),
393 Clocks::Sfro => Ok(MainClkSrc::SFRO),
394 Clocks::MainPllClk => Ok(MainClkSrc::PllMain),
395 Clocks::Rtc => Ok(MainClkSrc::RTC32k),
396 Clocks::Ffro => Ok(MainClkSrc::FFRO),
397 _ => Err(ClockError::ClockNotSupported),
398 }
399 }
400}
401
402/// Main clock config.
403pub struct MainClkConfig {
404 /// Main clock state
405 pub state: State,
406 /// Main clock source.
407 pub src: MainClkSrc,
408 /// Main clock divider.
409 pub div_int: AtomicU32,
410 /// Clock Frequency
411 pub freq: AtomicU32,
412}
413
414/// System Core Clock config, SW concept for systick
415pub struct SysClkConfig {
416 /// keeps track of the system core clock frequency
417 /// future use with systick
418 pub sysclkfreq: AtomicU32,
419}
420
421/// System Oscillator Config
422pub struct SysOscConfig {
423 /// Clock State
424 pub state: State,
425}
426const SYS_OSC_DEFAULT_FREQ: u32 = 24_000_000;
427
428/// Clock Errors
429#[derive(Clone, Copy, Debug, PartialEq, Eq)]
430#[cfg_attr(feature = "defmt", derive(defmt::Format))]
431pub enum ClockError {
432 /// Error due to attempting to change a clock with the wrong config block
433 ClockMismatch,
434 /// Error due to attempting to modify a clock that's not yet been enabled
435 ClockNotEnabled,
436 /// Error due to attempting to set a clock source that's not a supported option
437 ClockNotSupported,
438 /// Error due to attempting to set a clock to an invalid frequency
439 InvalidFrequency,
440 /// Error due to attempting to modify a clock output with an invalid divider
441 InvalidDiv,
442 /// Error due to attempting to modify a clock output with an invalid multiplier
443 InvalidMult,
444}
445
446/// Trait to configure one of the clocks
447pub trait ConfigurableClock {
448 /// Reset the clock, will enable it
449 fn disable(&self) -> Result<(), ClockError>;
450 /// Enable the clock
451 fn enable_and_reset(&self) -> Result<(), ClockError>;
452 /// Return the clock rate (Hz)
453 fn get_clock_rate(&self) -> Result<u32, ClockError>;
454 /// Set the desired clock rate (Hz)
455 fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError>;
456 /// Returns whether this clock is enabled
457 fn is_enabled(&self) -> bool;
458}
459
460impl LposcConfig {
461 /// Initializes low-power oscillator.
462 fn init_lposc() {
463 // Enable low power oscillator
464 // SAFETY: unsafe needed to take pointer to Sysctl0, only happens once during init
465 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
466 sysctl0.pdruncfg0_clr().write(|w| w.lposc_pd().clr_pdruncfg0());
467
468 // Wait for low-power oscillator to be ready (typically 64 us)
469 // Busy loop seems better here than trying to shoe-in an async delay
470 // SAFETY: unsafe needed to take pointer to Clkctl0, needed to validate HW is ready
471 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
472 while clkctl0.lposcctl0().read().clkrdy().bit_is_clear() {}
473 }
474}
475impl ConfigurableClock for LposcConfig {
476 fn enable_and_reset(&self) -> Result<(), ClockError> {
477 LposcConfig::init_lposc();
478 Ok(())
479 }
480 fn disable(&self) -> Result<(), ClockError> {
481 // SAFETY: unsafe needed to take pointer to Sysctl0, needed to power down the LPOSC HW
482 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
483 sysctl0.pdruncfg0_set().write(|w| w.lposc_pd().set_pdruncfg0());
484 // Wait until LPOSC disabled
485 while !sysctl0.pdruncfg0().read().lposc_pd().is_power_down() {}
486 Ok(())
487 }
488 fn get_clock_rate(&self) -> Result<u32, ClockError> {
489 Ok(self.freq.load(Ordering::Relaxed))
490 }
491 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
492 if let Ok(r) = <u32 as TryInto<LposcFreq>>::try_into(freq) {
493 match r {
494 LposcFreq::Lp1m => {
495 self.freq
496 .store(LposcFreq::Lp1m as u32, core::sync::atomic::Ordering::Relaxed);
497 Ok(())
498 }
499 LposcFreq::Lp32k => {
500 self.freq
501 .store(LposcFreq::Lp1m as u32, core::sync::atomic::Ordering::Relaxed);
502 Ok(())
503 }
504 }
505 } else {
506 error!("failed to convert desired clock rate, {:#}, to LPOSC Freq", freq);
507 Err(ClockError::InvalidFrequency)
508 }
509 }
510 fn is_enabled(&self) -> bool {
511 self.state == State::Enabled
512 }
513}
514
515impl FfroConfig {
516 /// Necessary register writes to initialize the FFRO clock
517 pub fn init_ffro_clk() {
518 // SAFETY: unsafe needed to take pointer to Sysctl0, only to power up FFRO
519 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
520
521 /* Power on FFRO (48/60MHz) */
522 sysctl0.pdruncfg0_clr().write(|w| w.ffro_pd().clr_pdruncfg0());
523
524 // SAFETY: unsafe needed to take pointer to Clkctl0, only to set proper ffro update mode
525 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
526
527 clkctl0.ffroctl1().write(|w| w.update().normal_mode());
528
529 // No FFRO enable/disable control in CLKCTL.
530 // Delay enough for FFRO to be stable in case it was just powered on
531 delay_loop_clocks(50, 12_000_000);
532 }
533}
534
535impl ConfigurableClock for FfroConfig {
536 fn enable_and_reset(&self) -> Result<(), ClockError> {
537 // SAFETY: should be called once
538 FfroConfig::init_ffro_clk();
539 // default is 48 MHz
540 Ok(())
541 }
542 fn disable(&self) -> Result<(), ClockError> {
543 // SAFETY: unsafe needed to take pointer to Sysctl0, only to power down FFRO
544 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
545 sysctl0.pdruncfg0_set().write(|w| w.ffro_pd().set_pdruncfg0());
546 delay_loop_clocks(30, 12_000_000);
547 // Wait until FFRO disabled
548 while !sysctl0.pdruncfg0().read().ffro_pd().is_power_down() {}
549 Ok(())
550 }
551 fn get_clock_rate(&self) -> Result<u32, ClockError> {
552 trace!("getting ffro clock rate");
553 Ok(self.freq.load(Ordering::Relaxed))
554 }
555 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
556 if let Ok(r) = <u32 as TryInto<FfroFreq>>::try_into(freq) {
557 match r {
558 FfroFreq::Ffro48m => {
559 // SAFETY: unsafe needed to take pointer to Clkctl0, needed to set the right HW frequency
560 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
561 clkctl0.ffroctl1().write(|w| w.update().update_safe_mode());
562 clkctl0.ffroctl0().write(|w| w.trim_range().ffro_48mhz());
563 clkctl0.ffroctl1().write(|w| w.update().normal_mode());
564
565 self.freq
566 .store(FfroFreq::Ffro48m as u32, core::sync::atomic::Ordering::Relaxed);
567 Ok(())
568 }
569 FfroFreq::Ffro60m => {
570 // SAFETY: unsafe needed to take pointer to Clkctl0, needed to set the right HW frequency
571 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
572 clkctl0.ffroctl1().write(|w| w.update().update_safe_mode());
573 clkctl0.ffroctl0().write(|w| w.trim_range().ffro_60mhz());
574 clkctl0.ffroctl1().write(|w| w.update().normal_mode());
575
576 self.freq
577 .store(FfroFreq::Ffro60m as u32, core::sync::atomic::Ordering::Relaxed);
578 Ok(())
579 }
580 }
581 } else {
582 error!("failed to convert desired clock rate, {:#}, to FFRO Freq", freq);
583 Err(ClockError::InvalidFrequency)
584 }
585 }
586 fn is_enabled(&self) -> bool {
587 self.state == State::Enabled
588 }
589}
590
591impl ConfigurableClock for SfroConfig {
592 fn enable_and_reset(&self) -> Result<(), ClockError> {
593 // SAFETY: unsafe needed to take pointer to Sysctl0, only to power up SFRO
594 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
595 sysctl0.pdruncfg0_clr().write(|w| w.sfro_pd().clr_pdruncfg0());
596 // wait until ready
597 while !sysctl0.pdruncfg0().read().sfro_pd().is_enabled() {}
598 Ok(())
599 }
600 fn disable(&self) -> Result<(), ClockError> {
601 // SAFETY: unsafe needed to take pointer to Sysctl0, only to power down SFRO
602 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
603 sysctl0.pdruncfg0_set().write(|w| w.sfro_pd().set_pdruncfg0());
604 delay_loop_clocks(30, 12_000_000);
605 // Wait until SFRO disabled
606 while !sysctl0.pdruncfg0().read().sfro_pd().is_power_down() {}
607 Ok(())
608 }
609 fn get_clock_rate(&self) -> Result<u32, ClockError> {
610 if self.state == State::Enabled {
611 Ok(SFRO_FREQ)
612 } else {
613 Err(ClockError::ClockNotEnabled)
614 }
615 }
616 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
617 if self.state == State::Enabled {
618 if freq == SFRO_FREQ {
619 trace!("Sfro frequency is already set at 16MHz");
620 Ok(())
621 } else {
622 Err(ClockError::InvalidFrequency)
623 }
624 } else {
625 Err(ClockError::ClockNotEnabled)
626 }
627 }
628 fn is_enabled(&self) -> bool {
629 self.state == State::Enabled
630 }
631}
632
633/// A Clock with multiple options for clock source
634pub trait MultiSourceClock {
635 /// Returns which clock is being used as the clock source and its rate
636 fn get_clock_source_and_rate(&self, clock: &Clocks) -> Result<(Clocks, u32), ClockError>;
637 /// Sets a specific clock source and its associated rate
638 fn set_clock_source_and_rate(
639 &mut self,
640 clock_src_config: &mut impl ConfigurableClock,
641 clock_src: &Clocks,
642 rate: u32,
643 ) -> Result<(), ClockError>;
644}
645
646impl MultiSourceClock for MainPllClkConfig {
647 fn get_clock_source_and_rate(&self, clock: &Clocks) -> Result<(Clocks, u32), ClockError> {
648 match clock {
649 Clocks::MainPllClk => {
650 let converted_clock = Clocks::from(self.src);
651 Ok((converted_clock, self.freq.load(Ordering::Relaxed)))
652 }
653 _ => Err(ClockError::ClockMismatch),
654 }
655 }
656 fn set_clock_source_and_rate(
657 &mut self,
658 clock_src_config: &mut impl ConfigurableClock,
659 clock_src: &Clocks,
660 rate: u32,
661 ) -> Result<(), ClockError> {
662 if let Ok(c) = <Clocks as TryInto<MainPllClkSrc>>::try_into(*clock_src) {
663 match c {
664 MainPllClkSrc::ClkIn => {
665 self.src = MainPllClkSrc::ClkIn;
666 // div mult and rate don't matter since this is an external clock
667 self.set_clock_rate(1, 1, rate)
668 }
669 MainPllClkSrc::FFRO => {
670 // FFRO Clock is divided by 2
671 let r = clock_src_config.get_clock_rate()?;
672 let base_rate = r / 2;
673 let m = MainPllClkConfig::calc_mult(rate, base_rate)?;
674
675 self.src = MainPllClkSrc::FFRO;
676 self.set_clock_rate(2, m, rate)
677 }
678 MainPllClkSrc::SFRO => {
679 if !clock_src_config.is_enabled() {
680 error!("Can't set SFRO as source for MainPll as it's not enabled");
681 return Err(ClockError::ClockNotEnabled);
682 }
683 // check if desired frequency is a valid multiple of 16m SFRO clock
684 let m = MainPllClkConfig::calc_mult(rate, SFRO_FREQ)?;
685 self.src = MainPllClkSrc::SFRO;
686 self.set_clock_rate(1, m, rate)
687 }
688 }
689 } else {
690 Err(ClockError::ClockNotSupported)
691 }
692 }
693}
694
695impl ConfigurableClock for MainPllClkConfig {
696 fn enable_and_reset(&self) -> Result<(), ClockError> {
697 MainPllClkConfig::init_syspll();
698
699 MainPllClkConfig::init_syspll_pfd0(self.pfd0);
700
701 MainPllClkConfig::init_syspll_pfd2(self.pfd2);
702 Ok(())
703 }
704 fn disable(&self) -> Result<(), ClockError> {
705 if self.is_enabled() {
706 error!("Attempting to reset the Main Pll Clock, should be resetting its source");
707 Err(ClockError::ClockNotSupported)
708 } else {
709 Err(ClockError::ClockNotEnabled)
710 }
711 }
712 fn get_clock_rate(&self) -> Result<u32, ClockError> {
713 if self.is_enabled() {
714 let (_c, rate) = self.get_clock_source_and_rate(&Clocks::MainPllClk)?;
715 Ok(rate)
716 } else {
717 Err(ClockError::ClockNotEnabled)
718 }
719 }
720 fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError> {
721 if self.is_enabled() {
722 trace!("attempting to set main pll clock rate");
723 // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0
724 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
725 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
726
727 // Power down pll before changes
728 sysctl0
729 .pdruncfg0_set()
730 .write(|w| w.syspllldo_pd().set_pdruncfg0().syspllana_pd().set_pdruncfg0());
731
732 let desired_freq: u64 = self.freq.load(Ordering::Relaxed).into();
733
734 match self.src {
735 c if c == MainPllClkSrc::ClkIn || c == MainPllClkSrc::FFRO || c == MainPllClkSrc::SFRO => {
736 let mut base_rate;
737 match c {
738 MainPllClkSrc::ClkIn => {
739 clkctl0.syspll0clksel().write(|w| w.sel().sysxtal_clk());
740 let r = self.get_clock_rate()?;
741 base_rate = r;
742 }
743 MainPllClkSrc::FFRO => {
744 trace!("found FFRO as source, wait a bit");
745 delay_loop_clocks(1000, desired_freq);
746 match clkctl0.ffroctl0().read().trim_range().is_ffro_48mhz() {
747 true => base_rate = Into::into(FfroFreq::Ffro48m),
748 false => base_rate = Into::into(FfroFreq::Ffro60m),
749 }
750 trace!("found ffro rate to be: {:#}", base_rate);
751 if div == 2 {
752 trace!("dividing FFRO rate by 2");
753 clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2());
754 delay_loop_clocks(150, desired_freq);
755 base_rate /= 2;
756 } else {
757 return Err(ClockError::InvalidDiv);
758 }
759 }
760 MainPllClkSrc::SFRO => {
761 base_rate = SFRO_FREQ;
762 clkctl0.syspll0clksel().write(|w| w.sel().sfro_clk());
763 }
764 };
765 base_rate *= u32::from(mult);
766 trace!("calculated base rate at: {:#}", base_rate);
767 if base_rate != freq {
768 // make sure to power syspll back up before returning the error
769 error!("invalid frequency found, powering syspll back up before returning error. Check div and mult");
770 // Clear System PLL reset
771 clkctl0.syspll0ctl0().write(|w| w.reset().normal());
772 // Power up SYSPLL
773 sysctl0
774 .pdruncfg0_clr()
775 .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0());
776 return Err(ClockError::InvalidFrequency);
777 }
778 trace!("setting default num and denom");
779 // SAFETY: unsafe needed to write the bits for the num and demon fields
780 clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0b0) });
781 clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0b1) });
782 delay_loop_clocks(30, desired_freq);
783 self.mult.store(mult, Ordering::Relaxed);
784 trace!("setting self.mult as: {:#}", mult);
785 match mult {
786 16 => {
787 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_16());
788 }
789 17 => {
790 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_17());
791 }
792 20 => {
793 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_20());
794 }
795 22 => {
796 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_22());
797 }
798 27 => {
799 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_27());
800 }
801 33 => {
802 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_33());
803 }
804 _ => return Err(ClockError::InvalidMult),
805 }
806 trace!("clear syspll reset");
807 // Clear System PLL reset
808 clkctl0.syspll0ctl0().modify(|_r, w| w.reset().normal());
809 // Power up SYSPLL
810 sysctl0
811 .pdruncfg0_clr()
812 .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0());
813
814 // Set System PLL HOLDRINGOFF_ENA
815 clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().enable());
816 delay_loop_clocks(75, desired_freq);
817
818 // Clear System PLL HOLDRINGOFF_ENA
819 clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable());
820 delay_loop_clocks(15, desired_freq);
821
822 trace!("setting new PFD0 bits");
823 // gate the output and clear bits.
824 // SAFETY: unsafe needed to write the bits for pfd0
825 clkctl0
826 .syspll0pfd()
827 .modify(|_, w| unsafe { w.pfd0_clkgate().gated().pfd0().bits(0x0) });
828 // set pfd bits and un-gate the clock output
829 // output is multiplied by syspll * 18/pfd0_bits
830 // SAFETY: unsafe needed to write the bits for pfd0
831 clkctl0
832 .syspll0pfd()
833 .modify(|_r, w| unsafe { w.pfd0_clkgate().not_gated().pfd0().bits(0x12) });
834 // wait for ready bit to be set
835 delay_loop_clocks(50, desired_freq);
836 trace!("waiting for mainpll clock to be ready");
837 while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {}
838 // clear by writing a 1
839 clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().set_bit());
840
841 Ok(())
842 }
843 _ => Err(ClockError::ClockNotSupported),
844 }
845 } else {
846 Err(ClockError::ClockNotEnabled)
847 }
848 }
849 fn is_enabled(&self) -> bool {
850 self.state == State::Enabled
851 }
852}
853
854impl MainPllClkConfig {
855 /// Calculate the mult value of a desired frequency, return error if invalid
856 pub(self) fn calc_mult(rate: u32, base_freq: u32) -> Result<u8, ClockError> {
857 trace!("calculating mult for {:#} / {:#}", rate, base_freq);
858 const VALIDMULTS: [u8; 6] = [16, 17, 20, 22, 27, 33];
859 if rate > base_freq && rate % base_freq == 0 {
860 let mult = (rate / base_freq) as u8;
861 trace!("verifying that calculated mult {:#} is a valid one", mult);
862 if VALIDMULTS.into_iter().any(|i| i == mult) {
863 Ok(mult)
864 } else {
865 Err(ClockError::InvalidFrequency)
866 }
867 } else {
868 Err(ClockError::InvalidFrequency)
869 }
870 }
871 pub(self) fn init_syspll() {
872 // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0
873 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
874 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
875
876 // Power down SYSPLL before change fractional settings
877 sysctl0
878 .pdruncfg0_set()
879 .write(|w| w.syspllldo_pd().set_pdruncfg0().syspllana_pd().set_pdruncfg0());
880
881 clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2());
882 // SAFETY: unsafe needed to write the bits for both num and denom
883 clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0x0) });
884 clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0x1) });
885
886 // kCLOCK_SysPllMult22
887 clkctl0.syspll0ctl0().modify(|_, w| w.mult().div_22());
888
889 // Clear System PLL reset
890 clkctl0.syspll0ctl0().modify(|_, w| w.reset().normal());
891
892 // Power up SYSPLL
893 sysctl0
894 .pdruncfg0_clr()
895 .write(|w| w.syspllldo_pd().clr_pdruncfg0().syspllana_pd().clr_pdruncfg0());
896 delay_loop_clocks((150 & 0xFFFF) / 2, 12_000_000);
897
898 // Set System PLL HOLDRINGOFF_ENA
899 clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().enable());
900 delay_loop_clocks((150 & 0xFFFF) / 2, 12_000_000);
901
902 // Clear System PLL HOLDRINGOFF_ENA
903 clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable());
904 delay_loop_clocks((15 & 0xFFFF) / 2, 12_000_000);
905 }
906 /// enables default settings for pfd2 bits
907 pub(self) fn init_syspll_pfd2(config_bits: u8) {
908 // SAFETY: unsafe needed to take pointer to Clkctl0 and write specific bits
909 // needed to change the output of pfd0
910 unsafe {
911 let clkctl0 = crate::pac::Clkctl0::steal();
912
913 // Disable the clock output first.
914 // SAFETY: unsafe needed to write the bits for pfd2
915 clkctl0
916 .syspll0pfd()
917 .modify(|_, w| w.pfd2_clkgate().gated().pfd2().bits(0x0));
918
919 // Set the new value and enable output.
920 // SAFETY: unsafe needed to write the bits for pfd2
921 clkctl0
922 .syspll0pfd()
923 .modify(|_, w| w.pfd2_clkgate().not_gated().pfd2().bits(config_bits));
924
925 // Wait for output becomes stable.
926 while clkctl0.syspll0pfd().read().pfd2_clkrdy().bit_is_clear() {}
927
928 // Clear ready status flag.
929 clkctl0.syspll0pfd().modify(|_, w| w.pfd2_clkrdy().clear_bit());
930 }
931 }
932 /// Enables default settings for pfd0
933 pub(self) fn init_syspll_pfd0(config_bits: u8) {
934 // SAFETY: unsafe needed to take pointer to Clkctl0 and write specific bits
935 // needed to change the output of pfd0
936 unsafe {
937 let clkctl0 = crate::pac::Clkctl0::steal();
938 // Disable the clock output first
939 clkctl0
940 .syspll0pfd()
941 .modify(|_, w| w.pfd0_clkgate().gated().pfd0().bits(0x0));
942
943 // Set the new value and enable output
944 clkctl0
945 .syspll0pfd()
946 .modify(|_, w| w.pfd0_clkgate().not_gated().pfd0().bits(config_bits));
947
948 // Wait for output becomes stable
949 while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {}
950
951 // Clear ready status flag
952 clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().clear_bit());
953 }
954 }
955}
956
957impl MainClkConfig {
958 fn init_main_clk() {
959 // SAFETY:: unsafe needed to take pointers to Clkctl0 and Clkctl1
960 // used to set the right HW frequency
961 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
962 let clkctl1 = unsafe { crate::pac::Clkctl1::steal() };
963
964 clkctl0.mainclkselb().write(|w| w.sel().main_pll_clk());
965
966 // Set PFC0DIV divider to value 2, Subtract 1 since 0-> 1, 1-> 2, etc...
967 clkctl0.pfcdiv(0).modify(|_, w| w.reset().set_bit());
968 // SAFETY: unsafe needed to write the bits for pfcdiv
969 clkctl0
970 .pfcdiv(0)
971 .write(|w| unsafe { w.div().bits(2 - 1).halt().clear_bit() });
972 while clkctl0.pfcdiv(0).read().reqflag().bit_is_set() {}
973
974 // Set FRGPLLCLKDIV divider to value 12, Subtract 1 since 0-> 1, 1-> 2, etc...
975 clkctl1.frgpllclkdiv().modify(|_, w| w.reset().set_bit());
976 // SAFETY: unsafe needed to write the bits for frgpllclkdiv
977 clkctl1
978 .frgpllclkdiv()
979 .write(|w| unsafe { w.div().bits(12 - 1).halt().clear_bit() });
980 while clkctl1.frgpllclkdiv().read().reqflag().bit_is_set() {}
981 }
982}
983impl MultiSourceClock for MainClkConfig {
984 fn get_clock_source_and_rate(&self, clock: &Clocks) -> Result<(Clocks, u32), ClockError> {
985 match clock {
986 Clocks::MainClk => {
987 let div: u32 = if self.src == MainClkSrc::FFROdiv4 { 4 } else { 1 };
988 let converted_clock = Clocks::from(self.src);
989 match ConfigurableClock::get_clock_rate(self) {
990 Ok(_rate) => {
991 // SAFETY: unsafe needed to take pointer to Clkctl0
992 // needed to calculate the clock rate from the bits written in the registers
993 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
994 if self.src == MainClkSrc::PllMain && clkctl0.syspll0ctl0().read().bypass().is_programmed_clk()
995 {
996 let mut temp;
997 temp = self.freq.load(Ordering::Relaxed)
998 * u32::from(clkctl0.syspll0ctl0().read().mult().bits());
999 temp = (u64::from(temp) * 18 / u64::from(clkctl0.syspll0pfd().read().pfd0().bits())) as u32;
1000 return Ok((converted_clock, temp));
1001 }
1002 Ok((converted_clock, self.freq.load(Ordering::Relaxed) / div))
1003 }
1004 Err(clk_err) => Err(clk_err),
1005 }
1006 }
1007 _ => Err(ClockError::ClockMismatch),
1008 }
1009 }
1010 fn set_clock_source_and_rate(
1011 &mut self,
1012 clock_src_config: &mut impl ConfigurableClock,
1013 clock_src: &Clocks,
1014 rate: u32,
1015 ) -> Result<(), ClockError> {
1016 if !clock_src_config.is_enabled() {
1017 return Err(ClockError::ClockNotEnabled);
1018 }
1019 if let Ok(c) = <Clocks as TryInto<MainClkSrc>>::try_into(*clock_src) {
1020 // SAFETY: unsafe needed to take pointer to Clkctl0
1021 // needed to change the clock source
1022 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
1023 match c {
1024 MainClkSrc::ClkIn => {
1025 self.src = MainClkSrc::ClkIn;
1026
1027 clkctl0.mainclksela().write(|w| w.sel().sysxtal_clk());
1028 clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk());
1029 Ok(())
1030 }
1031 // the following will yield the same result as if compared to FFROdiv4
1032 MainClkSrc::FFRO | MainClkSrc::FFROdiv4 => match rate {
1033 div4 if div4 == (FfroFreq::Ffro60m as u32) / 4 || div4 == (FfroFreq::Ffro48m as u32) / 4 => {
1034 self.src = MainClkSrc::FFROdiv4;
1035 self.freq.store(div4, Ordering::Relaxed);
1036
1037 clkctl0.mainclksela().write(|w| w.sel().ffro_div_4());
1038 clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk());
1039 Ok(())
1040 }
1041 div1 if div1 == FfroFreq::Ffro60m as u32 || div1 == FfroFreq::Ffro48m as u32 => {
1042 self.src = MainClkSrc::FFRO;
1043 self.freq.store(div1, Ordering::Relaxed);
1044
1045 clkctl0.mainclksela().write(|w| w.sel().ffro_clk());
1046 clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk());
1047 Ok(())
1048 }
1049 _ => Err(ClockError::InvalidFrequency),
1050 },
1051 MainClkSrc::Lposc => {
1052 if let Ok(r) = <u32 as TryInto<LposcFreq>>::try_into(rate) {
1053 match r {
1054 LposcFreq::Lp1m => {
1055 self.src = MainClkSrc::Lposc;
1056 self.freq.store(rate, Ordering::Relaxed);
1057
1058 clkctl0.mainclksela().write(|w| w.sel().lposc());
1059 clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk());
1060 Ok(())
1061 }
1062 LposcFreq::Lp32k => Err(ClockError::InvalidFrequency),
1063 }
1064 } else {
1065 Err(ClockError::InvalidFrequency)
1066 }
1067 }
1068 MainClkSrc::SFRO => {
1069 if rate == SFRO_FREQ {
1070 self.src = MainClkSrc::SFRO;
1071 self.freq.store(rate, Ordering::Relaxed);
1072 clkctl0.mainclkselb().write(|w| w.sel().sfro_clk());
1073 Ok(())
1074 } else {
1075 Err(ClockError::InvalidFrequency)
1076 }
1077 }
1078 MainClkSrc::PllMain => {
1079 let r = rate;
1080 // From Section 4.6.1.1 Pll Limitations of the RT6xx User manual
1081 let pll_max = 572_000_000;
1082 let pll_min = 80_000_000;
1083 if pll_min <= r && r <= pll_max {
1084 clkctl0.mainclkselb().write(|w| w.sel().main_pll_clk());
1085 self.src = MainClkSrc::PllMain;
1086 self.freq.store(r, Ordering::Relaxed);
1087 Ok(())
1088 } else {
1089 Err(ClockError::InvalidFrequency)
1090 }
1091 }
1092 MainClkSrc::RTC32k => {
1093 if rate == RtcFreq::SubSecond32kHz as u32 {
1094 self.src = MainClkSrc::RTC32k;
1095 self.freq.store(rate, Ordering::Relaxed);
1096 clkctl0.mainclkselb().write(|w| w.sel().rtc_32k_clk());
1097 Ok(())
1098 } else {
1099 Err(ClockError::InvalidFrequency)
1100 }
1101 }
1102 }
1103 } else {
1104 Err(ClockError::ClockNotSupported)
1105 }
1106 }
1107}
1108
1109impl ConfigurableClock for MainClkConfig {
1110 fn enable_and_reset(&self) -> Result<(), ClockError> {
1111 MainClkConfig::init_main_clk();
1112 Ok(())
1113 }
1114 fn disable(&self) -> Result<(), ClockError> {
1115 error!("Attempting to reset the main clock, should NOT happen during runtime");
1116 Err(ClockError::ClockNotSupported)
1117 }
1118 fn get_clock_rate(&self) -> Result<u32, ClockError> {
1119 let (_c, rate) = MainClkConfig::get_clock_source_and_rate(self, &Clocks::MainClk)?;
1120 Ok(rate)
1121 }
1122 fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> {
1123 error!("The multi-source set_clock_rate_and_source method should be used instead of set_clock_rate");
1124 Err(ClockError::ClockNotSupported)
1125 }
1126 fn is_enabled(&self) -> bool {
1127 self.state == State::Enabled
1128 }
1129}
1130
1131impl ConfigurableClock for ClkInConfig {
1132 fn enable_and_reset(&self) -> Result<(), ClockError> {
1133 // External Input, no hw writes needed
1134 Ok(())
1135 }
1136 fn disable(&self) -> Result<(), ClockError> {
1137 error!("Attempting to reset a clock input");
1138 Err(ClockError::ClockNotSupported)
1139 }
1140 fn get_clock_rate(&self) -> Result<u32, ClockError> {
1141 if self.freq.is_some() {
1142 Ok(self.freq.as_ref().unwrap().load(Ordering::Relaxed))
1143 } else {
1144 Err(ClockError::ClockNotEnabled)
1145 }
1146 }
1147 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
1148 trace!("Setting value of clk in config, this won't change the clock itself");
1149 self.freq.as_ref().unwrap().store(freq, Ordering::Relaxed);
1150 Ok(())
1151 }
1152 fn is_enabled(&self) -> bool {
1153 self.state == State::Enabled
1154 }
1155}
1156
1157impl RtcClkConfig {
1158 /// Register writes to initialize the RTC Clock
1159 fn init_rtc_clk() {
1160 // SAFETY: unsafe needed to take pointer to Clkctl0, Clkctl1, and RTC
1161 // needed to enable the RTC HW
1162 let cc0 = unsafe { pac::Clkctl0::steal() };
1163 let cc1 = unsafe { pac::Clkctl1::steal() };
1164 let r = unsafe { pac::Rtc::steal() };
1165 // Enable the RTC peripheral clock
1166 cc1.pscctl2_set().write(|w| w.rtc_lite_clk_set().set_clock());
1167 // Make sure the reset bit is cleared amd RTC OSC is powered up
1168 r.ctrl().modify(|_, w| w.swreset().not_in_reset().rtc_osc_pd().enable());
1169
1170 // set initial match value, note that with a 15 bit count-down timer this would
1171 // typically be 0x8000, but we are "doing some clever things" in time-driver.rs,
1172 // read more about it in the comments there
1173 // SAFETY: unsafe needed to write the bits
1174 r.wake().write(|w| unsafe { w.bits(0xA) });
1175
1176 // Enable 32K OSC
1177 cc0.osc32khzctl0().write(|w| w.ena32khz().enabled());
1178
1179 // enable rtc clk
1180 r.ctrl().modify(|_, w| w.rtc_en().enable());
1181 }
1182}
1183
1184impl ConfigurableClock for RtcClkConfig {
1185 fn enable_and_reset(&self) -> Result<(), ClockError> {
1186 // should only be called once if previously disabled
1187 RtcClkConfig::init_rtc_clk();
1188 Ok(())
1189 }
1190 fn disable(&self) -> Result<(), ClockError> {
1191 error!("Resetting the RTC clock, this should NOT happen during runtime");
1192 Err(ClockError::ClockNotSupported)
1193 }
1194 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
1195 if let Ok(r) = <u32 as TryInto<RtcFreq>>::try_into(freq) {
1196 // SAFETY: unsafe needed to take pointer to RTC
1197 // needed to enable the HW for the different RTC frequencies, powered down by default
1198 let rtc = unsafe { crate::pac::Rtc::steal() };
1199 match r {
1200 RtcFreq::Default1Hz => {
1201 if rtc.ctrl().read().rtc_en().is_enable() {
1202 trace!("Attempting to enable an already enabled clock, RTC 1Hz");
1203 } else {
1204 rtc.ctrl().modify(|_r, w| w.rtc_en().enable());
1205 }
1206 Ok(())
1207 }
1208 RtcFreq::HighResolution1khz => {
1209 if rtc.ctrl().read().rtc1khz_en().is_enable() {
1210 trace!("Attempting to enable an already enabled clock, RTC 1Hz");
1211 } else {
1212 rtc.ctrl().modify(|_r, w| w.rtc1khz_en().enable());
1213 }
1214 Ok(())
1215 }
1216 RtcFreq::SubSecond32kHz => {
1217 if rtc.ctrl().read().rtc_subsec_ena().is_enable() {
1218 trace!("Attempting to enable an already enabled clock, RTC 1Hz");
1219 } else {
1220 rtc.ctrl().modify(|_r, w| w.rtc_subsec_ena().enable());
1221 }
1222 Ok(())
1223 }
1224 }
1225 } else {
1226 Err(ClockError::InvalidFrequency)
1227 }
1228 }
1229 // unlike the others, since this provides multiple clocks, return the fastest one
1230 fn get_clock_rate(&self) -> Result<u32, ClockError> {
1231 if self.sub_second_state == State::Enabled {
1232 Ok(RtcFreq::SubSecond32kHz as u32)
1233 } else if self.wake_alarm_state == State::Enabled {
1234 Ok(RtcFreq::HighResolution1khz as u32)
1235 } else if self.state == State::Enabled {
1236 Ok(RtcFreq::Default1Hz as u32)
1237 } else {
1238 Err(ClockError::ClockNotEnabled)
1239 }
1240 }
1241 fn is_enabled(&self) -> bool {
1242 self.state == State::Enabled
1243 }
1244}
1245
1246impl SysClkConfig {
1247 /// Updates the system core clock frequency, SW concept used for systick
1248 fn update_sys_core_clock(&self) {
1249 trace!(
1250 "System core clock has been updated to {:?}, this involves no HW reg writes",
1251 self.sysclkfreq.load(Ordering::Relaxed)
1252 );
1253 }
1254}
1255
1256impl ConfigurableClock for SysOscConfig {
1257 fn enable_and_reset(&self) -> Result<(), ClockError> {
1258 if self.state == State::Enabled {
1259 trace!("SysOsc was already enabled");
1260 return Ok(());
1261 }
1262
1263 // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0, needed to modify clock HW
1264 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
1265 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
1266
1267 // Let CPU run on ffro for safe switching
1268 clkctl0.mainclksela().write(|w| w.sel().ffro_clk());
1269 clkctl0.mainclksela().write(|w| w.sel().ffro_div_4());
1270
1271 // Power on SYSXTAL
1272 sysctl0.pdruncfg0_clr().write(|w| w.sysxtal_pd().clr_pdruncfg0());
1273
1274 // Enable system OSC
1275 clkctl0
1276 .sysoscctl0()
1277 .write(|w| w.lp_enable().lp().bypass_enable().normal_mode());
1278
1279 delay_loop_clocks(260, SYS_OSC_DEFAULT_FREQ.into());
1280 Ok(())
1281 }
1282 fn disable(&self) -> Result<(), ClockError> {
1283 // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0, needed to modify clock HW
1284 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
1285 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
1286
1287 // Let CPU run on ffro for safe switching
1288 clkctl0.mainclksela().write(|w| w.sel().ffro_clk());
1289 clkctl0.mainclksela().write(|w| w.sel().ffro_div_4());
1290
1291 // Power on SYSXTAL
1292 sysctl0.pdruncfg0_set().write(|w| w.sysxtal_pd().set_pdruncfg0());
1293 Ok(())
1294 }
1295 fn get_clock_rate(&self) -> Result<u32, ClockError> {
1296 if self.state == State::Enabled {
1297 Ok(SYS_OSC_DEFAULT_FREQ)
1298 } else {
1299 Err(ClockError::ClockNotEnabled)
1300 }
1301 }
1302 fn is_enabled(&self) -> bool {
1303 self.state == State::Enabled
1304 }
1305 fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> {
1306 Err(ClockError::ClockNotSupported)
1307 }
1308}
1309
1310/// Method to delay for a certain number of microseconds given a clock rate
1311pub fn delay_loop_clocks(usec: u64, freq_mhz: u64) {
1312 let mut ticks = usec * freq_mhz / 1_000_000 / 4;
1313 if ticks > u64::from(u32::MAX) {
1314 ticks = u64::from(u32::MAX);
1315 }
1316 // won't panic since we check value above
1317 cortex_m::asm::delay(ticks as u32);
1318}
1319
1320/// Configure the pad voltage pmc registers for all 3 vddio ranges
1321fn set_pad_voltage_range() {
1322 // SAFETY: unsafe needed to take pointer to PNC as well as to write specific bits
1323 unsafe {
1324 let pmc = crate::pac::Pmc::steal();
1325 // Set up IO voltages
1326 // all 3 ranges need to be 1.71-1.98V which is 01
1327 pmc.padvrange().write(|w| {
1328 w.vddio_0range()
1329 .bits(0b01)
1330 .vddio_1range()
1331 .bits(0b01)
1332 .vddio_2range()
1333 .bits(0b01)
1334 });
1335 }
1336}
1337
1338/// Initialize AHB clock
1339fn init_syscpuahb_clk() {
1340 // SAFETY: unsafe needed to take pointer to Clkctl0
1341 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
1342 // SAFETY: unsafe needed to write the bits
1343 // Set syscpuahbclkdiv to value 2, Subtract 1 since 0-> 1, 1-> 2, etc...
1344 clkctl0.syscpuahbclkdiv().write(|w| unsafe { w.div().bits(2 - 1) });
1345
1346 while clkctl0.syscpuahbclkdiv().read().reqflag().bit_is_set() {}
1347}
1348
1349/// `ClockOut` config
1350pub struct ClockOutConfig {
1351 src: ClkOutSrc,
1352 div: u8,
1353}
1354
1355/// `ClockOut` sources
1356#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1357#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1358/// `ClockOut` sources
1359pub enum ClkOutSrc {
1360 /// No Source, reduce power consumption
1361 None,
1362 /// SFRO clock
1363 Sfro,
1364 /// External input clock
1365 ClkIn,
1366 /// Low-power oscillator
1367 Lposc,
1368 /// FFRO clock
1369 Ffro,
1370 /// Main clock
1371 MainClk,
1372 /// Main DSP clock
1373 DspMainClk,
1374 /// Main Pll clock
1375 MainPllClk,
1376 /// `SysPll` Aux0 clock
1377 Aux0PllClk,
1378 /// `SysPll` DSP clock
1379 DspPllClk,
1380 /// `SysPll` Aux1 clock
1381 Aux1PllClk,
1382 /// Audio Pll clock
1383 AudioPllClk,
1384 /// 32 `KHz` RTC
1385 RTC32k,
1386}
1387
1388/// Initialize the `ClkOutConfig`
1389impl ClockOutConfig {
1390 /// Default configuration for Clock out
1391 #[must_use]
1392 pub fn default_config() -> Self {
1393 Self {
1394 src: ClkOutSrc::None,
1395 div: 0,
1396 }
1397 }
1398
1399 /// Enable the Clock Out output
1400 pub fn enable_and_reset(&mut self) -> Result<(), ClockError> {
1401 self.set_clkout_source_and_div(self.src, self.div)?;
1402 Ok(())
1403 }
1404
1405 /// Disable Clock Out output and select None as the source to conserve power
1406 pub fn disable(&mut self) -> Result<(), ClockError> {
1407 self.set_clkout_source_and_div(ClkOutSrc::None, 0)?;
1408 Ok(())
1409 }
1410
1411 /// Set the source of the Clock Out pin
1412 fn set_clkout_source(&mut self, src: ClkOutSrc) -> Result<(), ClockError> {
1413 // SAFETY: unsafe needed to take pointers to Clkctl1, needed to set source in HW
1414 let cc1 = unsafe { pac::Clkctl1::steal() };
1415 match src {
1416 ClkOutSrc::None => {
1417 cc1.clkoutsel0().write(|w| w.sel().none());
1418 cc1.clkoutsel1().write(|w| w.sel().none());
1419 }
1420 ClkOutSrc::Sfro => {
1421 cc1.clkoutsel0().write(|w| w.sel().sfro_clk());
1422 cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output());
1423 }
1424 ClkOutSrc::ClkIn => {
1425 cc1.clkoutsel0().write(|w| w.sel().xtalin_clk());
1426 cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output());
1427 }
1428 ClkOutSrc::Lposc => {
1429 cc1.clkoutsel0().write(|w| w.sel().lposc());
1430 cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output());
1431 }
1432 ClkOutSrc::Ffro => {
1433 cc1.clkoutsel0().write(|w| w.sel().ffro_clk());
1434 cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output());
1435 }
1436 ClkOutSrc::MainClk => {
1437 cc1.clkoutsel0().write(|w| w.sel().main_clk());
1438 cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output());
1439 }
1440 ClkOutSrc::DspMainClk => {
1441 cc1.clkoutsel0().write(|w| w.sel().dsp_main_clk());
1442 cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output());
1443 }
1444 ClkOutSrc::MainPllClk => {
1445 cc1.clkoutsel0().write(|w| w.sel().none());
1446 cc1.clkoutsel1().write(|w| w.sel().main_pll_clk());
1447 }
1448 ClkOutSrc::Aux0PllClk => {
1449 cc1.clkoutsel0().write(|w| w.sel().none());
1450 cc1.clkoutsel1().write(|w| w.sel().syspll0_aux0_pll_clk());
1451 }
1452 ClkOutSrc::DspPllClk => {
1453 cc1.clkoutsel0().write(|w| w.sel().none());
1454 cc1.clkoutsel1().write(|w| w.sel().dsp_pll_clk());
1455 }
1456 ClkOutSrc::AudioPllClk => {
1457 cc1.clkoutsel0().write(|w| w.sel().none());
1458 cc1.clkoutsel1().write(|w| w.sel().audio_pll_clk());
1459 }
1460 ClkOutSrc::Aux1PllClk => {
1461 cc1.clkoutsel0().write(|w| w.sel().none());
1462 cc1.clkoutsel1().write(|w| w.sel().syspll0_aux1_pll_clk());
1463 }
1464 ClkOutSrc::RTC32k => {
1465 cc1.clkoutsel0().write(|w| w.sel().none());
1466 cc1.clkoutsel1().write(|w| w.sel().rtc_clk_32khz());
1467 }
1468 }
1469 self.src = src;
1470 Ok(())
1471 }
1472 /// set the clock out divider
1473 /// note that 1 will be added to div when mapping to the divider
1474 /// so bits(0) -> divide by 1
1475 /// ...
1476 /// bits(255)-> divide by 256
1477 pub fn set_clkout_divider(&self, div: u8) -> Result<(), ClockError> {
1478 // don't wait for clock to be ready if there's no source
1479 if self.src != ClkOutSrc::None {
1480 let cc1 = unsafe { pac::Clkctl1::steal() };
1481
1482 cc1.clkoutdiv()
1483 .modify(|_, w| unsafe { w.div().bits(div).halt().clear_bit() });
1484 while cc1.clkoutdiv().read().reqflag().bit_is_set() {}
1485 }
1486 Ok(())
1487 }
1488 /// set the source and divider for the clockout pin
1489 pub fn set_clkout_source_and_div(&mut self, src: ClkOutSrc, div: u8) -> Result<(), ClockError> {
1490 self.set_clkout_source(src)?;
1491
1492 self.set_clkout_divider(div)?;
1493
1494 Ok(())
1495 }
1496}
1497
1498/// Using the config, enables all desired clocks to desired clock rates
1499fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> {
1500 if let Err(e) = config.rtc.enable_and_reset() {
1501 error!("couldn't Power on OSC for RTC, result: {:?}", e);
1502 return Err(e);
1503 }
1504
1505 if let Err(e) = config.lposc.enable_and_reset() {
1506 error!("couldn't Power on LPOSC, result: {:?}", e);
1507 return Err(e);
1508 }
1509
1510 if let Err(e) = config.ffro.enable_and_reset() {
1511 error!("couldn't Power on FFRO, result: {:?}", e);
1512 return Err(e);
1513 }
1514
1515 if let Err(e) = config.sfro.enable_and_reset() {
1516 error!("couldn't Power on SFRO, result: {:?}", e);
1517 return Err(e);
1518 }
1519
1520 if let Err(e) = config.sys_osc.enable_and_reset() {
1521 error!("Couldn't enable sys oscillator {:?}", e);
1522 return Err(e);
1523 }
1524
1525 if let Err(e) = config.main_pll_clk.enable_and_reset() {
1526 error!("Couldn't enable main pll clock {:?}", e);
1527 return Err(e);
1528 }
1529
1530 // Move FLEXSPI clock source from main clock to FFRO to avoid instruction/data fetch issue in XIP when
1531 // updating PLL and main clock.
1532 // SAFETY: unsafe needed to take pointers to Clkctl0
1533 let cc0 = unsafe { pac::Clkctl0::steal() };
1534 cc0.flexspifclksel().write(|w| w.sel().ffro_clk());
1535
1536 // Move ESPI clock source to FFRO
1537 #[cfg(feature = "_espi")]
1538 {
1539 cc0.espiclksel().write(|w| w.sel().use_48_60m());
1540 }
1541
1542 init_syscpuahb_clk();
1543
1544 if let Err(e) = config.main_clk.enable_and_reset() {
1545 error!("Couldn't enable main clock {:?}", e);
1546 return Err(e);
1547 }
1548
1549 config.sys_clk.update_sys_core_clock();
1550 Ok(())
1551}
1552
1553/// SAFETY: must be called exactly once at bootup
1554pub(crate) unsafe fn init(config: ClockConfig) -> Result<(), ClockError> {
1555 init_clock_hw(config)?;
1556
1557 // set VDDIO ranges 0-2
1558 set_pad_voltage_range();
1559 Ok(())
1560}
1561
1562///Trait to expose perph clocks
1563trait SealedSysconPeripheral {
1564 fn enable_and_reset_perph_clock();
1565 fn disable_perph_clock();
1566}
1567
1568/// Clock and Reset control for peripherals
1569#[allow(private_bounds)]
1570pub trait SysconPeripheral: SealedSysconPeripheral + 'static {}
1571/// Enables and resets peripheral `T`.
1572///
1573/// # Safety
1574///
1575/// Peripheral must not be in use.
1576pub fn enable_and_reset<T: SysconPeripheral>() {
1577 T::enable_and_reset_perph_clock();
1578}
1579
1580/// Disables peripheral `T`.
1581///
1582/// # Safety
1583///
1584/// Peripheral must not be in use.
1585pub fn disable<T: SysconPeripheral>() {
1586 T::disable_perph_clock();
1587}
1588macro_rules! impl_perph_clk {
1589 ($peripheral:ident, $clkctl:ident, $clkreg:ident, $rstctl:ident, $rstreg:ident, $bit:expr) => {
1590 impl SealedSysconPeripheral for crate::peripherals::$peripheral {
1591 fn enable_and_reset_perph_clock() {
1592 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1
1593 let cc1 = unsafe { pac::$clkctl::steal() };
1594 let rc1 = unsafe { pac::$rstctl::steal() };
1595
1596 paste! {
1597 // SAFETY: unsafe due to the use of bits()
1598 cc1.[<$clkreg _set>]().write(|w| unsafe { w.bits(1 << $bit) });
1599
1600 // SAFETY: unsafe due to the use of bits()
1601 rc1.[<$rstreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) });
1602 }
1603 }
1604
1605 fn disable_perph_clock() {
1606 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1
1607 let cc1 = unsafe { pac::$clkctl::steal() };
1608 let rc1 = unsafe { pac::$rstctl::steal() };
1609
1610 paste! {
1611 // SAFETY: unsafe due to the use of bits()
1612 rc1.[<$rstreg _set>]().write(|w| unsafe { w.bits(1 << $bit) });
1613
1614 // SAFETY: unsafe due to the use of bits()
1615 cc1.[<$clkreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) });
1616 }
1617 }
1618 }
1619
1620 impl SysconPeripheral for crate::peripherals::$peripheral {}
1621 };
1622}
1623
1624// These should enabled once the relevant peripherals are implemented.
1625// impl_perph_clk!(GPIOINTCTL, Clkctl1, pscctl2, Rstctl1, prstctl2, 30);
1626// impl_perph_clk!(OTP, Clkctl0, pscctl0, Rstctl0, prstctl0, 17);
1627
1628// impl_perph_clk!(ROM_CTL_128KB, Clkctl0, pscctl0, Rstctl0, prstctl0, 2);
1629// impl_perph_clk!(USBHS_SRAM, Clkctl0, pscctl0, Rstctl0, prstctl0, 23);
1630
1631impl_perph_clk!(PIMCTL, Clkctl1, pscctl2, Rstctl1, prstctl2, 31);
1632impl_perph_clk!(ACMP, Clkctl0, pscctl1, Rstctl0, prstctl1, 15);
1633impl_perph_clk!(ADC0, Clkctl0, pscctl1, Rstctl0, prstctl1, 16);
1634impl_perph_clk!(CASPER, Clkctl0, pscctl0, Rstctl0, prstctl0, 9);
1635impl_perph_clk!(CRC, Clkctl1, pscctl1, Rstctl1, prstctl1, 16);
1636impl_perph_clk!(CTIMER0_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 0);
1637impl_perph_clk!(CTIMER1_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 1);
1638impl_perph_clk!(CTIMER2_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 2);
1639impl_perph_clk!(CTIMER3_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 3);
1640impl_perph_clk!(CTIMER4_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 4);
1641impl_perph_clk!(DMA0, Clkctl1, pscctl1, Rstctl1, prstctl1, 23);
1642impl_perph_clk!(DMA1, Clkctl1, pscctl1, Rstctl1, prstctl1, 24);
1643impl_perph_clk!(DMIC0, Clkctl1, pscctl0, Rstctl1, prstctl0, 24);
1644
1645#[cfg(feature = "_espi")]
1646impl_perph_clk!(ESPI, Clkctl0, pscctl1, Rstctl0, prstctl1, 7);
1647
1648impl_perph_clk!(FLEXCOMM0, Clkctl1, pscctl0, Rstctl1, prstctl0, 8);
1649impl_perph_clk!(FLEXCOMM1, Clkctl1, pscctl0, Rstctl1, prstctl0, 9);
1650impl_perph_clk!(FLEXCOMM14, Clkctl1, pscctl0, Rstctl1, prstctl0, 22);
1651impl_perph_clk!(FLEXCOMM15, Clkctl1, pscctl0, Rstctl1, prstctl0, 23);
1652impl_perph_clk!(FLEXCOMM2, Clkctl1, pscctl0, Rstctl1, prstctl0, 10);
1653impl_perph_clk!(FLEXCOMM3, Clkctl1, pscctl0, Rstctl1, prstctl0, 11);
1654impl_perph_clk!(FLEXCOMM4, Clkctl1, pscctl0, Rstctl1, prstctl0, 12);
1655impl_perph_clk!(FLEXCOMM5, Clkctl1, pscctl0, Rstctl1, prstctl0, 13);
1656impl_perph_clk!(FLEXCOMM6, Clkctl1, pscctl0, Rstctl1, prstctl0, 14);
1657impl_perph_clk!(FLEXCOMM7, Clkctl1, pscctl0, Rstctl1, prstctl0, 15);
1658impl_perph_clk!(FLEXSPI, Clkctl0, pscctl0, Rstctl0, prstctl0, 16);
1659impl_perph_clk!(FREQME, Clkctl1, pscctl1, Rstctl1, prstctl1, 31);
1660impl_perph_clk!(HASHCRYPT, Clkctl0, pscctl0, Rstctl0, prstctl0, 10);
1661impl_perph_clk!(HSGPIO0, Clkctl1, pscctl1, Rstctl1, prstctl1, 0);
1662impl_perph_clk!(HSGPIO1, Clkctl1, pscctl1, Rstctl1, prstctl1, 1);
1663impl_perph_clk!(HSGPIO2, Clkctl1, pscctl1, Rstctl1, prstctl1, 2);
1664impl_perph_clk!(HSGPIO3, Clkctl1, pscctl1, Rstctl1, prstctl1, 3);
1665impl_perph_clk!(HSGPIO4, Clkctl1, pscctl1, Rstctl1, prstctl1, 4);
1666impl_perph_clk!(HSGPIO5, Clkctl1, pscctl1, Rstctl1, prstctl1, 5);
1667impl_perph_clk!(HSGPIO6, Clkctl1, pscctl1, Rstctl1, prstctl1, 6);
1668impl_perph_clk!(HSGPIO7, Clkctl1, pscctl1, Rstctl1, prstctl1, 7);
1669impl_perph_clk!(I3C0, Clkctl1, pscctl2, Rstctl1, prstctl2, 16);
1670impl_perph_clk!(MRT0, Clkctl1, pscctl2, Rstctl1, prstctl2, 8);
1671impl_perph_clk!(MU_A, Clkctl1, pscctl1, Rstctl1, prstctl1, 28);
1672impl_perph_clk!(OS_EVENT, Clkctl1, pscctl0, Rstctl1, prstctl0, 27);
1673impl_perph_clk!(POWERQUAD, Clkctl0, pscctl0, Rstctl0, prstctl0, 8);
1674impl_perph_clk!(PUF, Clkctl0, pscctl0, Rstctl0, prstctl0, 11);
1675impl_perph_clk!(RNG, Clkctl0, pscctl0, Rstctl0, prstctl0, 12);
1676impl_perph_clk!(RTC, Clkctl1, pscctl2, Rstctl1, prstctl2, 7);
1677impl_perph_clk!(SCT0, Clkctl0, pscctl0, Rstctl0, prstctl0, 24);
1678impl_perph_clk!(SECGPIO, Clkctl0, pscctl1, Rstctl0, prstctl1, 24);
1679impl_perph_clk!(SEMA42, Clkctl1, pscctl1, Rstctl1, prstctl1, 29);
1680impl_perph_clk!(USBHSD, Clkctl0, pscctl0, Rstctl0, prstctl0, 21);
1681impl_perph_clk!(USBHSH, Clkctl0, pscctl0, Rstctl0, prstctl0, 22);
1682impl_perph_clk!(USBPHY, Clkctl0, pscctl0, Rstctl0, prstctl0, 20);
1683impl_perph_clk!(USDHC0, Clkctl0, pscctl1, Rstctl0, prstctl1, 2);
1684impl_perph_clk!(USDHC1, Clkctl0, pscctl1, Rstctl0, prstctl1, 3);
1685impl_perph_clk!(UTICK0, Clkctl0, pscctl2, Rstctl0, prstctl2, 0);
1686impl_perph_clk!(WDT0, Clkctl0, pscctl2, Rstctl0, prstctl2, 1);
1687impl_perph_clk!(WDT1, Clkctl1, pscctl2, Rstctl1, prstctl2, 10);