esp32/
timg.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//! TimG Group driver.
6
7use core::marker::PhantomData;
8
9use kernel::hil::time::{self, Alarm, Counter, Ticks, Ticks64, Time};
10use kernel::utilities::cells::OptionalCell;
11use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
12use kernel::utilities::registers::register_bitfields;
13use kernel::utilities::registers::{register_structs, ReadWrite};
14use kernel::utilities::StaticRef;
15use kernel::ErrorCode;
16
17pub const TIMG0_BASE: StaticRef<TimgRegisters> =
18    unsafe { StaticRef::new(0x6001_F000 as *const TimgRegisters) };
19
20pub const TIMG1_BASE: StaticRef<TimgRegisters> =
21    unsafe { StaticRef::new(0x6002_0000 as *const TimgRegisters) };
22
23/// 20MHz `Frequency`
24#[derive(Debug)]
25pub struct Freq20MHz;
26impl time::Frequency for Freq20MHz {
27    fn frequency() -> u32 {
28        20_000_000
29    }
30}
31
32/// 80MHz `Frequency`
33#[derive(Debug)]
34pub struct Freq80MHz;
35impl time::Frequency for Freq80MHz {
36    fn frequency() -> u32 {
37        80_000_000
38    }
39}
40
41register_structs! {
42    pub TimgRegisters {
43        (0x000 => t0config: ReadWrite<u32, CONFIG::Register>),
44        (0x004 => t0lo: ReadWrite<u32>),
45        (0x008 => t0hi: ReadWrite<u32>),
46        (0x00C => t0update: ReadWrite<u32>),
47        (0x010 => t0alarmlo: ReadWrite<u32>),
48        (0x014 => t0alarmhi: ReadWrite<u32>),
49        (0x018 => t0loadlo: ReadWrite<u32>),
50        (0x01C => t0loadhi: ReadWrite<u32>),
51        (0x020 => t0load: ReadWrite<u32>),
52
53        (0x024 => t1config: ReadWrite<u32, CONFIG::Register>),
54        (0x028 => t1lo: ReadWrite<u32>),
55        (0x02C => t1hi: ReadWrite<u32>),
56        (0x030 => t1update: ReadWrite<u32>),
57        (0x034 => t1alarmlo: ReadWrite<u32>),
58        (0x038 => t1alarmhi: ReadWrite<u32>),
59        (0x03C => t1loadlo: ReadWrite<u32>),
60        (0x040 => _reserved1),
61        (0x044 => t1load: ReadWrite<u32>),
62
63        (0x048 => wdtconfig0: ReadWrite<u32, WDTCONFIG0::Register>),
64        (0x04C => wdtconfig1: ReadWrite<u32, WDTCONFIG1::Register>),
65        (0x050 => wdtconfig2: ReadWrite<u32>),
66        (0x054 => wdtconfig3: ReadWrite<u32>),
67        (0x058 => wdtconfig4: ReadWrite<u32>),
68        (0x05C => wdtconfig5: ReadWrite<u32>),
69        (0x060 => wdtfeed: ReadWrite<u32>),
70        (0x064 => wdtwprotect: ReadWrite<u32>),
71
72        (0x068 => rtccalicfg: ReadWrite<u32, RTCCALICFG::Register>),
73        (0x06C => rtccalicfg1: ReadWrite<u32, RTCCALICFG1::Register>),
74
75        (0x070 => int_c3_ena: ReadWrite<u32, INT_C3::Register>),
76        (0x074 => int_c3_raw: ReadWrite<u32, INT_C3::Register>),
77        (0x078 => int_c3_st: ReadWrite<u32, INT_C3::Register>),
78        (0x07C => int_c3_clr: ReadWrite<u32, INT_C3::Register>),
79
80        (0x080 => _reserved2),
81
82        (0x098 => int_ena: ReadWrite<u32, INT::Register>),
83        (0x09C => int_raw: ReadWrite<u32, INT::Register>),
84        (0x0A0 => int_st: ReadWrite<u32, INT::Register>),
85        (0x0A4 => int_clr: ReadWrite<u32, INT::Register>),
86        (0x0A8 => @END),
87    }
88}
89
90register_bitfields![u32,
91    CONFIG [
92        USE_XTAL OFFSET(9) NUMBITS(1) [],
93        ALARM_EN OFFSET(10) NUMBITS(1) [],
94        LEVEL_INT_EN OFFSET(11) NUMBITS(1) [],
95        EDGE_INT_EN_OR_DIVIDER_RST OFFSET(12) NUMBITS(1) [],
96        DIVIDER OFFSET(13) NUMBITS(16) [],
97        AUTORELOAD OFFSET(29) NUMBITS(1) [],
98        INCREASE OFFSET(30) NUMBITS(1) [],
99        EN OFFSET(31) NUMBITS(1) [],
100    ],
101    WDTCONFIG0 [
102        APP_CPU_RESET_EN OFFSET(12) NUMBITS(1) [],
103        PROC_CPU_RESET_EN OFFSET(13) NUMBITS(1) [],
104        FLASHBOOT_MOD_EN OFFSET(14) NUMBITS(1) [],
105        SYS_RESET_LENGTH OFFSET(15) NUMBITS(3) [],
106        CPU_RESET_LENGTH OFFSET(18) NUMBITS(3) [],
107        LEVEL_INT_EN_OR_USE_XTAL OFFSET(21) NUMBITS(1) [],
108        EDGE_INT_EN_OR_UPDATE_EN OFFSET(22) NUMBITS(1) [],
109        STG3 OFFSET(23) NUMBITS(2) [],
110        STG2 OFFSET(25) NUMBITS(2) [],
111        STG1 OFFSET(27) NUMBITS(2) [],
112        STG0 OFFSET(29) NUMBITS(2) [],
113        EN OFFSET(31) NUMBITS(1) [],
114    ],
115    WDTCONFIG1 [
116        DIVCNT_RST OFFSET(0) NUMBITS(1) [],
117        CLK_PRESCALE OFFSET(16) NUMBITS(16) [],
118    ],
119    RTCCALICFG [
120        START_CYCLING OFFSET(12) NUMBITS(1) [],
121        CLK_SEL OFFSET(13) NUMBITS(2) [],
122        RDY OFFSET(15) NUMBITS(1) [],
123        MAX OFFSET(16) NUMBITS(15) [],
124        START OFFSET(31) NUMBITS(1) [],
125    ],
126    RTCCALICFG1 [
127        CYCLING_DATA_VLD OFFSET(0) NUMBITS(1) [],
128        VALUE OFFSET(7) NUMBITS(25) [],
129    ],
130    INT_C3 [
131        T0 OFFSET(0) NUMBITS(1) [],
132        WDT OFFSET(1) NUMBITS(1) [],
133    ],
134    INT [
135        T0 OFFSET(0) NUMBITS(1) [],
136        T1 OFFSET(1) NUMBITS(1) [],
137        WDT OFFSET(2) NUMBITS(1) [],
138    ],
139];
140
141#[derive(Copy, Clone)]
142pub enum ClockSource {
143    Pll = 0,
144    Xtal = 1,
145}
146
147pub struct TimG<'a, F: time::Frequency, const C3: bool> {
148    registers: StaticRef<TimgRegisters>,
149    clocksource: ClockSource,
150    alarm_client: OptionalCell<&'a dyn time::AlarmClient>,
151    _phantom: PhantomData<F>,
152}
153
154impl<F: time::Frequency, const C3: bool> TimG<'_, F, C3> {
155    pub const fn new(base: StaticRef<TimgRegisters>, clocksource: ClockSource) -> Self {
156        TimG {
157            registers: base,
158            clocksource,
159            alarm_client: OptionalCell::empty(),
160            _phantom: PhantomData,
161        }
162    }
163
164    pub fn handle_interrupt(&self) {
165        if C3 {
166            self.registers.int_c3_clr.modify(INT_C3::T0::SET);
167        } else {
168            self.registers.int_clr.modify(INT::T0::SET);
169        }
170        let _ = self.stop();
171        self.alarm_client.map(|client| {
172            client.alarm();
173        });
174    }
175
176    pub fn disable_wdt(&self) {
177        self.registers
178            .wdtconfig0
179            .modify(WDTCONFIG0::EN::CLEAR + WDTCONFIG0::FLASHBOOT_MOD_EN::CLEAR);
180
181        if self.registers.wdtconfig0.is_set(WDTCONFIG0::EN)
182            || self
183                .registers
184                .wdtconfig0
185                .is_set(WDTCONFIG0::FLASHBOOT_MOD_EN)
186        {
187            panic!("Can't disable TIMG WDT");
188        }
189    }
190}
191
192impl<F: time::Frequency, const C3: bool> time::Time for TimG<'_, F, C3> {
193    type Frequency = F;
194    type Ticks = Ticks64;
195
196    fn now(&self) -> Self::Ticks {
197        // a write (of any value) to T0UPDATE stores the
198        // current counter value to T0LO and T0HI
199        self.registers.t0update.set(0xABC);
200        Self::Ticks::from(
201            self.registers.t0lo.get() as u64 + ((self.registers.t0hi.get() as u64) << 32),
202        )
203    }
204}
205
206impl<'a, F: time::Frequency, const C3: bool> Counter<'a> for TimG<'a, F, C3> {
207    fn set_overflow_client(&self, _client: &'a dyn time::OverflowClient) {
208        // We have no way to know when this happens
209    }
210
211    fn start(&self) -> Result<(), ErrorCode> {
212        self.registers.t0config.write(CONFIG::EN::SET);
213
214        Ok(())
215    }
216
217    fn stop(&self) -> Result<(), ErrorCode> {
218        self.registers.t0config.write(CONFIG::EN::CLEAR);
219
220        Ok(())
221    }
222
223    fn reset(&self) -> Result<(), ErrorCode> {
224        Err(ErrorCode::FAIL)
225    }
226
227    fn is_running(&self) -> bool {
228        self.registers.t0config.is_set(CONFIG::EN)
229    }
230}
231
232impl<'a, F: time::Frequency, const C3: bool> Alarm<'a> for TimG<'a, F, C3> {
233    fn set_alarm_client(&self, client: &'a dyn time::AlarmClient) {
234        self.alarm_client.set(client);
235    }
236
237    fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
238        let now = self.now();
239        let mut expire = reference.wrapping_add(dt);
240        if !now.within_range(reference, expire) {
241            expire = now;
242        }
243
244        self.registers
245            .t0config
246            .modify(CONFIG::ALARM_EN::CLEAR + CONFIG::EN::CLEAR);
247
248        self.registers.t0config.modify(
249            CONFIG::USE_XTAL.val(self.clocksource as u32)
250                + CONFIG::INCREASE::SET
251                + CONFIG::DIVIDER.val(2 * (2 - self.clocksource as u32)),
252        );
253
254        if C3 {
255            self.registers
256                .t0config
257                .modify(CONFIG::EDGE_INT_EN_OR_DIVIDER_RST::SET);
258        }
259
260        let val = expire.into_u64();
261        let high = (val >> 32) as u32;
262        let low = (val & 0xffffffff) as u32;
263
264        self.registers.t0alarmlo.set(0xFFFF_FFFF);
265        self.registers.t0alarmhi.set(high);
266        self.registers.t0alarmlo.set(low);
267
268        if C3 {
269            self.registers.int_c3_ena.modify(INT_C3::T0::SET);
270        } else {
271            self.registers.int_ena.modify(INT::T0::SET);
272        }
273
274        self.registers
275            .t0config
276            .modify(CONFIG::ALARM_EN::SET + CONFIG::EN::SET);
277    }
278
279    fn get_alarm(&self) -> Self::Ticks {
280        Self::Ticks::from(
281            self.registers.t0alarmlo.get() as u64 + ((self.registers.t0alarmhi.get() as u64) << 32),
282        )
283    }
284
285    fn disarm(&self) -> Result<(), ErrorCode> {
286        self.registers.t0config.modify(CONFIG::ALARM_EN::CLEAR);
287
288        Ok(())
289    }
290
291    fn is_armed(&self) -> bool {
292        self.registers.t0config.is_set(CONFIG::ALARM_EN)
293    }
294
295    fn minimum_dt(&self) -> Self::Ticks {
296        Self::Ticks::from(1_u64)
297    }
298}