Skip to main content

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