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        if let SystemClockSource::RCFAST { .. } = clock_source {
842            if let SystemClockSource::RCFAST { .. } = prev_clock_source {
843                return;
844            }
845        }
846        // Disable the previous system clock
847        self.disable_system_clock(prev_clock_source);
848    }
849
850    /// Configure the system clock to use the DFLL with the RC32K as the source.
851    /// Run at 48 MHz.
852    unsafe fn configure_48mhz_dfll(&self) {
853        // Start the DFLL
854        scif::setup_dfll_rc32k_48mhz();
855
856        let clock_mask = self.system_on_clocks.get();
857        self.system_on_clocks
858            .set(clock_mask | ClockMask::DFLL as u32);
859    }
860
861    /// Configure the system clock to use the 16 MHz external crystal directly
862    unsafe fn configure_external_oscillator(
863        &self,
864        frequency: OscillatorFrequency,
865        startup_mode: OscillatorStartup,
866    ) {
867        // Start the OSC0 if it isn't already in use by the PLL
868        if (self.system_on_clocks.get() & ClockMask::PLL as u32) == 0 {
869            match frequency {
870                OscillatorFrequency::Frequency16MHz => match startup_mode {
871                    OscillatorStartup::FastStart => scif::setup_osc_16mhz_fast_startup(),
872                    OscillatorStartup::SlowStart => scif::setup_osc_16mhz_slow_startup(),
873                },
874            }
875        }
876
877        let clock_mask = self.system_on_clocks.get();
878        self.system_on_clocks
879            .set(clock_mask | ClockMask::OSC0 as u32);
880    }
881
882    /// Configure the system clock to use the PLL with the 16 MHz external crystal
883    unsafe fn configure_external_oscillator_pll(
884        &self,
885        frequency: OscillatorFrequency,
886        startup_mode: OscillatorStartup,
887    ) {
888        // Start the OSC0 if it isn't already on
889        if (self.system_on_clocks.get() & ClockMask::OSC0 as u32) == 0 {
890            match frequency {
891                OscillatorFrequency::Frequency16MHz => match startup_mode {
892                    OscillatorStartup::FastStart => scif::setup_osc_16mhz_fast_startup(),
893                    OscillatorStartup::SlowStart => scif::setup_osc_16mhz_slow_startup(),
894                },
895            }
896        }
897
898        // Start the PLL
899        scif::setup_pll_osc_48mhz();
900
901        let clock_mask = self.system_on_clocks.get();
902        self.system_on_clocks
903            .set(clock_mask | ClockMask::PLL as u32);
904    }
905
906    unsafe fn configure_80mhz_rc(&self) {
907        // Start the 80mhz RC oscillator
908        scif::setup_rc_80mhz();
909
910        // Divide peripheral clocks so that fCPU >= fAPBx
911        let pbasel = PM_REGS.pbasel.extract();
912        unlock(0x0000000C);
913        PM_REGS.pbasel.modify_no_read(
914            pbasel,
915            PeripheralBusXClockSelect::PBDIV::SET + PeripheralBusXClockSelect::PBSEL::CLEAR,
916        );
917        while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
918
919        let pbbsel = PM_REGS.pbbsel.extract();
920        unlock(0x00000010);
921        PM_REGS.pbbsel.modify_no_read(
922            pbbsel,
923            PeripheralBusXClockSelect::PBDIV::SET + PeripheralBusXClockSelect::PBSEL::CLEAR,
924        );
925        while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
926
927        let pbcsel = PM_REGS.pbcsel.extract();
928        unlock(0x00000014);
929        PM_REGS.pbcsel.modify_no_read(
930            pbcsel,
931            PeripheralBusXClockSelect::PBDIV::SET + PeripheralBusXClockSelect::PBSEL::CLEAR,
932        );
933        while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
934
935        let pbdsel = PM_REGS.pbdsel.extract();
936        unlock(0x00000018);
937        PM_REGS.pbdsel.modify_no_read(
938            pbdsel,
939            PeripheralBusXClockSelect::PBDIV::SET + PeripheralBusXClockSelect::PBSEL::CLEAR,
940        );
941        while PM_REGS.sr.matches_all(InterruptOrStatus::CKRDY::CLEAR) {}
942
943        let clock_mask = self.system_on_clocks.get();
944        self.system_on_clocks
945            .set(clock_mask | ClockMask::RC80M as u32);
946    }
947
948    unsafe fn configure_rcfast(&self, frequency: RcfastFrequency) {
949        // Start the RCFAST at the specified frequency
950        match frequency {
951            RcfastFrequency::Frequency4MHz => {
952                scif::setup_rcfast_4mhz();
953            }
954            RcfastFrequency::Frequency8MHz => {
955                scif::setup_rcfast_8mhz();
956            }
957            RcfastFrequency::Frequency12MHz => {
958                scif::setup_rcfast_12mhz();
959            }
960        }
961
962        let clock_mask = self.system_on_clocks.get();
963        self.system_on_clocks
964            .set(clock_mask | ClockMask::RCFAST as u32);
965    }
966
967    unsafe fn configure_1mhz_rc(&self) {
968        // Start the RC1M
969        bscif::setup_rc_1mhz();
970        let clock_mask = self.system_on_clocks.get();
971        self.system_on_clocks
972            .set(clock_mask | ClockMask::RC1M as u32);
973    }
974
975    pub fn get_system_frequency(&self) -> u32 {
976        // Return the current system frequency
977        match self.system_clock_source.get() {
978            SystemClockSource::RcsysAt115kHz => 115200,
979            SystemClockSource::DfllRc32kAt48MHz => 48000000,
980            SystemClockSource::ExternalOscillator { .. } => 16000000,
981            SystemClockSource::PllExternalOscillatorAt48MHz { .. } => 48000000,
982            SystemClockSource::RC80M => 40000000,
983            SystemClockSource::RCFAST { frequency } => match frequency {
984                RcfastFrequency::Frequency4MHz => 4300000,
985                RcfastFrequency::Frequency8MHz => 8200000,
986                RcfastFrequency::Frequency12MHz => 12000000,
987            },
988            SystemClockSource::RC1M => 1000000,
989        }
990    }
991}
992
993fn unlock(register_offset: u32) {
994    PM_REGS.unlock.set(0xAA000000 | register_offset);
995}
996
997fn select_main_clock(clock: MainClock) {
998    unlock(0);
999    PM_REGS.mcctrl.set(clock as u32);
1000}
1001
1002/// Utility macro to modify clock mask registers
1003///
1004/// It takes one of two forms:
1005///
1006/// ```rust,ignore
1007///     mask_clock!(CLOCK_MASK_OFFSET_MASK_OFFSET: pm_register | value)
1008/// ```
1009///
1010/// which performs a logical-or on the existing register value, or
1011///
1012/// ```rust,ignore
1013///     mask_clock!(CLOCK_MASK_OFFSET_MASK_OFFSET: pm_register & value)
1014/// ```
1015///
1016/// which performs a logical-and.
1017///
1018/// CLOCK is one of HSB, PBA, PBB, PBC or PBD
1019///
1020/// pm_register is one of hsbmask, pbamask, pbbmask, pbcmask or pbdmask.
1021///
1022macro_rules! mask_clock {
1023    ($mask_offset:ident : $field:ident | $mask:expr) => {{
1024        unlock($mask_offset);
1025        let val = PM_REGS.$field.get() | ($mask);
1026        PM_REGS.$field.set(val);
1027    }};
1028
1029    ($mask_offset:ident : $field:ident & $mask:expr) => {{
1030        unlock($mask_offset);
1031        let val = PM_REGS.$field.get() & ($mask);
1032        PM_REGS.$field.set(val);
1033    }};
1034}
1035
1036/// Utility macro to get value of clock register. Used to check if a specific
1037/// clock is enabled or not. See above description of `make_clock!`.
1038macro_rules! get_clock {
1039    ($mask_offset:ident : $field:ident & $mask:expr) => {{
1040        unlock($mask_offset);
1041        (PM_REGS.$field.get() & ($mask)) != 0
1042    }};
1043}
1044
1045/// Determines if the chip can safely go into deep sleep without preventing
1046/// currently active peripherals from operating.
1047///
1048/// We look at the PM's clock mask registers and compare them against a set of
1049/// known masks that include no peripherals that can't operate in deep
1050/// sleep (or that have no function during sleep). Specifically:
1051///
1052///   * HSB may only have clocks for the flash (and PicoCache), APBx bridges, and PDCA on.
1053///
1054///   * PBA may only have I2C Slaves on as they can self-wake.
1055///
1056///   * PBB may only have clocks for the flash, HRAMC1 (also flash related), and PDCA on.
1057///
1058///   * PBC and PBD may have any clocks on.
1059///
1060/// This means it is the responsibility of each peripheral to disable it's clock
1061/// mask whenever it is idle.
1062///
1063/// A special note here regarding the PDCA (Peripheral DMA Controller) clock.
1064/// If the core deep sleeps while a DMA operation is active, it is transparently paused
1065/// and resumed when the core wakes again. If a peripheral needs a DMA operation to complete
1066/// before sleeping, the peripheral should inhibit sleep. The rationale here is to allow deep
1067/// sleep for an I2C Slave peripheral configured to use DMA.
1068///
1069/// We also special case GPIO (which is in PBCMASK), and just see if any interrupts are pending
1070/// through the INTERRUPT_COUNT variable.
1071pub fn deep_sleep_ready() -> bool {
1072    // HSB clocks that can be enabled and the core is permitted to enter deep sleep.
1073    // added by us: ClockMaskHsb::PDCA::SET
1074    //     default: ClockMaskHsb::FLASHCALW::SET
1075    // added by us: ClockMaskHsb::FLASHCALW_PICOCACHE::SET
1076    //     default: ClockMaskHsb::APBA_BRIDGE::SET
1077    //     default: ClockMaskHsb::APBB_BRIDGE::SET
1078    //     default: ClockMaskHsb::APBC_BRIDGE::SET
1079    //     default: ClockMaskHsb::APBD_BRIDGE::SET
1080    let deep_sleep_hsbmask: FieldValue<u32, ClockMaskHsb::Register> = ClockMaskHsb::PDCA::SET
1081        + ClockMaskHsb::FLASHCALW::SET
1082        + ClockMaskHsb::FLASHCALW_PICOCACHE::SET
1083        + ClockMaskHsb::APBA_BRIDGE::SET
1084        + ClockMaskHsb::APBB_BRIDGE::SET
1085        + ClockMaskHsb::APBC_BRIDGE::SET
1086        + ClockMaskHsb::APBD_BRIDGE::SET;
1087
1088    // PBA clocks that can be enabled and the core is permitted to enter deep sleep.
1089    // added by us: ClockMaskPba::TWIS0::SET
1090    // added by us: ClockMaskPba::TWIS1::SET
1091    let deep_sleep_pbamask: FieldValue<u32, ClockMaskPba::Register> =
1092        ClockMaskPba::TWIS0::SET + ClockMaskPba::TWIS1::SET;
1093
1094    // PBB clocks that can be enabled and the core is permitted to enter deep sleep.
1095    //     default: ClockMaskPbb::FLASHCALW::SET
1096    // added by us: ClockMaskPbb::HRAMC1::SET
1097    // added by us: ClockMaskPbb::PDCA::SET
1098    let deep_sleep_pbbmask: FieldValue<u32, ClockMaskPbb::Register> =
1099        ClockMaskPbb::FLASHCALW::SET + ClockMaskPbb::HRAMC1::SET + ClockMaskPbb::PDCA::SET;
1100
1101    let hsb = PM_REGS.hsbmask.get() & !deep_sleep_hsbmask.mask() == 0;
1102    let pba = PM_REGS.pbamask.get() & !deep_sleep_pbamask.mask() == 0;
1103    let pbb = PM_REGS.pbbmask.get() & !deep_sleep_pbbmask.mask() == 0;
1104    let gpio = gpio::INTERRUPT_COUNT.load(Ordering::Relaxed) == 0;
1105    hsb && pba && pbb && gpio
1106}
1107
1108impl ClockInterface for Clock {
1109    fn is_enabled(&self) -> bool {
1110        match *self {
1111            Clock::HSB(v) => get_clock!(HSB_MASK_OFFSET: hsbmask & (1 << (v as u32))),
1112            Clock::PBA(v) => get_clock!(PBA_MASK_OFFSET: pbamask & (1 << (v as u32))),
1113            Clock::PBB(v) => get_clock!(PBB_MASK_OFFSET: pbbmask & (1 << (v as u32))),
1114            Clock::PBC(v) => get_clock!(PBC_MASK_OFFSET: pbcmask & (1 << (v as u32))),
1115            Clock::PBD(v) => get_clock!(PBD_MASK_OFFSET: pbdmask & (1 << (v as u32))),
1116        }
1117    }
1118
1119    fn enable(&self) {
1120        match *self {
1121            Clock::HSB(v) => mask_clock!(HSB_MASK_OFFSET: hsbmask | 1 << (v as u32)),
1122            Clock::PBA(v) => mask_clock!(PBA_MASK_OFFSET: pbamask | 1 << (v as u32)),
1123            Clock::PBB(v) => mask_clock!(PBB_MASK_OFFSET: pbbmask | 1 << (v as u32)),
1124            Clock::PBC(v) => mask_clock!(PBC_MASK_OFFSET: pbcmask | 1 << (v as u32)),
1125            Clock::PBD(v) => mask_clock!(PBD_MASK_OFFSET: pbdmask | 1 << (v as u32)),
1126        }
1127    }
1128
1129    fn disable(&self) {
1130        match *self {
1131            Clock::HSB(v) => mask_clock!(HSB_MASK_OFFSET: hsbmask & !(1 << (v as u32))),
1132            Clock::PBA(v) => mask_clock!(PBA_MASK_OFFSET: pbamask & !(1 << (v as u32))),
1133            Clock::PBB(v) => mask_clock!(PBB_MASK_OFFSET: pbbmask & !(1 << (v as u32))),
1134            Clock::PBC(v) => mask_clock!(PBC_MASK_OFFSET: pbcmask & !(1 << (v as u32))),
1135            Clock::PBD(v) => mask_clock!(PBD_MASK_OFFSET: pbdmask & !(1 << (v as u32))),
1136        }
1137    }
1138}
1139
1140pub fn enable_clock(clock: Clock) {
1141    match clock {
1142        Clock::HSB(v) => mask_clock!(HSB_MASK_OFFSET: hsbmask | 1 << (v as u32)),
1143        Clock::PBA(v) => mask_clock!(PBA_MASK_OFFSET: pbamask | 1 << (v as u32)),
1144        Clock::PBB(v) => mask_clock!(PBB_MASK_OFFSET: pbbmask | 1 << (v as u32)),
1145        Clock::PBC(v) => mask_clock!(PBC_MASK_OFFSET: pbcmask | 1 << (v as u32)),
1146        Clock::PBD(v) => mask_clock!(PBD_MASK_OFFSET: pbdmask | 1 << (v as u32)),
1147    }
1148}
1149
1150pub fn disable_clock(clock: Clock) {
1151    match clock {
1152        Clock::HSB(v) => mask_clock!(HSB_MASK_OFFSET: hsbmask & !(1 << (v as u32))),
1153        Clock::PBA(v) => mask_clock!(PBA_MASK_OFFSET: pbamask & !(1 << (v as u32))),
1154        Clock::PBB(v) => mask_clock!(PBB_MASK_OFFSET: pbbmask & !(1 << (v as u32))),
1155        Clock::PBC(v) => mask_clock!(PBC_MASK_OFFSET: pbcmask & !(1 << (v as u32))),
1156        Clock::PBD(v) => mask_clock!(PBD_MASK_OFFSET: pbdmask & !(1 << (v as u32))),
1157    }
1158}
1159
1160pub fn is_clock_enabled(clock: Clock) -> bool {
1161    match clock {
1162        Clock::HSB(v) => get_clock!(HSB_MASK_OFFSET: hsbmask & (1 << (v as u32))),
1163        Clock::PBA(v) => get_clock!(PBA_MASK_OFFSET: pbamask & (1 << (v as u32))),
1164        Clock::PBB(v) => get_clock!(PBB_MASK_OFFSET: pbbmask & (1 << (v as u32))),
1165        Clock::PBC(v) => get_clock!(PBC_MASK_OFFSET: pbcmask & (1 << (v as u32))),
1166        Clock::PBD(v) => get_clock!(PBD_MASK_OFFSET: pbdmask & (1 << (v as u32))),
1167    }
1168}