sam4l/
scif.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 system control interface for the SAM4L.
6//!
7//! This file includes support for the SCIF (Chapter 13 of SAML manual), which
8//! configures system clocks. Does not currently support all
9//! features/functionality: only main oscillator and generic clocks.
10//!
11//! - Author: Philip Levis
12//! - Date: Aug 2, 2015
13
14use crate::bscif;
15use kernel::utilities::registers::interfaces::{Readable, Writeable};
16use kernel::utilities::registers::{
17    register_bitfields, FieldValue, ReadOnly, ReadWrite, WriteOnly,
18};
19use kernel::utilities::StaticRef;
20
21pub enum Register {
22    IER = 0x00,
23    IDR = 0x04,
24    IMR = 0x08,
25    ISR = 0x0C,
26    ICR = 0x10,
27    PCLKSR = 0x14,
28    UNLOCK = 0x18,
29    CSCR = 0x1C,
30    OSCCTRL0 = 0x20,
31    PLL0 = 0x24,
32    DFLL0CONF = 0x28,
33    DFLL0MUL = 0x30,
34    DFLL0STEP = 0x34,
35    DFLL0SSG = 0x38,
36    RCFASTCFG = 0x48,
37    RC80MCR = 0x50,
38}
39
40#[allow(non_camel_case_types)]
41pub enum ClockSource {
42    RCSYS = 0,
43    OSC32K = 1,
44    DFLL0 = 2,
45    OSC0 = 3,
46    RC80M = 4,
47    RCFAST = 5,
48    RC1M = 6,
49    CLK_CPU = 7,
50    CLK_HSB = 8,
51    CLK_PBA = 9,
52    CLK_PBB = 10,
53    CLK_PBC = 11,
54    CLK_PBD = 12,
55    RC32K = 13,
56    RESERVED1 = 14,
57    CLK_1K = 15,
58    PLL0 = 16,
59    HRP = 17,
60    FP = 18,
61    GCLK_IN0 = 19,
62    GCLK_IN1 = 20,
63    GCLK11 = 21,
64}
65
66pub enum GenericClock {
67    GCLK0,
68    GCLK1,
69    GCLK2,
70    GCLK3,
71    GCLK4,
72    GCLK5,
73    GCLK6,
74    GCLK7,
75    GCLK8,
76    GCLK9,
77    GCLK10,
78    GCLK11,
79}
80
81#[repr(C)]
82struct ScifRegisters {
83    ier: WriteOnly<u32, Interrupt::Register>,
84    idr: WriteOnly<u32, Interrupt::Register>,
85    imr: ReadOnly<u32, Interrupt::Register>,
86    isr: ReadOnly<u32, Interrupt::Register>,
87    icr: WriteOnly<u32, Interrupt::Register>,
88    pclksr: ReadOnly<u32, Interrupt::Register>,
89    unlock: WriteOnly<u32, Unlock::Register>,
90    cscr: ReadWrite<u32>,
91    oscctrl0: ReadWrite<u32, Oscillator::Register>,
92    pll0: ReadWrite<u32, PllControl::Register>,
93    dfll0conf: ReadWrite<u32, Dfll::Register>,
94    dfll0val: ReadWrite<u32>,
95    dfll0mul: ReadWrite<u32>,
96    dfll0step: ReadWrite<u32, DfllStep::Register>,
97    dfll0ssg: ReadWrite<u32>,
98    dfll0ratio: ReadOnly<u32>,
99    dfll0sync: WriteOnly<u32>,
100    rccr: ReadWrite<u32>,
101    rcfastcfg: ReadWrite<u32, Rcfast::Register>,
102    rcfastsr: ReadOnly<u32>,
103    rc80mcr: ReadWrite<u32, Rc80m::Register>,
104    _reserved0: [u32; 4],
105    hrpcr: ReadWrite<u32>,
106    fpcr: ReadWrite<u32>,
107    fpmul: ReadWrite<u32>,
108    fpdiv: ReadWrite<u32>,
109    gcctrl0: ReadWrite<u32, GenericClockControl::Register>,
110    gcctrl1: ReadWrite<u32, GenericClockControl::Register>,
111    gcctrl2: ReadWrite<u32, GenericClockControl::Register>,
112    gcctrl3: ReadWrite<u32, GenericClockControl::Register>,
113    gcctrl4: ReadWrite<u32, GenericClockControl::Register>,
114    gcctrl5: ReadWrite<u32, GenericClockControl::Register>,
115    gcctrl6: ReadWrite<u32, GenericClockControl::Register>,
116    gcctrl7: ReadWrite<u32, GenericClockControl::Register>,
117    gcctrl8: ReadWrite<u32, GenericClockControl::Register>,
118    gcctrl9: ReadWrite<u32, GenericClockControl::Register>,
119    gcctrl10: ReadWrite<u32, GenericClockControl::Register>,
120    gcctrl11: ReadWrite<u32, GenericClockControl::Register>,
121    // Version registers are omitted here
122}
123
124register_bitfields![u32,
125    Interrupt [
126        RCFASTLOCKLOST 14,
127        RCFASTLOCK 13,
128        PLL0LOCKLOST 7,
129        PLL0LOCK 6,
130        DFLL0RCS 4,
131        DFLL0RDY 3,
132        DFLL0LOCKF 2,
133        DFLL0LOCKC 1,
134        OSC0RDY 0
135    ],
136    Unlock [
137        KEY OFFSET(24) NUMBITS(8) [],
138        ADDR OFFSET(0) NUMBITS(10) []
139    ],
140    Oscillator [
141        OSCEN OFFSET(16) NUMBITS(1) [],
142        STARTUP OFFSET(8) NUMBITS(4) [
143            Cycles64 = 1,
144            Cycles1024 = 14
145        ],
146        AGC OFFSET(3) NUMBITS(1) [],
147        GAIN OFFSET(1) NUMBITS(2) [
148            G0 = 0, G1 = 1, G2 = 2, G3 = 3, G4 = 4
149        ],
150        MODE OFFSET(0) NUMBITS(1) [
151            External = 0,
152            Crystal = 1
153        ]
154    ],
155    Dfll [
156        CALIB OFFSET(24) NUMBITS(4) [],
157        FCD OFFSET(23) NUMBITS(1) [],
158        RANGE OFFSET(16) NUMBITS(2) [],
159        QLDIS OFFSET(6) NUMBITS(1) [],
160        CCDIS OFFSET(5) NUMBITS(1) [],
161        LLAW OFFSET(3) NUMBITS(1) [],
162        STABLE OFFSET(2) NUMBITS(1) [],
163        MODE OFFSET(1) NUMBITS(1) [
164            OpenLoop = 0,
165            ClosedLoop = 1
166        ],
167        EN OFFSET(0) NUMBITS(1) []
168    ],
169    DfllStep [
170        CSTEP OFFSET(16) NUMBITS(5) [],
171        FSTEP OFFSET(0) NUMBITS(8) []
172    ],
173    GenericClockControl [
174        DIV OFFSET(16) NUMBITS(16) [],
175        OCSEL OFFSET(8) NUMBITS(5) [
176            // values available from enum ClockSource
177        ],
178        DIVEN OFFSET(1) NUMBITS(1) [],
179        CEN OFFSET(0) NUMBITS(1) []
180    ],
181    PllControl [
182        PLLCOUNT OFFSET(24) NUMBITS(6) [
183            Max = 0x3F
184        ],
185        PLLMUL OFFSET(16) NUMBITS(4) [],
186        PLLDIV OFFSET(8) NUMBITS(4) [],
187        PLLOSC OFFSET(1) NUMBITS(2) [
188            OSC0 = 0,
189            GCLK9 = 1
190        ],
191        PLLOPT OFFSET(3) NUMBITS(3) [
192            DivideBy2 = 2
193            // Other option combinations omitted here, as it
194            // is not clear in which order the bits are stored
195        ],
196        PLLEN OFFSET(0) NUMBITS(1) []
197    ],
198    Rcfast [
199        CALIB OFFSET(16) NUMBITS(7) [],
200        LOCKMARGIN OFFSET(12) NUMBITS(4) [],
201        FRANGE OFFSET(8) NUMBITS(2) [
202            Range4MHz = 0,
203            Range8MHz = 1,
204            Range12MHz = 2
205        ],
206        FCD OFFSET(7) NUMBITS(1) [],
207        NBPERIODS OFFSET(4) NUMBITS(3) [],
208        JITMODE OFFSET(2) NUMBITS(1) [],
209        TUNEEN OFFSET(1) NUMBITS(1) [],
210        EN OFFSET(0) NUMBITS(1) []
211    ],
212    Rc80m [
213        EN OFFSET(0) NUMBITS(1) []
214    ]
215];
216
217const SCIF: StaticRef<ScifRegisters> =
218    unsafe { StaticRef::new(0x400E0800 as *const ScifRegisters) };
219
220#[repr(usize)]
221pub enum Clock {
222    ClockRCSys = 0,
223    ClockOsc32 = 1,
224    ClockAPB = 2,
225    ClockGclk2 = 3,
226    Clock1K = 4,
227}
228
229pub fn unlock(register: Register) {
230    SCIF.unlock
231        .write(Unlock::KEY.val(0xAA) + Unlock::ADDR.val(register as u32));
232}
233
234pub fn oscillator_enable(internal: bool) {
235    let mode = if internal {
236        Oscillator::MODE::Crystal
237    } else {
238        Oscillator::MODE::External
239    };
240    unlock(Register::OSCCTRL0);
241    SCIF.oscctrl0.write(Oscillator::OSCEN::SET + mode);
242}
243
244pub fn oscillator_disable() {
245    unlock(Register::OSCCTRL0);
246    SCIF.oscctrl0.write(Oscillator::OSCEN::CLEAR);
247}
248
249pub fn setup_dfll_rc32k_48mhz() {
250    fn wait_dfll0_ready() {
251        while !SCIF.pclksr.is_set(Interrupt::DFLL0RDY) {}
252    }
253
254    // Check to see if the DFLL is already setup or is not locked
255    if !SCIF.dfll0conf.is_set(Dfll::EN) || !SCIF.pclksr.is_set(Interrupt::DFLL0LOCKF) {
256        // Enable the GENCLK_SRC_RC32K
257        if !bscif::rc32k_enabled() {
258            bscif::enable_rc32k();
259        }
260
261        // Next, initialize closed-loop mode ...
262
263        // Must do a SCIF sync before reading the SCIF registers?
264        // 13.7.16: "To be able to read the current value of DFLLxVAL or DFLLxRATIO, this bit must
265        //    be written to one. The updated value are available in DFLLxVAL or DFLLxRATIO when
266        //    PCLKSR.DFLL0RDY is set."
267        SCIF.dfll0sync.set(0x01);
268        wait_dfll0_ready();
269
270        // TODO: if already in closed mode, only turn on gclk and enable dfll
271        // Read the current DFLL settings
272        let scif_dfll0conf = SCIF.dfll0conf.get();
273        // Compute some new configuration field values
274        let new_config_fields = Dfll::EN::SET + Dfll::MODE::ClosedLoop + Dfll::RANGE.val(2);
275        // Apply the new field values to the current config value,
276        // for use further below ...
277        let scif_dfll0conf_new = new_config_fields.modify(scif_dfll0conf);
278
279        // Enable the generic clock with RC32K and no divider
280        SCIF.gcctrl0.write(
281            GenericClockControl::CEN::SET
282                + GenericClockControl::OCSEL.val(ClockSource::RC32K as u32)
283                + GenericClockControl::DIVEN::CLEAR
284                + GenericClockControl::DIV.val(0),
285        );
286
287        // Setup DFLL. Must wait after every operation for the ready bit to go high.
288        //
289        // First, enable dfll
290        unlock(Register::DFLL0CONF);
291        SCIF.dfll0conf.write(Dfll::EN::SET);
292        wait_dfll0_ready();
293
294        // Set step values
295        unlock(Register::DFLL0STEP);
296        SCIF.dfll0step
297            .write(DfllStep::FSTEP.val(4) + DfllStep::CSTEP.val(4));
298        wait_dfll0_ready();
299
300        // Set multiply value
301        unlock(Register::DFLL0MUL);
302        // 1464 = 48000000 / 32768
303        SCIF.dfll0mul.set(1464);
304        wait_dfll0_ready();
305
306        // Set SSG value
307        unlock(Register::DFLL0SSG);
308        // just set to zero to disable
309        SCIF.dfll0ssg.set(0);
310        wait_dfll0_ready();
311
312        // Set actual configuration
313        unlock(Register::DFLL0CONF);
314        // we already prepared this value
315        SCIF.dfll0conf.set(scif_dfll0conf_new);
316
317        // Now wait for the DFLL to become locked
318        while !SCIF.pclksr.is_set(Interrupt::DFLL0LOCKF) {}
319    }
320}
321
322pub unsafe fn disable_dfll_rc32k() {
323    // Must do a SCIF sync
324    SCIF.dfll0sync.set(0x01);
325    while !SCIF.pclksr.is_set(Interrupt::DFLL0RDY) {}
326
327    // Disable the DFLL
328    let dfll0conf = SCIF.dfll0conf.extract();
329    unlock(Register::DFLL0CONF);
330    SCIF.dfll0conf.modify_no_read(dfll0conf, Dfll::EN::CLEAR);
331
332    // Disable generic clock
333    generic_clock_disable(GenericClock::GCLK0);
334
335    // Wait for the DFLL to be disabled
336    while SCIF.dfll0conf.is_set(Dfll::EN) {}
337}
338
339pub unsafe fn setup_osc_16mhz_fast_startup() {
340    // Enable the OSC0 with ~557us startup time
341    unlock(Register::OSCCTRL0);
342    SCIF.oscctrl0.write(
343        Oscillator::OSCEN::SET
344            + Oscillator::STARTUP::Cycles64
345            + Oscillator::GAIN::G4
346            + Oscillator::MODE::Crystal,
347    );
348
349    // Wait for oscillator to be ready
350    while !SCIF.pclksr.is_set(Interrupt::OSC0RDY) {}
351}
352
353pub unsafe fn setup_osc_16mhz_slow_startup() {
354    // Enable the OSC0 with ~8.9ms startup time
355    unlock(Register::OSCCTRL0);
356    SCIF.oscctrl0.write(
357        Oscillator::OSCEN::SET
358            + Oscillator::STARTUP::Cycles1024
359            + Oscillator::GAIN::G4
360            + Oscillator::MODE::Crystal,
361    );
362
363    // Wait for oscillator to be ready
364    while !SCIF.pclksr.is_set(Interrupt::OSC0RDY) {}
365}
366
367pub unsafe fn disable_osc_16mhz() {
368    // Disable the OSC0
369    let oscctrl0 = SCIF.oscctrl0.extract();
370    unlock(Register::OSCCTRL0);
371    SCIF.oscctrl0
372        .modify_no_read(oscctrl0, Oscillator::OSCEN::CLEAR);
373
374    // Wait for oscillator to be disabled
375    while SCIF.oscctrl0.is_set(Oscillator::OSCEN) {}
376}
377
378pub unsafe fn setup_pll_osc_48mhz() {
379    // Enable the PLL, use OSC0 as the reference clock and set f_PLL=((5+1)/1*f_OSC0)/2
380    // PLLCOUNT specifies the number of RCSYS clock cycles before ISR.PLLLOCKn will be set after PLLn has been written
381    unlock(Register::PLL0);
382    SCIF.pll0.write(
383        PllControl::PLLCOUNT::Max
384            + PllControl::PLLMUL.val(5)
385            + PllControl::PLLDIV.val(1)
386            + PllControl::PLLOPT::DivideBy2
387            + PllControl::PLLOSC::OSC0
388            + PllControl::PLLEN::SET,
389    );
390
391    // Wait for the PLL to become locked
392    while !SCIF.pclksr.is_set(Interrupt::PLL0LOCK) {}
393}
394
395pub unsafe fn disable_pll() {
396    // Disable the PLL
397    let pll0 = SCIF.pll0.extract();
398    unlock(Register::PLL0);
399    SCIF.pll0.modify_no_read(pll0, PllControl::PLLEN::CLEAR);
400
401    // Wait for the PLL to be disabled
402    while SCIF.pll0.is_set(PllControl::PLLEN) {}
403}
404
405pub unsafe fn setup_rc_80mhz() {
406    // Enable the RC80M
407    let rc80mcr = SCIF.rc80mcr.extract();
408    unlock(Register::RC80MCR);
409    SCIF.rc80mcr.modify_no_read(rc80mcr, Rc80m::EN::SET);
410
411    // Wait for the RC80M to be enabled
412    while !SCIF.rc80mcr.is_set(Rc80m::EN) {}
413}
414
415pub unsafe fn disable_rc_80mhz() {
416    // Disable the RC80M
417    let rc80mcr = SCIF.rc80mcr.extract();
418    unlock(Register::RC80MCR);
419    SCIF.rc80mcr.modify_no_read(rc80mcr, Rc80m::EN::CLEAR);
420
421    // Wait for the RC80M to be disabled
422    while SCIF.rc80mcr.is_set(Rc80m::EN) {}
423}
424
425pub unsafe fn setup_rcfast_4mhz() {
426    // Enable the RCFAST with frequency set to 4MHz and in open loop mode
427    let rcfastcfg = SCIF.rcfastcfg.extract();
428    unlock(Register::RCFASTCFG);
429    SCIF.rcfastcfg.modify_no_read(
430        rcfastcfg,
431        Rcfast::FRANGE::Range4MHz + Rcfast::TUNEEN::CLEAR + Rcfast::EN::SET,
432    );
433
434    // Wait for the RCFAST to be enabled
435    while !SCIF.rcfastcfg.is_set(Rcfast::EN) {}
436}
437
438pub unsafe fn setup_rcfast_8mhz() {
439    // Enable the RCFAST with frequency set to 8MHz and in open loop mode
440    let rcfastcfg = SCIF.rcfastcfg.extract();
441    unlock(Register::RCFASTCFG);
442    SCIF.rcfastcfg.modify_no_read(
443        rcfastcfg,
444        Rcfast::FRANGE::Range8MHz + Rcfast::TUNEEN::CLEAR + Rcfast::EN::SET,
445    );
446
447    // Wait for the RCFAST to be enabled
448    while !SCIF.rcfastcfg.is_set(Rcfast::EN) {}
449}
450
451pub unsafe fn setup_rcfast_12mhz() {
452    // Enable the RCFAST with frequency set to 12MHz and in open loop mode
453    let rcfastcfg = SCIF.rcfastcfg.extract();
454    unlock(Register::RCFASTCFG);
455    SCIF.rcfastcfg.modify_no_read(
456        rcfastcfg,
457        Rcfast::FRANGE::Range12MHz + Rcfast::TUNEEN::CLEAR + Rcfast::EN::SET,
458    );
459
460    // Wait for the RCFAST to be enabled
461    while !SCIF.rcfastcfg.is_set(Rcfast::EN) {}
462}
463
464pub unsafe fn disable_rcfast() {
465    // Disable the RCFAST
466    let rcfastcfg = SCIF.rcfastcfg.extract();
467    unlock(Register::RCFASTCFG);
468    SCIF.rcfastcfg.modify_no_read(rcfastcfg, Rcfast::EN::CLEAR);
469
470    // Wait for the RCFAST to be disabled
471    while SCIF.rcfastcfg.is_set(Rcfast::EN) {}
472}
473
474pub fn generic_clock_disable(clock: GenericClock) {
475    generic_clock_control_write(clock, GenericClockControl::CEN::CLEAR);
476}
477
478pub fn generic_clock_enable(clock: GenericClock, source: ClockSource) {
479    generic_clock_control_write(
480        clock,
481        GenericClockControl::OCSEL.val(source as u32) + GenericClockControl::CEN::SET,
482    );
483}
484
485// Note that most clocks can only support 8 bits of divider:
486// interface does not currently check this. -pal
487pub fn generic_clock_enable_divided(clock: GenericClock, source: ClockSource, divider: u16) {
488    generic_clock_control_write(
489        clock,
490        GenericClockControl::OCSEL.val(source as u32)
491            + GenericClockControl::DIVEN::SET
492            + GenericClockControl::DIV.val(divider as u32)
493            + GenericClockControl::CEN::SET,
494    );
495}
496
497fn generic_clock_control_write(
498    clock: GenericClock,
499    val: FieldValue<u32, GenericClockControl::Register>,
500) {
501    match clock {
502        GenericClock::GCLK0 => SCIF.gcctrl0.write(val),
503        GenericClock::GCLK1 => SCIF.gcctrl1.write(val),
504        GenericClock::GCLK2 => SCIF.gcctrl2.write(val),
505        GenericClock::GCLK3 => SCIF.gcctrl3.write(val),
506        GenericClock::GCLK4 => SCIF.gcctrl4.write(val),
507        GenericClock::GCLK5 => SCIF.gcctrl5.write(val),
508        GenericClock::GCLK6 => SCIF.gcctrl6.write(val),
509        GenericClock::GCLK7 => SCIF.gcctrl7.write(val),
510        GenericClock::GCLK8 => SCIF.gcctrl8.write(val),
511        GenericClock::GCLK9 => SCIF.gcctrl9.write(val),
512        GenericClock::GCLK10 => SCIF.gcctrl10.write(val),
513        GenericClock::GCLK11 => SCIF.gcctrl11.write(val),
514    }
515}