From 92690d8590301360cca8889fe9d118eb3cc30202 Mon Sep 17 00:00:00 2001
From: Romain Goyet <romain@goyet.com>
Date: Fri, 2 Feb 2024 13:53:16 -0500
Subject: [PATCH] Migrate STM32WBA to RCCv3

---
 embassy-stm32/src/rcc/wba.rs | 195 +++++++++++++++++++----------------
 1 file changed, 104 insertions(+), 91 deletions(-)

diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index 1d04d480a..dfa236484 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -1,5 +1,8 @@
-use stm32_metapac::rcc::vals::{Pllsrc, Sw};
-
+pub use crate::pac::pwr::vals::Vos as VoltageScale;
+use crate::pac::rcc::regs::Cfgr1;
+pub use crate::pac::rcc::vals::{
+    Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as ClockSrc,
+};
 use crate::pac::{FLASH, RCC};
 use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
@@ -9,82 +12,108 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
 // HSE speed
 pub const HSE_FREQ: Hertz = Hertz(32_000_000);
 
-pub use crate::pac::pwr::vals::Vos as VoltageScale;
-pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
-
-#[derive(Copy, Clone)]
-pub enum ClockSrc {
-    HSE,
-    HSI,
-}
-
-#[derive(Clone, Copy, Debug)]
-pub enum PllSource {
-    HSE,
-    HSI,
-}
-
-impl Into<Pllsrc> for PllSource {
-    fn into(self) -> Pllsrc {
-        match self {
-            PllSource::HSE => Pllsrc::HSE,
-            PllSource::HSI => Pllsrc::HSI,
-        }
-    }
-}
-
-impl Into<Sw> for ClockSrc {
-    fn into(self) -> Sw {
-        match self {
-            ClockSrc::HSE => Sw::HSE,
-            ClockSrc::HSI => Sw::HSI,
-        }
-    }
+#[derive(Clone, Copy, Eq, PartialEq)]
+pub struct Hse {
+    pub prescaler: HsePrescaler,
 }
 
+/// Clocks configuration
 pub struct Config {
+    // base clock sources
+    pub hsi: bool,
+    pub hse: Option<Hse>,
+
+    // sysclk, buses.
     pub mux: ClockSrc,
     pub ahb_pre: AHBPrescaler,
     pub apb1_pre: APBPrescaler,
     pub apb2_pre: APBPrescaler,
     pub apb7_pre: APBPrescaler,
+
+    // low speed LSI/LSE/RTC
     pub ls: super::LsConfig,
+
+    pub adc_clock_source: AdcClockSource,
+
+    pub voltage_scale: VoltageScale,
 }
 
 impl Default for Config {
-    fn default() -> Self {
-        Self {
+    #[inline]
+    fn default() -> Config {
+        Config {
+            hse: None,
+            hsi: true,
             mux: ClockSrc::HSI,
             ahb_pre: AHBPrescaler::DIV1,
             apb1_pre: APBPrescaler::DIV1,
             apb2_pre: APBPrescaler::DIV1,
             apb7_pre: APBPrescaler::DIV1,
             ls: Default::default(),
+            adc_clock_source: AdcClockSource::HCLK1,
+            voltage_scale: VoltageScale::RANGE2,
         }
     }
 }
 
+fn hsi_enable() {
+    RCC.cr().modify(|w| w.set_hsion(true));
+    while !RCC.cr().read().hsirdy() {}
+}
+
 pub(crate) unsafe fn init(config: Config) {
+    // Switch to HSI to prevent problems with PLL configuration.
+    if !RCC.cr().read().hsion() {
+        hsi_enable()
+    }
+    if RCC.cfgr1().read().sws() != ClockSrc::HSI {
+        // Set HSI as a clock source, reset prescalers.
+        RCC.cfgr1().write_value(Cfgr1::default());
+        // Wait for clock switch status bits to change.
+        while RCC.cfgr1().read().sws() != ClockSrc::HSI {}
+    }
+
+    // Set voltage scale
+    crate::pac::PWR.vosr().write(|w| w.set_vos(config.voltage_scale));
+    while !crate::pac::PWR.vosr().read().vosrdy() {}
+
+    let rtc = config.ls.init();
+
+    let hsi = config.hsi.then(|| {
+        hsi_enable();
+
+        HSI_FREQ
+    });
+
+    let hse = config.hse.map(|hse| {
+        RCC.cr().write(|w| {
+            w.set_hseon(true);
+            w.set_hsepre(hse.prescaler);
+        });
+        while !RCC.cr().read().hserdy() {}
+
+        HSE_FREQ
+    });
+
     let sys_clk = match config.mux {
-        ClockSrc::HSE => {
-            RCC.cr().write(|w| w.set_hseon(true));
-            while !RCC.cr().read().hserdy() {}
-
-            HSE_FREQ
-        }
-        ClockSrc::HSI => {
-            RCC.cr().write(|w| w.set_hsion(true));
-            while !RCC.cr().read().hsirdy() {}
-
-            HSI_FREQ
-        }
+        ClockSrc::HSE => hse.unwrap(),
+        ClockSrc::HSI => hsi.unwrap(),
+        ClockSrc::_RESERVED_1 => unreachable!(),
+        ClockSrc::PLL1_R => todo!(),
     };
 
-    // TODO make configurable
-    let power_vos = VoltageScale::RANGE1;
+    assert!(sys_clk.0 <= 100_000_000);
 
-    // states and programming delay
-    let wait_states = match power_vos {
+    let hclk1 = sys_clk / config.ahb_pre;
+    let hclk2 = hclk1;
+    let hclk4 = hclk1;
+    // TODO: hclk5
+    let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre);
+    let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre);
+    let (pclk7, _) = super::util::calc_pclk(hclk1, config.apb7_pre);
+
+    // Set flash wait states
+    let flash_latency = match config.voltage_scale {
         VoltageScale::RANGE1 => match sys_clk.0 {
             ..=32_000_000 => 0,
             ..=64_000_000 => 1,
@@ -99,13 +128,24 @@ pub(crate) unsafe fn init(config: Config) {
         },
     };
 
-    FLASH.acr().modify(|w| {
-        w.set_latency(wait_states);
-    });
+    FLASH.acr().modify(|w| w.set_latency(flash_latency));
+    while FLASH.acr().read().latency() != flash_latency {}
+
+    // Set sram wait states
+    let _sram_latency = match config.voltage_scale {
+        VoltageScale::RANGE1 => 0,
+        VoltageScale::RANGE2 => match sys_clk.0 {
+            ..=12_000_000 => 0,
+            ..=16_000_000 => 1,
+            _ => 2,
+        },
+    };
+    // TODO: Set the SRAM wait states
 
     RCC.cfgr1().modify(|w| {
-        w.set_sw(config.mux.into());
+        w.set_sw(config.mux);
     });
+    while RCC.cfgr1().read().sws() != config.mux {}
 
     RCC.cfgr2().modify(|w| {
         w.set_hpre(config.ahb_pre);
@@ -113,45 +153,18 @@ pub(crate) unsafe fn init(config: Config) {
         w.set_ppre2(config.apb2_pre);
     });
 
-    RCC.cfgr3().modify(|w| {
-        w.set_ppre7(config.apb7_pre);
-    });
-
-    let ahb_freq = sys_clk / config.ahb_pre;
-    let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
-        APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
-        pre => {
-            let freq = ahb_freq / pre;
-            (freq, freq * 2u32)
-        }
-    };
-    let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
-        APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
-        pre => {
-            let freq = ahb_freq / pre;
-            (freq, freq * 2u32)
-        }
-    };
-    let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre {
-        APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
-        pre => {
-            let freq = ahb_freq / pre;
-            (freq, freq * 2u32)
-        }
-    };
-
-    let rtc = config.ls.init();
+    RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source));
 
     set_freqs(Clocks {
         sys: sys_clk,
-        hclk1: ahb_freq,
-        hclk2: ahb_freq,
-        hclk4: ahb_freq,
-        pclk1: apb1_freq,
-        pclk2: apb2_freq,
-        pclk7: apb7_freq,
-        pclk1_tim: apb1_tim_freq,
-        pclk2_tim: apb2_tim_freq,
+        hclk1,
+        hclk2,
+        hclk4,
+        pclk1,
+        pclk2,
+        pclk7,
+        pclk1_tim,
+        pclk2_tim,
         rtc,
     });
 }