1pub use crate::pac::pwr::vals::Vos as VoltageScale;
2#[cfg(all(peri_usb_otg_hs))]
3pub use crate::pac::rcc::vals::Otghssel;
4pub use crate::pac::rcc::vals::{
5 Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul,
6 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
7};
8use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge};
9#[cfg(all(peri_usb_otg_hs))]
10pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
11use crate::pac::{FLASH, PWR, RCC};
12use crate::rcc::LSI_FREQ;
13use crate::time::Hertz;
14
15/// HSI speed
16pub const HSI_FREQ: Hertz = Hertz(16_000_000);
17
18#[derive(Clone, Copy, Eq, PartialEq)]
19pub enum HseMode {
20 /// crystal/ceramic oscillator (HSEBYP=0)
21 Oscillator,
22 /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
23 Bypass,
24 /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
25 BypassDigital,
26}
27
28#[derive(Clone, Copy, Eq, PartialEq)]
29pub struct Hse {
30 /// HSE frequency.
31 pub freq: Hertz,
32 /// HSE mode.
33 pub mode: HseMode,
34}
35
36#[derive(Clone, Copy)]
37pub struct Pll {
38 /// The clock source for the PLL.
39 pub source: PllSource,
40 /// The PLL pre-divider.
41 ///
42 /// The clock speed of the `source` divided by `m` must be between 4 and 16 MHz.
43 pub prediv: PllPreDiv,
44 /// The PLL multiplier.
45 ///
46 /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544
47 /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`.
48 pub mul: PllMul,
49 /// The divider for the P output.
50 ///
51 /// The P output is one of several options
52 /// that can be used to feed the SAI/MDF/ADF Clock mux's.
53 pub divp: Option<PllDiv>,
54 /// The divider for the Q output.
55 ///
56 /// The Q ouput is one of severals options that can be used to feed the 48MHz clocks
57 /// and the OCTOSPI clock. It may also be used on the MDF/ADF clock mux's.
58 pub divq: Option<PllDiv>,
59 /// The divider for the R output.
60 ///
61 /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r`
62 /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default
63 /// `Config { voltage_range }`.
64 pub divr: Option<PllDiv>,
65}
66
67#[derive(Clone, Copy)]
68pub struct Config {
69 // base clock sources
70 pub msis: Option<MSIRange>,
71 pub msik: Option<MSIRange>,
72 pub hsi: bool,
73 pub hse: Option<Hse>,
74 pub hsi48: Option<super::Hsi48Config>,
75
76 // pll
77 pub pll1: Option<Pll>,
78 pub pll2: Option<Pll>,
79 pub pll3: Option<Pll>,
80
81 // sysclk, buses.
82 pub sys: Sysclk,
83 pub ahb_pre: AHBPrescaler,
84 pub apb1_pre: APBPrescaler,
85 pub apb2_pre: APBPrescaler,
86 pub apb3_pre: APBPrescaler,
87
88 /// The voltage range influences the maximum clock frequencies for different parts of the
89 /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks
90 /// exceeding 55 MHz require at least `RANGE2`.
91 ///
92 /// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits.
93 pub voltage_range: VoltageScale,
94 pub ls: super::LsConfig,
95
96 /// Per-peripheral kernel clock selection muxes
97 pub mux: super::mux::ClockMux,
98}
99
100impl Default for Config {
101 fn default() -> Self {
102 Self {
103 msis: Some(Msirange::RANGE_4MHZ),
104 msik: Some(Msirange::RANGE_4MHZ),
105 hse: None,
106 hsi: false,
107 hsi48: Some(Default::default()),
108 pll1: None,
109 pll2: None,
110 pll3: None,
111 sys: Sysclk::MSIS,
112 ahb_pre: AHBPrescaler::DIV1,
113 apb1_pre: APBPrescaler::DIV1,
114 apb2_pre: APBPrescaler::DIV1,
115 apb3_pre: APBPrescaler::DIV1,
116 voltage_range: VoltageScale::RANGE1,
117 ls: Default::default(),
118 mux: Default::default(),
119 }
120 }
121}
122
123pub(crate) unsafe fn init(config: Config) {
124 // Set the requested power mode
125 PWR.vosr().modify(|w| w.set_vos(config.voltage_range));
126 while !PWR.vosr().read().vosrdy() {}
127
128 let msis = config.msis.map(|range| {
129 // Check MSI output per RM0456 § 11.4.10
130 match config.voltage_range {
131 VoltageScale::RANGE4 => {
132 assert!(msirange_to_hertz(range).0 <= 24_000_000);
133 }
134 _ => {}
135 }
136
137 // RM0456 § 11.8.2: spin until MSIS is off or MSIS is ready before setting its range
138 loop {
139 let cr = RCC.cr().read();
140 if cr.msison() == false || cr.msisrdy() == true {
141 break;
142 }
143 }
144
145 RCC.icscr1().modify(|w| {
146 w.set_msisrange(range);
147 w.set_msirgsel(Msirgsel::ICSCR1);
148 });
149 RCC.cr().write(|w| {
150 w.set_msipllen(false);
151 w.set_msison(true);
152 });
153 while !RCC.cr().read().msisrdy() {}
154 msirange_to_hertz(range)
155 });
156
157 let msik = config.msik.map(|range| {
158 // Check MSI output per RM0456 § 11.4.10
159 match config.voltage_range {
160 VoltageScale::RANGE4 => {
161 assert!(msirange_to_hertz(range).0 <= 24_000_000);
162 }
163 _ => {}
164 }
165
166 // RM0456 § 11.8.2: spin until MSIS is off or MSIS is ready before setting its range
167 loop {
168 let cr = RCC.cr().read();
169 if cr.msikon() == false || cr.msikrdy() == true {
170 break;
171 }
172 }
173
174 RCC.icscr1().modify(|w| {
175 w.set_msikrange(range);
176 w.set_msirgsel(Msirgsel::ICSCR1);
177 });
178 RCC.cr().write(|w| {
179 w.set_msikon(true);
180 });
181 while !RCC.cr().read().msikrdy() {}
182 msirange_to_hertz(range)
183 });
184
185 let hsi = config.hsi.then(|| {
186 RCC.cr().write(|w| w.set_hsion(true));
187 while !RCC.cr().read().hsirdy() {}
188
189 HSI_FREQ
190 });
191
192 let hse = config.hse.map(|hse| {
193 // Check frequency limits per RM456 § 11.4.10
194 match config.voltage_range {
195 VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => {
196 assert!(hse.freq.0 <= 50_000_000);
197 }
198 VoltageScale::RANGE4 => {
199 assert!(hse.freq.0 <= 25_000_000);
200 }
201 }
202
203 // Enable HSE, and wait for it to stabilize
204 RCC.cr().write(|w| {
205 w.set_hseon(true);
206 w.set_hsebyp(hse.mode != HseMode::Oscillator);
207 w.set_hseext(match hse.mode {
208 HseMode::Oscillator | HseMode::Bypass => Hseext::ANALOG,
209 HseMode::BypassDigital => Hseext::DIGITAL,
210 });
211 });
212 while !RCC.cr().read().hserdy() {}
213
214 hse.freq
215 });
216
217 let hsi48 = config.hsi48.map(super::init_hsi48);
218
219 let pll_input = PllInput { hse, hsi, msi: msis };
220 let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range);
221 let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range);
222 let pll3 = init_pll(PllInstance::Pll3, config.pll3, &pll_input, config.voltage_range);
223
224 let sys_clk = match config.sys {
225 Sysclk::HSE => hse.unwrap(),
226 Sysclk::HSI => hsi.unwrap(),
227 Sysclk::MSIS => msis.unwrap(),
228 Sysclk::PLL1_R => pll1.r.unwrap(),
229 };
230
231 // Do we need the EPOD booster to reach the target clock speed per § 10.5.4?
232 if sys_clk >= Hertz::mhz(55) {
233 // Enable the booster
234 PWR.vosr().modify(|w| w.set_boosten(true));
235 while !PWR.vosr().read().boostrdy() {}
236 }
237
238 // The clock source is ready
239 // Calculate and set the flash wait states
240 let wait_states = match config.voltage_range {
241 // VOS 1 range VCORE 1.26V - 1.40V
242 VoltageScale::RANGE1 => match sys_clk.0 {
243 ..=32_000_000 => 0,
244 ..=64_000_000 => 1,
245 ..=96_000_000 => 2,
246 ..=128_000_000 => 3,
247 _ => 4,
248 },
249 // VOS 2 range VCORE 1.15V - 1.26V
250 VoltageScale::RANGE2 => match sys_clk.0 {
251 ..=30_000_000 => 0,
252 ..=60_000_000 => 1,
253 ..=90_000_000 => 2,
254 _ => 3,
255 },
256 // VOS 3 range VCORE 1.05V - 1.15V
257 VoltageScale::RANGE3 => match sys_clk.0 {
258 ..=24_000_000 => 0,
259 ..=48_000_000 => 1,
260 _ => 2,
261 },
262 // VOS 4 range VCORE 0.95V - 1.05V
263 VoltageScale::RANGE4 => match sys_clk.0 {
264 ..=12_000_000 => 0,
265 _ => 1,
266 },
267 };
268 FLASH.acr().modify(|w| {
269 w.set_latency(wait_states);
270 });
271
272 // Switch the system clock source
273 RCC.cfgr1().modify(|w| w.set_sw(config.sys));
274 while RCC.cfgr1().read().sws() != config.sys {}
275
276 // Configure the bus prescalers
277 RCC.cfgr2().modify(|w| {
278 w.set_hpre(config.ahb_pre);
279 w.set_ppre1(config.apb1_pre);
280 w.set_ppre2(config.apb2_pre);
281 });
282 RCC.cfgr3().modify(|w| {
283 w.set_ppre3(config.apb3_pre);
284 });
285
286 let hclk = sys_clk / config.ahb_pre;
287
288 let hclk_max = match config.voltage_range {
289 VoltageScale::RANGE1 => Hertz::mhz(160),
290 VoltageScale::RANGE2 => Hertz::mhz(110),
291 VoltageScale::RANGE3 => Hertz::mhz(55),
292 VoltageScale::RANGE4 => Hertz::mhz(25),
293 };
294 assert!(hclk <= hclk_max);
295
296 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
297 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre);
298 let (pclk3, _) = super::util::calc_pclk(hclk, config.apb3_pre);
299
300 let rtc = config.ls.init();
301
302 #[cfg(all(stm32u5, peri_usb_otg_hs))]
303 let usb_refck = match config.mux.otghssel {
304 Otghssel::HSE => hse,
305 Otghssel::HSE_DIV_2 => hse.map(|hse_val| hse_val / 2u8),
306 Otghssel::PLL1_P => pll1.p,
307 Otghssel::PLL1_P_DIV_2 => pll1.p.map(|pll1p_val| pll1p_val / 2u8),
308 };
309 #[cfg(all(stm32u5, peri_usb_otg_hs))]
310 let usb_refck_sel = match usb_refck {
311 Some(clk_val) => match clk_val {
312 Hertz(16_000_000) => Usbrefcksel::MHZ16,
313 Hertz(19_200_000) => Usbrefcksel::MHZ19_2,
314 Hertz(20_000_000) => Usbrefcksel::MHZ20,
315 Hertz(24_000_000) => Usbrefcksel::MHZ24,
316 Hertz(26_000_000) => Usbrefcksel::MHZ26,
317 Hertz(32_000_000) => Usbrefcksel::MHZ32,
318 _ => panic!("cannot select OTG_HS reference clock with source frequency of {} Hz, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val),
319 },
320 None => Usbrefcksel::MHZ24,
321 };
322 #[cfg(all(stm32u5, peri_usb_otg_hs))]
323 SYSCFG.otghsphycr().modify(|w| {
324 w.set_clksel(usb_refck_sel);
325 });
326
327 let lse = config.ls.lse.map(|l| l.frequency);
328 let lsi = config.ls.lsi.then_some(LSI_FREQ);
329
330 config.mux.init();
331
332 set_clocks!(
333 sys: Some(sys_clk),
334 hclk1: Some(hclk),
335 hclk2: Some(hclk),
336 hclk3: Some(hclk),
337 pclk1: Some(pclk1),
338 pclk2: Some(pclk2),
339 pclk3: Some(pclk3),
340 pclk1_tim: Some(pclk1_tim),
341 pclk2_tim: Some(pclk2_tim),
342 msik: msik,
343 hsi48: hsi48,
344 rtc: rtc,
345 lse: lse,
346 lsi: lsi,
347 hse: hse,
348 hse_div_2: hse.map(|clk| clk / 2u32),
349 hsi: hsi,
350 pll1_p: pll1.p,
351 pll1_p_div_2: pll1.p.map(|clk| clk / 2u32),
352 pll1_q: pll1.q,
353 pll1_r: pll1.r,
354 pll2_p: pll2.p,
355 pll2_q: pll2.q,
356 pll2_r: pll2.r,
357 pll3_p: pll3.p,
358 pll3_q: pll3.q,
359 pll3_r: pll3.r,
360
361 #[cfg(dsihost)]
362 dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers
363
364 // TODO
365 audioclk: None,
366 hsi48_div_2: None,
367 shsi: None,
368 shsi_div_2: None,
369 );
370}
371
372fn msirange_to_hertz(range: Msirange) -> Hertz {
373 match range {
374 Msirange::RANGE_48MHZ => Hertz(48_000_000),
375 Msirange::RANGE_24MHZ => Hertz(24_000_000),
376 Msirange::RANGE_16MHZ => Hertz(16_000_000),
377 Msirange::RANGE_12MHZ => Hertz(12_000_000),
378 Msirange::RANGE_4MHZ => Hertz(4_000_000),
379 Msirange::RANGE_2MHZ => Hertz(2_000_000),
380 Msirange::RANGE_1_33MHZ => Hertz(1_330_000),
381 Msirange::RANGE_1MHZ => Hertz(1_000_000),
382 Msirange::RANGE_3_072MHZ => Hertz(3_072_000),
383 Msirange::RANGE_1_536MHZ => Hertz(1_536_000),
384 Msirange::RANGE_1_024MHZ => Hertz(1_024_000),
385 Msirange::RANGE_768KHZ => Hertz(768_000),
386 Msirange::RANGE_400KHZ => Hertz(400_000),
387 Msirange::RANGE_200KHZ => Hertz(200_000),
388 Msirange::RANGE_133KHZ => Hertz(133_000),
389 Msirange::RANGE_100KHZ => Hertz(100_000),
390 }
391}
392
393pub(super) struct PllInput {
394 pub hsi: Option<Hertz>,
395 pub hse: Option<Hertz>,
396 pub msi: Option<Hertz>,
397}
398
399#[allow(unused)]
400#[derive(Default)]
401pub(super) struct PllOutput {
402 pub p: Option<Hertz>,
403 pub q: Option<Hertz>,
404 pub r: Option<Hertz>,
405}
406
407#[derive(PartialEq, Eq, Clone, Copy)]
408enum PllInstance {
409 Pll1 = 0,
410 Pll2 = 1,
411 Pll3 = 2,
412}
413
414fn pll_enable(instance: PllInstance, enabled: bool) {
415 RCC.cr().modify(|w: &mut Cr| w.set_pllon(n:instance as _, val:enabled));
416 while RCC.cr().read().pllrdy(instance as _) != enabled {}
417}
418
419fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale) -> PllOutput {
420 // Disable PLL
421 pll_enable(instance, false);
422
423 let Some(pll) = config else { return PllOutput::default() };
424
425 let src_freq = match pll.source {
426 PllSource::DISABLE => panic!("must not select PLL source as DISABLE"),
427 PllSource::HSE => unwrap!(input.hse),
428 PllSource::HSI => unwrap!(input.hsi),
429 PllSource::MSIS => unwrap!(input.msi),
430 };
431
432 // Calculate the reference clock, which is the source divided by m
433 let ref_freq = src_freq / pll.prediv;
434 // Check limits per RM0456 § 11.4.6
435 assert!(Hertz::mhz(4) <= ref_freq && ref_freq <= Hertz::mhz(16));
436
437 // Check PLL clocks per RM0456 § 11.4.10
438 let (vco_min, vco_max, out_max) = match voltage_range {
439 VoltageScale::RANGE1 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(208)),
440 VoltageScale::RANGE2 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(110)),
441 VoltageScale::RANGE3 => (Hertz::mhz(128), Hertz::mhz(330), Hertz::mhz(55)),
442 VoltageScale::RANGE4 => panic!("PLL is unavailable in voltage range 4"),
443 };
444
445 // Calculate the PLL VCO clock
446 let vco_freq = ref_freq * pll.mul;
447 assert!(vco_freq >= vco_min && vco_freq <= vco_max);
448
449 // Calculate output clocks.
450 let p = pll.divp.map(|div| vco_freq / div);
451 let q = pll.divq.map(|div| vco_freq / div);
452 let r = pll.divr.map(|div| vco_freq / div);
453 for freq in [p, q, r] {
454 if let Some(freq) = freq {
455 assert!(freq <= out_max);
456 }
457 }
458
459 let divr = match instance {
460 PllInstance::Pll1 => RCC.pll1divr(),
461 PllInstance::Pll2 => RCC.pll2divr(),
462 PllInstance::Pll3 => RCC.pll3divr(),
463 };
464 divr.write(|w| {
465 w.set_plln(pll.mul);
466 w.set_pllp(pll.divp.unwrap_or(PllDiv::DIV1));
467 w.set_pllq(pll.divq.unwrap_or(PllDiv::DIV1));
468 w.set_pllr(pll.divr.unwrap_or(PllDiv::DIV1));
469 });
470
471 let input_range = match ref_freq.0 {
472 ..=8_000_000 => Pllrge::FREQ_4TO8MHZ,
473 _ => Pllrge::FREQ_8TO16MHZ,
474 };
475
476 macro_rules! write_fields {
477 ($w:ident) => {
478 $w.set_pllpen(pll.divp.is_some());
479 $w.set_pllqen(pll.divq.is_some());
480 $w.set_pllren(pll.divr.is_some());
481 $w.set_pllm(pll.prediv);
482 $w.set_pllsrc(pll.source);
483 $w.set_pllrge(input_range);
484 };
485 }
486
487 match instance {
488 PllInstance::Pll1 => RCC.pll1cfgr().write(|w| {
489 // § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler
490 // value that results in an output between 4 and 16 MHz for the PWR EPOD boost
491 if r.unwrap() >= Hertz::mhz(55) {
492 // source_clk can be up to 50 MHz, so there's just a few cases:
493 let mboost = match src_freq.0 {
494 ..=16_000_000 => Pllmboost::DIV1, // Bypass, giving EPOD 4-16 MHz
495 ..=32_000_000 => Pllmboost::DIV2, // Divide by 2, giving EPOD 8-16 MHz
496 _ => Pllmboost::DIV4, // Divide by 4, giving EPOD 8-12.5 MHz
497 };
498 w.set_pllmboost(mboost);
499 }
500 write_fields!(w);
501 }),
502 PllInstance::Pll2 => RCC.pll2cfgr().write(|w| {
503 write_fields!(w);
504 }),
505 PllInstance::Pll3 => RCC.pll3cfgr().write(|w| {
506 write_fields!(w);
507 }),
508 }
509
510 // Enable PLL
511 pll_enable(instance, true);
512
513 PllOutput { p, q, r }
514}
515