1use core::{cmp::min, convert::TryFrom};
9use embedded_time::rate::Extensions;
10
11use crate::typestates::{
12 main_clock::MainClock,
13 ClocksSupport1MhzFroToken,
14 ClocksSupport32KhzFroToken,
15 ClocksSupportFlexcommToken,
17 ClocksSupportTouchToken,
18 ClocksSupportUsbfsToken,
19 ClocksSupportUsbhsToken,
20 ClocksSupportUtickToken,
21};
22use crate::{
23 peripherals::{anactrl::Anactrl, pmc::Pmc, syscon::Syscon},
24 time::{Hertz, Megahertz},
25};
26
27const MIN_USBFS_FREQ: Megahertz = Megahertz(24);
36const MIN_USBHS_FREQ: Megahertz = Megahertz(96);
37const DEFAULT_FREQ: Megahertz = Megahertz(12);
38
39#[derive(Debug, Default)]
40pub struct ClockRequirements {
41 pub system_frequency: Option<Megahertz>,
42 pub custom_pll: Option<Pll>,
43}
44
45#[derive(Debug, Copy, Clone)]
46pub struct Clocks {
47 pub(crate) main_clock: MainClock,
48 pub(crate) system_frequency: Hertz,
49}
50
51impl Clocks {
52 pub fn support_flexcomm_token(&self) -> Option<ClocksSupportFlexcommToken> {
53 Some(ClocksSupportFlexcommToken { __: () })
54 }
55
56 pub fn support_usbfs_token(&self) -> Option<ClocksSupportUsbfsToken> {
57 let fast_enough = self.system_frequency >= Hertz::from(MIN_USBFS_FREQ);
58 let can_latch_sof = self.main_clock == MainClock::Fro96Mhz;
59
60 if fast_enough && can_latch_sof {
61 Some(ClocksSupportUsbfsToken { __: () })
62 } else {
63 None
64 }
65 }
66
67 pub fn support_usbhs_token(&self) -> Option<ClocksSupportUsbhsToken> {
68 let fast_enough = self.system_frequency >= Hertz::from(MIN_USBHS_FREQ);
69 if fast_enough {
70 Some(ClocksSupportUsbhsToken { __: () })
71 } else {
72 None
73 }
74 }
75
76 pub fn support_utick_token(&self) -> Option<ClocksSupportUtickToken> {
77 Some(ClocksSupportUtickToken { __: () })
78 }
79
80 pub fn support_1mhz_fro_token(&self) -> Option<ClocksSupport1MhzFroToken> {
81 Some(ClocksSupport1MhzFroToken { __: () })
82 }
83
84 pub fn support_touch_token(&self) -> Option<ClocksSupportTouchToken> {
85 if self.system_frequency.0 >= 96 {
86 Some(ClocksSupportTouchToken { __: () })
87 } else {
88 None
89 }
90 }
91
92 pub fn enable_32k_fro(&self, pmc: &mut Pmc) -> ClocksSupport32KhzFroToken {
93 let mut token = ClocksSupport32KhzFroToken { __: () };
94 pmc.power_on(&mut token);
95 token
96 }
97}
98
99#[derive(Debug)]
107pub struct Pll {
108 n: u8,
109 m: u16,
110 p: u8,
111 selp: u8,
112 seli: u8,
113}
114
115impl Pll {
116 pub unsafe fn new(n: u8, m: u16, p: u8) -> Pll {
121 let selp = min((m >> 2) + 1, 31) as u8;
123 let seli = min(
124 63,
125 match m {
126 m if m >= 8000 => 1,
127 m if m >= 122 => 8000 / m,
128 _ => 2 * (m >> 2) + 3,
129 },
130 ) as u8;
131 Pll {
133 n,
134 m,
135 p,
136 selp,
137 seli,
138 }
139 }
140}
141
142static mut CONFIGURED: bool = false;
143
144#[derive(Debug)]
145pub enum ClocksError {
146 AlreadyConfigured,
148 NotFeasible,
149}
150
151pub type Result<T> = core::result::Result<T, ClocksError>;
152
153impl ClockRequirements {
158 pub fn system_frequency<Freq>(mut self, freq: Freq) -> Self
159 where
160 Freq: Into<Megahertz>,
161 {
162 self.system_frequency = Some(freq.into());
163 self
164 }
165
166 fn get_pll(freq: u32) -> Pll {
169 debug_assert!(freq >= 5);
170 debug_assert!(freq <= 150);
171 for n in 1..=6 {
178 for p in 1..=30 {
179 for m in 1..=255 {
180 if 2 * freq * n * p == 12 * m {
182 let selp = (m >> 2) + 1; let seli = 2 * (m >> 2) + 3; return Pll {
186 n: n as u8,
188 m: m as u16,
189 p: p as u8,
191 selp: selp as u8,
192 seli: seli as u8,
193 };
194 }
195 }
196 }
197 }
198
199 unreachable!();
200 }
201
202 fn configure_pll0(pll: Pll, pmc: &mut Pmc, syscon: &mut Syscon) {
203 pmc.raw
204 .pdruncfg0
205 .modify(|_, w| w.pden_pll0().poweredoff().pden_pll0_sscg().poweredoff());
206
207 syscon.raw.pll0ctrl.write(|w| unsafe {
208 w.clken()
209 .enable()
210 .seli()
211 .bits(pll.seli)
212 .selp()
213 .bits(pll.selp)
214 });
215
216 syscon
217 .raw
218 .pll0ndec
219 .write(|w| unsafe { w.ndiv().bits(pll.n) });
220 syscon.raw.pll0ndec.write(|w| unsafe {
221 w.ndiv().bits(pll.n).nreq().set_bit() });
223
224 syscon
225 .raw
226 .pll0pdec
227 .write(|w| unsafe { w.pdiv().bits(pll.p) });
228 syscon.raw.pll0pdec.write(|w| unsafe {
229 w.pdiv().bits(pll.p).preq().set_bit() });
231
232 syscon
233 .raw
234 .pll0sscg0
235 .write(|w| unsafe { w.md_lbs().bits(0) });
236
237 syscon
238 .raw
239 .pll0sscg1
240 .write(|w| unsafe { w.mdiv_ext().bits(pll.m).sel_ext().set_bit() });
241 syscon.raw.pll0sscg1.write(|w| unsafe {
242 w.mdiv_ext()
243 .bits(pll.m)
244 .sel_ext()
245 .set_bit()
246 .mreq()
247 .set_bit() .md_req()
249 .set_bit() });
251
252 pmc.raw
253 .pdruncfg0
254 .modify(|_, w| w.pden_pll0().poweredon().pden_pll0_sscg().poweredon());
255
256 crate::wait_at_least(6_000);
258 }
259
260 fn get_clock_source_and_div_for_freq(
261 freq: Megahertz,
262 pmc: &mut Pmc,
263 syscon: &mut Syscon,
264 ) -> (MainClock, u8) {
265 let (main_clock, sys_divider) = match freq {
266 freq if freq <= 12_u32.MHz() && 12 % freq.0 == 0 => (MainClock::Fro12Mhz, 12 / freq.0),
267 freq if freq <= 96_u32.MHz() && 96 % freq.0 == 0 => (MainClock::Fro96Mhz, 96 / freq.0),
268 freq if freq == 150_u32.MHz() => {
297 syscon.raw.pll0clksel.write(|w| {
298 w.sel().enum_0x0() });
300 Self::configure_pll0(
301 Pll {
302 n: 8,
303 m: 200,
304 p: 1,
305 selp: 31,
306 seli: 53,
307 },
308 pmc,
309 syscon,
310 );
311 (MainClock::Pll0, 1)
312 }
313
314 _ => {
315 let pll = Self::get_pll(freq.0);
316 syscon.raw.pll0clksel.write(|w| {
317 w.sel().enum_0x0() });
319 Self::configure_pll0(pll, pmc, syscon);
320 (MainClock::Pll0, 1)
321 }
322 };
323 debug_assert!(sys_divider < 256);
324 (main_clock, sys_divider as u8)
325 }
326
327 fn set_new_clock_source(
328 freq: Megahertz,
329 main_clock: MainClock,
330 sys_divider: u8,
331 syscon: &mut Syscon,
332 ) {
333 syscon
335 .raw
336 .fmccr
337 .modify(|_, w| unsafe { w.flashtim().bits(11) });
338
339 match main_clock {
340 MainClock::Fro12Mhz => {
341 syscon.raw.mainclksela.modify(|_, w| w.sel().enum_0x0());
343 syscon.raw.mainclkselb.modify(|_, w| w.sel().enum_0x0());
345 unsafe {
346 syscon
347 .raw
348 .ahbclkdiv
349 .modify(|_, w| w.div().bits(sys_divider - 1))
350 };
351 }
352 MainClock::Fro96Mhz => {
353 syscon.raw.mainclksela.modify(|_, w| w.sel().enum_0x3());
355 syscon.raw.mainclkselb.modify(|_, w| w.sel().enum_0x0());
357 unsafe {
358 syscon
359 .raw
360 .ahbclkdiv
361 .modify(|_, w| w.div().bits(sys_divider - 1))
362 };
363 }
364 MainClock::Pll0 => {
365 syscon.raw.mainclksela.modify(|_, w| w.sel().enum_0x0());
367 syscon.raw.mainclkselb.modify(|_, w| w.sel().enum_0x1());
369 unsafe {
370 syscon
371 .raw
372 .ahbclkdiv
373 .modify(|_, w| w.div().bits(sys_divider - 1))
374 };
375 }
376 }
377
378 match freq.0 {
380 0..=99 => {
381 unsafe {
382 syscon
383 .raw
384 .fmccr
385 .modify(|_, w| w.flashtim().bits((freq.0 / 11) as u8 - 1))
386 };
387 }
388 100..=115 => {
389 unsafe { syscon.raw.fmccr.modify(|_, w| w.flashtim().bits(9)) };
390 }
391 116..=130 => {
392 unsafe { syscon.raw.fmccr.modify(|_, w| w.flashtim().bits(10)) };
393 }
394 _ => {
395 unsafe { syscon.raw.fmccr.modify(|_, w| w.flashtim().bits(11)) };
396 }
397 }
398 }
399
400 pub fn configure(
405 self,
406 anactrl: &mut Anactrl,
407 pmc: &mut Pmc,
408 syscon: &mut Syscon,
409 ) -> Result<Clocks> {
410 if unsafe { CONFIGURED } {
411 return Err(ClocksError::AlreadyConfigured);
412 }
413
414 let freq: Megahertz = self.system_frequency.unwrap_or(DEFAULT_FREQ);
415
416 anactrl
422 .raw
423 .fro192m_ctrl
424 .modify(|_, w| w.ena_96mhzclk().enable());
425 anactrl
426 .raw
427 .fro192m_ctrl
428 .modify(|_, w| w.ena_12mhzclk().enable());
429
430 syscon
431 .raw
432 .clock_ctrl
433 .modify(|_, w| w.fro1mhz_clk_ena().enable().fro1mhz_utick_ena().enable());
434
435 let (main_clock, sys_divider) = Self::get_clock_source_and_div_for_freq(freq, pmc, syscon);
436 Self::set_new_clock_source(freq, main_clock, sys_divider, syscon);
437
438 unsafe { CONFIGURED = true };
439
440 Ok(Clocks {
441 main_clock,
442 system_frequency: Hertz::try_from(freq).unwrap(),
443 })
444 }
445
446 pub unsafe fn reconfigure(self, _clocks: Clocks, pmc: &mut Pmc, syscon: &mut Syscon) -> Clocks {
453 let freq: Megahertz = self.system_frequency.unwrap_or(DEFAULT_FREQ);
454
455 let (main_clock, sys_divider) = Self::get_clock_source_and_div_for_freq(freq, pmc, syscon);
456
457 Self::set_new_clock_source(freq, main_clock, sys_divider, syscon);
458
459 Clocks {
460 main_clock,
461 system_frequency: Hertz::try_from(freq).unwrap(),
462 }
463 }
464}