imxrt10xx/
gpt.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
5use core::sync::atomic::{AtomicU32, Ordering};
6use cortexm7::support::atomic;
7use kernel::hil;
8use kernel::hil::time::{Ticks, Ticks32, Time};
9use kernel::platform::chip::ClockInterface;
10use kernel::utilities::cells::OptionalCell;
11use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
12use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite};
13use kernel::utilities::StaticRef;
14use kernel::ErrorCode;
15
16use crate::ccm;
17use crate::nvic;
18
19/// General purpose timers
20#[repr(C)]
21struct GptRegisters {
22    /// GPT Control Register
23    cr: ReadWrite<u32, CR::Register>,
24    /// GPT Prescaler Register
25    pr: ReadWrite<u32, PR::Register>,
26    /// GPT Status Register
27    sr: ReadWrite<u32, SR::Register>,
28    /// GPT Interrupt Register
29    ir: ReadWrite<u32, IR::Register>,
30    /// GPT Output Compare Register 1
31    ocr1: ReadWrite<u32, OCR1::Register>,
32    /// GPT Output Compare Register 2
33    ocr2: ReadWrite<u32, OCR2::Register>,
34    /// GPT Output Compare Register 3
35    ocr3: ReadWrite<u32, OCR3::Register>,
36    /// GPT Input Capture Register 1
37    icr1: ReadOnly<u32, ICR1::Register>,
38    /// GPT Input Capture Register 2
39    icr2: ReadOnly<u32, ICR2::Register>,
40    /// GPT Counter Register
41    cnt: ReadOnly<u32, CNT::Register>,
42}
43
44register_bitfields![u32,
45    CR [
46        /// Force Output Compare Channel 3
47        FO3 OFFSET(31) NUMBITS(1) [],
48        /// Force Output Compare Channel 2
49        FO2 OFFSET(30) NUMBITS(1) [],
50        /// Force Output Compare Channel 1
51        FO1 OFFSET(29) NUMBITS(1) [],
52        /// Controls the Output Compare Channel 3 operating mode
53        OM3 OFFSET(26) NUMBITS(3) [],
54        /// Controls the Output Compare Channel 2 operating mode
55        OM2 OFFSET(23) NUMBITS(3) [],
56        /// Controls the Output Compare Channel 2 operating mode
57        OM1 OFFSET(20) NUMBITS(3) [],
58        /// Input Capture Channel 2 operating mode
59        IM2 OFFSET(18) NUMBITS(2) [],
60        /// Input Capture Channel 1 operating mode
61        IM1 OFFSET(16) NUMBITS(2) [],
62        /// Software reset
63        SWR OFFSET(15) NUMBITS(1) [],
64        /// Enable 24 MHz clock input from crystal
65        EN_24M OFFSET(10) NUMBITS(1) [],
66        /// Free run or Restart mode
67        FRR OFFSET(9) NUMBITS(1) [],
68        /// Clock source select
69        CLKSRC OFFSET(6) NUMBITS(3) [
70            /// No clock
71            NoClock = 0,
72            /// Peripheral Clock (ipg_clk)
73            PeripheralClock = 1,
74            /// High Frequency Reference Clock (ipg_clk_highfreq)
75            HighFrequencyReferenceClock = 2,
76            /// External Clock
77            ExternalClock = 3,
78            /// Low Frequency Reference Clock (ipg_clk_32k)
79            LowFrequencyReferenceClock = 4,
80            /// Crystal oscillator as Reference Clock (ipg_clk_24M)
81            CrystalOscillator = 5
82        ],
83        /// GPT Stop Mode enable
84        STOPEN OFFSET(5) NUMBITS(1) [],
85        /// GPT Doze Mode Enable
86        DOZEEN OFFSET(4) NUMBITS(1) [],
87        /// GPT Wait Mode enable
88        WAITEN OFFSET(3) NUMBITS(1) [],
89        /// GPT debug mode enable
90        DBGEN OFFSET(2) NUMBITS(1) [],
91        /// GPT Enable mode
92        ENMOD OFFSET(1) NUMBITS(1) [],
93        /// GPT Enable
94        EN OFFSET(0) NUMBITS(1) []
95    ],
96
97    PR [
98        /// Prescaler bits for 24M crystal clock
99        PRESCALER24M OFFSET(12) NUMBITS(4),
100        /// Prescaler bits
101        PRESCALER OFFSET(0) NUMBITS(12)
102    ],
103
104    SR [
105        /// Rollover Flag
106        ROV OFFSET(5) NUMBITS(1),
107        /// Input capture 2 Flag
108        IF2 OFFSET(4) NUMBITS(1),
109        /// Input capture 1 Flag
110        IF1 OFFSET(3) NUMBITS(1),
111        /// Output Compare 3 Flag
112        OF3 OFFSET(2) NUMBITS(1),
113        /// Output Compare 2 Flag
114        OF2 OFFSET(1) NUMBITS(1),
115        /// Output Compare 1 Flag
116        OF1 OFFSET(0) NUMBITS(1)
117    ],
118
119    IR [
120        /// Rollover Interrupt Enable
121        ROVIE OFFSET(5) NUMBITS(1),
122        /// Input capture 2 Interrupt Enable
123        IF2IE OFFSET(4) NUMBITS(1),
124        /// Input capture 1 Interrupt Enable
125        IF1IE OFFSET(3) NUMBITS(1),
126        /// Output Compare 3 Interrupt Enable
127        OF3IE OFFSET(2) NUMBITS(1),
128        /// Output Compare 2 Interrupt Enable
129        OF2IE OFFSET(1) NUMBITS(1),
130        /// Output Compare 1 Interrupt Enable
131        OF1IE OFFSET(0) NUMBITS(1)
132    ],
133
134    OCR1 [
135        COMP OFFSET(0) NUMBITS(32)
136    ],
137
138    OCR2 [
139        COMP OFFSET(0) NUMBITS(32)
140    ],
141
142    OCR3 [
143        COMP OFFSET(0) NUMBITS(32)
144    ],
145
146    ICR1 [
147        CAPT OFFSET(0) NUMBITS(32)
148    ],
149
150    ICR2 [
151        CAPT OFFSET(0) NUMBITS(32)
152    ],
153
154    CNT [
155        COUNT OFFSET(0) NUMBITS(32)
156    ]
157];
158
159const GPT1_BASE: StaticRef<GptRegisters> =
160    unsafe { StaticRef::new(0x401EC000 as *const GptRegisters) };
161const GPT2_BASE: StaticRef<GptRegisters> =
162    unsafe { StaticRef::new(0x401F0000 as *const GptRegisters) };
163
164pub struct Gpt<'a, S> {
165    registers: StaticRef<GptRegisters>,
166    clock: GptClock<'a>,
167    client: OptionalCell<&'a dyn hil::time::AlarmClient>,
168    irqn: u32,
169    _selection: core::marker::PhantomData<S>,
170}
171
172pub type Gpt1<'a> = Gpt<'a, _1>;
173pub type Gpt2<'a> = Gpt<'a, _2>;
174
175impl<'a> Gpt1<'a> {
176    pub const fn new_gpt1(ccm: &'a crate::ccm::Ccm) -> Self {
177        Gpt::new(
178            GPT1_BASE,
179            nvic::GPT1,
180            ccm::PeripheralClock::ccgr1(ccm, ccm::HCLK1::GPT1),
181        )
182    }
183}
184
185impl<'a> Gpt2<'a> {
186    pub const fn new_gpt2(ccm: &'a crate::ccm::Ccm) -> Self {
187        Gpt::new(
188            GPT2_BASE,
189            nvic::GPT2,
190            ccm::PeripheralClock::ccgr0(ccm, ccm::HCLK0::GPT2),
191        )
192    }
193}
194
195impl<'a, S> Gpt<'a, S> {
196    const fn new(
197        registers: StaticRef<GptRegisters>,
198        irqn: u32,
199        clock_gate: ccm::PeripheralClock<'a>,
200    ) -> Self {
201        Gpt {
202            registers,
203            clock: GptClock(clock_gate),
204            client: OptionalCell::empty(),
205            irqn,
206            _selection: core::marker::PhantomData,
207        }
208    }
209
210    pub fn is_enabled_clock(&self) -> bool {
211        self.clock.is_enabled()
212    }
213
214    pub fn enable_clock(&self) {
215        self.clock.enable();
216    }
217
218    pub fn disable_clock(&self) {
219        self.clock.disable();
220    }
221
222    pub fn handle_interrupt(&self) {
223        self.registers.sr.modify(SR::OF1::SET);
224        self.registers.ir.modify(IR::OF1IE::CLEAR);
225
226        self.client.map(|client| client.alarm());
227    }
228
229    /// Start the GPT, specifying the peripheral clock selection and the peripheral clock divider
230    ///
231    /// If you select the crystal oscillator as the periodic clock root, the GPT will divide the
232    /// input clock by 3.
233    ///
234    /// `divider` must be non-zero.
235    pub fn start(&self, selection: ccm::PerclkClockSel, divider: u8) {
236        // Disable GPT and the GPT interrupt register first
237        self.registers.cr.modify(CR::EN::CLEAR);
238
239        self.registers.ir.modify(IR::ROVIE::CLEAR);
240        self.registers.ir.modify(IR::IF1IE::CLEAR);
241        self.registers.ir.modify(IR::IF2IE::CLEAR);
242        self.registers.ir.modify(IR::OF1IE::CLEAR);
243        self.registers.ir.modify(IR::OF2IE::CLEAR);
244        self.registers.ir.modify(IR::OF3IE::CLEAR);
245
246        // Clear Output mode to disconnected
247        self.registers.cr.modify(CR::OM1::CLEAR);
248        self.registers.cr.modify(CR::OM2::CLEAR);
249        self.registers.cr.modify(CR::OM3::CLEAR);
250
251        // Disable Input Capture Mode
252        self.registers.cr.modify(CR::IM1::CLEAR);
253        self.registers.cr.modify(CR::IM2::CLEAR);
254
255        // Reset all the registers to the their default values, except EN,
256        // ENMOD, STOPEN, DOZEEN, WAITEN, and DBGEN bits in the CR
257        self.registers.cr.modify(CR::SWR::SET);
258
259        // wait until registers are cleared
260        while self.registers.cr.is_set(CR::SWR) {}
261
262        // Clear the GPT status register
263        self.registers.sr.set(31_u32);
264
265        // Enable free run mode
266        self.registers.cr.modify(CR::FRR::SET);
267
268        // Enable run in wait mode
269        self.registers.cr.modify(CR::WAITEN::SET);
270
271        // Enable run in stop mode
272        self.registers.cr.modify(CR::STOPEN::SET);
273
274        // Bring GPT counter to 0x00000000
275        self.registers.cr.modify(CR::ENMOD::SET);
276
277        // Set the value of the Output Compare Register
278        self.registers.ocr1.set(0xFFFF_FFFF - 1);
279
280        match selection {
281            ccm::PerclkClockSel::IPG => {
282                // Disable 24Mhz clock input from crystal
283                self.registers.cr.modify(CR::EN_24M::CLEAR);
284
285                // We will use the ipg_clk_highfreq provided by perclk_clk_root,
286                // which runs at 24.75 MHz. Before calling set_alarm, we assume clock
287                // to GPT1 has been enabled.
288                self.registers.cr.modify(CR::CLKSRC.val(0x2_u32));
289
290                // We do not prescale the value for the moment. We will do so
291                // after we will set the ARM_PLL1 CLK accordingly.
292                self.registers.pr.modify(PR::PRESCALER.val(0_u32));
293
294                self.set_frequency(IMXRT1050_IPG_CLOCK_HZ / divider as u32);
295            }
296            ccm::PerclkClockSel::Oscillator => {
297                // Enable 24MHz clock input
298                self.registers
299                    .cr
300                    .modify(CR::EN_24M::SET + CR::CLKSRC::CrystalOscillator);
301
302                // Funknown reasons, the 24HMz prescaler must be non-zero, even
303                // though zero is a valid value according to the reference manual.
304                // If it's not set, the counter doesn't count! Thanks to the se4L
305                // project for adding a comment to their code.
306                //
307                // I'm also finding that it can't be too large; a prescaler of 8
308                // for the 24MHz clock doesn't work!
309                const DEFAULT_PRESCALER: u32 = 3;
310                self.registers
311                    .pr
312                    .write(PR::PRESCALER24M.val(DEFAULT_PRESCALER - 1));
313                self.set_frequency(OSCILLATOR_HZ / DEFAULT_PRESCALER / divider as u32);
314            }
315        }
316
317        // Enable the GPT
318        self.registers.cr.modify(CR::EN::SET);
319
320        // Enable the Output Compare 1 Interrupt Enable
321        self.registers.ir.modify(IR::OF1IE::SET);
322    }
323
324    fn set_frequency(&self, hz: u32) {
325        let idx = match self.irqn {
326            nvic::GPT1 => 0,
327            nvic::GPT2 => 1,
328            _ => unreachable!(),
329        };
330        GPT_FREQUENCIES[idx].store(hz, Ordering::Release);
331    }
332}
333
334/// Assumed IPG clock frequency for the iMXRT1050 processor family.
335///
336/// TODO this is not a constant value; it changes when setting the ARM clock
337/// frequency. Change this after correctly configuring ARM frequency.
338const IMXRT1050_IPG_CLOCK_HZ: u32 = 24_750_000;
339/// Crystal oscillator frequency
340const OSCILLATOR_HZ: u32 = 24_000_000;
341
342/// GPT selection tags
343pub enum _1 {}
344pub enum _2 {}
345
346static GPT_FREQUENCIES: [AtomicU32; 2] = [AtomicU32::new(0), AtomicU32::new(0)];
347
348impl hil::time::Frequency for _1 {
349    fn frequency() -> u32 {
350        GPT_FREQUENCIES[0].load(Ordering::Acquire)
351    }
352}
353
354impl hil::time::Frequency for _2 {
355    fn frequency() -> u32 {
356        GPT_FREQUENCIES[1].load(Ordering::Acquire)
357    }
358}
359
360impl<F: hil::time::Frequency> hil::time::Time for Gpt<'_, F> {
361    type Frequency = F;
362    type Ticks = Ticks32;
363
364    fn now(&self) -> Ticks32 {
365        Ticks32::from(self.registers.cnt.get())
366    }
367}
368
369impl<'a, F: hil::time::Frequency> hil::time::Alarm<'a> for Gpt<'a, F> {
370    fn set_alarm_client(&self, client: &'a dyn hil::time::AlarmClient) {
371        self.client.set(client);
372    }
373
374    fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
375        let mut expire = reference.wrapping_add(dt);
376        let now = self.now();
377        if !now.within_range(reference, expire) {
378            expire = now;
379        }
380
381        if expire.wrapping_sub(now) < self.minimum_dt() {
382            expire = now.wrapping_add(self.minimum_dt());
383        }
384
385        let _ = self.disarm();
386        self.registers.ocr1.set(expire.into_u32());
387        self.registers.ir.modify(IR::OF1IE::SET);
388    }
389
390    fn get_alarm(&self) -> Self::Ticks {
391        Self::Ticks::from(self.registers.ocr1.get())
392    }
393
394    fn disarm(&self) -> Result<(), ErrorCode> {
395        unsafe {
396            atomic(|| {
397                // Disable counter
398                self.registers.ir.modify(IR::OF1IE::CLEAR);
399                cortexm7::nvic::Nvic::new(self.irqn).clear_pending();
400            });
401        }
402        Ok(())
403    }
404
405    fn is_armed(&self) -> bool {
406        // If alarm is enabled, then OF1IE is set
407        self.registers.ir.is_set(IR::OF1IE)
408    }
409
410    fn minimum_dt(&self) -> Self::Ticks {
411        Self::Ticks::from(1)
412    }
413}
414
415struct GptClock<'a>(ccm::PeripheralClock<'a>);
416
417impl ClockInterface for GptClock<'_> {
418    fn is_enabled(&self) -> bool {
419        self.0.is_enabled()
420    }
421
422    fn enable(&self) {
423        self.0.enable();
424    }
425
426    fn disable(&self) {
427        self.0.disable();
428    }
429}