bl702_hal/
clock.rs

1#![allow(non_camel_case_types, non_snake_case, clippy::upper_case_acronyms)]
2
3use crate::{
4    gpio::ClkCfg,
5    system::{
6        glb::{self, *},
7        hbn::{
8            self, HBN_32K_CLK_Type, HBN_32K_Sel, HBN_Power_On_Xtal_32K, HBN_Set_XCLK_CLK_Sel,
9            HBN_XCLK_CLK_Type,
10        },
11        pds,
12    },
13};
14use embedded_time::rate::Hertz;
15
16pub const BSP_FCLK_DIV: u8 = 0;
17pub const BSP_BCLK_DIV: u8 = 1;
18
19#[repr(C)]
20pub enum system_clock_type {
21    ///  clock source before fclk_div
22    SYSTEM_CLOCK_ROOT_CLOCK = 0,
23    ///  clock source after fclk_div
24    SYSTEM_CLOCK_FCLK,
25    ///  clock source after bclk_div
26    SYSTEM_CLOCK_BCLK,
27    ///  xtal clock
28    SYSTEM_CLOCK_XCLK,
29    ///  32K clock
30    SYSTEM_CLOCK_32K_CLK,
31    ///  audio PLL clock
32    SYSTEM_CLOCK_AUPLL,
33}
34
35/// System bus frequency
36pub const SYSFREQ: u32 = 144_000_000;
37/// External high-speed crystal frequency
38pub const XTAL_FREQ: u32 = 32_000_000;
39/// UART peripheral clock frequency when PLL selected
40pub const UART_PLL_FREQ: u32 = 96_000_000;
41
42#[derive(PartialEq, Eq, Copy, Clone)]
43#[repr(u32)]
44pub enum SysclkFreq {
45    Pll144Mhz = 144_000_000,
46}
47
48/// Frozen clock frequencies
49///
50/// The existance of this value indicates that the clock configuration can no longer be changed
51#[derive(Clone, Copy)]
52pub struct Clocks {
53    sysclk: Hertz,
54    uart_clk: Hertz,
55}
56
57impl Clocks {
58    pub fn new() -> Self {
59        Clocks {
60            sysclk: Hertz(SYSFREQ),
61            uart_clk: Hertz(UART_PLL_FREQ),
62        }
63    }
64
65    pub fn sysclk(&self) -> Hertz {
66        self.sysclk
67    }
68
69    pub const fn uart_clk(&self) -> Hertz {
70        self.uart_clk
71    }
72}
73
74impl Default for Clocks {
75    fn default() -> Self {
76        Self::new()
77    }
78}
79
80pub struct ClockConfig {
81    sysclk: SysclkFreq,
82}
83
84impl ClockConfig {
85    /// Create initial clock config
86    pub fn new() -> Self {
87        ClockConfig {
88            sysclk: SysclkFreq::Pll144Mhz,
89        }
90    }
91
92    /// Calculate and balance clock registers to configure into the given clock value.
93    /// Will choose closest valid value if it can't accurately select a frequency
94    pub fn freeze(self, _clk_cfg: &mut ClkCfg) -> Clocks {
95        let pll_enabled = true;
96        let sysclk = self.sysclk;
97        let uart_clk_div = 1; // leave uart clock at 96mhz
98
99        unsafe { hbn::ptr() }
100            .hbn_glb
101            .modify(|_, w| w.hbn_uart_clk_sel().bit(pll_enabled));
102
103        // Write UART clock divider
104        unsafe { glb::ptr() }.clk_cfg2.modify(|_, w| unsafe {
105            w.uart_clk_div()
106                .bits(uart_clk_div - 1_u8)
107                .uart_clk_en()
108                .set_bit()
109        });
110
111        Clocks {
112            sysclk: Hertz(sysclk as u32),
113            uart_clk: Hertz(UART_PLL_FREQ),
114        }
115    }
116}
117
118impl Default for ClockConfig {
119    fn default() -> Self {
120        Self::new()
121    }
122}
123
124/// This is late system init, called to reconfigure clocks as per users configuration
125pub fn board_clock_init() {
126    system_clock_init();
127    peripheral_clock_init();
128}
129
130/// Set up core clocks
131pub fn system_clock_init() {
132    // select root clock
133    GLB_Set_System_CLK(
134        GLB_DLL_XTAL_Type::GLB_DLL_XTAL_32M,
135        GLB_SYS_CLK_Type::GLB_SYS_CLK_DLL144M,
136    );
137
138    // set fclk/hclk and bclk clock
139    GLB_Set_System_CLK_Div(BSP_FCLK_DIV, BSP_BCLK_DIV);
140    // Set MTimer the same frequency as SystemCoreClock
141    GLB_Set_MTimer_CLK(
142        1,
143        GLB_MTIMER_CLK_Type::GLB_MTIMER_CLK_BCLK,
144        mtimer_get_clk_src_div() as u8,
145    );
146
147    // TODO: set audio PLL
148    //  PDS_Set_Audio_PLL_Freq(BSP_AUDIO_PLL_CLOCK_SOURCE - ROOT_CLOCK_SOURCE_AUPLL_12288000_HZ);
149    HBN_Power_On_Xtal_32K();
150    HBN_32K_Sel(HBN_32K_CLK_Type::HBN_32K_XTAL);
151
152    HBN_Set_XCLK_CLK_Sel(HBN_XCLK_CLK_Type::HBN_XCLK_CLK_XTAL);
153}
154
155/// Disable all peripheral clocks, then re-enable any that we're using  
156/// TODO: move clock enable into peripheral drivers
157pub fn peripheral_clock_init() {
158    peripheral_clock_gate_all();
159    unsafe {
160        glb::ptr().cgen_cfg1.modify(|_, w| {
161            w.uart0().set_bit();
162            w.uart1().set_bit();
163            w
164        });
165    }
166}
167
168/// This is early system init - called from preinit in the C SDK
169pub fn system_init() {
170    unsafe { riscv::interrupt::disable() };
171    let pds = unsafe { pds::ptr() };
172    let glb = unsafe { glb::ptr() };
173    let hbn = unsafe { hbn::ptr() };
174    let efuse0 = unsafe { &*bl702_pac::EF_DATA_0::ptr() };
175    pds.pds_int.modify(|_r, w| {
176        w.cr_pds_wake_int_mask().set_bit(); // mask pds wakeup
177        w.cr_pds_rf_done_int_mask().set_bit(); // mask rf done
178        w.cr_pds_pll_done_int_mask().set_bit(); // mask all pds wakeup source int
179        unsafe {
180            // mask all pds wakeup source int
181            w.cr_pds_wakeup_src_en().bits(0);
182        }
183        w
184    });
185
186    // GLB_Set_EM_Sel(GLB_EM_0KB);
187    glb.seam_misc.modify(|_r, w| unsafe { w.em_sel().bits(0) });
188
189    /* Restore default setting*/
190    /* GLB_UART_Sig_Swap_Set(UART_SIG_SWAP_NONE); */
191    glb.glb_parm
192        .modify(|_r, w| unsafe { w.uart_swap_set().bits(0) });
193
194    /* fix 57.6M */
195    if system_frequency() == 57 * 6000 * 1000 {
196        unsafe {
197            hbn.hbn_rsv2.write_with_zero(|w| {
198                // Add 0.5 for const rounding
199                w.hbn_rsv2().bits((57.6 * 1000.0 * 1000.0 + 0.5) as u32)
200            });
201        }
202    }
203
204    const CLIC_HART0_ADDR: usize = 0x02800000;
205    const CLIC_INTIP: usize = 0x000;
206    const CLIC_INTIE: usize = 0x400;
207    const IRQ_NUM_BASE: usize = 16;
208    const IRQ_QTY: usize = 64;
209    const IRQ_ITER_END: usize = (IRQ_NUM_BASE + IRQ_QTY + 2) / 4;
210    // TODO: create HAL CLIC interface rather than interact directly here
211    // Clear all interrupts
212    let clic_e = (CLIC_HART0_ADDR + CLIC_INTIE) as *mut usize;
213    for i in 0..IRQ_ITER_END {
214        unsafe { clic_e.wrapping_add(i).write_volatile(0) };
215    }
216    let clic_p = (CLIC_HART0_ADDR + CLIC_INTIP) as *mut usize;
217    for i in 0..IRQ_ITER_END {
218        unsafe { clic_p.wrapping_add(i).write_volatile(0) };
219    }
220
221    // TODO: update SVD with these fields
222    // SF io select from efuse value
223    let fuse = efuse0.ef_key_slot_5_w2.read().ef_key_slot_5_w2().bits();
224    let flash_cfg = (fuse >> 26) & 7;
225    let psram_cfg = (fuse >> 24) & 3;
226
227    let is_internal_flash = flash_cfg == 1 || flash_cfg == 2;
228    let is_internal_psram = psram_cfg == 1;
229
230    glb.gpio_use_psram__io.modify(|_r, w| {
231        unsafe {
232            if is_internal_flash && !is_internal_psram {
233                w.bits(0x3f);
234            } else {
235                w.bits(0);
236            }
237        }
238        w
239    });
240
241    // TODO: register USB handler (if this isn't done at link time)
242    // #ifdef BFLB_EFLASH_LOADER
243    //     Interrupt_Handler_Register(USB_IRQn, USB_DoNothing_IRQHandler);
244    // #endif
245
246    // HBN_BOR_CFG_Type borCfg = { 0 /* pu_bor */, 0 /* irq_bor_en */, 1 /* bor_vth */, 0 /* bor_sel */ };
247    hbn.hbn_irq_mode.modify(|_r, w| {
248        w.irq_bor_en().clear_bit();
249        w
250    });
251
252    hbn.hbn_misc.modify(|_r, w| {
253        w.pu_bor().clear_bit();
254        w.bor_vth().set_bit();
255        w.bor_sel().clear_bit();
256        w
257    });
258
259    unsafe { riscv::interrupt::enable() };
260}
261
262pub fn system_frequency() -> u32 {
263    let hbn = unsafe { &*bl702_pac::HBN::ptr() };
264    hbn.hbn_rsv2.read().hbn_rsv2().bits()
265}
266
267fn mtimer_get_clk_src_div() -> u32 {
268    system_clock_get(system_clock_type::SYSTEM_CLOCK_BCLK) / 1000 / 1000 - 1
269}
270
271fn system_clock_get(t: system_clock_type) -> u32 {
272    let clksel = GLB_Get_Root_CLK_Sel();
273    match t {
274        system_clock_type::SYSTEM_CLOCK_ROOT_CLOCK => {
275            if clksel == GLB_ROOT_CLK_Type::GLB_ROOT_CLK_RC32M
276                || clksel == GLB_ROOT_CLK_Type::GLB_ROOT_CLK_XTAL
277            {
278                32_000_000
279            } else {
280                let pll_sel = unsafe { glb::ptr().clk_cfg0.read().reg_pll_sel().bits() };
281                match pll_sel {
282                    0 => 57_600_000,
283                    1 => 96_000_000,
284                    2 => 144_000_000,
285                    _ => 0,
286                }
287            }
288        }
289        system_clock_type::SYSTEM_CLOCK_FCLK => {
290            system_clock_get(system_clock_type::SYSTEM_CLOCK_ROOT_CLOCK)
291                / (GLB_Get_HCLK_Div() as u32 + 1)
292        }
293        system_clock_type::SYSTEM_CLOCK_BCLK => {
294            system_clock_get(system_clock_type::SYSTEM_CLOCK_ROOT_CLOCK)
295                / (GLB_Get_HCLK_Div() as u32 + 1)
296                / (GLB_Get_BCLK_Div() as u32 + 1)
297        }
298        system_clock_type::SYSTEM_CLOCK_XCLK => 32_000_000,
299        system_clock_type::SYSTEM_CLOCK_32K_CLK => 32_000,
300        // TODO: lookup!
301        system_clock_type::SYSTEM_CLOCK_AUPLL => 12_288_000,
302    }
303}