1use crate::time::Hertz;
3use e310x::{Aonclk as AONCLK, Prci as PRCI, CLINT};
4use riscv::interrupt;
5use riscv::register::mcycle;
6
7const PLLREF_MIN: u32 = 6_000_000;
8const PLLREF_MAX: u32 = 48_000_000;
9const REFR_MIN: u32 = 6_000_000;
10const REFR_MAX: u32 = 12_000_000;
11const VCO_MIN: u32 = 384_000_000;
12const VCO_MAX: u32 = 768_000_000;
13const PLLOUT_MIN: u32 = 48_000_000;
14const PLLOUT_MAX: u32 = 384_000_000;
15const DIVOUT_MIN: u32 = 375_000;
16const DIVOUT_MAX: u32 = 384_000_000;
17
18pub trait PrciExt {
20 fn constrain(self) -> CoreClk;
23}
24
25pub trait AonExt {
27 fn constrain(self) -> AonClk;
30}
31
32impl PrciExt for PRCI {
33 fn constrain(self) -> CoreClk {
34 CoreClk {
35 hfxosc: None,
36 coreclk: Hertz(13_800_000), }
38 }
39}
40
41impl AonExt for AONCLK {
42 fn constrain(self) -> AonClk {
43 AonClk { lfaltclk: None }
44 }
45}
46
47pub struct CoreClk {
49 hfxosc: Option<Hertz>,
50 coreclk: Hertz,
51}
52
53impl CoreClk {
54 pub fn use_external<F: Into<Hertz>>(mut self, freq: F) -> Self {
56 let hz: Hertz = freq.into();
57 assert!(hz.0 < 20_000_000);
58
59 self.hfxosc = Some(hz);
60 self
61 }
62
63 pub fn coreclk<F: Into<Hertz>>(mut self, freq: F) -> Self {
65 self.coreclk = freq.into();
66 self
67 }
68
69 pub(crate) fn freeze(self) -> Hertz {
71 let prci = unsafe { PRCI::steal() };
75 let hfrosc_freq = self.configure_hfrosc();
76 prci.pllcfg()
78 .modify(|_, w| w.sel().bit(false).bypass().bit(true));
79
80 if let Some(freq) = self.hfxosc {
81 self.configure_with_external(freq)
82 } else {
83 self.configure_with_internal(hfrosc_freq)
84 }
85 }
86
87 fn configure_with_external(self, source_freq: Hertz) -> Hertz {
89 let prci = unsafe { PRCI::steal() };
90
91 prci.hfxosccfg().write(|w| w.enable().bit(true));
93
94 while !prci.hfxosccfg().read().ready().bit_is_set() {}
96
97 prci.pllcfg().modify(|_, w| w.refsel().bit(true));
99
100 let freq;
101 if source_freq.0 == self.coreclk.0 {
102 freq = source_freq;
104
105 prci.pllcfg().modify(|_, w| w.bypass().bit(true));
107
108 prci.plloutdiv().write(|w| w.divby1().bit(true));
110 } else {
111 freq = self.configure_pll(source_freq, self.coreclk);
115 }
116
117 prci.pllcfg().modify(|_, w| w.sel().bit(true));
119
120 prci.hfrosccfg().write(|w| w.enable().bit(false));
122
123 freq
124 }
125
126 fn configure_with_internal(self, hfrosc_freq: Hertz) -> Hertz {
128 let prci = unsafe { PRCI::steal() };
129
130 let freq;
131 if hfrosc_freq.0 == self.coreclk.0 {
132 freq = hfrosc_freq;
134
135 prci.pllcfg()
137 .modify(|_, w| w.sel().bit(false).bypass().bit(true));
138
139 prci.pllcfg().modify(|_, w| w.bypass().bit(true));
141 } else {
142 freq = self.configure_pll(hfrosc_freq, self.coreclk);
146
147 prci.pllcfg().modify(|_, w| w.sel().bit(true));
149 }
150
151 prci.hfxosccfg().write(|w| w.enable().bit(false));
153
154 freq
155 }
156
157 fn configure_hfrosc(&self) -> Hertz {
159 let prci = unsafe { PRCI::steal() };
160
161 prci.hfrosccfg()
165 .write(|w| unsafe { w.div().bits(4).trim().bits(16).enable().bit(true) });
166
167 while !prci.hfrosccfg().read().ready().bit_is_set() {}
169
170 Hertz(13_800_000)
171 }
172
173 fn configure_pll(&self, pllref_freq: Hertz, divout_freq: Hertz) -> Hertz {
176 let pllref_freq = pllref_freq.0;
177 assert!((PLLREF_MIN..=PLLREF_MAX).contains(&pllref_freq));
178
179 let divout_freq = divout_freq.0;
180 assert!((DIVOUT_MIN..=DIVOUT_MAX).contains(&divout_freq));
181
182 let divider_div;
184 let divider_bypass;
185
186 let d = PLLOUT_MAX / divout_freq;
187 if d > 1 {
188 divider_bypass = false;
189
190 if d > 128 {
191 divider_div = (128 / 2) - 1;
192 } else {
193 divider_div = (d / 2) - 1;
194 }
195 } else {
196 divider_div = 0;
197 divider_bypass = true;
198 }
199
200 let d = if divider_bypass {
202 1
203 } else {
204 2 * (divider_div + 1)
205 };
206 let pllout_freq = divout_freq * d;
207 assert!((PLLOUT_MIN..=PLLOUT_MAX).contains(&pllout_freq));
208
209 let r = match pllref_freq {
211 24_000_000..=48_000_000 => 4,
212 18_000_000..=23_999_999 => 3,
213 12_000_000..=17_999_999 => 2,
214 6_000_000..=11_999_999 => 1,
215 _ => unreachable!(),
216 };
217
218 let refr_freq = pllref_freq / r;
220 assert!((REFR_MIN..=REFR_MAX).contains(&refr_freq));
221
222 let q = match pllout_freq {
224 192_000_000..=384_000_000 => 2,
225 96_000_000..=191_999_999 => 4,
226 48_000_000..=95_999_999 => 8,
227 _ => unreachable!(),
228 };
229
230 let target_vco_freq: u32 = pllout_freq * q;
232 assert!((VCO_MIN..=VCO_MAX).contains(&target_vco_freq));
233
234 let f = target_vco_freq / refr_freq;
236 assert!(f <= 128);
237
238 let f_lo = (f / 2) * 2; let vco_lo = refr_freq * f_lo;
241 let f_hi = f_lo + 2;
242 let vco_hi = refr_freq * f_hi;
243 let (f, vco_freq) = if (f_hi <= 128 && vco_hi <= VCO_MAX)
244 && (target_vco_freq as i32 - vco_hi as i32).abs()
245 < (target_vco_freq as i32 - vco_lo as i32).abs()
246 {
247 (f_hi, vco_hi)
248 } else {
249 (f_lo, vco_lo)
250 };
251 assert!((VCO_MIN..=VCO_MAX).contains(&vco_freq));
252
253 let pllout_freq = vco_freq / q;
255 assert!((PLLOUT_MIN..=PLLOUT_MAX).contains(&pllout_freq));
256
257 let divout_freq = pllout_freq / d;
259 assert!((DIVOUT_MIN..=DIVOUT_MAX).contains(&divout_freq));
260
261 let r: u8 = (r - 1) as u8;
263 let f: u8 = (f / 2 - 1) as u8;
264 let q: u8 = match q {
265 2 => 0b01,
266 4 => 0b10,
267 8 => 0b11,
268 _ => unreachable!(),
269 };
270
271 let prci = unsafe { PRCI::steal() };
273 prci.pllcfg().modify(|_, w| unsafe {
274 w.pllr()
275 .bits(r)
276 .pllf()
277 .bits(f)
278 .pllq()
279 .bits(q)
280 .bypass()
281 .bit(false)
282 });
283
284 prci.plloutdiv()
286 .write(|w| unsafe { w.div().bits(divider_div as u8).divby1().bit(divider_bypass) });
287
288 let mtime = CLINT::mtimer().mtime;
294 let time = mtime.read() + 4;
295 while mtime.read() < time {}
296 while !prci.pllcfg().read().lock().bit_is_set() {}
298
299 Hertz(divout_freq)
300 }
301}
302
303pub struct AonClk {
305 lfaltclk: Option<Hertz>,
306}
307
308impl AonClk {
309 pub fn use_external<F: Into<Hertz>>(mut self, freq: F) -> Self {
311 let hz: Hertz = freq.into();
312 assert!(hz.0 < 500_000);
313
314 self.lfaltclk = Some(hz);
315 self
316 }
317
318 pub(crate) fn freeze(self) -> Hertz {
320 let aonclk = unsafe { AONCLK::steal() };
321
322 if let Some(freq) = self.lfaltclk {
323 aonclk.lfrosccfg().write(|w| w.enable().bit(false));
327
328 freq
329 } else {
330 let trim = 16;
333 let div = 4; aonclk.lfrosccfg().write(|w| unsafe {
337 w.trim().bits(trim);
338 w.div().bits(div);
339 w.enable().bit(true)
340 });
341
342 while !aonclk.lfrosccfg().read().ready().bit_is_set() {}
344
345 Hertz(32_768) }
347 }
348}
349
350#[derive(Clone, Copy)]
355pub struct Clocks {
356 coreclk: Hertz,
357 lfclk: Hertz,
358}
359
360impl Clocks {
361 pub fn freeze(coreclk: CoreClk, aonclk: AonClk) -> Self {
363 let coreclk = coreclk.freeze();
364 let lfclk = aonclk.freeze();
365 Clocks { coreclk, lfclk }
366 }
367
368 pub fn coreclk(&self) -> Hertz {
370 self.coreclk
371 }
372
373 pub fn tlclk(&self) -> Hertz {
375 self.coreclk
378 }
379
380 pub fn lfclk(&self) -> Hertz {
382 self.lfclk
383 }
384
385 fn _measure_coreclk(&self, min_ticks: u64) -> Hertz {
387 let mtime = CLINT::mtimer().mtime;
388 interrupt::free(|| {
389 while mtime.read() == mtime.read() {}
391
392 let start_cycle = mcycle::read64();
393 let start_time = mtime.read();
394
395 while start_time + min_ticks > mtime.read() {}
397
398 let end_cycle = mcycle::read64();
399 let end_time = mtime.read();
400
401 let delta_cycle: u64 = end_cycle - start_cycle;
402 let delta_time: u64 = end_time - start_time;
403
404 let res = (delta_cycle / delta_time) * 32768
405 + ((delta_cycle % delta_time) * 32768) / delta_time;
406 Hertz(res as u32)
408 })
409 }
410
411 pub fn measure_coreclk(&self) -> Hertz {
413 self._measure_coreclk(1);
415 self._measure_coreclk(10)
417 }
418}