Skip to main content

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