1use fugit::MegahertzU32;
4
5use crate::clock::{CLOCK_STATUS, ClockConfig, ClockStatus, HocoFrequency, SystemClockSource};
6use crate::pac::{
7 self,
8 system::vals::{Cksel, Fck, Hcfrq1, Hcstp, Ick, Opcm, Pcka, Pckb, Pckc, Pckd, Sodrv},
9};
10use crate::write_protect::ProtectedPeripheral as _;
11
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13#[derive(Debug, Clone)]
14pub enum UsbClockSource {
15 Pll,
16 Hoco,
17}
18
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21#[derive(Debug, Clone)]
22pub enum PllInput {
23 Mosc,
25}
26
27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29#[allow(missing_docs)]
30#[derive(Debug, Clone)]
31pub enum PllOutDiv {
32 Div2,
33 Div4,
34}
35
36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
38#[allow(missing_docs)]
39#[derive(Debug, Clone)]
40#[repr(u32)]
41pub enum PllOutMul {
42 Mul8,
43 Mul9,
44 Mul10,
45 Mul11,
46 Mul12,
47 Mul13,
48 Mul14,
49 Mul15,
50 Mul16,
51 Mul17,
52 Mul18,
53 Mul19,
54 Mul20,
55 Mul21,
56 Mul22,
57 Mul23,
58 Mul24,
59 Mul25,
60 Mul26,
61 Mul27,
62 Mul28,
63 Mul29,
64 Mul30,
65 Mul31,
66}
67
68impl Default for ClockConfig {
69 fn default() -> Self {
71 Self {
72 system: SystemClockSource::Hoco,
73 hoco: HocoFrequency::_48mhz,
74 mosc: None,
75 sosc: false,
76 pll: None,
77 usb: Some(UsbClockSource::Hoco),
78 }
79 }
80}
81
82pub(crate) fn init(config: ClockConfig) -> Result<(), ()> {
83 let system = pac::SYSTEM;
84
85 #[cfg(feature = "diag")]
86 {
87 use crate::ResetCause;
88
89 let reset_status_0 = system.rstsr0().read();
90 let reset_status_1 = system.rstsr1().read();
91
92 let reset_cause: ResetCause;
93 if reset_status_0.porf() {
94 reset_cause = ResetCause::PowerOn;
95 } else if reset_status_0.lvd0rf() || reset_status_0.lvd1rf() || reset_status_0.lvd2rf() {
96 reset_cause = ResetCause::LowVoltage;
97 } else if reset_status_1.wdtrf() || reset_status_1.iwdtrf() {
98 reset_cause = ResetCause::Watchdog;
99 } else if reset_status_1.rperf()
100 || reset_status_1.reerf()
101 || reset_status_1.bussrf()
102 || reset_status_1.busmrf()
103 {
104 reset_cause = ResetCause::HadwareError;
105 } else if reset_status_1.sperf() {
106 reset_cause = ResetCause::StackPointer;
107 } else if reset_status_1.swrf() {
108 reset_cause = ResetCause::SoftwareReset;
109 } else {
110 reset_cause = ResetCause::Unknown;
111 }
112
113 debug!("Reset reason: {}", reset_cause);
114 }
115
116 trace!(
126 "HOCO: wait={}, status={}",
127 system.hocowtcr().read(),
128 system.hococr().read()
129 );
130
131 system.protected_write(|| {
132 let should_configure = match system.hococr().read().hcstp() {
134 Hcstp::Start => {
135 let frq = system.hococr2().read().hcfrqw();
136 let should_configure = frq != config.hoco.into();
137 if should_configure {
138 system.hococr().write(|w| w.set_hcstp(Hcstp::Stop));
139 }
140 should_configure
141 }
142 Hcstp::Stop => true,
143 };
144
145 if should_configure {
146 system.hococr2().write(|r| r.set_hcfrqw(config.hoco.into()));
147 system.hococr().write(|w| w.set_hcstp(Hcstp::Start));
148 }
149
150 if config.sosc {
151 system.somcr().write(|r| r.set_sodrv(Sodrv::_00));
152 system.sosccr().write(|r| r.set_sostp(false));
153 while system.sosccr().read().sostp() {}
155 }
156
157 let hoco_freq = system.hococr2().read().hcfrqw();
158
159 trace!("Setting high speed mode on");
163 system.opccr().write(|w| w.set_opcm(Opcm::HighSpeed));
164
165 while system.opccr().read().opcmtsf() {}
166
167 if hoco_freq == Hcfrq1::_48mhz || hoco_freq == Hcfrq1::_64mhz {
169 trace!("Setting SYSTEM_MEMWAIT to 1");
170 system.memwait().write(|w| w.set_memwait(true));
171 }
172
173 system.sckscr().write(|w| w.set_cksel(Cksel::Hoco));
175
176 #[cfg(feature = "cache")]
177 {
178 let fcache = pac::FCACHE;
179 fcache.fcacheiv().write(|r| r.set_fcacheiv(true));
180
181 while fcache.fcacheiv().read().fcacheiv() {
182 asm::nop();
183 }
184
185 fcache.fcachee().write(|r| r.set_fcacheen(true));
186
187 info!("SYSTEM: fcache enabled");
188 }
189 #[cfg(not(feature = "cache"))]
190 {
191 let fcache = pac::FCACHE;
192 fcache.fcacheiv().write(|r| r.set_fcacheiv(true));
193 fcache.fcachee().write(|r| r.set_fcacheen(false));
194 trace!("SYSTEM: fcache disabled");
195 }
196
197 match hoco_freq {
205 Hcfrq1::_32mhz => system.sckdivcr().modify(|w| {
206 w.set_ick(Ick::Div1);
208 w.set_fck(Fck::Div1);
210 w.set_pcka(Pcka::Div1);
212 w.set_pckb(Pckb::Div1);
214 w.set_pckc(Pckc::Div1);
216 w.set_pckd(Pckd::Div1);
218 }),
219 Hcfrq1::_48mhz => system.sckdivcr().modify(|w| {
220 w.set_ick(Ick::Div1);
222 w.set_fck(Fck::Div2);
224 w.set_pcka(Pcka::Div1);
226 w.set_pckb(Pckb::Div2);
228 w.set_pckc(Pckc::Div1);
230 w.set_pckd(Pckd::Div1);
232 }),
233 Hcfrq1::_64mhz => system.sckdivcr().modify(|w| {
235 w.set_ick(Ick::Div2);
237 w.set_fck(Fck::Div2);
239 w.set_pcka(Pcka::Div2);
241 w.set_pckb(Pckb::Div2);
243 w.set_pckc(Pckc::Div1);
245 w.set_pckd(Pckd::Div1);
247 }),
248 _ => unimplemented!(),
249 }
250
251 if let Some(UsbClockSource::Hoco) = config.usb {
252 system.usbckcr().write(|w| w.set_usbclksel(true));
254 }
255 });
256
257 {
258 let system = pac::SYSTEM;
259
260 let hoco = system.hococr2().read().hcfrqw();
261 let hoco = match hoco {
262 Hcfrq1::_24mhz => MegahertzU32::from_raw(24),
263 Hcfrq1::_32mhz => MegahertzU32::from_raw(32),
264 Hcfrq1::_48mhz => MegahertzU32::from_raw(48),
265 Hcfrq1::_64mhz => MegahertzU32::from_raw(64),
266 _ => unimplemented!(),
267 }
268 .convert();
269
270 let prescaler = system.sckdivcr().read();
271
272 let system = match prescaler.ick() {
273 Ick::Div1 => hoco,
274 Ick::Div2 => hoco / 2,
275 Ick::Div4 => hoco / 4,
276 Ick::Div8 => hoco / 8,
277 Ick::Div16 => hoco / 16,
278 Ick::Div32 => hoco / 32,
279 Ick::Div64 => hoco / 64,
280 Ick::_RESERVED_7 => unimplemented!("Invalid sckdivcr.ick"),
281 };
282
283 let flash = match prescaler.fck() {
284 Fck::Div1 => hoco,
285 Fck::Div2 => hoco / 2,
286 Fck::Div4 => hoco / 4,
287 Fck::Div8 => hoco / 8,
288 Fck::Div16 => hoco / 16,
289 Fck::Div32 => hoco / 32,
290 Fck::Div64 => hoco / 64,
291 Fck::_RESERVED_7 => unimplemented!("Invalid sckdivcr.fck"),
292 };
293
294 let peripheral_a = match prescaler.pcka() {
295 Pcka::Div1 => hoco,
296 Pcka::Div2 => hoco / 2,
297 Pcka::Div4 => hoco / 4,
298 Pcka::Div8 => hoco / 8,
299 Pcka::Div16 => hoco / 16,
300 Pcka::Div32 => hoco / 32,
301 Pcka::Div64 => hoco / 64,
302 Pcka::_RESERVED_7 => unimplemented!("Invalid sckdivcr.pcka"),
303 };
304
305 let peripheral_b = match prescaler.pckb() {
306 Pckb::Div1 => hoco,
307 Pckb::Div2 => hoco / 2,
308 Pckb::Div4 => hoco / 4,
309 Pckb::Div8 => hoco / 8,
310 Pckb::Div16 => hoco / 16,
311 Pckb::Div32 => hoco / 32,
312 Pckb::Div64 => hoco / 64,
313 Pckb::_RESERVED_7 => unimplemented!("Invalid sckdivcr.pckb"),
314 };
315
316 let peripheral_c = match prescaler.pckc() {
317 Pckc::Div1 => hoco,
318 Pckc::Div2 => hoco / 2,
319 Pckc::Div4 => hoco / 4,
320 Pckc::Div8 => hoco / 8,
321 Pckc::Div16 => hoco / 16,
322 Pckc::Div32 => hoco / 32,
323 Pckc::Div64 => hoco / 64,
324 Pckc::_RESERVED_7 => unimplemented!("Invalid sckdivcr.pckc"),
325 };
326
327 let peripheral_d = match prescaler.pckd() {
328 Pckd::Div1 => hoco,
329 Pckd::Div2 => hoco / 2,
330 Pckd::Div4 => hoco / 4,
331 Pckd::Div8 => hoco / 8,
332 Pckd::Div16 => hoco / 16,
333 Pckd::Div32 => hoco / 32,
334 Pckd::Div64 => hoco / 64,
335 Pckd::_RESERVED_7 => unimplemented!("Invalid sckdivcr.pckd"),
336 };
337
338 let pll = None;
340
341 let usb = match config.usb {
342 Some(UsbClockSource::Hoco) => Some(hoco),
343 Some(UsbClockSource::Pll) => pll,
344 None => None,
345 };
346
347 CLOCK_STATUS
348 .init(ClockStatus {
349 hoco,
350 system,
351 flash,
352 peripheral_a,
353 peripheral_b,
354 peripheral_c,
355 peripheral_d,
356 master: hoco,
357 pll,
358 mosc: config.mosc,
359 sosc: config.sosc,
360 usb,
361 })
362 .or(Err(()))
363 }
364}