sam4l/
pm.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Implementation of the power manager (PM) peripheral.
6
7use crate::bpm;
8use crate::bscif;
9use crate::flashcalw;
10use crate::gpio;
11use crate::scif;
12use core::cell::Cell;
13use core::sync::atomic::Ordering;
14use kernel::platform::chip::ClockInterface;
15use kernel::utilities::registers::interfaces::{Readable, Writeable};
16use kernel::utilities::registers::{
17    register_bitfields, FieldValue, ReadOnly, ReadWrite, WriteOnly,
18};
19use kernel::utilities::StaticRef;
20
21/// §10.7 PM::UserInterface from SAM4L Datasheet.
22#[repr(C)]
23struct PmRegisters {
24    mcctrl: ReadWrite<u32, MainClockControl::Register>,
25    cpusel: ReadWrite<u32, CpuClockSelect::Register>,
26    _reserved1: u32,
27    pbasel: ReadWrite<u32, PeripheralBusXClockSelect::Register>,
28    pbbsel: ReadWrite<u32, PeripheralBusXClockSelect::Register>,
29    pbcsel: ReadWrite<u32, PeripheralBusXClockSelect::Register>,
30    pbdsel: ReadWrite<u32, PeripheralBusXClockSelect::Register>,
31    _reserved2: u32,
32    cpumask: ReadWrite<u32, ClockMaskCpu::Register>, // 0x020
33    hsbmask: ReadWrite<u32, ClockMaskHsb::Register>,
34    pbamask: ReadWrite<u32, ClockMaskPba::Register>,
35    pbbmask: ReadWrite<u32, ClockMaskPbb::Register>,
36    pbcmask: ReadWrite<u32, ClockMaskPbc::Register>,
37    pbdmask: ReadWrite<u32, ClockMaskPbd::Register>,
38    _reserved3: [u32; 2],
39    pbadivmask: ReadWrite<u32, DividedClockMask::Register>, // 0x040
40    _reserved4: [u32; 4],
41    cfdctrl: ReadWrite<u32, ClockFailureDetectorControl::Register>,
42    unlock: WriteOnly<u32, PmUnlock::Register>,
43    _reserved5: [u32; 25],                            // 0x60
44    ier: WriteOnly<u32, InterruptOrStatus::Register>, // 0xC0
45    idr: WriteOnly<u32, InterruptOrStatus::Register>,
46    imr: ReadOnly<u32, InterruptOrStatus::Register>,
47    isr: ReadOnly<u32, InterruptOrStatus::Register>,
48    icr: WriteOnly<u32, InterruptOrStatus::Register>,
49    sr: ReadOnly<u32, InterruptOrStatus::Register>,
50    _reserved6: [u32; 34],                                  // 0x100
51    ppcr: ReadWrite<u32, PeripheralPowerControl::Register>, // 0x160
52    _reserved7: [u32; 7],
53    rcause: ReadOnly<u32, ResetCause::Register>, // 0x180
54    wcause: ReadOnly<u32, WakeCause::Register>,
55    awen: ReadWrite<u32, AsynchronousWakeUpEnable::Register>,
56    _protctrl: u32, // This register is named, but undocumented in the datasheet
57    _reserved8: u32,
58    fastsleep: ReadWrite<u32, FastSleep::Register>,
59    _reserved9: [u32; 152],
60    config: ReadOnly<u32, Configuration::Register>, // 0x200
61    version: ReadOnly<u32, Version::Register>,
62}
63
64register_bitfields![u32,
65    MainClockControl [
66        /// Main Clock Selection:
67        ///
68        /// 0: RCSYS
69        /// 1: OSC0
70        /// 2: PLL
71        /// 3: DFLL
72        /// 4: RC80M (requires dividing down before use!)
73        /// 5: RCFAST
74        /// 6: RC1M
75        /// 7: Reserved
76        MCSEL OFFSET(0) NUMBITS(3) []
77    ],
78
79    /// Note: Writing this register clears SR.CKRDY. Must not write again until SR.CKRDY high.
80    CpuClockSelect [
81        /// CPU Division: Set to 1 to divide main clock by 2^(CPUSEL+1).
82        CPUDIV OFFSET(7) NUMBITS(1) [],
83
84        /// Exponent for CPU clock divider. Must be 0 if CPUDIV is 0.
85        CPUSEL OFFSET(0) NUMBITS(3) []
86    ],
87
88    /// Note: Writing this register clears SR.CKRDY. Must not write again until SR.CKRDY high.
89    PeripheralBusXClockSelect [
90        /// APBx Divisor: Set to 1 to divide APBx clock by 2^(PBSEL+1).
91        PBDIV OFFSET(7) NUMBITS(1) [],
92
93        /// Exponent for APBx clock divider. Must be 0 if PBDIV is 0.
94        PBSEL OFFSET(0) NUMBITS(3) []
95    ],
96
97    /// If bit n is cleared, the clock for module n is stopped. If bit n is set
98    /// the clock for module n is enabled according to the current / power mode.
99    ///
100    /// Reset Default: 0x1, OCD enabled.
101    ClockMaskCpu [
102        OCD 0
103    ],
104
105    /// If bit n is cleared, the clock for module n is stopped. If bit n is set
106    /// the clock for module n is enabled according to the current / power mode.
107    ///
108    /// Reset Default: 0x1e2, FLASHCALW, APB[A-D] bridge enabled.
109    ClockMaskHsb [
110        PDCA 0,
111        FLASHCALW 1,
112        FLASHCALW_PICOCACHE 2,
113        USBC 3,
114        CRCCU 4,
115        APBA_BRIDGE 5,
116        APBB_BRIDGE 6,
117        APBC_BRIDGE 7,
118        APBD_BRIDGE 8,
119        AESA 9
120    ],
121
122    /// If bit n is cleared, the clock for module n is stopped. If bit n is set
123    /// the clock for module n is enabled according to the current / power mode.
124    ///
125    /// Reset Default: 0x0, all disabled.
126    ClockMaskPba [
127        IISC 0,
128        SPI 1,
129        TC0 2,
130        TC1 3,
131        TWIM0 4,
132        TWIS0 5,
133        TWIM1 6,
134        TWIS1 7,
135        USART0 8,
136        USART1 9,
137        USART2 10,
138        USART3 11,
139        ADCIFE 12,
140        DACC 13,
141        ACIFC 14,
142        GLOC 15,
143        ABDACB 16,
144        TRNG 17,
145        PARC 18,
146        CATB 19,
147        TWIM2 21,
148        TWIM3 22,
149        LCDCA 23
150    ],
151
152    /// If bit n is cleared, the clock for module n is stopped. If bit n is set
153    /// the clock for module n is enabled according to the current / power mode.
154    ///
155    /// Reset Default: 0x1, FLASHCALW enabled.
156    ClockMaskPbb [
157        FLASHCALW 0,
158        HRAMC1 1,
159        HMATRIX 2,
160        PDCA 3,
161        CRCCU 4,
162        USBC 5,
163        PEVC 6
164    ],
165
166    /// If bit n is cleared, the clock for module n is stopped. If bit n is set
167    /// the clock for module n is enabled according to the current / power mode.
168    ///
169    /// Reset Default: 0x1f, PM, CHIPID, SCIF, FREQM, and GPIO enabled.
170    ClockMaskPbc [
171        PM 0,
172        CHIPID 1,
173        SCIF 2,
174        FREQM 3,
175        GPIO 4
176    ],
177
178    /// If bit n is cleared, the clock for module n is stopped. If bit n is set
179    /// the clock for module n is enabled according to the current / power mode.
180    ///
181    /// Reset Default: 0x3f, BPM, BSCIF, AST, WDT, EIC, PICOUART enabled.
182    ClockMaskPbd [
183        BPM 0,
184        BSCIF 1,
185        AST 2,
186        WDT 3,
187        EIC 4,
188        PICOUART 5
189    ],
190
191    /// If bit n is written to zero, the clock divided by 2^(n+1) is stopped.
192    /// If bit n is written to one, the clock divided by 2^(n+1) is enabled
193    /// according to the current power mode.
194    ///
195    /// Reset Default: 0x7f, all enabled.
196    DividedClockMask [
197        MASK OFFSET(0) NUMBITS(7) [
198            /// TC0 and TC1
199            TIMER_CLOCK2 = 1 << 0,
200
201            /// TC0 and TC1, and USART0-3
202            TIMER_CLOCK3 = 1 << 2,
203
204            /// TC0 and TC1
205            TIMER_CLOCK4 = 1 << 4,
206
207            /// TC0 and TC1
208            TIMER_CLOCK5 = 1 << 6
209        ]
210    ],
211
212    ClockFailureDetectorControl [
213        /// Store final value. If set to 1, register becomes read-only.
214        SFV 31,
215
216        /// Clock failure detector enable
217        CFDEN 0
218    ],
219
220    PmUnlock [
221        /// Write 0xAA to enable unlock
222        KEY OFFSET(24) NUMBITS(8) [],
223
224        /// Register address to unlock. Next APB access must write register specified here.
225        ADDR OFFSET(0) NUMBITS(10) []
226    ],
227
228    InterruptOrStatus [
229        /// Access Error: (1) Write to a protect register without an unlock
230        AE 31,
231
232        /// Wakeup Event Occurred: (1) Check WCAUSE register for wakeup source
233        WAKE 8,
234
235        /// Clock Ready: Synchronous clocks (0) written but not settled, (1) are ready
236        CKRDY 5,
237
238        /// Clock Failure Detected: (0) running correctly, (1) failure detected, reverting to RCSYS
239        CFD 0
240    ],
241
242    /// Reset Value: 0x1fe
243    PeripheralPowerControl [
244        /// On powerup, (0) flash waits for BOD18 to be ready, (1) does not wait
245        FWBOD18 10,
246
247        /// When waking up, (0) flash waits for bandgap to be ready, (1) does not wait
248        FWBGREF 9,
249
250        /// VREG Request Clock Mask, (0) disabled, (1) enabled
251        VREGRCMASK 8,
252
253        /// ADCIFE Request Clock Mask, (0) disabled, (1) enabled
254        ADCIFERCMASK 7,
255
256        /// PEVC Request Clock Mask, (0) disabled, (1) enabled
257        PEVCRCMASK 6,
258
259        /// TWIS1 Request Clock Mask, (0) disabled, (1) enabled
260        TWIS1RCMASK 5,
261
262        /// TWIS0 Request Clock Mask, (0) disabled, (1) enabled
263        TWIS0RCMASK 4,
264
265        /// AST Request Clock Mask, (0) disabled, (1) enabled
266        ASTRCMASK 3,
267
268        /// ACIFC Request Clock Mask, (0) disabled, (1) enabled
269        ACIFCRCMASK 2,
270
271        /// CAT Request Clock Mask, (0) disabled, (1) enabled
272        CATBRCMASK 1,
273
274        /// Reset Pullup, pullup on external reset pin is (0) disabled, (1) enabled
275        RSTPUN 0
276    ],
277
278    ResetCause [
279        /// Brown-out 3.3V reset (supply voltage too low)
280        BOD33 13,
281
282        /// Power-on reset (I/O voltage too low)
283        POR33 10,
284
285        /// OCD Reset (the SYSRESETREQ bit in AIRCR of the CPU was written to 1)
286        OCDRST 8,
287
288        /// Backup reset
289        BKUP 6,
290
291        /// Watchdog reset
292        WDT 3,
293
294        /// External reset pin (RESET_N was pulled low)
295        EXT 2,
296
297        /// Brown-out reset (core voltage below brown-out threshold)
298        BOD 1,
299
300        /// Power-on reset (core voltage below power-on threshold)
301        POR 0
302    ],
303
304    WakeCause [
305        AST 17,
306        EIC 16,
307        LCDCA 7,
308        PICOUART 6,
309        BOD33_IRQ 5,
310        BOD18_IRQ 4,
311        PSOK 3,
312        USBC 2,
313        TWIS1 1,
314        TWIS0 0
315    ],
316
317    /// For each bit, if set, the wakeup is enabled
318    AsynchronousWakeUpEnable [
319        LCDCA 7,
320        PICOUART 6,
321        BOD33_IRQ 5,
322        BOD18_IRQ 4,
323        PSOK 3,
324        USBC 2,
325        TWIS1 1,
326        TWIS0 0
327    ],
328
329    /// Each bit in this register corresponds to a clock source set as the main
330    /// clock just before entering power save mode and just after wake-up to
331    /// make the wakeup time faster.
332    ///
333    /// 0: The corresponding clock source is not set as the main clock after wake-up.
334    /// 1: The corresponding clock source is set as the main clock after wake-up.
335    FastSleep [
336        DFLL 24,
337        RC1M 18,
338        RCFAST 17,
339        RC80 16,
340        PLL 8,
341        OSC 0
342    ],
343
344    Configuration [
345        /// HSB PEVC clock implemented
346        HSBPEVC 7,
347
348        /// APBD implemented
349        PBD 3,
350
351        /// APBC implemented
352        PBC 2,
353
354        /// APBB implemented
355        PBB 1,
356
357        /// APBA implemented
358        PBA 0
359    ],
360
361    Version [
362        /// Reserved. No functionality associated.
363        VARIANT OFFSET(16) NUMBITS(4) [],
364
365        VERSION OFFSET(0) NUMBITS(12) []
366    ]
367];
368
369pub enum MainClock {
370    RCSYS,
371    OSC0,
372    PLL,
373    DFLL,
374    RC80M,
375    RCFAST,
376    RC1M,
377}
378
379#[derive(Copy, Clone, Debug)]
380pub enum Clock {
381    HSB(HSBClock),
382    PBA(PBAClock),
383    PBB(PBBClock),
384    PBC(PBCClock),
385    PBD(PBDClock),
386}
387
388#[derive(Copy, Clone, Debug)]
389pub enum HSBClock {
390    PDCA,
391    FLASHCALW,
392    FLASHCALWP,
393    USBC,
394    CRCCU,
395    APBA,
396    APBB,
397    APBC,
398    APBD,
399    AESA,
400}
401
402#[derive(Copy, Clone, Debug)]
403pub enum PBAClock {
404    IISC,
405    SPI,
406    TC0,
407    TC1,
408    TWIM0,
409    TWIS0,
410    TWIM1,
411    TWIS1,
412    USART0,
413    USART1,
414    USART2,
415    USART3,
416    ADCIFE,
417    DACC,
418    ACIFC,
419    GLOC,
420    ABSACB,
421    TRNG,
422    PARC,
423    CATB,
424    NULL,
425    TWIM2,
426    TWIM3,
427    LCDCA,
428}
429
430#[derive(Copy, Clone, Debug)]
431pub enum PBBClock {
432    FLASHCALW,
433    HRAMC1,
434    HMATRIX,
435    PDCA,
436    CRCCU,
437    USBC,
438    PEVC,
439}
440
441#[derive(Copy, Clone, Debug)]
442pub enum PBCClock {
443    PM,
444    CHIPID,
445    SCIF,
446    FREQM,
447    GPIO,
448}
449
450#[derive(Copy, Clone, Debug)]
451pub enum PBDClock {
452    BPM,
453    BSCIF,
454    AST,
455    WDT,
456    EIC,
457    PICOUART,
458}
459
460/// Frequency of the external oscillator.
461///
462/// For the SAM4L, different configurations are needed for different
463/// ranges of oscillator frequency, so based on the input frequency,
464/// various configurations may need to change.  When additional
465/// oscillator frequencies are needed, they should be added here and
466/// the `setup_system_clock` function should be modified to support
467/// it.
468#[derive(Copy, Clone, Debug, PartialEq)]
469pub enum OscillatorFrequency {
470    /// 16 MHz external oscillator
471    Frequency16MHz,
472}
473
474#[derive(Copy, Clone, Debug, PartialEq)]
475pub enum RcfastFrequency {
476    Frequency4MHz,
477    Frequency8MHz,
478    Frequency12MHz,
479}
480
481/// Configuration for the startup time of the external oscillator.
482///
483/// In practice we have found that some boards work with a short
484/// startup time, while others need a slow start in order to properly
485/// wake from sleep. In general, we find that for systems that do not
486/// work, at fast speed, they will hang or panic after several entries
487/// into WAIT mode.
488#[derive(Copy, Clone, Debug, PartialEq)]
489pub enum OscillatorStartup {
490    /// Use a fast startup. ~0.5 ms in practice.
491    FastStart,
492
493    /// Use a slow startup. ~8.9 ms in practice.
494    SlowStart,
495}
496
497/// Which source the system clock should be generated from.
498///
499/// These are specified as system clock source appended with the clock
500/// that it is sourced from appended with the final frequency of the
501/// system. So for example, one option is to use the DFLL sourced from
502/// the RC32K with a final frequency of 48 MHz.
503///
504/// When new options (either sources or final frequencies) are needed, they
505/// should be added to this list, and then the `setup_system_clock` function
506/// can be modified to support it. This is necessary because configurations
507/// must be changed not just with the input source but also based on the
508/// desired final frequency.
509///
510/// For options utilizing an external oscillator, the configurations for that
511/// oscillator must also be provided.
512#[derive(Copy, Clone, Debug, PartialEq)]
513pub enum SystemClockSource {
514    /// Use the RCSYS clock (which the system starts up on anyways). Final
515    /// system frequency will be 115 kHz. Note that while this is the default,
516    /// Tock is NOT guaranteed to work on this setting and will likely fail.
517    RcsysAt115kHz,
518
519    RC1M,
520
521    RCFAST {
522        frequency: RcfastFrequency,
523    },
524
525    /// Use an external crystal oscillator as the direct source for the
526    /// system clock. The final system frequency will match the frequency of
527    /// the external oscillator.
528    ExternalOscillator {
529        frequency: OscillatorFrequency,
530        startup_mode: OscillatorStartup,
531    },
532
533    /// Use an external crystal oscillator as the input to the internal phase
534    /// locked loop (PLL) for the system clock. This results in a final
535    /// frequency of 48 MHz.
536    PllExternalOscillatorAt48MHz {
537        frequency: OscillatorFrequency,
538        startup_mode: OscillatorStartup,
539    },
540
541    /// Use the internal digital frequency locked loop (DFLL) sourced from
542    /// the internal RC32K clock. Note this typically requires calibration
543    /// of the RC32K to have a consistent clock. Final frequency of 48 MHz.
544    DfllRc32kAt48MHz,
545
546    RC80M,
547}
548
549pub enum ClockMask {
550    RCSYS = 0x01,
551    RC1M = 0x02,
552    RCFAST = 0x04,
553    OSC0 = 0x08,
554    DFLL = 0x10,
555    PLL = 0x20,
556    RC80M = 0x40,
557}
558
559const HSB_MASK_OFFSET: u32 = 0x24;
560const PBA_MASK_OFFSET: u32 = 0x28;
561const PBB_MASK_OFFSET: u32 = 0x2C;
562const PBC_MASK_OFFSET: u32 = 0x30;
563const PBD_MASK_OFFSET: u32 = 0x34;
564
565const PM_BASE: usize = 0x400E0000;
566const PM_REGS: StaticRef<PmRegisters> = unsafe { StaticRef::new(PM_BASE as *const PmRegisters) };
567
568/// Contains state for the power management peripheral. This includes the
569/// configurations for various system clocks and the final frequency that the
570/// system is running at.
571pub struct PowerManager {
572    /// Clock source configuration
573    system_clock_source: Cell<SystemClockSource>,
574
575    /// Mask of clocks that are on
576    system_on_clocks: Cell<u32>,
577
578    /// Has setup_system_clock been called once
579    system_initial_configs: Cell<bool>,
580}
581
582impl PowerManager {
583    pub const fn new() -> Self {
584        Self {
585            // Set to the RCSYS by default.
586            system_clock_source: Cell::new(SystemClockSource::RcsysAt115kHz),
587
588            system_on_clocks: Cell::new(ClockMask::RCSYS as u32),
589
590            system_initial_configs: Cell::new(false),
591        }
592    }
593}
594
595impl PowerManager {
596    /// Sets up the system clock. This should be called as one of the first
597    /// lines in the `main()` function within the platform's `main.rs`.
598    pub unsafe fn setup_system_clock(
599        &self,
600        clock_source: SystemClockSource,
601        flash_controller: &flashcalw::FLASHCALW,
602    ) {
603        if !self.system_initial_configs.get() {
604            // For now, always go to PS2 as it enables all core speeds
605            // These features are not available in PS1: USB, DFLL, Flash programming/erasing
606            bpm::set_power_scaling(bpm::PowerScaling::PS2);
607
608            // Need the 32k RC oscillator for BPM, AST, and DFLL
609            bscif::enable_rc32k();
610
611            // Enable HCACHE
612            flash_controller.enable_cache();
613
614            // Enable flash high speed mode, only for PS2
615            flash_controller.enable_high_speed_flash();
616
617            self.system_initial_configs.set(true);
618        }
619
620        match clock_source {
621            SystemClockSource::RcsysAt115kHz => {
622                // No configurations necessary, RCSYS is always on in run mode
623                // Set Flash wait state to 0 for <= 24MHz in PS2
624                flash_controller.set_wait_state(0);
625                // Change the system clock to RCSYS
626                select_main_clock(MainClock::RCSYS);
627            }
628
629            SystemClockSource::DfllRc32kAt48MHz => {
630                // Configure and turn on DFLL at 48MHz
631                self.configure_48mhz_dfll();
632                // Set Flash wait state to 1 for > 24MHz in PS2
633                flash_controller.set_wait_state(1);
634                // Change the system clock to DFLL
635                select_main_clock(MainClock::DFLL);
636            }
637
638            SystemClockSource::ExternalOscillator {
639                frequency,
640                startup_mode,
641            } => {
642                // Configure and turn on OSC0
643                self.configure_external_oscillator(frequency, startup_mode);
644                // Set Flash wait state to 0 for <= 24MHz in PS2
645                flash_controller.set_wait_state(0);
646                // Change the system clock to OSC0
647                select_main_clock(MainClock::OSC0);
648            }
649
650            SystemClockSource::PllExternalOscillatorAt48MHz {
651                frequency,
652                startup_mode,
653            } => {
654                // Configure and turn on PLL at 48MHz
655                self.configure_external_oscillator_pll(frequency, startup_mode);
656                // Set Flash wait state to 1 for > 24MHz in PS2
657                flash_controller.set_wait_state(1);
658                // Change the system clock to PLL
659                select_main_clock(MainClock::PLL);
660            }
661
662            SystemClockSource::RC80M => {
663                // Configure and turn on RC80M
664                self.configure_80mhz_rc();
665
666                // If the 80MHz RC is used as the main clock source, it must be divided by
667                //  at least 2 before being used as CPU's clock source
668                let cpusel = PM_REGS.cpusel.extract();
669                unlock(0x00000004);
670                PM_REGS.cpusel.modify_no_read(
671                    cpusel,
672                    CpuClockSelect::CPUDIV::SET + CpuClockSelect::CPUSEL::CLEAR,
673                );
674                while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
675
676                // Set Flash wait state to 1 for > 24MHz in PS2
677                flash_controller.set_wait_state(1);
678                // Change the system clock to RC80M
679                select_main_clock(MainClock::RC80M);
680            }
681
682            SystemClockSource::RCFAST { frequency } => {
683                // Check if RCFAST is already on, in which case temporarily switch the system to RCSYS
684                // since RCFAST has to be disabled before its configurations can be changed
685                if (self.system_on_clocks.get() & (ClockMask::RCFAST as u32)) != 0 {
686                    select_main_clock(MainClock::RCSYS);
687                    scif::disable_rcfast();
688                }
689
690                // Configure and turn on RCFAST at specified frequency
691                self.configure_rcfast(frequency);
692                // Set Flash wait state to 0 for <= 24MHz in PS2
693                flash_controller.set_wait_state(0);
694                // Change the system clock to RCFAST
695                select_main_clock(MainClock::RCFAST);
696            }
697
698            SystemClockSource::RC1M => {
699                // Configure and turn on RC1M
700                self.configure_1mhz_rc();
701                // Set Flash wait state to 0 for <= 24MHz in PS2
702                flash_controller.set_wait_state(0);
703                // Change the system clock to RC1M
704                select_main_clock(MainClock::RC1M);
705            }
706        }
707
708        self.system_clock_source.set(clock_source);
709    }
710
711    // Disables the clock passed in as clock_source
712    pub unsafe fn disable_system_clock(&self, clock_source: SystemClockSource) {
713        // Disable previous clock
714
715        match clock_source {
716            SystemClockSource::RcsysAt115kHz => {
717                //Rcsys is always on except in sleep modes
718            }
719
720            SystemClockSource::ExternalOscillator { .. } => {
721                // Only turn off OSC0 if PLL is not using it as a reference clock
722                if self.system_on_clocks.get() & (ClockMask::PLL as u32) == 0 {
723                    scif::disable_osc_16mhz();
724                }
725                let clock_mask = self.system_on_clocks.get();
726                self.system_on_clocks
727                    .set(clock_mask & !(ClockMask::OSC0 as u32));
728            }
729
730            SystemClockSource::PllExternalOscillatorAt48MHz { .. } => {
731                // Disable PLL
732                scif::disable_pll();
733                // don't turn off reference clock OSC0 if OSC0 is on
734                if self.system_on_clocks.get() & (ClockMask::OSC0 as u32) == 0 {
735                    scif::disable_osc_16mhz();
736                }
737                let clock_mask = self.system_on_clocks.get();
738                self.system_on_clocks
739                    .set(clock_mask & !(ClockMask::PLL as u32));
740            }
741
742            SystemClockSource::DfllRc32kAt48MHz => {
743                // Disable DFLL
744                scif::disable_dfll_rc32k();
745                let clock_mask = self.system_on_clocks.get();
746                self.system_on_clocks
747                    .set(clock_mask & !(ClockMask::DFLL as u32));
748            }
749
750            SystemClockSource::RC80M => {
751                // Disable RC80M
752                scif::disable_rc_80mhz();
753
754                // Stop dividing the main clock
755                let cpusel = PM_REGS.cpusel.extract();
756                unlock(0x00000004);
757                PM_REGS.cpusel.modify_no_read(
758                    cpusel,
759                    CpuClockSelect::CPUDIV::CLEAR + CpuClockSelect::CPUSEL::CLEAR,
760                );
761                while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
762
763                // Stop dividing peripheral clocks
764                let pbasel = PM_REGS.pbasel.extract();
765                unlock(0x0000000C);
766                PM_REGS.pbasel.modify_no_read(
767                    pbasel,
768                    PeripheralBusXClockSelect::PBDIV::CLEAR
769                        + PeripheralBusXClockSelect::PBSEL::CLEAR,
770                );
771                while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
772
773                let pbbsel = PM_REGS.pbbsel.extract();
774                unlock(0x00000010);
775                PM_REGS.pbbsel.modify_no_read(
776                    pbbsel,
777                    PeripheralBusXClockSelect::PBDIV::CLEAR
778                        + PeripheralBusXClockSelect::PBSEL::CLEAR,
779                );
780                while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
781
782                let pbcsel = PM_REGS.pbcsel.extract();
783                unlock(0x00000014);
784                PM_REGS.pbcsel.modify_no_read(
785                    pbcsel,
786                    PeripheralBusXClockSelect::PBDIV::CLEAR
787                        + PeripheralBusXClockSelect::PBSEL::CLEAR,
788                );
789                while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
790
791                let pbdsel = PM_REGS.pbdsel.extract();
792                unlock(0x00000018);
793                PM_REGS.pbdsel.modify_no_read(
794                    pbdsel,
795                    PeripheralBusXClockSelect::PBDIV::CLEAR
796                        + PeripheralBusXClockSelect::PBSEL::CLEAR,
797                );
798                while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
799
800                let clock_mask = self.system_on_clocks.get();
801                self.system_on_clocks
802                    .set(clock_mask & !(ClockMask::RC80M as u32));
803            }
804
805            SystemClockSource::RCFAST { .. } => {
806                // Disable RCFAST
807                scif::disable_rcfast();
808                let clock_mask = self.system_on_clocks.get();
809                self.system_on_clocks
810                    .set(clock_mask & !(ClockMask::RCFAST as u32));
811            }
812
813            SystemClockSource::RC1M => {
814                // Disable RC1M
815                bscif::disable_rc_1mhz();
816                let clock_mask = self.system_on_clocks.get();
817                self.system_on_clocks
818                    .set(clock_mask & !(ClockMask::RC1M as u32));
819            }
820        }
821    }
822
823    // Changes the system clock to the clock passed in as clock_source and disables
824    // the previous system clock
825    pub unsafe fn change_system_clock(
826        &self,
827        clock_source: SystemClockSource,
828        flash_controller: &flashcalw::FLASHCALW,
829    ) {
830        // If the clock you want to switch to is the current system clock, do nothing
831        let prev_clock_source = self.system_clock_source.get();
832        if prev_clock_source == clock_source {
833            return;
834        }
835
836        // Turn on and switch to the new system clock
837        self.setup_system_clock(clock_source, flash_controller);
838
839        // Don't disable RCFAST if the current clock is still RCFAST, just at
840        // a different frequency
841        match clock_source {
842            SystemClockSource::RCFAST { .. } => match prev_clock_source {
843                SystemClockSource::RCFAST { .. } => {
844                    return;
845                }
846                _ => {}
847            },
848            _ => {}
849        }
850        // Disable the previous system clock
851        self.disable_system_clock(prev_clock_source);
852    }
853
854    /// Configure the system clock to use the DFLL with the RC32K as the source.
855    /// Run at 48 MHz.
856    unsafe fn configure_48mhz_dfll(&self) {
857        // Start the DFLL
858        scif::setup_dfll_rc32k_48mhz();
859
860        let clock_mask = self.system_on_clocks.get();
861        self.system_on_clocks
862            .set(clock_mask | ClockMask::DFLL as u32);
863    }
864
865    /// Configure the system clock to use the 16 MHz external crystal directly
866    unsafe fn configure_external_oscillator(
867        &self,
868        frequency: OscillatorFrequency,
869        startup_mode: OscillatorStartup,
870    ) {
871        // Start the OSC0 if it isn't already in use by the PLL
872        if (self.system_on_clocks.get() & ClockMask::PLL as u32) == 0 {
873            match frequency {
874                OscillatorFrequency::Frequency16MHz => match startup_mode {
875                    OscillatorStartup::FastStart => scif::setup_osc_16mhz_fast_startup(),
876                    OscillatorStartup::SlowStart => scif::setup_osc_16mhz_slow_startup(),
877                },
878            }
879        }
880
881        let clock_mask = self.system_on_clocks.get();
882        self.system_on_clocks
883            .set(clock_mask | ClockMask::OSC0 as u32);
884    }
885
886    /// Configure the system clock to use the PLL with the 16 MHz external crystal
887    unsafe fn configure_external_oscillator_pll(
888        &self,
889        frequency: OscillatorFrequency,
890        startup_mode: OscillatorStartup,
891    ) {
892        // Start the OSC0 if it isn't already on
893        if (self.system_on_clocks.get() & ClockMask::OSC0 as u32) == 0 {
894            match frequency {
895                OscillatorFrequency::Frequency16MHz => match startup_mode {
896                    OscillatorStartup::FastStart => scif::setup_osc_16mhz_fast_startup(),
897                    OscillatorStartup::SlowStart => scif::setup_osc_16mhz_slow_startup(),
898                },
899            }
900        }
901
902        // Start the PLL
903        scif::setup_pll_osc_48mhz();
904
905        let clock_mask = self.system_on_clocks.get();
906        self.system_on_clocks
907            .set(clock_mask | ClockMask::PLL as u32);
908    }
909
910    unsafe fn configure_80mhz_rc(&self) {
911        // Start the 80mhz RC oscillator
912        scif::setup_rc_80mhz();
913
914        // Divide peripheral clocks so that fCPU >= fAPBx
915        let pbasel = PM_REGS.pbasel.extract();
916        unlock(0x0000000C);
917        PM_REGS.pbasel.modify_no_read(
918            pbasel,
919            PeripheralBusXClockSelect::PBDIV::SET + PeripheralBusXClockSelect::PBSEL::CLEAR,
920        );
921        while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
922
923        let pbbsel = PM_REGS.pbbsel.extract();
924        unlock(0x00000010);
925        PM_REGS.pbbsel.modify_no_read(
926            pbbsel,
927            PeripheralBusXClockSelect::PBDIV::SET + PeripheralBusXClockSelect::PBSEL::CLEAR,
928        );
929        while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
930
931        let pbcsel = PM_REGS.pbcsel.extract();
932        unlock(0x00000014);
933        PM_REGS.pbcsel.modify_no_read(
934            pbcsel,
935            PeripheralBusXClockSelect::PBDIV::SET + PeripheralBusXClockSelect::PBSEL::CLEAR,
936        );
937        while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
938
939        let pbdsel = PM_REGS.pbdsel.extract();
940        unlock(0x00000018);
941        PM_REGS.pbdsel.modify_no_read(
942            pbdsel,
943            PeripheralBusXClockSelect::PBDIV::SET + PeripheralBusXClockSelect::PBSEL::CLEAR,
944        );
945        while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
946
947        let clock_mask = self.system_on_clocks.get();
948        self.system_on_clocks
949            .set(clock_mask | ClockMask::RC80M as u32);
950    }
951
952    unsafe fn configure_rcfast(&self, frequency: RcfastFrequency) {
953        // Start the RCFAST at the specified frequency
954        match frequency {
955            RcfastFrequency::Frequency4MHz => {
956                scif::setup_rcfast_4mhz();
957            }
958            RcfastFrequency::Frequency8MHz => {
959                scif::setup_rcfast_8mhz();
960            }
961            RcfastFrequency::Frequency12MHz => {
962                scif::setup_rcfast_12mhz();
963            }
964        }
965
966        let clock_mask = self.system_on_clocks.get();
967        self.system_on_clocks
968            .set(clock_mask | ClockMask::RCFAST as u32);
969    }
970
971    unsafe fn configure_1mhz_rc(&self) {
972        // Start the RC1M
973        bscif::setup_rc_1mhz();
974        let clock_mask = self.system_on_clocks.get();
975        self.system_on_clocks
976            .set(clock_mask | ClockMask::RC1M as u32);
977    }
978
979    pub fn get_system_frequency(&self) -> u32 {
980        // Return the current system frequency
981        match self.system_clock_source.get() {
982            SystemClockSource::RcsysAt115kHz => 115200,
983            SystemClockSource::DfllRc32kAt48MHz => 48000000,
984            SystemClockSource::ExternalOscillator { .. } => 16000000,
985            SystemClockSource::PllExternalOscillatorAt48MHz { .. } => 48000000,
986            SystemClockSource::RC80M => 40000000,
987            SystemClockSource::RCFAST { frequency } => match frequency {
988                RcfastFrequency::Frequency4MHz => 4300000,
989                RcfastFrequency::Frequency8MHz => 8200000,
990                RcfastFrequency::Frequency12MHz => 12000000,
991            },
992            SystemClockSource::RC1M => 1000000,
993        }
994    }
995}
996
997fn unlock(register_offset: u32) {
998    PM_REGS.unlock.set(0xAA000000 | register_offset);
999}
1000
1001fn select_main_clock(clock: MainClock) {
1002    unlock(0);
1003    PM_REGS.mcctrl.set(clock as u32);
1004}
1005
1006/// Utility macro to modify clock mask registers
1007///
1008/// It takes one of two forms:
1009///
1010/// ```rust,ignore
1011///     mask_clock!(CLOCK_MASK_OFFSET_MASK_OFFSET: pm_register | value)
1012/// ```
1013///
1014/// which performs a logical-or on the existing register value, or
1015///
1016/// ```rust,ignore
1017///     mask_clock!(CLOCK_MASK_OFFSET_MASK_OFFSET: pm_register & value)
1018/// ```
1019///
1020/// which performs a logical-and.
1021///
1022/// CLOCK is one of HSB, PBA, PBB, PBC or PBD
1023///
1024/// pm_register is one of hsbmask, pbamask, pbbmask, pbcmask or pbdmask.
1025///
1026macro_rules! mask_clock {
1027    ($mask_offset:ident : $field:ident | $mask:expr) => {{
1028        unlock($mask_offset);
1029        let val = PM_REGS.$field.get() | ($mask);
1030        PM_REGS.$field.set(val);
1031    }};
1032
1033    ($mask_offset:ident : $field:ident & $mask:expr) => {{
1034        unlock($mask_offset);
1035        let val = PM_REGS.$field.get() & ($mask);
1036        PM_REGS.$field.set(val);
1037    }};
1038}
1039
1040/// Utility macro to get value of clock register. Used to check if a specific
1041/// clock is enabled or not. See above description of `make_clock!`.
1042macro_rules! get_clock {
1043    ($mask_offset:ident : $field:ident & $mask:expr) => {{
1044        unlock($mask_offset);
1045        (PM_REGS.$field.get() & ($mask)) != 0
1046    }};
1047}
1048
1049/// Determines if the chip can safely go into deep sleep without preventing
1050/// currently active peripherals from operating.
1051///
1052/// We look at the PM's clock mask registers and compare them against a set of
1053/// known masks that include no peripherals that can't operate in deep
1054/// sleep (or that have no function during sleep). Specifically:
1055///
1056///   * HSB may only have clocks for the flash (and PicoCache), APBx bridges, and PDCA on.
1057///
1058///   * PBA may only have I2C Slaves on as they can self-wake.
1059///
1060///   * PBB may only have clocks for the flash, HRAMC1 (also flash related), and PDCA on.
1061///
1062///   * PBC and PBD may have any clocks on.
1063///
1064/// This means it is the responsibility of each peripheral to disable it's clock
1065/// mask whenever it is idle.
1066///
1067/// A special note here regarding the PDCA (Peripheral DMA Controller) clock.
1068/// If the core deep sleeps while a DMA operation is active, it is transparently paused
1069/// and resumed when the core wakes again. If a peripheral needs a DMA operation to complete
1070/// before sleeping, the peripheral should inhibit sleep. The rationale here is to allow deep
1071/// sleep for an I2C Slave peripheral configured to use DMA.
1072///
1073/// We also special case GPIO (which is in PBCMASK), and just see if any interrupts are pending
1074/// through the INTERRUPT_COUNT variable.
1075pub fn deep_sleep_ready() -> bool {
1076    // HSB clocks that can be enabled and the core is permitted to enter deep sleep.
1077    // added by us: ClockMaskHsb::PDCA::SET
1078    //     default: ClockMaskHsb::FLASHCALW::SET
1079    // added by us: ClockMaskHsb::FLASHCALW_PICOCACHE::SET
1080    //     default: ClockMaskHsb::APBA_BRIDGE::SET
1081    //     default: ClockMaskHsb::APBB_BRIDGE::SET
1082    //     default: ClockMaskHsb::APBC_BRIDGE::SET
1083    //     default: ClockMaskHsb::APBD_BRIDGE::SET
1084    let deep_sleep_hsbmask: FieldValue<u32, ClockMaskHsb::Register> = ClockMaskHsb::PDCA::SET
1085        + ClockMaskHsb::FLASHCALW::SET
1086        + ClockMaskHsb::FLASHCALW_PICOCACHE::SET
1087        + ClockMaskHsb::APBA_BRIDGE::SET
1088        + ClockMaskHsb::APBB_BRIDGE::SET
1089        + ClockMaskHsb::APBC_BRIDGE::SET
1090        + ClockMaskHsb::APBD_BRIDGE::SET;
1091
1092    // PBA clocks that can be enabled and the core is permitted to enter deep sleep.
1093    // added by us: ClockMaskPba::TWIS0::SET
1094    // added by us: ClockMaskPba::TWIS1::SET
1095    let deep_sleep_pbamask: FieldValue<u32, ClockMaskPba::Register> =
1096        ClockMaskPba::TWIS0::SET + ClockMaskPba::TWIS1::SET;
1097
1098    // PBB clocks that can be enabled and the core is permitted to enter deep sleep.
1099    //     default: ClockMaskPbb::FLASHCALW::SET
1100    // added by us: ClockMaskPbb::HRAMC1::SET
1101    // added by us: ClockMaskPbb::PDCA::SET
1102    let deep_sleep_pbbmask: FieldValue<u32, ClockMaskPbb::Register> =
1103        ClockMaskPbb::FLASHCALW::SET + ClockMaskPbb::HRAMC1::SET + ClockMaskPbb::PDCA::SET;
1104
1105    let hsb = PM_REGS.hsbmask.get() & !deep_sleep_hsbmask.mask() == 0;
1106    let pba = PM_REGS.pbamask.get() & !deep_sleep_pbamask.mask() == 0;
1107    let pbb = PM_REGS.pbbmask.get() & !deep_sleep_pbbmask.mask() == 0;
1108    let gpio = gpio::INTERRUPT_COUNT.load(Ordering::Relaxed) == 0;
1109    hsb && pba && pbb && gpio
1110}
1111
1112impl ClockInterface for Clock {
1113    fn is_enabled(&self) -> bool {
1114        match *self {
1115            Clock::HSB(v) => get_clock!(HSB_MASK_OFFSET: hsbmask & (1 << (v as u32))),
1116            Clock::PBA(v) => get_clock!(PBA_MASK_OFFSET: pbamask & (1 << (v as u32))),
1117            Clock::PBB(v) => get_clock!(PBB_MASK_OFFSET: pbbmask & (1 << (v as u32))),
1118            Clock::PBC(v) => get_clock!(PBC_MASK_OFFSET: pbcmask & (1 << (v as u32))),
1119            Clock::PBD(v) => get_clock!(PBD_MASK_OFFSET: pbdmask & (1 << (v as u32))),
1120        }
1121    }
1122
1123    fn enable(&self) {
1124        match *self {
1125            Clock::HSB(v) => mask_clock!(HSB_MASK_OFFSET: hsbmask | 1 << (v as u32)),
1126            Clock::PBA(v) => mask_clock!(PBA_MASK_OFFSET: pbamask | 1 << (v as u32)),
1127            Clock::PBB(v) => mask_clock!(PBB_MASK_OFFSET: pbbmask | 1 << (v as u32)),
1128            Clock::PBC(v) => mask_clock!(PBC_MASK_OFFSET: pbcmask | 1 << (v as u32)),
1129            Clock::PBD(v) => mask_clock!(PBD_MASK_OFFSET: pbdmask | 1 << (v as u32)),
1130        }
1131    }
1132
1133    fn disable(&self) {
1134        match *self {
1135            Clock::HSB(v) => mask_clock!(HSB_MASK_OFFSET: hsbmask & !(1 << (v as u32))),
1136            Clock::PBA(v) => mask_clock!(PBA_MASK_OFFSET: pbamask & !(1 << (v as u32))),
1137            Clock::PBB(v) => mask_clock!(PBB_MASK_OFFSET: pbbmask & !(1 << (v as u32))),
1138            Clock::PBC(v) => mask_clock!(PBC_MASK_OFFSET: pbcmask & !(1 << (v as u32))),
1139            Clock::PBD(v) => mask_clock!(PBD_MASK_OFFSET: pbdmask & !(1 << (v as u32))),
1140        }
1141    }
1142}
1143
1144pub fn enable_clock(clock: Clock) {
1145    match clock {
1146        Clock::HSB(v) => mask_clock!(HSB_MASK_OFFSET: hsbmask | 1 << (v as u32)),
1147        Clock::PBA(v) => mask_clock!(PBA_MASK_OFFSET: pbamask | 1 << (v as u32)),
1148        Clock::PBB(v) => mask_clock!(PBB_MASK_OFFSET: pbbmask | 1 << (v as u32)),
1149        Clock::PBC(v) => mask_clock!(PBC_MASK_OFFSET: pbcmask | 1 << (v as u32)),
1150        Clock::PBD(v) => mask_clock!(PBD_MASK_OFFSET: pbdmask | 1 << (v as u32)),
1151    }
1152}
1153
1154pub fn disable_clock(clock: Clock) {
1155    match clock {
1156        Clock::HSB(v) => mask_clock!(HSB_MASK_OFFSET: hsbmask & !(1 << (v as u32))),
1157        Clock::PBA(v) => mask_clock!(PBA_MASK_OFFSET: pbamask & !(1 << (v as u32))),
1158        Clock::PBB(v) => mask_clock!(PBB_MASK_OFFSET: pbbmask & !(1 << (v as u32))),
1159        Clock::PBC(v) => mask_clock!(PBC_MASK_OFFSET: pbcmask & !(1 << (v as u32))),
1160        Clock::PBD(v) => mask_clock!(PBD_MASK_OFFSET: pbdmask & !(1 << (v as u32))),
1161    }
1162}
1163
1164pub fn is_clock_enabled(clock: Clock) -> bool {
1165    match clock {
1166        Clock::HSB(v) => get_clock!(HSB_MASK_OFFSET: hsbmask & (1 << (v as u32))),
1167        Clock::PBA(v) => get_clock!(PBA_MASK_OFFSET: pbamask & (1 << (v as u32))),
1168        Clock::PBB(v) => get_clock!(PBB_MASK_OFFSET: pbbmask & (1 << (v as u32))),
1169        Clock::PBC(v) => get_clock!(PBC_MASK_OFFSET: pbcmask & (1 << (v as u32))),
1170        Clock::PBD(v) => get_clock!(PBD_MASK_OFFSET: pbdmask & (1 << (v as u32))),
1171    }
1172}