1use 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#[derive(Debug)]
25pub struct Freq20MHz;
26impl time::Frequency for Freq20MHz {
27 fn frequency() -> u32 {
28 20_000_000
29 }
30}
31
32#[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 self.registers.t0update.set(0xABC);
200 while self.registers.t0update.get() != 0 {}
201
202 Self::Ticks::from(
203 self.registers.t0lo.get() as u64 + ((self.registers.t0hi.get() as u64) << 32),
204 )
205 }
206}
207
208impl<'a, F: time::Frequency, const C3: bool> Counter<'a> for TimG<'a, F, C3> {
209 fn set_overflow_client(&self, _client: &'a dyn time::OverflowClient) {
210 }
212
213 fn start(&self) -> Result<(), ErrorCode> {
214 self.registers.t0config.write(CONFIG::EN::SET);
215
216 Ok(())
217 }
218
219 fn stop(&self) -> Result<(), ErrorCode> {
220 self.registers.t0config.write(CONFIG::EN::CLEAR);
221
222 Ok(())
223 }
224
225 fn reset(&self) -> Result<(), ErrorCode> {
226 Err(ErrorCode::FAIL)
227 }
228
229 fn is_running(&self) -> bool {
230 self.registers.t0config.is_set(CONFIG::EN)
231 }
232}
233
234impl<'a, F: time::Frequency, const C3: bool> Alarm<'a> for TimG<'a, F, C3> {
235 fn set_alarm_client(&self, client: &'a dyn time::AlarmClient) {
236 self.alarm_client.set(client);
237 }
238
239 fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
240 let now = self.now();
241 let mut expire = reference.wrapping_add(dt);
242 if !now.within_range(reference, expire) {
243 expire = now;
244 }
245
246 self.registers
247 .t0config
248 .modify(CONFIG::ALARM_EN::CLEAR + CONFIG::EN::CLEAR);
249
250 self.registers.t0config.modify(
251 CONFIG::USE_XTAL.val(self.clocksource as u32)
252 + CONFIG::INCREASE::SET
253 + CONFIG::DIVIDER.val(2 * (2 - self.clocksource as u32)),
254 );
255
256 if C3 {
257 self.registers
258 .t0config
259 .modify(CONFIG::EDGE_INT_EN_OR_DIVIDER_RST::SET);
260 }
261
262 let val = expire.into_u64();
263 let high = (val >> 32) as u32;
264 let low = (val & 0xffffffff) as u32;
265
266 self.registers.t0alarmlo.set(0xFFFF_FFFF);
267 self.registers.t0alarmhi.set(high);
268 self.registers.t0alarmlo.set(low);
269
270 if C3 {
271 self.registers.int_c3_ena.modify(INT_C3::T0::SET);
272 } else {
273 self.registers.int_ena.modify(INT::T0::SET);
274 }
275
276 self.registers
277 .t0config
278 .modify(CONFIG::ALARM_EN::SET + CONFIG::EN::SET);
279 }
280
281 fn get_alarm(&self) -> Self::Ticks {
282 Self::Ticks::from(
283 self.registers.t0alarmlo.get() as u64 + ((self.registers.t0alarmhi.get() as u64) << 32),
284 )
285 }
286
287 fn disarm(&self) -> Result<(), ErrorCode> {
288 self.registers.t0config.modify(CONFIG::ALARM_EN::CLEAR);
289
290 Ok(())
291 }
292
293 fn is_armed(&self) -> bool {
294 self.registers.t0config.is_set(CONFIG::ALARM_EN)
295 }
296
297 fn minimum_dt(&self) -> Self::Ticks {
298 Self::Ticks::from(1_u64)
299 }
300}